1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2020 Joyent, Inc.
  25  * Copyright 2012 Milan Jurik. All rights reserved.
  26  * Copyright 2017 RackTop Systems.
  27  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
  28  */
  29 
  30 
  31 #include <alloca.h>
  32 #include <assert.h>
  33 #include <ctype.h>
  34 #include <door.h>
  35 #include <errno.h>
  36 #include <fcntl.h>
  37 #include <fnmatch.h>
  38 #include <inttypes.h>
  39 #include <libintl.h>
  40 #include <libnvpair.h>
  41 #include <libscf.h>
  42 #include <libscf_priv.h>
  43 #include <libtecla.h>
  44 #include <libuutil.h>
  45 #include <limits.h>
  46 #include <locale.h>
  47 #include <stdarg.h>
  48 #include <string.h>
  49 #include <strings.h>
  50 #include <time.h>
  51 #include <unistd.h>
  52 #include <wait.h>
  53 #include <poll.h>
  54 
  55 #include <libxml/tree.h>
  56 
  57 #include <sys/param.h>
  58 
  59 #include <sys/stat.h>
  60 #include <sys/mman.h>
  61 
  62 #include "svccfg.h"
  63 #include "notify_params.h"
  64 #include "manifest_hash.h"
  65 #include "manifest_find.h"
  66 
  67 /* The colon namespaces in each entity (each followed by a newline). */
  68 #define COLON_NAMESPACES        ":properties\n"
  69 
  70 #define TEMP_FILE_PATTERN       "/tmp/svccfg-XXXXXX"
  71 
  72 /* These are characters which the lexer requires to be in double-quotes. */
  73 #define CHARS_TO_QUOTE          " \t\n\\>=\"()"
  74 
  75 #define HASH_SIZE               16
  76 #define HASH_PG_TYPE            "framework"
  77 #define HASH_PG_FLAGS           0
  78 #define HASH_PROP               "md5sum"
  79 
  80 /*
  81  * Indentation used in the output of the describe subcommand.
  82  */
  83 #define TMPL_VALUE_INDENT       "  "
  84 #define TMPL_INDENT             "    "
  85 #define TMPL_INDENT_2X          "        "
  86 #define TMPL_CHOICE_INDENT      "      "
  87 
  88 /*
  89  * Directory locations for manifests
  90  */
  91 #define VARSVC_DIR              "/var/svc/manifest"
  92 #define LIBSVC_DIR              "/lib/svc/manifest"
  93 #define VARSVC_PR               "var_svc_manifest"
  94 #define LIBSVC_PR               "lib_svc_manifest"
  95 #define MFSTFILEPR              "manifestfile"
  96 
  97 #define SUPPORTPROP             "support"
  98 
  99 #define MFSTHISTFILE            "/lib/svc/share/mfsthistory"
 100 
 101 #define MFSTFILE_MAX            16
 102 
 103 /*
 104  * These are the classes of elements which may appear as children of service
 105  * or instance elements in XML manifests.
 106  */
 107 struct entity_elts {
 108         xmlNodePtr      create_default_instance;
 109         xmlNodePtr      single_instance;
 110         xmlNodePtr      restarter;
 111         xmlNodePtr      dependencies;
 112         xmlNodePtr      dependents;
 113         xmlNodePtr      method_context;
 114         xmlNodePtr      exec_methods;
 115         xmlNodePtr      notify_params;
 116         xmlNodePtr      property_groups;
 117         xmlNodePtr      instances;
 118         xmlNodePtr      stability;
 119         xmlNodePtr      template;
 120 };
 121 
 122 /*
 123  * Likewise for property_group elements.
 124  */
 125 struct pg_elts {
 126         xmlNodePtr      stability;
 127         xmlNodePtr      propvals;
 128         xmlNodePtr      properties;
 129 };
 130 
 131 /*
 132  * Likewise for template elements.
 133  */
 134 struct template_elts {
 135         xmlNodePtr      common_name;
 136         xmlNodePtr      description;
 137         xmlNodePtr      documentation;
 138 };
 139 
 140 /*
 141  * Likewise for type (for notification parameters) elements.
 142  */
 143 struct params_elts {
 144         xmlNodePtr      paramval;
 145         xmlNodePtr      parameter;
 146 };
 147 
 148 /*
 149  * This structure is for snaplevel lists.  They are convenient because libscf
 150  * only allows traversing snaplevels in one direction.
 151  */
 152 struct snaplevel {
 153         uu_list_node_t  list_node;
 154         scf_snaplevel_t *sl;
 155 };
 156 
 157 /*
 158  * This is used for communication between lscf_service_export and
 159  * export_callback.
 160  */
 161 struct export_args {
 162         const char      *filename;
 163         int             flags;
 164 };
 165 
 166 /*
 167  * The service_manifest structure is used by the upgrade process
 168  * to create a list of service to manifest linkages from the manifests
 169  * in a set of given directories.
 170  */
 171 typedef struct service_manifest {
 172         const char      *servicename;
 173         uu_list_t       *mfstlist;
 174         size_t  mfstlist_sz;
 175 
 176         uu_avl_node_t   svcmfst_node;
 177 } service_manifest_t;
 178 
 179 /*
 180  * Structure to track the manifest file property group
 181  * and the manifest file associated with that property
 182  * group.  Also, a flag to keep the access once it has
 183  * been checked.
 184  */
 185 struct mpg_mfile {
 186         char    *mpg;
 187         char    *mfile;
 188         int     access;
 189 };
 190 
 191 const char * const scf_pg_general = SCF_PG_GENERAL;
 192 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
 193 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
 194 const char * const scf_property_external = "external";
 195 
 196 const char * const snap_initial = "initial";
 197 const char * const snap_lastimport = "last-import";
 198 const char * const snap_previous = "previous";
 199 const char * const snap_running = "running";
 200 
 201 scf_handle_t *g_hndl = NULL;    /* only valid after lscf_prep_hndl() */
 202 
 203 ssize_t max_scf_fmri_len;
 204 ssize_t max_scf_name_len;
 205 ssize_t max_scf_pg_type_len;
 206 ssize_t max_scf_value_len;
 207 static size_t max_scf_len;
 208 
 209 static scf_scope_t *cur_scope;
 210 static scf_service_t *cur_svc = NULL;
 211 static scf_instance_t *cur_inst = NULL;
 212 static scf_snapshot_t *cur_snap = NULL;
 213 static scf_snaplevel_t *cur_level = NULL;
 214 
 215 static uu_list_pool_t *snaplevel_pool;
 216 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
 217 static uu_list_t *cur_levels;
 218 static struct snaplevel *cur_elt;               /* cur_elt->sl == cur_level */
 219 
 220 static FILE *tempfile = NULL;
 221 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
 222 
 223 static const char *emsg_entity_not_selected;
 224 static const char *emsg_permission_denied;
 225 static const char *emsg_create_xml;
 226 static const char *emsg_cant_modify_snapshots;
 227 static const char *emsg_invalid_for_snapshot;
 228 static const char *emsg_read_only;
 229 static const char *emsg_deleted;
 230 static const char *emsg_invalid_pg_name;
 231 static const char *emsg_invalid_prop_name;
 232 static const char *emsg_no_such_pg;
 233 static const char *emsg_fmri_invalid_pg_name;
 234 static const char *emsg_fmri_invalid_pg_name_type;
 235 static const char *emsg_pg_added;
 236 static const char *emsg_pg_changed;
 237 static const char *emsg_pg_deleted;
 238 static const char *emsg_pg_mod_perm;
 239 static const char *emsg_pg_add_perm;
 240 static const char *emsg_pg_del_perm;
 241 static const char *emsg_snap_perm;
 242 static const char *emsg_dpt_dangling;
 243 static const char *emsg_dpt_no_dep;
 244 
 245 static int li_only = 0;
 246 static int no_refresh = 0;
 247 
 248 /* how long in ns we should wait between checks for a pg */
 249 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
 250 
 251 /* import globals, to minimize allocations */
 252 static scf_scope_t *imp_scope = NULL;
 253 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
 254 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
 255 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
 256 static scf_snapshot_t *imp_rsnap = NULL;
 257 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
 258 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
 259 static scf_property_t *imp_prop = NULL;
 260 static scf_iter_t *imp_iter = NULL;
 261 static scf_iter_t *imp_rpg_iter = NULL;
 262 static scf_iter_t *imp_up_iter = NULL;
 263 static scf_transaction_t *imp_tx = NULL;        /* always reset this */
 264 static char *imp_str = NULL;
 265 static size_t imp_str_sz;
 266 static char *imp_tsname = NULL;
 267 static char *imp_fe1 = NULL;            /* for fmri_equal() */
 268 static char *imp_fe2 = NULL;
 269 static uu_list_t *imp_deleted_dpts = NULL;      /* pgroup_t's to refresh */
 270 
 271 /* upgrade_dependents() globals */
 272 static scf_instance_t *ud_inst = NULL;
 273 static scf_snaplevel_t *ud_snpl = NULL;
 274 static scf_propertygroup_t *ud_pg = NULL;
 275 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
 276 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
 277 static int ud_run_dpts_pg_set = 0;
 278 static scf_property_t *ud_prop = NULL;
 279 static scf_property_t *ud_dpt_prop = NULL;
 280 static scf_value_t *ud_val = NULL;
 281 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
 282 static scf_transaction_t *ud_tx = NULL;
 283 static char *ud_ctarg = NULL;
 284 static char *ud_oldtarg = NULL;
 285 static char *ud_name = NULL;
 286 
 287 /* export globals */
 288 static scf_instance_t *exp_inst;
 289 static scf_propertygroup_t *exp_pg;
 290 static scf_property_t *exp_prop;
 291 static scf_value_t *exp_val;
 292 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
 293 static char *exp_str;
 294 static size_t exp_str_sz;
 295 
 296 /* cleanup globals */
 297 static uu_avl_pool_t *service_manifest_pool = NULL;
 298 static uu_avl_t *service_manifest_tree = NULL;
 299 
 300 static void scfdie_lineno(int lineno) __NORETURN;
 301 
 302 static char *start_method_names[] = {
 303         "start",
 304         "inetd_start",
 305         NULL
 306 };
 307 
 308 static struct uri_scheme {
 309         const char *scheme;
 310         const char *protocol;
 311 } uri_scheme[] = {
 312         { "mailto", "smtp" },
 313         { "snmp", "snmp" },
 314         { "syslog", "syslog" },
 315         { NULL, NULL }
 316 };
 317 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
 318     sizeof (struct uri_scheme)) - 1)
 319 
 320 static int
 321 check_uri_scheme(const char *scheme)
 322 {
 323         int i;
 324 
 325         for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
 326                 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
 327                         return (i);
 328         }
 329 
 330         return (-1);
 331 }
 332 
 333 static int
 334 check_uri_protocol(const char *p)
 335 {
 336         int i;
 337 
 338         for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
 339                 if (strcmp(p, uri_scheme[i].protocol) == 0)
 340                         return (i);
 341         }
 342 
 343         return (-1);
 344 }
 345 
 346 /*
 347  * For unexpected libscf errors.
 348  */
 349 #ifdef NDEBUG
 350 
 351 static void scfdie(void) __NORETURN;
 352 
 353 static void
 354 scfdie(void)
 355 {
 356         scf_error_t err = scf_error();
 357 
 358         if (err == SCF_ERROR_CONNECTION_BROKEN)
 359                 uu_die(gettext("Repository connection broken.  Exiting.\n"));
 360 
 361         uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
 362             scf_strerror(err));
 363 }
 364 
 365 #else
 366 
 367 #define scfdie()        scfdie_lineno(__LINE__)
 368 
 369 static void
 370 scfdie_lineno(int lineno)
 371 {
 372         scf_error_t err = scf_error();
 373 
 374         if (err == SCF_ERROR_CONNECTION_BROKEN)
 375                 uu_die(gettext("Repository connection broken.  Exiting.\n"));
 376 
 377         uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
 378             ": %s.\n"), lineno, scf_strerror(err));
 379 }
 380 
 381 #endif
 382 
 383 static void
 384 scfwarn(void)
 385 {
 386         warn(gettext("Unexpected libscf error: %s.\n"),
 387             scf_strerror(scf_error()));
 388 }
 389 
 390 /*
 391  * Clear a field of a structure.
 392  */
 393 static int
 394 clear_int(void *a, void *b)
 395 {
 396         /* LINTED */
 397         *(int *)((char *)a + (size_t)b) = 0;
 398 
 399         return (UU_WALK_NEXT);
 400 }
 401 
 402 static int
 403 scferror2errno(scf_error_t err)
 404 {
 405         switch (err) {
 406         case SCF_ERROR_BACKEND_ACCESS:
 407                 return (EACCES);
 408 
 409         case SCF_ERROR_BACKEND_READONLY:
 410                 return (EROFS);
 411 
 412         case SCF_ERROR_CONNECTION_BROKEN:
 413                 return (ECONNABORTED);
 414 
 415         case SCF_ERROR_CONSTRAINT_VIOLATED:
 416         case SCF_ERROR_INVALID_ARGUMENT:
 417                 return (EINVAL);
 418 
 419         case SCF_ERROR_DELETED:
 420                 return (ECANCELED);
 421 
 422         case SCF_ERROR_EXISTS:
 423                 return (EEXIST);
 424 
 425         case SCF_ERROR_NO_MEMORY:
 426                 return (ENOMEM);
 427 
 428         case SCF_ERROR_NO_RESOURCES:
 429                 return (ENOSPC);
 430 
 431         case SCF_ERROR_NOT_FOUND:
 432                 return (ENOENT);
 433 
 434         case SCF_ERROR_PERMISSION_DENIED:
 435                 return (EPERM);
 436 
 437         default:
 438 #ifndef NDEBUG
 439                 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
 440                     __FILE__, __LINE__, err);
 441 #else
 442                 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
 443 #endif
 444                 abort();
 445                 /* NOTREACHED */
 446         }
 447 }
 448 
 449 static int
 450 entity_get_pg(void *ent, int issvc, const char *name,
 451     scf_propertygroup_t *pg)
 452 {
 453         if (issvc)
 454                 return (scf_service_get_pg(ent, name, pg));
 455         else
 456                 return (scf_instance_get_pg(ent, name, pg));
 457 }
 458 
 459 static void
 460 entity_destroy(void *ent, int issvc)
 461 {
 462         if (issvc)
 463                 scf_service_destroy(ent);
 464         else
 465                 scf_instance_destroy(ent);
 466 }
 467 
 468 static int
 469 get_pg(const char *pg_name, scf_propertygroup_t *pg)
 470 {
 471         int ret;
 472 
 473         if (cur_level != NULL)
 474                 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
 475         else if (cur_inst != NULL)
 476                 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
 477         else
 478                 ret = scf_service_get_pg(cur_svc, pg_name, pg);
 479 
 480         return (ret);
 481 }
 482 
 483 /*
 484  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
 485  * snaplevel.  Otherwise find the instance snaplevel.
 486  *
 487  * Returns
 488  *   0 - success
 489  *   ECONNABORTED - repository connection broken
 490  *   ECANCELED - instance containing snap was deleted
 491  *   ENOENT - snap has no snaplevels
 492  *          - requested snaplevel not found
 493  */
 494 static int
 495 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
 496 {
 497         if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
 498                 switch (scf_error()) {
 499                 case SCF_ERROR_CONNECTION_BROKEN:
 500                 case SCF_ERROR_DELETED:
 501                 case SCF_ERROR_NOT_FOUND:
 502                         return (scferror2errno(scf_error()));
 503 
 504                 case SCF_ERROR_HANDLE_MISMATCH:
 505                 case SCF_ERROR_NOT_BOUND:
 506                 case SCF_ERROR_NOT_SET:
 507                 default:
 508                         bad_error("scf_snapshot_get_base_snaplevel",
 509                             scf_error());
 510                 }
 511         }
 512 
 513         for (;;) {
 514                 ssize_t ssz;
 515 
 516                 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
 517                 if (ssz >= 0) {
 518                         if (!get_svc)
 519                                 return (0);
 520                 } else {
 521                         switch (scf_error()) {
 522                         case SCF_ERROR_CONSTRAINT_VIOLATED:
 523                                 if (get_svc)
 524                                         return (0);
 525                                 break;
 526 
 527                         case SCF_ERROR_DELETED:
 528                         case SCF_ERROR_CONNECTION_BROKEN:
 529                                 return (scferror2errno(scf_error()));
 530 
 531                         case SCF_ERROR_NOT_SET:
 532                         case SCF_ERROR_NOT_BOUND:
 533                         default:
 534                                 bad_error("scf_snaplevel_get_instance_name",
 535                                     scf_error());
 536                         }
 537                 }
 538 
 539                 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
 540                         switch (scf_error()) {
 541                         case SCF_ERROR_NOT_FOUND:
 542                         case SCF_ERROR_CONNECTION_BROKEN:
 543                         case SCF_ERROR_DELETED:
 544                                 return (scferror2errno(scf_error()));
 545 
 546                         case SCF_ERROR_HANDLE_MISMATCH:
 547                         case SCF_ERROR_NOT_BOUND:
 548                         case SCF_ERROR_NOT_SET:
 549                         case SCF_ERROR_INVALID_ARGUMENT:
 550                         default:
 551                                 bad_error("scf_snaplevel_get_next_snaplevel",
 552                                     scf_error());
 553                         }
 554                 }
 555         }
 556 }
 557 
 558 /*
 559  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
 560  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
 561  * the property group named name in it.  If it doesn't have a running
 562  * snapshot, set pg to the instance's current property group named name.
 563  *
 564  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
 565  * its instances.  If one has a running snapshot with a service snaplevel, set
 566  * pg to the property group named name in it.  If no such snaplevel could be
 567  * found, set pg to the service's current property group named name.
 568  *
 569  * iter, inst, snap, and snpl are required scratch objects.
 570  *
 571  * Returns
 572  *   0 - success
 573  *   ECONNABORTED - repository connection broken
 574  *   ECANCELED - ent was deleted
 575  *   ENOENT - no such property group
 576  *   EINVAL - name is an invalid property group name
 577  *   EBADF - found running snapshot is missing a snaplevel
 578  */
 579 static int
 580 entity_get_running_pg(void *ent, int issvc, const char *name,
 581     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
 582     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
 583 {
 584         int r;
 585 
 586         if (issvc) {
 587                 /* Search for an instance with a running snapshot. */
 588                 if (scf_iter_service_instances(iter, ent) != 0) {
 589                         switch (scf_error()) {
 590                         case SCF_ERROR_DELETED:
 591                         case SCF_ERROR_CONNECTION_BROKEN:
 592                                 return (scferror2errno(scf_error()));
 593 
 594                         case SCF_ERROR_NOT_SET:
 595                         case SCF_ERROR_NOT_BOUND:
 596                         case SCF_ERROR_HANDLE_MISMATCH:
 597                         default:
 598                                 bad_error("scf_iter_service_instances",
 599                                     scf_error());
 600                         }
 601                 }
 602 
 603                 for (;;) {
 604                         r = scf_iter_next_instance(iter, inst);
 605                         if (r == 0) {
 606                                 if (scf_service_get_pg(ent, name, pg) == 0)
 607                                         return (0);
 608 
 609                                 switch (scf_error()) {
 610                                 case SCF_ERROR_DELETED:
 611                                 case SCF_ERROR_NOT_FOUND:
 612                                 case SCF_ERROR_INVALID_ARGUMENT:
 613                                 case SCF_ERROR_CONNECTION_BROKEN:
 614                                         return (scferror2errno(scf_error()));
 615 
 616                                 case SCF_ERROR_NOT_BOUND:
 617                                 case SCF_ERROR_HANDLE_MISMATCH:
 618                                 case SCF_ERROR_NOT_SET:
 619                                 default:
 620                                         bad_error("scf_service_get_pg",
 621                                             scf_error());
 622                                 }
 623                         }
 624                         if (r != 1) {
 625                                 switch (scf_error()) {
 626                                 case SCF_ERROR_DELETED:
 627                                 case SCF_ERROR_CONNECTION_BROKEN:
 628                                         return (scferror2errno(scf_error()));
 629 
 630                                 case SCF_ERROR_INVALID_ARGUMENT:
 631                                 case SCF_ERROR_NOT_SET:
 632                                 case SCF_ERROR_NOT_BOUND:
 633                                 case SCF_ERROR_HANDLE_MISMATCH:
 634                                 default:
 635                                         bad_error("scf_iter_next_instance",
 636                                             scf_error());
 637                                 }
 638                         }
 639 
 640                         if (scf_instance_get_snapshot(inst, snap_running,
 641                             snap) == 0)
 642                                 break;
 643 
 644                         switch (scf_error()) {
 645                         case SCF_ERROR_NOT_FOUND:
 646                         case SCF_ERROR_DELETED:
 647                                 continue;
 648 
 649                         case SCF_ERROR_CONNECTION_BROKEN:
 650                                 return (ECONNABORTED);
 651 
 652                         case SCF_ERROR_HANDLE_MISMATCH:
 653                         case SCF_ERROR_INVALID_ARGUMENT:
 654                         case SCF_ERROR_NOT_SET:
 655                         case SCF_ERROR_NOT_BOUND:
 656                         default:
 657                                 bad_error("scf_instance_get_snapshot",
 658                                     scf_error());
 659                         }
 660                 }
 661         } else {
 662                 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
 663                         switch (scf_error()) {
 664                         case SCF_ERROR_NOT_FOUND:
 665                                 break;
 666 
 667                         case SCF_ERROR_DELETED:
 668                         case SCF_ERROR_CONNECTION_BROKEN:
 669                                 return (scferror2errno(scf_error()));
 670 
 671                         case SCF_ERROR_NOT_BOUND:
 672                         case SCF_ERROR_HANDLE_MISMATCH:
 673                         case SCF_ERROR_INVALID_ARGUMENT:
 674                         case SCF_ERROR_NOT_SET:
 675                         default:
 676                                 bad_error("scf_instance_get_snapshot",
 677                                     scf_error());
 678                         }
 679 
 680                         if (scf_instance_get_pg(ent, name, pg) == 0)
 681                                 return (0);
 682 
 683                         switch (scf_error()) {
 684                         case SCF_ERROR_DELETED:
 685                         case SCF_ERROR_NOT_FOUND:
 686                         case SCF_ERROR_INVALID_ARGUMENT:
 687                         case SCF_ERROR_CONNECTION_BROKEN:
 688                                 return (scferror2errno(scf_error()));
 689 
 690                         case SCF_ERROR_NOT_BOUND:
 691                         case SCF_ERROR_HANDLE_MISMATCH:
 692                         case SCF_ERROR_NOT_SET:
 693                         default:
 694                                 bad_error("scf_instance_get_pg", scf_error());
 695                         }
 696                 }
 697         }
 698 
 699         r = get_snaplevel(snap, issvc, snpl);
 700         switch (r) {
 701         case 0:
 702                 break;
 703 
 704         case ECONNABORTED:
 705         case ECANCELED:
 706                 return (r);
 707 
 708         case ENOENT:
 709                 return (EBADF);
 710 
 711         default:
 712                 bad_error("get_snaplevel", r);
 713         }
 714 
 715         if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
 716                 return (0);
 717 
 718         switch (scf_error()) {
 719         case SCF_ERROR_DELETED:
 720         case SCF_ERROR_INVALID_ARGUMENT:
 721         case SCF_ERROR_CONNECTION_BROKEN:
 722         case SCF_ERROR_NOT_FOUND:
 723                 return (scferror2errno(scf_error()));
 724 
 725         case SCF_ERROR_NOT_BOUND:
 726         case SCF_ERROR_HANDLE_MISMATCH:
 727         case SCF_ERROR_NOT_SET:
 728         default:
 729                 bad_error("scf_snaplevel_get_pg", scf_error());
 730                 /* NOTREACHED */
 731         }
 732 }
 733 
 734 /*
 735  * To be registered with atexit().
 736  */
 737 static void
 738 remove_tempfile(void)
 739 {
 740         int ret;
 741 
 742         if (tempfile != NULL) {
 743                 if (fclose(tempfile) == EOF)
 744                         (void) warn(gettext("Could not close temporary file"));
 745                 tempfile = NULL;
 746         }
 747 
 748         if (tempfilename[0] != '\0') {
 749                 do {
 750                         ret = remove(tempfilename);
 751                 } while (ret == -1 && errno == EINTR);
 752                 if (ret == -1)
 753                         warn(gettext("Could not remove temporary file"));
 754                 tempfilename[0] = '\0';
 755         }
 756 }
 757 
 758 /*
 759  * Launch private svc.configd(1M) for manipulating alternate repositories.
 760  */
 761 static void
 762 start_private_repository(engine_state_t *est)
 763 {
 764         int fd, stat;
 765         struct door_info info;
 766         pid_t pid;
 767 
 768         /*
 769          * 1.  Create a temporary file for the door.
 770          */
 771         if (est->sc_repo_doorname != NULL)
 772                 free((void *)est->sc_repo_doorname);
 773 
 774         est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
 775         if (est->sc_repo_doorname == NULL)
 776                 uu_die(gettext("Could not acquire temporary filename"));
 777 
 778         fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
 779         if (fd < 0)
 780                 uu_die(gettext("Could not create temporary file for "
 781                     "repository server"));
 782 
 783         (void) close(fd);
 784 
 785         /*
 786          * 2.  Launch a configd with that door, using the specified
 787          * repository.
 788          */
 789         if ((est->sc_repo_pid = fork()) == 0) {
 790                 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
 791                     "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
 792                     NULL);
 793                 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
 794         } else if (est->sc_repo_pid == -1)
 795                 uu_die(gettext("Attempt to fork failed"));
 796 
 797         do {
 798                 pid = waitpid(est->sc_repo_pid, &stat, 0);
 799         } while (pid == -1 && errno == EINTR);
 800 
 801         if (pid == -1)
 802                 uu_die(gettext("Could not waitpid() for repository server"));
 803 
 804         if (!WIFEXITED(stat)) {
 805                 uu_die(gettext("Repository server failed (status %d).\n"),
 806                     stat);
 807         } else if (WEXITSTATUS(stat) != 0) {
 808                 uu_die(gettext("Repository server failed (exit %d).\n"),
 809                     WEXITSTATUS(stat));
 810         }
 811 
 812         /*
 813          * See if it was successful by checking if the door is a door.
 814          */
 815 
 816         fd = open(est->sc_repo_doorname, O_RDWR);
 817         if (fd < 0)
 818                 uu_die(gettext("Could not open door \"%s\""),
 819                     est->sc_repo_doorname);
 820 
 821         if (door_info(fd, &info) < 0)
 822                 uu_die(gettext("Unexpected door_info() error"));
 823 
 824         if (close(fd) == -1)
 825                 warn(gettext("Could not close repository door"),
 826                     strerror(errno));
 827 
 828         est->sc_repo_pid = info.di_target;
 829 }
 830 
 831 void
 832 lscf_cleanup(void)
 833 {
 834         /*
 835          * In the case where we've launched a private svc.configd(1M)
 836          * instance, we must terminate our child and remove the temporary
 837          * rendezvous point.
 838          */
 839         if (est->sc_repo_pid > 0) {
 840                 (void) kill(est->sc_repo_pid, SIGTERM);
 841                 (void) waitpid(est->sc_repo_pid, NULL, 0);
 842                 (void) unlink(est->sc_repo_doorname);
 843 
 844                 est->sc_repo_pid = 0;
 845         }
 846 }
 847 
 848 void
 849 unselect_cursnap(void)
 850 {
 851         void *cookie;
 852 
 853         cur_level = NULL;
 854 
 855         cookie = NULL;
 856         while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
 857                 scf_snaplevel_destroy(cur_elt->sl);
 858                 free(cur_elt);
 859         }
 860 
 861         scf_snapshot_destroy(cur_snap);
 862         cur_snap = NULL;
 863 }
 864 
 865 void
 866 lscf_prep_hndl(void)
 867 {
 868         if (g_hndl != NULL)
 869                 return;
 870 
 871         g_hndl = scf_handle_create(SCF_VERSION);
 872         if (g_hndl == NULL)
 873                 scfdie();
 874 
 875         if (est->sc_repo_filename != NULL)
 876                 start_private_repository(est);
 877 
 878         if (est->sc_repo_doorname != NULL) {
 879                 scf_value_t *repo_value;
 880                 int ret;
 881 
 882                 repo_value = scf_value_create(g_hndl);
 883                 if (repo_value == NULL)
 884                         scfdie();
 885 
 886                 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
 887                 assert(ret == SCF_SUCCESS);
 888 
 889                 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
 890                     SCF_SUCCESS)
 891                         scfdie();
 892 
 893                 scf_value_destroy(repo_value);
 894         }
 895 
 896         if (scf_handle_bind(g_hndl) != 0)
 897                 uu_die(gettext("Could not connect to repository server: %s.\n"),
 898                     scf_strerror(scf_error()));
 899 
 900         cur_scope = scf_scope_create(g_hndl);
 901         if (cur_scope == NULL)
 902                 scfdie();
 903 
 904         if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
 905                 scfdie();
 906 }
 907 
 908 static void
 909 repository_teardown(void)
 910 {
 911         if (g_hndl != NULL) {
 912                 if (cur_snap != NULL)
 913                         unselect_cursnap();
 914                 scf_instance_destroy(cur_inst);
 915                 scf_service_destroy(cur_svc);
 916                 scf_scope_destroy(cur_scope);
 917                 scf_handle_destroy(g_hndl);
 918                 cur_inst = NULL;
 919                 cur_svc = NULL;
 920                 cur_scope = NULL;
 921                 g_hndl = NULL;
 922                 lscf_cleanup();
 923         }
 924 }
 925 
 926 void
 927 lscf_set_repository(const char *repfile, int force)
 928 {
 929         repository_teardown();
 930 
 931         if (est->sc_repo_filename != NULL) {
 932                 free((void *)est->sc_repo_filename);
 933                 est->sc_repo_filename = NULL;
 934         }
 935 
 936         if ((force == 0) && (access(repfile, R_OK) != 0)) {
 937                 /*
 938                  * Repository file does not exist
 939                  * or has no read permission.
 940                  */
 941                 warn(gettext("Cannot access \"%s\": %s\n"),
 942                     repfile, strerror(errno));
 943         } else {
 944                 est->sc_repo_filename = safe_strdup(repfile);
 945         }
 946 
 947         lscf_prep_hndl();
 948 }
 949 
 950 void
 951 lscf_init()
 952 {
 953         if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
 954             (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
 955             (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
 956             0 ||
 957             (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
 958                 scfdie();
 959 
 960         max_scf_len = max_scf_fmri_len;
 961         if (max_scf_name_len > max_scf_len)
 962                 max_scf_len = max_scf_name_len;
 963         if (max_scf_pg_type_len > max_scf_len)
 964                 max_scf_len = max_scf_pg_type_len;
 965         /*
 966          * When a value of type opaque is represented as a string, the
 967          * string contains 2 characters for every byte of data.  That is
 968          * because the string contains the hex representation of the opaque
 969          * value.
 970          */
 971         if (2 * max_scf_value_len > max_scf_len)
 972                 max_scf_len = 2 * max_scf_value_len;
 973 
 974         if (atexit(remove_tempfile) != 0)
 975                 uu_die(gettext("Could not register atexit() function"));
 976 
 977         emsg_entity_not_selected = gettext("An entity is not selected.\n");
 978         emsg_permission_denied = gettext("Permission denied.\n");
 979         emsg_create_xml = gettext("Could not create XML node.\n");
 980         emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
 981         emsg_invalid_for_snapshot =
 982             gettext("Invalid operation on a snapshot.\n");
 983         emsg_read_only = gettext("Backend read-only.\n");
 984         emsg_deleted = gettext("Current selection has been deleted.\n");
 985         emsg_invalid_pg_name =
 986             gettext("Invalid property group name \"%s\".\n");
 987         emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
 988         emsg_no_such_pg = gettext("No such property group \"%s\".\n");
 989         emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
 990             "with invalid name \"%s\".\n");
 991         emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
 992             "group with invalid name \"%s\" or type \"%s\".\n");
 993         emsg_pg_added = gettext("%s changed unexpectedly "
 994             "(property group \"%s\" added).\n");
 995         emsg_pg_changed = gettext("%s changed unexpectedly "
 996             "(property group \"%s\" changed).\n");
 997         emsg_pg_deleted = gettext("%s changed unexpectedly "
 998             "(property group \"%s\" or an ancestor was deleted).\n");
 999         emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
1000             "in %s (permission denied).\n");
1001         emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1002             "in %s (permission denied).\n");
1003         emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1004             "in %s (permission denied).\n");
1005         emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1006             "(permission denied).\n");
1007         emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1008             "new dependent \"%s\" because it already exists).  Warning: The "
1009             "current dependent's target (%s) does not exist.\n");
1010         emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1011             "dependent \"%s\" because it already exists).  Warning: The "
1012             "current dependent's target (%s) does not have a dependency named "
1013             "\"%s\" as expected.\n");
1014 
1015         string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1016             offsetof(string_list_t, node), NULL, 0);
1017         snaplevel_pool = uu_list_pool_create("snaplevels",
1018             sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1019             NULL, 0);
1020 }
1021 
1022 
1023 static const char *
1024 prop_to_typestr(const scf_property_t *prop)
1025 {
1026         scf_type_t ty;
1027 
1028         if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1029                 scfdie();
1030 
1031         return (scf_type_to_string(ty));
1032 }
1033 
1034 static scf_type_t
1035 string_to_type(const char *type)
1036 {
1037         size_t len = strlen(type);
1038         char *buf;
1039 
1040         if (len == 0 || type[len - 1] != ':')
1041                 return (SCF_TYPE_INVALID);
1042 
1043         buf = (char *)alloca(len + 1);
1044         (void) strlcpy(buf, type, len + 1);
1045         buf[len - 1] = 0;
1046 
1047         return (scf_string_to_type(buf));
1048 }
1049 
1050 static scf_value_t *
1051 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1052 {
1053         scf_value_t *v;
1054         char *dup, *nstr;
1055         size_t len;
1056 
1057         v = scf_value_create(g_hndl);
1058         if (v == NULL)
1059                 scfdie();
1060 
1061         len = strlen(str);
1062         if (require_quotes &&
1063             (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1064                 semerr(gettext("Multiple string values or string values "
1065                     "with spaces must be quoted with '\"'.\n"));
1066                 scf_value_destroy(v);
1067                 return (NULL);
1068         }
1069 
1070         nstr = dup = safe_strdup(str);
1071         if (dup[0] == '\"') {
1072                 /*
1073                  * Strip out the first and the last quote.
1074                  */
1075                 dup[len - 1] = '\0';
1076                 nstr = dup + 1;
1077         }
1078 
1079         if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1080                 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1081                 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1082                     scf_type_to_string(ty), nstr);
1083                 scf_value_destroy(v);
1084                 v = NULL;
1085         }
1086         free(dup);
1087         return (v);
1088 }
1089 
1090 /*
1091  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1092  * Optionally append a comment prefix ('#') to newlines ('\n').
1093  */
1094 static int
1095 quote_and_print(const char *str, FILE *strm, int commentnl)
1096 {
1097         const char *cp;
1098 
1099         for (cp = str; *cp != '\0'; ++cp) {
1100                 if (*cp == '"' || *cp == '\\')
1101                         (void) putc('\\', strm);
1102 
1103                 (void) putc(*cp, strm);
1104 
1105                 if (commentnl && *cp == '\n') {
1106                         (void) putc('#', strm);
1107                 }
1108         }
1109 
1110         return (ferror(strm));
1111 }
1112 
1113 /*
1114  * These wrappers around lowlevel functions provide consistent error checking
1115  * and warnings.
1116  */
1117 static int
1118 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1119 {
1120         if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1121                 return (0);
1122 
1123         if (scf_error() != SCF_ERROR_NOT_FOUND)
1124                 scfdie();
1125 
1126         if (g_verbose) {
1127                 ssize_t len;
1128                 char *fmri;
1129 
1130                 len = scf_pg_to_fmri(pg, NULL, 0);
1131                 if (len < 0)
1132                         scfdie();
1133 
1134                 fmri = safe_malloc(len + 1);
1135 
1136                 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1137                         scfdie();
1138 
1139                 warn(gettext("Expected property %s of property group %s is "
1140                     "missing.\n"), propname, fmri);
1141 
1142                 free(fmri);
1143         }
1144 
1145         return (-1);
1146 }
1147 
1148 static int
1149 prop_check_type(scf_property_t *prop, scf_type_t ty)
1150 {
1151         scf_type_t pty;
1152 
1153         if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1154                 scfdie();
1155 
1156         if (ty == pty)
1157                 return (0);
1158 
1159         if (g_verbose) {
1160                 ssize_t len;
1161                 char *fmri;
1162                 const char *tystr;
1163 
1164                 len = scf_property_to_fmri(prop, NULL, 0);
1165                 if (len < 0)
1166                         scfdie();
1167 
1168                 fmri = safe_malloc(len + 1);
1169 
1170                 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1171                         scfdie();
1172 
1173                 tystr = scf_type_to_string(ty);
1174                 if (tystr == NULL)
1175                         tystr = "?";
1176 
1177                 warn(gettext("Property %s is not of expected type %s.\n"),
1178                     fmri, tystr);
1179 
1180                 free(fmri);
1181         }
1182 
1183         return (-1);
1184 }
1185 
1186 static int
1187 prop_get_val(scf_property_t *prop, scf_value_t *val)
1188 {
1189         scf_error_t err;
1190 
1191         if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1192                 return (0);
1193 
1194         err = scf_error();
1195 
1196         if (err != SCF_ERROR_NOT_FOUND &&
1197             err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1198             err != SCF_ERROR_PERMISSION_DENIED)
1199                 scfdie();
1200 
1201         if (g_verbose) {
1202                 ssize_t len;
1203                 char *fmri, *emsg;
1204 
1205                 len = scf_property_to_fmri(prop, NULL, 0);
1206                 if (len < 0)
1207                         scfdie();
1208 
1209                 fmri = safe_malloc(len + 1);
1210 
1211                 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1212                         scfdie();
1213 
1214                 if (err == SCF_ERROR_NOT_FOUND)
1215                         emsg = gettext("Property %s has no values; expected "
1216                             "one.\n");
1217                 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1218                         emsg = gettext("Property %s has multiple values; "
1219                             "expected one.\n");
1220                 else
1221                         emsg = gettext("No permission to read property %s.\n");
1222 
1223                 warn(emsg, fmri);
1224 
1225                 free(fmri);
1226         }
1227 
1228         return (-1);
1229 }
1230 
1231 
1232 static boolean_t
1233 snaplevel_is_instance(const scf_snaplevel_t *level)
1234 {
1235         if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1236                 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1237                         scfdie();
1238                 return (0);
1239         } else {
1240                 return (1);
1241         }
1242 }
1243 
1244 /*
1245  * Decode FMRI into a service or instance, and put the result in *ep.  If
1246  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1247  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1248  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1249  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1250  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1251  * whether *ep is a service.
1252  */
1253 static scf_error_t
1254 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1255 {
1256         char *fmri_copy;
1257         const char *sstr, *istr, *pgstr;
1258         scf_service_t *svc;
1259         scf_instance_t *inst;
1260 
1261         fmri_copy = strdup(fmri);
1262         if (fmri_copy == NULL)
1263                 return (SCF_ERROR_NO_MEMORY);
1264 
1265         if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1266             SCF_SUCCESS) {
1267                 free(fmri_copy);
1268                 return (SCF_ERROR_INVALID_ARGUMENT);
1269         }
1270 
1271         free(fmri_copy);
1272 
1273         if (sstr == NULL || pgstr != NULL)
1274                 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1275 
1276         if (istr == NULL) {
1277                 svc = scf_service_create(h);
1278                 if (svc == NULL)
1279                         return (SCF_ERROR_NO_MEMORY);
1280 
1281                 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1282                     SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1283                         if (scf_error() != SCF_ERROR_NOT_FOUND)
1284                                 scfdie();
1285 
1286                         return (SCF_ERROR_NOT_FOUND);
1287                 }
1288 
1289                 *ep = svc;
1290                 *isservice = 1;
1291         } else {
1292                 inst = scf_instance_create(h);
1293                 if (inst == NULL)
1294                         return (SCF_ERROR_NO_MEMORY);
1295 
1296                 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1297                     NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1298                         if (scf_error() != SCF_ERROR_NOT_FOUND)
1299                                 scfdie();
1300 
1301                         return (SCF_ERROR_NOT_FOUND);
1302                 }
1303 
1304                 *ep = inst;
1305                 *isservice = 0;
1306         }
1307 
1308         return (SCF_ERROR_NONE);
1309 }
1310 
1311 /*
1312  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1313  * *ep, and set or clear *isservicep if it is a service or an instance.
1314  * Returns
1315  *   SCF_ERROR_NONE - success
1316  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1317  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1318  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1319  *   SCF_ERROR_NOT_FOUND - no such scope
1320  *   SCF_ERROR_PERMISSION_DENIED
1321  *   SCF_ERROR_BACKEND_READONLY
1322  *   SCF_ERROR_BACKEND_ACCESS
1323  */
1324 static scf_error_t
1325 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1326 {
1327         char *fmri_copy;
1328         const char *scstr, *sstr, *istr, *pgstr;
1329         scf_scope_t *scope = NULL;
1330         scf_service_t *svc = NULL;
1331         scf_instance_t *inst = NULL;
1332         scf_error_t scfe;
1333 
1334         fmri_copy = safe_strdup(fmri);
1335 
1336         if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1337             0) {
1338                 free(fmri_copy);
1339                 return (SCF_ERROR_INVALID_ARGUMENT);
1340         }
1341 
1342         if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1343                 free(fmri_copy);
1344                 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1345         }
1346 
1347         *ep = NULL;
1348 
1349         if ((scope = scf_scope_create(h)) == NULL ||
1350             (svc = scf_service_create(h)) == NULL ||
1351             (inst = scf_instance_create(h)) == NULL) {
1352                 scfe = SCF_ERROR_NO_MEMORY;
1353                 goto out;
1354         }
1355 
1356 get_scope:
1357         if (scf_handle_get_scope(h, scstr, scope) != 0) {
1358                 switch (scf_error()) {
1359                 case SCF_ERROR_CONNECTION_BROKEN:
1360                         scfdie();
1361                         /* NOTREACHED */
1362 
1363                 case SCF_ERROR_NOT_FOUND:
1364                         scfe = SCF_ERROR_NOT_FOUND;
1365                         goto out;
1366 
1367                 case SCF_ERROR_HANDLE_MISMATCH:
1368                 case SCF_ERROR_NOT_BOUND:
1369                 case SCF_ERROR_INVALID_ARGUMENT:
1370                 default:
1371                         bad_error("scf_handle_get_scope", scf_error());
1372                 }
1373         }
1374 
1375 get_svc:
1376         if (scf_scope_get_service(scope, sstr, svc) != 0) {
1377                 switch (scf_error()) {
1378                 case SCF_ERROR_CONNECTION_BROKEN:
1379                         scfdie();
1380                         /* NOTREACHED */
1381 
1382                 case SCF_ERROR_DELETED:
1383                         goto get_scope;
1384 
1385                 case SCF_ERROR_NOT_FOUND:
1386                         break;
1387 
1388                 case SCF_ERROR_HANDLE_MISMATCH:
1389                 case SCF_ERROR_INVALID_ARGUMENT:
1390                 case SCF_ERROR_NOT_BOUND:
1391                 case SCF_ERROR_NOT_SET:
1392                 default:
1393                         bad_error("scf_scope_get_service", scf_error());
1394                 }
1395 
1396                 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1397                         switch (scf_error()) {
1398                         case SCF_ERROR_CONNECTION_BROKEN:
1399                                 scfdie();
1400                                 /* NOTREACHED */
1401 
1402                         case SCF_ERROR_DELETED:
1403                                 goto get_scope;
1404 
1405                         case SCF_ERROR_PERMISSION_DENIED:
1406                         case SCF_ERROR_BACKEND_READONLY:
1407                         case SCF_ERROR_BACKEND_ACCESS:
1408                                 scfe = scf_error();
1409                                 goto out;
1410 
1411                         case SCF_ERROR_HANDLE_MISMATCH:
1412                         case SCF_ERROR_INVALID_ARGUMENT:
1413                         case SCF_ERROR_NOT_BOUND:
1414                         case SCF_ERROR_NOT_SET:
1415                         default:
1416                                 bad_error("scf_scope_get_service", scf_error());
1417                         }
1418                 }
1419         }
1420 
1421         if (istr == NULL) {
1422                 scfe = SCF_ERROR_NONE;
1423                 *ep = svc;
1424                 *isservicep = 1;
1425                 goto out;
1426         }
1427 
1428 get_inst:
1429         if (scf_service_get_instance(svc, istr, inst) != 0) {
1430                 switch (scf_error()) {
1431                 case SCF_ERROR_CONNECTION_BROKEN:
1432                         scfdie();
1433                         /* NOTREACHED */
1434 
1435                 case SCF_ERROR_DELETED:
1436                         goto get_svc;
1437 
1438                 case SCF_ERROR_NOT_FOUND:
1439                         break;
1440 
1441                 case SCF_ERROR_HANDLE_MISMATCH:
1442                 case SCF_ERROR_INVALID_ARGUMENT:
1443                 case SCF_ERROR_NOT_BOUND:
1444                 case SCF_ERROR_NOT_SET:
1445                 default:
1446                         bad_error("scf_service_get_instance", scf_error());
1447                 }
1448 
1449                 if (scf_service_add_instance(svc, istr, inst) != 0) {
1450                         switch (scf_error()) {
1451                         case SCF_ERROR_CONNECTION_BROKEN:
1452                                 scfdie();
1453                                 /* NOTREACHED */
1454 
1455                         case SCF_ERROR_DELETED:
1456                                 goto get_svc;
1457 
1458                         case SCF_ERROR_PERMISSION_DENIED:
1459                         case SCF_ERROR_BACKEND_READONLY:
1460                         case SCF_ERROR_BACKEND_ACCESS:
1461                                 scfe = scf_error();
1462                                 goto out;
1463 
1464                         case SCF_ERROR_HANDLE_MISMATCH:
1465                         case SCF_ERROR_INVALID_ARGUMENT:
1466                         case SCF_ERROR_NOT_BOUND:
1467                         case SCF_ERROR_NOT_SET:
1468                         default:
1469                                 bad_error("scf_service_add_instance",
1470                                     scf_error());
1471                         }
1472                 }
1473         }
1474 
1475         scfe = SCF_ERROR_NONE;
1476         *ep = inst;
1477         *isservicep = 0;
1478 
1479 out:
1480         if (*ep != inst)
1481                 scf_instance_destroy(inst);
1482         if (*ep != svc)
1483                 scf_service_destroy(svc);
1484         scf_scope_destroy(scope);
1485         free(fmri_copy);
1486         return (scfe);
1487 }
1488 
1489 /*
1490  * Create or update a snapshot of inst.  snap is a required scratch object.
1491  *
1492  * Returns
1493  *   0 - success
1494  *   ECONNABORTED - repository connection broken
1495  *   EPERM - permission denied
1496  *   ENOSPC - configd is out of resources
1497  *   ECANCELED - inst was deleted
1498  *   -1 - unknown libscf error (message printed)
1499  */
1500 static int
1501 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1502 {
1503 again:
1504         if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1505                 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1506                         switch (scf_error()) {
1507                         case SCF_ERROR_CONNECTION_BROKEN:
1508                         case SCF_ERROR_PERMISSION_DENIED:
1509                         case SCF_ERROR_NO_RESOURCES:
1510                                 return (scferror2errno(scf_error()));
1511 
1512                         case SCF_ERROR_NOT_SET:
1513                         case SCF_ERROR_INVALID_ARGUMENT:
1514                         default:
1515                                 bad_error("_scf_snapshot_take_attach",
1516                                     scf_error());
1517                         }
1518                 }
1519         } else {
1520                 switch (scf_error()) {
1521                 case SCF_ERROR_NOT_FOUND:
1522                         break;
1523 
1524                 case SCF_ERROR_DELETED:
1525                 case SCF_ERROR_CONNECTION_BROKEN:
1526                         return (scferror2errno(scf_error()));
1527 
1528                 case SCF_ERROR_HANDLE_MISMATCH:
1529                 case SCF_ERROR_NOT_BOUND:
1530                 case SCF_ERROR_INVALID_ARGUMENT:
1531                 case SCF_ERROR_NOT_SET:
1532                 default:
1533                         bad_error("scf_instance_get_snapshot", scf_error());
1534                 }
1535 
1536                 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1537                         switch (scf_error()) {
1538                         case SCF_ERROR_EXISTS:
1539                                 goto again;
1540 
1541                         case SCF_ERROR_CONNECTION_BROKEN:
1542                         case SCF_ERROR_NO_RESOURCES:
1543                         case SCF_ERROR_PERMISSION_DENIED:
1544                                 return (scferror2errno(scf_error()));
1545 
1546                         default:
1547                                 scfwarn();
1548                                 return (-1);
1549 
1550                         case SCF_ERROR_NOT_SET:
1551                         case SCF_ERROR_INTERNAL:
1552                         case SCF_ERROR_INVALID_ARGUMENT:
1553                         case SCF_ERROR_HANDLE_MISMATCH:
1554                                 bad_error("_scf_snapshot_take_new",
1555                                     scf_error());
1556                         }
1557                 }
1558         }
1559 
1560         return (0);
1561 }
1562 
1563 static int
1564 refresh_running_snapshot(void *entity)
1565 {
1566         scf_snapshot_t *snap;
1567         int r;
1568 
1569         if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1570                 scfdie();
1571         r = take_snap(entity, snap_running, snap);
1572         scf_snapshot_destroy(snap);
1573 
1574         return (r);
1575 }
1576 
1577 /*
1578  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1579  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1580  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1581  * for scratch space.  Returns
1582  *   0 - success
1583  *   ECONNABORTED - repository connection broken
1584  *   ECANCELED - entity was deleted
1585  *   EACCES - backend denied access
1586  *   EPERM - permission denied
1587  *   ENOSPC - repository server out of resources
1588  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1589  */
1590 static int
1591 refresh_entity(int isservice, void *entity, const char *fmri,
1592     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1593 {
1594         scf_error_t scfe;
1595         int r;
1596 
1597         if (!isservice) {
1598                 /*
1599                  * Let restarter handles refreshing and making new running
1600                  * snapshot only if operating on a live repository and not
1601                  * running in early import.
1602                  */
1603                 if (est->sc_repo_filename == NULL &&
1604                     est->sc_repo_doorname == NULL &&
1605                     est->sc_in_emi == 0) {
1606                         if (_smf_refresh_instance_i(entity) == 0) {
1607                                 if (g_verbose)
1608                                         warn(gettext("Refreshed %s.\n"), fmri);
1609                                 return (0);
1610                         }
1611 
1612                         switch (scf_error()) {
1613                         case SCF_ERROR_BACKEND_ACCESS:
1614                                 return (EACCES);
1615 
1616                         case SCF_ERROR_PERMISSION_DENIED:
1617                                 return (EPERM);
1618 
1619                         default:
1620                                 return (-1);
1621                         }
1622                 } else {
1623                         r = refresh_running_snapshot(entity);
1624                         switch (r) {
1625                         case 0:
1626                                 break;
1627 
1628                         case ECONNABORTED:
1629                         case ECANCELED:
1630                         case EPERM:
1631                         case ENOSPC:
1632                                 break;
1633 
1634                         default:
1635                                 bad_error("refresh_running_snapshot",
1636                                     scf_error());
1637                         }
1638 
1639                         return (r);
1640                 }
1641         }
1642 
1643         if (scf_iter_service_instances(iter, entity) != 0) {
1644                 switch (scf_error()) {
1645                 case SCF_ERROR_CONNECTION_BROKEN:
1646                         return (ECONNABORTED);
1647 
1648                 case SCF_ERROR_DELETED:
1649                         return (ECANCELED);
1650 
1651                 case SCF_ERROR_HANDLE_MISMATCH:
1652                 case SCF_ERROR_NOT_BOUND:
1653                 case SCF_ERROR_NOT_SET:
1654                 default:
1655                         bad_error("scf_iter_service_instances", scf_error());
1656                 }
1657         }
1658 
1659         for (;;) {
1660                 r = scf_iter_next_instance(iter, inst);
1661                 if (r == 0)
1662                         break;
1663                 if (r != 1) {
1664                         switch (scf_error()) {
1665                         case SCF_ERROR_CONNECTION_BROKEN:
1666                                 return (ECONNABORTED);
1667 
1668                         case SCF_ERROR_DELETED:
1669                                 return (ECANCELED);
1670 
1671                         case SCF_ERROR_HANDLE_MISMATCH:
1672                         case SCF_ERROR_NOT_BOUND:
1673                         case SCF_ERROR_NOT_SET:
1674                         case SCF_ERROR_INVALID_ARGUMENT:
1675                         default:
1676                                 bad_error("scf_iter_next_instance",
1677                                     scf_error());
1678                         }
1679                 }
1680 
1681                 /*
1682                  * Similarly, just take a new running snapshot if operating on
1683                  * a non-live repository or running during early import.
1684                  */
1685                 if (est->sc_repo_filename != NULL ||
1686                     est->sc_repo_doorname != NULL ||
1687                     est->sc_in_emi == 1) {
1688                         r = refresh_running_snapshot(inst);
1689                         switch (r) {
1690                         case 0:
1691                                 continue;
1692 
1693                         case ECONNABORTED:
1694                         case ECANCELED:
1695                         case EPERM:
1696                         case ENOSPC:
1697                                 break;
1698                         default:
1699                                 bad_error("refresh_running_snapshot",
1700                                     scf_error());
1701                         }
1702 
1703                         return (r);
1704 
1705                 }
1706 
1707                 if (_smf_refresh_instance_i(inst) == 0) {
1708                         if (g_verbose) {
1709                                 if (scf_instance_get_name(inst, name_buf,
1710                                     max_scf_name_len + 1) < 0)
1711                                         (void) strcpy(name_buf, "?");
1712 
1713                                 warn(gettext("Refreshed %s:%s.\n"),
1714                                     fmri, name_buf);
1715                         }
1716                 } else {
1717                         if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1718                             g_verbose) {
1719                                 scfe = scf_error();
1720 
1721                                 if (scf_instance_to_fmri(inst, name_buf,
1722                                     max_scf_name_len + 1) < 0)
1723                                         (void) strcpy(name_buf, "?");
1724 
1725                                 warn(gettext(
1726                                     "Refresh of %s:%s failed: %s.\n"), fmri,
1727                                     name_buf, scf_strerror(scfe));
1728                         }
1729                 }
1730         }
1731 
1732         return (0);
1733 }
1734 
1735 static void
1736 private_refresh(void)
1737 {
1738         scf_instance_t *pinst = NULL;
1739         scf_iter_t *piter = NULL;
1740         ssize_t fmrilen;
1741         size_t bufsz;
1742         char *fmribuf;
1743         void *ent;
1744         int issvc;
1745         int r;
1746 
1747         if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1748                 return;
1749 
1750         assert(cur_svc != NULL);
1751 
1752         bufsz = max_scf_fmri_len + 1;
1753         fmribuf = safe_malloc(bufsz);
1754         if (cur_inst) {
1755                 issvc = 0;
1756                 ent = cur_inst;
1757                 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1758         } else {
1759                 issvc = 1;
1760                 ent = cur_svc;
1761                 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1762                 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1763                         scfdie();
1764 
1765                 if ((piter = scf_iter_create(g_hndl)) == NULL)
1766                         scfdie();
1767         }
1768         if (fmrilen < 0) {
1769                 free(fmribuf);
1770                 if (scf_error() != SCF_ERROR_DELETED)
1771                         scfdie();
1772 
1773                 warn(emsg_deleted);
1774                 return;
1775         }
1776         assert(fmrilen < bufsz);
1777 
1778         r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1779         switch (r) {
1780         case 0:
1781                 break;
1782 
1783         case ECONNABORTED:
1784                 warn(gettext("Could not refresh %s "
1785                     "(repository connection broken).\n"), fmribuf);
1786                 break;
1787 
1788         case ECANCELED:
1789                 warn(emsg_deleted);
1790                 break;
1791 
1792         case EPERM:
1793                 warn(gettext("Could not refresh %s "
1794                     "(permission denied).\n"), fmribuf);
1795                 break;
1796 
1797         case ENOSPC:
1798                 warn(gettext("Could not refresh %s "
1799                     "(repository server out of resources).\n"),
1800                     fmribuf);
1801                 break;
1802 
1803         case EACCES:
1804         default:
1805                 bad_error("refresh_entity", scf_error());
1806         }
1807 
1808         if (issvc) {
1809                 scf_instance_destroy(pinst);
1810                 scf_iter_destroy(piter);
1811         }
1812 
1813         free(fmribuf);
1814 }
1815 
1816 
1817 static int
1818 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1819 {
1820         cbp->sc_err = scferror2errno(err);
1821         return (UU_WALK_ERROR);
1822 }
1823 
1824 static int
1825 stash_scferror(scf_callback_t *cbp)
1826 {
1827         return (stash_scferror_err(cbp, scf_error()));
1828 }
1829 
1830 static int select_inst(const char *);
1831 static int select_svc(const char *);
1832 
1833 /*
1834  * Take a property that does not have a type and check to see if a type
1835  * exists or can be gleened from the current data.  Set the type.
1836  *
1837  * Check the current level (instance) and then check the higher level
1838  * (service).  This could be the case for adding a new property to
1839  * the instance that's going to "override" a service level property.
1840  *
1841  * For a property :
1842  * 1. Take the type from an existing property
1843  * 2. Take the type from a template entry
1844  *
1845  * If the type can not be found, then leave the type as is, and let the import
1846  * report the problem of the missing type.
1847  */
1848 static int
1849 find_current_prop_type(void *p, void *g)
1850 {
1851         property_t *prop = p;
1852         scf_callback_t *lcb = g;
1853         pgroup_t *pg = NULL;
1854 
1855         const char *fmri = NULL;
1856         char *lfmri = NULL;
1857         char *cur_selection = NULL;
1858 
1859         scf_propertygroup_t *sc_pg = NULL;
1860         scf_property_t *sc_prop = NULL;
1861         scf_pg_tmpl_t *t_pg = NULL;
1862         scf_prop_tmpl_t *t_prop = NULL;
1863         scf_type_t prop_type;
1864 
1865         value_t *vp;
1866         int issvc = lcb->sc_service;
1867         int r = UU_WALK_ERROR;
1868 
1869         if (prop->sc_value_type != SCF_TYPE_INVALID)
1870                 return (UU_WALK_NEXT);
1871 
1872         t_prop = scf_tmpl_prop_create(g_hndl);
1873         sc_prop = scf_property_create(g_hndl);
1874         if (sc_prop == NULL || t_prop == NULL) {
1875                 warn(gettext("Unable to create the property to attempt and "
1876                     "find a missing type.\n"));
1877 
1878                 scf_property_destroy(sc_prop);
1879                 scf_tmpl_prop_destroy(t_prop);
1880 
1881                 return (UU_WALK_ERROR);
1882         }
1883 
1884         if (lcb->sc_flags == 1) {
1885                 pg = lcb->sc_parent;
1886                 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1887                 fmri = pg->sc_parent->sc_fmri;
1888 retry_pg:
1889                 if (cur_svc && cur_selection == NULL) {
1890                         cur_selection = safe_malloc(max_scf_fmri_len + 1);
1891                         lscf_get_selection_str(cur_selection,
1892                             max_scf_fmri_len + 1);
1893 
1894                         if (strcmp(cur_selection, fmri) != 0) {
1895                                 lscf_select(fmri);
1896                         } else {
1897                                 free(cur_selection);
1898                                 cur_selection = NULL;
1899                         }
1900                 } else {
1901                         lscf_select(fmri);
1902                 }
1903 
1904                 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1905                         warn(gettext("Unable to create property group to "
1906                             "find a missing property type.\n"));
1907 
1908                         goto out;
1909                 }
1910 
1911                 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1912                         /*
1913                          * If this is the sc_pg from the parent
1914                          * let the caller clean up the sc_pg,
1915                          * and just throw it away in this case.
1916                          */
1917                         if (sc_pg != lcb->sc_parent)
1918                                 scf_pg_destroy(sc_pg);
1919 
1920                         sc_pg = NULL;
1921                         if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1922                                 warn(gettext("Unable to create template "
1923                                     "property group to find a property "
1924                                     "type.\n"));
1925 
1926                                 goto out;
1927                         }
1928 
1929                         if (scf_tmpl_get_by_pg_name(fmri, NULL,
1930                             pg->sc_pgroup_name, NULL, t_pg,
1931                             SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1932                                 /*
1933                                  * if instance get service and jump back
1934                                  */
1935                                 scf_tmpl_pg_destroy(t_pg);
1936                                 t_pg = NULL;
1937                                 if (issvc == 0) {
1938                                         entity_t *e = pg->sc_parent->sc_parent;
1939 
1940                                         fmri = e->sc_fmri;
1941                                         issvc = 1;
1942                                         goto retry_pg;
1943                                 } else {
1944                                         goto out;
1945                                 }
1946                         }
1947                 }
1948         } else {
1949                 sc_pg = lcb->sc_parent;
1950         }
1951 
1952         /*
1953          * Attempt to get the type from an existing property.  If the property
1954          * cannot be found then attempt to get the type from a template entry
1955          * for the property.
1956          *
1957          * Finally, if at the instance level look at the service level.
1958          */
1959         if (sc_pg != NULL &&
1960             pg_get_prop(sc_pg, prop->sc_property_name,
1961             sc_prop) == SCF_SUCCESS &&
1962             scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1963                 prop->sc_value_type = prop_type;
1964 
1965                 /*
1966                  * Found a type, update the value types and validate
1967                  * the actual value against this type.
1968                  */
1969                 for (vp = uu_list_first(prop->sc_property_values);
1970                     vp != NULL;
1971                     vp = uu_list_next(prop->sc_property_values, vp)) {
1972                         vp->sc_type = prop->sc_value_type;
1973                         lxml_store_value(vp, 0, NULL);
1974                 }
1975 
1976                 r = UU_WALK_NEXT;
1977                 goto out;
1978         }
1979 
1980         /*
1981          * If we get here with t_pg set to NULL then we had to have
1982          * gotten an sc_pg but that sc_pg did not have the property
1983          * we are looking for.   So if the t_pg is not null look up
1984          * the template entry for the property.
1985          *
1986          * If the t_pg is null then need to attempt to get a matching
1987          * template entry for the sc_pg, and see if there is a property
1988          * entry for that template entry.
1989          */
1990 do_tmpl :
1991         if (t_pg != NULL &&
1992             scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1993             t_prop, 0) == SCF_SUCCESS) {
1994                 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1995                         prop->sc_value_type = prop_type;
1996 
1997                         /*
1998                          * Found a type, update the value types and validate
1999                          * the actual value against this type.
2000                          */
2001                         for (vp = uu_list_first(prop->sc_property_values);
2002                             vp != NULL;
2003                             vp = uu_list_next(prop->sc_property_values, vp)) {
2004                                 vp->sc_type = prop->sc_value_type;
2005                                 lxml_store_value(vp, 0, NULL);
2006                         }
2007 
2008                         r = UU_WALK_NEXT;
2009                         goto out;
2010                 }
2011         } else {
2012                 if (t_pg == NULL && sc_pg) {
2013                         if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2014                                 warn(gettext("Unable to create template "
2015                                     "property group to find a property "
2016                                     "type.\n"));
2017 
2018                                 goto out;
2019                         }
2020 
2021                         if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2022                                 scf_tmpl_pg_destroy(t_pg);
2023                                 t_pg = NULL;
2024                         } else {
2025                                 goto do_tmpl;
2026                         }
2027                 }
2028         }
2029 
2030         if (issvc == 0) {
2031                 scf_instance_t *i;
2032                 scf_service_t *s;
2033 
2034                 issvc = 1;
2035                 if (lcb->sc_flags == 1) {
2036                         entity_t *e = pg->sc_parent->sc_parent;
2037 
2038                         fmri = e->sc_fmri;
2039                         goto retry_pg;
2040                 }
2041 
2042                 /*
2043                  * because lcb->sc_flags was not set then this means
2044                  * the pg was not used and can be used here.
2045                  */
2046                 if ((pg = internal_pgroup_new()) == NULL) {
2047                         warn(gettext("Could not create internal property group "
2048                             "to find a missing type."));
2049 
2050                         goto out;
2051                 }
2052 
2053                 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2054                 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2055                     max_scf_name_len + 1) < 0)
2056                                 goto out;
2057 
2058                 i = scf_instance_create(g_hndl);
2059                 s = scf_service_create(g_hndl);
2060                 if (i == NULL || s == NULL ||
2061                     scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2062                         warn(gettext("Could not get a service for the instance "
2063                             "to find a missing type."));
2064 
2065                         goto out;
2066                 }
2067 
2068                 /*
2069                  * Check to see truly at the instance level.
2070                  */
2071                 lfmri = safe_malloc(max_scf_fmri_len + 1);
2072                 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2073                     scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2074                         goto out;
2075                 else
2076                         fmri = (const char *)lfmri;
2077 
2078                 goto retry_pg;
2079         }
2080 
2081 out :
2082         if (sc_pg != lcb->sc_parent) {
2083                 scf_pg_destroy(sc_pg);
2084         }
2085 
2086         /*
2087          * If this is true then the pg was allocated
2088          * here, and the name was set so need to free
2089          * the name and the pg.
2090          */
2091         if (pg != NULL && pg != lcb->sc_parent) {
2092                 free((char *)pg->sc_pgroup_name);
2093                 internal_pgroup_free(pg);
2094         }
2095 
2096         if (cur_selection) {
2097                 lscf_select(cur_selection);
2098                 free(cur_selection);
2099         }
2100 
2101         scf_tmpl_pg_destroy(t_pg);
2102         scf_tmpl_prop_destroy(t_prop);
2103         scf_property_destroy(sc_prop);
2104 
2105         if (r != UU_WALK_NEXT)
2106                 warn(gettext("Could not find property type for \"%s\" "
2107                     "from \"%s\"\n"), prop->sc_property_name,
2108                     fmri != NULL ? fmri : lcb->sc_source_fmri);
2109 
2110         free(lfmri);
2111 
2112         return (r);
2113 }
2114 
2115 /*
2116  * Take a property group that does not have a type and check to see if a type
2117  * exists or can be gleened from the current data.  Set the type.
2118  *
2119  * Check the current level (instance) and then check the higher level
2120  * (service).  This could be the case for adding a new property to
2121  * the instance that's going to "override" a service level property.
2122  *
2123  * For a property group
2124  * 1. Take the type from an existing property group
2125  * 2. Take the type from a template entry
2126  *
2127  * If the type can not be found, then leave the type as is, and let the import
2128  * report the problem of the missing type.
2129  */
2130 static int
2131 find_current_pg_type(void *p, void *sori)
2132 {
2133         entity_t *si = sori;
2134         pgroup_t *pg = p;
2135 
2136         const char *ofmri, *fmri;
2137         char *cur_selection = NULL;
2138         char *pg_type = NULL;
2139 
2140         scf_propertygroup_t *sc_pg = NULL;
2141         scf_pg_tmpl_t *t_pg = NULL;
2142 
2143         int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2144         int r = UU_WALK_ERROR;
2145 
2146         ofmri = fmri = si->sc_fmri;
2147         if (pg->sc_pgroup_type != NULL) {
2148                 r = UU_WALK_NEXT;
2149 
2150                 goto out;
2151         }
2152 
2153         sc_pg = scf_pg_create(g_hndl);
2154         if (sc_pg == NULL) {
2155                 warn(gettext("Unable to create property group to attempt "
2156                     "and find a missing type.\n"));
2157 
2158                 return (UU_WALK_ERROR);
2159         }
2160 
2161         /*
2162          * Using get_pg() requires that the cur_svc/cur_inst be
2163          * via lscf_select.  Need to preserve the current selection
2164          * if going to use lscf_select() to set up the cur_svc/cur_inst
2165          */
2166         if (cur_svc) {
2167                 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2168                 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2169         }
2170 
2171         /*
2172          * If the property group exists get the type, and set
2173          * the pgroup_t type of that type.
2174          *
2175          * If not the check for a template pg_pattern entry
2176          * and take the type from that.
2177          */
2178 retry_svc:
2179         lscf_select(fmri);
2180 
2181         if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2182                 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2183                 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2184                     max_scf_pg_type_len + 1) != -1) {
2185                         pg->sc_pgroup_type = pg_type;
2186 
2187                         r = UU_WALK_NEXT;
2188                         goto out;
2189                 } else {
2190                         free(pg_type);
2191                 }
2192         } else {
2193                 if ((t_pg == NULL) &&
2194                     (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2195                         goto out;
2196 
2197                 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2198                     NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2199                     scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2200                         pg->sc_pgroup_type = pg_type;
2201 
2202                         r = UU_WALK_NEXT;
2203                         goto out;
2204                 }
2205         }
2206 
2207         /*
2208          * If type is not found at the instance level then attempt to
2209          * find the type at the service level.
2210          */
2211         if (!issvc) {
2212                 si = si->sc_parent;
2213                 fmri = si->sc_fmri;
2214                 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2215                 goto retry_svc;
2216         }
2217 
2218 out :
2219         if (cur_selection) {
2220                 lscf_select(cur_selection);
2221                 free(cur_selection);
2222         }
2223 
2224         /*
2225          * Now walk the properties of the property group to make sure that
2226          * all properties have the correct type and values are valid for
2227          * those types.
2228          */
2229         if (r == UU_WALK_NEXT) {
2230                 scf_callback_t cb;
2231 
2232                 cb.sc_service = issvc;
2233                 cb.sc_source_fmri = ofmri;
2234                 if (sc_pg != NULL) {
2235                         cb.sc_parent = sc_pg;
2236                         cb.sc_flags = 0;
2237                 } else {
2238                         cb.sc_parent = pg;
2239                         cb.sc_flags = 1;
2240                 }
2241 
2242                 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2243                     &cb, UU_DEFAULT) != 0) {
2244                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2245                                 bad_error("uu_list_walk", uu_error());
2246 
2247                         r = UU_WALK_ERROR;
2248                 }
2249         } else {
2250                 warn(gettext("Could not find property group type for "
2251                     "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2252         }
2253 
2254         scf_tmpl_pg_destroy(t_pg);
2255         scf_pg_destroy(sc_pg);
2256 
2257         return (r);
2258 }
2259 
2260 /*
2261  * Import.  These functions import a bundle into the repository.
2262  */
2263 
2264 /*
2265  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2266  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2267  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2268  * lcbdata->sc_err to
2269  *   ENOMEM - out of memory
2270  *   ECONNABORTED - repository connection broken
2271  *   ECANCELED - sc_trans's property group was deleted
2272  *   EINVAL - p's name is invalid (error printed)
2273  *          - p has an invalid value (error printed)
2274  */
2275 static int
2276 lscf_property_import(void *v, void *pvt)
2277 {
2278         property_t *p = v;
2279         scf_callback_t *lcbdata = pvt;
2280         value_t *vp;
2281         scf_transaction_t *trans = lcbdata->sc_trans;
2282         scf_transaction_entry_t *entr;
2283         scf_value_t *val;
2284         scf_type_t tp;
2285 
2286         if ((lcbdata->sc_flags & SCI_NOENABLED ||
2287             lcbdata->sc_flags & SCI_DELAYENABLE) &&
2288             strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2289                 lcbdata->sc_enable = p;
2290                 return (UU_WALK_NEXT);
2291         }
2292 
2293         entr = scf_entry_create(lcbdata->sc_handle);
2294         if (entr == NULL) {
2295                 switch (scf_error()) {
2296                 case SCF_ERROR_NO_MEMORY:
2297                         return (stash_scferror(lcbdata));
2298 
2299                 case SCF_ERROR_INVALID_ARGUMENT:
2300                 default:
2301                         bad_error("scf_entry_create", scf_error());
2302                 }
2303         }
2304 
2305         tp = p->sc_value_type;
2306 
2307         if (scf_transaction_property_new(trans, entr,
2308             p->sc_property_name, tp) != 0) {
2309                 switch (scf_error()) {
2310                 case SCF_ERROR_INVALID_ARGUMENT:
2311                         semerr(emsg_invalid_prop_name, p->sc_property_name);
2312                         scf_entry_destroy(entr);
2313                         return (stash_scferror(lcbdata));
2314 
2315                 case SCF_ERROR_EXISTS:
2316                         break;
2317 
2318                 case SCF_ERROR_DELETED:
2319                 case SCF_ERROR_CONNECTION_BROKEN:
2320                         scf_entry_destroy(entr);
2321                         return (stash_scferror(lcbdata));
2322 
2323                 case SCF_ERROR_NOT_BOUND:
2324                 case SCF_ERROR_HANDLE_MISMATCH:
2325                 case SCF_ERROR_NOT_SET:
2326                 default:
2327                         bad_error("scf_transaction_property_new", scf_error());
2328                 }
2329 
2330                 if (scf_transaction_property_change_type(trans, entr,
2331                     p->sc_property_name, tp) != 0) {
2332                         switch (scf_error()) {
2333                         case SCF_ERROR_DELETED:
2334                         case SCF_ERROR_CONNECTION_BROKEN:
2335                                 scf_entry_destroy(entr);
2336                                 return (stash_scferror(lcbdata));
2337 
2338                         case SCF_ERROR_INVALID_ARGUMENT:
2339                                 semerr(emsg_invalid_prop_name,
2340                                     p->sc_property_name);
2341                                 scf_entry_destroy(entr);
2342                                 return (stash_scferror(lcbdata));
2343 
2344                         case SCF_ERROR_NOT_FOUND:
2345                         case SCF_ERROR_NOT_SET:
2346                         case SCF_ERROR_HANDLE_MISMATCH:
2347                         case SCF_ERROR_NOT_BOUND:
2348                         default:
2349                                 bad_error(
2350                                     "scf_transaction_property_change_type",
2351                                     scf_error());
2352                         }
2353                 }
2354         }
2355 
2356         for (vp = uu_list_first(p->sc_property_values);
2357             vp != NULL;
2358             vp = uu_list_next(p->sc_property_values, vp)) {
2359                 val = scf_value_create(g_hndl);
2360                 if (val == NULL) {
2361                         switch (scf_error()) {
2362                         case SCF_ERROR_NO_MEMORY:
2363                                 return (stash_scferror(lcbdata));
2364 
2365                         case SCF_ERROR_INVALID_ARGUMENT:
2366                         default:
2367                                 bad_error("scf_value_create", scf_error());
2368                         }
2369                 }
2370 
2371                 switch (tp) {
2372                 case SCF_TYPE_BOOLEAN:
2373                         scf_value_set_boolean(val, vp->sc_u.sc_count);
2374                         break;
2375                 case SCF_TYPE_COUNT:
2376                         scf_value_set_count(val, vp->sc_u.sc_count);
2377                         break;
2378                 case SCF_TYPE_INTEGER:
2379                         scf_value_set_integer(val, vp->sc_u.sc_integer);
2380                         break;
2381                 default:
2382                         assert(vp->sc_u.sc_string != NULL);
2383                         if (scf_value_set_from_string(val, tp,
2384                             vp->sc_u.sc_string) != 0) {
2385                                 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2386                                         bad_error("scf_value_set_from_string",
2387                                             scf_error());
2388 
2389                                 warn(gettext("Value \"%s\" is not a valid "
2390                                     "%s.\n"), vp->sc_u.sc_string,
2391                                     scf_type_to_string(tp));
2392                                 scf_value_destroy(val);
2393                                 return (stash_scferror(lcbdata));
2394                         }
2395                         break;
2396                 }
2397 
2398                 if (scf_entry_add_value(entr, val) != 0)
2399                         bad_error("scf_entry_add_value", scf_error());
2400         }
2401 
2402         return (UU_WALK_NEXT);
2403 }
2404 
2405 /*
2406  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2407  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2408  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2409  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2410  * lcbdata->sc_err to
2411  *   ECONNABORTED - repository connection broken
2412  *   ENOMEM - out of memory
2413  *   ENOSPC - svc.configd is out of resources
2414  *   ECANCELED - sc_parent was deleted
2415  *   EPERM - could not create property group (permission denied) (error printed)
2416  *         - could not modify property group (permission denied) (error printed)
2417  *         - could not delete property group (permission denied) (error printed)
2418  *   EROFS - could not create property group (repository is read-only)
2419  *         - could not delete property group (repository is read-only)
2420  *   EACCES - could not create property group (backend access denied)
2421  *          - could not delete property group (backend access denied)
2422  *   EEXIST - could not create property group (already exists)
2423  *   EINVAL - invalid property group name (error printed)
2424  *          - invalid property name (error printed)
2425  *          - invalid value (error printed)
2426  *   EBUSY - new property group deleted (error printed)
2427  *         - new property group changed (error printed)
2428  *         - property group added (error printed)
2429  *         - property group deleted (error printed)
2430  */
2431 static int
2432 entity_pgroup_import(void *v, void *pvt)
2433 {
2434         pgroup_t *p = v;
2435         scf_callback_t cbdata;
2436         scf_callback_t *lcbdata = pvt;
2437         void *ent = lcbdata->sc_parent;
2438         int issvc = lcbdata->sc_service;
2439         int r;
2440 
2441         const char * const pg_changed = gettext("%s changed unexpectedly "
2442             "(new property group \"%s\" changed).\n");
2443 
2444         /* Never import deleted property groups. */
2445         if (p->sc_pgroup_delete) {
2446                 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2447                     entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2448                         goto delete_pg;
2449                 }
2450                 return (UU_WALK_NEXT);
2451         }
2452 
2453         if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2454             strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2455                 lcbdata->sc_general = p;
2456                 return (UU_WALK_NEXT);
2457         }
2458 
2459 add_pg:
2460         if (issvc)
2461                 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2462                     p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2463         else
2464                 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2465                     p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2466         if (r != 0) {
2467                 switch (scf_error()) {
2468                 case SCF_ERROR_DELETED:
2469                 case SCF_ERROR_CONNECTION_BROKEN:
2470                 case SCF_ERROR_BACKEND_READONLY:
2471                 case SCF_ERROR_BACKEND_ACCESS:
2472                 case SCF_ERROR_NO_RESOURCES:
2473                         return (stash_scferror(lcbdata));
2474 
2475                 case SCF_ERROR_EXISTS:
2476                         if (lcbdata->sc_flags & SCI_FORCE)
2477                                 break;
2478                         return (stash_scferror(lcbdata));
2479 
2480                 case SCF_ERROR_INVALID_ARGUMENT:
2481                         warn(emsg_fmri_invalid_pg_name_type,
2482                             lcbdata->sc_source_fmri,
2483                             p->sc_pgroup_name, p->sc_pgroup_type);
2484                         return (stash_scferror(lcbdata));
2485 
2486                 case SCF_ERROR_PERMISSION_DENIED:
2487                         warn(emsg_pg_add_perm, p->sc_pgroup_name,
2488                             lcbdata->sc_target_fmri);
2489                         return (stash_scferror(lcbdata));
2490 
2491                 case SCF_ERROR_NOT_BOUND:
2492                 case SCF_ERROR_HANDLE_MISMATCH:
2493                 case SCF_ERROR_NOT_SET:
2494                 default:
2495                         bad_error("scf_service_add_pg", scf_error());
2496                 }
2497 
2498                 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2499                         switch (scf_error()) {
2500                         case SCF_ERROR_CONNECTION_BROKEN:
2501                         case SCF_ERROR_DELETED:
2502                                 return (stash_scferror(lcbdata));
2503 
2504                         case SCF_ERROR_INVALID_ARGUMENT:
2505                                 warn(emsg_fmri_invalid_pg_name,
2506                                     lcbdata->sc_source_fmri,
2507                                     p->sc_pgroup_name);
2508                                 return (stash_scferror(lcbdata));
2509 
2510                         case SCF_ERROR_NOT_FOUND:
2511                                 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2512                                     p->sc_pgroup_name);
2513                                 lcbdata->sc_err = EBUSY;
2514                                 return (UU_WALK_ERROR);
2515 
2516                         case SCF_ERROR_NOT_BOUND:
2517                         case SCF_ERROR_HANDLE_MISMATCH:
2518                         case SCF_ERROR_NOT_SET:
2519                         default:
2520                                 bad_error("entity_get_pg", scf_error());
2521                         }
2522                 }
2523 
2524                 if (lcbdata->sc_flags & SCI_KEEP)
2525                         goto props;
2526 
2527 delete_pg:
2528                 if (scf_pg_delete(imp_pg) != 0) {
2529                         switch (scf_error()) {
2530                         case SCF_ERROR_DELETED:
2531                                 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2532                                     p->sc_pgroup_name);
2533                                 lcbdata->sc_err = EBUSY;
2534                                 return (UU_WALK_ERROR);
2535 
2536                         case SCF_ERROR_PERMISSION_DENIED:
2537                                 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2538                                     lcbdata->sc_target_fmri);
2539                                 return (stash_scferror(lcbdata));
2540 
2541                         case SCF_ERROR_BACKEND_READONLY:
2542                         case SCF_ERROR_BACKEND_ACCESS:
2543                         case SCF_ERROR_CONNECTION_BROKEN:
2544                                 return (stash_scferror(lcbdata));
2545 
2546                         case SCF_ERROR_NOT_SET:
2547                         default:
2548                                 bad_error("scf_pg_delete", scf_error());
2549                         }
2550                 }
2551 
2552                 if (p->sc_pgroup_delete)
2553                         return (UU_WALK_NEXT);
2554 
2555                 goto add_pg;
2556         }
2557 
2558 props:
2559 
2560         /*
2561          * Add properties to property group, if any.
2562          */
2563         cbdata.sc_handle = lcbdata->sc_handle;
2564         cbdata.sc_parent = imp_pg;
2565         cbdata.sc_flags = lcbdata->sc_flags;
2566         cbdata.sc_trans = imp_tx;
2567         cbdata.sc_enable = NULL;
2568 
2569         if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2570                 switch (scf_error()) {
2571                 case SCF_ERROR_BACKEND_ACCESS:
2572                 case SCF_ERROR_BACKEND_READONLY:
2573                 case SCF_ERROR_CONNECTION_BROKEN:
2574                         return (stash_scferror(lcbdata));
2575 
2576                 case SCF_ERROR_DELETED:
2577                         warn(pg_changed, lcbdata->sc_target_fmri,
2578                             p->sc_pgroup_name);
2579                         lcbdata->sc_err = EBUSY;
2580                         return (UU_WALK_ERROR);
2581 
2582                 case SCF_ERROR_PERMISSION_DENIED:
2583                         warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2584                             lcbdata->sc_target_fmri);
2585                         return (stash_scferror(lcbdata));
2586 
2587                 case SCF_ERROR_NOT_BOUND:
2588                 case SCF_ERROR_NOT_SET:
2589                 case SCF_ERROR_IN_USE:
2590                 case SCF_ERROR_HANDLE_MISMATCH:
2591                 default:
2592                         bad_error("scf_transaction_start", scf_error());
2593                 }
2594         }
2595 
2596         if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2597             UU_DEFAULT) != 0) {
2598                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2599                         bad_error("uu_list_walk", uu_error());
2600                 scf_transaction_reset(imp_tx);
2601 
2602                 lcbdata->sc_err = cbdata.sc_err;
2603                 if (cbdata.sc_err == ECANCELED) {
2604                         warn(pg_changed, lcbdata->sc_target_fmri,
2605                             p->sc_pgroup_name);
2606                         lcbdata->sc_err = EBUSY;
2607                 }
2608                 return (UU_WALK_ERROR);
2609         }
2610 
2611         if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2612                 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2613 
2614                 /*
2615                  * take the snapshot running snapshot then
2616                  * import the stored general/enable property
2617                  */
2618                 r = take_snap(ent, snap_running, imp_rsnap);
2619                 switch (r) {
2620                 case 0:
2621                         break;
2622 
2623                 case ECONNABORTED:
2624                         warn(gettext("Could not take %s snapshot on import "
2625                             "(repository connection broken).\n"),
2626                             snap_running);
2627                         lcbdata->sc_err = r;
2628                         return (UU_WALK_ERROR);
2629                 case ECANCELED:
2630                         warn(emsg_deleted);
2631                         lcbdata->sc_err = r;
2632                         return (UU_WALK_ERROR);
2633 
2634                 case EPERM:
2635                         warn(gettext("Could not take %s snapshot "
2636                             "(permission denied).\n"), snap_running);
2637                         lcbdata->sc_err = r;
2638                         return (UU_WALK_ERROR);
2639 
2640                 case ENOSPC:
2641                         warn(gettext("Could not take %s snapshot"
2642                             "(repository server out of resources).\n"),
2643                             snap_running);
2644                         lcbdata->sc_err = r;
2645                         return (UU_WALK_ERROR);
2646 
2647                 default:
2648                         bad_error("take_snap", r);
2649                 }
2650 
2651                 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2652                 if (r != UU_WALK_NEXT) {
2653                         if (r != UU_WALK_ERROR)
2654                                 bad_error("lscf_property_import", r);
2655                         return (EINVAL);
2656                 }
2657         }
2658 
2659         r = scf_transaction_commit(imp_tx);
2660         switch (r) {
2661         case 1:
2662                 r = UU_WALK_NEXT;
2663                 break;
2664 
2665         case 0:
2666                 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2667                 lcbdata->sc_err = EBUSY;
2668                 r = UU_WALK_ERROR;
2669                 break;
2670 
2671         case -1:
2672                 switch (scf_error()) {
2673                 case SCF_ERROR_BACKEND_READONLY:
2674                 case SCF_ERROR_BACKEND_ACCESS:
2675                 case SCF_ERROR_CONNECTION_BROKEN:
2676                 case SCF_ERROR_NO_RESOURCES:
2677                         r = stash_scferror(lcbdata);
2678                         break;
2679 
2680                 case SCF_ERROR_DELETED:
2681                         warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2682                             p->sc_pgroup_name);
2683                         lcbdata->sc_err = EBUSY;
2684                         r = UU_WALK_ERROR;
2685                         break;
2686 
2687                 case SCF_ERROR_PERMISSION_DENIED:
2688                         warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2689                             lcbdata->sc_target_fmri);
2690                         r = stash_scferror(lcbdata);
2691                         break;
2692 
2693                 case SCF_ERROR_NOT_SET:
2694                 case SCF_ERROR_INVALID_ARGUMENT:
2695                 case SCF_ERROR_NOT_BOUND:
2696                 default:
2697                         bad_error("scf_transaction_commit", scf_error());
2698                 }
2699                 break;
2700 
2701         default:
2702                 bad_error("scf_transaction_commit", r);
2703         }
2704 
2705         scf_transaction_destroy_children(imp_tx);
2706 
2707         return (r);
2708 }
2709 
2710 /*
2711  * Returns
2712  *   0 - success
2713  *   ECONNABORTED - repository connection broken
2714  *   ENOMEM - out of memory
2715  *   ENOSPC - svc.configd is out of resources
2716  *   ECANCELED - inst was deleted
2717  *   EPERM - could not create property group (permission denied) (error printed)
2718  *         - could not modify property group (permission denied) (error printed)
2719  *   EROFS - could not create property group (repository is read-only)
2720  *   EACCES - could not create property group (backend access denied)
2721  *   EEXIST - could not create property group (already exists)
2722  *   EINVAL - invalid property group name (error printed)
2723  *          - invalid property name (error printed)
2724  *          - invalid value (error printed)
2725  *   EBUSY - new property group changed (error printed)
2726  */
2727 static int
2728 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2729     const entity_t *isvc, int flags)
2730 {
2731         scf_callback_t cbdata;
2732 
2733         cbdata.sc_handle = scf_service_handle(svc);
2734         cbdata.sc_parent = svc;
2735         cbdata.sc_service = 1;
2736         cbdata.sc_general = 0;
2737         cbdata.sc_enable = 0;
2738         cbdata.sc_flags = flags;
2739         cbdata.sc_source_fmri = isvc->sc_fmri;
2740         cbdata.sc_target_fmri = target_fmri;
2741 
2742         /*
2743          * If the op is set, then add the flag to the callback
2744          * flags for later use.
2745          */
2746         if (isvc->sc_op != SVCCFG_OP_NONE) {
2747                 switch (isvc->sc_op) {
2748                 case SVCCFG_OP_IMPORT :
2749                         cbdata.sc_flags |= SCI_OP_IMPORT;
2750                         break;
2751                 case SVCCFG_OP_APPLY :
2752                         cbdata.sc_flags |= SCI_OP_APPLY;
2753                         break;
2754                 case SVCCFG_OP_RESTORE :
2755                         cbdata.sc_flags |= SCI_OP_RESTORE;
2756                         break;
2757                 default :
2758                         uu_die(gettext("lscf_import_service_pgs : "
2759                             "Unknown op stored in the service entity\n"));
2760 
2761                 }
2762         }
2763 
2764         if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2765             UU_DEFAULT) != 0) {
2766                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2767                         bad_error("uu_list_walk", uu_error());
2768 
2769                 return (cbdata.sc_err);
2770         }
2771 
2772         return (0);
2773 }
2774 
2775 /*
2776  * Returns
2777  *   0 - success
2778  *   ECONNABORTED - repository connection broken
2779  *   ENOMEM - out of memory
2780  *   ENOSPC - svc.configd is out of resources
2781  *   ECANCELED - inst was deleted
2782  *   EPERM - could not create property group (permission denied) (error printed)
2783  *         - could not modify property group (permission denied) (error printed)
2784  *   EROFS - could not create property group (repository is read-only)
2785  *   EACCES - could not create property group (backend access denied)
2786  *   EEXIST - could not create property group (already exists)
2787  *   EINVAL - invalid property group name (error printed)
2788  *          - invalid property name (error printed)
2789  *          - invalid value (error printed)
2790  *   EBUSY - new property group changed (error printed)
2791  */
2792 static int
2793 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2794     const entity_t *iinst, int flags)
2795 {
2796         scf_callback_t cbdata;
2797 
2798         cbdata.sc_handle = scf_instance_handle(inst);
2799         cbdata.sc_parent = inst;
2800         cbdata.sc_service = 0;
2801         cbdata.sc_general = NULL;
2802         cbdata.sc_enable = NULL;
2803         cbdata.sc_flags = flags;
2804         cbdata.sc_source_fmri = iinst->sc_fmri;
2805         cbdata.sc_target_fmri = target_fmri;
2806 
2807         /*
2808          * If the op is set, then add the flag to the callback
2809          * flags for later use.
2810          */
2811         if (iinst->sc_op != SVCCFG_OP_NONE) {
2812                 switch (iinst->sc_op) {
2813                 case SVCCFG_OP_IMPORT :
2814                         cbdata.sc_flags |= SCI_OP_IMPORT;
2815                         break;
2816                 case SVCCFG_OP_APPLY :
2817                         cbdata.sc_flags |= SCI_OP_APPLY;
2818                         break;
2819                 case SVCCFG_OP_RESTORE :
2820                         cbdata.sc_flags |= SCI_OP_RESTORE;
2821                         break;
2822                 default :
2823                         uu_die(gettext("lscf_import_instance_pgs : "
2824                             "Unknown op stored in the instance entity\n"));
2825                 }
2826         }
2827 
2828         if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2829             UU_DEFAULT) != 0) {
2830                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2831                         bad_error("uu_list_walk", uu_error());
2832 
2833                 return (cbdata.sc_err);
2834         }
2835 
2836         if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2837                 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2838                 /*
2839                  * If importing with the SCI_NOENABLED flag then
2840                  * skip the delay, but if not then add the delay
2841                  * of the enable property.
2842                  */
2843                 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2844                         cbdata.sc_flags |= SCI_DELAYENABLE;
2845                 }
2846 
2847                 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2848                     != UU_WALK_NEXT)
2849                         return (cbdata.sc_err);
2850         }
2851 
2852         return (0);
2853 }
2854 
2855 /*
2856  * Report the reasons why we can't upgrade pg2 to pg1.
2857  */
2858 static void
2859 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2860     int new)
2861 {
2862         property_t *p1, *p2;
2863 
2864         assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2865 
2866         if (!pg_attrs_equal(pg1, pg2, fmri, new))
2867                 return;
2868 
2869         for (p1 = uu_list_first(pg1->sc_pgroup_props);
2870             p1 != NULL;
2871             p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2872                 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2873                 if (p2 != NULL) {
2874                         (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2875                             new);
2876                         continue;
2877                 }
2878 
2879                 if (new)
2880                         warn(gettext("Conflict upgrading %s (new property "
2881                             "group \"%s\" is missing property \"%s\").\n"),
2882                             fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2883                 else
2884                         warn(gettext("Conflict upgrading %s (property "
2885                             "\"%s/%s\" is missing).\n"), fmri,
2886                             pg1->sc_pgroup_name, p1->sc_property_name);
2887         }
2888 
2889         /*
2890          * Since pg1 should be from the manifest, any properties in pg2 which
2891          * aren't in pg1 shouldn't be reported as conflicts.
2892          */
2893 }
2894 
2895 /*
2896  * Add transaction entries to tx which will upgrade cur's pg according to old
2897  * & new.
2898  *
2899  * Returns
2900  *   0 - success
2901  *   EINVAL - new has a property with an invalid name or value (message emitted)
2902  *   ENOMEM - out of memory
2903  */
2904 static int
2905 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2906     pgroup_t *cur, int speak, const char *fmri)
2907 {
2908         property_t *p, *new_p, *cur_p;
2909         scf_transaction_entry_t *e;
2910         int r;
2911         int is_general;
2912         int is_protected;
2913 
2914         if (uu_list_walk(new->sc_pgroup_props, clear_int,
2915             (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2916                 bad_error("uu_list_walk", uu_error());
2917 
2918         is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2919 
2920         for (p = uu_list_first(old->sc_pgroup_props);
2921             p != NULL;
2922             p = uu_list_next(old->sc_pgroup_props, p)) {
2923                 /* p is a property in the old property group. */
2924 
2925                 /* Protect live properties. */
2926                 is_protected = 0;
2927                 if (is_general) {
2928                         if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2929                             0 ||
2930                             strcmp(p->sc_property_name,
2931                             SCF_PROPERTY_RESTARTER) == 0)
2932                                 is_protected = 1;
2933                 }
2934 
2935                 /* Look for the same property in the new properties. */
2936                 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2937                 if (new_p != NULL) {
2938                         new_p->sc_seen = 1;
2939 
2940                         /*
2941                          * If the new property is the same as the old, don't do
2942                          * anything (leave any user customizations).
2943                          */
2944                         if (prop_equal(p, new_p, NULL, NULL, 0))
2945                                 continue;
2946 
2947                         if (new_p->sc_property_override)
2948                                 goto upgrade;
2949                 }
2950 
2951                 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2952                 if (cur_p == NULL) {
2953                         /*
2954                          * p has been deleted from the repository.  If we were
2955                          * going to delete it anyway, do nothing.  Otherwise
2956                          * report a conflict.
2957                          */
2958                         if (new_p == NULL)
2959                                 continue;
2960 
2961                         if (is_protected)
2962                                 continue;
2963 
2964                         warn(gettext("Conflict upgrading %s "
2965                             "(property \"%s/%s\" is missing).\n"), fmri,
2966                             old->sc_pgroup_name, p->sc_property_name);
2967                         continue;
2968                 }
2969 
2970                 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2971                         /*
2972                          * Conflict.  Don't warn if the property is already the
2973                          * way we want it, though.
2974                          */
2975                         if (is_protected)
2976                                 continue;
2977 
2978                         if (new_p == NULL)
2979                                 (void) prop_equal(p, cur_p, fmri,
2980                                     old->sc_pgroup_name, 0);
2981                         else
2982                                 (void) prop_equal(cur_p, new_p, fmri,
2983                                     old->sc_pgroup_name, 0);
2984                         continue;
2985                 }
2986 
2987                 if (is_protected) {
2988                         if (speak)
2989                                 warn(gettext("%s: Refusing to upgrade "
2990                                     "\"%s/%s\" (live property).\n"), fmri,
2991                                     old->sc_pgroup_name, p->sc_property_name);
2992                         continue;
2993                 }
2994 
2995 upgrade:
2996                 /* p hasn't been customized in the repository.  Upgrade it. */
2997                 if (new_p == NULL) {
2998                         /* p was deleted.  Delete from cur if unchanged. */
2999                         if (speak)
3000                                 warn(gettext(
3001                                     "%s: Deleting property \"%s/%s\".\n"),
3002                                     fmri, old->sc_pgroup_name,
3003                                     p->sc_property_name);
3004 
3005                         e = scf_entry_create(g_hndl);
3006                         if (e == NULL)
3007                                 return (ENOMEM);
3008 
3009                         if (scf_transaction_property_delete(tx, e,
3010                             p->sc_property_name) != 0) {
3011                                 switch (scf_error()) {
3012                                 case SCF_ERROR_DELETED:
3013                                         scf_entry_destroy(e);
3014                                         return (ECANCELED);
3015 
3016                                 case SCF_ERROR_CONNECTION_BROKEN:
3017                                         scf_entry_destroy(e);
3018                                         return (ECONNABORTED);
3019 
3020                                 case SCF_ERROR_NOT_FOUND:
3021                                         /*
3022                                          * This can happen if cur is from the
3023                                          * running snapshot (and it differs
3024                                          * from the live properties).
3025                                          */
3026                                         scf_entry_destroy(e);
3027                                         break;
3028 
3029                                 case SCF_ERROR_HANDLE_MISMATCH:
3030                                 case SCF_ERROR_NOT_BOUND:
3031                                 case SCF_ERROR_NOT_SET:
3032                                 case SCF_ERROR_INVALID_ARGUMENT:
3033                                 default:
3034                                         bad_error(
3035                                             "scf_transaction_property_delete",
3036                                             scf_error());
3037                                 }
3038                         }
3039                 } else {
3040                         scf_callback_t ctx;
3041 
3042                         if (speak)
3043                                 warn(gettext(
3044                                     "%s: Upgrading property \"%s/%s\".\n"),
3045                                     fmri, old->sc_pgroup_name,
3046                                     p->sc_property_name);
3047 
3048                         ctx.sc_handle = g_hndl;
3049                         ctx.sc_trans = tx;
3050                         ctx.sc_flags = 0;
3051 
3052                         r = lscf_property_import(new_p, &ctx);
3053                         if (r != UU_WALK_NEXT) {
3054                                 if (r != UU_WALK_ERROR)
3055                                         bad_error("lscf_property_import", r);
3056                                 return (EINVAL);
3057                         }
3058                 }
3059         }
3060 
3061         /* Go over the properties which were added. */
3062         for (new_p = uu_list_first(new->sc_pgroup_props);
3063             new_p != NULL;
3064             new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3065                 if (new_p->sc_seen)
3066                         continue;
3067 
3068                 /* This is a new property. */
3069                 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3070                 if (cur_p == NULL) {
3071                         scf_callback_t ctx;
3072 
3073                         ctx.sc_handle = g_hndl;
3074                         ctx.sc_trans = tx;
3075                         ctx.sc_flags = 0;
3076 
3077                         r = lscf_property_import(new_p, &ctx);
3078                         if (r != UU_WALK_NEXT) {
3079                                 if (r != UU_WALK_ERROR)
3080                                         bad_error("lscf_property_import", r);
3081                                 return (EINVAL);
3082                         }
3083                         continue;
3084                 }
3085 
3086                 /*
3087                  * Report a conflict if the new property differs from the
3088                  * current one.  Unless it's general/enabled, since that's
3089                  * never in the last-import snapshot.
3090                  */
3091                 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3092                     0 &&
3093                     strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3094                         continue;
3095 
3096                 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3097         }
3098 
3099         return (0);
3100 }
3101 
3102 /*
3103  * Upgrade pg according to old & new.
3104  *
3105  * Returns
3106  *   0 - success
3107  *   ECONNABORTED - repository connection broken
3108  *   ENOMEM - out of memory
3109  *   ENOSPC - svc.configd is out of resources
3110  *   ECANCELED - pg was deleted
3111  *   EPERM - couldn't modify pg (permission denied)
3112  *   EROFS - couldn't modify pg (backend read-only)
3113  *   EACCES - couldn't modify pg (backend access denied)
3114  *   EINVAL - new has a property with invalid name or value (error printed)
3115  *   EBUSY - pg changed unexpectedly
3116  */
3117 static int
3118 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3119     pgroup_t *new, int speak, const char *fmri)
3120 {
3121         int r;
3122 
3123         if (scf_transaction_start(imp_tx, pg) != 0) {
3124                 switch (scf_error()) {
3125                 case SCF_ERROR_CONNECTION_BROKEN:
3126                 case SCF_ERROR_DELETED:
3127                 case SCF_ERROR_PERMISSION_DENIED:
3128                 case SCF_ERROR_BACKEND_READONLY:
3129                 case SCF_ERROR_BACKEND_ACCESS:
3130                         return (scferror2errno(scf_error()));
3131 
3132                 case SCF_ERROR_HANDLE_MISMATCH:
3133                 case SCF_ERROR_IN_USE:
3134                 case SCF_ERROR_NOT_BOUND:
3135                 case SCF_ERROR_NOT_SET:
3136                 default:
3137                         bad_error("scf_transaction_start", scf_error());
3138                 }
3139         }
3140 
3141         r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3142         switch (r) {
3143         case 0:
3144                 break;
3145 
3146         case EINVAL:
3147         case ENOMEM:
3148                 scf_transaction_destroy_children(imp_tx);
3149                 return (r);
3150 
3151         default:
3152                 bad_error("add_upgrade_entries", r);
3153         }
3154 
3155         r = scf_transaction_commit(imp_tx);
3156 
3157         scf_transaction_destroy_children(imp_tx);
3158 
3159         switch (r) {
3160         case 1:
3161                 break;
3162 
3163         case 0:
3164                 return (EBUSY);
3165 
3166         case -1:
3167                 switch (scf_error()) {
3168                 case SCF_ERROR_CONNECTION_BROKEN:
3169                 case SCF_ERROR_NO_RESOURCES:
3170                 case SCF_ERROR_PERMISSION_DENIED:
3171                 case SCF_ERROR_BACKEND_READONLY:
3172                 case SCF_ERROR_BACKEND_ACCESS:
3173                 case SCF_ERROR_DELETED:
3174                         return (scferror2errno(scf_error()));
3175 
3176                 case SCF_ERROR_NOT_BOUND:
3177                 case SCF_ERROR_INVALID_ARGUMENT:
3178                 case SCF_ERROR_NOT_SET:
3179                 default:
3180                         bad_error("scf_transaction_commit", scf_error());
3181                 }
3182 
3183         default:
3184                 bad_error("scf_transaction_commit", r);
3185         }
3186 
3187         return (0);
3188 }
3189 
3190 /*
3191  * Compares two entity FMRIs.  Returns
3192  *
3193  *   1 - equal
3194  *   0 - not equal
3195  *   -1 - f1 is invalid or not an entity
3196  *   -2 - f2 is invalid or not an entity
3197  */
3198 static int
3199 fmri_equal(const char *f1, const char *f2)
3200 {
3201         int r;
3202         const char *s1, *i1, *pg1;
3203         const char *s2, *i2, *pg2;
3204 
3205         if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3206                 return (-1);
3207         if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3208                 return (-1);
3209 
3210         if (s1 == NULL || pg1 != NULL)
3211                 return (-1);
3212 
3213         if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3214                 return (-2);
3215         if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3216                 return (-2);
3217 
3218         if (s2 == NULL || pg2 != NULL)
3219                 return (-2);
3220 
3221         r = strcmp(s1, s2);
3222         if (r != 0)
3223                 return (0);
3224 
3225         if (i1 == NULL && i2 == NULL)
3226                 return (1);
3227 
3228         if (i1 == NULL || i2 == NULL)
3229                 return (0);
3230 
3231         return (strcmp(i1, i2) == 0);
3232 }
3233 
3234 /*
3235  * Import a dependent by creating a dependency property group in the dependent
3236  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3237  * dependents pg, and add an entry to create a new property for this
3238  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3239  *
3240  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3241  * lcbdata->sc_err to
3242  *   ECONNABORTED - repository connection broken
3243  *   ENOMEM - out of memory
3244  *   ENOSPC - configd is out of resources
3245  *   EINVAL - target is invalid (error printed)
3246  *          - target is not an entity (error printed)
3247  *          - dependent has invalid name (error printed)
3248  *          - invalid property name (error printed)
3249  *          - invalid value (error printed)
3250  *          - scope of target does not exist (error printed)
3251  *   EPERM - couldn't create target (permission denied) (error printed)
3252  *         - couldn't create dependency pg (permission denied) (error printed)
3253  *         - couldn't modify dependency pg (permission denied) (error printed)
3254  *   EROFS - couldn't create target (repository read-only)
3255  *         - couldn't create dependency pg (repository read-only)
3256  *   EACCES - couldn't create target (backend access denied)
3257  *          - couldn't create dependency pg (backend access denied)
3258  *   ECANCELED - sc_trans's pg was deleted
3259  *   EALREADY - property for dependent already exists in sc_trans's pg
3260  *   EEXIST - dependency pg already exists in target (error printed)
3261  *   EBUSY - target deleted (error printed)
3262  *         - property group changed during import (error printed)
3263  */
3264 static int
3265 lscf_dependent_import(void *a1, void *pvt)
3266 {
3267         pgroup_t *pgrp = a1;
3268         scf_callback_t *lcbdata = pvt;
3269 
3270         int isservice;
3271         int ret;
3272         scf_transaction_entry_t *e;
3273         scf_value_t *val;
3274         scf_callback_t dependent_cbdata;
3275         scf_error_t scfe;
3276 
3277         /*
3278          * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3279          * it's invalid, we fail before modifying the repository.
3280          */
3281         scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3282             &dependent_cbdata.sc_parent, &isservice);
3283         switch (scfe) {
3284         case SCF_ERROR_NONE:
3285                 break;
3286 
3287         case SCF_ERROR_NO_MEMORY:
3288                 return (stash_scferror_err(lcbdata, scfe));
3289 
3290         case SCF_ERROR_INVALID_ARGUMENT:
3291                 semerr(gettext("The FMRI for the \"%s\" dependent is "
3292                     "invalid.\n"), pgrp->sc_pgroup_name);
3293                 return (stash_scferror_err(lcbdata, scfe));
3294 
3295         case SCF_ERROR_CONSTRAINT_VIOLATED:
3296                 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3297                     "specifies neither a service nor an instance.\n"),
3298                     pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3299                 return (stash_scferror_err(lcbdata, scfe));
3300 
3301         case SCF_ERROR_NOT_FOUND:
3302                 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3303                     &dependent_cbdata.sc_parent, &isservice);
3304                 switch (scfe) {
3305                 case SCF_ERROR_NONE:
3306                         break;
3307 
3308                 case SCF_ERROR_NO_MEMORY:
3309                 case SCF_ERROR_BACKEND_READONLY:
3310                 case SCF_ERROR_BACKEND_ACCESS:
3311                         return (stash_scferror_err(lcbdata, scfe));
3312 
3313                 case SCF_ERROR_NOT_FOUND:
3314                         semerr(gettext("The scope in FMRI \"%s\" for the "
3315                             "\"%s\" dependent does not exist.\n"),
3316                             pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3317                         lcbdata->sc_err = EINVAL;
3318                         return (UU_WALK_ERROR);
3319 
3320                 case SCF_ERROR_PERMISSION_DENIED:
3321                         warn(gettext(
3322                             "Could not create %s (permission denied).\n"),
3323                             pgrp->sc_pgroup_fmri);
3324                         return (stash_scferror_err(lcbdata, scfe));
3325 
3326                 case SCF_ERROR_INVALID_ARGUMENT:
3327                 case SCF_ERROR_CONSTRAINT_VIOLATED:
3328                 default:
3329                         bad_error("create_entity", scfe);
3330                 }
3331                 break;
3332 
3333         default:
3334                 bad_error("fmri_to_entity", scfe);
3335         }
3336 
3337         if (lcbdata->sc_trans != NULL) {
3338                 e = scf_entry_create(lcbdata->sc_handle);
3339                 if (e == NULL) {
3340                         if (scf_error() != SCF_ERROR_NO_MEMORY)
3341                                 bad_error("scf_entry_create", scf_error());
3342 
3343                         entity_destroy(dependent_cbdata.sc_parent, isservice);
3344                         return (stash_scferror(lcbdata));
3345                 }
3346 
3347                 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3348                     pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3349                         switch (scf_error()) {
3350                         case SCF_ERROR_INVALID_ARGUMENT:
3351                                 warn(gettext("Dependent of %s has invalid name "
3352                                     "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3353                                     pgrp->sc_pgroup_name);
3354                                 /* FALLTHROUGH */
3355 
3356                         case SCF_ERROR_DELETED:
3357                         case SCF_ERROR_CONNECTION_BROKEN:
3358                                 scf_entry_destroy(e);
3359                                 entity_destroy(dependent_cbdata.sc_parent,
3360                                     isservice);
3361                                 return (stash_scferror(lcbdata));
3362 
3363                         case SCF_ERROR_EXISTS:
3364                                 scf_entry_destroy(e);
3365                                 entity_destroy(dependent_cbdata.sc_parent,
3366                                     isservice);
3367                                 lcbdata->sc_err = EALREADY;
3368                                 return (UU_WALK_ERROR);
3369 
3370                         case SCF_ERROR_NOT_BOUND:
3371                         case SCF_ERROR_HANDLE_MISMATCH:
3372                         case SCF_ERROR_NOT_SET:
3373                         default:
3374                                 bad_error("scf_transaction_property_new",
3375                                     scf_error());
3376                         }
3377                 }
3378 
3379                 val = scf_value_create(lcbdata->sc_handle);
3380                 if (val == NULL) {
3381                         if (scf_error() != SCF_ERROR_NO_MEMORY)
3382                                 bad_error("scf_value_create", scf_error());
3383 
3384                         entity_destroy(dependent_cbdata.sc_parent, isservice);
3385                         return (stash_scferror(lcbdata));
3386                 }
3387 
3388                 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3389                     pgrp->sc_pgroup_fmri) != 0)
3390                         /* invalid should have been caught above */
3391                         bad_error("scf_value_set_from_string", scf_error());
3392 
3393                 if (scf_entry_add_value(e, val) != 0)
3394                         bad_error("scf_entry_add_value", scf_error());
3395         }
3396 
3397         /* Add the property group to the target entity. */
3398 
3399         dependent_cbdata.sc_handle = lcbdata->sc_handle;
3400         dependent_cbdata.sc_flags = lcbdata->sc_flags;
3401         dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3402         dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3403 
3404         ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3405 
3406         entity_destroy(dependent_cbdata.sc_parent, isservice);
3407 
3408         if (ret == UU_WALK_NEXT)
3409                 return (ret);
3410 
3411         if (ret != UU_WALK_ERROR)
3412                 bad_error("entity_pgroup_import", ret);
3413 
3414         switch (dependent_cbdata.sc_err) {
3415         case ECANCELED:
3416                 warn(gettext("%s deleted unexpectedly.\n"),
3417                     pgrp->sc_pgroup_fmri);
3418                 lcbdata->sc_err = EBUSY;
3419                 break;
3420 
3421         case EEXIST:
3422                 warn(gettext("Could not create \"%s\" dependency in %s "
3423                     "(already exists).\n"), pgrp->sc_pgroup_name,
3424                     pgrp->sc_pgroup_fmri);
3425                 /* FALLTHROUGH */
3426 
3427         default:
3428                 lcbdata->sc_err = dependent_cbdata.sc_err;
3429         }
3430 
3431         return (UU_WALK_ERROR);
3432 }
3433 
3434 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3435     const scf_snaplevel_t *, scf_transaction_t *);
3436 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3437     const pgroup_t *);
3438 
3439 /*
3440  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3441  * the current dependent targets from running (the snaplevel of a running
3442  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3443  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3444  * dependent targets and dependency properties from li_dpts_pg (the
3445  * "dependents" property group in snpl) and snpl (the snaplevel which
3446  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3447  * snpl doesn't have a "dependents" property group, and any dependents in ient
3448  * are new.
3449  *
3450  * Returns
3451  *   0 - success
3452  *   ECONNABORTED - repository connection broken
3453  *   ENOMEM - out of memory
3454  *   ENOSPC - configd is out of resources
3455  *   ECANCELED - ent was deleted
3456  *   ENODEV - the entity containing li_dpts_pg was deleted
3457  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3458  *         - couldn't upgrade dependent (permission denied) (error printed)
3459  *         - couldn't create dependent (permission denied) (error printed)
3460  *   EROFS - could not modify dependents pg (repository read-only)
3461  *         - couldn't upgrade dependent (repository read-only)
3462  *         - couldn't create dependent (repository read-only)
3463  *   EACCES - could not modify dependents pg (backend access denied)
3464  *          - could not upgrade dependent (backend access denied)
3465  *          - could not create dependent (backend access denied)
3466  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3467  *         - dependent target deleted (error printed)
3468  *         - dependent pg changed (error printed)
3469  *   EINVAL - new dependent is invalid (error printed)
3470  *   EBADF - snpl is corrupt (error printed)
3471  *         - snpl has corrupt pg (error printed)
3472  *         - dependency pg in target is corrupt (error printed)
3473  *         - target has corrupt snapshot (error printed)
3474  *   EEXIST - dependency pg already existed in target service (error printed)
3475  */
3476 static int
3477 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3478     const scf_snaplevel_t *snpl, const entity_t *ient,
3479     const scf_snaplevel_t *running, void *ent)
3480 {
3481         pgroup_t *new_dpt_pgroup;
3482         scf_callback_t cbdata;
3483         int r, unseen, tx_started = 0;
3484         int have_cur_depts;
3485 
3486         const char * const dependents = "dependents";
3487 
3488         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3489 
3490         if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3491                 /* Nothing to do. */
3492                 return (0);
3493 
3494         /* Fetch the current version of the "dependents" property group. */
3495         have_cur_depts = 1;
3496         if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3497                 switch (scf_error()) {
3498                 case SCF_ERROR_NOT_FOUND:
3499                         break;
3500 
3501                 case SCF_ERROR_DELETED:
3502                 case SCF_ERROR_CONNECTION_BROKEN:
3503                         return (scferror2errno(scf_error()));
3504 
3505                 case SCF_ERROR_NOT_SET:
3506                 case SCF_ERROR_INVALID_ARGUMENT:
3507                 case SCF_ERROR_HANDLE_MISMATCH:
3508                 case SCF_ERROR_NOT_BOUND:
3509                 default:
3510                         bad_error("entity_get_pg", scf_error());
3511                 }
3512 
3513                 have_cur_depts = 0;
3514         }
3515 
3516         /* Fetch the running version of the "dependents" property group. */
3517         ud_run_dpts_pg_set = 0;
3518         if (running != NULL)
3519                 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3520         else
3521                 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3522         if (r == 0) {
3523                 ud_run_dpts_pg_set = 1;
3524         } else {
3525                 switch (scf_error()) {
3526                 case SCF_ERROR_NOT_FOUND:
3527                         break;
3528 
3529                 case SCF_ERROR_DELETED:
3530                 case SCF_ERROR_CONNECTION_BROKEN:
3531                         return (scferror2errno(scf_error()));
3532 
3533                 case SCF_ERROR_NOT_SET:
3534                 case SCF_ERROR_INVALID_ARGUMENT:
3535                 case SCF_ERROR_HANDLE_MISMATCH:
3536                 case SCF_ERROR_NOT_BOUND:
3537                 default:
3538                         bad_error(running ? "scf_snaplevel_get_pg" :
3539                             "entity_get_pg", scf_error());
3540                 }
3541         }
3542 
3543         /*
3544          * Clear the seen fields of the dependents, so we can tell which ones
3545          * are new.
3546          */
3547         if (uu_list_walk(ient->sc_dependents, clear_int,
3548             (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3549                 bad_error("uu_list_walk", uu_error());
3550 
3551         if (li_dpts_pg != NULL) {
3552                 /*
3553                  * Each property in li_dpts_pg represents a dependent tag in
3554                  * the old manifest.  For each, call upgrade_dependent(),
3555                  * which will change ud_cur_depts_pg or dependencies in other
3556                  * services as appropriate.  Note (a) that changes to
3557                  * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3558                  * made en masse, and (b) it's ok if the entity doesn't have
3559                  * a current version of the "dependents" property group,
3560                  * because we'll just consider all dependents as customized
3561                  * (by being deleted).
3562                  */
3563 
3564                 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3565                         switch (scf_error()) {
3566                         case SCF_ERROR_DELETED:
3567                                 return (ENODEV);
3568 
3569                         case SCF_ERROR_CONNECTION_BROKEN:
3570                                 return (ECONNABORTED);
3571 
3572                         case SCF_ERROR_HANDLE_MISMATCH:
3573                         case SCF_ERROR_NOT_BOUND:
3574                         case SCF_ERROR_NOT_SET:
3575                         default:
3576                                 bad_error("scf_iter_pg_properties",
3577                                     scf_error());
3578                         }
3579                 }
3580 
3581                 if (have_cur_depts &&
3582                     scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3583                         switch (scf_error()) {
3584                         case SCF_ERROR_BACKEND_ACCESS:
3585                         case SCF_ERROR_BACKEND_READONLY:
3586                         case SCF_ERROR_CONNECTION_BROKEN:
3587                                 return (scferror2errno(scf_error()));
3588 
3589                         case SCF_ERROR_DELETED:
3590                                 warn(emsg_pg_deleted, ient->sc_fmri,
3591                                     dependents);
3592                                 return (EBUSY);
3593 
3594                         case SCF_ERROR_PERMISSION_DENIED:
3595                                 warn(emsg_pg_mod_perm, dependents,
3596                                     ient->sc_fmri);
3597                                 return (scferror2errno(scf_error()));
3598 
3599                         case SCF_ERROR_HANDLE_MISMATCH:
3600                         case SCF_ERROR_IN_USE:
3601                         case SCF_ERROR_NOT_BOUND:
3602                         case SCF_ERROR_NOT_SET:
3603                         default:
3604                                 bad_error("scf_transaction_start", scf_error());
3605                         }
3606                 }
3607                 tx_started = have_cur_depts;
3608 
3609                 for (;;) {
3610                         r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3611                         if (r == 0)
3612                                 break;
3613                         if (r == 1) {
3614                                 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3615                                     tx_started ? ud_tx : NULL);
3616                                 switch (r) {
3617                                 case 0:
3618                                         continue;
3619 
3620                                 case ECONNABORTED:
3621                                 case ENOMEM:
3622                                 case ENOSPC:
3623                                 case EBADF:
3624                                 case EBUSY:
3625                                 case EINVAL:
3626                                 case EPERM:
3627                                 case EROFS:
3628                                 case EACCES:
3629                                 case EEXIST:
3630                                         break;
3631 
3632                                 case ECANCELED:
3633                                         r = ENODEV;
3634                                         break;
3635 
3636                                 default:
3637                                         bad_error("upgrade_dependent", r);
3638                                 }
3639 
3640                                 if (tx_started)
3641                                         scf_transaction_destroy_children(ud_tx);
3642                                 return (r);
3643                         }
3644                         if (r != -1)
3645                                 bad_error("scf_iter_next_property", r);
3646 
3647                         switch (scf_error()) {
3648                         case SCF_ERROR_DELETED:
3649                                 r = ENODEV;
3650                                 break;
3651 
3652                         case SCF_ERROR_CONNECTION_BROKEN:
3653                                 r = ECONNABORTED;
3654                                 break;
3655 
3656                         case SCF_ERROR_NOT_SET:
3657                         case SCF_ERROR_INVALID_ARGUMENT:
3658                         case SCF_ERROR_NOT_BOUND:
3659                         case SCF_ERROR_HANDLE_MISMATCH:
3660                         default:
3661                                 bad_error("scf_iter_next_property",
3662                                     scf_error());
3663                         }
3664 
3665                         if (tx_started)
3666                                 scf_transaction_destroy_children(ud_tx);
3667                         return (r);
3668                 }
3669         }
3670 
3671         /* import unseen dependents */
3672         unseen = 0;
3673         for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3674             new_dpt_pgroup != NULL;
3675             new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3676             new_dpt_pgroup)) {
3677                 if (!new_dpt_pgroup->sc_pgroup_seen) {
3678                         unseen = 1;
3679                         break;
3680                 }
3681         }
3682 
3683         /* If there are none, exit early. */
3684         if (unseen == 0)
3685                 goto commit;
3686 
3687         /* Set up for lscf_dependent_import() */
3688         cbdata.sc_handle = g_hndl;
3689         cbdata.sc_parent = ent;
3690         cbdata.sc_service = issvc;
3691         cbdata.sc_flags = 0;
3692 
3693         if (!have_cur_depts) {
3694                 /*
3695                  * We have new dependents to import, so we need a "dependents"
3696                  * property group.
3697                  */
3698                 if (issvc)
3699                         r = scf_service_add_pg(ent, dependents,
3700                             SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3701                 else
3702                         r = scf_instance_add_pg(ent, dependents,
3703                             SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3704                 if (r != 0) {
3705                         switch (scf_error()) {
3706                         case SCF_ERROR_DELETED:
3707                         case SCF_ERROR_CONNECTION_BROKEN:
3708                         case SCF_ERROR_BACKEND_READONLY:
3709                         case SCF_ERROR_BACKEND_ACCESS:
3710                         case SCF_ERROR_NO_RESOURCES:
3711                                 return (scferror2errno(scf_error()));
3712 
3713                         case SCF_ERROR_EXISTS:
3714                                 warn(emsg_pg_added, ient->sc_fmri, dependents);
3715                                 return (EBUSY);
3716 
3717                         case SCF_ERROR_PERMISSION_DENIED:
3718                                 warn(emsg_pg_add_perm, dependents,
3719                                     ient->sc_fmri);
3720                                 return (scferror2errno(scf_error()));
3721 
3722                         case SCF_ERROR_NOT_BOUND:
3723                         case SCF_ERROR_HANDLE_MISMATCH:
3724                         case SCF_ERROR_INVALID_ARGUMENT:
3725                         case SCF_ERROR_NOT_SET:
3726                         default:
3727                                 bad_error("scf_service_add_pg", scf_error());
3728                         }
3729                 }
3730         }
3731 
3732         cbdata.sc_trans = ud_tx;
3733 
3734         if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3735                 switch (scf_error()) {
3736                 case SCF_ERROR_CONNECTION_BROKEN:
3737                 case SCF_ERROR_BACKEND_ACCESS:
3738                 case SCF_ERROR_BACKEND_READONLY:
3739                         return (scferror2errno(scf_error()));
3740 
3741                 case SCF_ERROR_DELETED:
3742                         warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3743                         return (EBUSY);
3744 
3745                 case SCF_ERROR_PERMISSION_DENIED:
3746                         warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3747                         return (scferror2errno(scf_error()));
3748 
3749                 case SCF_ERROR_HANDLE_MISMATCH:
3750                 case SCF_ERROR_IN_USE:
3751                 case SCF_ERROR_NOT_BOUND:
3752                 case SCF_ERROR_NOT_SET:
3753                 default:
3754                         bad_error("scf_transaction_start", scf_error());
3755                 }
3756         }
3757         tx_started = 1;
3758 
3759         for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3760             new_dpt_pgroup != NULL;
3761             new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3762             new_dpt_pgroup)) {
3763                 if (new_dpt_pgroup->sc_pgroup_seen)
3764                         continue;
3765 
3766                 if (ud_run_dpts_pg_set) {
3767                         /*
3768                          * If the dependent is already there, then we have
3769                          * a conflict.
3770                          */
3771                         if (scf_pg_get_property(ud_run_dpts_pg,
3772                             new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3773                                 r = handle_dependent_conflict(ient, ud_prop,
3774                                     new_dpt_pgroup);
3775                                 switch (r) {
3776                                 case 0:
3777                                         continue;
3778 
3779                                 case ECONNABORTED:
3780                                 case ENOMEM:
3781                                 case EBUSY:
3782                                 case EBADF:
3783                                 case EINVAL:
3784                                         scf_transaction_destroy_children(ud_tx);
3785                                         return (r);
3786 
3787                                 default:
3788                                         bad_error("handle_dependent_conflict",
3789                                             r);
3790                                 }
3791                         } else {
3792                                 switch (scf_error()) {
3793                                 case SCF_ERROR_NOT_FOUND:
3794                                         break;
3795 
3796                                 case SCF_ERROR_INVALID_ARGUMENT:
3797                                         warn(emsg_fmri_invalid_pg_name,
3798                                             ient->sc_fmri,
3799                                             new_dpt_pgroup->sc_pgroup_name);
3800                                         scf_transaction_destroy_children(ud_tx);
3801                                         return (EINVAL);
3802 
3803                                 case SCF_ERROR_DELETED:
3804                                         warn(emsg_pg_deleted, ient->sc_fmri,
3805                                             new_dpt_pgroup->sc_pgroup_name);
3806                                         scf_transaction_destroy_children(ud_tx);
3807                                         return (EBUSY);
3808 
3809                                 case SCF_ERROR_CONNECTION_BROKEN:
3810                                         scf_transaction_destroy_children(ud_tx);
3811                                         return (ECONNABORTED);
3812 
3813                                 case SCF_ERROR_NOT_BOUND:
3814                                 case SCF_ERROR_HANDLE_MISMATCH:
3815                                 case SCF_ERROR_NOT_SET:
3816                                 default:
3817                                         bad_error("scf_pg_get_property",
3818                                             scf_error());
3819                                 }
3820                         }
3821                 }
3822 
3823                 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3824                 if (r != UU_WALK_NEXT) {
3825                         if (r != UU_WALK_ERROR)
3826                                 bad_error("lscf_dependent_import", r);
3827 
3828                         if (cbdata.sc_err == EALREADY) {
3829                                 /* Collisions were handled preemptively. */
3830                                 bad_error("lscf_dependent_import",
3831                                     cbdata.sc_err);
3832                         }
3833 
3834                         scf_transaction_destroy_children(ud_tx);
3835                         return (cbdata.sc_err);
3836                 }
3837         }
3838 
3839 commit:
3840         if (!tx_started)
3841                 return (0);
3842 
3843         r = scf_transaction_commit(ud_tx);
3844 
3845         scf_transaction_destroy_children(ud_tx);
3846 
3847         switch (r) {
3848         case 1:
3849                 return (0);
3850 
3851         case 0:
3852                 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3853                 return (EBUSY);
3854 
3855         case -1:
3856                 break;
3857 
3858         default:
3859                 bad_error("scf_transaction_commit", r);
3860         }
3861 
3862         switch (scf_error()) {
3863         case SCF_ERROR_CONNECTION_BROKEN:
3864         case SCF_ERROR_BACKEND_READONLY:
3865         case SCF_ERROR_BACKEND_ACCESS:
3866         case SCF_ERROR_NO_RESOURCES:
3867                 return (scferror2errno(scf_error()));
3868 
3869         case SCF_ERROR_DELETED:
3870                 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3871                 return (EBUSY);
3872 
3873         case SCF_ERROR_PERMISSION_DENIED:
3874                 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3875                 return (scferror2errno(scf_error()));
3876 
3877         case SCF_ERROR_NOT_BOUND:
3878         case SCF_ERROR_INVALID_ARGUMENT:
3879         case SCF_ERROR_NOT_SET:
3880         default:
3881                 bad_error("scf_transaction_destroy", scf_error());
3882                 /* NOTREACHED */
3883         }
3884 }
3885 
3886 /*
3887  * Used to add the manifests to the list of currently supported manifests.
3888  * We can modify the existing manifest list removing entries if the files
3889  * don't exist.
3890  *
3891  * Get the old list and the new file name
3892  * If the new file name is in the list return
3893  * If not then add the file to the list.
3894  * As we process the list check to see if the files in the old list exist
3895  *      if not then remove the file from the list.
3896  * Commit the list of manifest file names.
3897  *
3898  */
3899 static int
3900 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3901     const scf_snaplevel_t *running, void *ent)
3902 {
3903         scf_propertygroup_t *ud_mfsts_pg = NULL;
3904         scf_property_t *ud_prop = NULL;
3905         scf_iter_t *ud_prop_iter;
3906         scf_value_t *fname_value;
3907         scf_callback_t cbdata;
3908         pgroup_t *mfst_pgroup;
3909         property_t *mfst_prop;
3910         property_t *old_prop;
3911         char *pname;
3912         char *fval;
3913         char *old_pname;
3914         char *old_fval;
3915         int no_upgrade_pg;
3916         int mfst_seen;
3917         int r;
3918 
3919         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3920 
3921         /*
3922          * This should always be the service base on the code
3923          * path, and the fact that the manifests pg is a service
3924          * level property group only.
3925          */
3926         ud_mfsts_pg = scf_pg_create(g_hndl);
3927         ud_prop = scf_property_create(g_hndl);
3928         ud_prop_iter = scf_iter_create(g_hndl);
3929         fname_value = scf_value_create(g_hndl);
3930 
3931         /* Fetch the "manifests" property group */
3932         no_upgrade_pg = 0;
3933         r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3934             ud_mfsts_pg);
3935         if (r != 0) {
3936                 switch (scf_error()) {
3937                 case SCF_ERROR_NOT_FOUND:
3938                         no_upgrade_pg = 1;
3939                         break;
3940 
3941                 case SCF_ERROR_DELETED:
3942                 case SCF_ERROR_CONNECTION_BROKEN:
3943                         return (scferror2errno(scf_error()));
3944 
3945                 case SCF_ERROR_NOT_SET:
3946                 case SCF_ERROR_INVALID_ARGUMENT:
3947                 case SCF_ERROR_HANDLE_MISMATCH:
3948                 case SCF_ERROR_NOT_BOUND:
3949                 default:
3950                         bad_error(running ? "scf_snaplevel_get_pg" :
3951                             "entity_get_pg", scf_error());
3952                 }
3953         }
3954 
3955         if (no_upgrade_pg) {
3956                 cbdata.sc_handle = g_hndl;
3957                 cbdata.sc_parent = ent;
3958                 cbdata.sc_service = issvc;
3959                 cbdata.sc_flags = SCI_FORCE;
3960                 cbdata.sc_source_fmri = ient->sc_fmri;
3961                 cbdata.sc_target_fmri = ient->sc_fmri;
3962 
3963                 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3964                         return (cbdata.sc_err);
3965 
3966                 return (0);
3967         }
3968 
3969         /* Fetch the new manifests property group */
3970         mfst_pgroup = internal_pgroup_find_or_create(ient,
3971             SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3972         assert(mfst_pgroup != NULL);
3973 
3974         if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3975             SCF_SUCCESS)
3976                 return (-1);
3977 
3978         if ((pname = malloc(MAXPATHLEN)) == NULL)
3979                 return (ENOMEM);
3980         if ((fval = malloc(MAXPATHLEN)) == NULL) {
3981                 free(pname);
3982                 return (ENOMEM);
3983         }
3984 
3985         while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3986                 mfst_seen = 0;
3987                 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3988                         continue;
3989 
3990                 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3991                     mfst_prop != NULL;
3992                     mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3993                     mfst_prop)) {
3994                         if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3995                                 mfst_seen = 1;
3996                         }
3997                 }
3998 
3999                 /*
4000                  * If the manifest is not seen then add it to the new mfst
4001                  * property list to get proccessed into the repo.
4002                  */
4003                 if (mfst_seen == 0) {
4004                         /*
4005                          * If we cannot get the value then there is no
4006                          * reason to attempt to attach the value to
4007                          * the property group
4008                          */
4009                         if (prop_get_val(ud_prop, fname_value) == 0 &&
4010                             scf_value_get_astring(fname_value, fval,
4011                             MAXPATHLEN) != -1)  {
4012                                 old_pname = safe_strdup(pname);
4013                                 old_fval = safe_strdup(fval);
4014                                 old_prop = internal_property_create(old_pname,
4015                                     SCF_TYPE_ASTRING, 1, old_fval);
4016 
4017                                 /*
4018                                  * Already checked to see if the property exists
4019                                  * in the group, and it does not.
4020                                  */
4021                                 (void) internal_attach_property(mfst_pgroup,
4022                                     old_prop);
4023                         }
4024                 }
4025         }
4026         free(pname);
4027         free(fval);
4028 
4029         cbdata.sc_handle = g_hndl;
4030         cbdata.sc_parent = ent;
4031         cbdata.sc_service = issvc;
4032         cbdata.sc_flags = SCI_FORCE;
4033         cbdata.sc_source_fmri = ient->sc_fmri;
4034         cbdata.sc_target_fmri = ient->sc_fmri;
4035 
4036         if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4037                 return (cbdata.sc_err);
4038 
4039         return (r);
4040 }
4041 
4042 /*
4043  * prop is taken to be a property in the "dependents" property group of snpl,
4044  * which is taken to be the snaplevel of a last-import snapshot corresponding
4045  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4046  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4047  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4048  * of the entity ient represents (possibly in the running snapshot).  If it
4049  * needs to be changed, an entry will be added to tx, if not NULL.
4050  *
4051  * Returns
4052  *   0 - success
4053  *   ECONNABORTED - repository connection broken
4054  *   ENOMEM - out of memory
4055  *   ENOSPC - configd was out of resources
4056  *   ECANCELED - snpl's entity was deleted
4057  *   EINVAL - dependent target is invalid (error printed)
4058  *          - dependent is invalid (error printed)
4059  *   EBADF - snpl is corrupt (error printed)
4060  *         - snpl has corrupt pg (error printed)
4061  *         - dependency pg in target is corrupt (error printed)
4062  *         - running snapshot in dependent is missing snaplevel (error printed)
4063  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4064  *         - couldn't create dependent (permission denied) (error printed)
4065  *         - couldn't modify dependent pg (permission denied) (error printed)
4066  *   EROFS - couldn't delete dependency pg (repository read-only)
4067  *         - couldn't create dependent (repository read-only)
4068  *   EACCES - couldn't delete dependency pg (backend access denied)
4069  *          - couldn't create dependent (backend access denied)
4070  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4071  *         - tx's pg was deleted (error printed)
4072  *         - dependent pg was changed or deleted (error printed)
4073  *   EEXIST - dependency pg already exists in new target (error printed)
4074  */
4075 static int
4076 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4077     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4078 {
4079         pgroup_t pgrp;
4080         scf_type_t ty;
4081         pgroup_t *new_dpt_pgroup;
4082         pgroup_t *old_dpt_pgroup = NULL;
4083         pgroup_t *current_pg;
4084         pgroup_t *dpt;
4085         scf_callback_t cbdata;
4086         int tissvc;
4087         void *target_ent;
4088         scf_error_t serr;
4089         int r;
4090         scf_transaction_entry_t *ent;
4091 
4092         const char * const cf_inval = gettext("Conflict upgrading %s "
4093             "(dependent \"%s\" has invalid dependents property).\n");
4094         const char * const cf_missing = gettext("Conflict upgrading %s "
4095             "(dependent \"%s\" is missing).\n");
4096         const char * const cf_newdpg = gettext("Conflict upgrading %s "
4097             "(dependent \"%s\" has new dependency property group).\n");
4098         const char * const cf_newtarg = gettext("Conflict upgrading %s "
4099             "(dependent \"%s\" has new target).\n");
4100         const char * const li_corrupt =
4101             gettext("%s: \"last-import\" snapshot is corrupt.\n");
4102         const char * const upgrading =
4103             gettext("%s: Upgrading dependent \"%s\".\n");
4104         const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4105             "corrupt (missing snaplevel).\n");
4106 
4107         if (scf_property_type(prop, &ty) != 0) {
4108                 switch (scf_error()) {
4109                 case SCF_ERROR_DELETED:
4110                 case SCF_ERROR_CONNECTION_BROKEN:
4111                         return (scferror2errno(scf_error()));
4112 
4113                 case SCF_ERROR_NOT_BOUND:
4114                 case SCF_ERROR_NOT_SET:
4115                 default:
4116                         bad_error("scf_property_type", scf_error());
4117                 }
4118         }
4119 
4120         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4121                 warn(li_corrupt, ient->sc_fmri);
4122                 return (EBADF);
4123         }
4124 
4125         /*
4126          * prop represents a dependent in the old manifest.  It is named after
4127          * the dependent.
4128          */
4129         if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4130                 switch (scf_error()) {
4131                 case SCF_ERROR_DELETED:
4132                 case SCF_ERROR_CONNECTION_BROKEN:
4133                         return (scferror2errno(scf_error()));
4134 
4135                 case SCF_ERROR_NOT_BOUND:
4136                 case SCF_ERROR_NOT_SET:
4137                 default:
4138                         bad_error("scf_property_get_name", scf_error());
4139                 }
4140         }
4141 
4142         /* See if it's in the new manifest. */
4143         pgrp.sc_pgroup_name = ud_name;
4144         new_dpt_pgroup =
4145             uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4146 
4147         /* If it's not, delete it... if it hasn't been customized. */
4148         if (new_dpt_pgroup == NULL) {
4149                 if (!ud_run_dpts_pg_set)
4150                         return (0);
4151 
4152                 if (scf_property_get_value(prop, ud_val) != 0) {
4153                         switch (scf_error()) {
4154                         case SCF_ERROR_NOT_FOUND:
4155                         case SCF_ERROR_CONSTRAINT_VIOLATED:
4156                                 warn(li_corrupt, ient->sc_fmri);
4157                                 return (EBADF);
4158 
4159                         case SCF_ERROR_DELETED:
4160                         case SCF_ERROR_CONNECTION_BROKEN:
4161                                 return (scferror2errno(scf_error()));
4162 
4163                         case SCF_ERROR_HANDLE_MISMATCH:
4164                         case SCF_ERROR_NOT_BOUND:
4165                         case SCF_ERROR_NOT_SET:
4166                         case SCF_ERROR_PERMISSION_DENIED:
4167                         default:
4168                                 bad_error("scf_property_get_value",
4169                                     scf_error());
4170                         }
4171                 }
4172 
4173                 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4174                     max_scf_value_len + 1) < 0)
4175                         bad_error("scf_value_get_as_string", scf_error());
4176 
4177                 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4178                     0) {
4179                         switch (scf_error()) {
4180                         case SCF_ERROR_NOT_FOUND:
4181                                 return (0);
4182 
4183                         case SCF_ERROR_CONNECTION_BROKEN:
4184                                 return (scferror2errno(scf_error()));
4185 
4186                         case SCF_ERROR_DELETED:
4187                                 warn(emsg_pg_deleted, ient->sc_fmri,
4188                                     "dependents");
4189                                 return (EBUSY);
4190 
4191                         case SCF_ERROR_INVALID_ARGUMENT:
4192                         case SCF_ERROR_NOT_BOUND:
4193                         case SCF_ERROR_HANDLE_MISMATCH:
4194                         case SCF_ERROR_NOT_SET:
4195                         default:
4196                                 bad_error("scf_pg_get_property", scf_error());
4197                         }
4198                 }
4199                 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4200                         switch (scf_error()) {
4201                         case SCF_ERROR_NOT_FOUND:
4202                         case SCF_ERROR_CONSTRAINT_VIOLATED:
4203                                 warn(cf_inval, ient->sc_fmri, ud_name);
4204                                 return (0);
4205 
4206                         case SCF_ERROR_DELETED:
4207                         case SCF_ERROR_CONNECTION_BROKEN:
4208                                 return (scferror2errno(scf_error()));
4209 
4210                         case SCF_ERROR_HANDLE_MISMATCH:
4211                         case SCF_ERROR_NOT_BOUND:
4212                         case SCF_ERROR_NOT_SET:
4213                         case SCF_ERROR_PERMISSION_DENIED:
4214                         default:
4215                                 bad_error("scf_property_get_value",
4216                                     scf_error());
4217                         }
4218                 }
4219 
4220                 ty = scf_value_type(ud_val);
4221                 assert(ty != SCF_TYPE_INVALID);
4222                 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4223                         warn(cf_inval, ient->sc_fmri, ud_name);
4224                         return (0);
4225                 }
4226 
4227                 if (scf_value_get_as_string(ud_val, ud_ctarg,
4228                     max_scf_value_len + 1) < 0)
4229                         bad_error("scf_value_get_as_string", scf_error());
4230 
4231                 r = fmri_equal(ud_ctarg, ud_oldtarg);
4232                 switch (r) {
4233                 case 1:
4234                         break;
4235 
4236                 case 0:
4237                 case -1:        /* warn? */
4238                         warn(cf_newtarg, ient->sc_fmri, ud_name);
4239                         return (0);
4240 
4241                 case -2:
4242                         warn(li_corrupt, ient->sc_fmri);
4243                         return (EBADF);
4244 
4245                 default:
4246                         bad_error("fmri_equal", r);
4247                 }
4248 
4249                 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4250                         switch (scf_error()) {
4251                         case SCF_ERROR_NOT_FOUND:
4252                                 warn(li_corrupt, ient->sc_fmri);
4253                                 return (EBADF);
4254 
4255                         case SCF_ERROR_DELETED:
4256                         case SCF_ERROR_CONNECTION_BROKEN:
4257                                 return (scferror2errno(scf_error()));
4258 
4259                         case SCF_ERROR_NOT_BOUND:
4260                         case SCF_ERROR_HANDLE_MISMATCH:
4261                         case SCF_ERROR_INVALID_ARGUMENT:
4262                         case SCF_ERROR_NOT_SET:
4263                         default:
4264                                 bad_error("scf_snaplevel_get_pg", scf_error());
4265                         }
4266                 }
4267 
4268                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4269                     snap_lastimport);
4270                 switch (r) {
4271                 case 0:
4272                         break;
4273 
4274                 case ECANCELED:
4275                 case ECONNABORTED:
4276                 case ENOMEM:
4277                 case EBADF:
4278                         return (r);
4279 
4280                 case EACCES:
4281                 default:
4282                         bad_error("load_pg", r);
4283                 }
4284 
4285                 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4286                 switch (serr) {
4287                 case SCF_ERROR_NONE:
4288                         break;
4289 
4290                 case SCF_ERROR_NO_MEMORY:
4291                         internal_pgroup_free(old_dpt_pgroup);
4292                         return (ENOMEM);
4293 
4294                 case SCF_ERROR_NOT_FOUND:
4295                         internal_pgroup_free(old_dpt_pgroup);
4296                         goto delprop;
4297 
4298                 case SCF_ERROR_CONSTRAINT_VIOLATED:     /* caught above */
4299                 case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
4300                 default:
4301                         bad_error("fmri_to_entity", serr);
4302                 }
4303 
4304                 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4305                     ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4306                 switch (r) {
4307                 case 0:
4308                         break;
4309 
4310                 case ECONNABORTED:
4311                         internal_pgroup_free(old_dpt_pgroup);
4312                         return (r);
4313 
4314                 case ECANCELED:
4315                 case ENOENT:
4316                         internal_pgroup_free(old_dpt_pgroup);
4317                         goto delprop;
4318 
4319                 case EBADF:
4320                         warn(r_no_lvl, ud_ctarg);
4321                         internal_pgroup_free(old_dpt_pgroup);
4322                         return (r);
4323 
4324                 case EINVAL:
4325                 default:
4326                         bad_error("entity_get_running_pg", r);
4327                 }
4328 
4329                 /* load it */
4330                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4331                 switch (r) {
4332                 case 0:
4333                         break;
4334 
4335                 case ECANCELED:
4336                         internal_pgroup_free(old_dpt_pgroup);
4337                         goto delprop;
4338 
4339                 case ECONNABORTED:
4340                 case ENOMEM:
4341                 case EBADF:
4342                         internal_pgroup_free(old_dpt_pgroup);
4343                         return (r);
4344 
4345                 case EACCES:
4346                 default:
4347                         bad_error("load_pg", r);
4348                 }
4349 
4350                 /* compare property groups */
4351                 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4352                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4353                         internal_pgroup_free(old_dpt_pgroup);
4354                         internal_pgroup_free(current_pg);
4355                         return (0);
4356                 }
4357 
4358                 internal_pgroup_free(old_dpt_pgroup);
4359                 internal_pgroup_free(current_pg);
4360 
4361                 if (g_verbose)
4362                         warn(gettext("%s: Deleting dependent \"%s\".\n"),
4363                             ient->sc_fmri, ud_name);
4364 
4365                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4366                         switch (scf_error()) {
4367                         case SCF_ERROR_NOT_FOUND:
4368                         case SCF_ERROR_DELETED:
4369                                 internal_pgroup_free(old_dpt_pgroup);
4370                                 goto delprop;
4371 
4372                         case SCF_ERROR_CONNECTION_BROKEN:
4373                                 internal_pgroup_free(old_dpt_pgroup);
4374                                 return (ECONNABORTED);
4375 
4376                         case SCF_ERROR_NOT_SET:
4377                         case SCF_ERROR_INVALID_ARGUMENT:
4378                         case SCF_ERROR_HANDLE_MISMATCH:
4379                         case SCF_ERROR_NOT_BOUND:
4380                         default:
4381                                 bad_error("entity_get_pg", scf_error());
4382                         }
4383                 }
4384 
4385                 if (scf_pg_delete(ud_pg) != 0) {
4386                         switch (scf_error()) {
4387                         case SCF_ERROR_DELETED:
4388                                 break;
4389 
4390                         case SCF_ERROR_CONNECTION_BROKEN:
4391                         case SCF_ERROR_BACKEND_READONLY:
4392                         case SCF_ERROR_BACKEND_ACCESS:
4393                                 return (scferror2errno(scf_error()));
4394 
4395                         case SCF_ERROR_PERMISSION_DENIED:
4396                                 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4397                                 return (scferror2errno(scf_error()));
4398 
4399                         case SCF_ERROR_NOT_SET:
4400                         default:
4401                                 bad_error("scf_pg_delete", scf_error());
4402                         }
4403                 }
4404 
4405                 /*
4406                  * This service was changed, so it must be refreshed.  But
4407                  * since it's not mentioned in the new manifest, we have to
4408                  * record its FMRI here for use later.  We record the name
4409                  * & the entity (via sc_parent) in case we need to print error
4410                  * messages during the refresh.
4411                  */
4412                 dpt = internal_pgroup_new();
4413                 if (dpt == NULL)
4414                         return (ENOMEM);
4415                 dpt->sc_pgroup_name = strdup(ud_name);
4416                 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4417                 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4418                         return (ENOMEM);
4419                 dpt->sc_parent = (entity_t *)ient;
4420                 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4421                         uu_die(gettext("libuutil error: %s\n"),
4422                             uu_strerror(uu_error()));
4423 
4424 delprop:
4425                 if (tx == NULL)
4426                         return (0);
4427 
4428                 ent = scf_entry_create(g_hndl);
4429                 if (ent == NULL)
4430                         return (ENOMEM);
4431 
4432                 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4433                         scf_entry_destroy(ent);
4434                         switch (scf_error()) {
4435                         case SCF_ERROR_DELETED:
4436                                 warn(emsg_pg_deleted, ient->sc_fmri,
4437                                     "dependents");
4438                                 return (EBUSY);
4439 
4440                         case SCF_ERROR_CONNECTION_BROKEN:
4441                                 return (scferror2errno(scf_error()));
4442 
4443                         case SCF_ERROR_NOT_FOUND:
4444                                 break;
4445 
4446                         case SCF_ERROR_HANDLE_MISMATCH:
4447                         case SCF_ERROR_NOT_BOUND:
4448                         case SCF_ERROR_INVALID_ARGUMENT:
4449                         case SCF_ERROR_NOT_SET:
4450                         default:
4451                                 bad_error("scf_transaction_property_delete",
4452                                     scf_error());
4453                         }
4454                 }
4455 
4456                 return (0);
4457         }
4458 
4459         new_dpt_pgroup->sc_pgroup_seen = 1;
4460 
4461         /*
4462          * Decide whether the dependent has changed in the manifest.
4463          */
4464         /* Compare the target. */
4465         if (scf_property_get_value(prop, ud_val) != 0) {
4466                 switch (scf_error()) {
4467                 case SCF_ERROR_NOT_FOUND:
4468                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4469                         warn(li_corrupt, ient->sc_fmri);
4470                         return (EBADF);
4471 
4472                 case SCF_ERROR_DELETED:
4473                 case SCF_ERROR_CONNECTION_BROKEN:
4474                         return (scferror2errno(scf_error()));
4475 
4476                 case SCF_ERROR_HANDLE_MISMATCH:
4477                 case SCF_ERROR_NOT_BOUND:
4478                 case SCF_ERROR_NOT_SET:
4479                 case SCF_ERROR_PERMISSION_DENIED:
4480                 default:
4481                         bad_error("scf_property_get_value", scf_error());
4482                 }
4483         }
4484 
4485         if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4486             0)
4487                 bad_error("scf_value_get_as_string", scf_error());
4488 
4489         /*
4490          * If the fmri's are not equal then the old fmri will need to
4491          * be refreshed to ensure that the changes are properly updated
4492          * in that service.
4493          */
4494         r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4495         switch (r) {
4496         case 0:
4497                 dpt = internal_pgroup_new();
4498                 if (dpt == NULL)
4499                         return (ENOMEM);
4500                 dpt->sc_pgroup_name = strdup(ud_name);
4501                 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4502                 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4503                         return (ENOMEM);
4504                 dpt->sc_parent = (entity_t *)ient;
4505                 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4506                         uu_die(gettext("libuutil error: %s\n"),
4507                             uu_strerror(uu_error()));
4508                 break;
4509 
4510         case 1:
4511                 /* Compare the dependency pgs. */
4512                 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4513                         switch (scf_error()) {
4514                         case SCF_ERROR_NOT_FOUND:
4515                                 warn(li_corrupt, ient->sc_fmri);
4516                                 return (EBADF);
4517 
4518                         case SCF_ERROR_DELETED:
4519                         case SCF_ERROR_CONNECTION_BROKEN:
4520                                 return (scferror2errno(scf_error()));
4521 
4522                         case SCF_ERROR_NOT_BOUND:
4523                         case SCF_ERROR_HANDLE_MISMATCH:
4524                         case SCF_ERROR_INVALID_ARGUMENT:
4525                         case SCF_ERROR_NOT_SET:
4526                         default:
4527                                 bad_error("scf_snaplevel_get_pg", scf_error());
4528                         }
4529                 }
4530 
4531                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4532                     snap_lastimport);
4533                 switch (r) {
4534                 case 0:
4535                         break;
4536 
4537                 case ECANCELED:
4538                 case ECONNABORTED:
4539                 case ENOMEM:
4540                 case EBADF:
4541                         return (r);
4542 
4543                 case EACCES:
4544                 default:
4545                         bad_error("load_pg", r);
4546                 }
4547 
4548                 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4549                         /* no change, leave customizations */
4550                         internal_pgroup_free(old_dpt_pgroup);
4551                         return (0);
4552                 }
4553                 break;
4554 
4555         case -1:
4556                 warn(li_corrupt, ient->sc_fmri);
4557                 return (EBADF);
4558 
4559         case -2:
4560                 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4561                     ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4562                 return (EINVAL);
4563 
4564         default:
4565                 bad_error("fmri_equal", r);
4566         }
4567 
4568         /*
4569          * The dependent has changed in the manifest.  Upgrade the current
4570          * properties if they haven't been customized.
4571          */
4572 
4573         /*
4574          * If new_dpt_pgroup->sc_override, then act as though the property
4575          * group hasn't been customized.
4576          */
4577         if (new_dpt_pgroup->sc_pgroup_override) {
4578                 (void) strcpy(ud_ctarg, ud_oldtarg);
4579                 goto nocust;
4580         }
4581 
4582         if (!ud_run_dpts_pg_set) {
4583                 warn(cf_missing, ient->sc_fmri, ud_name);
4584                 r = 0;
4585                 goto out;
4586         } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4587                 switch (scf_error()) {
4588                 case SCF_ERROR_NOT_FOUND:
4589                         warn(cf_missing, ient->sc_fmri, ud_name);
4590                         r = 0;
4591                         goto out;
4592 
4593                 case SCF_ERROR_CONNECTION_BROKEN:
4594                         r = scferror2errno(scf_error());
4595                         goto out;
4596 
4597                 case SCF_ERROR_DELETED:
4598                         warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4599                         r = EBUSY;
4600                         goto out;
4601 
4602                 case SCF_ERROR_INVALID_ARGUMENT:
4603                 case SCF_ERROR_NOT_BOUND:
4604                 case SCF_ERROR_HANDLE_MISMATCH:
4605                 case SCF_ERROR_NOT_SET:
4606                 default:
4607                         bad_error("scf_pg_get_property", scf_error());
4608                 }
4609         }
4610 
4611         if (scf_property_get_value(ud_prop, ud_val) != 0) {
4612                 switch (scf_error()) {
4613                 case SCF_ERROR_NOT_FOUND:
4614                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4615                         warn(cf_inval, ient->sc_fmri, ud_name);
4616                         r = 0;
4617                         goto out;
4618 
4619                 case SCF_ERROR_DELETED:
4620                 case SCF_ERROR_CONNECTION_BROKEN:
4621                         r = scferror2errno(scf_error());
4622                         goto out;
4623 
4624                 case SCF_ERROR_HANDLE_MISMATCH:
4625                 case SCF_ERROR_NOT_BOUND:
4626                 case SCF_ERROR_NOT_SET:
4627                 case SCF_ERROR_PERMISSION_DENIED:
4628                 default:
4629                         bad_error("scf_property_get_value", scf_error());
4630                 }
4631         }
4632 
4633         ty = scf_value_type(ud_val);
4634         assert(ty != SCF_TYPE_INVALID);
4635         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4636                 warn(cf_inval, ient->sc_fmri, ud_name);
4637                 r = 0;
4638                 goto out;
4639         }
4640         if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4641             0)
4642                 bad_error("scf_value_get_as_string", scf_error());
4643 
4644         r = fmri_equal(ud_ctarg, ud_oldtarg);
4645         if (r == -1) {
4646                 warn(cf_inval, ient->sc_fmri, ud_name);
4647                 r = 0;
4648                 goto out;
4649         } else if (r == -2) {
4650                 warn(li_corrupt, ient->sc_fmri);
4651                 r = EBADF;
4652                 goto out;
4653         } else if (r == 0) {
4654                 /*
4655                  * Target has been changed.  Only abort now if it's been
4656                  * changed to something other than what's in the manifest.
4657                  */
4658                 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4659                 if (r == -1) {
4660                         warn(cf_inval, ient->sc_fmri, ud_name);
4661                         r = 0;
4662                         goto out;
4663                 } else if (r == 0) {
4664                         warn(cf_newtarg, ient->sc_fmri, ud_name);
4665                         r = 0;
4666                         goto out;
4667                 } else if (r != 1) {
4668                         /* invalid sc_pgroup_fmri caught above */
4669                         bad_error("fmri_equal", r);
4670                 }
4671 
4672                 /*
4673                  * Fetch the current dependency pg.  If it's what the manifest
4674                  * says, then no problem.
4675                  */
4676                 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4677                 switch (serr) {
4678                 case SCF_ERROR_NONE:
4679                         break;
4680 
4681                 case SCF_ERROR_NOT_FOUND:
4682                         warn(cf_missing, ient->sc_fmri, ud_name);
4683                         r = 0;
4684                         goto out;
4685 
4686                 case SCF_ERROR_NO_MEMORY:
4687                         r = ENOMEM;
4688                         goto out;
4689 
4690                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4691                 case SCF_ERROR_INVALID_ARGUMENT:
4692                 default:
4693                         bad_error("fmri_to_entity", serr);
4694                 }
4695 
4696                 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4697                     ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4698                 switch (r) {
4699                 case 0:
4700                         break;
4701 
4702                 case ECONNABORTED:
4703                         goto out;
4704 
4705                 case ECANCELED:
4706                 case ENOENT:
4707                         warn(cf_missing, ient->sc_fmri, ud_name);
4708                         r = 0;
4709                         goto out;
4710 
4711                 case EBADF:
4712                         warn(r_no_lvl, ud_ctarg);
4713                         goto out;
4714 
4715                 case EINVAL:
4716                 default:
4717                         bad_error("entity_get_running_pg", r);
4718                 }
4719 
4720                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4721                 switch (r) {
4722                 case 0:
4723                         break;
4724 
4725                 case ECANCELED:
4726                         warn(cf_missing, ient->sc_fmri, ud_name);
4727                         r = 0;
4728                         goto out;
4729 
4730                 case ECONNABORTED:
4731                 case ENOMEM:
4732                 case EBADF:
4733                         goto out;
4734 
4735                 case EACCES:
4736                 default:
4737                         bad_error("load_pg", r);
4738                 }
4739 
4740                 if (!pg_equal(current_pg, new_dpt_pgroup))
4741                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4742                 internal_pgroup_free(current_pg);
4743                 r = 0;
4744                 goto out;
4745         } else if (r != 1) {
4746                 bad_error("fmri_equal", r);
4747         }
4748 
4749 nocust:
4750         /*
4751          * Target has not been customized.  Check the dependency property
4752          * group.
4753          */
4754 
4755         if (old_dpt_pgroup == NULL) {
4756                 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4757                     ud_pg) != 0) {
4758                         switch (scf_error()) {
4759                         case SCF_ERROR_NOT_FOUND:
4760                                 warn(li_corrupt, ient->sc_fmri);
4761                                 return (EBADF);
4762 
4763                         case SCF_ERROR_DELETED:
4764                         case SCF_ERROR_CONNECTION_BROKEN:
4765                                 return (scferror2errno(scf_error()));
4766 
4767                         case SCF_ERROR_NOT_BOUND:
4768                         case SCF_ERROR_HANDLE_MISMATCH:
4769                         case SCF_ERROR_INVALID_ARGUMENT:
4770                         case SCF_ERROR_NOT_SET:
4771                         default:
4772                                 bad_error("scf_snaplevel_get_pg", scf_error());
4773                         }
4774                 }
4775 
4776                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4777                     snap_lastimport);
4778                 switch (r) {
4779                 case 0:
4780                         break;
4781 
4782                 case ECANCELED:
4783                 case ECONNABORTED:
4784                 case ENOMEM:
4785                 case EBADF:
4786                         return (r);
4787 
4788                 case EACCES:
4789                 default:
4790                         bad_error("load_pg", r);
4791                 }
4792         }
4793         serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4794         switch (serr) {
4795         case SCF_ERROR_NONE:
4796                 break;
4797 
4798         case SCF_ERROR_NOT_FOUND:
4799                 warn(cf_missing, ient->sc_fmri, ud_name);
4800                 r = 0;
4801                 goto out;
4802 
4803         case SCF_ERROR_NO_MEMORY:
4804                 r = ENOMEM;
4805                 goto out;
4806 
4807         case SCF_ERROR_CONSTRAINT_VIOLATED:
4808         case SCF_ERROR_INVALID_ARGUMENT:
4809         default:
4810                 bad_error("fmri_to_entity", serr);
4811         }
4812 
4813         r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4814             ud_iter2, ud_inst, imp_snap, ud_snpl);
4815         switch (r) {
4816         case 0:
4817                 break;
4818 
4819         case ECONNABORTED:
4820                 goto out;
4821 
4822         case ECANCELED:
4823         case ENOENT:
4824                 warn(cf_missing, ient->sc_fmri, ud_name);
4825                 r = 0;
4826                 goto out;
4827 
4828         case EBADF:
4829                 warn(r_no_lvl, ud_ctarg);
4830                 goto out;
4831 
4832         case EINVAL:
4833         default:
4834                 bad_error("entity_get_running_pg", r);
4835         }
4836 
4837         r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4838         switch (r) {
4839         case 0:
4840                 break;
4841 
4842         case ECANCELED:
4843                 warn(cf_missing, ient->sc_fmri, ud_name);
4844                 goto out;
4845 
4846         case ECONNABORTED:
4847         case ENOMEM:
4848         case EBADF:
4849                 goto out;
4850 
4851         case EACCES:
4852         default:
4853                 bad_error("load_pg", r);
4854         }
4855 
4856         if (!pg_equal(current_pg, old_dpt_pgroup)) {
4857                 if (!pg_equal(current_pg, new_dpt_pgroup))
4858                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4859                 internal_pgroup_free(current_pg);
4860                 r = 0;
4861                 goto out;
4862         }
4863 
4864         /* Uncustomized.  Upgrade. */
4865 
4866         r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4867         switch (r) {
4868         case 1:
4869                 if (pg_equal(current_pg, new_dpt_pgroup)) {
4870                         /* Already upgraded. */
4871                         internal_pgroup_free(current_pg);
4872                         r = 0;
4873                         goto out;
4874                 }
4875 
4876                 internal_pgroup_free(current_pg);
4877 
4878                 /* upgrade current_pg */
4879                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4880                         switch (scf_error()) {
4881                         case SCF_ERROR_CONNECTION_BROKEN:
4882                                 r = scferror2errno(scf_error());
4883                                 goto out;
4884 
4885                         case SCF_ERROR_DELETED:
4886                                 warn(cf_missing, ient->sc_fmri, ud_name);
4887                                 r = 0;
4888                                 goto out;
4889 
4890                         case SCF_ERROR_NOT_FOUND:
4891                                 break;
4892 
4893                         case SCF_ERROR_INVALID_ARGUMENT:
4894                         case SCF_ERROR_NOT_BOUND:
4895                         case SCF_ERROR_NOT_SET:
4896                         case SCF_ERROR_HANDLE_MISMATCH:
4897                         default:
4898                                 bad_error("entity_get_pg", scf_error());
4899                         }
4900 
4901                         if (tissvc)
4902                                 r = scf_service_add_pg(target_ent, ud_name,
4903                                     SCF_GROUP_DEPENDENCY, 0, ud_pg);
4904                         else
4905                                 r = scf_instance_add_pg(target_ent, ud_name,
4906                                     SCF_GROUP_DEPENDENCY, 0, ud_pg);
4907                         if (r != 0) {
4908                                 switch (scf_error()) {
4909                                 case SCF_ERROR_CONNECTION_BROKEN:
4910                                 case SCF_ERROR_NO_RESOURCES:
4911                                 case SCF_ERROR_BACKEND_READONLY:
4912                                 case SCF_ERROR_BACKEND_ACCESS:
4913                                         r = scferror2errno(scf_error());
4914                                         goto out;
4915 
4916                                 case SCF_ERROR_DELETED:
4917                                         warn(cf_missing, ient->sc_fmri,
4918                                             ud_name);
4919                                         r = 0;
4920                                         goto out;
4921 
4922                                 case SCF_ERROR_PERMISSION_DENIED:
4923                                         warn(emsg_pg_deleted, ud_ctarg,
4924                                             ud_name);
4925                                         r = EPERM;
4926                                         goto out;
4927 
4928                                 case SCF_ERROR_EXISTS:
4929                                         warn(emsg_pg_added, ud_ctarg, ud_name);
4930                                         r = EBUSY;
4931                                         goto out;
4932 
4933                                 case SCF_ERROR_NOT_BOUND:
4934                                 case SCF_ERROR_HANDLE_MISMATCH:
4935                                 case SCF_ERROR_INVALID_ARGUMENT:
4936                                 case SCF_ERROR_NOT_SET:
4937                                 default:
4938                                         bad_error("entity_add_pg", scf_error());
4939                                 }
4940                         }
4941                 }
4942 
4943                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4944                 switch (r) {
4945                 case 0:
4946                         break;
4947 
4948                 case ECANCELED:
4949                         warn(cf_missing, ient->sc_fmri, ud_name);
4950                         goto out;
4951 
4952                 case ECONNABORTED:
4953                 case ENOMEM:
4954                 case EBADF:
4955                         goto out;
4956 
4957                 case EACCES:
4958                 default:
4959                         bad_error("load_pg", r);
4960                 }
4961 
4962                 if (g_verbose)
4963                         warn(upgrading, ient->sc_fmri, ud_name);
4964 
4965                 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4966                     new_dpt_pgroup, 0, ient->sc_fmri);
4967                 switch (r) {
4968                 case 0:
4969                         break;
4970 
4971                 case ECANCELED:
4972                         warn(emsg_pg_deleted, ud_ctarg, ud_name);
4973                         r = EBUSY;
4974                         goto out;
4975 
4976                 case EPERM:
4977                         warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4978                         goto out;
4979 
4980                 case EBUSY:
4981                         warn(emsg_pg_changed, ud_ctarg, ud_name);
4982                         goto out;
4983 
4984                 case ECONNABORTED:
4985                 case ENOMEM:
4986                 case ENOSPC:
4987                 case EROFS:
4988                 case EACCES:
4989                 case EINVAL:
4990                         goto out;
4991 
4992                 default:
4993                         bad_error("upgrade_pg", r);
4994                 }
4995                 break;
4996 
4997         case 0: {
4998                 scf_transaction_entry_t *ent;
4999                 scf_value_t *val;
5000 
5001                 internal_pgroup_free(current_pg);
5002 
5003                 /* delete old pg */
5004                 if (g_verbose)
5005                         warn(upgrading, ient->sc_fmri, ud_name);
5006 
5007                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5008                         switch (scf_error()) {
5009                         case SCF_ERROR_CONNECTION_BROKEN:
5010                                 r = scferror2errno(scf_error());
5011                                 goto out;
5012 
5013                         case SCF_ERROR_DELETED:
5014                                 warn(cf_missing, ient->sc_fmri, ud_name);
5015                                 r = 0;
5016                                 goto out;
5017 
5018                         case SCF_ERROR_NOT_FOUND:
5019                                 break;
5020 
5021                         case SCF_ERROR_INVALID_ARGUMENT:
5022                         case SCF_ERROR_NOT_BOUND:
5023                         case SCF_ERROR_NOT_SET:
5024                         case SCF_ERROR_HANDLE_MISMATCH:
5025                         default:
5026                                 bad_error("entity_get_pg", scf_error());
5027                         }
5028                 } else if (scf_pg_delete(ud_pg) != 0) {
5029                         switch (scf_error()) {
5030                         case SCF_ERROR_DELETED:
5031                                 break;
5032 
5033                         case SCF_ERROR_CONNECTION_BROKEN:
5034                         case SCF_ERROR_BACKEND_READONLY:
5035                         case SCF_ERROR_BACKEND_ACCESS:
5036                                 r = scferror2errno(scf_error());
5037                                 goto out;
5038 
5039                         case SCF_ERROR_PERMISSION_DENIED:
5040                                 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5041                                 r = scferror2errno(scf_error());
5042                                 goto out;
5043 
5044                         case SCF_ERROR_NOT_SET:
5045                         default:
5046                                 bad_error("scf_pg_delete", scf_error());
5047                         }
5048                 }
5049 
5050                 /* import new one */
5051                 cbdata.sc_handle = g_hndl;
5052                 cbdata.sc_trans = NULL;         /* handled below */
5053                 cbdata.sc_flags = 0;
5054 
5055                 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5056                 if (r != UU_WALK_NEXT) {
5057                         if (r != UU_WALK_ERROR)
5058                                 bad_error("lscf_dependent_import", r);
5059 
5060                         r = cbdata.sc_err;
5061                         goto out;
5062                 }
5063 
5064                 if (tx == NULL)
5065                         break;
5066 
5067                 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5068                     (val = scf_value_create(g_hndl)) == NULL) {
5069                         if (scf_error() == SCF_ERROR_NO_MEMORY)
5070                                 return (ENOMEM);
5071 
5072                         bad_error("scf_entry_create", scf_error());
5073                 }
5074 
5075                 if (scf_transaction_property_change_type(tx, ent, ud_name,
5076                     SCF_TYPE_FMRI) != 0) {
5077                         switch (scf_error()) {
5078                         case SCF_ERROR_CONNECTION_BROKEN:
5079                                 r = scferror2errno(scf_error());
5080                                 goto out;
5081 
5082                         case SCF_ERROR_DELETED:
5083                                 warn(emsg_pg_deleted, ient->sc_fmri,
5084                                     "dependents");
5085                                 r = EBUSY;
5086                                 goto out;
5087 
5088                         case SCF_ERROR_NOT_FOUND:
5089                                 break;
5090 
5091                         case SCF_ERROR_NOT_BOUND:
5092                         case SCF_ERROR_HANDLE_MISMATCH:
5093                         case SCF_ERROR_INVALID_ARGUMENT:
5094                         case SCF_ERROR_NOT_SET:
5095                         default:
5096                                 bad_error("scf_transaction_property_"
5097                                     "change_type", scf_error());
5098                         }
5099 
5100                         if (scf_transaction_property_new(tx, ent, ud_name,
5101                             SCF_TYPE_FMRI) != 0) {
5102                                 switch (scf_error()) {
5103                                 case SCF_ERROR_CONNECTION_BROKEN:
5104                                         r = scferror2errno(scf_error());
5105                                         goto out;
5106 
5107                                 case SCF_ERROR_DELETED:
5108                                         warn(emsg_pg_deleted, ient->sc_fmri,
5109                                             "dependents");
5110                                         r = EBUSY;
5111                                         goto out;
5112 
5113                                 case SCF_ERROR_EXISTS:
5114                                         warn(emsg_pg_changed, ient->sc_fmri,
5115                                             "dependents");
5116                                         r = EBUSY;
5117                                         goto out;
5118 
5119                                 case SCF_ERROR_INVALID_ARGUMENT:
5120                                 case SCF_ERROR_HANDLE_MISMATCH:
5121                                 case SCF_ERROR_NOT_BOUND:
5122                                 case SCF_ERROR_NOT_SET:
5123                                 default:
5124                                         bad_error("scf_transaction_property_"
5125                                             "new", scf_error());
5126                                 }
5127                         }
5128                 }
5129 
5130                 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5131                     new_dpt_pgroup->sc_pgroup_fmri) != 0)
5132                         /* invalid sc_pgroup_fmri caught above */
5133                         bad_error("scf_value_set_from_string",
5134                             scf_error());
5135 
5136                 if (scf_entry_add_value(ent, val) != 0)
5137                         bad_error("scf_entry_add_value", scf_error());
5138                 break;
5139         }
5140 
5141         case -2:
5142                 warn(li_corrupt, ient->sc_fmri);
5143                 internal_pgroup_free(current_pg);
5144                 r = EBADF;
5145                 goto out;
5146 
5147         case -1:
5148         default:
5149                 /* invalid sc_pgroup_fmri caught above */
5150                 bad_error("fmri_equal", r);
5151         }
5152 
5153         r = 0;
5154 
5155 out:
5156         if (old_dpt_pgroup != NULL)
5157                 internal_pgroup_free(old_dpt_pgroup);
5158 
5159         return (r);
5160 }
5161 
5162 /*
5163  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5164  * would import it, except it seems to exist in the service anyway.  Compare
5165  * the existent dependent with the one we would import, and report any
5166  * differences (if there are none, be silent).  prop is the property which
5167  * represents the existent dependent (in the dependents property group) in the
5168  * entity corresponding to ient.
5169  *
5170  * Returns
5171  *   0 - success (Sort of.  At least, we can continue importing.)
5172  *   ECONNABORTED - repository connection broken
5173  *   EBUSY - ancestor of prop was deleted (error printed)
5174  *   ENOMEM - out of memory
5175  *   EBADF - corrupt property group (error printed)
5176  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5177  */
5178 static int
5179 handle_dependent_conflict(const entity_t * const ient,
5180     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5181 {
5182         int r;
5183         scf_type_t ty;
5184         scf_error_t scfe;
5185         void *tptr;
5186         int tissvc;
5187         pgroup_t *pgroup;
5188 
5189         if (scf_property_get_value(prop, ud_val) != 0) {
5190                 switch (scf_error()) {
5191                 case SCF_ERROR_CONNECTION_BROKEN:
5192                         return (scferror2errno(scf_error()));
5193 
5194                 case SCF_ERROR_DELETED:
5195                         warn(emsg_pg_deleted, ient->sc_fmri,
5196                             new_dpt_pgroup->sc_pgroup_name);
5197                         return (EBUSY);
5198 
5199                 case SCF_ERROR_CONSTRAINT_VIOLATED:
5200                 case SCF_ERROR_NOT_FOUND:
5201                         warn(gettext("Conflict upgrading %s (not importing "
5202                             "dependent \"%s\" because it already exists.)  "
5203                             "Warning: The \"%s/%2$s\" property has more or "
5204                             "fewer than one value)).\n"), ient->sc_fmri,
5205                             new_dpt_pgroup->sc_pgroup_name, "dependents");
5206                         return (0);
5207 
5208                 case SCF_ERROR_HANDLE_MISMATCH:
5209                 case SCF_ERROR_NOT_BOUND:
5210                 case SCF_ERROR_NOT_SET:
5211                 case SCF_ERROR_PERMISSION_DENIED:
5212                 default:
5213                         bad_error("scf_property_get_value",
5214                             scf_error());
5215                 }
5216         }
5217 
5218         ty = scf_value_type(ud_val);
5219         assert(ty != SCF_TYPE_INVALID);
5220         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5221                 warn(gettext("Conflict upgrading %s (not importing dependent "
5222                     "\"%s\" because it already exists).  Warning: The "
5223                     "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5224                     ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5225                     scf_type_to_string(ty), "dependents");
5226                 return (0);
5227         }
5228 
5229         if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5230             0)
5231                 bad_error("scf_value_get_as_string", scf_error());
5232 
5233         r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5234         switch (r) {
5235         case 0:
5236                 warn(gettext("Conflict upgrading %s (not importing dependent "
5237                     "\"%s\" (target \"%s\") because it already exists with "
5238                     "target \"%s\").\n"), ient->sc_fmri,
5239                     new_dpt_pgroup->sc_pgroup_name,
5240                     new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5241                 return (0);
5242 
5243         case 1:
5244                 break;
5245 
5246         case -1:
5247                 warn(gettext("Conflict upgrading %s (not importing dependent "
5248                     "\"%s\" because it already exists).  Warning: The current "
5249                     "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5250                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5251                 return (0);
5252 
5253         case -2:
5254                 warn(gettext("Dependent \"%s\" of %s has invalid target "
5255                     "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5256                     new_dpt_pgroup->sc_pgroup_fmri);
5257                 return (EINVAL);
5258 
5259         default:
5260                 bad_error("fmri_equal", r);
5261         }
5262 
5263         /* compare dependency pgs in target */
5264         scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5265         switch (scfe) {
5266         case SCF_ERROR_NONE:
5267                 break;
5268 
5269         case SCF_ERROR_NO_MEMORY:
5270                 return (ENOMEM);
5271 
5272         case SCF_ERROR_NOT_FOUND:
5273                 warn(emsg_dpt_dangling, ient->sc_fmri,
5274                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5275                 return (0);
5276 
5277         case SCF_ERROR_CONSTRAINT_VIOLATED:
5278         case SCF_ERROR_INVALID_ARGUMENT:
5279         default:
5280                 bad_error("fmri_to_entity", scfe);
5281         }
5282 
5283         r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5284             ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5285         switch (r) {
5286         case 0:
5287                 break;
5288 
5289         case ECONNABORTED:
5290                 return (r);
5291 
5292         case ECANCELED:
5293                 warn(emsg_dpt_dangling, ient->sc_fmri,
5294                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5295                 return (0);
5296 
5297         case EBADF:
5298                 if (tissvc)
5299                         warn(gettext("%s has an instance with a \"%s\" "
5300                             "snapshot which is missing a snaplevel.\n"),
5301                             ud_ctarg, "running");
5302                 else
5303                         warn(gettext("%s has a \"%s\" snapshot which is "
5304                             "missing a snaplevel.\n"), ud_ctarg, "running");
5305                 /* FALLTHROUGH */
5306 
5307         case ENOENT:
5308                 warn(emsg_dpt_no_dep, ient->sc_fmri,
5309                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5310                     new_dpt_pgroup->sc_pgroup_name);
5311                 return (0);
5312 
5313         case EINVAL:
5314         default:
5315                 bad_error("entity_get_running_pg", r);
5316         }
5317 
5318         pgroup = internal_pgroup_new();
5319         if (pgroup == NULL)
5320                 return (ENOMEM);
5321 
5322         r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5323         switch (r) {
5324         case 0:
5325                 break;
5326 
5327         case ECONNABORTED:
5328         case EBADF:
5329         case ENOMEM:
5330                 internal_pgroup_free(pgroup);
5331                 return (r);
5332 
5333         case ECANCELED:
5334                 warn(emsg_dpt_no_dep, ient->sc_fmri,
5335                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5336                     new_dpt_pgroup->sc_pgroup_name);
5337                 internal_pgroup_free(pgroup);
5338                 return (0);
5339 
5340         case EACCES:
5341         default:
5342                 bad_error("load_pg", r);
5343         }
5344 
5345         /* report differences */
5346         report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5347         internal_pgroup_free(pgroup);
5348         return (0);
5349 }
5350 
5351 /*
5352  * lipg is a property group in the last-import snapshot of ent, which is an
5353  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5354  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5355  * in ents's property groups, compare and upgrade ent appropriately.
5356  *
5357  * Returns
5358  *   0 - success
5359  *   ECONNABORTED - repository connection broken
5360  *   ENOMEM - out of memory
5361  *   ENOSPC - configd is out of resources
5362  *   EINVAL - ient has invalid dependent (error printed)
5363  *          - ient has invalid pgroup_t (error printed)
5364  *   ECANCELED - ent has been deleted
5365  *   ENODEV - entity containing lipg has been deleted
5366  *          - entity containing running has been deleted
5367  *   EPERM - could not delete pg (permission denied) (error printed)
5368  *         - couldn't upgrade dependents (permission denied) (error printed)
5369  *         - couldn't import pg (permission denied) (error printed)
5370  *         - couldn't upgrade pg (permission denied) (error printed)
5371  *   EROFS - could not delete pg (repository read-only)
5372  *         - couldn't upgrade dependents (repository read-only)
5373  *         - couldn't import pg (repository read-only)
5374  *         - couldn't upgrade pg (repository read-only)
5375  *   EACCES - could not delete pg (backend access denied)
5376  *          - couldn't upgrade dependents (backend access denied)
5377  *          - couldn't import pg (backend access denied)
5378  *          - couldn't upgrade pg (backend access denied)
5379  *          - couldn't read property (backend access denied)
5380  *   EBUSY - property group was added (error printed)
5381  *         - property group was deleted (error printed)
5382  *         - property group changed (error printed)
5383  *         - "dependents" pg was added, changed, or deleted (error printed)
5384  *         - dependent target deleted (error printed)
5385  *         - dependent pg changed (error printed)
5386  *   EBADF - imp_snpl is corrupt (error printed)
5387  *         - ent has bad pg (error printed)
5388  *   EEXIST - dependent collision in target service (error printed)
5389  */
5390 static int
5391 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5392     const scf_snaplevel_t *running)
5393 {
5394         int r;
5395         pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5396         scf_callback_t cbdata;
5397 
5398         const char * const cf_pg_missing =
5399             gettext("Conflict upgrading %s (property group %s is missing)\n");
5400         const char * const deleting =
5401             gettext("%s: Deleting property group \"%s\".\n");
5402 
5403         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5404 
5405         /* Skip dependent property groups. */
5406         if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5407                 switch (scf_error()) {
5408                 case SCF_ERROR_DELETED:
5409                         return (ENODEV);
5410 
5411                 case SCF_ERROR_CONNECTION_BROKEN:
5412                         return (ECONNABORTED);
5413 
5414                 case SCF_ERROR_NOT_SET:
5415                 case SCF_ERROR_NOT_BOUND:
5416                 default:
5417                         bad_error("scf_pg_get_type", scf_error());
5418                 }
5419         }
5420 
5421         if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5422                 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5423                         return (0);
5424 
5425                 switch (scf_error()) {
5426                 case SCF_ERROR_NOT_FOUND:
5427                         break;
5428 
5429                 case SCF_ERROR_CONNECTION_BROKEN:
5430                         return (ECONNABORTED);
5431 
5432                 case SCF_ERROR_DELETED:
5433                         return (ENODEV);
5434 
5435                 case SCF_ERROR_INVALID_ARGUMENT:
5436                 case SCF_ERROR_NOT_BOUND:
5437                 case SCF_ERROR_HANDLE_MISMATCH:
5438                 case SCF_ERROR_NOT_SET:
5439                 default:
5440                         bad_error("scf_pg_get_property", scf_error());
5441                 }
5442         }
5443 
5444         /* lookup pg in new properties */
5445         if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5446                 switch (scf_error()) {
5447                 case SCF_ERROR_DELETED:
5448                         return (ENODEV);
5449 
5450                 case SCF_ERROR_CONNECTION_BROKEN:
5451                         return (ECONNABORTED);
5452 
5453                 case SCF_ERROR_NOT_SET:
5454                 case SCF_ERROR_NOT_BOUND:
5455                 default:
5456                         bad_error("scf_pg_get_name", scf_error());
5457                 }
5458         }
5459 
5460         pgrp.sc_pgroup_name = imp_str;
5461         mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5462 
5463         if (mpg != NULL)
5464                 mpg->sc_pgroup_seen = 1;
5465 
5466         /* Special handling for dependents */
5467         if (strcmp(imp_str, "dependents") == 0)
5468                 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5469 
5470         if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5471                 return (upgrade_manifestfiles(NULL, ient, running, ent));
5472 
5473         if (mpg == NULL || mpg->sc_pgroup_delete) {
5474                 /* property group was deleted from manifest */
5475                 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5476                         switch (scf_error()) {
5477                         case SCF_ERROR_NOT_FOUND:
5478                                 return (0);
5479 
5480                         case SCF_ERROR_DELETED:
5481                         case SCF_ERROR_CONNECTION_BROKEN:
5482                                 return (scferror2errno(scf_error()));
5483 
5484                         case SCF_ERROR_INVALID_ARGUMENT:
5485                         case SCF_ERROR_HANDLE_MISMATCH:
5486                         case SCF_ERROR_NOT_BOUND:
5487                         case SCF_ERROR_NOT_SET:
5488                         default:
5489                                 bad_error("entity_get_pg", scf_error());
5490                         }
5491                 }
5492 
5493                 if (mpg != NULL && mpg->sc_pgroup_delete) {
5494                         if (g_verbose)
5495                                 warn(deleting, ient->sc_fmri, imp_str);
5496                         if (scf_pg_delete(imp_pg2) == 0)
5497                                 return (0);
5498 
5499                         switch (scf_error()) {
5500                         case SCF_ERROR_DELETED:
5501                                 return (0);
5502 
5503                         case SCF_ERROR_CONNECTION_BROKEN:
5504                         case SCF_ERROR_BACKEND_READONLY:
5505                         case SCF_ERROR_BACKEND_ACCESS:
5506                                 return (scferror2errno(scf_error()));
5507 
5508                         case SCF_ERROR_PERMISSION_DENIED:
5509                                 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5510                                 return (scferror2errno(scf_error()));
5511 
5512                         case SCF_ERROR_NOT_SET:
5513                         default:
5514                                 bad_error("scf_pg_delete", scf_error());
5515                         }
5516                 }
5517 
5518                 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5519                 switch (r) {
5520                 case 0:
5521                         break;
5522 
5523                 case ECANCELED:
5524                         return (ENODEV);
5525 
5526                 case ECONNABORTED:
5527                 case ENOMEM:
5528                 case EBADF:
5529                 case EACCES:
5530                         return (r);
5531 
5532                 default:
5533                         bad_error("load_pg", r);
5534                 }
5535 
5536                 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5537                 switch (r) {
5538                 case 0:
5539                         break;
5540 
5541                 case ECANCELED:
5542                 case ECONNABORTED:
5543                 case ENOMEM:
5544                 case EBADF:
5545                 case EACCES:
5546                         internal_pgroup_free(lipg_i);
5547                         return (r);
5548 
5549                 default:
5550                         bad_error("load_pg", r);
5551                 }
5552 
5553                 if (pg_equal(lipg_i, curpg_i)) {
5554                         if (g_verbose)
5555                                 warn(deleting, ient->sc_fmri, imp_str);
5556                         if (scf_pg_delete(imp_pg2) != 0) {
5557                                 switch (scf_error()) {
5558                                 case SCF_ERROR_DELETED:
5559                                         break;
5560 
5561                                 case SCF_ERROR_CONNECTION_BROKEN:
5562                                         internal_pgroup_free(lipg_i);
5563                                         internal_pgroup_free(curpg_i);
5564                                         return (ECONNABORTED);
5565 
5566                                 case SCF_ERROR_NOT_SET:
5567                                 case SCF_ERROR_NOT_BOUND:
5568                                 default:
5569                                         bad_error("scf_pg_delete", scf_error());
5570                                 }
5571                         }
5572                 } else {
5573                         report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5574                 }
5575 
5576                 internal_pgroup_free(lipg_i);
5577                 internal_pgroup_free(curpg_i);
5578 
5579                 return (0);
5580         }
5581 
5582         /*
5583          * Only dependent pgs can have override set, and we skipped those
5584          * above.
5585          */
5586         assert(!mpg->sc_pgroup_override);
5587 
5588         /* compare */
5589         r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5590         switch (r) {
5591         case 0:
5592                 break;
5593 
5594         case ECANCELED:
5595                 return (ENODEV);
5596 
5597         case ECONNABORTED:
5598         case EBADF:
5599         case ENOMEM:
5600         case EACCES:
5601                 return (r);
5602 
5603         default:
5604                 bad_error("load_pg", r);
5605         }
5606 
5607         if (pg_equal(mpg, lipg_i)) {
5608                 /* The manifest pg has not changed.  Move on. */
5609                 r = 0;
5610                 goto out;
5611         }
5612 
5613         /* upgrade current properties according to lipg & mpg */
5614         if (running != NULL)
5615                 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5616         else
5617                 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5618         if (r != 0) {
5619                 switch (scf_error()) {
5620                 case SCF_ERROR_CONNECTION_BROKEN:
5621                         r = scferror2errno(scf_error());
5622                         goto out;
5623 
5624                 case SCF_ERROR_DELETED:
5625                         if (running != NULL)
5626                                 r = ENODEV;
5627                         else
5628                                 r = ECANCELED;
5629                         goto out;
5630 
5631                 case SCF_ERROR_NOT_FOUND:
5632                         break;
5633 
5634                 case SCF_ERROR_INVALID_ARGUMENT:
5635                 case SCF_ERROR_HANDLE_MISMATCH:
5636                 case SCF_ERROR_NOT_BOUND:
5637                 case SCF_ERROR_NOT_SET:
5638                 default:
5639                         bad_error("entity_get_pg", scf_error());
5640                 }
5641 
5642                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5643 
5644                 r = 0;
5645                 goto out;
5646         }
5647 
5648         r = load_pg_attrs(imp_pg2, &curpg_i);
5649         switch (r) {
5650         case 0:
5651                 break;
5652 
5653         case ECANCELED:
5654                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5655                 r = 0;
5656                 goto out;
5657 
5658         case ECONNABORTED:
5659         case ENOMEM:
5660                 goto out;
5661 
5662         default:
5663                 bad_error("load_pg_attrs", r);
5664         }
5665 
5666         if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5667                 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5668                 internal_pgroup_free(curpg_i);
5669                 r = 0;
5670                 goto out;
5671         }
5672 
5673         internal_pgroup_free(curpg_i);
5674 
5675         r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5676         switch (r) {
5677         case 0:
5678                 break;
5679 
5680         case ECANCELED:
5681                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5682                 r = 0;
5683                 goto out;
5684 
5685         case ECONNABORTED:
5686         case EBADF:
5687         case ENOMEM:
5688         case EACCES:
5689                 goto out;
5690 
5691         default:
5692                 bad_error("load_pg", r);
5693         }
5694 
5695         if (pg_equal(lipg_i, curpg_i) &&
5696             !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5697                 int do_delete = 1;
5698 
5699                 if (g_verbose)
5700                         warn(gettext("%s: Upgrading property group \"%s\".\n"),
5701                             ient->sc_fmri, mpg->sc_pgroup_name);
5702 
5703                 internal_pgroup_free(curpg_i);
5704 
5705                 if (running != NULL &&
5706                     entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5707                         switch (scf_error()) {
5708                         case SCF_ERROR_DELETED:
5709                                 r = ECANCELED;
5710                                 goto out;
5711 
5712                         case SCF_ERROR_NOT_FOUND:
5713                                 do_delete = 0;
5714                                 break;
5715 
5716                         case SCF_ERROR_CONNECTION_BROKEN:
5717                                 r = scferror2errno(scf_error());
5718                                 goto out;
5719 
5720                         case SCF_ERROR_HANDLE_MISMATCH:
5721                         case SCF_ERROR_INVALID_ARGUMENT:
5722                         case SCF_ERROR_NOT_SET:
5723                         case SCF_ERROR_NOT_BOUND:
5724                         default:
5725                                 bad_error("entity_get_pg", scf_error());
5726                         }
5727                 }
5728 
5729                 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5730                         switch (scf_error()) {
5731                         case SCF_ERROR_DELETED:
5732                                 break;
5733 
5734                         case SCF_ERROR_CONNECTION_BROKEN:
5735                         case SCF_ERROR_BACKEND_READONLY:
5736                         case SCF_ERROR_BACKEND_ACCESS:
5737                                 r = scferror2errno(scf_error());
5738                                 goto out;
5739 
5740                         case SCF_ERROR_PERMISSION_DENIED:
5741                                 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5742                                     ient->sc_fmri);
5743                                 r = scferror2errno(scf_error());
5744                                 goto out;
5745 
5746                         case SCF_ERROR_NOT_SET:
5747                         case SCF_ERROR_NOT_BOUND:
5748                         default:
5749                                 bad_error("scf_pg_delete", scf_error());
5750                         }
5751                 }
5752 
5753                 cbdata.sc_handle = g_hndl;
5754                 cbdata.sc_parent = ent;
5755                 cbdata.sc_service = issvc;
5756                 cbdata.sc_flags = 0;
5757                 cbdata.sc_source_fmri = ient->sc_fmri;
5758                 cbdata.sc_target_fmri = ient->sc_fmri;
5759 
5760                 r = entity_pgroup_import(mpg, &cbdata);
5761                 switch (r) {
5762                 case UU_WALK_NEXT:
5763                         r = 0;
5764                         goto out;
5765 
5766                 case UU_WALK_ERROR:
5767                         if (cbdata.sc_err == EEXIST) {
5768                                 warn(emsg_pg_added, ient->sc_fmri,
5769                                     mpg->sc_pgroup_name);
5770                                 r = EBUSY;
5771                         } else {
5772                                 r = cbdata.sc_err;
5773                         }
5774                         goto out;
5775 
5776                 default:
5777                         bad_error("entity_pgroup_import", r);
5778                 }
5779         }
5780 
5781         if (running != NULL &&
5782             entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5783                 switch (scf_error()) {
5784                 case SCF_ERROR_CONNECTION_BROKEN:
5785                 case SCF_ERROR_DELETED:
5786                         r = scferror2errno(scf_error());
5787                         goto out;
5788 
5789                 case SCF_ERROR_NOT_FOUND:
5790                         break;
5791 
5792                 case SCF_ERROR_HANDLE_MISMATCH:
5793                 case SCF_ERROR_INVALID_ARGUMENT:
5794                 case SCF_ERROR_NOT_SET:
5795                 case SCF_ERROR_NOT_BOUND:
5796                 default:
5797                         bad_error("entity_get_pg", scf_error());
5798                 }
5799 
5800                 cbdata.sc_handle = g_hndl;
5801                 cbdata.sc_parent = ent;
5802                 cbdata.sc_service = issvc;
5803                 cbdata.sc_flags = SCI_FORCE;
5804                 cbdata.sc_source_fmri = ient->sc_fmri;
5805                 cbdata.sc_target_fmri = ient->sc_fmri;
5806 
5807                 r = entity_pgroup_import(mpg, &cbdata);
5808                 switch (r) {
5809                 case UU_WALK_NEXT:
5810                         r = 0;
5811                         goto out;
5812 
5813                 case UU_WALK_ERROR:
5814                         if (cbdata.sc_err == EEXIST) {
5815                                 warn(emsg_pg_added, ient->sc_fmri,
5816                                     mpg->sc_pgroup_name);
5817                                 r = EBUSY;
5818                         } else {
5819                                 r = cbdata.sc_err;
5820                         }
5821                         goto out;
5822 
5823                 default:
5824                         bad_error("entity_pgroup_import", r);
5825                 }
5826         }
5827 
5828         r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5829         internal_pgroup_free(curpg_i);
5830         switch (r) {
5831         case 0:
5832                 ient->sc_import_state = IMPORT_PROP_BEGUN;
5833                 break;
5834 
5835         case ECANCELED:
5836                 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5837                 r = EBUSY;
5838                 break;
5839 
5840         case EPERM:
5841                 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5842                 break;
5843 
5844         case EBUSY:
5845                 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5846                 break;
5847 
5848         case ECONNABORTED:
5849         case ENOMEM:
5850         case ENOSPC:
5851         case EROFS:
5852         case EACCES:
5853         case EINVAL:
5854                 break;
5855 
5856         default:
5857                 bad_error("upgrade_pg", r);
5858         }
5859 
5860 out:
5861         internal_pgroup_free(lipg_i);
5862         return (r);
5863 }
5864 
5865 /*
5866  * Upgrade the properties of ent according to snpl & ient.
5867  *
5868  * Returns
5869  *   0 - success
5870  *   ECONNABORTED - repository connection broken
5871  *   ENOMEM - out of memory
5872  *   ENOSPC - configd is out of resources
5873  *   ECANCELED - ent was deleted
5874  *   ENODEV - entity containing snpl was deleted
5875  *          - entity containing running was deleted
5876  *   EBADF - imp_snpl is corrupt (error printed)
5877  *         - ent has corrupt pg (error printed)
5878  *         - dependent has corrupt pg (error printed)
5879  *         - dependent target has a corrupt snapshot (error printed)
5880  *   EBUSY - pg was added, changed, or deleted (error printed)
5881  *         - dependent target was deleted (error printed)
5882  *         - dependent pg changed (error printed)
5883  *   EINVAL - invalid property group name (error printed)
5884  *          - invalid property name (error printed)
5885  *          - invalid value (error printed)
5886  *          - ient has invalid pgroup or dependent (error printed)
5887  *   EPERM - could not create property group (permission denied) (error printed)
5888  *         - could not modify property group (permission denied) (error printed)
5889  *         - couldn't delete, upgrade, or import pg or dependent (error printed)
5890  *   EROFS - could not create property group (repository read-only)
5891  *         - couldn't delete, upgrade, or import pg or dependent
5892  *   EACCES - could not create property group (backend access denied)
5893  *          - couldn't delete, upgrade, or import pg or dependent
5894  *   EEXIST - dependent collision in target service (error printed)
5895  */
5896 static int
5897 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5898     entity_t *ient)
5899 {
5900         pgroup_t *pg, *rpg;
5901         int r;
5902         uu_list_t *pgs = ient->sc_pgroups;
5903 
5904         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5905 
5906         /* clear sc_sceen for pgs */
5907         if (uu_list_walk(pgs, clear_int,
5908             (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5909                 bad_error("uu_list_walk", uu_error());
5910 
5911         if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5912                 switch (scf_error()) {
5913                 case SCF_ERROR_DELETED:
5914                         return (ENODEV);
5915 
5916                 case SCF_ERROR_CONNECTION_BROKEN:
5917                         return (ECONNABORTED);
5918 
5919                 case SCF_ERROR_NOT_SET:
5920                 case SCF_ERROR_NOT_BOUND:
5921                 case SCF_ERROR_HANDLE_MISMATCH:
5922                 default:
5923                         bad_error("scf_iter_snaplevel_pgs", scf_error());
5924                 }
5925         }
5926 
5927         for (;;) {
5928                 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5929                 if (r == 0)
5930                         break;
5931                 if (r == 1) {
5932                         r = process_old_pg(imp_pg, ient, ent, running);
5933                         switch (r) {
5934                         case 0:
5935                                 break;
5936 
5937                         case ECONNABORTED:
5938                         case ENOMEM:
5939                         case ENOSPC:
5940                         case ECANCELED:
5941                         case ENODEV:
5942                         case EPERM:
5943                         case EROFS:
5944                         case EACCES:
5945                         case EBADF:
5946                         case EBUSY:
5947                         case EINVAL:
5948                         case EEXIST:
5949                                 return (r);
5950 
5951                         default:
5952                                 bad_error("process_old_pg", r);
5953                         }
5954                         continue;
5955                 }
5956                 if (r != -1)
5957                         bad_error("scf_iter_next_pg", r);
5958 
5959                 switch (scf_error()) {
5960                 case SCF_ERROR_DELETED:
5961                         return (ENODEV);
5962 
5963                 case SCF_ERROR_CONNECTION_BROKEN:
5964                         return (ECONNABORTED);
5965 
5966                 case SCF_ERROR_HANDLE_MISMATCH:
5967                 case SCF_ERROR_NOT_BOUND:
5968                 case SCF_ERROR_NOT_SET:
5969                 case SCF_ERROR_INVALID_ARGUMENT:
5970                 default:
5971                         bad_error("scf_iter_next_pg", scf_error());
5972                 }
5973         }
5974 
5975         for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5976                 if (pg->sc_pgroup_seen)
5977                         continue;
5978 
5979                 /* pg is new */
5980 
5981                 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5982                         r = upgrade_dependents(NULL, imp_snpl, ient, running,
5983                             ent);
5984                         switch (r) {
5985                         case 0:
5986                                 break;
5987 
5988                         case ECONNABORTED:
5989                         case ENOMEM:
5990                         case ENOSPC:
5991                         case ECANCELED:
5992                         case ENODEV:
5993                         case EBADF:
5994                         case EBUSY:
5995                         case EINVAL:
5996                         case EPERM:
5997                         case EROFS:
5998                         case EACCES:
5999                         case EEXIST:
6000                                 return (r);
6001 
6002                         default:
6003                                 bad_error("upgrade_dependents", r);
6004                         }
6005                         continue;
6006                 }
6007 
6008                 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6009                         r = upgrade_manifestfiles(pg, ient, running, ent);
6010                         switch (r) {
6011                         case 0:
6012                                 break;
6013 
6014                         case ECONNABORTED:
6015                         case ENOMEM:
6016                         case ENOSPC:
6017                         case ECANCELED:
6018                         case ENODEV:
6019                         case EBADF:
6020                         case EBUSY:
6021                         case EINVAL:
6022                         case EPERM:
6023                         case EROFS:
6024                         case EACCES:
6025                         case EEXIST:
6026                                 return (r);
6027 
6028                         default:
6029                                 bad_error("upgrade_manifestfiles", r);
6030                         }
6031                         continue;
6032                 }
6033 
6034                 if (running != NULL) {
6035                         r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6036                             imp_pg);
6037                 } else {
6038                         r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6039                             imp_pg);
6040                 }
6041                 if (r != 0) {
6042                         scf_callback_t cbdata;
6043 
6044                         switch (scf_error()) {
6045                         case SCF_ERROR_NOT_FOUND:
6046                                 break;
6047 
6048                         case SCF_ERROR_CONNECTION_BROKEN:
6049                                 return (scferror2errno(scf_error()));
6050 
6051                         case SCF_ERROR_DELETED:
6052                                 if (running != NULL)
6053                                         return (ENODEV);
6054                                 else
6055                                         return (scferror2errno(scf_error()));
6056 
6057                         case SCF_ERROR_INVALID_ARGUMENT:
6058                                 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6059                                     pg->sc_pgroup_name);
6060                                 return (EINVAL);
6061 
6062                         case SCF_ERROR_NOT_SET:
6063                         case SCF_ERROR_HANDLE_MISMATCH:
6064                         case SCF_ERROR_NOT_BOUND:
6065                         default:
6066                                 bad_error("entity_get_pg", scf_error());
6067                         }
6068 
6069                         /* User doesn't have pg, so import it. */
6070 
6071                         cbdata.sc_handle = g_hndl;
6072                         cbdata.sc_parent = ent;
6073                         cbdata.sc_service = issvc;
6074                         cbdata.sc_flags = SCI_FORCE;
6075                         cbdata.sc_source_fmri = ient->sc_fmri;
6076                         cbdata.sc_target_fmri = ient->sc_fmri;
6077 
6078                         r = entity_pgroup_import(pg, &cbdata);
6079                         switch (r) {
6080                         case UU_WALK_NEXT:
6081                                 ient->sc_import_state = IMPORT_PROP_BEGUN;
6082                                 continue;
6083 
6084                         case UU_WALK_ERROR:
6085                                 if (cbdata.sc_err == EEXIST) {
6086                                         warn(emsg_pg_added, ient->sc_fmri,
6087                                             pg->sc_pgroup_name);
6088                                         return (EBUSY);
6089                                 }
6090                                 return (cbdata.sc_err);
6091 
6092                         default:
6093                                 bad_error("entity_pgroup_import", r);
6094                         }
6095                 }
6096 
6097                 /* report differences between pg & current */
6098                 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6099                 switch (r) {
6100                 case 0:
6101                         break;
6102 
6103                 case ECANCELED:
6104                         warn(emsg_pg_deleted, ient->sc_fmri,
6105                             pg->sc_pgroup_name);
6106                         return (EBUSY);
6107 
6108                 case ECONNABORTED:
6109                 case EBADF:
6110                 case ENOMEM:
6111                 case EACCES:
6112                         return (r);
6113 
6114                 default:
6115                         bad_error("load_pg", r);
6116                 }
6117                 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6118                 internal_pgroup_free(rpg);
6119                 rpg = NULL;
6120         }
6121 
6122         return (0);
6123 }
6124 
6125 /*
6126  * Import an instance.  If it doesn't exist, create it.  If it has
6127  * a last-import snapshot, upgrade its properties.  Finish by updating its
6128  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6129  * could have been created for a dependent tag in another manifest.  Import the
6130  * new properties.  If there's a conflict, don't override, like now?
6131  *
6132  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6133  * lcbdata->sc_err to
6134  *   ECONNABORTED - repository connection broken
6135  *   ENOMEM - out of memory
6136  *   ENOSPC - svc.configd is out of resources
6137  *   EEXIST - dependency collision in dependent service (error printed)
6138  *   EPERM - couldn't create temporary instance (permission denied)
6139  *         - couldn't import into temporary instance (permission denied)
6140  *         - couldn't take snapshot (permission denied)
6141  *         - couldn't upgrade properties (permission denied)
6142  *         - couldn't import properties (permission denied)
6143  *         - couldn't import dependents (permission denied)
6144  *   EROFS - couldn't create temporary instance (repository read-only)
6145  *         - couldn't import into temporary instance (repository read-only)
6146  *         - couldn't upgrade properties (repository read-only)
6147  *         - couldn't import properties (repository read-only)
6148  *         - couldn't import dependents (repository read-only)
6149  *   EACCES - couldn't create temporary instance (backend access denied)
6150  *          - couldn't import into temporary instance (backend access denied)
6151  *          - couldn't upgrade properties (backend access denied)
6152  *          - couldn't import properties (backend access denied)
6153  *          - couldn't import dependents (backend access denied)
6154  *   EINVAL - invalid instance name (error printed)
6155  *          - invalid pgroup_t's (error printed)
6156  *          - invalid dependents (error printed)
6157  *   EBUSY - temporary service deleted (error printed)
6158  *         - temporary instance deleted (error printed)
6159  *         - temporary instance changed (error printed)
6160  *         - temporary instance already exists (error printed)
6161  *         - instance deleted (error printed)
6162  *   EBADF - instance has corrupt last-import snapshot (error printed)
6163  *         - instance is corrupt (error printed)
6164  *         - dependent has corrupt pg (error printed)
6165  *         - dependent target has a corrupt snapshot (error printed)
6166  *   -1 - unknown libscf error (error printed)
6167  */
6168 static int
6169 lscf_instance_import(void *v, void *pvt)
6170 {
6171         entity_t *inst = v;
6172         scf_callback_t ctx;
6173         scf_callback_t *lcbdata = pvt;
6174         scf_service_t *rsvc = lcbdata->sc_parent;
6175         int r;
6176         scf_snaplevel_t *running;
6177         int flags = lcbdata->sc_flags;
6178 
6179         const char * const emsg_tdel =
6180             gettext("Temporary instance svc:/%s:%s was deleted.\n");
6181         const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6182             "changed unexpectedly.\n");
6183         const char * const emsg_del = gettext("%s changed unexpectedly "
6184             "(instance \"%s\" was deleted.)\n");
6185         const char * const emsg_badsnap = gettext(
6186             "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6187 
6188         /*
6189          * prepare last-import snapshot:
6190          * create temporary instance (service was precreated)
6191          * populate with properties from bundle
6192          * take snapshot
6193          */
6194         if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6195                 switch (scf_error()) {
6196                 case SCF_ERROR_CONNECTION_BROKEN:
6197                 case SCF_ERROR_NO_RESOURCES:
6198                 case SCF_ERROR_BACKEND_READONLY:
6199                 case SCF_ERROR_BACKEND_ACCESS:
6200                         return (stash_scferror(lcbdata));
6201 
6202                 case SCF_ERROR_EXISTS:
6203                         warn(gettext("Temporary service svc:/%s "
6204                             "changed unexpectedly (instance \"%s\" added).\n"),
6205                             imp_tsname, inst->sc_name);
6206                         lcbdata->sc_err = EBUSY;
6207                         return (UU_WALK_ERROR);
6208 
6209                 case SCF_ERROR_DELETED:
6210                         warn(gettext("Temporary service svc:/%s "
6211                             "was deleted unexpectedly.\n"), imp_tsname);
6212                         lcbdata->sc_err = EBUSY;
6213                         return (UU_WALK_ERROR);
6214 
6215                 case SCF_ERROR_INVALID_ARGUMENT:
6216                         warn(gettext("Invalid instance name \"%s\".\n"),
6217                             inst->sc_name);
6218                         return (stash_scferror(lcbdata));
6219 
6220                 case SCF_ERROR_PERMISSION_DENIED:
6221                         warn(gettext("Could not create temporary instance "
6222                             "\"%s\" in svc:/%s (permission denied).\n"),
6223                             inst->sc_name, imp_tsname);
6224                         return (stash_scferror(lcbdata));
6225 
6226                 case SCF_ERROR_HANDLE_MISMATCH:
6227                 case SCF_ERROR_NOT_BOUND:
6228                 case SCF_ERROR_NOT_SET:
6229                 default:
6230                         bad_error("scf_service_add_instance", scf_error());
6231                 }
6232         }
6233 
6234         r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6235             inst->sc_name);
6236         if (r < 0)
6237                 bad_error("snprintf", errno);
6238 
6239         r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6240             lcbdata->sc_flags | SCI_NOENABLED);
6241         switch (r) {
6242         case 0:
6243                 break;
6244 
6245         case ECANCELED:
6246                 warn(emsg_tdel, imp_tsname, inst->sc_name);
6247                 lcbdata->sc_err = EBUSY;
6248                 r = UU_WALK_ERROR;
6249                 goto deltemp;
6250 
6251         case EEXIST:
6252                 warn(emsg_tchg, imp_tsname, inst->sc_name);
6253                 lcbdata->sc_err = EBUSY;
6254                 r = UU_WALK_ERROR;
6255                 goto deltemp;
6256 
6257         case ECONNABORTED:
6258                 goto connaborted;
6259 
6260         case ENOMEM:
6261         case ENOSPC:
6262         case EPERM:
6263         case EROFS:
6264         case EACCES:
6265         case EINVAL:
6266         case EBUSY:
6267                 lcbdata->sc_err = r;
6268                 r = UU_WALK_ERROR;
6269                 goto deltemp;
6270 
6271         default:
6272                 bad_error("lscf_import_instance_pgs", r);
6273         }
6274 
6275         r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6276             inst->sc_name);
6277         if (r < 0)
6278                 bad_error("snprintf", errno);
6279 
6280         ctx.sc_handle = lcbdata->sc_handle;
6281         ctx.sc_parent = imp_tinst;
6282         ctx.sc_service = 0;
6283         ctx.sc_source_fmri = inst->sc_fmri;
6284         ctx.sc_target_fmri = imp_str;
6285         if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6286             UU_DEFAULT) != 0) {
6287                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6288                         bad_error("uu_list_walk", uu_error());
6289 
6290                 switch (ctx.sc_err) {
6291                 case ECONNABORTED:
6292                         goto connaborted;
6293 
6294                 case ECANCELED:
6295                         warn(emsg_tdel, imp_tsname, inst->sc_name);
6296                         lcbdata->sc_err = EBUSY;
6297                         break;
6298 
6299                 case EEXIST:
6300                         warn(emsg_tchg, imp_tsname, inst->sc_name);
6301                         lcbdata->sc_err = EBUSY;
6302                         break;
6303 
6304                 default:
6305                         lcbdata->sc_err = ctx.sc_err;
6306                 }
6307                 r = UU_WALK_ERROR;
6308                 goto deltemp;
6309         }
6310 
6311         if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6312             inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6313                 switch (scf_error()) {
6314                 case SCF_ERROR_CONNECTION_BROKEN:
6315                         goto connaborted;
6316 
6317                 case SCF_ERROR_NO_RESOURCES:
6318                         r = stash_scferror(lcbdata);
6319                         goto deltemp;
6320 
6321                 case SCF_ERROR_EXISTS:
6322                         warn(emsg_tchg, imp_tsname, inst->sc_name);
6323                         lcbdata->sc_err = EBUSY;
6324                         r = UU_WALK_ERROR;
6325                         goto deltemp;
6326 
6327                 case SCF_ERROR_PERMISSION_DENIED:
6328                         warn(gettext("Could not take \"%s\" snapshot of %s "
6329                             "(permission denied).\n"), snap_lastimport,
6330                             imp_str);
6331                         r = stash_scferror(lcbdata);
6332                         goto deltemp;
6333 
6334                 default:
6335                         scfwarn();
6336                         lcbdata->sc_err = -1;
6337                         r = UU_WALK_ERROR;
6338                         goto deltemp;
6339 
6340                 case SCF_ERROR_HANDLE_MISMATCH:
6341                 case SCF_ERROR_INVALID_ARGUMENT:
6342                 case SCF_ERROR_NOT_SET:
6343                         bad_error("_scf_snapshot_take_new_named", scf_error());
6344                 }
6345         }
6346 
6347         if (lcbdata->sc_flags & SCI_FRESH)
6348                 goto fresh;
6349 
6350         if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6351                 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6352                     imp_lisnap) != 0) {
6353                         switch (scf_error()) {
6354                         case SCF_ERROR_DELETED:
6355                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6356                                     inst->sc_name);
6357                                 lcbdata->sc_err = EBUSY;
6358                                 r = UU_WALK_ERROR;
6359                                 goto deltemp;
6360 
6361                         case SCF_ERROR_NOT_FOUND:
6362                                 flags |= SCI_FORCE;
6363                                 goto nosnap;
6364 
6365                         case SCF_ERROR_CONNECTION_BROKEN:
6366                                 goto connaborted;
6367 
6368                         case SCF_ERROR_INVALID_ARGUMENT:
6369                         case SCF_ERROR_HANDLE_MISMATCH:
6370                         case SCF_ERROR_NOT_BOUND:
6371                         case SCF_ERROR_NOT_SET:
6372                         default:
6373                                 bad_error("scf_instance_get_snapshot",
6374                                     scf_error());
6375                         }
6376                 }
6377 
6378                 /* upgrade */
6379 
6380                 /*
6381                  * compare new properties with last-import properties
6382                  * upgrade current properties
6383                  */
6384                 /* clear sc_sceen for pgs */
6385                 if (uu_list_walk(inst->sc_pgroups, clear_int,
6386                     (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6387                     0)
6388                         bad_error("uu_list_walk", uu_error());
6389 
6390                 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6391                 switch (r) {
6392                 case 0:
6393                         break;
6394 
6395                 case ECONNABORTED:
6396                         goto connaborted;
6397 
6398                 case ECANCELED:
6399                         warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6400                         lcbdata->sc_err = EBUSY;
6401                         r = UU_WALK_ERROR;
6402                         goto deltemp;
6403 
6404                 case ENOENT:
6405                         warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6406                         lcbdata->sc_err = EBADF;
6407                         r = UU_WALK_ERROR;
6408                         goto deltemp;
6409 
6410                 default:
6411                         bad_error("get_snaplevel", r);
6412                 }
6413 
6414                 if (scf_instance_get_snapshot(imp_inst, snap_running,
6415                     imp_rsnap) != 0) {
6416                         switch (scf_error()) {
6417                         case SCF_ERROR_DELETED:
6418                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6419                                     inst->sc_name);
6420                                 lcbdata->sc_err = EBUSY;
6421                                 r = UU_WALK_ERROR;
6422                                 goto deltemp;
6423 
6424                         case SCF_ERROR_NOT_FOUND:
6425                                 break;
6426 
6427                         case SCF_ERROR_CONNECTION_BROKEN:
6428                                 goto connaborted;
6429 
6430                         case SCF_ERROR_INVALID_ARGUMENT:
6431                         case SCF_ERROR_HANDLE_MISMATCH:
6432                         case SCF_ERROR_NOT_BOUND:
6433                         case SCF_ERROR_NOT_SET:
6434                         default:
6435                                 bad_error("scf_instance_get_snapshot",
6436                                     scf_error());
6437                         }
6438 
6439                         running = NULL;
6440                 } else {
6441                         r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6442                         switch (r) {
6443                         case 0:
6444                                 running = imp_rsnpl;
6445                                 break;
6446 
6447                         case ECONNABORTED:
6448                                 goto connaborted;
6449 
6450                         case ECANCELED:
6451                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6452                                     inst->sc_name);
6453                                 lcbdata->sc_err = EBUSY;
6454                                 r = UU_WALK_ERROR;
6455                                 goto deltemp;
6456 
6457                         case ENOENT:
6458                                 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6459                                 lcbdata->sc_err = EBADF;
6460                                 r = UU_WALK_ERROR;
6461                                 goto deltemp;
6462 
6463                         default:
6464                                 bad_error("get_snaplevel", r);
6465                         }
6466                 }
6467 
6468                 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6469                 switch (r) {
6470                 case 0:
6471                         break;
6472 
6473                 case ECANCELED:
6474                 case ENODEV:
6475                         warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6476                         lcbdata->sc_err = EBUSY;
6477                         r = UU_WALK_ERROR;
6478                         goto deltemp;
6479 
6480                 case ECONNABORTED:
6481                         goto connaborted;
6482 
6483                 case ENOMEM:
6484                 case ENOSPC:
6485                 case EBADF:
6486                 case EBUSY:
6487                 case EINVAL:
6488                 case EPERM:
6489                 case EROFS:
6490                 case EACCES:
6491                 case EEXIST:
6492                         lcbdata->sc_err = r;
6493                         r = UU_WALK_ERROR;
6494                         goto deltemp;
6495 
6496                 default:
6497                         bad_error("upgrade_props", r);
6498                 }
6499 
6500                 inst->sc_import_state = IMPORT_PROP_DONE;
6501         } else {
6502                 switch (scf_error()) {
6503                 case SCF_ERROR_CONNECTION_BROKEN:
6504                         goto connaborted;
6505 
6506                 case SCF_ERROR_NOT_FOUND:
6507                         break;
6508 
6509                 case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
6510                 case SCF_ERROR_HANDLE_MISMATCH:
6511                 case SCF_ERROR_NOT_BOUND:
6512                 case SCF_ERROR_NOT_SET:
6513                 default:
6514                         bad_error("scf_service_get_instance", scf_error());
6515                 }
6516 
6517 fresh:
6518                 /* create instance */
6519                 if (scf_service_add_instance(rsvc, inst->sc_name,
6520                     imp_inst) != 0) {
6521                         switch (scf_error()) {
6522                         case SCF_ERROR_CONNECTION_BROKEN:
6523                                 goto connaborted;
6524 
6525                         case SCF_ERROR_NO_RESOURCES:
6526                         case SCF_ERROR_BACKEND_READONLY:
6527                         case SCF_ERROR_BACKEND_ACCESS:
6528                                 r = stash_scferror(lcbdata);
6529                                 goto deltemp;
6530 
6531                         case SCF_ERROR_EXISTS:
6532                                 warn(gettext("%s changed unexpectedly "
6533                                     "(instance \"%s\" added).\n"),
6534                                     inst->sc_parent->sc_fmri, inst->sc_name);
6535                                 lcbdata->sc_err = EBUSY;
6536                                 r = UU_WALK_ERROR;
6537                                 goto deltemp;
6538 
6539                         case SCF_ERROR_PERMISSION_DENIED:
6540                                 warn(gettext("Could not create \"%s\" instance "
6541                                     "in %s (permission denied).\n"),
6542                                     inst->sc_name, inst->sc_parent->sc_fmri);
6543                                 r = stash_scferror(lcbdata);
6544                                 goto deltemp;
6545 
6546                         case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6547                         case SCF_ERROR_HANDLE_MISMATCH:
6548                         case SCF_ERROR_NOT_BOUND:
6549                         case SCF_ERROR_NOT_SET:
6550                         default:
6551                                 bad_error("scf_service_add_instance",
6552                                     scf_error());
6553                         }
6554                 }
6555 
6556 nosnap:
6557                 /*
6558                  * Create a last-import snapshot to serve as an attachment
6559                  * point for the real one from the temporary instance.  Since
6560                  * the contents is irrelevant, take it now, while the instance
6561                  * is empty, to minimize svc.configd's work.
6562                  */
6563                 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6564                     imp_lisnap) != 0) {
6565                         switch (scf_error()) {
6566                         case SCF_ERROR_CONNECTION_BROKEN:
6567                                 goto connaborted;
6568 
6569                         case SCF_ERROR_NO_RESOURCES:
6570                                 r = stash_scferror(lcbdata);
6571                                 goto deltemp;
6572 
6573                         case SCF_ERROR_EXISTS:
6574                                 warn(gettext("%s changed unexpectedly "
6575                                     "(snapshot \"%s\" added).\n"),
6576                                     inst->sc_fmri, snap_lastimport);
6577                                 lcbdata->sc_err = EBUSY;
6578                                 r = UU_WALK_ERROR;
6579                                 goto deltemp;
6580 
6581                         case SCF_ERROR_PERMISSION_DENIED:
6582                                 warn(gettext("Could not take \"%s\" snapshot "
6583                                     "of %s (permission denied).\n"),
6584                                     snap_lastimport, inst->sc_fmri);
6585                                 r = stash_scferror(lcbdata);
6586                                 goto deltemp;
6587 
6588                         default:
6589                                 scfwarn();
6590                                 lcbdata->sc_err = -1;
6591                                 r = UU_WALK_ERROR;
6592                                 goto deltemp;
6593 
6594                         case SCF_ERROR_NOT_SET:
6595                         case SCF_ERROR_INTERNAL:
6596                         case SCF_ERROR_INVALID_ARGUMENT:
6597                         case SCF_ERROR_HANDLE_MISMATCH:
6598                                 bad_error("_scf_snapshot_take_new",
6599                                     scf_error());
6600                         }
6601                 }
6602 
6603                 if (li_only)
6604                         goto lionly;
6605 
6606                 inst->sc_import_state = IMPORT_PROP_BEGUN;
6607 
6608                 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6609                     flags);
6610                 switch (r) {
6611                 case 0:
6612                         break;
6613 
6614                 case ECONNABORTED:
6615                         goto connaborted;
6616 
6617                 case ECANCELED:
6618                         warn(gettext("%s changed unexpectedly "
6619                             "(instance \"%s\" deleted).\n"),
6620                             inst->sc_parent->sc_fmri, inst->sc_name);
6621                         lcbdata->sc_err = EBUSY;
6622                         r = UU_WALK_ERROR;
6623                         goto deltemp;
6624 
6625                 case EEXIST:
6626                         warn(gettext("%s changed unexpectedly "
6627                             "(property group added).\n"), inst->sc_fmri);
6628                         lcbdata->sc_err = EBUSY;
6629                         r = UU_WALK_ERROR;
6630                         goto deltemp;
6631 
6632                 default:
6633                         lcbdata->sc_err = r;
6634                         r = UU_WALK_ERROR;
6635                         goto deltemp;
6636 
6637                 case EINVAL:    /* caught above */
6638                         bad_error("lscf_import_instance_pgs", r);
6639                 }
6640 
6641                 ctx.sc_parent = imp_inst;
6642                 ctx.sc_service = 0;
6643                 ctx.sc_trans = NULL;
6644                 ctx.sc_flags = 0;
6645                 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6646                     &ctx, UU_DEFAULT) != 0) {
6647                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6648                                 bad_error("uu_list_walk", uu_error());
6649 
6650                         if (ctx.sc_err == ECONNABORTED)
6651                                 goto connaborted;
6652                         lcbdata->sc_err = ctx.sc_err;
6653                         r = UU_WALK_ERROR;
6654                         goto deltemp;
6655                 }
6656 
6657                 inst->sc_import_state = IMPORT_PROP_DONE;
6658 
6659                 if (g_verbose)
6660                         warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6661                             snap_initial, inst->sc_fmri);
6662                 r = take_snap(imp_inst, snap_initial, imp_snap);
6663                 switch (r) {
6664                 case 0:
6665                         break;
6666 
6667                 case ECONNABORTED:
6668                         goto connaborted;
6669 
6670                 case ENOSPC:
6671                 case -1:
6672                         lcbdata->sc_err = r;
6673                         r = UU_WALK_ERROR;
6674                         goto deltemp;
6675 
6676                 case ECANCELED:
6677                         warn(gettext("%s changed unexpectedly "
6678                             "(instance %s deleted).\n"),
6679                             inst->sc_parent->sc_fmri, inst->sc_name);
6680                         lcbdata->sc_err = r;
6681                         r = UU_WALK_ERROR;
6682                         goto deltemp;
6683 
6684                 case EPERM:
6685                         warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6686                         lcbdata->sc_err = r;
6687                         r = UU_WALK_ERROR;
6688                         goto deltemp;
6689 
6690                 default:
6691                         bad_error("take_snap", r);
6692                 }
6693         }
6694 
6695 lionly:
6696         if (lcbdata->sc_flags & SCI_NOSNAP)
6697                 goto deltemp;
6698 
6699         /* transfer snapshot from temporary instance */
6700         if (g_verbose)
6701                 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6702                     snap_lastimport, inst->sc_fmri);
6703         if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6704                 switch (scf_error()) {
6705                 case SCF_ERROR_CONNECTION_BROKEN:
6706                         goto connaborted;
6707 
6708                 case SCF_ERROR_NO_RESOURCES:
6709                         r = stash_scferror(lcbdata);
6710                         goto deltemp;
6711 
6712                 case SCF_ERROR_PERMISSION_DENIED:
6713                         warn(gettext("Could not take \"%s\" snapshot for %s "
6714                             "(permission denied).\n"), snap_lastimport,
6715                             inst->sc_fmri);
6716                         r = stash_scferror(lcbdata);
6717                         goto deltemp;
6718 
6719                 case SCF_ERROR_NOT_SET:
6720                 case SCF_ERROR_HANDLE_MISMATCH:
6721                 default:
6722                         bad_error("_scf_snapshot_attach", scf_error());
6723                 }
6724         }
6725 
6726         inst->sc_import_state = IMPORT_COMPLETE;
6727 
6728         r = UU_WALK_NEXT;
6729 
6730 deltemp:
6731         /* delete temporary instance */
6732         if (scf_instance_delete(imp_tinst) != 0) {
6733                 switch (scf_error()) {
6734                 case SCF_ERROR_DELETED:
6735                         break;
6736 
6737                 case SCF_ERROR_CONNECTION_BROKEN:
6738                         goto connaborted;
6739 
6740                 case SCF_ERROR_NOT_SET:
6741                 case SCF_ERROR_NOT_BOUND:
6742                 default:
6743                         bad_error("scf_instance_delete", scf_error());
6744                 }
6745         }
6746 
6747         return (r);
6748 
6749 connaborted:
6750         warn(gettext("Could not delete svc:/%s:%s "
6751             "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6752         lcbdata->sc_err = ECONNABORTED;
6753         return (UU_WALK_ERROR);
6754 }
6755 
6756 /*
6757  * When an instance is imported we end up telling configd about it. Once we tell
6758  * configd about these changes, startd eventually notices. If this is a new
6759  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6760  * property group. However, many of the other tools expect that this property
6761  * group exists and has certain values.
6762  *
6763  * These values are added asynchronously by startd. We should not return from
6764  * this routine until we can verify that the property group we need is there.
6765  *
6766  * Before we go ahead and verify this, we have to ask ourselves an important
6767  * question: Is the early manifest service currently running?  Because if it is
6768  * running and it has invoked us, then the service will never get a restarter
6769  * property because svc.startd is blocked on EMI finishing before it lets itself
6770  * fully connect to svc.configd. Of course, this means that this race condition
6771  * is in fact impossible to 100% eliminate.
6772  *
6773  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6774  * the state of the EMI instance. If it is online it bails out and makes sure
6775  * that it doesn't run again. In this case, we're going to do something similar,
6776  * only if the state is online, then we're going to actually verify. EMI always
6777  * has to be present, but it can be explicitly disabled to reduce the amount of
6778  * damage it can cause. If EMI has been disabled then we no longer have to worry
6779  * about the implicit race condition and can go ahead and check things. If EMI
6780  * is in some state that isn't online or disabled and isn't runinng, then we
6781  * assume that things are rather bad and we're not going to get in your way,
6782  * even if the rest of SMF does.
6783  *
6784  * Returns 0 on success or returns an errno.
6785  */
6786 #ifndef NATIVE_BUILD
6787 static int
6788 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6789 {
6790         int ret, err;
6791         struct timespec ts;
6792         char *emi_state;
6793 
6794         /*
6795          * smf_get_state does not distinguish between its different failure
6796          * modes: memory allocation failures, SMF internal failures, and a lack
6797          * of EMI entirely because it's been removed. In these cases, we're
6798          * going to be conservative and opt to say that if we don't know, better
6799          * to not block import or falsely warn to the user.
6800          */
6801         if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6802                 return (0);
6803         }
6804 
6805         /*
6806          * As per the block comment for this function check the state of EMI
6807          */
6808         if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6809             strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6810                 warn(gettext("Not validating instance %s:%s because EMI's "
6811                     "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6812                 free(emi_state);
6813                 return (0);
6814         }
6815 
6816         free(emi_state);
6817 
6818         /*
6819          * First we have to get the property.
6820          */
6821         if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6822                 ret = scf_error();
6823                 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6824                 return (ret);
6825         }
6826 
6827         /*
6828          * We should always be able to get the instance. It should already
6829          * exist because we just created it or got it. There probably is a
6830          * slim chance that someone may have come in and deleted it though from
6831          * under us.
6832          */
6833         if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6834             != 0) {
6835                 ret = scf_error();
6836                 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6837                 switch (ret) {
6838                 case SCF_ERROR_DELETED:
6839                         err = ENODEV;
6840                         break;
6841                 case SCF_ERROR_CONNECTION_BROKEN:
6842                         warn(gettext("Lost repository connection\n"));
6843                         err = ECONNABORTED;
6844                         break;
6845                 case SCF_ERROR_NOT_FOUND:
6846                         warn(gettext("Instance \"%s\" disappeared out from "
6847                             "under us.\n"), inst->sc_name);
6848                         err = ENOENT;
6849                         break;
6850                 default:
6851                         bad_error("scf_service_get_instance", ret);
6852                 }
6853 
6854                 return (err);
6855         }
6856 
6857         /*
6858          * An astute observer may want to use _scf_wait_pg which would notify us
6859          * of a property group change, unfortunately that does not work if the
6860          * property group in question does not exist. So instead we have to
6861          * manually poll and ask smf the best way to get to it.
6862          */
6863         while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6864             != SCF_SUCCESS) {
6865                 ret = scf_error();
6866                 if (ret != SCF_ERROR_NOT_FOUND) {
6867                         warn(gettext("Failed to get restarter property "
6868                             "group for instance: %s\n"), inst->sc_name);
6869                         switch (ret) {
6870                         case SCF_ERROR_DELETED:
6871                                 err = ENODEV;
6872                                 break;
6873                         case SCF_ERROR_CONNECTION_BROKEN:
6874                                 warn(gettext("Lost repository connection\n"));
6875                                 err = ECONNABORTED;
6876                                 break;
6877                         default:
6878                                 bad_error("scf_service_get_instance", ret);
6879                         }
6880 
6881                         return (err);
6882                 }
6883 
6884                 ts.tv_sec = pg_timeout / NANOSEC;
6885                 ts.tv_nsec = pg_timeout % NANOSEC;
6886 
6887                 (void) nanosleep(&ts, NULL);
6888         }
6889 
6890         /*
6891          * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6892          * So in addition to the property group being present, we need to wait
6893          * for the property to be there in some form.
6894          *
6895          * Note that a property group is a frozen snapshot in time. To properly
6896          * get beyond this, you have to refresh the property group each time.
6897          */
6898         while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6899             imp_prop)) != 0) {
6900 
6901                 ret = scf_error();
6902                 if (ret != SCF_ERROR_NOT_FOUND) {
6903                         warn(gettext("Failed to get property %s from the "
6904                             "restarter property group of instance %s\n"),
6905                             SCF_PROPERTY_STATE, inst->sc_name);
6906                         switch (ret) {
6907                         case SCF_ERROR_CONNECTION_BROKEN:
6908                                 warn(gettext("Lost repository connection\n"));
6909                                 err = ECONNABORTED;
6910                                 break;
6911                         case SCF_ERROR_DELETED:
6912                                 err = ENODEV;
6913                                 break;
6914                         default:
6915                                 bad_error("scf_pg_get_property", ret);
6916                         }
6917 
6918                         return (err);
6919                 }
6920 
6921                 ts.tv_sec = pg_timeout / NANOSEC;
6922                 ts.tv_nsec = pg_timeout % NANOSEC;
6923 
6924                 (void) nanosleep(&ts, NULL);
6925 
6926                 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6927                 if (ret != SCF_SUCCESS) {
6928                         warn(gettext("Failed to get restarter property "
6929                             "group for instance: %s\n"), inst->sc_name);
6930                         switch (ret) {
6931                         case SCF_ERROR_DELETED:
6932                                 err = ENODEV;
6933                                 break;
6934                         case SCF_ERROR_CONNECTION_BROKEN:
6935                                 warn(gettext("Lost repository connection\n"));
6936                                 err = ECONNABORTED;
6937                                 break;
6938                         default:
6939                                 bad_error("scf_service_get_instance", ret);
6940                         }
6941 
6942                         return (err);
6943                 }
6944         }
6945 
6946         /*
6947          * We don't have to free the property groups or other values that we got
6948          * because we stored them in global variables that are allocated and
6949          * freed by the routines that call into these functions. Unless of
6950          * course the rest of the code here that we are basing this on is
6951          * mistaken.
6952          */
6953         return (0);
6954 }
6955 #endif
6956 
6957 /*
6958  * If the service is missing, create it, import its properties, and import the
6959  * instances.  Since the service is brand new, it should be empty, and if we
6960  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6961  *
6962  * If the service exists, we want to upgrade its properties and import the
6963  * instances.  Upgrade requires a last-import snapshot, though, which are
6964  * children of instances, so first we'll have to go through the instances
6965  * looking for a last-import snapshot.  If we don't find one then we'll just
6966  * override-import the service properties (but don't delete existing
6967  * properties: another service might have declared us as a dependent).  Before
6968  * we change anything, though, we want to take the previous snapshots.  We
6969  * also give lscf_instance_import() a leg up on taking last-import snapshots
6970  * by importing the manifest's service properties into a temporary service.
6971  *
6972  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6973  * sets lcbdata->sc_err to
6974  *   ECONNABORTED - repository connection broken
6975  *   ENOMEM - out of memory
6976  *   ENOSPC - svc.configd is out of resources
6977  *   EPERM - couldn't create temporary service (error printed)
6978  *         - couldn't import into temp service (error printed)
6979  *         - couldn't create service (error printed)
6980  *         - couldn't import dependent (error printed)
6981  *         - couldn't take snapshot (error printed)
6982  *         - couldn't create instance (error printed)
6983  *         - couldn't create, modify, or delete pg (error printed)
6984  *         - couldn't create, modify, or delete dependent (error printed)
6985  *         - couldn't import instance (error printed)
6986  *   EROFS - couldn't create temporary service (repository read-only)
6987  *         - couldn't import into temporary service (repository read-only)
6988  *         - couldn't create service (repository read-only)
6989  *         - couldn't import dependent (repository read-only)
6990  *         - couldn't create instance (repository read-only)
6991  *         - couldn't create, modify, or delete pg or dependent
6992  *         - couldn't import instance (repository read-only)
6993  *   EACCES - couldn't create temporary service (backend access denied)
6994  *          - couldn't import into temporary service (backend access denied)
6995  *          - couldn't create service (backend access denied)
6996  *          - couldn't import dependent (backend access denied)
6997  *          - couldn't create instance (backend access denied)
6998  *          - couldn't create, modify, or delete pg or dependent
6999  *          - couldn't import instance (backend access denied)
7000  *   EINVAL - service name is invalid (error printed)
7001  *          - service name is too long (error printed)
7002  *          - s has invalid pgroup (error printed)
7003  *          - s has invalid dependent (error printed)
7004  *          - instance name is invalid (error printed)
7005  *          - instance entity_t is invalid (error printed)
7006  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7007  *          - couldn't import dependent (dependency pg already exists) (printed)
7008  *          - dependency collision in dependent service (error printed)
7009  *   EBUSY - temporary service deleted (error printed)
7010  *         - property group added to temporary service (error printed)
7011  *         - new property group changed or was deleted (error printed)
7012  *         - service was added unexpectedly (error printed)
7013  *         - service was deleted unexpectedly (error printed)
7014  *         - property group added to new service (error printed)
7015  *         - instance added unexpectedly (error printed)
7016  *         - instance deleted unexpectedly (error printed)
7017  *         - dependent service deleted unexpectedly (error printed)
7018  *         - pg was added, changed, or deleted (error printed)
7019  *         - dependent pg changed (error printed)
7020  *         - temporary instance added, changed, or deleted (error printed)
7021  *   EBADF - a last-import snapshot is corrupt (error printed)
7022  *         - the service is corrupt (error printed)
7023  *         - a dependent is corrupt (error printed)
7024  *         - an instance is corrupt (error printed)
7025  *         - an instance has a corrupt last-import snapshot (error printed)
7026  *         - dependent target has a corrupt snapshot (error printed)
7027  *   -1 - unknown libscf error (error printed)
7028  */
7029 static int
7030 lscf_service_import(void *v, void *pvt)
7031 {
7032         entity_t *s = v;
7033         scf_callback_t cbdata;
7034         scf_callback_t *lcbdata = pvt;
7035         scf_scope_t *scope = lcbdata->sc_parent;
7036         entity_t *inst, linst;
7037         int r;
7038         int fresh = 0;
7039         scf_snaplevel_t *running;
7040         int have_ge = 0;
7041         boolean_t retried = B_FALSE;
7042 
7043         const char * const ts_deleted = gettext("Temporary service svc:/%s "
7044             "was deleted unexpectedly.\n");
7045         const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7046             "changed unexpectedly (property group added).\n");
7047         const char * const s_deleted =
7048             gettext("%s was deleted unexpectedly.\n");
7049         const char * const i_deleted =
7050             gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7051         const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7052             "is corrupt (missing service snaplevel).\n");
7053         const char * const s_mfile_upd =
7054             gettext("Unable to update the manifest file connection "
7055             "for %s\n");
7056 
7057         li_only = 0;
7058         /* Validate the service name */
7059         if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7060                 switch (scf_error()) {
7061                 case SCF_ERROR_CONNECTION_BROKEN:
7062                         return (stash_scferror(lcbdata));
7063 
7064                 case SCF_ERROR_INVALID_ARGUMENT:
7065                         warn(gettext("\"%s\" is an invalid service name.  "
7066                             "Cannot import.\n"), s->sc_name);
7067                         return (stash_scferror(lcbdata));
7068 
7069                 case SCF_ERROR_NOT_FOUND:
7070                         break;
7071 
7072                 case SCF_ERROR_HANDLE_MISMATCH:
7073                 case SCF_ERROR_NOT_BOUND:
7074                 case SCF_ERROR_NOT_SET:
7075                 default:
7076                         bad_error("scf_scope_get_service", scf_error());
7077                 }
7078         }
7079 
7080         /* create temporary service */
7081         /*
7082          * the size of the buffer was reduced to max_scf_name_len to prevent
7083          * hitting bug 6681151.  After the bug fix, the size of the buffer
7084          * should be restored to its original value (max_scf_name_len +1)
7085          */
7086         r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7087         if (r < 0)
7088                 bad_error("snprintf", errno);
7089         if (r > max_scf_name_len) {
7090                 warn(gettext(
7091                     "Service name \"%s\" is too long.  Cannot import.\n"),
7092                     s->sc_name);
7093                 lcbdata->sc_err = EINVAL;
7094                 return (UU_WALK_ERROR);
7095         }
7096 
7097 retry:
7098         if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7099                 switch (scf_error()) {
7100                 case SCF_ERROR_CONNECTION_BROKEN:
7101                 case SCF_ERROR_NO_RESOURCES:
7102                 case SCF_ERROR_BACKEND_READONLY:
7103                 case SCF_ERROR_BACKEND_ACCESS:
7104                         return (stash_scferror(lcbdata));
7105 
7106                 case SCF_ERROR_EXISTS:
7107                         if (!retried) {
7108                                 lscf_delete(imp_tsname, 0);
7109                                 retried = B_TRUE;
7110                                 goto retry;
7111                         }
7112                         warn(gettext(
7113                             "Temporary service \"%s\" must be deleted before "
7114                             "this manifest can be imported.\n"), imp_tsname);
7115                         return (stash_scferror(lcbdata));
7116 
7117                 case SCF_ERROR_PERMISSION_DENIED:
7118                         warn(gettext("Could not create temporary service "
7119                             "\"%s\" (permission denied).\n"), imp_tsname);
7120                         return (stash_scferror(lcbdata));
7121 
7122                 case SCF_ERROR_INVALID_ARGUMENT:
7123                 case SCF_ERROR_HANDLE_MISMATCH:
7124                 case SCF_ERROR_NOT_BOUND:
7125                 case SCF_ERROR_NOT_SET:
7126                 default:
7127                         bad_error("scf_scope_add_service", scf_error());
7128                 }
7129         }
7130 
7131         r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7132         if (r < 0)
7133                 bad_error("snprintf", errno);
7134 
7135         cbdata.sc_handle = lcbdata->sc_handle;
7136         cbdata.sc_parent = imp_tsvc;
7137         cbdata.sc_service = 1;
7138         cbdata.sc_source_fmri = s->sc_fmri;
7139         cbdata.sc_target_fmri = imp_str;
7140         cbdata.sc_flags = 0;
7141 
7142         if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7143             UU_DEFAULT) != 0) {
7144                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7145                         bad_error("uu_list_walk", uu_error());
7146 
7147                 lcbdata->sc_err = cbdata.sc_err;
7148                 switch (cbdata.sc_err) {
7149                 case ECONNABORTED:
7150                         goto connaborted;
7151 
7152                 case ECANCELED:
7153                         warn(ts_deleted, imp_tsname);
7154                         lcbdata->sc_err = EBUSY;
7155                         return (UU_WALK_ERROR);
7156 
7157                 case EEXIST:
7158                         warn(ts_pg_added, imp_tsname);
7159                         lcbdata->sc_err = EBUSY;
7160                         return (UU_WALK_ERROR);
7161                 }
7162 
7163                 r = UU_WALK_ERROR;
7164                 goto deltemp;
7165         }
7166 
7167         if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7168             UU_DEFAULT) != 0) {
7169                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7170                         bad_error("uu_list_walk", uu_error());
7171 
7172                 lcbdata->sc_err = cbdata.sc_err;
7173                 switch (cbdata.sc_err) {
7174                 case ECONNABORTED:
7175                         goto connaborted;
7176 
7177                 case ECANCELED:
7178                         warn(ts_deleted, imp_tsname);
7179                         lcbdata->sc_err = EBUSY;
7180                         return (UU_WALK_ERROR);
7181 
7182                 case EEXIST:
7183                         warn(ts_pg_added, imp_tsname);
7184                         lcbdata->sc_err = EBUSY;
7185                         return (UU_WALK_ERROR);
7186                 }
7187 
7188                 r = UU_WALK_ERROR;
7189                 goto deltemp;
7190         }
7191 
7192         if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7193                 switch (scf_error()) {
7194                 case SCF_ERROR_NOT_FOUND:
7195                         break;
7196 
7197                 case SCF_ERROR_CONNECTION_BROKEN:
7198                         goto connaborted;
7199 
7200                 case SCF_ERROR_INVALID_ARGUMENT:
7201                 case SCF_ERROR_HANDLE_MISMATCH:
7202                 case SCF_ERROR_NOT_BOUND:
7203                 case SCF_ERROR_NOT_SET:
7204                 default:
7205                         bad_error("scf_scope_get_service", scf_error());
7206                 }
7207 
7208                 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7209                         switch (scf_error()) {
7210                         case SCF_ERROR_CONNECTION_BROKEN:
7211                                 goto connaborted;
7212 
7213                         case SCF_ERROR_NO_RESOURCES:
7214                         case SCF_ERROR_BACKEND_READONLY:
7215                         case SCF_ERROR_BACKEND_ACCESS:
7216                                 r = stash_scferror(lcbdata);
7217                                 goto deltemp;
7218 
7219                         case SCF_ERROR_EXISTS:
7220                                 warn(gettext("Scope \"%s\" changed unexpectedly"
7221                                     " (service \"%s\" added).\n"),
7222                                     SCF_SCOPE_LOCAL, s->sc_name);
7223                                 lcbdata->sc_err = EBUSY;
7224                                 goto deltemp;
7225 
7226                         case SCF_ERROR_PERMISSION_DENIED:
7227                                 warn(gettext("Could not create service \"%s\" "
7228                                     "(permission denied).\n"), s->sc_name);
7229                                 goto deltemp;
7230 
7231                         case SCF_ERROR_INVALID_ARGUMENT:
7232                         case SCF_ERROR_HANDLE_MISMATCH:
7233                         case SCF_ERROR_NOT_BOUND:
7234                         case SCF_ERROR_NOT_SET:
7235                         default:
7236                                 bad_error("scf_scope_add_service", scf_error());
7237                         }
7238                 }
7239 
7240                 s->sc_import_state = IMPORT_PROP_BEGUN;
7241 
7242                 /* import service properties */
7243                 cbdata.sc_handle = lcbdata->sc_handle;
7244                 cbdata.sc_parent = imp_svc;
7245                 cbdata.sc_service = 1;
7246                 cbdata.sc_flags = lcbdata->sc_flags;
7247                 cbdata.sc_source_fmri = s->sc_fmri;
7248                 cbdata.sc_target_fmri = s->sc_fmri;
7249 
7250                 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7251                     &cbdata, UU_DEFAULT) != 0) {
7252                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7253                                 bad_error("uu_list_walk", uu_error());
7254 
7255                         lcbdata->sc_err = cbdata.sc_err;
7256                         switch (cbdata.sc_err) {
7257                         case ECONNABORTED:
7258                                 goto connaborted;
7259 
7260                         case ECANCELED:
7261                                 warn(s_deleted, s->sc_fmri);
7262                                 lcbdata->sc_err = EBUSY;
7263                                 return (UU_WALK_ERROR);
7264 
7265                         case EEXIST:
7266                                 warn(gettext("%s changed unexpectedly "
7267                                     "(property group added).\n"), s->sc_fmri);
7268                                 lcbdata->sc_err = EBUSY;
7269                                 return (UU_WALK_ERROR);
7270 
7271                         case EINVAL:
7272                                 /* caught above */
7273                                 bad_error("entity_pgroup_import",
7274                                     cbdata.sc_err);
7275                         }
7276 
7277                         r = UU_WALK_ERROR;
7278                         goto deltemp;
7279                 }
7280 
7281                 cbdata.sc_trans = NULL;
7282                 cbdata.sc_flags = 0;
7283                 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7284                     &cbdata, UU_DEFAULT) != 0) {
7285                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7286                                 bad_error("uu_list_walk", uu_error());
7287 
7288                         lcbdata->sc_err = cbdata.sc_err;
7289                         if (cbdata.sc_err == ECONNABORTED)
7290                                 goto connaborted;
7291                         r = UU_WALK_ERROR;
7292                         goto deltemp;
7293                 }
7294 
7295                 s->sc_import_state = IMPORT_PROP_DONE;
7296 
7297                 /*
7298                  * This is a new service, so we can't take previous snapshots
7299                  * or upgrade service properties.
7300                  */
7301                 fresh = 1;
7302                 goto instances;
7303         }
7304 
7305         /* Clear sc_seen for the instances. */
7306         if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7307             (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7308                 bad_error("uu_list_walk", uu_error());
7309 
7310         /*
7311          * Take previous snapshots for all instances.  Even for ones not
7312          * mentioned in the bundle, since we might change their service
7313          * properties.
7314          */
7315         if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7316                 switch (scf_error()) {
7317                 case SCF_ERROR_CONNECTION_BROKEN:
7318                         goto connaborted;
7319 
7320                 case SCF_ERROR_DELETED:
7321                         warn(s_deleted, s->sc_fmri);
7322                         lcbdata->sc_err = EBUSY;
7323                         r = UU_WALK_ERROR;
7324                         goto deltemp;
7325 
7326                 case SCF_ERROR_HANDLE_MISMATCH:
7327                 case SCF_ERROR_NOT_BOUND:
7328                 case SCF_ERROR_NOT_SET:
7329                 default:
7330                         bad_error("scf_iter_service_instances", scf_error());
7331                 }
7332         }
7333 
7334         for (;;) {
7335                 r = scf_iter_next_instance(imp_iter, imp_inst);
7336                 if (r == 0)
7337                         break;
7338                 if (r != 1) {
7339                         switch (scf_error()) {
7340                         case SCF_ERROR_DELETED:
7341                                 warn(s_deleted, s->sc_fmri);
7342                                 lcbdata->sc_err = EBUSY;
7343                                 r = UU_WALK_ERROR;
7344                                 goto deltemp;
7345 
7346                         case SCF_ERROR_CONNECTION_BROKEN:
7347                                 goto connaborted;
7348 
7349                         case SCF_ERROR_NOT_BOUND:
7350                         case SCF_ERROR_HANDLE_MISMATCH:
7351                         case SCF_ERROR_INVALID_ARGUMENT:
7352                         case SCF_ERROR_NOT_SET:
7353                         default:
7354                                 bad_error("scf_iter_next_instance",
7355                                     scf_error());
7356                         }
7357                 }
7358 
7359                 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7360                         switch (scf_error()) {
7361                         case SCF_ERROR_DELETED:
7362                                 continue;
7363 
7364                         case SCF_ERROR_CONNECTION_BROKEN:
7365                                 goto connaborted;
7366 
7367                         case SCF_ERROR_NOT_SET:
7368                         case SCF_ERROR_NOT_BOUND:
7369                         default:
7370                                 bad_error("scf_instance_get_name", scf_error());
7371                         }
7372                 }
7373 
7374                 if (g_verbose)
7375                         warn(gettext(
7376                             "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7377                             snap_previous, s->sc_name, imp_str);
7378 
7379                 r = take_snap(imp_inst, snap_previous, imp_snap);
7380                 switch (r) {
7381                 case 0:
7382                         break;
7383 
7384                 case ECANCELED:
7385                         continue;
7386 
7387                 case ECONNABORTED:
7388                         goto connaborted;
7389 
7390                 case EPERM:
7391                         warn(gettext("Could not take \"%s\" snapshot of "
7392                             "svc:/%s:%s (permission denied).\n"),
7393                             snap_previous, s->sc_name, imp_str);
7394                         lcbdata->sc_err = r;
7395                         return (UU_WALK_ERROR);
7396 
7397                 case ENOSPC:
7398                 case -1:
7399                         lcbdata->sc_err = r;
7400                         r = UU_WALK_ERROR;
7401                         goto deltemp;
7402 
7403                 default:
7404                         bad_error("take_snap", r);
7405                 }
7406 
7407                 linst.sc_name = imp_str;
7408                 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7409                     &linst, NULL, NULL);
7410                 if (inst != NULL) {
7411                         inst->sc_import_state = IMPORT_PREVIOUS;
7412                         inst->sc_seen = 1;
7413                 }
7414         }
7415 
7416         /*
7417          * Create the new instances and take previous snapshots of
7418          * them.  This is not necessary, but it maximizes data preservation.
7419          */
7420         for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7421             inst != NULL;
7422             inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7423             inst)) {
7424                 if (inst->sc_seen)
7425                         continue;
7426 
7427                 if (scf_service_add_instance(imp_svc, inst->sc_name,
7428                     imp_inst) != 0) {
7429                         switch (scf_error()) {
7430                         case SCF_ERROR_CONNECTION_BROKEN:
7431                                 goto connaborted;
7432 
7433                         case SCF_ERROR_BACKEND_READONLY:
7434                         case SCF_ERROR_BACKEND_ACCESS:
7435                         case SCF_ERROR_NO_RESOURCES:
7436                                 r = stash_scferror(lcbdata);
7437                                 goto deltemp;
7438 
7439                         case SCF_ERROR_EXISTS:
7440                                 warn(gettext("%s changed unexpectedly "
7441                                     "(instance \"%s\" added).\n"), s->sc_fmri,
7442                                     inst->sc_name);
7443                                 lcbdata->sc_err = EBUSY;
7444                                 r = UU_WALK_ERROR;
7445                                 goto deltemp;
7446 
7447                         case SCF_ERROR_INVALID_ARGUMENT:
7448                                 warn(gettext("Service \"%s\" has instance with "
7449                                     "invalid name \"%s\".\n"), s->sc_name,
7450                                     inst->sc_name);
7451                                 r = stash_scferror(lcbdata);
7452                                 goto deltemp;
7453 
7454                         case SCF_ERROR_PERMISSION_DENIED:
7455                                 warn(gettext("Could not create instance \"%s\" "
7456                                     "in %s (permission denied).\n"),
7457                                     inst->sc_name, s->sc_fmri);
7458                                 r = stash_scferror(lcbdata);
7459                                 goto deltemp;
7460 
7461                         case SCF_ERROR_HANDLE_MISMATCH:
7462                         case SCF_ERROR_NOT_BOUND:
7463                         case SCF_ERROR_NOT_SET:
7464                         default:
7465                                 bad_error("scf_service_add_instance",
7466                                     scf_error());
7467                         }
7468                 }
7469 
7470                 if (g_verbose)
7471                         warn(gettext("Taking \"%s\" snapshot for "
7472                             "new service %s.\n"), snap_previous, inst->sc_fmri);
7473                 r = take_snap(imp_inst, snap_previous, imp_snap);
7474                 switch (r) {
7475                 case 0:
7476                         break;
7477 
7478                 case ECANCELED:
7479                         warn(i_deleted, s->sc_fmri, inst->sc_name);
7480                         lcbdata->sc_err = EBUSY;
7481                         r = UU_WALK_ERROR;
7482                         goto deltemp;
7483 
7484                 case ECONNABORTED:
7485                         goto connaborted;
7486 
7487                 case EPERM:
7488                         warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7489                         lcbdata->sc_err = r;
7490                         r = UU_WALK_ERROR;
7491                         goto deltemp;
7492 
7493                 case ENOSPC:
7494                 case -1:
7495                         r = UU_WALK_ERROR;
7496                         goto deltemp;
7497 
7498                 default:
7499                         bad_error("take_snap", r);
7500                 }
7501         }
7502 
7503         s->sc_import_state = IMPORT_PREVIOUS;
7504 
7505         /*
7506          * Upgrade service properties, if we can find a last-import snapshot.
7507          * Any will do because we don't support different service properties
7508          * in different manifests, so all snaplevels of the service in all of
7509          * the last-import snapshots of the instances should be the same.
7510          */
7511         if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7512                 switch (scf_error()) {
7513                 case SCF_ERROR_CONNECTION_BROKEN:
7514                         goto connaborted;
7515 
7516                 case SCF_ERROR_DELETED:
7517                         warn(s_deleted, s->sc_fmri);
7518                         lcbdata->sc_err = EBUSY;
7519                         r = UU_WALK_ERROR;
7520                         goto deltemp;
7521 
7522                 case SCF_ERROR_HANDLE_MISMATCH:
7523                 case SCF_ERROR_NOT_BOUND:
7524                 case SCF_ERROR_NOT_SET:
7525                 default:
7526                         bad_error("scf_iter_service_instances", scf_error());
7527                 }
7528         }
7529 
7530         for (;;) {
7531                 r = scf_iter_next_instance(imp_iter, imp_inst);
7532                 if (r == -1) {
7533                         switch (scf_error()) {
7534                         case SCF_ERROR_DELETED:
7535                                 warn(s_deleted, s->sc_fmri);
7536                                 lcbdata->sc_err = EBUSY;
7537                                 r = UU_WALK_ERROR;
7538                                 goto deltemp;
7539 
7540                         case SCF_ERROR_CONNECTION_BROKEN:
7541                                 goto connaborted;
7542 
7543                         case SCF_ERROR_NOT_BOUND:
7544                         case SCF_ERROR_HANDLE_MISMATCH:
7545                         case SCF_ERROR_INVALID_ARGUMENT:
7546                         case SCF_ERROR_NOT_SET:
7547                         default:
7548                                 bad_error("scf_iter_next_instance",
7549                                     scf_error());
7550                         }
7551                 }
7552 
7553                 if (r == 0) {
7554                         /*
7555                          * Didn't find any last-import snapshots.  Override-
7556                          * import the properties.  Unless one of the instances
7557                          * has a general/enabled property, in which case we're
7558                          * probably running a last-import-capable svccfg for
7559                          * the first time, and we should only take the
7560                          * last-import snapshot.
7561                          */
7562                         if (have_ge) {
7563                                 pgroup_t *mfpg;
7564                                 scf_callback_t mfcbdata;
7565 
7566                                 li_only = 1;
7567                                 no_refresh = 1;
7568                                 /*
7569                                  * Need to go ahead and import the manifestfiles
7570                                  * pg if it exists. If the last-import snapshot
7571                                  * upgrade code is ever removed this code can
7572                                  * be removed as well.
7573                                  */
7574                                 mfpg = internal_pgroup_find(s,
7575                                     SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7576 
7577                                 if (mfpg) {
7578                                         mfcbdata.sc_handle = g_hndl;
7579                                         mfcbdata.sc_parent = imp_svc;
7580                                         mfcbdata.sc_service = 1;
7581                                         mfcbdata.sc_flags = SCI_FORCE;
7582                                         mfcbdata.sc_source_fmri = s->sc_fmri;
7583                                         mfcbdata.sc_target_fmri = s->sc_fmri;
7584                                         if (entity_pgroup_import(mfpg,
7585                                             &mfcbdata) != UU_WALK_NEXT) {
7586                                                 warn(s_mfile_upd, s->sc_fmri);
7587                                                 r = UU_WALK_ERROR;
7588                                                 goto deltemp;
7589                                         }
7590                                 }
7591                                 break;
7592                         }
7593 
7594                         s->sc_import_state = IMPORT_PROP_BEGUN;
7595 
7596                         cbdata.sc_handle = g_hndl;
7597                         cbdata.sc_parent = imp_svc;
7598                         cbdata.sc_service = 1;
7599                         cbdata.sc_flags = SCI_FORCE;
7600                         cbdata.sc_source_fmri = s->sc_fmri;
7601                         cbdata.sc_target_fmri = s->sc_fmri;
7602                         if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7603                             &cbdata, UU_DEFAULT) != 0) {
7604                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7605                                         bad_error("uu_list_walk", uu_error());
7606                                 lcbdata->sc_err = cbdata.sc_err;
7607                                 switch (cbdata.sc_err) {
7608                                 case ECONNABORTED:
7609                                         goto connaborted;
7610 
7611                                 case ECANCELED:
7612                                         warn(s_deleted, s->sc_fmri);
7613                                         lcbdata->sc_err = EBUSY;
7614                                         break;
7615 
7616                                 case EINVAL:    /* caught above */
7617                                 case EEXIST:
7618                                         bad_error("entity_pgroup_import",
7619                                             cbdata.sc_err);
7620                                 }
7621 
7622                                 r = UU_WALK_ERROR;
7623                                 goto deltemp;
7624                         }
7625 
7626                         cbdata.sc_trans = NULL;
7627                         cbdata.sc_flags = 0;
7628                         if (uu_list_walk(s->sc_dependents,
7629                             lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7630                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7631                                         bad_error("uu_list_walk", uu_error());
7632                                 lcbdata->sc_err = cbdata.sc_err;
7633                                 if (cbdata.sc_err == ECONNABORTED)
7634                                         goto connaborted;
7635                                 r = UU_WALK_ERROR;
7636                                 goto deltemp;
7637                         }
7638                         break;
7639                 }
7640 
7641                 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7642                     imp_snap) != 0) {
7643                         switch (scf_error()) {
7644                         case SCF_ERROR_DELETED:
7645                                 continue;
7646 
7647                         case SCF_ERROR_NOT_FOUND:
7648                                 break;
7649 
7650                         case SCF_ERROR_CONNECTION_BROKEN:
7651                                 goto connaborted;
7652 
7653                         case SCF_ERROR_HANDLE_MISMATCH:
7654                         case SCF_ERROR_NOT_BOUND:
7655                         case SCF_ERROR_INVALID_ARGUMENT:
7656                         case SCF_ERROR_NOT_SET:
7657                         default:
7658                                 bad_error("scf_instance_get_snapshot",
7659                                     scf_error());
7660                         }
7661 
7662                         if (have_ge)
7663                                 continue;
7664 
7665                         /*
7666                          * Check for a general/enabled property.  This is how
7667                          * we tell whether to import if there turn out to be
7668                          * no last-import snapshots.
7669                          */
7670                         if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7671                             imp_pg) == 0) {
7672                                 if (scf_pg_get_property(imp_pg,
7673                                     SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7674                                         have_ge = 1;
7675                                 } else {
7676                                         switch (scf_error()) {
7677                                         case SCF_ERROR_DELETED:
7678                                         case SCF_ERROR_NOT_FOUND:
7679                                                 continue;
7680 
7681                                         case SCF_ERROR_INVALID_ARGUMENT:
7682                                         case SCF_ERROR_HANDLE_MISMATCH:
7683                                         case SCF_ERROR_CONNECTION_BROKEN:
7684                                         case SCF_ERROR_NOT_BOUND:
7685                                         case SCF_ERROR_NOT_SET:
7686                                         default:
7687                                                 bad_error("scf_pg_get_property",
7688                                                     scf_error());
7689                                         }
7690                                 }
7691                         } else {
7692                                 switch (scf_error()) {
7693                                 case SCF_ERROR_DELETED:
7694                                 case SCF_ERROR_NOT_FOUND:
7695                                         continue;
7696 
7697                                 case SCF_ERROR_CONNECTION_BROKEN:
7698                                         goto connaborted;
7699 
7700                                 case SCF_ERROR_NOT_BOUND:
7701                                 case SCF_ERROR_NOT_SET:
7702                                 case SCF_ERROR_INVALID_ARGUMENT:
7703                                 case SCF_ERROR_HANDLE_MISMATCH:
7704                                 default:
7705                                         bad_error("scf_instance_get_pg",
7706                                             scf_error());
7707                                 }
7708                         }
7709                         continue;
7710                 }
7711 
7712                 /* find service snaplevel */
7713                 r = get_snaplevel(imp_snap, 1, imp_snpl);
7714                 switch (r) {
7715                 case 0:
7716                         break;
7717 
7718                 case ECONNABORTED:
7719                         goto connaborted;
7720 
7721                 case ECANCELED:
7722                         continue;
7723 
7724                 case ENOENT:
7725                         if (scf_instance_get_name(imp_inst, imp_str,
7726                             imp_str_sz) < 0)
7727                                 (void) strcpy(imp_str, "?");
7728                         warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7729                         lcbdata->sc_err = EBADF;
7730                         r = UU_WALK_ERROR;
7731                         goto deltemp;
7732 
7733                 default:
7734                         bad_error("get_snaplevel", r);
7735                 }
7736 
7737                 if (scf_instance_get_snapshot(imp_inst, snap_running,
7738                     imp_rsnap) != 0) {
7739                         switch (scf_error()) {
7740                         case SCF_ERROR_DELETED:
7741                                 continue;
7742 
7743                         case SCF_ERROR_NOT_FOUND:
7744                                 break;
7745 
7746                         case SCF_ERROR_CONNECTION_BROKEN:
7747                                 goto connaborted;
7748 
7749                         case SCF_ERROR_INVALID_ARGUMENT:
7750                         case SCF_ERROR_HANDLE_MISMATCH:
7751                         case SCF_ERROR_NOT_BOUND:
7752                         case SCF_ERROR_NOT_SET:
7753                         default:
7754                                 bad_error("scf_instance_get_snapshot",
7755                                     scf_error());
7756                         }
7757                         running = NULL;
7758                 } else {
7759                         r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7760                         switch (r) {
7761                         case 0:
7762                                 running = imp_rsnpl;
7763                                 break;
7764 
7765                         case ECONNABORTED:
7766                                 goto connaborted;
7767 
7768                         case ECANCELED:
7769                                 continue;
7770 
7771                         case ENOENT:
7772                                 if (scf_instance_get_name(imp_inst, imp_str,
7773                                     imp_str_sz) < 0)
7774                                         (void) strcpy(imp_str, "?");
7775                                 warn(badsnap, snap_running, s->sc_name,
7776                                     imp_str);
7777                                 lcbdata->sc_err = EBADF;
7778                                 r = UU_WALK_ERROR;
7779                                 goto deltemp;
7780 
7781                         default:
7782                                 bad_error("get_snaplevel", r);
7783                         }
7784                 }
7785 
7786                 if (g_verbose) {
7787                         if (scf_instance_get_name(imp_inst, imp_str,
7788                             imp_str_sz) < 0)
7789                                 (void) strcpy(imp_str, "?");
7790                         warn(gettext("Upgrading properties of %s according to "
7791                             "instance \"%s\".\n"), s->sc_fmri, imp_str);
7792                 }
7793 
7794                 /* upgrade service properties */
7795                 r = upgrade_props(imp_svc, running, imp_snpl, s);
7796                 if (r == 0)
7797                         break;
7798 
7799                 switch (r) {
7800                 case ECONNABORTED:
7801                         goto connaborted;
7802 
7803                 case ECANCELED:
7804                         warn(s_deleted, s->sc_fmri);
7805                         lcbdata->sc_err = EBUSY;
7806                         break;
7807 
7808                 case ENODEV:
7809                         if (scf_instance_get_name(imp_inst, imp_str,
7810                             imp_str_sz) < 0)
7811                                 (void) strcpy(imp_str, "?");
7812                         warn(i_deleted, s->sc_fmri, imp_str);
7813                         lcbdata->sc_err = EBUSY;
7814                         break;
7815 
7816                 default:
7817                         lcbdata->sc_err = r;
7818                 }
7819 
7820                 r = UU_WALK_ERROR;
7821                 goto deltemp;
7822         }
7823 
7824         s->sc_import_state = IMPORT_PROP_DONE;
7825 
7826 instances:
7827         /* import instances */
7828         cbdata.sc_handle = lcbdata->sc_handle;
7829         cbdata.sc_parent = imp_svc;
7830         cbdata.sc_service = 1;
7831         cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7832         cbdata.sc_general = NULL;
7833 
7834         if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7835             lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7836                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7837                         bad_error("uu_list_walk", uu_error());
7838 
7839                 lcbdata->sc_err = cbdata.sc_err;
7840                 if (cbdata.sc_err == ECONNABORTED)
7841                         goto connaborted;
7842                 r = UU_WALK_ERROR;
7843                 goto deltemp;
7844         }
7845 
7846         s->sc_import_state = IMPORT_COMPLETE;
7847         r = UU_WALK_NEXT;
7848 
7849 deltemp:
7850         /* delete temporary service */
7851         if (scf_service_delete(imp_tsvc) != 0) {
7852                 switch (scf_error()) {
7853                 case SCF_ERROR_DELETED:
7854                         break;
7855 
7856                 case SCF_ERROR_CONNECTION_BROKEN:
7857                         goto connaborted;
7858 
7859                 case SCF_ERROR_EXISTS:
7860                         warn(gettext(
7861                             "Could not delete svc:/%s (instances exist).\n"),
7862                             imp_tsname);
7863                         break;
7864 
7865                 case SCF_ERROR_NOT_SET:
7866                 case SCF_ERROR_NOT_BOUND:
7867                 default:
7868                         bad_error("scf_service_delete", scf_error());
7869                 }
7870         }
7871 
7872         return (r);
7873 
7874 connaborted:
7875         warn(gettext("Could not delete svc:/%s "
7876             "(repository connection broken).\n"), imp_tsname);
7877         lcbdata->sc_err = ECONNABORTED;
7878         return (UU_WALK_ERROR);
7879 }
7880 
7881 static const char *
7882 import_progress(int st)
7883 {
7884         switch (st) {
7885         case 0:
7886                 return (gettext("not reached."));
7887 
7888         case IMPORT_PREVIOUS:
7889                 return (gettext("previous snapshot taken."));
7890 
7891         case IMPORT_PROP_BEGUN:
7892                 return (gettext("some properties imported."));
7893 
7894         case IMPORT_PROP_DONE:
7895                 return (gettext("properties imported."));
7896 
7897         case IMPORT_COMPLETE:
7898                 return (gettext("imported."));
7899 
7900         case IMPORT_REFRESHED:
7901                 return (gettext("refresh requested."));
7902 
7903         default:
7904 #ifndef NDEBUG
7905                 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7906                     __FILE__, __LINE__, st);
7907 #endif
7908                 abort();
7909                 /* NOTREACHED */
7910         }
7911 }
7912 
7913 /*
7914  * Returns
7915  *   0 - success
7916  *     - fmri wasn't found (error printed)
7917  *     - entity was deleted (error printed)
7918  *     - backend denied access (error printed)
7919  *   ENOMEM - out of memory (error printed)
7920  *   ECONNABORTED - repository connection broken (error printed)
7921  *   EPERM - permission denied (error printed)
7922  *   -1 - unknown libscf error (error printed)
7923  */
7924 static int
7925 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7926 {
7927         scf_error_t serr;
7928         void *ent;
7929         int issvc;
7930         int r;
7931 
7932         const char *deleted = gettext("Could not refresh %s (deleted).\n");
7933         const char *dpt_deleted = gettext("Could not refresh %s "
7934             "(dependent \"%s\" of %s) (deleted).\n");
7935 
7936         serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7937         switch (serr) {
7938         case SCF_ERROR_NONE:
7939                 break;
7940 
7941         case SCF_ERROR_NO_MEMORY:
7942                 if (name == NULL)
7943                         warn(gettext("Could not refresh %s (out of memory).\n"),
7944                             fmri);
7945                 else
7946                         warn(gettext("Could not refresh %s "
7947                             "(dependent \"%s\" of %s) (out of memory).\n"),
7948                             fmri, name, d_fmri);
7949                 return (ENOMEM);
7950 
7951         case SCF_ERROR_NOT_FOUND:
7952                 if (name == NULL)
7953                         warn(deleted, fmri);
7954                 else
7955                         warn(dpt_deleted, fmri, name, d_fmri);
7956                 return (0);
7957 
7958         case SCF_ERROR_INVALID_ARGUMENT:
7959         case SCF_ERROR_CONSTRAINT_VIOLATED:
7960         default:
7961                 bad_error("fmri_to_entity", serr);
7962         }
7963 
7964         r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7965         switch (r) {
7966         case 0:
7967                 break;
7968 
7969         case ECONNABORTED:
7970                 if (name != NULL)
7971                         warn(gettext("Could not refresh %s "
7972                             "(dependent \"%s\" of %s) "
7973                             "(repository connection broken).\n"), fmri, name,
7974                             d_fmri);
7975                 return (r);
7976 
7977         case ECANCELED:
7978                 if (name == NULL)
7979                         warn(deleted, fmri);
7980                 else
7981                         warn(dpt_deleted, fmri, name, d_fmri);
7982                 return (0);
7983 
7984         case EACCES:
7985                 if (!g_verbose)
7986                         return (0);
7987                 if (name == NULL)
7988                         warn(gettext("Could not refresh %s "
7989                             "(backend access denied).\n"), fmri);
7990                 else
7991                         warn(gettext("Could not refresh %s "
7992                             "(dependent \"%s\" of %s) "
7993                             "(backend access denied).\n"), fmri, name, d_fmri);
7994                 return (0);
7995 
7996         case EPERM:
7997                 if (name == NULL)
7998                         warn(gettext("Could not refresh %s "
7999                             "(permission denied).\n"), fmri);
8000                 else
8001                         warn(gettext("Could not refresh %s "
8002                             "(dependent \"%s\" of %s) "
8003                             "(permission denied).\n"), fmri, name, d_fmri);
8004                 return (r);
8005 
8006         case ENOSPC:
8007                 if (name == NULL)
8008                         warn(gettext("Could not refresh %s "
8009                             "(repository server out of resources).\n"),
8010                             fmri);
8011                 else
8012                         warn(gettext("Could not refresh %s "
8013                             "(dependent \"%s\" of %s) "
8014                             "(repository server out of resources).\n"),
8015                             fmri, name, d_fmri);
8016                 return (r);
8017 
8018         case -1:
8019                 scfwarn();
8020                 return (r);
8021 
8022         default:
8023                 bad_error("refresh_entity", r);
8024         }
8025 
8026         if (issvc)
8027                 scf_service_destroy(ent);
8028         else
8029                 scf_instance_destroy(ent);
8030 
8031         return (0);
8032 }
8033 
8034 static int
8035 alloc_imp_globals()
8036 {
8037         int r;
8038 
8039         const char * const emsg_nomem = gettext("Out of memory.\n");
8040         const char * const emsg_nores =
8041             gettext("svc.configd is out of resources.\n");
8042 
8043         imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8044             max_scf_name_len : max_scf_fmri_len) + 1;
8045 
8046         if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8047             (imp_svc = scf_service_create(g_hndl)) == NULL ||
8048             (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8049             (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8050             (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8051             (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8052             (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8053             (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8054             (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8055             (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8056             (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8057             (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8058             (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8059             (imp_prop = scf_property_create(g_hndl)) == NULL ||
8060             (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8061             (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8062             (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8063             (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8064             (imp_str = malloc(imp_str_sz)) == NULL ||
8065             (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8066             (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8067             (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8068             (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8069             (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8070             (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8071             (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8072             (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8073             (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8074             (ud_prop = scf_property_create(g_hndl)) == NULL ||
8075             (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8076             (ud_val = scf_value_create(g_hndl)) == NULL ||
8077             (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8078             (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8079             (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8080             (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8081             (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8082             (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8083                 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8084                         warn(emsg_nores);
8085                 else
8086                         warn(emsg_nomem);
8087 
8088                 return (-1);
8089         }
8090 
8091         r = load_init();
8092         switch (r) {
8093         case 0:
8094                 break;
8095 
8096         case ENOMEM:
8097                 warn(emsg_nomem);
8098                 return (-1);
8099 
8100         default:
8101                 bad_error("load_init", r);
8102         }
8103 
8104         return (0);
8105 }
8106 
8107 static void
8108 free_imp_globals()
8109 {
8110         pgroup_t *old_dpt;
8111         void *cookie;
8112 
8113         load_fini();
8114 
8115         free(ud_ctarg);
8116         free(ud_oldtarg);
8117         free(ud_name);
8118         ud_ctarg = ud_oldtarg = ud_name = NULL;
8119 
8120         scf_transaction_destroy(ud_tx);
8121         ud_tx = NULL;
8122         scf_iter_destroy(ud_iter);
8123         scf_iter_destroy(ud_iter2);
8124         ud_iter = ud_iter2 = NULL;
8125         scf_value_destroy(ud_val);
8126         ud_val = NULL;
8127         scf_property_destroy(ud_prop);
8128         scf_property_destroy(ud_dpt_prop);
8129         ud_prop = ud_dpt_prop = NULL;
8130         scf_pg_destroy(ud_pg);
8131         scf_pg_destroy(ud_cur_depts_pg);
8132         scf_pg_destroy(ud_run_dpts_pg);
8133         ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8134         scf_snaplevel_destroy(ud_snpl);
8135         ud_snpl = NULL;
8136         scf_instance_destroy(ud_inst);
8137         ud_inst = NULL;
8138 
8139         free(imp_str);
8140         free(imp_tsname);
8141         free(imp_fe1);
8142         free(imp_fe2);
8143         imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8144 
8145         cookie = NULL;
8146         while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8147             NULL) {
8148                 free((char *)old_dpt->sc_pgroup_name);
8149                 free((char *)old_dpt->sc_pgroup_fmri);
8150                 internal_pgroup_free(old_dpt);
8151         }
8152         uu_list_destroy(imp_deleted_dpts);
8153 
8154         scf_transaction_destroy(imp_tx);
8155         imp_tx = NULL;
8156         scf_iter_destroy(imp_iter);
8157         scf_iter_destroy(imp_rpg_iter);
8158         scf_iter_destroy(imp_up_iter);
8159         imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8160         scf_property_destroy(imp_prop);
8161         imp_prop = NULL;
8162         scf_pg_destroy(imp_pg);
8163         scf_pg_destroy(imp_pg2);
8164         imp_pg = imp_pg2 = NULL;
8165         scf_snaplevel_destroy(imp_snpl);
8166         scf_snaplevel_destroy(imp_rsnpl);
8167         imp_snpl = imp_rsnpl = NULL;
8168         scf_snapshot_destroy(imp_snap);
8169         scf_snapshot_destroy(imp_lisnap);
8170         scf_snapshot_destroy(imp_tlisnap);
8171         scf_snapshot_destroy(imp_rsnap);
8172         imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8173         scf_instance_destroy(imp_inst);
8174         scf_instance_destroy(imp_tinst);
8175         imp_inst = imp_tinst = NULL;
8176         scf_service_destroy(imp_svc);
8177         scf_service_destroy(imp_tsvc);
8178         imp_svc = imp_tsvc = NULL;
8179         scf_scope_destroy(imp_scope);
8180         imp_scope = NULL;
8181 
8182         load_fini();
8183 }
8184 
8185 int
8186 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8187 {
8188         scf_callback_t cbdata;
8189         int result = 0;
8190         entity_t *svc, *inst;
8191         uu_list_t *insts;
8192         int r;
8193         pgroup_t *old_dpt;
8194         int annotation_set = 0;
8195 
8196         const char * const emsg_nomem = gettext("Out of memory.\n");
8197         const char * const emsg_nores =
8198             gettext("svc.configd is out of resources.\n");
8199 
8200         lscf_prep_hndl();
8201 
8202         if (alloc_imp_globals())
8203                 goto out;
8204 
8205         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8206                 switch (scf_error()) {
8207                 case SCF_ERROR_CONNECTION_BROKEN:
8208                         warn(gettext("Repository connection broken.\n"));
8209                         repository_teardown();
8210                         result = -1;
8211                         goto out;
8212 
8213                 case SCF_ERROR_NOT_FOUND:
8214                 case SCF_ERROR_INVALID_ARGUMENT:
8215                 case SCF_ERROR_NOT_BOUND:
8216                 case SCF_ERROR_HANDLE_MISMATCH:
8217                 default:
8218                         bad_error("scf_handle_get_scope", scf_error());
8219                 }
8220         }
8221 
8222         /* Set up the auditing annotation. */
8223         if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8224                 annotation_set = 1;
8225         } else {
8226                 switch (scf_error()) {
8227                 case SCF_ERROR_CONNECTION_BROKEN:
8228                         warn(gettext("Repository connection broken.\n"));
8229                         repository_teardown();
8230                         result = -1;
8231                         goto out;
8232 
8233                 case SCF_ERROR_INVALID_ARGUMENT:
8234                 case SCF_ERROR_NOT_BOUND:
8235                 case SCF_ERROR_NO_RESOURCES:
8236                 case SCF_ERROR_INTERNAL:
8237                         bad_error("_scf_set_annotation", scf_error());
8238                         /* NOTREACHED */
8239 
8240                 default:
8241                         /*
8242                          * Do not terminate import because of inability to
8243                          * generate annotation audit event.
8244                          */
8245                         warn(gettext("_scf_set_annotation() unexpectedly "
8246                             "failed with return code of %d\n"), scf_error());
8247                         break;
8248                 }
8249         }
8250 
8251         /*
8252          * Clear the sc_import_state's of all services & instances so we can
8253          * report how far we got if we fail.
8254          */
8255         for (svc = uu_list_first(bndl->sc_bundle_services);
8256             svc != NULL;
8257             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8258                 svc->sc_import_state = 0;
8259 
8260                 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8261                     clear_int, (void *)offsetof(entity_t, sc_import_state),
8262                     UU_DEFAULT) != 0)
8263                         bad_error("uu_list_walk", uu_error());
8264         }
8265 
8266         cbdata.sc_handle = g_hndl;
8267         cbdata.sc_parent = imp_scope;
8268         cbdata.sc_flags = flags;
8269         cbdata.sc_general = NULL;
8270 
8271         if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8272             &cbdata, UU_DEFAULT) == 0) {
8273                 char *eptr;
8274                 /* Success.  Refresh everything. */
8275 
8276                 if (flags & SCI_NOREFRESH || no_refresh) {
8277                         no_refresh = 0;
8278                         result = 0;
8279                         goto out;
8280                 }
8281 
8282                 for (svc = uu_list_first(bndl->sc_bundle_services);
8283                     svc != NULL;
8284                     svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8285                         pgroup_t *dpt;
8286 
8287                         insts = svc->sc_u.sc_service.sc_service_instances;
8288 
8289                         for (inst = uu_list_first(insts);
8290                             inst != NULL;
8291                             inst = uu_list_next(insts, inst)) {
8292                                 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8293                                 switch (r) {
8294                                 case 0:
8295                                         break;
8296 
8297                                 case ENOMEM:
8298                                 case ECONNABORTED:
8299                                 case EPERM:
8300                                 case -1:
8301                                         goto progress;
8302 
8303                                 default:
8304                                         bad_error("imp_refresh_fmri", r);
8305                                 }
8306 
8307                                 inst->sc_import_state = IMPORT_REFRESHED;
8308 
8309                                 for (dpt = uu_list_first(inst->sc_dependents);
8310                                     dpt != NULL;
8311                                     dpt = uu_list_next(inst->sc_dependents,
8312                                     dpt))
8313                                         if (imp_refresh_fmri(
8314                                             dpt->sc_pgroup_fmri,
8315                                             dpt->sc_pgroup_name,
8316                                             inst->sc_fmri) != 0)
8317                                                 goto progress;
8318                         }
8319 
8320                         for (dpt = uu_list_first(svc->sc_dependents);
8321                             dpt != NULL;
8322                             dpt = uu_list_next(svc->sc_dependents, dpt))
8323                                 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8324                                     dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8325                                         goto progress;
8326                 }
8327 
8328                 for (old_dpt = uu_list_first(imp_deleted_dpts);
8329                     old_dpt != NULL;
8330                     old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8331                         if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8332                             old_dpt->sc_pgroup_name,
8333                             old_dpt->sc_parent->sc_fmri) != 0)
8334                                 goto progress;
8335 
8336                 result = 0;
8337 
8338                 /*
8339                  * This snippet of code assumes that we are running svccfg as we
8340                  * normally do -- witih svc.startd running. Of course, that is
8341                  * not actually the case all the time because we also use a
8342                  * varient of svc.configd and svccfg which are only meant to
8343                  * run during the build process. During this time we have no
8344                  * svc.startd, so this check would hang the build process.
8345                  *
8346                  * However, we've also given other consolidations, a bit of a
8347                  * means to tie themselves into a knot. They're not properly
8348                  * using the native build equivalents, but they've been getting
8349                  * away with it anyways. Therefore, if we've found that
8350                  * SVCCFG_REPOSITORY is set indicating that a separate configd
8351                  * should be spun up, then we have to assume it's not using a
8352                  * startd and we should not do this check.
8353                  */
8354 #ifndef NATIVE_BUILD
8355                 /*
8356                  * Verify that the restarter group is preset
8357                  */
8358                 eptr = getenv("SVCCFG_REPOSITORY");
8359                 for (svc = uu_list_first(bndl->sc_bundle_services);
8360                     svc != NULL && eptr == NULL;
8361                     svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8362 
8363                         insts = svc->sc_u.sc_service.sc_service_instances;
8364 
8365                         for (inst = uu_list_first(insts);
8366                             inst != NULL;
8367                             inst = uu_list_next(insts, inst)) {
8368                                 if (lscf_instance_verify(imp_scope, svc,
8369                                     inst) != 0)
8370                                         goto progress;
8371                         }
8372                 }
8373 #endif
8374                 goto out;
8375 
8376         }
8377 
8378         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8379                 bad_error("uu_list_walk", uu_error());
8380 
8381 printerr:
8382         /* If the error hasn't been printed yet, do so here. */
8383         switch (cbdata.sc_err) {
8384         case ECONNABORTED:
8385                 warn(gettext("Repository connection broken.\n"));
8386                 break;
8387 
8388         case ENOMEM:
8389                 warn(emsg_nomem);
8390                 break;
8391 
8392         case ENOSPC:
8393                 warn(emsg_nores);
8394                 break;
8395 
8396         case EROFS:
8397                 warn(gettext("Repository is read-only.\n"));
8398                 break;
8399 
8400         case EACCES:
8401                 warn(gettext("Repository backend denied access.\n"));
8402                 break;
8403 
8404         case EPERM:
8405         case EINVAL:
8406         case EEXIST:
8407         case EBUSY:
8408         case EBADF:
8409         case -1:
8410                 break;
8411 
8412         default:
8413                 bad_error("lscf_service_import", cbdata.sc_err);
8414         }
8415 
8416 progress:
8417         warn(gettext("Import of %s failed.  Progress:\n"), filename);
8418 
8419         for (svc = uu_list_first(bndl->sc_bundle_services);
8420             svc != NULL;
8421             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8422                 insts = svc->sc_u.sc_service.sc_service_instances;
8423 
8424                 warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8425                     import_progress(svc->sc_import_state));
8426 
8427                 for (inst = uu_list_first(insts);
8428                     inst != NULL;
8429                     inst = uu_list_next(insts, inst))
8430                         warn(gettext("    Instance \"%s\": %s\n"),
8431                             inst->sc_name,
8432                             import_progress(inst->sc_import_state));
8433         }
8434 
8435         if (cbdata.sc_err == ECONNABORTED)
8436                 repository_teardown();
8437 
8438 
8439         result = -1;
8440 
8441 out:
8442         if (annotation_set != 0) {
8443                 /* Turn off annotation.  It is no longer needed. */
8444                 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8445         }
8446 
8447         free_imp_globals();
8448 
8449         return (result);
8450 }
8451 
8452 /*
8453  * _lscf_import_err() summarize the error handling returned by
8454  * lscf_import_{instance | service}_pgs
8455  * Return values are:
8456  * IMPORT_NEXT
8457  * IMPORT_OUT
8458  * IMPORT_BAD
8459  */
8460 
8461 #define IMPORT_BAD      -1
8462 #define IMPORT_NEXT     0
8463 #define IMPORT_OUT      1
8464 
8465 static int
8466 _lscf_import_err(int err, const char *fmri)
8467 {
8468         switch (err) {
8469         case 0:
8470                 if (g_verbose)
8471                         warn(gettext("%s updated.\n"), fmri);
8472                 return (IMPORT_NEXT);
8473 
8474         case ECONNABORTED:
8475                 warn(gettext("Could not update %s "
8476                     "(repository connection broken).\n"), fmri);
8477                 return (IMPORT_OUT);
8478 
8479         case ENOMEM:
8480                 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8481                 return (IMPORT_OUT);
8482 
8483         case ENOSPC:
8484                 warn(gettext("Could not update %s "
8485                     "(repository server out of resources).\n"), fmri);
8486                 return (IMPORT_OUT);
8487 
8488         case ECANCELED:
8489                 warn(gettext(
8490                     "Could not update %s (deleted).\n"), fmri);
8491                 return (IMPORT_NEXT);
8492 
8493         case EPERM:
8494         case EINVAL:
8495         case EBUSY:
8496                 return (IMPORT_NEXT);
8497 
8498         case EROFS:
8499                 warn(gettext("Could not update %s (repository read-only).\n"),
8500                     fmri);
8501                 return (IMPORT_OUT);
8502 
8503         case EACCES:
8504                 warn(gettext("Could not update %s "
8505                     "(backend access denied).\n"), fmri);
8506                 return (IMPORT_NEXT);
8507 
8508         case EEXIST:
8509         default:
8510                 return (IMPORT_BAD);
8511         }
8512 
8513         /*NOTREACHED*/
8514 }
8515 
8516 /*
8517  * The global imp_svc and imp_inst should be set by the caller in the
8518  * check to make sure the service and instance exist that the apply is
8519  * working on.
8520  */
8521 static int
8522 lscf_dependent_apply(void *dpg, void *e)
8523 {
8524         scf_callback_t cb;
8525         pgroup_t *dpt_pgroup = dpg;
8526         pgroup_t *deldpt;
8527         entity_t *ent = e;
8528         int tissvc;
8529         void *sc_ent, *tent;
8530         scf_error_t serr;
8531         int r;
8532 
8533         const char * const dependents = "dependents";
8534         const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8535 
8536         if (issvc)
8537                 sc_ent = imp_svc;
8538         else
8539                 sc_ent = imp_inst;
8540 
8541         if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8542             imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8543             scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8544             imp_prop) != 0) {
8545                 switch (scf_error()) {
8546                 case SCF_ERROR_NOT_FOUND:
8547                 case SCF_ERROR_DELETED:
8548                         break;
8549 
8550                 case SCF_ERROR_CONNECTION_BROKEN:
8551                 case SCF_ERROR_NOT_SET:
8552                 case SCF_ERROR_INVALID_ARGUMENT:
8553                 case SCF_ERROR_HANDLE_MISMATCH:
8554                 case SCF_ERROR_NOT_BOUND:
8555                 default:
8556                         bad_error("entity_get_pg", scf_error());
8557                 }
8558         } else {
8559                 /*
8560                  * Found the dependents/<wip dep> so check to
8561                  * see if the service is different.  If so
8562                  * store the service for later refresh, and
8563                  * delete the wip dependency from the service
8564                  */
8565                 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8566                         switch (scf_error()) {
8567                                 case SCF_ERROR_DELETED:
8568                                         break;
8569 
8570                                 case SCF_ERROR_CONNECTION_BROKEN:
8571                                 case SCF_ERROR_NOT_SET:
8572                                 case SCF_ERROR_INVALID_ARGUMENT:
8573                                 case SCF_ERROR_HANDLE_MISMATCH:
8574                                 case SCF_ERROR_NOT_BOUND:
8575                                 default:
8576                                         bad_error("scf_property_get_value",
8577                                             scf_error());
8578                         }
8579                 }
8580 
8581                 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8582                     max_scf_value_len + 1) < 0)
8583                         bad_error("scf_value_get_as_string", scf_error());
8584 
8585                 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8586                 switch (r) {
8587                 case 1:
8588                         break;
8589                 case 0:
8590                         if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8591                             &tissvc)) != SCF_ERROR_NONE) {
8592                                 if (serr == SCF_ERROR_NOT_FOUND) {
8593                                         break;
8594                                 } else {
8595                                         bad_error("fmri_to_entity", serr);
8596                                 }
8597                         }
8598 
8599                         if (entity_get_pg(tent, tissvc,
8600                             dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8601                                 serr = scf_error();
8602                                 if (serr == SCF_ERROR_NOT_FOUND ||
8603                                     serr == SCF_ERROR_DELETED) {
8604                                         break;
8605                                 } else {
8606                                         bad_error("entity_get_pg", scf_error());
8607                                 }
8608                         }
8609 
8610                         if (scf_pg_delete(imp_pg) != 0) {
8611                                 serr = scf_error();
8612                                 if (serr == SCF_ERROR_NOT_FOUND ||
8613                                     serr == SCF_ERROR_DELETED) {
8614                                         break;
8615                                 } else {
8616                                         bad_error("scf_pg_delete", scf_error());
8617                                 }
8618                         }
8619 
8620                         deldpt = internal_pgroup_new();
8621                         if (deldpt == NULL)
8622                                 return (ENOMEM);
8623                         deldpt->sc_pgroup_name =
8624                             strdup(dpt_pgroup->sc_pgroup_name);
8625                         deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8626                         if (deldpt->sc_pgroup_name == NULL ||
8627                             deldpt->sc_pgroup_fmri == NULL)
8628                                 return (ENOMEM);
8629                         deldpt->sc_parent = (entity_t *)ent;
8630                         if (uu_list_insert_after(imp_deleted_dpts, NULL,
8631                             deldpt) != 0)
8632                                 uu_die(gettext("libuutil error: %s\n"),
8633                                     uu_strerror(uu_error()));
8634 
8635                         break;
8636                 default:
8637                         bad_error("fmri_equal", r);
8638                 }
8639         }
8640 
8641         cb.sc_handle = g_hndl;
8642         cb.sc_parent = ent;
8643         cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8644         cb.sc_source_fmri = ent->sc_fmri;
8645         cb.sc_target_fmri = ent->sc_fmri;
8646         cb.sc_trans = NULL;
8647         cb.sc_flags = SCI_FORCE;
8648 
8649         if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8650                 return (UU_WALK_ERROR);
8651 
8652         r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8653         switch (r) {
8654         case 0:
8655                 break;
8656 
8657         case ENOMEM:
8658         case ECONNABORTED:
8659         case EPERM:
8660         case -1:
8661                 warn(gettext("Unable to refresh \"%s\"\n"),
8662                     dpt_pgroup->sc_pgroup_fmri);
8663                 return (UU_WALK_ERROR);
8664 
8665         default:
8666                 bad_error("imp_refresh_fmri", r);
8667         }
8668 
8669         return (UU_WALK_NEXT);
8670 }
8671 
8672 /*
8673  * Returns
8674  *   0 - success
8675  *   -1 - lscf_import_instance_pgs() failed.
8676  */
8677 int
8678 lscf_bundle_apply(bundle_t *bndl, const char *file)
8679 {
8680         pgroup_t *old_dpt;
8681         entity_t *svc, *inst;
8682         int annotation_set = 0;
8683         int ret = 0;
8684         int r = 0;
8685 
8686         lscf_prep_hndl();
8687 
8688         if ((ret = alloc_imp_globals()))
8689                 goto out;
8690 
8691         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8692                 scfdie();
8693 
8694         /*
8695          * Set the strings to be used for the security audit annotation
8696          * event.
8697          */
8698         if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8699                 annotation_set = 1;
8700         } else {
8701                 switch (scf_error()) {
8702                 case SCF_ERROR_CONNECTION_BROKEN:
8703                         warn(gettext("Repository connection broken.\n"));
8704                         goto out;
8705 
8706                 case SCF_ERROR_INVALID_ARGUMENT:
8707                 case SCF_ERROR_NOT_BOUND:
8708                 case SCF_ERROR_NO_RESOURCES:
8709                 case SCF_ERROR_INTERNAL:
8710                         bad_error("_scf_set_annotation", scf_error());
8711                         /* NOTREACHED */
8712 
8713                 default:
8714                         /*
8715                          * Do not abort apply operation because of
8716                          * inability to create annotation audit event.
8717                          */
8718                         warn(gettext("_scf_set_annotation() unexpectedly "
8719                             "failed with return code of %d\n"), scf_error());
8720                         break;
8721                 }
8722         }
8723 
8724         for (svc = uu_list_first(bndl->sc_bundle_services);
8725             svc != NULL;
8726             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8727                 int refresh = 0;
8728 
8729                 if (scf_scope_get_service(imp_scope, svc->sc_name,
8730                     imp_svc) != 0) {
8731                         switch (scf_error()) {
8732                         case SCF_ERROR_NOT_FOUND:
8733                                 if (g_verbose)
8734                                         warn(gettext("Ignoring nonexistent "
8735                                             "service %s.\n"), svc->sc_name);
8736                                 continue;
8737 
8738                         default:
8739                                 scfdie();
8740                         }
8741                 }
8742 
8743                 /*
8744                  * If there were missing types in the profile, then need to
8745                  * attempt to find the types.
8746                  */
8747                 if (svc->sc_miss_type) {
8748                         if (uu_list_numnodes(svc->sc_pgroups) &&
8749                             uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8750                             svc, UU_DEFAULT) != 0) {
8751                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8752                                         bad_error("uu_list_walk", uu_error());
8753 
8754                                 ret = -1;
8755                                 continue;
8756                         }
8757 
8758                         for (inst = uu_list_first(
8759                             svc->sc_u.sc_service.sc_service_instances);
8760                             inst != NULL;
8761                             inst = uu_list_next(
8762                             svc->sc_u.sc_service.sc_service_instances, inst)) {
8763                                 /*
8764                                  * If the instance doesn't exist just
8765                                  * skip to the next instance and let the
8766                                  * import note the missing instance.
8767                                  */
8768                                 if (scf_service_get_instance(imp_svc,
8769                                     inst->sc_name, imp_inst) != 0)
8770                                         continue;
8771 
8772                                 if (uu_list_walk(inst->sc_pgroups,
8773                                     find_current_pg_type, inst,
8774                                     UU_DEFAULT) != 0) {
8775                                         if (uu_error() !=
8776                                             UU_ERROR_CALLBACK_FAILED)
8777                                                 bad_error("uu_list_walk",
8778                                                     uu_error());
8779 
8780                                         ret = -1;
8781                                         inst->sc_miss_type = B_TRUE;
8782                                 }
8783                         }
8784                 }
8785 
8786                 /*
8787                  * if we have pgs in the profile, we need to refresh ALL
8788                  * instances of the service
8789                  */
8790                 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8791                         refresh = 1;
8792                         r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8793                             SCI_FORCE | SCI_KEEP);
8794                         switch (_lscf_import_err(r, svc->sc_fmri)) {
8795                         case IMPORT_NEXT:
8796                                 break;
8797 
8798                         case IMPORT_OUT:
8799                                 goto out;
8800 
8801                         case IMPORT_BAD:
8802                         default:
8803                                 bad_error("lscf_import_service_pgs", r);
8804                         }
8805                 }
8806 
8807                 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8808                         uu_list_walk(svc->sc_dependents,
8809                             lscf_dependent_apply, svc, UU_DEFAULT);
8810                 }
8811 
8812                 for (inst = uu_list_first(
8813                     svc->sc_u.sc_service.sc_service_instances);
8814                     inst != NULL;
8815                     inst = uu_list_next(
8816                     svc->sc_u.sc_service.sc_service_instances, inst)) {
8817                         /*
8818                          * This instance still has missing types
8819                          * so skip it.
8820                          */
8821                         if (inst->sc_miss_type) {
8822                                 if (g_verbose)
8823                                         warn(gettext("Ignoring instance "
8824                                             "%s:%s with missing types\n"),
8825                                             inst->sc_parent->sc_name,
8826                                             inst->sc_name);
8827 
8828                                 continue;
8829                         }
8830 
8831                         if (scf_service_get_instance(imp_svc, inst->sc_name,
8832                             imp_inst) != 0) {
8833                                 switch (scf_error()) {
8834                                 case SCF_ERROR_NOT_FOUND:
8835                                         if (g_verbose)
8836                                                 warn(gettext("Ignoring "
8837                                                     "nonexistant instance "
8838                                                     "%s:%s.\n"),
8839                                                     inst->sc_parent->sc_name,
8840                                                     inst->sc_name);
8841                                         continue;
8842 
8843                                 default:
8844                                         scfdie();
8845                                 }
8846                         }
8847 
8848                         /*
8849                          * If the instance does not have a general/enabled
8850                          * property and no last-import snapshot then the
8851                          * instance is not a fully installed instance and
8852                          * should not have a profile applied to it.
8853                          *
8854                          * This could happen if a service/instance declares
8855                          * a dependent on behalf of another service/instance.
8856                          *
8857                          */
8858                         if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8859                             imp_snap) != 0) {
8860                                 if (scf_instance_get_pg(imp_inst,
8861                                     SCF_PG_GENERAL, imp_pg) != 0 ||
8862                                     scf_pg_get_property(imp_pg,
8863                                     SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8864                                         if (g_verbose)
8865                                                 warn(gettext("Ignoreing "
8866                                                     "partial instance "
8867                                                     "%s:%s.\n"),
8868                                                     inst->sc_parent->sc_name,
8869                                                     inst->sc_name);
8870                                         continue;
8871                                 }
8872                         }
8873 
8874                         r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8875                             inst, SCI_FORCE | SCI_KEEP);
8876                         switch (_lscf_import_err(r, inst->sc_fmri)) {
8877                         case IMPORT_NEXT:
8878                                 break;
8879 
8880                         case IMPORT_OUT:
8881                                 goto out;
8882 
8883                         case IMPORT_BAD:
8884                         default:
8885                                 bad_error("lscf_import_instance_pgs", r);
8886                         }
8887 
8888                         if (uu_list_numnodes(inst->sc_dependents) != 0) {
8889                                 uu_list_walk(inst->sc_dependents,
8890                                     lscf_dependent_apply, inst, UU_DEFAULT);
8891                         }
8892 
8893                         /* refresh only if there is no pgs in the service */
8894                         if (refresh == 0)
8895                                 (void) refresh_entity(0, imp_inst,
8896                                     inst->sc_fmri, NULL, NULL, NULL);
8897                 }
8898 
8899                 if (refresh == 1) {
8900                         char *name_buf = safe_malloc(max_scf_name_len + 1);
8901 
8902                         (void) refresh_entity(1, imp_svc, svc->sc_name,
8903                             imp_inst, imp_iter, name_buf);
8904                         free(name_buf);
8905                 }
8906 
8907                 for (old_dpt = uu_list_first(imp_deleted_dpts);
8908                     old_dpt != NULL;
8909                     old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8910                         if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8911                             old_dpt->sc_pgroup_name,
8912                             old_dpt->sc_parent->sc_fmri) != 0) {
8913                                 warn(gettext("Unable to refresh \"%s\"\n"),
8914                                     old_dpt->sc_pgroup_fmri);
8915                         }
8916                 }
8917         }
8918 
8919 out:
8920         if (annotation_set) {
8921                 /* Remove security audit annotation strings. */
8922                 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8923         }
8924 
8925         free_imp_globals();
8926         return (ret);
8927 }
8928 
8929 
8930 /*
8931  * Export.  These functions create and output an XML tree of a service
8932  * description from the repository.  This is largely the inverse of
8933  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8934  *
8935  * - We must include any properties which are not represented specifically by
8936  *   a service manifest, e.g., properties created by an admin post-import.  To
8937  *   do so we'll iterate through all properties and deal with each
8938  *   apropriately.
8939  *
8940  * - Children of services and instances must must be in the order set by the
8941  *   DTD, but we iterate over the properties in undefined order.  The elements
8942  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8943  *   number of classes of them, however, we'll keep the classes separate and
8944  *   assemble them in order.
8945  */
8946 
8947 /*
8948  * Convenience function to handle xmlSetProp errors (and type casting).
8949  */
8950 static void
8951 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8952 {
8953         if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8954                 uu_die(gettext("Could not set XML property.\n"));
8955 }
8956 
8957 /*
8958  * Convenience function to set an XML attribute to the single value of an
8959  * astring property.  If the value happens to be the default, don't set the
8960  * attribute.  "dval" should be the default value supplied by the DTD, or
8961  * NULL for no default.
8962  */
8963 static int
8964 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8965     const char *name, const char *dval)
8966 {
8967         scf_value_t *val;
8968         ssize_t len;
8969         char *str;
8970 
8971         val = scf_value_create(g_hndl);
8972         if (val == NULL)
8973                 scfdie();
8974 
8975         if (prop_get_val(prop, val) != 0) {
8976                 scf_value_destroy(val);
8977                 return (-1);
8978         }
8979 
8980         len = scf_value_get_as_string(val, NULL, 0);
8981         if (len < 0)
8982                 scfdie();
8983 
8984         str = safe_malloc(len + 1);
8985 
8986         if (scf_value_get_as_string(val, str, len + 1) < 0)
8987                 scfdie();
8988 
8989         scf_value_destroy(val);
8990 
8991         if (dval == NULL || strcmp(str, dval) != 0)
8992                 safe_setprop(n, name, str);
8993 
8994         free(str);
8995 
8996         return (0);
8997 }
8998 
8999 /*
9000  * As above, but the attribute is always set.
9001  */
9002 static int
9003 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9004 {
9005         return (set_attr_from_prop_default(prop, n, name, NULL));
9006 }
9007 
9008 /*
9009  * Dump the given document onto f, with "'s replaced by ''s.
9010  */
9011 static int
9012 write_service_bundle(xmlDocPtr doc, FILE *f)
9013 {
9014         xmlChar *mem;
9015         int sz, i;
9016 
9017         mem = NULL;
9018         xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9019 
9020         if (mem == NULL) {
9021                 semerr(gettext("Could not dump XML tree.\n"));
9022                 return (-1);
9023         }
9024 
9025         /*
9026          * Fortunately libxml produces &quot; instead of ", so we can blindly
9027          * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9028          * &apos; code?!
9029          */
9030         for (i = 0; i < sz; ++i) {
9031                 char c = (char)mem[i];
9032 
9033                 if (c == '"')
9034                         (void) fputc('\'', f);
9035                 else if (c == '\'')
9036                         (void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9037                 else
9038                         (void) fputc(c, f);
9039         }
9040 
9041         return (0);
9042 }
9043 
9044 /*
9045  * Create the DOM elements in elts necessary to (generically) represent prop
9046  * (i.e., a property or propval element).  If the name of the property is
9047  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9048  */
9049 static void
9050 export_property(scf_property_t *prop, const char *name_arg,
9051     struct pg_elts *elts, int flags)
9052 {
9053         const char *type;
9054         scf_error_t err = 0;
9055         xmlNodePtr pnode, lnode;
9056         char *lnname;
9057         int ret;
9058 
9059         /* name */
9060         if (name_arg != NULL) {
9061                 (void) strcpy(exp_str, name_arg);
9062         } else {
9063                 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9064                         scfdie();
9065         }
9066 
9067         /* type */
9068         type = prop_to_typestr(prop);
9069         if (type == NULL)
9070                 uu_die(gettext("Can't export property %s: unknown type.\n"),
9071                     exp_str);
9072 
9073         /* If we're exporting values, and there's just one, export it here. */
9074         if (!(flags & SCE_ALL_VALUES))
9075                 goto empty;
9076 
9077         if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9078                 xmlNodePtr n;
9079 
9080                 /* Single value, so use propval */
9081                 n = xmlNewNode(NULL, (xmlChar *)"propval");
9082                 if (n == NULL)
9083                         uu_die(emsg_create_xml);
9084 
9085                 safe_setprop(n, name_attr, exp_str);
9086                 safe_setprop(n, type_attr, type);
9087 
9088                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9089                         scfdie();
9090                 safe_setprop(n, value_attr, exp_str);
9091 
9092                 if (elts->propvals == NULL)
9093                         elts->propvals = n;
9094                 else
9095                         (void) xmlAddSibling(elts->propvals, n);
9096 
9097                 return;
9098         }
9099 
9100         err = scf_error();
9101 
9102         if (err == SCF_ERROR_PERMISSION_DENIED) {
9103                 semerr(emsg_permission_denied);
9104                 return;
9105         }
9106 
9107         if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9108             err != SCF_ERROR_NOT_FOUND &&
9109             err != SCF_ERROR_PERMISSION_DENIED)
9110                 scfdie();
9111 
9112 empty:
9113         /* Multiple (or no) values, so use property */
9114         pnode = xmlNewNode(NULL, (xmlChar *)"property");
9115         if (pnode == NULL)
9116                 uu_die(emsg_create_xml);
9117 
9118         safe_setprop(pnode, name_attr, exp_str);
9119         safe_setprop(pnode, type_attr, type);
9120 
9121         if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9122                 lnname = uu_msprintf("%s_list", type);
9123                 if (lnname == NULL)
9124                         uu_die(gettext("Could not create string"));
9125 
9126                 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9127                 if (lnode == NULL)
9128                         uu_die(emsg_create_xml);
9129 
9130                 uu_free(lnname);
9131 
9132                 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9133                         scfdie();
9134 
9135                 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9136                     1) {
9137                         xmlNodePtr vn;
9138 
9139                         vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9140                             NULL);
9141                         if (vn == NULL)
9142                                 uu_die(emsg_create_xml);
9143 
9144                         if (scf_value_get_as_string(exp_val, exp_str,
9145                             exp_str_sz) < 0)
9146                                 scfdie();
9147                         safe_setprop(vn, value_attr, exp_str);
9148                 }
9149                 if (ret != 0)
9150                         scfdie();
9151         }
9152 
9153         if (elts->properties == NULL)
9154                 elts->properties = pnode;
9155         else
9156                 (void) xmlAddSibling(elts->properties, pnode);
9157 }
9158 
9159 /*
9160  * Add a property_group element for this property group to elts.
9161  */
9162 static void
9163 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9164 {
9165         xmlNodePtr n;
9166         struct pg_elts elts;
9167         int ret;
9168         boolean_t read_protected;
9169 
9170         n = xmlNewNode(NULL, (xmlChar *)"property_group");
9171 
9172         /* name */
9173         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9174                 scfdie();
9175         safe_setprop(n, name_attr, exp_str);
9176 
9177         /* type */
9178         if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9179                 scfdie();
9180         safe_setprop(n, type_attr, exp_str);
9181 
9182         /* properties */
9183         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9184                 scfdie();
9185 
9186         (void) memset(&elts, 0, sizeof (elts));
9187 
9188         /*
9189          * If this property group is not read protected, we always want to
9190          * output all the values.  Otherwise, we only output the values if the
9191          * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9192          */
9193         if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9194                 scfdie();
9195 
9196         if (!read_protected)
9197                 flags |= SCE_ALL_VALUES;
9198 
9199         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9200                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9201                         scfdie();
9202 
9203                 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9204                         xmlNodePtr m;
9205 
9206                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9207                         if (m == NULL)
9208                                 uu_die(emsg_create_xml);
9209 
9210                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9211                                 elts.stability = m;
9212                                 continue;
9213                         }
9214 
9215                         xmlFreeNode(m);
9216                 }
9217 
9218                 export_property(exp_prop, NULL, &elts, flags);
9219         }
9220         if (ret == -1)
9221                 scfdie();
9222 
9223         (void) xmlAddChild(n, elts.stability);
9224         (void) xmlAddChildList(n, elts.propvals);
9225         (void) xmlAddChildList(n, elts.properties);
9226 
9227         if (eelts->property_groups == NULL)
9228                 eelts->property_groups = n;
9229         else
9230                 (void) xmlAddSibling(eelts->property_groups, n);
9231 }
9232 
9233 /*
9234  * Create an XML node representing the dependency described by the given
9235  * property group and put it in eelts.  Unless the dependency is not valid, in
9236  * which case create a generic property_group element which represents it and
9237  * put it in eelts.
9238  */
9239 static void
9240 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9241 {
9242         xmlNodePtr n;
9243         int err = 0, ret;
9244         struct pg_elts elts;
9245 
9246         n = xmlNewNode(NULL, (xmlChar *)"dependency");
9247         if (n == NULL)
9248                 uu_die(emsg_create_xml);
9249 
9250         /*
9251          * If the external flag is present, skip this dependency because it
9252          * should have been created by another manifest.
9253          */
9254         if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9255                 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9256                     prop_get_val(exp_prop, exp_val) == 0) {
9257                         uint8_t b;
9258 
9259                         if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9260                                 scfdie();
9261 
9262                         if (b)
9263                                 return;
9264                 }
9265         } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9266                 scfdie();
9267 
9268         /* Get the required attributes. */
9269 
9270         /* name */
9271         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9272                 scfdie();
9273         safe_setprop(n, name_attr, exp_str);
9274 
9275         /* grouping */
9276         if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9277             set_attr_from_prop(exp_prop, n, "grouping") != 0)
9278                 err = 1;
9279 
9280         /* restart_on */
9281         if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9282             set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9283                 err = 1;
9284 
9285         /* type */
9286         if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9287             set_attr_from_prop(exp_prop, n, type_attr) != 0)
9288                 err = 1;
9289 
9290         /*
9291          * entities: Not required, but if we create no children, it will be
9292          * created as empty on import, so fail if it's missing.
9293          */
9294         if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9295             prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9296                 scf_iter_t *eiter;
9297                 int ret2;
9298 
9299                 eiter = scf_iter_create(g_hndl);
9300                 if (eiter == NULL)
9301                         scfdie();
9302 
9303                 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9304                         scfdie();
9305 
9306                 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9307                         xmlNodePtr ch;
9308 
9309                         if (scf_value_get_astring(exp_val, exp_str,
9310                             exp_str_sz) < 0)
9311                                 scfdie();
9312 
9313                         /*
9314                          * service_fmri's must be first, so we can add them
9315                          * here.
9316                          */
9317                         ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9318                             NULL);
9319                         if (ch == NULL)
9320                                 uu_die(emsg_create_xml);
9321 
9322                         safe_setprop(ch, value_attr, exp_str);
9323                 }
9324                 if (ret2 == -1)
9325                         scfdie();
9326 
9327                 scf_iter_destroy(eiter);
9328         } else
9329                 err = 1;
9330 
9331         if (err) {
9332                 xmlFreeNode(n);
9333 
9334                 export_pg(pg, eelts, SCE_ALL_VALUES);
9335 
9336                 return;
9337         }
9338 
9339         /* Iterate through the properties & handle each. */
9340         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9341                 scfdie();
9342 
9343         (void) memset(&elts, 0, sizeof (elts));
9344 
9345         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9346                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9347                         scfdie();
9348 
9349                 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9350                     strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9351                     strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9352                     strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9353                         continue;
9354                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9355                         xmlNodePtr m;
9356 
9357                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9358                         if (m == NULL)
9359                                 uu_die(emsg_create_xml);
9360 
9361                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9362                                 elts.stability = m;
9363                                 continue;
9364                         }
9365 
9366                         xmlFreeNode(m);
9367                 }
9368 
9369                 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9370         }
9371         if (ret == -1)
9372                 scfdie();
9373 
9374         (void) xmlAddChild(n, elts.stability);
9375         (void) xmlAddChildList(n, elts.propvals);
9376         (void) xmlAddChildList(n, elts.properties);
9377 
9378         if (eelts->dependencies == NULL)
9379                 eelts->dependencies = n;
9380         else
9381                 (void) xmlAddSibling(eelts->dependencies, n);
9382 }
9383 
9384 static xmlNodePtr
9385 export_method_environment(scf_propertygroup_t *pg)
9386 {
9387         xmlNodePtr env;
9388         int ret;
9389         int children = 0;
9390 
9391         if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9392                 return (NULL);
9393 
9394         env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9395         if (env == NULL)
9396                 uu_die(emsg_create_xml);
9397 
9398         if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9399                 scfdie();
9400 
9401         if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9402                 scfdie();
9403 
9404         while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9405                 xmlNodePtr ev;
9406                 char *cp;
9407 
9408                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9409                         scfdie();
9410 
9411                 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9412                         warn(gettext("Invalid environment variable \"%s\".\n"),
9413                             exp_str);
9414                         continue;
9415                 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9416                         warn(gettext("Invalid environment variable \"%s\"; "
9417                             "\"SMF_\" prefix is reserved.\n"), exp_str);
9418                         continue;
9419                 }
9420 
9421                 *cp = '\0';
9422                 cp++;
9423 
9424                 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9425                 if (ev == NULL)
9426                         uu_die(emsg_create_xml);
9427 
9428                 safe_setprop(ev, name_attr, exp_str);
9429                 safe_setprop(ev, value_attr, cp);
9430                 children++;
9431         }
9432 
9433         if (ret != 0)
9434                 scfdie();
9435 
9436         if (children == 0) {
9437                 xmlFreeNode(env);
9438                 return (NULL);
9439         }
9440 
9441         return (env);
9442 }
9443 
9444 /*
9445  * As above, but for a method property group.
9446  */
9447 static void
9448 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9449 {
9450         xmlNodePtr n, env;
9451         char *str;
9452         int err = 0, nonenv, ret;
9453         uint8_t use_profile;
9454         struct pg_elts elts;
9455         xmlNodePtr ctxt = NULL;
9456 
9457         n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9458 
9459         /* Get the required attributes. */
9460 
9461         /* name */
9462         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9463                 scfdie();
9464         safe_setprop(n, name_attr, exp_str);
9465 
9466         /* type */
9467         if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9468             set_attr_from_prop(exp_prop, n, type_attr) != 0)
9469                 err = 1;
9470 
9471         /* exec */
9472         if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9473             set_attr_from_prop(exp_prop, n, "exec") != 0)
9474                 err = 1;
9475 
9476         /* timeout */
9477         if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9478             prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9479             prop_get_val(exp_prop, exp_val) == 0) {
9480                 uint64_t c;
9481 
9482                 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9483                         scfdie();
9484 
9485                 str = uu_msprintf("%llu", c);
9486                 if (str == NULL)
9487                         uu_die(gettext("Could not create string"));
9488 
9489                 safe_setprop(n, "timeout_seconds", str);
9490                 free(str);
9491         } else
9492                 err = 1;
9493 
9494         if (err) {
9495                 xmlFreeNode(n);
9496 
9497                 export_pg(pg, eelts, SCE_ALL_VALUES);
9498 
9499                 return;
9500         }
9501 
9502 
9503         /*
9504          * If we're going to have a method_context child, we need to know
9505          * before we iterate through the properties.  Since method_context's
9506          * are optional, we don't want to complain about any properties
9507          * missing if none of them are there.  Thus we can't use the
9508          * convenience functions.
9509          */
9510         nonenv =
9511             scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9512             SCF_SUCCESS ||
9513             scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9514             SCF_SUCCESS ||
9515             scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9516             SCF_SUCCESS ||
9517             scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9518             SCF_SUCCESS ||
9519             scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9520             SCF_SUCCESS;
9521 
9522         if (nonenv) {
9523                 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9524                 if (ctxt == NULL)
9525                         uu_die(emsg_create_xml);
9526 
9527                 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9528                     0 &&
9529                     set_attr_from_prop_default(exp_prop, ctxt,
9530                     "working_directory", ":default") != 0)
9531                         err = 1;
9532 
9533                 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9534                     set_attr_from_prop_default(exp_prop, ctxt, "project",
9535                     ":default") != 0)
9536                         err = 1;
9537 
9538                 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9539                     0 &&
9540                     set_attr_from_prop_default(exp_prop, ctxt,
9541                     "resource_pool", ":default") != 0)
9542                         err = 1;
9543 
9544                 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9545                     set_attr_from_prop_default(exp_prop, ctxt,
9546                     "security_flags", ":default") != 0)
9547                         err = 1;
9548 
9549                 /*
9550                  * We only want to complain about profile or credential
9551                  * properties if we will use them.  To determine that we must
9552                  * examine USE_PROFILE.
9553                  */
9554                 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9555                     prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9556                     prop_get_val(exp_prop, exp_val) == 0) {
9557                         if (scf_value_get_boolean(exp_val, &use_profile) !=
9558                             SCF_SUCCESS) {
9559                                 scfdie();
9560                         }
9561 
9562                         if (use_profile) {
9563                                 xmlNodePtr prof;
9564 
9565                                 prof = xmlNewChild(ctxt, NULL,
9566                                     (xmlChar *)"method_profile", NULL);
9567                                 if (prof == NULL)
9568                                         uu_die(emsg_create_xml);
9569 
9570                                 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9571                                     exp_prop) != 0 ||
9572                                     set_attr_from_prop(exp_prop, prof,
9573                                     name_attr) != 0)
9574                                         err = 1;
9575                         } else {
9576                                 xmlNodePtr cred;
9577 
9578                                 cred = xmlNewChild(ctxt, NULL,
9579                                     (xmlChar *)"method_credential", NULL);
9580                                 if (cred == NULL)
9581                                         uu_die(emsg_create_xml);
9582 
9583                                 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9584                                     exp_prop) != 0 ||
9585                                     set_attr_from_prop(exp_prop, cred,
9586                                     "user") != 0) {
9587                                         err = 1;
9588                                 }
9589 
9590                                 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9591                                     exp_prop) == 0 &&
9592                                     set_attr_from_prop_default(exp_prop, cred,
9593                                     "group", ":default") != 0)
9594                                         err = 1;
9595 
9596                                 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9597                                     exp_prop) == 0 &&
9598                                     set_attr_from_prop_default(exp_prop, cred,
9599                                     "supp_groups", ":default") != 0)
9600                                         err = 1;
9601 
9602                                 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9603                                     exp_prop) == 0 &&
9604                                     set_attr_from_prop_default(exp_prop, cred,
9605                                     "privileges", ":default") != 0)
9606                                         err = 1;
9607 
9608                                 if (pg_get_prop(pg,
9609                                     SCF_PROPERTY_LIMIT_PRIVILEGES,
9610                                     exp_prop) == 0 &&
9611                                     set_attr_from_prop_default(exp_prop, cred,
9612                                     "limit_privileges", ":default") != 0)
9613                                         err = 1;
9614                         }
9615                 }
9616         }
9617 
9618         if ((env = export_method_environment(pg)) != NULL) {
9619                 if (ctxt == NULL) {
9620                         ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9621                         if (ctxt == NULL)
9622                                 uu_die(emsg_create_xml);
9623                 }
9624                 (void) xmlAddChild(ctxt, env);
9625         }
9626 
9627         if (env != NULL || (nonenv && err == 0))
9628                 (void) xmlAddChild(n, ctxt);
9629         else
9630                 xmlFreeNode(ctxt);
9631 
9632         nonenv = (err == 0);
9633 
9634         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9635                 scfdie();
9636 
9637         (void) memset(&elts, 0, sizeof (elts));
9638 
9639         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9640                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9641                         scfdie();
9642 
9643                 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9644                     strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9645                     strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9646                         continue;
9647                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9648                         xmlNodePtr m;
9649 
9650                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9651                         if (m == NULL)
9652                                 uu_die(emsg_create_xml);
9653 
9654                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9655                                 elts.stability = m;
9656                                 continue;
9657                         }
9658 
9659                         xmlFreeNode(m);
9660                 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9661                     0 ||
9662                     strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9663                     strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9664                     strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9665                         if (nonenv)
9666                                 continue;
9667                 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9668                     strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9669                     strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9670                     strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9671                     strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9672                     strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9673                         if (nonenv && !use_profile)
9674                                 continue;
9675                 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9676                         if (nonenv && use_profile)
9677                                 continue;
9678                 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9679                         if (env != NULL)
9680                                 continue;
9681                 }
9682 
9683                 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9684         }
9685         if (ret == -1)
9686                 scfdie();
9687 
9688         (void) xmlAddChild(n, elts.stability);
9689         (void) xmlAddChildList(n, elts.propvals);
9690         (void) xmlAddChildList(n, elts.properties);
9691 
9692         if (eelts->exec_methods == NULL)
9693                 eelts->exec_methods = n;
9694         else
9695                 (void) xmlAddSibling(eelts->exec_methods, n);
9696 }
9697 
9698 static void
9699 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9700     struct entity_elts *eelts)
9701 {
9702         xmlNodePtr pgnode;
9703 
9704         pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9705         if (pgnode == NULL)
9706                 uu_die(emsg_create_xml);
9707 
9708         safe_setprop(pgnode, name_attr, name);
9709         safe_setprop(pgnode, type_attr, type);
9710 
9711         (void) xmlAddChildList(pgnode, elts->propvals);
9712         (void) xmlAddChildList(pgnode, elts->properties);
9713 
9714         if (eelts->property_groups == NULL)
9715                 eelts->property_groups = pgnode;
9716         else
9717                 (void) xmlAddSibling(eelts->property_groups, pgnode);
9718 }
9719 
9720 /*
9721  * Process the general property group for a service.  This is the one with the
9722  * goodies.
9723  */
9724 static void
9725 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9726 {
9727         struct pg_elts elts;
9728         int ret;
9729 
9730         /*
9731          * In case there are properties which don't correspond to child
9732          * entities of the service entity, we'll set up a pg_elts structure to
9733          * put them in.
9734          */
9735         (void) memset(&elts, 0, sizeof (elts));
9736 
9737         /* Walk the properties, looking for special ones. */
9738         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9739                 scfdie();
9740 
9741         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9742                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9743                         scfdie();
9744 
9745                 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9746                         /*
9747                          * Unimplemented and obsolete, but we still process it
9748                          * for compatibility purposes.
9749                          */
9750                         if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9751                             prop_get_val(exp_prop, exp_val) == 0) {
9752                                 uint8_t b;
9753 
9754                                 if (scf_value_get_boolean(exp_val, &b) !=
9755                                     SCF_SUCCESS)
9756                                         scfdie();
9757 
9758                                 if (b) {
9759                                         selts->single_instance =
9760                                             xmlNewNode(NULL,
9761                                             (xmlChar *)"single_instance");
9762                                         if (selts->single_instance == NULL)
9763                                                 uu_die(emsg_create_xml);
9764                                 }
9765 
9766                                 continue;
9767                         }
9768                 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9769                         xmlNodePtr rnode, sfnode;
9770 
9771                         rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9772                         if (rnode == NULL)
9773                                 uu_die(emsg_create_xml);
9774 
9775                         sfnode = xmlNewChild(rnode, NULL,
9776                             (xmlChar *)"service_fmri", NULL);
9777                         if (sfnode == NULL)
9778                                 uu_die(emsg_create_xml);
9779 
9780                         if (set_attr_from_prop(exp_prop, sfnode,
9781                             value_attr) == 0) {
9782                                 selts->restarter = rnode;
9783                                 continue;
9784                         }
9785 
9786                         xmlFreeNode(rnode);
9787                 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9788                     0) {
9789                         xmlNodePtr s;
9790 
9791                         s = xmlNewNode(NULL, (xmlChar *)"stability");
9792                         if (s == NULL)
9793                                 uu_die(emsg_create_xml);
9794 
9795                         if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9796                                 selts->stability = s;
9797                                 continue;
9798                         }
9799 
9800                         xmlFreeNode(s);
9801                 }
9802 
9803                 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9804         }
9805         if (ret == -1)
9806                 scfdie();
9807 
9808         if (elts.propvals != NULL || elts.properties != NULL)
9809                 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9810                     selts);
9811 }
9812 
9813 static void
9814 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9815 {
9816         xmlNodePtr n, prof, cred, env;
9817         uint8_t use_profile;
9818         int ret, err = 0;
9819 
9820         n = xmlNewNode(NULL, (xmlChar *)"method_context");
9821 
9822         env = export_method_environment(pg);
9823 
9824         /* Need to know whether we'll use a profile or not. */
9825         if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9826             prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9827             prop_get_val(exp_prop, exp_val) == 0) {
9828                 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9829                         scfdie();
9830 
9831                 if (use_profile)
9832                         prof =
9833                             xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9834                             NULL);
9835                 else
9836                         cred =
9837                             xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9838                             NULL);
9839         }
9840 
9841         if (env != NULL)
9842                 (void) xmlAddChild(n, env);
9843 
9844         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9845                 scfdie();
9846 
9847         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9848                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9849                         scfdie();
9850 
9851                 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9852                         if (set_attr_from_prop(exp_prop, n,
9853                             "working_directory") != 0)
9854                                 err = 1;
9855                 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9856                         if (set_attr_from_prop(exp_prop, n, "project") != 0)
9857                                 err = 1;
9858                 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9859                         if (set_attr_from_prop(exp_prop, n,
9860                             "resource_pool") != 0)
9861                                 err = 1;
9862                 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9863                         if (set_attr_from_prop(exp_prop, n,
9864                             "security_flags") != 0)
9865                                 err = 1;
9866                 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9867                         /* EMPTY */
9868                 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9869                         if (use_profile ||
9870                             set_attr_from_prop(exp_prop, cred, "user") != 0)
9871                                 err = 1;
9872                 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9873                         if (use_profile ||
9874                             set_attr_from_prop(exp_prop, cred, "group") != 0)
9875                                 err = 1;
9876                 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9877                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9878                             "supp_groups") != 0)
9879                                 err = 1;
9880                 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9881                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9882                             "privileges") != 0)
9883                                 err = 1;
9884                 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9885                     0) {
9886                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9887                             "limit_privileges") != 0)
9888                                 err = 1;
9889                 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9890                         if (!use_profile || set_attr_from_prop(exp_prop,
9891                             prof, name_attr) != 0)
9892                                 err = 1;
9893                 } else {
9894                         /* Can't have generic properties in method_context's */
9895                         err = 1;
9896                 }
9897         }
9898         if (ret == -1)
9899                 scfdie();
9900 
9901         if (err && env == NULL) {
9902                 xmlFreeNode(n);
9903                 export_pg(pg, elts, SCE_ALL_VALUES);
9904                 return;
9905         }
9906 
9907         elts->method_context = n;
9908 }
9909 
9910 /*
9911  * Given a dependency property group in the tfmri entity (target fmri), return
9912  * a dependent element which represents it.
9913  */
9914 static xmlNodePtr
9915 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9916 {
9917         uint8_t b;
9918         xmlNodePtr n, sf;
9919         int err = 0, ret;
9920         struct pg_elts pgelts;
9921 
9922         /*
9923          * If external isn't set to true then exporting the service will
9924          * export this as a normal dependency, so we should stop to avoid
9925          * duplication.
9926          */
9927         if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9928             scf_property_get_value(exp_prop, exp_val) != 0 ||
9929             scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9930                 if (g_verbose) {
9931                         warn(gettext("Dependent \"%s\" cannot be exported "
9932                             "properly because the \"%s\" property of the "
9933                             "\"%s\" dependency of %s is not set to true.\n"),
9934                             name, scf_property_external, name, tfmri);
9935                 }
9936 
9937                 return (NULL);
9938         }
9939 
9940         n = xmlNewNode(NULL, (xmlChar *)"dependent");
9941         if (n == NULL)
9942                 uu_die(emsg_create_xml);
9943 
9944         safe_setprop(n, name_attr, name);
9945 
9946         /* Get the required attributes */
9947         if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9948             set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9949                 err = 1;
9950 
9951         if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9952             set_attr_from_prop(exp_prop, n, "grouping") != 0)
9953                 err = 1;
9954 
9955         if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9956             prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9957             prop_get_val(exp_prop, exp_val) == 0) {
9958                 /* EMPTY */
9959         } else
9960                 err = 1;
9961 
9962         if (err) {
9963                 xmlFreeNode(n);
9964                 return (NULL);
9965         }
9966 
9967         sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9968         if (sf == NULL)
9969                 uu_die(emsg_create_xml);
9970 
9971         safe_setprop(sf, value_attr, tfmri);
9972 
9973         /*
9974          * Now add elements for the other properties.
9975          */
9976         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9977                 scfdie();
9978 
9979         (void) memset(&pgelts, 0, sizeof (pgelts));
9980 
9981         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9982                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9983                         scfdie();
9984 
9985                 if (strcmp(exp_str, scf_property_external) == 0 ||
9986                     strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9987                     strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9988                     strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9989                         continue;
9990                 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9991                         if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9992                             prop_get_val(exp_prop, exp_val) == 0) {
9993                                 char type[sizeof ("service") + 1];
9994 
9995                                 if (scf_value_get_astring(exp_val, type,
9996                                     sizeof (type)) < 0)
9997                                         scfdie();
9998 
9999                                 if (strcmp(type, "service") == 0)
10000                                         continue;
10001                         }
10002                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10003                         xmlNodePtr s;
10004 
10005                         s = xmlNewNode(NULL, (xmlChar *)"stability");
10006                         if (s == NULL)
10007                                 uu_die(emsg_create_xml);
10008 
10009                         if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10010                                 pgelts.stability = s;
10011                                 continue;
10012                         }
10013 
10014                         xmlFreeNode(s);
10015                 }
10016 
10017                 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10018         }
10019         if (ret == -1)
10020                 scfdie();
10021 
10022         (void) xmlAddChild(n, pgelts.stability);
10023         (void) xmlAddChildList(n, pgelts.propvals);
10024         (void) xmlAddChildList(n, pgelts.properties);
10025 
10026         return (n);
10027 }
10028 
10029 static void
10030 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10031 {
10032         scf_propertygroup_t *opg;
10033         scf_iter_t *iter;
10034         char *type, *fmri;
10035         int ret;
10036         struct pg_elts pgelts;
10037         xmlNodePtr n;
10038         scf_error_t serr;
10039 
10040         if ((opg = scf_pg_create(g_hndl)) == NULL ||
10041             (iter = scf_iter_create(g_hndl)) == NULL)
10042                 scfdie();
10043 
10044         /* Can't use exp_prop_iter due to export_dependent(). */
10045         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10046                 scfdie();
10047 
10048         type = safe_malloc(max_scf_pg_type_len + 1);
10049 
10050         /* Get an extra byte so we can tell if values are too long. */
10051         fmri = safe_malloc(max_scf_fmri_len + 2);
10052 
10053         (void) memset(&pgelts, 0, sizeof (pgelts));
10054 
10055         while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10056                 void *entity;
10057                 int isservice;
10058                 scf_type_t ty;
10059 
10060                 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10061                         scfdie();
10062 
10063                 if ((ty != SCF_TYPE_ASTRING &&
10064                     prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10065                     prop_get_val(exp_prop, exp_val) != 0) {
10066                         export_property(exp_prop, NULL, &pgelts,
10067                             SCE_ALL_VALUES);
10068                         continue;
10069                 }
10070 
10071                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10072                         scfdie();
10073 
10074                 if (scf_value_get_astring(exp_val, fmri,
10075                     max_scf_fmri_len + 2) < 0)
10076                         scfdie();
10077 
10078                 /* Look for a dependency group in the target fmri. */
10079                 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10080                 switch (serr) {
10081                 case SCF_ERROR_NONE:
10082                         break;
10083 
10084                 case SCF_ERROR_NO_MEMORY:
10085                         uu_die(gettext("Out of memory.\n"));
10086                         /* NOTREACHED */
10087 
10088                 case SCF_ERROR_INVALID_ARGUMENT:
10089                         if (g_verbose) {
10090                                 if (scf_property_to_fmri(exp_prop, fmri,
10091                                     max_scf_fmri_len + 2) < 0)
10092                                         scfdie();
10093 
10094                                 warn(gettext("The value of %s is not a valid "
10095                                     "FMRI.\n"), fmri);
10096                         }
10097 
10098                         export_property(exp_prop, exp_str, &pgelts,
10099                             SCE_ALL_VALUES);
10100                         continue;
10101 
10102                 case SCF_ERROR_CONSTRAINT_VIOLATED:
10103                         if (g_verbose) {
10104                                 if (scf_property_to_fmri(exp_prop, fmri,
10105                                     max_scf_fmri_len + 2) < 0)
10106                                         scfdie();
10107 
10108                                 warn(gettext("The value of %s does not specify "
10109                                     "a service or an instance.\n"), fmri);
10110                         }
10111 
10112                         export_property(exp_prop, exp_str, &pgelts,
10113                             SCE_ALL_VALUES);
10114                         continue;
10115 
10116                 case SCF_ERROR_NOT_FOUND:
10117                         if (g_verbose) {
10118                                 if (scf_property_to_fmri(exp_prop, fmri,
10119                                     max_scf_fmri_len + 2) < 0)
10120                                         scfdie();
10121 
10122                                 warn(gettext("The entity specified by %s does "
10123                                     "not exist.\n"), fmri);
10124                         }
10125 
10126                         export_property(exp_prop, exp_str, &pgelts,
10127                             SCE_ALL_VALUES);
10128                         continue;
10129 
10130                 default:
10131 #ifndef NDEBUG
10132                         (void) fprintf(stderr, "%s:%d: %s() failed with "
10133                             "unexpected error %d.\n", __FILE__, __LINE__,
10134                             "fmri_to_entity", serr);
10135 #endif
10136                         abort();
10137                 }
10138 
10139                 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10140                         if (scf_error() != SCF_ERROR_NOT_FOUND)
10141                                 scfdie();
10142 
10143                         warn(gettext("Entity %s is missing dependency property "
10144                             "group %s.\n"), fmri, exp_str);
10145 
10146                         export_property(exp_prop, NULL, &pgelts,
10147                             SCE_ALL_VALUES);
10148                         continue;
10149                 }
10150 
10151                 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10152                         scfdie();
10153 
10154                 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10155                         if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10156                                 scfdie();
10157 
10158                         warn(gettext("Property group %s is not of "
10159                             "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10160 
10161                         export_property(exp_prop, NULL, &pgelts,
10162                             SCE_ALL_VALUES);
10163                         continue;
10164                 }
10165 
10166                 n = export_dependent(opg, exp_str, fmri);
10167                 if (n == NULL) {
10168                         export_property(exp_prop, exp_str, &pgelts,
10169                             SCE_ALL_VALUES);
10170                 } else {
10171                         if (eelts->dependents == NULL)
10172                                 eelts->dependents = n;
10173                         else
10174                                 (void) xmlAddSibling(eelts->dependents,
10175                                     n);
10176                 }
10177         }
10178         if (ret == -1)
10179                 scfdie();
10180 
10181         free(fmri);
10182         free(type);
10183 
10184         scf_iter_destroy(iter);
10185         scf_pg_destroy(opg);
10186 
10187         if (pgelts.propvals != NULL || pgelts.properties != NULL)
10188                 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10189                     eelts);
10190 }
10191 
10192 static void
10193 make_node(xmlNodePtr *nodep, const char *name)
10194 {
10195         if (*nodep == NULL) {
10196                 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10197                 if (*nodep == NULL)
10198                         uu_die(emsg_create_xml);
10199         }
10200 }
10201 
10202 static xmlNodePtr
10203 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10204 {
10205         int ret;
10206         xmlNodePtr parent = NULL;
10207         xmlNodePtr loctext = NULL;
10208 
10209         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10210                 scfdie();
10211 
10212         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10213                 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10214                     prop_get_val(exp_prop, exp_val) != 0)
10215                         continue;
10216 
10217                 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10218                         scfdie();
10219 
10220                 make_node(&parent, parname);
10221                 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10222                     (xmlChar *)exp_str);
10223                 if (loctext == NULL)
10224                         uu_die(emsg_create_xml);
10225 
10226                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10227                         scfdie();
10228 
10229                 safe_setprop(loctext, "xml:lang", exp_str);
10230         }
10231 
10232         if (ret == -1)
10233                 scfdie();
10234 
10235         return (parent);
10236 }
10237 
10238 static xmlNodePtr
10239 export_tm_manpage(scf_propertygroup_t *pg)
10240 {
10241         xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10242         if (manpage == NULL)
10243                 uu_die(emsg_create_xml);
10244 
10245         if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10246             set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10247             pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10248             set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10249                 xmlFreeNode(manpage);
10250                 return (NULL);
10251         }
10252 
10253         if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10254                 (void) set_attr_from_prop_default(exp_prop,
10255                     manpage, "manpath", ":default");
10256 
10257         return (manpage);
10258 }
10259 
10260 static xmlNodePtr
10261 export_tm_doc_link(scf_propertygroup_t *pg)
10262 {
10263         xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10264         if (doc_link == NULL)
10265                 uu_die(emsg_create_xml);
10266 
10267         if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10268             set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10269             pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10270             set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10271                 xmlFreeNode(doc_link);
10272                 return (NULL);
10273         }
10274         return (doc_link);
10275 }
10276 
10277 /*
10278  * Process template information for a service or instances.
10279  */
10280 static void
10281 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10282     struct template_elts *telts)
10283 {
10284         size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10285         size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10286         xmlNodePtr child = NULL;
10287 
10288         if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10289                 scfdie();
10290 
10291         if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10292                 telts->common_name = export_tm_loctext(pg, "common_name");
10293                 if (telts->common_name == NULL)
10294                         export_pg(pg, elts, SCE_ALL_VALUES);
10295                 return;
10296         } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10297                 telts->description = export_tm_loctext(pg, "description");
10298                 if (telts->description == NULL)
10299                         export_pg(pg, elts, SCE_ALL_VALUES);
10300                 return;
10301         }
10302 
10303         if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10304                 child = export_tm_manpage(pg);
10305         } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10306                 child = export_tm_doc_link(pg);
10307         }
10308 
10309         if (child != NULL) {
10310                 make_node(&telts->documentation, "documentation");
10311                 (void) xmlAddChild(telts->documentation, child);
10312         } else {
10313                 export_pg(pg, elts, SCE_ALL_VALUES);
10314         }
10315 }
10316 
10317 /*
10318  * Process parameter and paramval elements
10319  */
10320 static void
10321 export_parameter(scf_property_t *prop, const char *name,
10322     struct params_elts *elts)
10323 {
10324         xmlNodePtr param;
10325         scf_error_t err = 0;
10326         int ret;
10327 
10328         if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10329                 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10330                         uu_die(emsg_create_xml);
10331 
10332                 safe_setprop(param, name_attr, name);
10333 
10334                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10335                         scfdie();
10336                 safe_setprop(param, value_attr, exp_str);
10337 
10338                 if (elts->paramval == NULL)
10339                         elts->paramval = param;
10340                 else
10341                         (void) xmlAddSibling(elts->paramval, param);
10342 
10343                 return;
10344         }
10345 
10346         err = scf_error();
10347 
10348         if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10349             err != SCF_ERROR_NOT_FOUND)
10350                 scfdie();
10351 
10352         if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10353                 uu_die(emsg_create_xml);
10354 
10355         safe_setprop(param, name_attr, name);
10356 
10357         if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10358                 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10359                         scfdie();
10360 
10361                 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10362                     1) {
10363                         xmlNodePtr vn;
10364 
10365                         if ((vn = xmlNewChild(param, NULL,
10366                             (xmlChar *)"value_node", NULL)) == NULL)
10367                                 uu_die(emsg_create_xml);
10368 
10369                         if (scf_value_get_as_string(exp_val, exp_str,
10370                             exp_str_sz) < 0)
10371                                 scfdie();
10372 
10373                         safe_setprop(vn, value_attr, exp_str);
10374                 }
10375                 if (ret != 0)
10376                         scfdie();
10377         }
10378 
10379         if (elts->parameter == NULL)
10380                 elts->parameter = param;
10381         else
10382                 (void) xmlAddSibling(elts->parameter, param);
10383 }
10384 
10385 /*
10386  * Process notification parameters for a service or instance
10387  */
10388 static void
10389 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10390 {
10391         xmlNodePtr n, event, *type;
10392         struct params_elts *eelts;
10393         int ret, err, i;
10394         char *s;
10395 
10396         n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10397         event = xmlNewNode(NULL, (xmlChar *)"event");
10398         if (n == NULL || event == NULL)
10399                 uu_die(emsg_create_xml);
10400 
10401         /* event value */
10402         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10403                 scfdie();
10404         /* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10405         if ((s = strchr(exp_str, ',')) != NULL)
10406                 *s = '\0';
10407         safe_setprop(event, value_attr, exp_str);
10408 
10409         (void) xmlAddChild(n, event);
10410 
10411         if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10412             (eelts = calloc(URI_SCHEME_NUM,
10413             sizeof (struct params_elts))) == NULL)
10414                 uu_die(gettext("Out of memory.\n"));
10415 
10416         err = 0;
10417 
10418         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10419                 scfdie();
10420 
10421         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10422                 char *t, *p;
10423 
10424                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10425                         scfdie();
10426 
10427                 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10428                         /*
10429                          * this is not a well formed notification parameters
10430                          * element, we should export as regular pg
10431                          */
10432                         err = 1;
10433                         break;
10434                 }
10435 
10436                 if ((i = check_uri_protocol(t)) < 0) {
10437                         err = 1;
10438                         break;
10439                 }
10440 
10441                 if (type[i] == NULL) {
10442                         if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10443                             NULL)
10444                                 uu_die(emsg_create_xml);
10445 
10446                         safe_setprop(type[i], name_attr, t);
10447                 }
10448                 if (strcmp(p, active_attr) == 0) {
10449                         if (set_attr_from_prop(exp_prop, type[i],
10450                             active_attr) != 0) {
10451                                 err = 1;
10452                                 break;
10453                         }
10454                         continue;
10455                 }
10456                 /*
10457                  * We export the parameter
10458                  */
10459                 export_parameter(exp_prop, p, &eelts[i]);
10460         }
10461 
10462         if (ret == -1)
10463                 scfdie();
10464 
10465         if (err == 1) {
10466                 for (i = 0; i < URI_SCHEME_NUM; ++i)
10467                         xmlFree(type[i]);
10468                 free(type);
10469 
10470                 export_pg(pg, elts, SCE_ALL_VALUES);
10471 
10472                 return;
10473         } else {
10474                 for (i = 0; i < URI_SCHEME_NUM; ++i)
10475                         if (type[i] != NULL) {
10476                                 (void) xmlAddChildList(type[i],
10477                                     eelts[i].paramval);
10478                                 (void) xmlAddChildList(type[i],
10479                                     eelts[i].parameter);
10480                                 (void) xmlAddSibling(event, type[i]);
10481                         }
10482         }
10483         free(type);
10484 
10485         if (elts->notify_params == NULL)
10486                 elts->notify_params = n;
10487         else
10488                 (void) xmlAddSibling(elts->notify_params, n);
10489 }
10490 
10491 /*
10492  * Process the general property group for an instance.
10493  */
10494 static void
10495 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10496     struct entity_elts *elts)
10497 {
10498         uint8_t enabled;
10499         struct pg_elts pgelts;
10500         int ret;
10501 
10502         /* enabled */
10503         if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10504             prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10505             prop_get_val(exp_prop, exp_val) == 0) {
10506                 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10507                         scfdie();
10508         } else {
10509                 enabled = 0;
10510         }
10511 
10512         safe_setprop(inode, enabled_attr, enabled ? true : false);
10513 
10514         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10515                 scfdie();
10516 
10517         (void) memset(&pgelts, 0, sizeof (pgelts));
10518 
10519         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10520                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10521                         scfdie();
10522 
10523                 if (strcmp(exp_str, scf_property_enabled) == 0) {
10524                         continue;
10525                 } else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) {
10526                         continue;
10527                 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10528                         xmlNodePtr rnode, sfnode;
10529 
10530                         rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10531                         if (rnode == NULL)
10532                                 uu_die(emsg_create_xml);
10533 
10534                         sfnode = xmlNewChild(rnode, NULL,
10535                             (xmlChar *)"service_fmri", NULL);
10536                         if (sfnode == NULL)
10537                                 uu_die(emsg_create_xml);
10538 
10539                         if (set_attr_from_prop(exp_prop, sfnode,
10540                             value_attr) == 0) {
10541                                 elts->restarter = rnode;
10542                                 continue;
10543                         }
10544 
10545                         xmlFreeNode(rnode);
10546                 }
10547 
10548                 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10549         }
10550         if (ret == -1)
10551                 scfdie();
10552 
10553         if (pgelts.propvals != NULL || pgelts.properties != NULL)
10554                 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10555                     elts);
10556 }
10557 
10558 /*
10559  * Put an instance element for the given instance into selts.
10560  */
10561 static void
10562 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10563 {
10564         xmlNodePtr n;
10565         boolean_t isdefault;
10566         struct entity_elts elts;
10567         struct template_elts template_elts;
10568         int ret;
10569 
10570         n = xmlNewNode(NULL, (xmlChar *)"instance");
10571         if (n == NULL)
10572                 uu_die(emsg_create_xml);
10573 
10574         /* name */
10575         if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10576                 scfdie();
10577         safe_setprop(n, name_attr, exp_str);
10578         isdefault = strcmp(exp_str, "default") == 0;
10579 
10580         /* check existance of general pg (since general/enabled is required) */
10581         if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10582                 if (scf_error() != SCF_ERROR_NOT_FOUND)
10583                         scfdie();
10584 
10585                 if (g_verbose) {
10586                         if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10587                                 scfdie();
10588 
10589                         warn(gettext("Instance %s has no general property "
10590                             "group; it will be marked disabled.\n"), exp_str);
10591                 }
10592 
10593                 safe_setprop(n, enabled_attr, false);
10594         } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10595             strcmp(exp_str, scf_group_framework) != 0) {
10596                 if (g_verbose) {
10597                         if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10598                                 scfdie();
10599 
10600                         warn(gettext("Property group %s is not of type "
10601                             "framework; the instance will be marked "
10602                             "disabled.\n"), exp_str);
10603                 }
10604 
10605                 safe_setprop(n, enabled_attr, false);
10606         }
10607 
10608         /* property groups */
10609         if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10610                 scfdie();
10611 
10612         (void) memset(&elts, 0, sizeof (elts));
10613         (void) memset(&template_elts, 0, sizeof (template_elts));
10614 
10615         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10616                 uint32_t pgflags;
10617 
10618                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10619                         scfdie();
10620 
10621                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10622                         continue;
10623 
10624                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10625                         scfdie();
10626 
10627                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10628                         export_dependency(exp_pg, &elts);
10629                         continue;
10630                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10631                         export_method(exp_pg, &elts);
10632                         continue;
10633                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10634                         if (scf_pg_get_name(exp_pg, exp_str,
10635                             max_scf_name_len + 1) < 0)
10636                                 scfdie();
10637 
10638                         if (strcmp(exp_str, scf_pg_general) == 0) {
10639                                 export_inst_general(exp_pg, n, &elts);
10640                                 continue;
10641                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10642                             0) {
10643                                 export_method_context(exp_pg, &elts);
10644                                 continue;
10645                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10646                                 export_dependents(exp_pg, &elts);
10647                                 continue;
10648                         }
10649                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10650                         export_template(exp_pg, &elts, &template_elts);
10651                         continue;
10652                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10653                         export_notify_params(exp_pg, &elts);
10654                         continue;
10655                 }
10656 
10657                 /* Ordinary pg. */
10658                 export_pg(exp_pg, &elts, flags);
10659         }
10660         if (ret == -1)
10661                 scfdie();
10662 
10663         if (template_elts.common_name != NULL) {
10664                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10665                 (void) xmlAddChild(elts.template, template_elts.common_name);
10666                 (void) xmlAddChild(elts.template, template_elts.description);
10667                 (void) xmlAddChild(elts.template, template_elts.documentation);
10668         } else {
10669                 xmlFreeNode(template_elts.description);
10670                 xmlFreeNode(template_elts.documentation);
10671         }
10672 
10673         if (isdefault && elts.restarter == NULL &&
10674             elts.dependencies == NULL && elts.method_context == NULL &&
10675             elts.exec_methods == NULL && elts.notify_params == NULL &&
10676             elts.property_groups == NULL && elts.template == NULL) {
10677                 xmlChar *eval;
10678 
10679                 /* This is a default instance */
10680                 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10681 
10682                 xmlFreeNode(n);
10683 
10684                 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10685                 if (n == NULL)
10686                         uu_die(emsg_create_xml);
10687 
10688                 safe_setprop(n, enabled_attr, (char *)eval);
10689                 xmlFree(eval);
10690 
10691                 selts->create_default_instance = n;
10692         } else {
10693                 /* Assemble the children in order. */
10694                 (void) xmlAddChild(n, elts.restarter);
10695                 (void) xmlAddChildList(n, elts.dependencies);
10696                 (void) xmlAddChildList(n, elts.dependents);
10697                 (void) xmlAddChild(n, elts.method_context);
10698                 (void) xmlAddChildList(n, elts.exec_methods);
10699                 (void) xmlAddChildList(n, elts.notify_params);
10700                 (void) xmlAddChildList(n, elts.property_groups);
10701                 (void) xmlAddChild(n, elts.template);
10702 
10703                 if (selts->instances == NULL)
10704                         selts->instances = n;
10705                 else
10706                         (void) xmlAddSibling(selts->instances, n);
10707         }
10708 }
10709 
10710 /*
10711  * Return a service element for the given service.
10712  */
10713 static xmlNodePtr
10714 export_service(scf_service_t *svc, int flags)
10715 {
10716         xmlNodePtr snode;
10717         struct entity_elts elts;
10718         struct template_elts template_elts;
10719         int ret;
10720 
10721         snode = xmlNewNode(NULL, (xmlChar *)"service");
10722         if (snode == NULL)
10723                 uu_die(emsg_create_xml);
10724 
10725         /* Get & set name attribute */
10726         if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10727                 scfdie();
10728         safe_setprop(snode, name_attr, exp_str);
10729 
10730         safe_setprop(snode, type_attr, "service");
10731         safe_setprop(snode, "version", "0");
10732 
10733         /* Acquire child elements. */
10734         if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10735                 scfdie();
10736 
10737         (void) memset(&elts, 0, sizeof (elts));
10738         (void) memset(&template_elts, 0, sizeof (template_elts));
10739 
10740         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10741                 uint32_t pgflags;
10742 
10743                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10744                         scfdie();
10745 
10746                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10747                         continue;
10748 
10749                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10750                         scfdie();
10751 
10752                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10753                         export_dependency(exp_pg, &elts);
10754                         continue;
10755                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10756                         export_method(exp_pg, &elts);
10757                         continue;
10758                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10759                         if (scf_pg_get_name(exp_pg, exp_str,
10760                             max_scf_name_len + 1) < 0)
10761                                 scfdie();
10762 
10763                         if (strcmp(exp_str, scf_pg_general) == 0) {
10764                                 export_svc_general(exp_pg, &elts);
10765                                 continue;
10766                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10767                             0) {
10768                                 export_method_context(exp_pg, &elts);
10769                                 continue;
10770                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10771                                 export_dependents(exp_pg, &elts);
10772                                 continue;
10773                         } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10774                                 continue;
10775                         }
10776                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10777                         export_template(exp_pg, &elts, &template_elts);
10778                         continue;
10779                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10780                         export_notify_params(exp_pg, &elts);
10781                         continue;
10782                 }
10783 
10784                 export_pg(exp_pg, &elts, flags);
10785         }
10786         if (ret == -1)
10787                 scfdie();
10788 
10789         if (template_elts.common_name != NULL) {
10790                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10791                 (void) xmlAddChild(elts.template, template_elts.common_name);
10792                 (void) xmlAddChild(elts.template, template_elts.description);
10793                 (void) xmlAddChild(elts.template, template_elts.documentation);
10794         } else {
10795                 xmlFreeNode(template_elts.description);
10796                 xmlFreeNode(template_elts.documentation);
10797         }
10798 
10799         /* Iterate instances */
10800         if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10801                 scfdie();
10802 
10803         while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10804                 export_instance(exp_inst, &elts, flags);
10805         if (ret == -1)
10806                 scfdie();
10807 
10808         /* Now add all of the accumulated elements in order. */
10809         (void) xmlAddChild(snode, elts.create_default_instance);
10810         (void) xmlAddChild(snode, elts.single_instance);
10811         (void) xmlAddChild(snode, elts.restarter);
10812         (void) xmlAddChildList(snode, elts.dependencies);
10813         (void) xmlAddChildList(snode, elts.dependents);
10814         (void) xmlAddChild(snode, elts.method_context);
10815         (void) xmlAddChildList(snode, elts.exec_methods);
10816         (void) xmlAddChildList(snode, elts.notify_params);
10817         (void) xmlAddChildList(snode, elts.property_groups);
10818         (void) xmlAddChildList(snode, elts.instances);
10819         (void) xmlAddChild(snode, elts.stability);
10820         (void) xmlAddChild(snode, elts.template);
10821 
10822         return (snode);
10823 }
10824 
10825 static int
10826 export_callback(void *data, scf_walkinfo_t *wip)
10827 {
10828         FILE *f;
10829         xmlDocPtr doc;
10830         xmlNodePtr sb;
10831         int result;
10832         struct export_args *argsp = (struct export_args *)data;
10833 
10834         if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10835             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10836             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10837             (exp_val = scf_value_create(g_hndl)) == NULL ||
10838             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10839             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10840             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10841             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10842                 scfdie();
10843 
10844         exp_str_sz = max_scf_len + 1;
10845         exp_str = safe_malloc(exp_str_sz);
10846 
10847         if (argsp->filename != NULL) {
10848                 errno = 0;
10849                 f = fopen(argsp->filename, "wb");
10850                 if (f == NULL) {
10851                         if (errno == 0)
10852                                 uu_die(gettext("Could not open \"%s\": no free "
10853                                     "stdio streams.\n"), argsp->filename);
10854                         else
10855                                 uu_die(gettext("Could not open \"%s\""),
10856                                     argsp->filename);
10857                 }
10858         } else
10859                 f = stdout;
10860 
10861         doc = xmlNewDoc((xmlChar *)"1.0");
10862         if (doc == NULL)
10863                 uu_die(gettext("Could not create XML document.\n"));
10864 
10865         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10866             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10867                 uu_die(emsg_create_xml);
10868 
10869         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10870         if (sb == NULL)
10871                 uu_die(emsg_create_xml);
10872         safe_setprop(sb, type_attr, "manifest");
10873         safe_setprop(sb, name_attr, "export");
10874         (void) xmlAddSibling(doc->children, sb);
10875 
10876         (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10877 
10878         result = write_service_bundle(doc, f);
10879 
10880         free(exp_str);
10881         scf_iter_destroy(exp_val_iter);
10882         scf_iter_destroy(exp_prop_iter);
10883         scf_iter_destroy(exp_pg_iter);
10884         scf_iter_destroy(exp_inst_iter);
10885         scf_value_destroy(exp_val);
10886         scf_property_destroy(exp_prop);
10887         scf_pg_destroy(exp_pg);
10888         scf_instance_destroy(exp_inst);
10889 
10890         xmlFreeDoc(doc);
10891 
10892         if (f != stdout)
10893                 (void) fclose(f);
10894 
10895         return (result);
10896 }
10897 
10898 /*
10899  * Get the service named by fmri, build an XML tree which represents it, and
10900  * dump it into filename (or stdout if filename is NULL).
10901  */
10902 int
10903 lscf_service_export(char *fmri, const char *filename, int flags)
10904 {
10905         struct export_args args;
10906         char *fmridup;
10907         const char *scope, *svc, *inst;
10908         size_t cblen = 3 * max_scf_name_len;
10909         char *canonbuf = alloca(cblen);
10910         int ret, err;
10911 
10912         lscf_prep_hndl();
10913 
10914         bzero(&args, sizeof (args));
10915         args.filename = filename;
10916         args.flags = flags;
10917 
10918         /*
10919          * If some poor user has passed an exact instance FMRI, of the sort
10920          * one might cut and paste from svcs(1) or an error message, warn
10921          * and chop off the instance instead of failing.
10922          */
10923         fmridup = alloca(strlen(fmri) + 1);
10924         (void) strcpy(fmridup, fmri);
10925         if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10926             sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10927             scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10928             inst != NULL) {
10929                 (void) strlcpy(canonbuf, "svc:/", cblen);
10930                 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10931                         (void) strlcat(canonbuf, "/", cblen);
10932                         (void) strlcat(canonbuf, scope, cblen);
10933                 }
10934                 (void) strlcat(canonbuf, svc, cblen);
10935                 fmri = canonbuf;
10936 
10937                 warn(gettext("Only services may be exported; ignoring "
10938                     "instance portion of argument.\n"));
10939         }
10940 
10941         err = 0;
10942         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10943             SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10944             &args, &err, semerr)) != 0) {
10945                 if (ret != -1)
10946                         semerr(gettext("Failed to walk instances: %s\n"),
10947                             scf_strerror(ret));
10948                 return (-1);
10949         }
10950 
10951         /*
10952          * Error message has already been printed.
10953          */
10954         if (err != 0)
10955                 return (-1);
10956 
10957         return (0);
10958 }
10959 
10960 
10961 /*
10962  * Archive
10963  */
10964 
10965 static xmlNodePtr
10966 make_archive(int flags)
10967 {
10968         xmlNodePtr sb;
10969         scf_scope_t *scope;
10970         scf_service_t *svc;
10971         scf_iter_t *iter;
10972         int r;
10973 
10974         if ((scope = scf_scope_create(g_hndl)) == NULL ||
10975             (svc = scf_service_create(g_hndl)) == NULL ||
10976             (iter = scf_iter_create(g_hndl)) == NULL ||
10977             (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10978             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10979             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10980             (exp_val = scf_value_create(g_hndl)) == NULL ||
10981             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10982             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10983             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10984             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10985                 scfdie();
10986 
10987         exp_str_sz = max_scf_len + 1;
10988         exp_str = safe_malloc(exp_str_sz);
10989 
10990         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10991         if (sb == NULL)
10992                 uu_die(emsg_create_xml);
10993         safe_setprop(sb, type_attr, "archive");
10994         safe_setprop(sb, name_attr, "none");
10995 
10996         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10997                 scfdie();
10998         if (scf_iter_scope_services(iter, scope) != 0)
10999                 scfdie();
11000 
11001         for (;;) {
11002                 r = scf_iter_next_service(iter, svc);
11003                 if (r == 0)
11004                         break;
11005                 if (r != 1)
11006                         scfdie();
11007 
11008                 if (scf_service_get_name(svc, exp_str,
11009                     max_scf_name_len + 1) < 0)
11010                         scfdie();
11011 
11012                 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11013                         continue;
11014 
11015                 (void) xmlAddChild(sb, export_service(svc, flags));
11016         }
11017 
11018         free(exp_str);
11019 
11020         scf_iter_destroy(exp_val_iter);
11021         scf_iter_destroy(exp_prop_iter);
11022         scf_iter_destroy(exp_pg_iter);
11023         scf_iter_destroy(exp_inst_iter);
11024         scf_value_destroy(exp_val);
11025         scf_property_destroy(exp_prop);
11026         scf_pg_destroy(exp_pg);
11027         scf_instance_destroy(exp_inst);
11028         scf_iter_destroy(iter);
11029         scf_service_destroy(svc);
11030         scf_scope_destroy(scope);
11031 
11032         return (sb);
11033 }
11034 
11035 int
11036 lscf_archive(const char *filename, int flags)
11037 {
11038         FILE *f;
11039         xmlDocPtr doc;
11040         int result;
11041 
11042         lscf_prep_hndl();
11043 
11044         if (filename != NULL) {
11045                 errno = 0;
11046                 f = fopen(filename, "wb");
11047                 if (f == NULL) {
11048                         if (errno == 0)
11049                                 uu_die(gettext("Could not open \"%s\": no free "
11050                                     "stdio streams.\n"), filename);
11051                         else
11052                                 uu_die(gettext("Could not open \"%s\""),
11053                                     filename);
11054                 }
11055         } else
11056                 f = stdout;
11057 
11058         doc = xmlNewDoc((xmlChar *)"1.0");
11059         if (doc == NULL)
11060                 uu_die(gettext("Could not create XML document.\n"));
11061 
11062         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11063             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11064                 uu_die(emsg_create_xml);
11065 
11066         (void) xmlAddSibling(doc->children, make_archive(flags));
11067 
11068         result = write_service_bundle(doc, f);
11069 
11070         xmlFreeDoc(doc);
11071 
11072         if (f != stdout)
11073                 (void) fclose(f);
11074 
11075         return (result);
11076 }
11077 
11078 
11079 /*
11080  * "Extract" a profile.
11081  */
11082 int
11083 lscf_profile_extract(const char *filename)
11084 {
11085         FILE *f;
11086         xmlDocPtr doc;
11087         xmlNodePtr sb, snode, inode;
11088         scf_scope_t *scope;
11089         scf_service_t *svc;
11090         scf_instance_t *inst;
11091         scf_propertygroup_t *pg;
11092         scf_property_t *prop;
11093         scf_value_t *val;
11094         scf_iter_t *siter, *iiter;
11095         int r, s;
11096         char *namebuf;
11097         uint8_t b;
11098         int result;
11099 
11100         lscf_prep_hndl();
11101 
11102         if (filename != NULL) {
11103                 errno = 0;
11104                 f = fopen(filename, "wb");
11105                 if (f == NULL) {
11106                         if (errno == 0)
11107                                 uu_die(gettext("Could not open \"%s\": no "
11108                                     "free stdio streams.\n"), filename);
11109                         else
11110                                 uu_die(gettext("Could not open \"%s\""),
11111                                     filename);
11112                 }
11113         } else
11114                 f = stdout;
11115 
11116         doc = xmlNewDoc((xmlChar *)"1.0");
11117         if (doc == NULL)
11118                 uu_die(gettext("Could not create XML document.\n"));
11119 
11120         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11121             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11122                 uu_die(emsg_create_xml);
11123 
11124         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11125         if (sb == NULL)
11126                 uu_die(emsg_create_xml);
11127         safe_setprop(sb, type_attr, "profile");
11128         safe_setprop(sb, name_attr, "extract");
11129         (void) xmlAddSibling(doc->children, sb);
11130 
11131         if ((scope = scf_scope_create(g_hndl)) == NULL ||
11132             (svc = scf_service_create(g_hndl)) == NULL ||
11133             (inst = scf_instance_create(g_hndl)) == NULL ||
11134             (pg = scf_pg_create(g_hndl)) == NULL ||
11135             (prop = scf_property_create(g_hndl)) == NULL ||
11136             (val = scf_value_create(g_hndl)) == NULL ||
11137             (siter = scf_iter_create(g_hndl)) == NULL ||
11138             (iiter = scf_iter_create(g_hndl)) == NULL)
11139                 scfdie();
11140 
11141         if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11142                 scfdie();
11143 
11144         if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11145                 scfdie();
11146 
11147         namebuf = safe_malloc(max_scf_name_len + 1);
11148 
11149         while ((r = scf_iter_next_service(siter, svc)) == 1) {
11150                 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11151                         scfdie();
11152 
11153                 snode = xmlNewNode(NULL, (xmlChar *)"service");
11154                 if (snode == NULL)
11155                         uu_die(emsg_create_xml);
11156 
11157                 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11158                     0)
11159                         scfdie();
11160 
11161                 safe_setprop(snode, name_attr, namebuf);
11162 
11163                 safe_setprop(snode, type_attr, "service");
11164                 safe_setprop(snode, "version", "0");
11165 
11166                 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11167                         if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11168                             SCF_SUCCESS) {
11169                                 if (scf_error() != SCF_ERROR_NOT_FOUND)
11170                                         scfdie();
11171 
11172                                 if (g_verbose) {
11173                                         ssize_t len;
11174                                         char *fmri;
11175 
11176                                         len =
11177                                             scf_instance_to_fmri(inst, NULL, 0);
11178                                         if (len < 0)
11179                                                 scfdie();
11180 
11181                                         fmri = safe_malloc(len + 1);
11182 
11183                                         if (scf_instance_to_fmri(inst, fmri,
11184                                             len + 1) < 0)
11185                                                 scfdie();
11186 
11187                                         warn("Instance %s has no \"%s\" "
11188                                             "property group.\n", fmri,
11189                                             scf_pg_general);
11190 
11191                                         free(fmri);
11192                                 }
11193 
11194                                 continue;
11195                         }
11196 
11197                         if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11198                             prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11199                             prop_get_val(prop, val) != 0)
11200                                 continue;
11201 
11202                         inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11203                             NULL);
11204                         if (inode == NULL)
11205                                 uu_die(emsg_create_xml);
11206 
11207                         if (scf_instance_get_name(inst, namebuf,
11208                             max_scf_name_len + 1) < 0)
11209                                 scfdie();
11210 
11211                         safe_setprop(inode, name_attr, namebuf);
11212 
11213                         if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11214                                 scfdie();
11215 
11216                         safe_setprop(inode, enabled_attr, b ? true : false);
11217                 }
11218                 if (s < 0)
11219                         scfdie();
11220 
11221                 if (snode->children != NULL)
11222                         (void) xmlAddChild(sb, snode);
11223                 else
11224                         xmlFreeNode(snode);
11225         }
11226         if (r < 0)
11227                 scfdie();
11228 
11229         free(namebuf);
11230 
11231         result = write_service_bundle(doc, f);
11232 
11233         xmlFreeDoc(doc);
11234 
11235         if (f != stdout)
11236                 (void) fclose(f);
11237 
11238         return (result);
11239 }
11240 
11241 
11242 /*
11243  * Entity manipulation commands
11244  */
11245 
11246 /*
11247  * Entity selection.  If no entity is selected, then the current scope is in
11248  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11249  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11250  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11251  * cur_inst will be non-NULL.
11252  */
11253 
11254 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11255 static int
11256 select_inst(const char *name)
11257 {
11258         scf_instance_t *inst;
11259         scf_error_t err;
11260 
11261         assert(cur_svc != NULL);
11262 
11263         inst = scf_instance_create(g_hndl);
11264         if (inst == NULL)
11265                 scfdie();
11266 
11267         if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11268                 cur_inst = inst;
11269                 return (0);
11270         }
11271 
11272         err = scf_error();
11273         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11274                 scfdie();
11275 
11276         scf_instance_destroy(inst);
11277         return (1);
11278 }
11279 
11280 /* Returns as above. */
11281 static int
11282 select_svc(const char *name)
11283 {
11284         scf_service_t *svc;
11285         scf_error_t err;
11286 
11287         assert(cur_scope != NULL);
11288 
11289         svc = scf_service_create(g_hndl);
11290         if (svc == NULL)
11291                 scfdie();
11292 
11293         if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11294                 cur_svc = svc;
11295                 return (0);
11296         }
11297 
11298         err = scf_error();
11299         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11300                 scfdie();
11301 
11302         scf_service_destroy(svc);
11303         return (1);
11304 }
11305 
11306 /* ARGSUSED */
11307 static int
11308 select_callback(void *unused, scf_walkinfo_t *wip)
11309 {
11310         scf_instance_t *inst;
11311         scf_service_t *svc;
11312         scf_scope_t *scope;
11313 
11314         if (wip->inst != NULL) {
11315                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11316                     (svc = scf_service_create(g_hndl)) == NULL ||
11317                     (inst = scf_instance_create(g_hndl)) == NULL)
11318                         scfdie();
11319 
11320                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11321                     inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11322                         scfdie();
11323         } else {
11324                 assert(wip->svc != NULL);
11325 
11326                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11327                     (svc = scf_service_create(g_hndl)) == NULL)
11328                         scfdie();
11329 
11330                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11331                     NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11332                         scfdie();
11333 
11334                 inst = NULL;
11335         }
11336 
11337         /* Clear out the current selection */
11338         assert(cur_scope != NULL);
11339         scf_scope_destroy(cur_scope);
11340         scf_service_destroy(cur_svc);
11341         scf_instance_destroy(cur_inst);
11342 
11343         cur_scope = scope;
11344         cur_svc = svc;
11345         cur_inst = inst;
11346 
11347         return (0);
11348 }
11349 
11350 static int
11351 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11352 {
11353         char **fmri = fmri_p;
11354 
11355         *fmri = strdup(wip->fmri);
11356         if (*fmri == NULL)
11357                 uu_die(gettext("Out of memory.\n"));
11358 
11359         return (0);
11360 }
11361 
11362 /*
11363  * validate [fmri]
11364  * Perform the validation of an FMRI instance.
11365  */
11366 void
11367 lscf_validate_fmri(const char *fmri)
11368 {
11369         int ret = 0;
11370         size_t inst_sz;
11371         char *inst_fmri = NULL;
11372         scf_tmpl_errors_t *errs = NULL;
11373         char *snapbuf = NULL;
11374 
11375         lscf_prep_hndl();
11376 
11377         if (fmri == NULL) {
11378                 inst_sz = max_scf_fmri_len + 1;
11379                 inst_fmri = safe_malloc(inst_sz);
11380 
11381                 if (cur_snap != NULL) {
11382                         snapbuf = safe_malloc(max_scf_name_len + 1);
11383                         if (scf_snapshot_get_name(cur_snap, snapbuf,
11384                             max_scf_name_len + 1) < 0)
11385                                 scfdie();
11386                 }
11387                 if (cur_inst == NULL) {
11388                         semerr(gettext("No instance selected\n"));
11389                         goto cleanup;
11390                 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11391                     inst_sz) >= inst_sz) {
11392                         /* sanity check. Should never get here */
11393                         uu_die(gettext("Unexpected error! file %s, line %d\n"),
11394                             __FILE__, __LINE__);
11395                 }
11396         } else {
11397                 scf_error_t scf_err;
11398                 int err = 0;
11399 
11400                 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11401                     validate_callback, &inst_fmri, &err, semerr)) != 0) {
11402                         uu_warn("Failed to walk instances: %s\n",
11403                             scf_strerror(scf_err));
11404                         goto cleanup;
11405                 }
11406                 if (err != 0) {
11407                         /* error message displayed by scf_walk_fmri */
11408                         goto cleanup;
11409                 }
11410         }
11411 
11412         ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11413             SCF_TMPL_VALIDATE_FLAG_CURRENT);
11414         if (ret == -1) {
11415                 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11416                         warn(gettext("Template data for %s is invalid. "
11417                             "Consider reverting to a previous snapshot or "
11418                             "restoring original configuration.\n"), inst_fmri);
11419                 } else {
11420                         uu_warn("%s: %s\n",
11421                             gettext("Error validating the instance"),
11422                             scf_strerror(scf_error()));
11423                 }
11424         } else if (ret == 1 && errs != NULL) {
11425                 scf_tmpl_error_t *err = NULL;
11426                 char *msg;
11427                 size_t len = 256;       /* initial error buffer size */
11428                 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11429                     SCF_TMPL_STRERROR_HUMAN : 0;
11430 
11431                 msg = safe_malloc(len);
11432 
11433                 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11434                         int ret;
11435 
11436                         if ((ret = scf_tmpl_strerror(err, msg, len,
11437                             flag)) >= len) {
11438                                 len = ret + 1;
11439                                 msg = realloc(msg, len);
11440                                 if (msg == NULL)
11441                                         uu_die(gettext(
11442                                             "Out of memory.\n"));
11443                                 (void) scf_tmpl_strerror(err, msg, len,
11444                                     flag);
11445                         }
11446                         (void) fprintf(stderr, "%s\n", msg);
11447                 }
11448                 if (msg != NULL)
11449                         free(msg);
11450         }
11451         if (errs != NULL)
11452                 scf_tmpl_errors_destroy(errs);
11453 
11454 cleanup:
11455         free(inst_fmri);
11456         free(snapbuf);
11457 }
11458 
11459 static void
11460 lscf_validate_file(const char *filename)
11461 {
11462         tmpl_errors_t *errs;
11463 
11464         bundle_t *b = internal_bundle_new();
11465         if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11466                 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11467                         tmpl_errors_print(stderr, errs, "");
11468                         semerr(gettext("Validation failed.\n"));
11469                 }
11470                 tmpl_errors_destroy(errs);
11471         }
11472         (void) internal_bundle_free(b);
11473 }
11474 
11475 /*
11476  * validate [fmri|file]
11477  */
11478 void
11479 lscf_validate(const char *arg)
11480 {
11481         const char *str;
11482 
11483         if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11484             sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11485                 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11486                 lscf_validate_file(str);
11487         } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11488             sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11489                 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11490                 lscf_validate_fmri(str);
11491         } else if (access(arg, R_OK | F_OK) == 0) {
11492                 lscf_validate_file(arg);
11493         } else {
11494                 lscf_validate_fmri(arg);
11495         }
11496 }
11497 
11498 void
11499 lscf_select(const char *fmri)
11500 {
11501         int ret, err;
11502 
11503         lscf_prep_hndl();
11504 
11505         if (cur_snap != NULL) {
11506                 struct snaplevel *elt;
11507                 char *buf;
11508 
11509                 /* Error unless name is that of the next level. */
11510                 elt = uu_list_next(cur_levels, cur_elt);
11511                 if (elt == NULL) {
11512                         semerr(gettext("No children.\n"));
11513                         return;
11514                 }
11515 
11516                 buf = safe_malloc(max_scf_name_len + 1);
11517 
11518                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11519                     max_scf_name_len + 1) < 0)
11520                         scfdie();
11521 
11522                 if (strcmp(buf, fmri) != 0) {
11523                         semerr(gettext("No such child.\n"));
11524                         free(buf);
11525                         return;
11526                 }
11527 
11528                 free(buf);
11529 
11530                 cur_elt = elt;
11531                 cur_level = elt->sl;
11532                 return;
11533         }
11534 
11535         /*
11536          * Special case for 'svc:', which takes the user to the scope level.
11537          */
11538         if (strcmp(fmri, "svc:") == 0) {
11539                 scf_instance_destroy(cur_inst);
11540                 scf_service_destroy(cur_svc);
11541                 cur_inst = NULL;
11542                 cur_svc = NULL;
11543                 return;
11544         }
11545 
11546         /*
11547          * Special case for ':properties'.  This appears as part of 'list' but
11548          * can't be selected.  Give a more helpful error message in this case.
11549          */
11550         if (strcmp(fmri, ":properties") == 0) {
11551                 semerr(gettext(":properties is not an entity.  Try 'listprop' "
11552                     "to list properties.\n"));
11553                 return;
11554         }
11555 
11556         /*
11557          * First try the argument as relative to the current selection.
11558          */
11559         if (cur_inst != NULL) {
11560                 /* EMPTY */;
11561         } else if (cur_svc != NULL) {
11562                 if (select_inst(fmri) != 1)
11563                         return;
11564         } else {
11565                 if (select_svc(fmri) != 1)
11566                         return;
11567         }
11568 
11569         err = 0;
11570         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11571             select_callback, NULL, &err, semerr)) != 0) {
11572                 semerr(gettext("Failed to walk instances: %s\n"),
11573                     scf_strerror(ret));
11574         }
11575 }
11576 
11577 void
11578 lscf_unselect(void)
11579 {
11580         lscf_prep_hndl();
11581 
11582         if (cur_snap != NULL) {
11583                 struct snaplevel *elt;
11584 
11585                 elt = uu_list_prev(cur_levels, cur_elt);
11586                 if (elt == NULL) {
11587                         semerr(gettext("No parent levels.\n"));
11588                 } else {
11589                         cur_elt = elt;
11590                         cur_level = elt->sl;
11591                 }
11592         } else if (cur_inst != NULL) {
11593                 scf_instance_destroy(cur_inst);
11594                 cur_inst = NULL;
11595         } else if (cur_svc != NULL) {
11596                 scf_service_destroy(cur_svc);
11597                 cur_svc = NULL;
11598         } else {
11599                 semerr(gettext("Cannot unselect at scope level.\n"));
11600         }
11601 }
11602 
11603 /*
11604  * Return the FMRI of the current selection, for the prompt.
11605  */
11606 void
11607 lscf_get_selection_str(char *buf, size_t bufsz)
11608 {
11609         char *cp;
11610         ssize_t fmrilen, szret;
11611         boolean_t deleted = B_FALSE;
11612 
11613         if (g_hndl == NULL) {
11614                 (void) strlcpy(buf, "svc:", bufsz);
11615                 return;
11616         }
11617 
11618         if (cur_level != NULL) {
11619                 assert(cur_snap != NULL);
11620 
11621                 /* [ snapshot ] FMRI [: instance ] */
11622                 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11623                     + 2 + max_scf_name_len + 1 + 1);
11624 
11625                 buf[0] = '[';
11626 
11627                 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11628                     max_scf_name_len + 1);
11629                 if (szret < 0) {
11630                         if (scf_error() != SCF_ERROR_DELETED)
11631                                 scfdie();
11632 
11633                         goto snap_deleted;
11634                 }
11635 
11636                 (void) strcat(buf, "]svc:/");
11637 
11638                 cp = strchr(buf, '\0');
11639 
11640                 szret = scf_snaplevel_get_service_name(cur_level, cp,
11641                     max_scf_name_len + 1);
11642                 if (szret < 0) {
11643                         if (scf_error() != SCF_ERROR_DELETED)
11644                                 scfdie();
11645 
11646                         goto snap_deleted;
11647                 }
11648 
11649                 cp = strchr(cp, '\0');
11650 
11651                 if (snaplevel_is_instance(cur_level)) {
11652                         *cp++ = ':';
11653 
11654                         if (scf_snaplevel_get_instance_name(cur_level, cp,
11655                             max_scf_name_len + 1) < 0) {
11656                                 if (scf_error() != SCF_ERROR_DELETED)
11657                                         scfdie();
11658 
11659                                 goto snap_deleted;
11660                         }
11661                 } else {
11662                         *cp++ = '[';
11663                         *cp++ = ':';
11664 
11665                         if (scf_instance_get_name(cur_inst, cp,
11666                             max_scf_name_len + 1) < 0) {
11667                                 if (scf_error() != SCF_ERROR_DELETED)
11668                                         scfdie();
11669 
11670                                 goto snap_deleted;
11671                         }
11672 
11673                         (void) strcat(buf, "]");
11674                 }
11675 
11676                 return;
11677 
11678 snap_deleted:
11679                 deleted = B_TRUE;
11680                 free(buf);
11681                 unselect_cursnap();
11682         }
11683 
11684         assert(cur_snap == NULL);
11685 
11686         if (cur_inst != NULL) {
11687                 assert(cur_svc != NULL);
11688                 assert(cur_scope != NULL);
11689 
11690                 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11691                 if (fmrilen >= 0) {
11692                         assert(fmrilen < bufsz);
11693                         if (deleted)
11694                                 warn(emsg_deleted);
11695                         return;
11696                 }
11697 
11698                 if (scf_error() != SCF_ERROR_DELETED)
11699                         scfdie();
11700 
11701                 deleted = B_TRUE;
11702 
11703                 scf_instance_destroy(cur_inst);
11704                 cur_inst = NULL;
11705         }
11706 
11707         if (cur_svc != NULL) {
11708                 assert(cur_scope != NULL);
11709 
11710                 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11711                 if (szret >= 0) {
11712                         assert(szret < bufsz);
11713                         if (deleted)
11714                                 warn(emsg_deleted);
11715                         return;
11716                 }
11717 
11718                 if (scf_error() != SCF_ERROR_DELETED)
11719                         scfdie();
11720 
11721                 deleted = B_TRUE;
11722                 scf_service_destroy(cur_svc);
11723                 cur_svc = NULL;
11724         }
11725 
11726         assert(cur_scope != NULL);
11727         fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11728 
11729         if (fmrilen < 0)
11730                 scfdie();
11731 
11732         assert(fmrilen < bufsz);
11733         if (deleted)
11734                 warn(emsg_deleted);
11735 }
11736 
11737 /*
11738  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11739  * :statistics) are listed for the current selection.
11740  */
11741 void
11742 lscf_list(const char *pattern)
11743 {
11744         scf_iter_t *iter;
11745         char *buf;
11746         int ret;
11747 
11748         lscf_prep_hndl();
11749 
11750         if (cur_level != NULL) {
11751                 struct snaplevel *elt;
11752 
11753                 (void) fputs(COLON_NAMESPACES, stdout);
11754 
11755                 elt = uu_list_next(cur_levels, cur_elt);
11756                 if (elt == NULL)
11757                         return;
11758 
11759                 /*
11760                  * For now, we know that the next level is an instance.  But
11761                  * if we ever have multiple scopes, this could be complicated.
11762                  */
11763                 buf = safe_malloc(max_scf_name_len + 1);
11764                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11765                     max_scf_name_len + 1) >= 0) {
11766                         (void) puts(buf);
11767                 } else {
11768                         if (scf_error() != SCF_ERROR_DELETED)
11769                                 scfdie();
11770                 }
11771 
11772                 free(buf);
11773 
11774                 return;
11775         }
11776 
11777         if (cur_inst != NULL) {
11778                 (void) fputs(COLON_NAMESPACES, stdout);
11779                 return;
11780         }
11781 
11782         iter = scf_iter_create(g_hndl);
11783         if (iter == NULL)
11784                 scfdie();
11785 
11786         buf = safe_malloc(max_scf_name_len + 1);
11787 
11788         if (cur_svc != NULL) {
11789                 /* List the instances in this service. */
11790                 scf_instance_t *inst;
11791 
11792                 inst = scf_instance_create(g_hndl);
11793                 if (inst == NULL)
11794                         scfdie();
11795 
11796                 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11797                         safe_printf(COLON_NAMESPACES);
11798 
11799                         for (;;) {
11800                                 ret = scf_iter_next_instance(iter, inst);
11801                                 if (ret == 0)
11802                                         break;
11803                                 if (ret != 1) {
11804                                         if (scf_error() != SCF_ERROR_DELETED)
11805                                                 scfdie();
11806 
11807                                         break;
11808                                 }
11809 
11810                                 if (scf_instance_get_name(inst, buf,
11811                                     max_scf_name_len + 1) >= 0) {
11812                                         if (pattern == NULL ||
11813                                             fnmatch(pattern, buf, 0) == 0)
11814                                                 (void) puts(buf);
11815                                 } else {
11816                                         if (scf_error() != SCF_ERROR_DELETED)
11817                                                 scfdie();
11818                                 }
11819                         }
11820                 } else {
11821                         if (scf_error() != SCF_ERROR_DELETED)
11822                                 scfdie();
11823                 }
11824 
11825                 scf_instance_destroy(inst);
11826         } else {
11827                 /* List the services in this scope. */
11828                 scf_service_t *svc;
11829 
11830                 assert(cur_scope != NULL);
11831 
11832                 svc = scf_service_create(g_hndl);
11833                 if (svc == NULL)
11834                         scfdie();
11835 
11836                 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11837                         scfdie();
11838 
11839                 for (;;) {
11840                         ret = scf_iter_next_service(iter, svc);
11841                         if (ret == 0)
11842                                 break;
11843                         if (ret != 1)
11844                                 scfdie();
11845 
11846                         if (scf_service_get_name(svc, buf,
11847                             max_scf_name_len + 1) >= 0) {
11848                                 if (pattern == NULL ||
11849                                     fnmatch(pattern, buf, 0) == 0)
11850                                         safe_printf("%s\n", buf);
11851                         } else {
11852                                 if (scf_error() != SCF_ERROR_DELETED)
11853                                         scfdie();
11854                         }
11855                 }
11856 
11857                 scf_service_destroy(svc);
11858         }
11859 
11860         free(buf);
11861         scf_iter_destroy(iter);
11862 }
11863 
11864 /*
11865  * Entity addition.  Creates an empty entity in the current selection.
11866  */
11867 void
11868 lscf_add(const char *name)
11869 {
11870         lscf_prep_hndl();
11871 
11872         if (cur_snap != NULL) {
11873                 semerr(emsg_cant_modify_snapshots);
11874         } else if (cur_inst != NULL) {
11875                 semerr(gettext("Cannot add entities to an instance.\n"));
11876         } else if (cur_svc != NULL) {
11877 
11878                 if (scf_service_add_instance(cur_svc, name, NULL) !=
11879                     SCF_SUCCESS) {
11880                         switch (scf_error()) {
11881                         case SCF_ERROR_INVALID_ARGUMENT:
11882                                 semerr(gettext("Invalid name.\n"));
11883                                 break;
11884 
11885                         case SCF_ERROR_EXISTS:
11886                                 semerr(gettext("Instance already exists.\n"));
11887                                 break;
11888 
11889                         case SCF_ERROR_PERMISSION_DENIED:
11890                                 semerr(emsg_permission_denied);
11891                                 break;
11892 
11893                         default:
11894                                 scfdie();
11895                         }
11896                 }
11897         } else {
11898                 assert(cur_scope != NULL);
11899 
11900                 if (scf_scope_add_service(cur_scope, name, NULL) !=
11901                     SCF_SUCCESS) {
11902                         switch (scf_error()) {
11903                         case SCF_ERROR_INVALID_ARGUMENT:
11904                                 semerr(gettext("Invalid name.\n"));
11905                                 break;
11906 
11907                         case SCF_ERROR_EXISTS:
11908                                 semerr(gettext("Service already exists.\n"));
11909                                 break;
11910 
11911                         case SCF_ERROR_PERMISSION_DENIED:
11912                                 semerr(emsg_permission_denied);
11913                                 break;
11914 
11915                         case SCF_ERROR_BACKEND_READONLY:
11916                                 semerr(emsg_read_only);
11917                                 break;
11918 
11919                         default:
11920                                 scfdie();
11921                         }
11922                 }
11923         }
11924 }
11925 
11926 /* return 1 if the entity has no persistent pgs, else return 0 */
11927 static int
11928 entity_has_no_pgs(void *ent, int isservice)
11929 {
11930         scf_iter_t *iter = NULL;
11931         scf_propertygroup_t *pg = NULL;
11932         uint32_t flags;
11933         int err;
11934         int ret = 1;
11935 
11936         if ((iter = scf_iter_create(g_hndl)) == NULL ||
11937             (pg = scf_pg_create(g_hndl)) == NULL)
11938                 scfdie();
11939 
11940         if (isservice) {
11941                 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11942                         scfdie();
11943         } else {
11944                 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11945                         scfdie();
11946         }
11947 
11948         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11949                 if (scf_pg_get_flags(pg, &flags) != 0)
11950                         scfdie();
11951 
11952                 /* skip nonpersistent pgs */
11953                 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11954                         continue;
11955 
11956                 ret = 0;
11957                 break;
11958         }
11959 
11960         if (err == -1)
11961                 scfdie();
11962 
11963         scf_pg_destroy(pg);
11964         scf_iter_destroy(iter);
11965 
11966         return (ret);
11967 }
11968 
11969 /* return 1 if the service has no instances, else return 0 */
11970 static int
11971 svc_has_no_insts(scf_service_t *svc)
11972 {
11973         scf_instance_t *inst;
11974         scf_iter_t *iter;
11975         int r;
11976         int ret = 1;
11977 
11978         if ((inst = scf_instance_create(g_hndl)) == NULL ||
11979             (iter = scf_iter_create(g_hndl)) == NULL)
11980                 scfdie();
11981 
11982         if (scf_iter_service_instances(iter, svc) != 0)
11983                 scfdie();
11984 
11985         r = scf_iter_next_instance(iter, inst);
11986         if (r == 1) {
11987                 ret = 0;
11988         } else if (r == 0) {
11989                 ret = 1;
11990         } else if (r == -1) {
11991                 scfdie();
11992         } else {
11993                 bad_error("scf_iter_next_instance", r);
11994         }
11995 
11996         scf_iter_destroy(iter);
11997         scf_instance_destroy(inst);
11998 
11999         return (ret);
12000 }
12001 
12002 /*
12003  * Entity deletion.
12004  */
12005 
12006 /*
12007  * Delete the property group <fmri>/:properties/<name>.  Returns
12008  * SCF_ERROR_NONE on success (or if the entity is not found),
12009  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12010  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12011  * denied.
12012  */
12013 static scf_error_t
12014 delete_dependency_pg(const char *fmri, const char *name)
12015 {
12016         void *entity = NULL;
12017         int isservice;
12018         scf_propertygroup_t *pg = NULL;
12019         scf_error_t result;
12020         char *pgty;
12021         scf_service_t *svc = NULL;
12022         scf_instance_t *inst = NULL;
12023         scf_iter_t *iter = NULL;
12024         char *name_buf = NULL;
12025 
12026         result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12027         switch (result) {
12028         case SCF_ERROR_NONE:
12029                 break;
12030 
12031         case SCF_ERROR_NO_MEMORY:
12032                 uu_die(gettext("Out of memory.\n"));
12033                 /* NOTREACHED */
12034 
12035         case SCF_ERROR_INVALID_ARGUMENT:
12036         case SCF_ERROR_CONSTRAINT_VIOLATED:
12037                 return (SCF_ERROR_INVALID_ARGUMENT);
12038 
12039         case SCF_ERROR_NOT_FOUND:
12040                 result = SCF_ERROR_NONE;
12041                 goto out;
12042 
12043         default:
12044                 bad_error("fmri_to_entity", result);
12045         }
12046 
12047         pg = scf_pg_create(g_hndl);
12048         if (pg == NULL)
12049                 scfdie();
12050 
12051         if (entity_get_pg(entity, isservice, name, pg) != 0) {
12052                 if (scf_error() != SCF_ERROR_NOT_FOUND)
12053                         scfdie();
12054 
12055                 result = SCF_ERROR_NONE;
12056                 goto out;
12057         }
12058 
12059         pgty = safe_malloc(max_scf_pg_type_len + 1);
12060 
12061         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12062                 scfdie();
12063 
12064         if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12065                 result = SCF_ERROR_TYPE_MISMATCH;
12066                 free(pgty);
12067                 goto out;
12068         }
12069 
12070         free(pgty);
12071 
12072         if (scf_pg_delete(pg) != 0) {
12073                 result = scf_error();
12074                 if (result != SCF_ERROR_PERMISSION_DENIED)
12075                         scfdie();
12076                 goto out;
12077         }
12078 
12079         /*
12080          * We have to handle the case where we've just deleted the last
12081          * property group of a "dummy" entity (instance or service).
12082          * A "dummy" entity is an entity only present to hold an
12083          * external dependency.
12084          * So, in the case we deleted the last property group then we
12085          * can also delete the entity. If the entity is an instance then
12086          * we must verify if this was the last instance for the service
12087          * and if it is, we can also delete the service if it doesn't
12088          * have any property group either.
12089          */
12090 
12091         result = SCF_ERROR_NONE;
12092 
12093         if (isservice) {
12094                 svc = (scf_service_t *)entity;
12095 
12096                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12097                     (iter = scf_iter_create(g_hndl)) == NULL)
12098                         scfdie();
12099 
12100                 name_buf = safe_malloc(max_scf_name_len + 1);
12101         } else {
12102                 inst = (scf_instance_t *)entity;
12103         }
12104 
12105         /*
12106          * If the entity is an instance and we've just deleted its last
12107          * property group then we should delete it.
12108          */
12109         if (!isservice && entity_has_no_pgs(entity, isservice)) {
12110                 /* find the service before deleting the inst. - needed later */
12111                 if ((svc = scf_service_create(g_hndl)) == NULL)
12112                         scfdie();
12113 
12114                 if (scf_instance_get_parent(inst, svc) != 0)
12115                         scfdie();
12116 
12117                 /* delete the instance */
12118                 if (scf_instance_delete(inst) != 0) {
12119                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12120                                 scfdie();
12121 
12122                         result = SCF_ERROR_PERMISSION_DENIED;
12123                         goto out;
12124                 }
12125                 /* no need to refresh the instance */
12126                 inst = NULL;
12127         }
12128 
12129         /*
12130          * If the service has no more instances and pgs or we just deleted the
12131          * last instance and the service doesn't have anymore propery groups
12132          * then the service should be deleted.
12133          */
12134         if (svc != NULL &&
12135             svc_has_no_insts(svc) &&
12136             entity_has_no_pgs((void *)svc, 1)) {
12137                 if (scf_service_delete(svc) == 0) {
12138                         if (isservice) {
12139                                 /* no need to refresh the service */
12140                                 svc = NULL;
12141                         }
12142 
12143                         goto out;
12144                 }
12145 
12146                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12147                         scfdie();
12148 
12149                 result = SCF_ERROR_PERMISSION_DENIED;
12150         }
12151 
12152         /* if the entity has not been deleted, refresh it */
12153         if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12154                 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12155                     name_buf);
12156         }
12157 
12158 out:
12159         if (isservice && (inst != NULL && iter != NULL)) {
12160                 free(name_buf);
12161                 scf_iter_destroy(iter);
12162                 scf_instance_destroy(inst);
12163         }
12164 
12165         if (!isservice && svc != NULL) {
12166                 scf_service_destroy(svc);
12167         }
12168 
12169         scf_pg_destroy(pg);
12170         if (entity != NULL)
12171                 entity_destroy(entity, isservice);
12172 
12173         return (result);
12174 }
12175 
12176 static int
12177 delete_dependents(scf_propertygroup_t *pg)
12178 {
12179         char *pgty, *name, *fmri;
12180         scf_property_t *prop;
12181         scf_value_t *val;
12182         scf_iter_t *iter;
12183         int r;
12184         scf_error_t err;
12185 
12186         /* Verify that the pg has the correct type. */
12187         pgty = safe_malloc(max_scf_pg_type_len + 1);
12188         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12189                 scfdie();
12190 
12191         if (strcmp(pgty, scf_group_framework) != 0) {
12192                 if (g_verbose) {
12193                         fmri = safe_malloc(max_scf_fmri_len + 1);
12194                         if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12195                                 scfdie();
12196 
12197                         warn(gettext("Property group %s is not of expected "
12198                             "type %s.\n"), fmri, scf_group_framework);
12199 
12200                         free(fmri);
12201                 }
12202 
12203                 free(pgty);
12204                 return (-1);
12205         }
12206 
12207         free(pgty);
12208 
12209         /* map delete_dependency_pg onto the properties. */
12210         if ((prop = scf_property_create(g_hndl)) == NULL ||
12211             (val = scf_value_create(g_hndl)) == NULL ||
12212             (iter = scf_iter_create(g_hndl)) == NULL)
12213                 scfdie();
12214 
12215         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12216                 scfdie();
12217 
12218         name = safe_malloc(max_scf_name_len + 1);
12219         fmri = safe_malloc(max_scf_fmri_len + 2);
12220 
12221         while ((r = scf_iter_next_property(iter, prop)) == 1) {
12222                 scf_type_t ty;
12223 
12224                 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12225                         scfdie();
12226 
12227                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12228                         scfdie();
12229 
12230                 if ((ty != SCF_TYPE_ASTRING &&
12231                     prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12232                     prop_get_val(prop, val) != 0)
12233                         continue;
12234 
12235                 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12236                         scfdie();
12237 
12238                 err = delete_dependency_pg(fmri, name);
12239                 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12240                         if (scf_property_to_fmri(prop, fmri,
12241                             max_scf_fmri_len + 2) < 0)
12242                                 scfdie();
12243 
12244                         warn(gettext("Value of %s is not a valid FMRI.\n"),
12245                             fmri);
12246                 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12247                         warn(gettext("Property group \"%s\" of entity \"%s\" "
12248                             "does not have dependency type.\n"), name, fmri);
12249                 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12250                         warn(gettext("Could not delete property group \"%s\" "
12251                             "of entity \"%s\" (permission denied).\n"), name,
12252                             fmri);
12253                 }
12254         }
12255         if (r == -1)
12256                 scfdie();
12257 
12258         scf_value_destroy(val);
12259         scf_property_destroy(prop);
12260 
12261         return (0);
12262 }
12263 
12264 /*
12265  * Returns 1 if the instance may be running, and 0 otherwise.
12266  */
12267 static int
12268 inst_is_running(scf_instance_t *inst)
12269 {
12270         scf_propertygroup_t *pg;
12271         scf_property_t *prop;
12272         scf_value_t *val;
12273         char buf[MAX_SCF_STATE_STRING_SZ];
12274         int ret = 0;
12275         ssize_t szret;
12276 
12277         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12278             (prop = scf_property_create(g_hndl)) == NULL ||
12279             (val = scf_value_create(g_hndl)) == NULL)
12280                 scfdie();
12281 
12282         if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12283                 if (scf_error() != SCF_ERROR_NOT_FOUND)
12284                         scfdie();
12285                 goto out;
12286         }
12287 
12288         if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12289             prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12290             prop_get_val(prop, val) != 0)
12291                 goto out;
12292 
12293         szret = scf_value_get_astring(val, buf, sizeof (buf));
12294         assert(szret >= 0);
12295 
12296         ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12297             strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12298 
12299 out:
12300         scf_value_destroy(val);
12301         scf_property_destroy(prop);
12302         scf_pg_destroy(pg);
12303         return (ret);
12304 }
12305 
12306 static uint8_t
12307 pg_is_external_dependency(scf_propertygroup_t *pg)
12308 {
12309         char *type;
12310         scf_value_t *val;
12311         scf_property_t *prop;
12312         uint8_t b = B_FALSE;
12313 
12314         type = safe_malloc(max_scf_pg_type_len + 1);
12315 
12316         if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12317                 scfdie();
12318 
12319         if ((prop = scf_property_create(g_hndl)) == NULL ||
12320             (val = scf_value_create(g_hndl)) == NULL)
12321                 scfdie();
12322 
12323         if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12324                 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12325                         if (scf_property_get_value(prop, val) != 0)
12326                                 scfdie();
12327                         if (scf_value_get_boolean(val, &b) != 0)
12328                                 scfdie();
12329                 }
12330         }
12331 
12332         free(type);
12333         (void) scf_value_destroy(val);
12334         (void) scf_property_destroy(prop);
12335 
12336         return (b);
12337 }
12338 
12339 #define DELETE_FAILURE                  -1
12340 #define DELETE_SUCCESS_NOEXTDEPS        0
12341 #define DELETE_SUCCESS_EXTDEPS          1
12342 
12343 /*
12344  * lscf_instance_delete() deletes an instance.  Before calling
12345  * scf_instance_delete(), though, we make sure the instance isn't
12346  * running and delete dependencies in other entities which the instance
12347  * declared as "dependents".  If there are dependencies which were
12348  * created for other entities, then instead of deleting the instance we
12349  * make it "empty" by deleting all other property groups and all
12350  * snapshots.
12351  *
12352  * lscf_instance_delete() verifies that there is no external dependency pgs
12353  * before suppressing the instance. If there is, then we must not remove them
12354  * now in case the instance is re-created otherwise the dependencies would be
12355  * lost. The external dependency pgs will be removed if the dependencies are
12356  * removed.
12357  *
12358  * Returns:
12359  *  DELETE_FAILURE              on failure
12360  *  DELETE_SUCCESS_NOEXTDEPS    on success - no external dependencies
12361  *  DELETE_SUCCESS_EXTDEPS      on success - external dependencies
12362  */
12363 static int
12364 lscf_instance_delete(scf_instance_t *inst, int force)
12365 {
12366         scf_propertygroup_t *pg;
12367         scf_snapshot_t *snap;
12368         scf_iter_t *iter;
12369         int err;
12370         int external = 0;
12371 
12372         /* If we're not forcing and the instance is running, refuse. */
12373         if (!force && inst_is_running(inst)) {
12374                 char *fmri;
12375 
12376                 fmri = safe_malloc(max_scf_fmri_len + 1);
12377 
12378                 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12379                         scfdie();
12380 
12381                 semerr(gettext("Instance %s may be running.  "
12382                     "Use delete -f if it is not.\n"), fmri);
12383 
12384                 free(fmri);
12385                 return (DELETE_FAILURE);
12386         }
12387 
12388         pg = scf_pg_create(g_hndl);
12389         if (pg == NULL)
12390                 scfdie();
12391 
12392         if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12393                 (void) delete_dependents(pg);
12394         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12395                 scfdie();
12396 
12397         scf_pg_destroy(pg);
12398 
12399         /*
12400          * If the instance has some external dependencies then we must
12401          * keep them in case the instance is reimported otherwise the
12402          * dependencies would be lost on reimport.
12403          */
12404         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12405             (pg = scf_pg_create(g_hndl)) == NULL)
12406                 scfdie();
12407 
12408         if (scf_iter_instance_pgs(iter, inst) < 0)
12409                 scfdie();
12410 
12411         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12412                 if (pg_is_external_dependency(pg)) {
12413                         external = 1;
12414                         continue;
12415                 }
12416 
12417                 if (scf_pg_delete(pg) != 0) {
12418                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12419                                 scfdie();
12420                         else {
12421                                 semerr(emsg_permission_denied);
12422 
12423                                 (void) scf_iter_destroy(iter);
12424                                 (void) scf_pg_destroy(pg);
12425                                 return (DELETE_FAILURE);
12426                         }
12427                 }
12428         }
12429 
12430         if (err == -1)
12431                 scfdie();
12432 
12433         (void) scf_iter_destroy(iter);
12434         (void) scf_pg_destroy(pg);
12435 
12436         if (external) {
12437                 /*
12438                  * All the pgs have been deleted for the instance except
12439                  * the ones holding the external dependencies.
12440                  * For the job to be complete, we must also delete the
12441                  * snapshots associated with the instance.
12442                  */
12443                 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12444                     NULL)
12445                         scfdie();
12446                 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12447                         scfdie();
12448 
12449                 if (scf_iter_instance_snapshots(iter, inst) == -1)
12450                         scfdie();
12451 
12452                 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12453                         if (_scf_snapshot_delete(snap) != 0) {
12454                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12455                                         scfdie();
12456 
12457                                 semerr(emsg_permission_denied);
12458 
12459                                 (void) scf_iter_destroy(iter);
12460                                 (void) scf_snapshot_destroy(snap);
12461                                 return (DELETE_FAILURE);
12462                         }
12463                 }
12464 
12465                 if (err == -1)
12466                         scfdie();
12467 
12468                 (void) scf_iter_destroy(iter);
12469                 (void) scf_snapshot_destroy(snap);
12470                 return (DELETE_SUCCESS_EXTDEPS);
12471         }
12472 
12473         if (scf_instance_delete(inst) != 0) {
12474                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12475                         scfdie();
12476 
12477                 semerr(emsg_permission_denied);
12478 
12479                 return (DELETE_FAILURE);
12480         }
12481 
12482         return (DELETE_SUCCESS_NOEXTDEPS);
12483 }
12484 
12485 /*
12486  * lscf_service_delete() deletes a service.  Before calling
12487  * scf_service_delete(), though, we call lscf_instance_delete() for
12488  * each of the instances and delete dependencies in other entities
12489  * which were created as "dependents" of this service.  If there are
12490  * dependencies which were created for other entities, then we delete
12491  * all other property groups in the service and leave it as "empty".
12492  *
12493  * lscf_service_delete() verifies that there is no external dependency
12494  * pgs at the instance & service level before suppressing the service.
12495  * If there is, then we must not remove them now in case the service
12496  * is re-imported otherwise the dependencies would be lost. The external
12497  * dependency pgs will be removed if the dependencies are removed.
12498  *
12499  * Returns:
12500  *   DELETE_FAILURE             on failure
12501  *   DELETE_SUCCESS_NOEXTDEPS   on success - no external dependencies
12502  *   DELETE_SUCCESS_EXTDEPS     on success - external dependencies
12503  */
12504 static int
12505 lscf_service_delete(scf_service_t *svc, int force)
12506 {
12507         int r;
12508         scf_instance_t *inst;
12509         scf_propertygroup_t *pg;
12510         scf_iter_t *iter;
12511         int ret;
12512         int external = 0;
12513 
12514         if ((inst = scf_instance_create(g_hndl)) == NULL ||
12515             (pg = scf_pg_create(g_hndl)) == NULL ||
12516             (iter = scf_iter_create(g_hndl)) == NULL)
12517                 scfdie();
12518 
12519         if (scf_iter_service_instances(iter, svc) != 0)
12520                 scfdie();
12521 
12522         for (r = scf_iter_next_instance(iter, inst);
12523             r == 1;
12524             r = scf_iter_next_instance(iter, inst)) {
12525 
12526                 ret = lscf_instance_delete(inst, force);
12527                 if (ret == DELETE_FAILURE) {
12528                         scf_iter_destroy(iter);
12529                         scf_pg_destroy(pg);
12530                         scf_instance_destroy(inst);
12531                         return (DELETE_FAILURE);
12532                 }
12533 
12534                 /*
12535                  * Record the fact that there is some external dependencies
12536                  * at the instance level.
12537                  */
12538                 if (ret == DELETE_SUCCESS_EXTDEPS)
12539                         external |= 1;
12540         }
12541 
12542         if (r != 0)
12543                 scfdie();
12544 
12545         /* Delete dependency property groups in dependent services. */
12546         if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12547                 (void) delete_dependents(pg);
12548         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12549                 scfdie();
12550 
12551         scf_iter_destroy(iter);
12552         scf_pg_destroy(pg);
12553         scf_instance_destroy(inst);
12554 
12555         /*
12556          * If the service has some external dependencies then we don't
12557          * want to remove them in case the service is re-imported.
12558          */
12559         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12560             (iter = scf_iter_create(g_hndl)) == NULL)
12561                 scfdie();
12562 
12563         if (scf_iter_service_pgs(iter, svc) < 0)
12564                 scfdie();
12565 
12566         while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12567                 if (pg_is_external_dependency(pg)) {
12568                         external |= 2;
12569                         continue;
12570                 }
12571 
12572                 if (scf_pg_delete(pg) != 0) {
12573                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12574                                 scfdie();
12575                         else {
12576                                 semerr(emsg_permission_denied);
12577 
12578                                 (void) scf_iter_destroy(iter);
12579                                 (void) scf_pg_destroy(pg);
12580                                 return (DELETE_FAILURE);
12581                         }
12582                 }
12583         }
12584 
12585         if (r == -1)
12586                 scfdie();
12587 
12588         (void) scf_iter_destroy(iter);
12589         (void) scf_pg_destroy(pg);
12590 
12591         if (external != 0)
12592                 return (DELETE_SUCCESS_EXTDEPS);
12593 
12594         if (scf_service_delete(svc) == 0)
12595                 return (DELETE_SUCCESS_NOEXTDEPS);
12596 
12597         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12598                 scfdie();
12599 
12600         semerr(emsg_permission_denied);
12601         return (DELETE_FAILURE);
12602 }
12603 
12604 static int
12605 delete_callback(void *data, scf_walkinfo_t *wip)
12606 {
12607         int force = (int)data;
12608 
12609         if (wip->inst != NULL)
12610                 (void) lscf_instance_delete(wip->inst, force);
12611         else
12612                 (void) lscf_service_delete(wip->svc, force);
12613 
12614         return (0);
12615 }
12616 
12617 void
12618 lscf_delete(const char *fmri, int force)
12619 {
12620         scf_service_t *svc;
12621         scf_instance_t *inst;
12622         int ret;
12623 
12624         lscf_prep_hndl();
12625 
12626         if (cur_snap != NULL) {
12627                 if (!snaplevel_is_instance(cur_level)) {
12628                         char *buf;
12629 
12630                         buf = safe_malloc(max_scf_name_len + 1);
12631                         if (scf_instance_get_name(cur_inst, buf,
12632                             max_scf_name_len + 1) >= 0) {
12633                                 if (strcmp(buf, fmri) == 0) {
12634                                         semerr(emsg_cant_modify_snapshots);
12635                                         free(buf);
12636                                         return;
12637                                 }
12638                         } else if (scf_error() != SCF_ERROR_DELETED) {
12639                                 scfdie();
12640                         }
12641                         free(buf);
12642                 }
12643         } else if (cur_inst != NULL) {
12644                 /* EMPTY */;
12645         } else if (cur_svc != NULL) {
12646                 inst = scf_instance_create(g_hndl);
12647                 if (inst == NULL)
12648                         scfdie();
12649 
12650                 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12651                     SCF_SUCCESS) {
12652                         (void) lscf_instance_delete(inst, force);
12653                         scf_instance_destroy(inst);
12654                         return;
12655                 }
12656 
12657                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12658                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12659                         scfdie();
12660 
12661                 scf_instance_destroy(inst);
12662         } else {
12663                 assert(cur_scope != NULL);
12664 
12665                 svc = scf_service_create(g_hndl);
12666                 if (svc == NULL)
12667                         scfdie();
12668 
12669                 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12670                     SCF_SUCCESS) {
12671                         (void) lscf_service_delete(svc, force);
12672                         scf_service_destroy(svc);
12673                         return;
12674                 }
12675 
12676                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12677                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12678                         scfdie();
12679 
12680                 scf_service_destroy(svc);
12681         }
12682 
12683         /*
12684          * Match FMRI to entity.
12685          */
12686         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12687             delete_callback, (void *)force, NULL, semerr)) != 0) {
12688                 semerr(gettext("Failed to walk instances: %s\n"),
12689                     scf_strerror(ret));
12690         }
12691 }
12692 
12693 
12694 
12695 /*
12696  * :properties commands.  These all end with "pg" or "prop" and generally
12697  * operate on the currently selected entity.
12698  */
12699 
12700 /*
12701  * Property listing.  List the property groups, properties, their types and
12702  * their values for the currently selected entity.
12703  */
12704 static void
12705 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12706 {
12707         char *buf;
12708         uint32_t flags;
12709 
12710         buf = safe_malloc(max_scf_pg_type_len + 1);
12711 
12712         if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12713                 scfdie();
12714 
12715         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12716                 scfdie();
12717 
12718         safe_printf("%-*s  %s", namewidth, name, buf);
12719 
12720         if (flags & SCF_PG_FLAG_NONPERSISTENT)
12721                 safe_printf("\tNONPERSISTENT");
12722 
12723         safe_printf("\n");
12724 
12725         free(buf);
12726 }
12727 
12728 static boolean_t
12729 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12730 {
12731         if (scf_property_get_value(prop, val) == 0) {
12732                 return (B_FALSE);
12733         } else {
12734                 switch (scf_error()) {
12735                 case SCF_ERROR_NOT_FOUND:
12736                         return (B_FALSE);
12737                 case SCF_ERROR_PERMISSION_DENIED:
12738                 case SCF_ERROR_CONSTRAINT_VIOLATED:
12739                         return (B_TRUE);
12740                 default:
12741                         scfdie();
12742                         /*NOTREACHED*/
12743                 }
12744         }
12745 }
12746 
12747 static void
12748 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12749 {
12750         scf_iter_t *iter;
12751         scf_value_t *val;
12752         const char *type;
12753         int multiple_strings = 0;
12754         int ret;
12755 
12756         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12757             (val = scf_value_create(g_hndl)) == NULL)
12758                 scfdie();
12759 
12760         type = prop_to_typestr(prop);
12761         assert(type != NULL);
12762 
12763         safe_printf("%-*s  %-7s ", len, name, type);
12764 
12765         if (prop_has_multiple_values(prop, val) &&
12766             (scf_value_type(val) == SCF_TYPE_ASTRING ||
12767             scf_value_type(val) == SCF_TYPE_USTRING))
12768                 multiple_strings = 1;
12769 
12770         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12771                 scfdie();
12772 
12773         while ((ret = scf_iter_next_value(iter, val)) == 1) {
12774                 char *buf;
12775                 ssize_t vlen, szret;
12776 
12777                 vlen = scf_value_get_as_string(val, NULL, 0);
12778                 if (vlen < 0)
12779                         scfdie();
12780 
12781                 buf = safe_malloc(vlen + 1);
12782 
12783                 szret = scf_value_get_as_string(val, buf, vlen + 1);
12784                 if (szret < 0)
12785                         scfdie();
12786                 assert(szret <= vlen);
12787 
12788                 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12789                 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12790                         safe_printf(" \"");
12791                         (void) quote_and_print(buf, stdout, 0);
12792                         (void) putchar('"');
12793                         if (ferror(stdout)) {
12794                                 (void) putchar('\n');
12795                                 uu_die(gettext("Error writing to stdout.\n"));
12796                         }
12797                 } else {
12798                         safe_printf(" %s", buf);
12799                 }
12800 
12801                 free(buf);
12802         }
12803         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12804                 scfdie();
12805 
12806         if (putchar('\n') != '\n')
12807                 uu_die(gettext("Could not output newline"));
12808 }
12809 
12810 /*
12811  * Outputs template property group info for the describe subcommand.
12812  * If 'templates' == 2, verbose output is printed in the format expected
12813  * for describe -v, which includes all templates fields.  If pg is
12814  * not NULL, we're describing the template data, not an existing property
12815  * group, and formatting should be appropriate for describe -t.
12816  */
12817 static void
12818 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12819 {
12820         char *buf;
12821         uint8_t required;
12822         scf_property_t *stability_prop;
12823         scf_value_t *stability_val;
12824 
12825         if (templates == 0)
12826                 return;
12827 
12828         if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12829             (stability_val = scf_value_create(g_hndl)) == NULL)
12830                 scfdie();
12831 
12832         if (templates == 2 && pg != NULL) {
12833                 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12834                     stability_prop) == 0) {
12835                         if (prop_check_type(stability_prop,
12836                             SCF_TYPE_ASTRING) == 0 &&
12837                             prop_get_val(stability_prop, stability_val) == 0) {
12838                                 char *stability;
12839 
12840                                 stability = safe_malloc(max_scf_value_len + 1);
12841 
12842                                 if (scf_value_get_astring(stability_val,
12843                                     stability, max_scf_value_len + 1) == -1 &&
12844                                     scf_error() != SCF_ERROR_NOT_FOUND)
12845                                         scfdie();
12846 
12847                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
12848                                     gettext("stability"), stability);
12849 
12850                                 free(stability);
12851                         }
12852                 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12853                         scfdie();
12854         }
12855 
12856         scf_property_destroy(stability_prop);
12857         scf_value_destroy(stability_val);
12858 
12859         if (pgt == NULL)
12860                 return;
12861 
12862         if (pg == NULL || templates == 2) {
12863                 /* print type info only if scf_tmpl_pg_name succeeds */
12864                 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12865                         if (pg != NULL)
12866                                 safe_printf("%s", TMPL_INDENT);
12867                         safe_printf("%s: ", gettext("name"));
12868                         safe_printf("%s\n", buf);
12869                         free(buf);
12870                 }
12871 
12872                 /* print type info only if scf_tmpl_pg_type succeeds */
12873                 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12874                         if (pg != NULL)
12875                                 safe_printf("%s", TMPL_INDENT);
12876                         safe_printf("%s: ", gettext("type"));
12877                         safe_printf("%s\n", buf);
12878                         free(buf);
12879                 }
12880         }
12881 
12882         if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12883                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12884                     required ? "true" : "false");
12885 
12886         if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12887                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12888                     buf);
12889                 free(buf);
12890         }
12891 
12892         if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12893                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12894                     buf);
12895                 free(buf);
12896         }
12897 
12898         if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12899                 if (templates == 2)
12900                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12901                             gettext("description"), buf);
12902                 else
12903                         safe_printf("%s%s\n", TMPL_INDENT, buf);
12904                 free(buf);
12905         }
12906 
12907 }
12908 
12909 /*
12910  * With as_value set to true, indent as appropriate for the value level.
12911  * If false, indent to appropriate level for inclusion in constraint
12912  * or choice printout.
12913  */
12914 static void
12915 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12916     int as_value)
12917 {
12918         char *buf;
12919 
12920         if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12921                 if (as_value == 0)
12922                         safe_printf("%s", TMPL_CHOICE_INDENT);
12923                 else
12924                         safe_printf("%s", TMPL_INDENT);
12925                 safe_printf("%s: %s\n", gettext("value common name"), buf);
12926                 free(buf);
12927         }
12928 
12929         if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12930                 if (as_value == 0)
12931                         safe_printf("%s", TMPL_CHOICE_INDENT);
12932                 else
12933                         safe_printf("%s", TMPL_INDENT);
12934                 safe_printf("%s: %s\n", gettext("value description"), buf);
12935                 free(buf);
12936         }
12937 }
12938 
12939 static void
12940 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12941 {
12942         safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12943         /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12944         safe_printf("%s\n", val_buf);
12945 
12946         print_template_value_details(prt, val_buf, 1);
12947 }
12948 
12949 static void
12950 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12951 {
12952         int i, printed = 0;
12953         scf_values_t values;
12954         scf_count_ranges_t c_ranges;
12955         scf_int_ranges_t i_ranges;
12956 
12957         printed = 0;
12958         i = 0;
12959         if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12960                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12961                     gettext("value constraints"));
12962                 printed++;
12963                 for (i = 0; i < values.value_count; ++i) {
12964                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12965                             gettext("value name"), values.values_as_strings[i]);
12966                         if (verbose == 1)
12967                                 print_template_value_details(prt,
12968                                     values.values_as_strings[i], 0);
12969                 }
12970 
12971                 scf_values_destroy(&values);
12972         }
12973 
12974         if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12975                 if (printed++ == 0)
12976                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12977                             gettext("value constraints"));
12978                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12979                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12980                             gettext("range"), c_ranges.scr_min[i],
12981                             c_ranges.scr_max[i]);
12982                 }
12983                 scf_count_ranges_destroy(&c_ranges);
12984         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12985             scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12986                 if (printed++ == 0)
12987                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12988                             gettext("value constraints"));
12989                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12990                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12991                             gettext("range"), i_ranges.sir_min[i],
12992                             i_ranges.sir_max[i]);
12993                 }
12994                 scf_int_ranges_destroy(&i_ranges);
12995         }
12996 }
12997 
12998 static void
12999 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
13000 {
13001         int i = 0, printed = 0;
13002         scf_values_t values;
13003         scf_count_ranges_t c_ranges;
13004         scf_int_ranges_t i_ranges;
13005 
13006         printed = 0;
13007         if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13008                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13009                     gettext("value constraints"));
13010                 printed++;
13011                 for (i = 0; i < values.value_count; i++) {
13012                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13013                             gettext("value name"), values.values_as_strings[i]);
13014                         if (verbose == 1)
13015                                 print_template_value_details(prt,
13016                                     values.values_as_strings[i], 0);
13017                 }
13018 
13019                 scf_values_destroy(&values);
13020         }
13021 
13022         if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13023                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13024                         if (printed++ == 0)
13025                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13026                                     gettext("value choices"));
13027                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13028                             gettext("range"), c_ranges.scr_min[i],
13029                             c_ranges.scr_max[i]);
13030                 }
13031                 scf_count_ranges_destroy(&c_ranges);
13032         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13033             scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13034                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13035                         if (printed++ == 0)
13036                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13037                                     gettext("value choices"));
13038                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13039                             gettext("range"), i_ranges.sir_min[i],
13040                             i_ranges.sir_max[i]);
13041                 }
13042                 scf_int_ranges_destroy(&i_ranges);
13043         }
13044 }
13045 
13046 static void
13047 list_values_by_template(scf_prop_tmpl_t *prt)
13048 {
13049         print_template_constraints(prt, 1);
13050         print_template_choices(prt, 1);
13051 }
13052 
13053 static void
13054 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13055 {
13056         char *val_buf;
13057         scf_iter_t *iter;
13058         scf_value_t *val;
13059         int ret;
13060 
13061         if ((iter = scf_iter_create(g_hndl)) == NULL ||
13062             (val = scf_value_create(g_hndl)) == NULL)
13063                 scfdie();
13064 
13065         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13066                 scfdie();
13067 
13068         val_buf = safe_malloc(max_scf_value_len + 1);
13069 
13070         while ((ret = scf_iter_next_value(iter, val)) == 1) {
13071                 if (scf_value_get_as_string(val, val_buf,
13072                     max_scf_value_len + 1) < 0)
13073                         scfdie();
13074 
13075                 print_template_value(prt, val_buf);
13076         }
13077         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13078                 scfdie();
13079         free(val_buf);
13080 
13081         print_template_constraints(prt, 0);
13082         print_template_choices(prt, 0);
13083 
13084 }
13085 
13086 /*
13087  * Outputs property info for the describe subcommand
13088  * Verbose output if templates == 2, -v option of svccfg describe
13089  * Displays template data if prop is not NULL, -t option of svccfg describe
13090  */
13091 static void
13092 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13093 {
13094         char *buf;
13095         uint8_t u_buf;
13096         int i;
13097         uint64_t min, max;
13098         scf_values_t values;
13099 
13100         if (prt == NULL || templates == 0)
13101                 return;
13102 
13103         if (prop == NULL) {
13104                 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13105                 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13106                         safe_printf("%s\n", buf);
13107                         free(buf);
13108                 } else
13109                         safe_printf("(%s)\n", gettext("any"));
13110         }
13111 
13112         if (prop == NULL || templates == 2) {
13113                 if (prop != NULL)
13114                         safe_printf("%s", TMPL_INDENT);
13115                 else
13116                         safe_printf("%s", TMPL_VALUE_INDENT);
13117                 safe_printf("%s: ", gettext("type"));
13118                 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13119                         safe_printf("%s\n", buf);
13120                         free(buf);
13121                 } else
13122                         safe_printf("(%s)\n", gettext("any"));
13123         }
13124 
13125         if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13126                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13127                     u_buf ? "true" : "false");
13128 
13129         if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13130                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13131                     buf);
13132                 free(buf);
13133         }
13134 
13135         if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13136                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13137                     buf);
13138                 free(buf);
13139         }
13140 
13141         if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13142                 safe_printf("%s%s\n", TMPL_INDENT, buf);
13143                 free(buf);
13144         }
13145 
13146         if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13147                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13148                     scf_tmpl_visibility_to_string(u_buf));
13149 
13150         if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13151                 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13152                     gettext("minimum number of values"), min);
13153                 if (max == ULLONG_MAX) {
13154                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13155                             gettext("maximum number of values"),
13156                             gettext("unlimited"));
13157                 } else {
13158                         safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13159                             gettext("maximum number of values"), max);
13160                 }
13161         }
13162 
13163         if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13164                 for (i = 0; i < values.value_count; i++) {
13165                         if (i == 0) {
13166                                 safe_printf("%s%s:", TMPL_INDENT,
13167                                     gettext("internal separators"));
13168                         }
13169                         safe_printf(" \"%s\"", values.values_as_strings[i]);
13170                 }
13171                 safe_printf("\n");
13172         }
13173 
13174         if (templates != 2)
13175                 return;
13176 
13177         if (prop != NULL)
13178                 list_values_tmpl(prt, prop);
13179         else
13180                 list_values_by_template(prt);
13181 }
13182 
13183 static char *
13184 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13185 {
13186         char *rv;
13187 
13188         rv = _scf_read_single_astring_from_pg(pg, prop_name);
13189         if (rv == NULL) {
13190                 switch (scf_error()) {
13191                 case SCF_ERROR_NOT_FOUND:
13192                         break;
13193                 default:
13194                         scfdie();
13195                 }
13196         }
13197         return (rv);
13198 }
13199 
13200 static void
13201 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13202 {
13203         size_t doc_len;
13204         size_t man_len;
13205         char *pg_name;
13206         char *text = NULL;
13207         int rv;
13208 
13209         doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13210         man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13211         pg_name = safe_malloc(max_scf_name_len + 1);
13212         while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13213                 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13214                         scfdie();
13215                 }
13216                 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13217                         /* Display doc_link and and uri */
13218                         safe_printf("%s%s:\n", TMPL_INDENT,
13219                             gettext("doc_link"));
13220                         text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13221                         if (text != NULL) {
13222                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13223                                     TMPL_INDENT, gettext("name"), text);
13224                                 uu_free(text);
13225                         }
13226                         text = read_astring(pg, SCF_PROPERTY_TM_URI);
13227                         if (text != NULL) {
13228                                 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13229                                     gettext("uri"), text);
13230                                 uu_free(text);
13231                         }
13232                 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13233                     man_len) == 0) {
13234                         /* Display manpage title, section and path */
13235                         safe_printf("%s%s:\n", TMPL_INDENT,
13236                             gettext("manpage"));
13237                         text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13238                         if (text != NULL) {
13239                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13240                                     TMPL_INDENT, gettext("title"), text);
13241                                 uu_free(text);
13242                         }
13243                         text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13244                         if (text != NULL) {
13245                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13246                                     TMPL_INDENT, gettext("section"), text);
13247                                 uu_free(text);
13248                         }
13249                         text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13250                         if (text != NULL) {
13251                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13252                                     TMPL_INDENT, gettext("manpath"), text);
13253                                 uu_free(text);
13254                         }
13255                 }
13256         }
13257         if (rv == -1)
13258                 scfdie();
13259 
13260 done:
13261         free(pg_name);
13262 }
13263 
13264 static void
13265 list_entity_tmpl(int templates)
13266 {
13267         char *common_name = NULL;
13268         char *description = NULL;
13269         char *locale = NULL;
13270         scf_iter_t *iter;
13271         scf_propertygroup_t *pg;
13272         scf_property_t *prop;
13273         int r;
13274         scf_value_t *val;
13275 
13276         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13277             (prop = scf_property_create(g_hndl)) == NULL ||
13278             (val = scf_value_create(g_hndl)) == NULL ||
13279             (iter = scf_iter_create(g_hndl)) == NULL)
13280                 scfdie();
13281 
13282         locale = setlocale(LC_MESSAGES, NULL);
13283 
13284         if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13285                 common_name = safe_malloc(max_scf_value_len + 1);
13286 
13287                 /* Try both the current locale and the "C" locale. */
13288                 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13289                     (scf_error() == SCF_ERROR_NOT_FOUND &&
13290                     scf_pg_get_property(pg, "C", prop) == 0)) {
13291                         if (prop_get_val(prop, val) == 0 &&
13292                             scf_value_get_ustring(val, common_name,
13293                             max_scf_value_len + 1) != -1) {
13294                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
13295                                     gettext("common name"), common_name);
13296                         }
13297                 }
13298         }
13299 
13300         /*
13301          * Do description, manpages, and doc links if templates == 2.
13302          */
13303         if (templates == 2) {
13304                 /* Get the description. */
13305                 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13306                         description = safe_malloc(max_scf_value_len + 1);
13307 
13308                         /* Try both the current locale and the "C" locale. */
13309                         if (scf_pg_get_property(pg, locale, prop) == 0 ||
13310                             (scf_error() == SCF_ERROR_NOT_FOUND &&
13311                             scf_pg_get_property(pg, "C", prop) == 0)) {
13312                                 if (prop_get_val(prop, val) == 0 &&
13313                                     scf_value_get_ustring(val, description,
13314                                     max_scf_value_len + 1) != -1) {
13315                                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13316                                             gettext("description"),
13317                                             description);
13318                                 }
13319                         }
13320                 }
13321 
13322                 /* Process doc_link & manpage elements. */
13323                 if (cur_level != NULL) {
13324                         r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13325                             SCF_GROUP_TEMPLATE);
13326                 } else if (cur_inst != NULL) {
13327                         r = scf_iter_instance_pgs_typed(iter, cur_inst,
13328                             SCF_GROUP_TEMPLATE);
13329                 } else {
13330                         r = scf_iter_service_pgs_typed(iter, cur_svc,
13331                             SCF_GROUP_TEMPLATE);
13332                 }
13333                 if (r == 0) {
13334                         display_documentation(iter, pg);
13335                 }
13336         }
13337 
13338         free(common_name);
13339         free(description);
13340         scf_pg_destroy(pg);
13341         scf_property_destroy(prop);
13342         scf_value_destroy(val);
13343         scf_iter_destroy(iter);
13344 }
13345 
13346 static void
13347 listtmpl(const char *pattern, int templates)
13348 {
13349         scf_pg_tmpl_t *pgt;
13350         scf_prop_tmpl_t *prt;
13351         char *snapbuf = NULL;
13352         char *fmribuf;
13353         char *pg_name = NULL, *prop_name = NULL;
13354         ssize_t prop_name_size;
13355         char *qual_prop_name;
13356         char *search_name;
13357         int listed = 0;
13358 
13359         if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13360             (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13361                 scfdie();
13362 
13363         fmribuf = safe_malloc(max_scf_name_len + 1);
13364         qual_prop_name = safe_malloc(max_scf_name_len + 1);
13365 
13366         if (cur_snap != NULL) {
13367                 snapbuf = safe_malloc(max_scf_name_len + 1);
13368                 if (scf_snapshot_get_name(cur_snap, snapbuf,
13369                     max_scf_name_len + 1) < 0)
13370                         scfdie();
13371         }
13372 
13373         if (cur_inst != NULL) {
13374                 if (scf_instance_to_fmri(cur_inst, fmribuf,
13375                     max_scf_name_len + 1) < 0)
13376                         scfdie();
13377         } else if (cur_svc != NULL) {
13378                 if (scf_service_to_fmri(cur_svc, fmribuf,
13379                     max_scf_name_len + 1) < 0)
13380                         scfdie();
13381         } else
13382                 abort();
13383 
13384         /* If pattern is specified, we want to list only those items. */
13385         while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13386                 listed = 0;
13387                 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13388                     fnmatch(pattern, pg_name, 0) == 0)) {
13389                         list_pg_tmpl(pgt, NULL, templates);
13390                         listed++;
13391                 }
13392 
13393                 scf_tmpl_prop_reset(prt);
13394 
13395                 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13396                         search_name = NULL;
13397                         prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13398                         if ((prop_name_size > 0) && (pg_name != NULL)) {
13399                                 if (snprintf(qual_prop_name,
13400                                     max_scf_name_len + 1, "%s/%s",
13401                                     pg_name, prop_name) >=
13402                                     max_scf_name_len + 1) {
13403                                         prop_name_size = -1;
13404                                 } else {
13405                                         search_name = qual_prop_name;
13406                                 }
13407                         }
13408                         if (listed > 0 || pattern == NULL ||
13409                             (prop_name_size > 0 &&
13410                             fnmatch(pattern, search_name,
13411                             FNM_PATHNAME) == 0))
13412                                 list_prop_tmpl(prt, NULL, templates);
13413                         if (prop_name != NULL) {
13414                                 free(prop_name);
13415                                 prop_name = NULL;
13416                         }
13417                 }
13418                 if (pg_name != NULL) {
13419                         free(pg_name);
13420                         pg_name = NULL;
13421                 }
13422         }
13423 
13424         scf_tmpl_prop_destroy(prt);
13425         scf_tmpl_pg_destroy(pgt);
13426         free(snapbuf);
13427         free(fmribuf);
13428         free(qual_prop_name);
13429 }
13430 
13431 static void
13432 listprop(const char *pattern, int only_pgs, int templates)
13433 {
13434         scf_propertygroup_t *pg;
13435         scf_property_t *prop;
13436         scf_iter_t *iter, *piter;
13437         char *pgnbuf, *prnbuf, *ppnbuf;
13438         scf_pg_tmpl_t *pgt, *pgtp;
13439         scf_prop_tmpl_t *prt;
13440 
13441         void **objects;
13442         char **names;
13443         void **tmpls;
13444         int allocd, i;
13445 
13446         int ret;
13447         ssize_t pgnlen, prnlen, szret;
13448         size_t max_len = 0;
13449 
13450         if (cur_svc == NULL && cur_inst == NULL) {
13451                 semerr(emsg_entity_not_selected);
13452                 return;
13453         }
13454 
13455         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13456             (prop = scf_property_create(g_hndl)) == NULL ||
13457             (iter = scf_iter_create(g_hndl)) == NULL ||
13458             (piter = scf_iter_create(g_hndl)) == NULL ||
13459             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13460             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13461                 scfdie();
13462 
13463         prnbuf = safe_malloc(max_scf_name_len + 1);
13464 
13465         if (cur_level != NULL)
13466                 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13467         else if (cur_inst != NULL)
13468                 ret = scf_iter_instance_pgs(iter, cur_inst);
13469         else
13470                 ret = scf_iter_service_pgs(iter, cur_svc);
13471         if (ret != 0) {
13472                 return;
13473         }
13474 
13475         /*
13476          * We want to only list items which match pattern, and we want the
13477          * second column to line up, so during the first pass we'll save
13478          * matching items, their names, and their templates in objects,
13479          * names, and tmpls, computing the maximum name length as we go,
13480          * and then we'll print them out.
13481          *
13482          * Note: We always keep an extra slot available so the array can be
13483          * NULL-terminated.
13484          */
13485         i = 0;
13486         allocd = 1;
13487         objects = safe_malloc(sizeof (*objects));
13488         names = safe_malloc(sizeof (*names));
13489         tmpls = safe_malloc(sizeof (*tmpls));
13490 
13491         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13492                 int new_pg = 0;
13493                 int print_props = 0;
13494                 pgtp = NULL;
13495 
13496                 pgnlen = scf_pg_get_name(pg, NULL, 0);
13497                 if (pgnlen < 0)
13498                         scfdie();
13499 
13500                 pgnbuf = safe_malloc(pgnlen + 1);
13501 
13502                 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13503                 if (szret < 0)
13504                         scfdie();
13505                 assert(szret <= pgnlen);
13506 
13507                 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13508                         if (scf_error() != SCF_ERROR_NOT_FOUND)
13509                                 scfdie();
13510                         pgtp = NULL;
13511                 } else {
13512                         pgtp = pgt;
13513                 }
13514 
13515                 if (pattern == NULL ||
13516                     fnmatch(pattern, pgnbuf, 0) == 0) {
13517                         if (i+1 >= allocd) {
13518                                 allocd *= 2;
13519                                 objects = realloc(objects,
13520                                     sizeof (*objects) * allocd);
13521                                 names =
13522                                     realloc(names, sizeof (*names) * allocd);
13523                                 tmpls = realloc(tmpls,
13524                                     sizeof (*tmpls) * allocd);
13525                                 if (objects == NULL || names == NULL ||
13526                                     tmpls == NULL)
13527                                         uu_die(gettext("Out of memory"));
13528                         }
13529                         objects[i] = pg;
13530                         names[i] = pgnbuf;
13531 
13532                         if (pgtp == NULL)
13533                                 tmpls[i] = NULL;
13534                         else
13535                                 tmpls[i] = pgt;
13536 
13537                         ++i;
13538 
13539                         if (pgnlen > max_len)
13540                                 max_len = pgnlen;
13541 
13542                         new_pg = 1;
13543                         print_props = 1;
13544                 }
13545 
13546                 if (only_pgs) {
13547                         if (new_pg) {
13548                                 pg = scf_pg_create(g_hndl);
13549                                 if (pg == NULL)
13550                                         scfdie();
13551                                 pgt = scf_tmpl_pg_create(g_hndl);
13552                                 if (pgt == NULL)
13553                                         scfdie();
13554                         } else
13555                                 free(pgnbuf);
13556 
13557                         continue;
13558                 }
13559 
13560                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13561                         scfdie();
13562 
13563                 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13564                         prnlen = scf_property_get_name(prop, prnbuf,
13565                             max_scf_name_len + 1);
13566                         if (prnlen < 0)
13567                                 scfdie();
13568 
13569                         /* Will prepend the property group name and a slash. */
13570                         prnlen += pgnlen + 1;
13571 
13572                         ppnbuf = safe_malloc(prnlen + 1);
13573 
13574                         if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13575                             prnbuf) < 0)
13576                                 uu_die("snprintf");
13577 
13578                         if (pattern == NULL || print_props == 1 ||
13579                             fnmatch(pattern, ppnbuf, 0) == 0) {
13580                                 if (i+1 >= allocd) {
13581                                         allocd *= 2;
13582                                         objects = realloc(objects,
13583                                             sizeof (*objects) * allocd);
13584                                         names = realloc(names,
13585                                             sizeof (*names) * allocd);
13586                                         tmpls = realloc(tmpls,
13587                                             sizeof (*tmpls) * allocd);
13588                                         if (objects == NULL || names == NULL ||
13589                                             tmpls == NULL)
13590                                                 uu_die(gettext(
13591                                                     "Out of memory"));
13592                                 }
13593 
13594                                 objects[i] = prop;
13595                                 names[i] = ppnbuf;
13596 
13597                                 if (pgtp != NULL) {
13598                                         if (scf_tmpl_get_by_prop(pgt, prnbuf,
13599                                             prt, 0) < 0) {
13600                                                 if (scf_error() !=
13601                                                     SCF_ERROR_NOT_FOUND)
13602                                                         scfdie();
13603                                                 tmpls[i] = NULL;
13604                                         } else {
13605                                                 tmpls[i] = prt;
13606                                         }
13607                                 } else {
13608                                         tmpls[i] = NULL;
13609                                 }
13610 
13611                                 ++i;
13612 
13613                                 if (prnlen > max_len)
13614                                         max_len = prnlen;
13615 
13616                                 prop = scf_property_create(g_hndl);
13617                                 prt = scf_tmpl_prop_create(g_hndl);
13618                         } else {
13619                                 free(ppnbuf);
13620                         }
13621                 }
13622 
13623                 if (new_pg) {
13624                         pg = scf_pg_create(g_hndl);
13625                         if (pg == NULL)
13626                                 scfdie();
13627                         pgt = scf_tmpl_pg_create(g_hndl);
13628                         if (pgt == NULL)
13629                                 scfdie();
13630                 } else
13631                         free(pgnbuf);
13632         }
13633         if (ret != 0)
13634                 scfdie();
13635 
13636         objects[i] = NULL;
13637 
13638         scf_pg_destroy(pg);
13639         scf_tmpl_pg_destroy(pgt);
13640         scf_property_destroy(prop);
13641         scf_tmpl_prop_destroy(prt);
13642 
13643         for (i = 0; objects[i] != NULL; ++i) {
13644                 if (strchr(names[i], '/') == NULL) {
13645                         /* property group */
13646                         pg = (scf_propertygroup_t *)objects[i];
13647                         pgt = (scf_pg_tmpl_t *)tmpls[i];
13648                         list_pg_info(pg, names[i], max_len);
13649                         list_pg_tmpl(pgt, pg, templates);
13650                         free(names[i]);
13651                         scf_pg_destroy(pg);
13652                         if (pgt != NULL)
13653                                 scf_tmpl_pg_destroy(pgt);
13654                 } else {
13655                         /* property */
13656                         prop = (scf_property_t *)objects[i];
13657                         prt = (scf_prop_tmpl_t *)tmpls[i];
13658                         list_prop_info(prop, names[i], max_len);
13659                         list_prop_tmpl(prt, prop, templates);
13660                         free(names[i]);
13661                         scf_property_destroy(prop);
13662                         if (prt != NULL)
13663                                 scf_tmpl_prop_destroy(prt);
13664                 }
13665         }
13666 
13667         free(names);
13668         free(objects);
13669         free(tmpls);
13670 }
13671 
13672 void
13673 lscf_listpg(const char *pattern)
13674 {
13675         lscf_prep_hndl();
13676 
13677         listprop(pattern, 1, 0);
13678 }
13679 
13680 /*
13681  * Property group and property creation, setting, and deletion.  setprop (and
13682  * its alias, addprop) can either create a property group of a given type, or
13683  * it can create or set a property to a given type and list of values.
13684  */
13685 void
13686 lscf_addpg(const char *name, const char *type, const char *flags)
13687 {
13688         scf_propertygroup_t *pg;
13689         int ret;
13690         uint32_t flgs = 0;
13691         const char *cp;
13692 
13693 
13694         lscf_prep_hndl();
13695 
13696         if (cur_snap != NULL) {
13697                 semerr(emsg_cant_modify_snapshots);
13698                 return;
13699         }
13700 
13701         if (cur_inst == NULL && cur_svc == NULL) {
13702                 semerr(emsg_entity_not_selected);
13703                 return;
13704         }
13705 
13706         if (flags != NULL) {
13707                 for (cp = flags; *cp != '\0'; ++cp) {
13708                         switch (*cp) {
13709                         case 'P':
13710                                 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13711                                 break;
13712 
13713                         case 'p':
13714                                 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13715                                 break;
13716 
13717                         default:
13718                                 semerr(gettext("Invalid property group flag "
13719                                     "%c."), *cp);
13720                                 return;
13721                         }
13722                 }
13723         }
13724 
13725         pg = scf_pg_create(g_hndl);
13726         if (pg == NULL)
13727                 scfdie();
13728 
13729         if (cur_inst != NULL)
13730                 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13731         else
13732                 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13733 
13734         if (ret != SCF_SUCCESS) {
13735                 switch (scf_error()) {
13736                 case SCF_ERROR_INVALID_ARGUMENT:
13737                         semerr(gettext("Name, type, or flags are invalid.\n"));
13738                         break;
13739 
13740                 case SCF_ERROR_EXISTS:
13741                         semerr(gettext("Property group already exists.\n"));
13742                         break;
13743 
13744                 case SCF_ERROR_PERMISSION_DENIED:
13745                         semerr(emsg_permission_denied);
13746                         break;
13747 
13748                 case SCF_ERROR_BACKEND_ACCESS:
13749                         semerr(gettext("Backend refused access.\n"));
13750                         break;
13751 
13752                 default:
13753                         scfdie();
13754                 }
13755         }
13756 
13757         scf_pg_destroy(pg);
13758 
13759         private_refresh();
13760 }
13761 
13762 void
13763 lscf_delpg(char *name)
13764 {
13765         lscf_prep_hndl();
13766 
13767         if (cur_snap != NULL) {
13768                 semerr(emsg_cant_modify_snapshots);
13769                 return;
13770         }
13771 
13772         if (cur_inst == NULL && cur_svc == NULL) {
13773                 semerr(emsg_entity_not_selected);
13774                 return;
13775         }
13776 
13777         if (strchr(name, '/') != NULL) {
13778                 semerr(emsg_invalid_pg_name, name);
13779                 return;
13780         }
13781 
13782         lscf_delprop(name);
13783 }
13784 
13785 /*
13786  * scf_delhash() is used to remove the property group related to the
13787  * hash entry for a specific manifest in the repository. pgname will be
13788  * constructed from the location of the manifest file. If deathrow isn't 0,
13789  * manifest file doesn't need to exist (manifest string will be used as
13790  * an absolute path).
13791  */
13792 void
13793 lscf_delhash(char *manifest, int deathrow)
13794 {
13795         char *pgname;
13796 
13797         if (cur_snap != NULL ||
13798             cur_inst != NULL || cur_svc != NULL) {
13799                 warn(gettext("error, an entity is selected\n"));
13800                 return;
13801         }
13802 
13803         /* select smf/manifest */
13804         lscf_select(HASH_SVC);
13805         /*
13806          * Translate the manifest file name to property name. In the deathrow
13807          * case, the manifest file does not need to exist.
13808          */
13809         pgname = mhash_filename_to_propname(manifest,
13810             deathrow ? B_TRUE : B_FALSE);
13811         if (pgname == NULL) {
13812                 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13813                 return;
13814         }
13815         /* delete the hash property name */
13816         lscf_delpg(pgname);
13817 }
13818 
13819 void
13820 lscf_listprop(const char *pattern)
13821 {
13822         lscf_prep_hndl();
13823 
13824         listprop(pattern, 0, 0);
13825 }
13826 
13827 int
13828 lscf_setprop(const char *pgname, const char *type, const char *value,
13829     const uu_list_t *values)
13830 {
13831         scf_type_t ty, current_ty;
13832         scf_service_t *svc;
13833         scf_propertygroup_t *pg, *parent_pg;
13834         scf_property_t *prop, *parent_prop;
13835         scf_pg_tmpl_t *pgt;
13836         scf_prop_tmpl_t *prt;
13837         int ret, result = 0;
13838         scf_transaction_t *tx;
13839         scf_transaction_entry_t *e;
13840         scf_value_t *v;
13841         uu_list_walk_t *walk;
13842         string_list_t *sp;
13843         char *propname;
13844         int req_quotes = 0;
13845 
13846         lscf_prep_hndl();
13847 
13848         if ((e = scf_entry_create(g_hndl)) == NULL ||
13849             (svc = scf_service_create(g_hndl)) == NULL ||
13850             (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13851             (pg = scf_pg_create(g_hndl)) == NULL ||
13852             (parent_prop = scf_property_create(g_hndl)) == NULL ||
13853             (prop = scf_property_create(g_hndl)) == NULL ||
13854             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13855             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13856             (tx = scf_transaction_create(g_hndl)) == NULL)
13857                 scfdie();
13858 
13859         if (cur_snap != NULL) {
13860                 semerr(emsg_cant_modify_snapshots);
13861                 goto fail;
13862         }
13863 
13864         if (cur_inst == NULL && cur_svc == NULL) {
13865                 semerr(emsg_entity_not_selected);
13866                 goto fail;
13867         }
13868 
13869         propname = strchr(pgname, '/');
13870         if (propname == NULL) {
13871                 semerr(gettext("Property names must contain a `/'.\n"));
13872                 goto fail;
13873         }
13874 
13875         *propname = '\0';
13876         ++propname;
13877 
13878         if (type != NULL) {
13879                 ty = string_to_type(type);
13880                 if (ty == SCF_TYPE_INVALID) {
13881                         semerr(gettext("Unknown type \"%s\".\n"), type);
13882                         goto fail;
13883                 }
13884         }
13885 
13886         if (cur_inst != NULL)
13887                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13888         else
13889                 ret = scf_service_get_pg(cur_svc, pgname, pg);
13890         if (ret != SCF_SUCCESS) {
13891                 switch (scf_error()) {
13892                 case SCF_ERROR_NOT_FOUND:
13893                         semerr(emsg_no_such_pg, pgname);
13894                         goto fail;
13895 
13896                 case SCF_ERROR_INVALID_ARGUMENT:
13897                         semerr(emsg_invalid_pg_name, pgname);
13898                         goto fail;
13899 
13900                 default:
13901                         scfdie();
13902                         break;
13903                 }
13904         }
13905 
13906         do {
13907                 if (scf_pg_update(pg) == -1)
13908                         scfdie();
13909                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13910                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13911                                 scfdie();
13912 
13913                         semerr(emsg_permission_denied);
13914                         goto fail;
13915                 }
13916 
13917                 ret = scf_pg_get_property(pg, propname, prop);
13918                 if (ret == SCF_SUCCESS) {
13919                         if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13920                                 scfdie();
13921 
13922                         if (type == NULL)
13923                                 ty = current_ty;
13924                         if (scf_transaction_property_change_type(tx, e,
13925                             propname, ty) == -1)
13926                                 scfdie();
13927 
13928                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13929                         /* Infer the type, if possible. */
13930                         if (type == NULL) {
13931                                 /*
13932                                  * First check if we're an instance and the
13933                                  * property is set on the service.
13934                                  */
13935                                 if (cur_inst != NULL &&
13936                                     scf_instance_get_parent(cur_inst,
13937                                     svc) == 0 &&
13938                                     scf_service_get_pg(cur_svc, pgname,
13939                                     parent_pg) == 0 &&
13940                                     scf_pg_get_property(parent_pg, propname,
13941                                     parent_prop) == 0 &&
13942                                     scf_property_type(parent_prop,
13943                                     &current_ty) == 0) {
13944                                         ty = current_ty;
13945 
13946                                 /* Then check for a type set in a template. */
13947                                 } else if (scf_tmpl_get_by_pg(pg, pgt,
13948                                     0) == 0 &&
13949                                     scf_tmpl_get_by_prop(pgt, propname, prt,
13950                                     0) == 0 &&
13951                                     scf_tmpl_prop_type(prt, &current_ty) == 0) {
13952                                         ty = current_ty;
13953 
13954                                 /* If type can't be inferred, fail. */
13955                                 } else {
13956                                         semerr(gettext("Type required for new "
13957                                             "properties.\n"));
13958                                         goto fail;
13959                                 }
13960                         }
13961                         if (scf_transaction_property_new(tx, e, propname,
13962                             ty) == -1)
13963                                 scfdie();
13964                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13965                         semerr(emsg_invalid_prop_name, propname);
13966                         goto fail;
13967                 } else {
13968                         scfdie();
13969                 }
13970 
13971                 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13972                         req_quotes = 1;
13973 
13974                 if (value != NULL) {
13975                         v = string_to_value(value, ty, 0);
13976 
13977                         if (v == NULL)
13978                                 goto fail;
13979 
13980                         ret = scf_entry_add_value(e, v);
13981                         assert(ret == SCF_SUCCESS);
13982                 } else {
13983                         assert(values != NULL);
13984 
13985                         walk = uu_list_walk_start((uu_list_t *)values,
13986                             UU_DEFAULT);
13987                         if (walk == NULL)
13988                                 uu_die(gettext("Could not walk list"));
13989 
13990                         for (sp = uu_list_walk_next(walk); sp != NULL;
13991                             sp = uu_list_walk_next(walk)) {
13992                                 v = string_to_value(sp->str, ty, req_quotes);
13993 
13994                                 if (v == NULL) {
13995                                         scf_entry_destroy_children(e);
13996                                         goto fail;
13997                                 }
13998 
13999                                 ret = scf_entry_add_value(e, v);
14000                                 assert(ret == SCF_SUCCESS);
14001                         }
14002                         uu_list_walk_end(walk);
14003                 }
14004                 result = scf_transaction_commit(tx);
14005 
14006                 scf_transaction_reset(tx);
14007                 scf_entry_destroy_children(e);
14008         } while (result == 0);
14009 
14010         if (result < 0) {
14011                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14012                         scfdie();
14013 
14014                 semerr(emsg_permission_denied);
14015                 goto fail;
14016         }
14017 
14018         ret = 0;
14019 
14020         private_refresh();
14021 
14022         goto cleanup;
14023 
14024 fail:
14025         ret = -1;
14026 
14027 cleanup:
14028         scf_transaction_destroy(tx);
14029         scf_entry_destroy(e);
14030         scf_service_destroy(svc);
14031         scf_pg_destroy(parent_pg);
14032         scf_pg_destroy(pg);
14033         scf_property_destroy(parent_prop);
14034         scf_property_destroy(prop);
14035         scf_tmpl_pg_destroy(pgt);
14036         scf_tmpl_prop_destroy(prt);
14037 
14038         return (ret);
14039 }
14040 
14041 void
14042 lscf_delprop(char *pgn)
14043 {
14044         char *slash, *pn;
14045         scf_propertygroup_t *pg;
14046         scf_transaction_t *tx;
14047         scf_transaction_entry_t *e;
14048         int ret;
14049 
14050 
14051         lscf_prep_hndl();
14052 
14053         if (cur_snap != NULL) {
14054                 semerr(emsg_cant_modify_snapshots);
14055                 return;
14056         }
14057 
14058         if (cur_inst == NULL && cur_svc == NULL) {
14059                 semerr(emsg_entity_not_selected);
14060                 return;
14061         }
14062 
14063         pg = scf_pg_create(g_hndl);
14064         if (pg == NULL)
14065                 scfdie();
14066 
14067         slash = strchr(pgn, '/');
14068         if (slash == NULL) {
14069                 pn = NULL;
14070         } else {
14071                 *slash = '\0';
14072                 pn = slash + 1;
14073         }
14074 
14075         if (cur_inst != NULL)
14076                 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14077         else
14078                 ret = scf_service_get_pg(cur_svc, pgn, pg);
14079         if (ret != SCF_SUCCESS) {
14080                 switch (scf_error()) {
14081                 case SCF_ERROR_NOT_FOUND:
14082                         semerr(emsg_no_such_pg, pgn);
14083                         break;
14084 
14085                 case SCF_ERROR_INVALID_ARGUMENT:
14086                         semerr(emsg_invalid_pg_name, pgn);
14087                         break;
14088 
14089                 default:
14090                         scfdie();
14091                 }
14092 
14093                 scf_pg_destroy(pg);
14094 
14095                 return;
14096         }
14097 
14098         if (pn == NULL) {
14099                 /* Try to delete the property group. */
14100                 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14101                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14102                                 scfdie();
14103 
14104                         semerr(emsg_permission_denied);
14105                 } else {
14106                         private_refresh();
14107                 }
14108 
14109                 scf_pg_destroy(pg);
14110                 return;
14111         }
14112 
14113         e = scf_entry_create(g_hndl);
14114         tx = scf_transaction_create(g_hndl);
14115 
14116         do {
14117                 if (scf_pg_update(pg) == -1)
14118                         scfdie();
14119                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14120                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14121                                 scfdie();
14122 
14123                         semerr(emsg_permission_denied);
14124                         break;
14125                 }
14126 
14127                 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14128                         if (scf_error() == SCF_ERROR_NOT_FOUND) {
14129                                 semerr(gettext("No such property %s/%s.\n"),
14130                                     pgn, pn);
14131                                 break;
14132                         } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14133                                 semerr(emsg_invalid_prop_name, pn);
14134                                 break;
14135                         } else {
14136                                 scfdie();
14137                         }
14138                 }
14139 
14140                 ret = scf_transaction_commit(tx);
14141 
14142                 if (ret == 0)
14143                         scf_transaction_reset(tx);
14144         } while (ret == 0);
14145 
14146         if (ret < 0) {
14147                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14148                         scfdie();
14149 
14150                 semerr(emsg_permission_denied);
14151         } else {
14152                 private_refresh();
14153         }
14154 
14155         scf_transaction_destroy(tx);
14156         scf_entry_destroy(e);
14157         scf_pg_destroy(pg);
14158 }
14159 
14160 /*
14161  * Property editing.
14162  */
14163 
14164 static int
14165 write_edit_script(FILE *strm)
14166 {
14167         char *fmribuf;
14168         ssize_t fmrilen;
14169 
14170         scf_propertygroup_t *pg;
14171         scf_property_t *prop;
14172         scf_value_t *val;
14173         scf_type_t ty;
14174         int ret, result = 0;
14175         scf_iter_t *iter, *piter, *viter;
14176         char *buf, *tybuf, *pname;
14177         const char *emsg_write_error;
14178 
14179 
14180         emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14181 
14182 
14183         /* select fmri */
14184         if (cur_inst != NULL) {
14185                 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14186                 if (fmrilen < 0)
14187                         scfdie();
14188                 fmribuf = safe_malloc(fmrilen + 1);
14189                 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14190                         scfdie();
14191         } else {
14192                 assert(cur_svc != NULL);
14193                 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14194                 if (fmrilen < 0)
14195                         scfdie();
14196                 fmribuf = safe_malloc(fmrilen + 1);
14197                 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14198                         scfdie();
14199         }
14200 
14201         if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14202                 warn(emsg_write_error, strerror(errno));
14203                 free(fmribuf);
14204                 return (-1);
14205         }
14206 
14207         free(fmribuf);
14208 
14209 
14210         if ((pg = scf_pg_create(g_hndl)) == NULL ||
14211             (prop = scf_property_create(g_hndl)) == NULL ||
14212             (val = scf_value_create(g_hndl)) == NULL ||
14213             (iter = scf_iter_create(g_hndl)) == NULL ||
14214             (piter = scf_iter_create(g_hndl)) == NULL ||
14215             (viter = scf_iter_create(g_hndl)) == NULL)
14216                 scfdie();
14217 
14218         buf = safe_malloc(max_scf_name_len + 1);
14219         tybuf = safe_malloc(max_scf_pg_type_len + 1);
14220         pname = safe_malloc(max_scf_name_len + 1);
14221 
14222         if (cur_inst != NULL)
14223                 ret = scf_iter_instance_pgs(iter, cur_inst);
14224         else
14225                 ret = scf_iter_service_pgs(iter, cur_svc);
14226         if (ret != SCF_SUCCESS)
14227                 scfdie();
14228 
14229         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14230                 int ret2;
14231 
14232                 /*
14233                  * # delprop pg
14234                  * # addpg pg type
14235                  */
14236                 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14237                         scfdie();
14238 
14239                 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14240                         scfdie();
14241 
14242                 if (fprintf(strm, "# Property group \"%s\"\n"
14243                     "# delprop %s\n"
14244                     "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14245                         warn(emsg_write_error, strerror(errno));
14246                         result = -1;
14247                         goto out;
14248                 }
14249 
14250                 /* # setprop pg/prop = (values) */
14251 
14252                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14253                         scfdie();
14254 
14255                 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14256                         int first = 1;
14257                         int ret3;
14258                         int multiple;
14259                         int is_str;
14260                         scf_type_t bty;
14261 
14262                         if (scf_property_get_name(prop, pname,
14263                             max_scf_name_len + 1) < 0)
14264                                 scfdie();
14265 
14266                         if (scf_property_type(prop, &ty) != 0)
14267                                 scfdie();
14268 
14269                         multiple = prop_has_multiple_values(prop, val);
14270 
14271                         if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14272                             pname, scf_type_to_string(ty), multiple ? "(" : "")
14273                             < 0) {
14274                                 warn(emsg_write_error, strerror(errno));
14275                                 result = -1;
14276                                 goto out;
14277                         }
14278 
14279                         (void) scf_type_base_type(ty, &bty);
14280                         is_str = (bty == SCF_TYPE_ASTRING);
14281 
14282                         if (scf_iter_property_values(viter, prop) !=
14283                             SCF_SUCCESS)
14284                                 scfdie();
14285 
14286                         while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14287                                 char *buf;
14288                                 ssize_t buflen;
14289 
14290                                 buflen = scf_value_get_as_string(val, NULL, 0);
14291                                 if (buflen < 0)
14292                                         scfdie();
14293 
14294                                 buf = safe_malloc(buflen + 1);
14295 
14296                                 if (scf_value_get_as_string(val, buf,
14297                                     buflen + 1) < 0)
14298                                         scfdie();
14299 
14300                                 if (first)
14301                                         first = 0;
14302                                 else {
14303                                         if (putc(' ', strm) != ' ') {
14304                                                 warn(emsg_write_error,
14305                                                     strerror(errno));
14306                                                 result = -1;
14307                                                 goto out;
14308                                         }
14309                                 }
14310 
14311                                 if ((is_str && multiple) ||
14312                                     strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14313                                         (void) putc('"', strm);
14314                                         (void) quote_and_print(buf, strm, 1);
14315                                         (void) putc('"', strm);
14316 
14317                                         if (ferror(strm)) {
14318                                                 warn(emsg_write_error,
14319                                                     strerror(errno));
14320                                                 result = -1;
14321                                                 goto out;
14322                                         }
14323                                 } else {
14324                                         if (fprintf(strm, "%s", buf) < 0) {
14325                                                 warn(emsg_write_error,
14326                                                     strerror(errno));
14327                                                 result = -1;
14328                                                 goto out;
14329                                         }
14330                                 }
14331 
14332                                 free(buf);
14333                         }
14334                         if (ret3 < 0 &&
14335                             scf_error() != SCF_ERROR_PERMISSION_DENIED)
14336                                 scfdie();
14337 
14338                         /* Write closing paren if mult-value property */
14339                         if ((multiple && putc(')', strm) == EOF) ||
14340 
14341                             /* Write final newline */
14342                             fputc('\n', strm) == EOF) {
14343                                 warn(emsg_write_error, strerror(errno));
14344                                 result = -1;
14345                                 goto out;
14346                         }
14347                 }
14348                 if (ret2 < 0)
14349                         scfdie();
14350 
14351                 if (fputc('\n', strm) == EOF) {
14352                         warn(emsg_write_error, strerror(errno));
14353                         result = -1;
14354                         goto out;
14355                 }
14356         }
14357         if (ret < 0)
14358                 scfdie();
14359 
14360 out:
14361         free(pname);
14362         free(tybuf);
14363         free(buf);
14364         scf_iter_destroy(viter);
14365         scf_iter_destroy(piter);
14366         scf_iter_destroy(iter);
14367         scf_value_destroy(val);
14368         scf_property_destroy(prop);
14369         scf_pg_destroy(pg);
14370 
14371         if (result == 0) {
14372                 if (fflush(strm) != 0) {
14373                         warn(emsg_write_error, strerror(errno));
14374                         return (-1);
14375                 }
14376         }
14377 
14378         return (result);
14379 }
14380 
14381 int
14382 lscf_editprop()
14383 {
14384         char *buf, *editor;
14385         size_t bufsz;
14386         int tmpfd;
14387         char tempname[] = TEMP_FILE_PATTERN;
14388 
14389         lscf_prep_hndl();
14390 
14391         if (cur_snap != NULL) {
14392                 semerr(emsg_cant_modify_snapshots);
14393                 return (-1);
14394         }
14395 
14396         if (cur_svc == NULL && cur_inst == NULL) {
14397                 semerr(emsg_entity_not_selected);
14398                 return (-1);
14399         }
14400 
14401         tmpfd = mkstemp(tempname);
14402         if (tmpfd == -1) {
14403                 semerr(gettext("Could not create temporary file.\n"));
14404                 return (-1);
14405         }
14406 
14407         (void) strcpy(tempfilename, tempname);
14408 
14409         tempfile = fdopen(tmpfd, "r+");
14410         if (tempfile == NULL) {
14411                 warn(gettext("Could not create temporary file.\n"));
14412                 if (close(tmpfd) == -1)
14413                         warn(gettext("Could not close temporary file: %s.\n"),
14414                             strerror(errno));
14415 
14416                 remove_tempfile();
14417 
14418                 return (-1);
14419         }
14420 
14421         if (write_edit_script(tempfile) == -1) {
14422                 remove_tempfile();
14423                 return (-1);
14424         }
14425 
14426         editor = getenv("EDITOR");
14427         if (editor == NULL)
14428                 editor = "vi";
14429 
14430         bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14431         buf = safe_malloc(bufsz);
14432 
14433         if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14434                 uu_die(gettext("Error creating editor command"));
14435 
14436         if (system(buf) == -1) {
14437                 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14438                     strerror(errno));
14439                 free(buf);
14440                 remove_tempfile();
14441                 return (-1);
14442         }
14443 
14444         free(buf);
14445 
14446         (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14447 
14448         remove_tempfile();
14449 
14450         return (0);
14451 }
14452 
14453 static void
14454 add_string(uu_list_t *strlist, const char *str)
14455 {
14456         string_list_t *elem;
14457         elem = safe_malloc(sizeof (*elem));
14458         uu_list_node_init(elem, &elem->node, string_pool);
14459         elem->str = safe_strdup(str);
14460         if (uu_list_append(strlist, elem) != 0)
14461                 uu_die(gettext("libuutil error: %s\n"),
14462                     uu_strerror(uu_error()));
14463 }
14464 
14465 static int
14466 remove_string(uu_list_t *strlist, const char *str)
14467 {
14468         uu_list_walk_t  *elems;
14469         string_list_t   *sp;
14470 
14471         /*
14472          * Find the element that needs to be removed.
14473          */
14474         elems = uu_list_walk_start(strlist, UU_DEFAULT);
14475         while ((sp = uu_list_walk_next(elems)) != NULL) {
14476                 if (strcmp(sp->str, str) == 0)
14477                         break;
14478         }
14479         uu_list_walk_end(elems);
14480 
14481         /*
14482          * Returning 1 here as the value was not found, this
14483          * might not be an error.  Leave it to the caller to
14484          * decide.
14485          */
14486         if (sp == NULL) {
14487                 return (1);
14488         }
14489 
14490         uu_list_remove(strlist, sp);
14491 
14492         free(sp->str);
14493         free(sp);
14494 
14495         return (0);
14496 }
14497 
14498 /*
14499  * Get all property values that don't match the given glob pattern,
14500  * if a pattern is specified.
14501  */
14502 static void
14503 get_prop_values(scf_property_t *prop, uu_list_t *values,
14504     const char *pattern)
14505 {
14506         scf_iter_t *iter;
14507         scf_value_t *val;
14508         int ret;
14509 
14510         if ((iter = scf_iter_create(g_hndl)) == NULL ||
14511             (val = scf_value_create(g_hndl)) == NULL)
14512                 scfdie();
14513 
14514         if (scf_iter_property_values(iter, prop) != 0)
14515                 scfdie();
14516 
14517         while ((ret = scf_iter_next_value(iter, val)) == 1) {
14518                 char *buf;
14519                 ssize_t vlen, szret;
14520 
14521                 vlen = scf_value_get_as_string(val, NULL, 0);
14522                 if (vlen < 0)
14523                         scfdie();
14524 
14525                 buf = safe_malloc(vlen + 1);
14526 
14527                 szret = scf_value_get_as_string(val, buf, vlen + 1);
14528                 if (szret < 0)
14529                         scfdie();
14530                 assert(szret <= vlen);
14531 
14532                 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14533                         add_string(values, buf);
14534 
14535                 free(buf);
14536         }
14537 
14538         if (ret == -1)
14539                 scfdie();
14540 
14541         scf_value_destroy(val);
14542         scf_iter_destroy(iter);
14543 }
14544 
14545 static int
14546 lscf_setpropvalue(const char *pgname, const char *type,
14547     const char *arg, int isadd, int isnotfoundok)
14548 {
14549         scf_type_t ty;
14550         scf_propertygroup_t *pg;
14551         scf_property_t *prop;
14552         int ret, result = 0;
14553         scf_transaction_t *tx;
14554         scf_transaction_entry_t *e;
14555         scf_value_t *v;
14556         string_list_t *sp;
14557         char *propname;
14558         uu_list_t *values;
14559         uu_list_walk_t *walk;
14560         void *cookie = NULL;
14561         char *pattern = NULL;
14562 
14563         lscf_prep_hndl();
14564 
14565         if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14566                 uu_die(gettext("Could not create property list: %s\n"),
14567                     uu_strerror(uu_error()));
14568 
14569         if (!isadd)
14570                 pattern = safe_strdup(arg);
14571 
14572         if ((e = scf_entry_create(g_hndl)) == NULL ||
14573             (pg = scf_pg_create(g_hndl)) == NULL ||
14574             (prop = scf_property_create(g_hndl)) == NULL ||
14575             (tx = scf_transaction_create(g_hndl)) == NULL)
14576                 scfdie();
14577 
14578         if (cur_snap != NULL) {
14579                 semerr(emsg_cant_modify_snapshots);
14580                 goto fail;
14581         }
14582 
14583         if (cur_inst == NULL && cur_svc == NULL) {
14584                 semerr(emsg_entity_not_selected);
14585                 goto fail;
14586         }
14587 
14588         propname = strchr(pgname, '/');
14589         if (propname == NULL) {
14590                 semerr(gettext("Property names must contain a `/'.\n"));
14591                 goto fail;
14592         }
14593 
14594         *propname = '\0';
14595         ++propname;
14596 
14597         if (type != NULL) {
14598                 ty = string_to_type(type);
14599                 if (ty == SCF_TYPE_INVALID) {
14600                         semerr(gettext("Unknown type \"%s\".\n"), type);
14601                         goto fail;
14602                 }
14603         }
14604 
14605         if (cur_inst != NULL)
14606                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14607         else
14608                 ret = scf_service_get_pg(cur_svc, pgname, pg);
14609         if (ret != 0) {
14610                 switch (scf_error()) {
14611                 case SCF_ERROR_NOT_FOUND:
14612                         if (isnotfoundok) {
14613                                 result = 0;
14614                         } else {
14615                                 semerr(emsg_no_such_pg, pgname);
14616                                 result = -1;
14617                         }
14618                         goto out;
14619 
14620                 case SCF_ERROR_INVALID_ARGUMENT:
14621                         semerr(emsg_invalid_pg_name, pgname);
14622                         goto fail;
14623 
14624                 default:
14625                         scfdie();
14626                 }
14627         }
14628 
14629         do {
14630                 if (scf_pg_update(pg) == -1)
14631                         scfdie();
14632                 if (scf_transaction_start(tx, pg) != 0) {
14633                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14634                                 scfdie();
14635 
14636                         semerr(emsg_permission_denied);
14637                         goto fail;
14638                 }
14639 
14640                 ret = scf_pg_get_property(pg, propname, prop);
14641                 if (ret == 0) {
14642                         scf_type_t ptype;
14643                         char *pat = pattern;
14644 
14645                         if (scf_property_type(prop, &ptype) != 0)
14646                                 scfdie();
14647 
14648                         if (isadd) {
14649                                 if (type != NULL && ptype != ty) {
14650                                         semerr(gettext("Property \"%s\" is not "
14651                                             "of type \"%s\".\n"), propname,
14652                                             type);
14653                                         goto fail;
14654                                 }
14655 
14656                                 pat = NULL;
14657                         } else {
14658                                 size_t len = strlen(pat);
14659                                 if (len > 0 && pat[len - 1] == '\"')
14660                                         pat[len - 1] = '\0';
14661                                 if (len > 0 && pat[0] == '\"')
14662                                         pat++;
14663                         }
14664 
14665                         ty = ptype;
14666 
14667                         get_prop_values(prop, values, pat);
14668 
14669                         if (isadd)
14670                                 add_string(values, arg);
14671 
14672                         if (scf_transaction_property_change(tx, e,
14673                             propname, ty) == -1)
14674                                 scfdie();
14675                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14676                         if (isadd) {
14677                                 if (type == NULL) {
14678                                         semerr(gettext("Type required "
14679                                             "for new properties.\n"));
14680                                         goto fail;
14681                                 }
14682 
14683                                 add_string(values, arg);
14684 
14685                                 if (scf_transaction_property_new(tx, e,
14686                                     propname, ty) == -1)
14687                                         scfdie();
14688                         } else if (isnotfoundok) {
14689                                 result = 0;
14690                                 goto out;
14691                         } else {
14692                                 semerr(gettext("No such property %s/%s.\n"),
14693                                     pgname, propname);
14694                                 result = -1;
14695                                 goto out;
14696                         }
14697                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14698                         semerr(emsg_invalid_prop_name, propname);
14699                         goto fail;
14700                 } else {
14701                         scfdie();
14702                 }
14703 
14704                 walk = uu_list_walk_start(values, UU_DEFAULT);
14705                 if (walk == NULL)
14706                         uu_die(gettext("Could not walk property list.\n"));
14707 
14708                 for (sp = uu_list_walk_next(walk); sp != NULL;
14709                     sp = uu_list_walk_next(walk)) {
14710                         v = string_to_value(sp->str, ty, 0);
14711 
14712                         if (v == NULL) {
14713                                 scf_entry_destroy_children(e);
14714                                 goto fail;
14715                         }
14716                         ret = scf_entry_add_value(e, v);
14717                         assert(ret == 0);
14718                 }
14719                 uu_list_walk_end(walk);
14720 
14721                 result = scf_transaction_commit(tx);
14722 
14723                 scf_transaction_reset(tx);
14724                 scf_entry_destroy_children(e);
14725         } while (result == 0);
14726 
14727         if (result < 0) {
14728                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14729                         scfdie();
14730 
14731                 semerr(emsg_permission_denied);
14732                 goto fail;
14733         }
14734 
14735         result = 0;
14736 
14737         private_refresh();
14738 
14739 out:
14740         scf_transaction_destroy(tx);
14741         scf_entry_destroy(e);
14742         scf_pg_destroy(pg);
14743         scf_property_destroy(prop);
14744         free(pattern);
14745 
14746         while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14747                 free(sp->str);
14748                 free(sp);
14749         }
14750 
14751         uu_list_destroy(values);
14752 
14753         return (result);
14754 
14755 fail:
14756         result = -1;
14757         goto out;
14758 }
14759 
14760 int
14761 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14762 {
14763         return (lscf_setpropvalue(pgname, type, value, 1, 0));
14764 }
14765 
14766 int
14767 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14768 {
14769         return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14770 }
14771 
14772 /*
14773  * Look for a standard start method, first in the instance (if any),
14774  * then the service.
14775  */
14776 static const char *
14777 start_method_name(int *in_instance)
14778 {
14779         scf_propertygroup_t *pg;
14780         char **p;
14781         int ret;
14782         scf_instance_t *inst = cur_inst;
14783 
14784         if ((pg = scf_pg_create(g_hndl)) == NULL)
14785                 scfdie();
14786 
14787 again:
14788         for (p = start_method_names; *p != NULL; p++) {
14789                 if (inst != NULL)
14790                         ret = scf_instance_get_pg(inst, *p, pg);
14791                 else
14792                         ret = scf_service_get_pg(cur_svc, *p, pg);
14793 
14794                 if (ret == 0) {
14795                         size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14796                         char *buf = safe_malloc(bufsz);
14797 
14798                         if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14799                                 free(buf);
14800                                 continue;
14801                         }
14802                         if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14803                                 free(buf);
14804                                 continue;
14805                         }
14806 
14807                         free(buf);
14808                         *in_instance = (inst != NULL);
14809                         scf_pg_destroy(pg);
14810                         return (*p);
14811                 }
14812 
14813                 if (scf_error() == SCF_ERROR_NOT_FOUND)
14814                         continue;
14815 
14816                 scfdie();
14817         }
14818 
14819         if (inst != NULL) {
14820                 inst = NULL;
14821                 goto again;
14822         }
14823 
14824         scf_pg_destroy(pg);
14825         return (NULL);
14826 }
14827 
14828 static int
14829 addpg(const char *name, const char *type)
14830 {
14831         scf_propertygroup_t *pg;
14832         int ret;
14833 
14834         pg = scf_pg_create(g_hndl);
14835         if (pg == NULL)
14836                 scfdie();
14837 
14838         if (cur_inst != NULL)
14839                 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14840         else
14841                 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14842 
14843         if (ret != 0) {
14844                 switch (scf_error()) {
14845                 case SCF_ERROR_EXISTS:
14846                         ret = 0;
14847                         break;
14848 
14849                 case SCF_ERROR_PERMISSION_DENIED:
14850                         semerr(emsg_permission_denied);
14851                         break;
14852 
14853                 default:
14854                         scfdie();
14855                 }
14856         }
14857 
14858         scf_pg_destroy(pg);
14859         return (ret);
14860 }
14861 
14862 int
14863 lscf_setenv(uu_list_t *args, int isunset)
14864 {
14865         int ret = 0;
14866         size_t i;
14867         int argc;
14868         char **argv = NULL;
14869         string_list_t *slp;
14870         char *pattern;
14871         char *prop;
14872         int do_service = 0;
14873         int do_instance = 0;
14874         const char *method = NULL;
14875         const char *name = NULL;
14876         const char *value = NULL;
14877         scf_instance_t *saved_cur_inst = cur_inst;
14878 
14879         lscf_prep_hndl();
14880 
14881         argc = uu_list_numnodes(args);
14882         if (argc < 1)
14883                 goto usage;
14884 
14885         argv = calloc(argc + 1, sizeof (char *));
14886         if (argv == NULL)
14887                 uu_die(gettext("Out of memory.\n"));
14888 
14889         for (slp = uu_list_first(args), i = 0;
14890             slp != NULL;
14891             slp = uu_list_next(args, slp), ++i)
14892                 argv[i] = slp->str;
14893 
14894         argv[i] = NULL;
14895 
14896         opterr = 0;
14897         optind = 0;
14898         for (;;) {
14899                 ret = getopt(argc, argv, "sim:");
14900                 if (ret == -1)
14901                         break;
14902 
14903                 switch (ret) {
14904                 case 's':
14905                         do_service = 1;
14906                         cur_inst = NULL;
14907                         break;
14908 
14909                 case 'i':
14910                         do_instance = 1;
14911                         break;
14912 
14913                 case 'm':
14914                         method = optarg;
14915                         break;
14916 
14917                 case '?':
14918                         goto usage;
14919 
14920                 default:
14921                         bad_error("getopt", ret);
14922                 }
14923         }
14924 
14925         argc -= optind;
14926         if ((do_service && do_instance) ||
14927             (isunset && argc != 1) ||
14928             (!isunset && argc != 2))
14929                 goto usage;
14930 
14931         name = argv[optind];
14932         if (!isunset)
14933                 value = argv[optind + 1];
14934 
14935         if (cur_snap != NULL) {
14936                 semerr(emsg_cant_modify_snapshots);
14937                 ret = -1;
14938                 goto out;
14939         }
14940 
14941         if (cur_inst == NULL && cur_svc == NULL) {
14942                 semerr(emsg_entity_not_selected);
14943                 ret = -1;
14944                 goto out;
14945         }
14946 
14947         if (do_instance && cur_inst == NULL) {
14948                 semerr(gettext("No instance is selected.\n"));
14949                 ret = -1;
14950                 goto out;
14951         }
14952 
14953         if (do_service && cur_svc == NULL) {
14954                 semerr(gettext("No service is selected.\n"));
14955                 ret = -1;
14956                 goto out;
14957         }
14958 
14959         if (method == NULL) {
14960                 if (do_instance || do_service) {
14961                         method = "method_context";
14962                         if (!isunset) {
14963                                 ret = addpg("method_context",
14964                                     SCF_GROUP_FRAMEWORK);
14965                                 if (ret != 0)
14966                                         goto out;
14967                         }
14968                 } else {
14969                         int in_instance;
14970                         method = start_method_name(&in_instance);
14971                         if (method == NULL) {
14972                                 semerr(gettext(
14973                                     "Couldn't find start method; please "
14974                                     "specify a method with '-m'.\n"));
14975                                 ret = -1;
14976                                 goto out;
14977                         }
14978                         if (!in_instance)
14979                                 cur_inst = NULL;
14980                 }
14981         } else {
14982                 scf_propertygroup_t *pg;
14983                 size_t bufsz;
14984                 char *buf;
14985                 int ret;
14986 
14987                 if ((pg = scf_pg_create(g_hndl)) == NULL)
14988                         scfdie();
14989 
14990                 if (cur_inst != NULL)
14991                         ret = scf_instance_get_pg(cur_inst, method, pg);
14992                 else
14993                         ret = scf_service_get_pg(cur_svc, method, pg);
14994 
14995                 if (ret != 0) {
14996                         scf_pg_destroy(pg);
14997                         switch (scf_error()) {
14998                         case SCF_ERROR_NOT_FOUND:
14999                                 semerr(gettext("Couldn't find the method "
15000                                     "\"%s\".\n"), method);
15001                                 goto out;
15002 
15003                         case SCF_ERROR_INVALID_ARGUMENT:
15004                                 semerr(gettext("Invalid method name \"%s\".\n"),
15005                                     method);
15006                                 goto out;
15007 
15008                         default:
15009                                 scfdie();
15010                         }
15011                 }
15012 
15013                 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15014                 buf = safe_malloc(bufsz);
15015 
15016                 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15017                     strcmp(buf, SCF_GROUP_METHOD) != 0) {
15018                         semerr(gettext("Property group \"%s\" is not of type "
15019                             "\"method\".\n"), method);
15020                         ret = -1;
15021                         free(buf);
15022                         scf_pg_destroy(pg);
15023                         goto out;
15024                 }
15025 
15026                 free(buf);
15027                 scf_pg_destroy(pg);
15028         }
15029 
15030         prop = uu_msprintf("%s/environment", method);
15031         pattern = uu_msprintf("%s=*", name);
15032 
15033         if (prop == NULL || pattern == NULL)
15034                 uu_die(gettext("Out of memory.\n"));
15035 
15036         ret = lscf_delpropvalue(prop, pattern, !isunset);
15037 
15038         if (ret == 0 && !isunset) {
15039                 uu_free(pattern);
15040                 uu_free(prop);
15041                 prop = uu_msprintf("%s/environment", method);
15042                 pattern = uu_msprintf("%s=%s", name, value);
15043                 if (prop == NULL || pattern == NULL)
15044                         uu_die(gettext("Out of memory.\n"));
15045                 ret = lscf_addpropvalue(prop, "astring:", pattern);
15046         }
15047         uu_free(pattern);
15048         uu_free(prop);
15049 
15050 out:
15051         cur_inst = saved_cur_inst;
15052 
15053         free(argv);
15054         return (ret);
15055 usage:
15056         ret = -2;
15057         goto out;
15058 }
15059 
15060 /*
15061  * Snapshot commands
15062  */
15063 
15064 void
15065 lscf_listsnap()
15066 {
15067         scf_snapshot_t *snap;
15068         scf_iter_t *iter;
15069         char *nb;
15070         int r;
15071 
15072         lscf_prep_hndl();
15073 
15074         if (cur_inst == NULL) {
15075                 semerr(gettext("Instance not selected.\n"));
15076                 return;
15077         }
15078 
15079         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15080             (iter = scf_iter_create(g_hndl)) == NULL)
15081                 scfdie();
15082 
15083         if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15084                 scfdie();
15085 
15086         nb = safe_malloc(max_scf_name_len + 1);
15087 
15088         while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15089                 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15090                         scfdie();
15091 
15092                 (void) puts(nb);
15093         }
15094         if (r < 0)
15095                 scfdie();
15096 
15097         free(nb);
15098         scf_iter_destroy(iter);
15099         scf_snapshot_destroy(snap);
15100 }
15101 
15102 void
15103 lscf_selectsnap(const char *name)
15104 {
15105         scf_snapshot_t *snap;
15106         scf_snaplevel_t *level;
15107 
15108         lscf_prep_hndl();
15109 
15110         if (cur_inst == NULL) {
15111                 semerr(gettext("Instance not selected.\n"));
15112                 return;
15113         }
15114 
15115         if (cur_snap != NULL) {
15116                 if (name != NULL) {
15117                         char *cur_snap_name;
15118                         boolean_t nochange;
15119 
15120                         cur_snap_name = safe_malloc(max_scf_name_len + 1);
15121 
15122                         if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15123                             max_scf_name_len + 1) < 0)
15124                                 scfdie();
15125 
15126                         nochange = strcmp(name, cur_snap_name) == 0;
15127 
15128                         free(cur_snap_name);
15129 
15130                         if (nochange)
15131                                 return;
15132                 }
15133 
15134                 unselect_cursnap();
15135         }
15136 
15137         if (name == NULL)
15138                 return;
15139 
15140         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15141             (level = scf_snaplevel_create(g_hndl)) == NULL)
15142                 scfdie();
15143 
15144         if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15145             SCF_SUCCESS) {
15146                 switch (scf_error()) {
15147                 case SCF_ERROR_INVALID_ARGUMENT:
15148                         semerr(gettext("Invalid name \"%s\".\n"), name);
15149                         break;
15150 
15151                 case SCF_ERROR_NOT_FOUND:
15152                         semerr(gettext("No such snapshot \"%s\".\n"), name);
15153                         break;
15154 
15155                 default:
15156                         scfdie();
15157                 }
15158 
15159                 scf_snaplevel_destroy(level);
15160                 scf_snapshot_destroy(snap);
15161                 return;
15162         }
15163 
15164         /* Load the snaplevels into our list. */
15165         cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15166         if (cur_levels == NULL)
15167                 uu_die(gettext("Could not create list: %s\n"),
15168                     uu_strerror(uu_error()));
15169 
15170         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15171                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15172                         scfdie();
15173 
15174                 semerr(gettext("Snapshot has no snaplevels.\n"));
15175 
15176                 scf_snaplevel_destroy(level);
15177                 scf_snapshot_destroy(snap);
15178                 return;
15179         }
15180 
15181         cur_snap = snap;
15182 
15183         for (;;) {
15184                 cur_elt = safe_malloc(sizeof (*cur_elt));
15185                 uu_list_node_init(cur_elt, &cur_elt->list_node,
15186                     snaplevel_pool);
15187                 cur_elt->sl = level;
15188                 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15189                         uu_die(gettext("libuutil error: %s\n"),
15190                             uu_strerror(uu_error()));
15191 
15192                 level = scf_snaplevel_create(g_hndl);
15193                 if (level == NULL)
15194                         scfdie();
15195 
15196                 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15197                     level) != SCF_SUCCESS) {
15198                         if (scf_error() != SCF_ERROR_NOT_FOUND)
15199                                 scfdie();
15200 
15201                         scf_snaplevel_destroy(level);
15202                         break;
15203                 }
15204         }
15205 
15206         cur_elt = uu_list_last(cur_levels);
15207         cur_level = cur_elt->sl;
15208 }
15209 
15210 /*
15211  * Copies the properties & values in src to dst.  Assumes src won't change.
15212  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15213  * and 0 on success.
15214  *
15215  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15216  * property, if it is copied and has type boolean.  (See comment in
15217  * lscf_revert()).
15218  */
15219 static int
15220 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15221     uint8_t enabled)
15222 {
15223         scf_transaction_t *tx;
15224         scf_iter_t *iter, *viter;
15225         scf_property_t *prop;
15226         scf_value_t *v;
15227         char *nbuf;
15228         int r;
15229 
15230         tx = scf_transaction_create(g_hndl);
15231         if (tx == NULL)
15232                 scfdie();
15233 
15234         if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15235                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15236                         scfdie();
15237 
15238                 scf_transaction_destroy(tx);
15239 
15240                 return (-1);
15241         }
15242 
15243         if ((iter = scf_iter_create(g_hndl)) == NULL ||
15244             (prop = scf_property_create(g_hndl)) == NULL ||
15245             (viter = scf_iter_create(g_hndl)) == NULL)
15246                 scfdie();
15247 
15248         nbuf = safe_malloc(max_scf_name_len + 1);
15249 
15250         if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15251                 scfdie();
15252 
15253         for (;;) {
15254                 scf_transaction_entry_t *e;
15255                 scf_type_t ty;
15256 
15257                 r = scf_iter_next_property(iter, prop);
15258                 if (r == -1)
15259                         scfdie();
15260                 if (r == 0)
15261                         break;
15262 
15263                 e = scf_entry_create(g_hndl);
15264                 if (e == NULL)
15265                         scfdie();
15266 
15267                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15268                         scfdie();
15269 
15270                 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15271                         scfdie();
15272 
15273                 if (scf_transaction_property_new(tx, e, nbuf,
15274                     ty) != SCF_SUCCESS)
15275                         scfdie();
15276 
15277                 if ((enabled == 0 || enabled == 1) &&
15278                     strcmp(nbuf, scf_property_enabled) == 0 &&
15279                     ty == SCF_TYPE_BOOLEAN) {
15280                         v = scf_value_create(g_hndl);
15281                         if (v == NULL)
15282                                 scfdie();
15283 
15284                         scf_value_set_boolean(v, enabled);
15285 
15286                         if (scf_entry_add_value(e, v) != 0)
15287                                 scfdie();
15288                 } else {
15289                         if (scf_iter_property_values(viter, prop) != 0)
15290                                 scfdie();
15291 
15292                         for (;;) {
15293                                 v = scf_value_create(g_hndl);
15294                                 if (v == NULL)
15295                                         scfdie();
15296 
15297                                 r = scf_iter_next_value(viter, v);
15298                                 if (r == -1)
15299                                         scfdie();
15300                                 if (r == 0) {
15301                                         scf_value_destroy(v);
15302                                         break;
15303                                 }
15304 
15305                                 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15306                                         scfdie();
15307                         }
15308                 }
15309         }
15310 
15311         free(nbuf);
15312         scf_iter_destroy(viter);
15313         scf_property_destroy(prop);
15314         scf_iter_destroy(iter);
15315 
15316         r = scf_transaction_commit(tx);
15317         if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15318                 scfdie();
15319 
15320         scf_transaction_destroy_children(tx);
15321         scf_transaction_destroy(tx);
15322 
15323         switch (r) {
15324         case 1:         return (0);
15325         case 0:         return (-2);
15326         case -1:        return (-1);
15327 
15328         default:
15329                 abort();
15330         }
15331 
15332         /* NOTREACHED */
15333 }
15334 
15335 void
15336 lscf_revert(const char *snapname)
15337 {
15338         scf_snapshot_t *snap, *prev;
15339         scf_snaplevel_t *level, *nlevel;
15340         scf_iter_t *iter;
15341         scf_propertygroup_t *pg, *npg;
15342         scf_property_t *prop;
15343         scf_value_t *val;
15344         char *nbuf, *tbuf;
15345         uint8_t enabled;
15346 
15347         lscf_prep_hndl();
15348 
15349         if (cur_inst == NULL) {
15350                 semerr(gettext("Instance not selected.\n"));
15351                 return;
15352         }
15353 
15354         if (snapname != NULL) {
15355                 snap = scf_snapshot_create(g_hndl);
15356                 if (snap == NULL)
15357                         scfdie();
15358 
15359                 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15360                     SCF_SUCCESS) {
15361                         switch (scf_error()) {
15362                         case SCF_ERROR_INVALID_ARGUMENT:
15363                                 semerr(gettext("Invalid snapshot name "
15364                                     "\"%s\".\n"), snapname);
15365                                 break;
15366 
15367                         case SCF_ERROR_NOT_FOUND:
15368                                 semerr(gettext("No such snapshot.\n"));
15369                                 break;
15370 
15371                         default:
15372                                 scfdie();
15373                         }
15374 
15375                         scf_snapshot_destroy(snap);
15376                         return;
15377                 }
15378         } else {
15379                 if (cur_snap != NULL) {
15380                         snap = cur_snap;
15381                 } else {
15382                         semerr(gettext("No snapshot selected.\n"));
15383                         return;
15384                 }
15385         }
15386 
15387         if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15388             (level = scf_snaplevel_create(g_hndl)) == NULL ||
15389             (iter = scf_iter_create(g_hndl)) == NULL ||
15390             (pg = scf_pg_create(g_hndl)) == NULL ||
15391             (npg = scf_pg_create(g_hndl)) == NULL ||
15392             (prop = scf_property_create(g_hndl)) == NULL ||
15393             (val = scf_value_create(g_hndl)) == NULL)
15394                 scfdie();
15395 
15396         nbuf = safe_malloc(max_scf_name_len + 1);
15397         tbuf = safe_malloc(max_scf_pg_type_len + 1);
15398 
15399         /* Take the "previous" snapshot before we blow away the properties. */
15400         if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15401                 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15402                         scfdie();
15403         } else {
15404                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15405                         scfdie();
15406 
15407                 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15408                         scfdie();
15409         }
15410 
15411         /* Save general/enabled, since we're probably going to replace it. */
15412         enabled = 2;
15413         if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15414             scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15415             scf_property_get_value(prop, val) == 0)
15416                 (void) scf_value_get_boolean(val, &enabled);
15417 
15418         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15419                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15420                         scfdie();
15421 
15422                 goto out;
15423         }
15424 
15425         for (;;) {
15426                 boolean_t isinst;
15427                 uint32_t flags;
15428                 int r;
15429 
15430                 /* Clear the properties from the corresponding entity. */
15431                 isinst = snaplevel_is_instance(level);
15432 
15433                 if (!isinst)
15434                         r = scf_iter_service_pgs(iter, cur_svc);
15435                 else
15436                         r = scf_iter_instance_pgs(iter, cur_inst);
15437                 if (r != SCF_SUCCESS)
15438                         scfdie();
15439 
15440                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15441                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15442                                 scfdie();
15443 
15444                         /* Skip nonpersistent pgs. */
15445                         if (flags & SCF_PG_FLAG_NONPERSISTENT)
15446                                 continue;
15447 
15448                         if (scf_pg_delete(pg) != SCF_SUCCESS) {
15449                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15450                                         scfdie();
15451 
15452                                 semerr(emsg_permission_denied);
15453                                 goto out;
15454                         }
15455                 }
15456                 if (r == -1)
15457                         scfdie();
15458 
15459                 /* Copy the properties to the corresponding entity. */
15460                 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15461                         scfdie();
15462 
15463                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15464                         if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15465                                 scfdie();
15466 
15467                         if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15468                             0)
15469                                 scfdie();
15470 
15471                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15472                                 scfdie();
15473 
15474                         if (!isinst)
15475                                 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15476                                     flags, npg);
15477                         else
15478                                 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15479                                     flags, npg);
15480                         if (r != SCF_SUCCESS) {
15481                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15482                                         scfdie();
15483 
15484                                 semerr(emsg_permission_denied);
15485                                 goto out;
15486                         }
15487 
15488                         if ((enabled == 0 || enabled == 1) &&
15489                             strcmp(nbuf, scf_pg_general) == 0)
15490                                 r = pg_copy(pg, npg, enabled);
15491                         else
15492                                 r = pg_copy(pg, npg, 2);
15493 
15494                         switch (r) {
15495                         case 0:
15496                                 break;
15497 
15498                         case -1:
15499                                 semerr(emsg_permission_denied);
15500                                 goto out;
15501 
15502                         case -2:
15503                                 semerr(gettext(
15504                                     "Interrupted by another change.\n"));
15505                                 goto out;
15506 
15507                         default:
15508                                 abort();
15509                         }
15510                 }
15511                 if (r == -1)
15512                         scfdie();
15513 
15514                 /* Get next level. */
15515                 nlevel = scf_snaplevel_create(g_hndl);
15516                 if (nlevel == NULL)
15517                         scfdie();
15518 
15519                 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15520                     SCF_SUCCESS) {
15521                         if (scf_error() != SCF_ERROR_NOT_FOUND)
15522                                 scfdie();
15523 
15524                         scf_snaplevel_destroy(nlevel);
15525                         break;
15526                 }
15527 
15528                 scf_snaplevel_destroy(level);
15529                 level = nlevel;
15530         }
15531 
15532         if (snapname == NULL) {
15533                 lscf_selectsnap(NULL);
15534                 snap = NULL;            /* cur_snap has been destroyed */
15535         }
15536 
15537 out:
15538         free(tbuf);
15539         free(nbuf);
15540         scf_value_destroy(val);
15541         scf_property_destroy(prop);
15542         scf_pg_destroy(npg);
15543         scf_pg_destroy(pg);
15544         scf_iter_destroy(iter);
15545         scf_snaplevel_destroy(level);
15546         scf_snapshot_destroy(prev);
15547         if (snap != cur_snap)
15548                 scf_snapshot_destroy(snap);
15549 }
15550 
15551 void
15552 lscf_refresh(void)
15553 {
15554         ssize_t fmrilen;
15555         size_t bufsz;
15556         char *fmribuf;
15557         int r;
15558 
15559         lscf_prep_hndl();
15560 
15561         if (cur_inst == NULL) {
15562                 semerr(gettext("Instance not selected.\n"));
15563                 return;
15564         }
15565 
15566         bufsz = max_scf_fmri_len + 1;
15567         fmribuf = safe_malloc(bufsz);
15568         fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15569         if (fmrilen < 0) {
15570                 free(fmribuf);
15571                 if (scf_error() != SCF_ERROR_DELETED)
15572                         scfdie();
15573                 scf_instance_destroy(cur_inst);
15574                 cur_inst = NULL;
15575                 warn(emsg_deleted);
15576                 return;
15577         }
15578         assert(fmrilen < bufsz);
15579 
15580         r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15581         switch (r) {
15582         case 0:
15583                 break;
15584 
15585         case ECONNABORTED:
15586                 warn(gettext("Could not refresh %s "
15587                     "(repository connection broken).\n"), fmribuf);
15588                 break;
15589 
15590         case ECANCELED:
15591                 warn(emsg_deleted);
15592                 break;
15593 
15594         case EPERM:
15595                 warn(gettext("Could not refresh %s "
15596                     "(permission denied).\n"), fmribuf);
15597                 break;
15598 
15599         case ENOSPC:
15600                 warn(gettext("Could not refresh %s "
15601                     "(repository server out of resources).\n"),
15602                     fmribuf);
15603                 break;
15604 
15605         case EACCES:
15606         default:
15607                 bad_error("refresh_entity", scf_error());
15608         }
15609 
15610         free(fmribuf);
15611 }
15612 
15613 /*
15614  * describe [-v] [-t] [pg/prop]
15615  */
15616 int
15617 lscf_describe(uu_list_t *args, int hasargs)
15618 {
15619         int ret = 0;
15620         size_t i;
15621         int argc;
15622         char **argv = NULL;
15623         string_list_t *slp;
15624         int do_verbose = 0;
15625         int do_templates = 0;
15626         char *pattern = NULL;
15627 
15628         lscf_prep_hndl();
15629 
15630         if (hasargs != 0)  {
15631                 argc = uu_list_numnodes(args);
15632                 if (argc < 1)
15633                         goto usage;
15634 
15635                 argv = calloc(argc + 1, sizeof (char *));
15636                 if (argv == NULL)
15637                         uu_die(gettext("Out of memory.\n"));
15638 
15639                 for (slp = uu_list_first(args), i = 0;
15640                     slp != NULL;
15641                     slp = uu_list_next(args, slp), ++i)
15642                         argv[i] = slp->str;
15643 
15644                 argv[i] = NULL;
15645 
15646                 /*
15647                  * We start optind = 0 because our list of arguments
15648                  * starts at argv[0]
15649                  */
15650                 optind = 0;
15651                 opterr = 0;
15652                 for (;;) {
15653                         ret = getopt(argc, argv, "vt");
15654                         if (ret == -1)
15655                                 break;
15656 
15657                         switch (ret) {
15658                         case 'v':
15659                                 do_verbose = 1;
15660                                 break;
15661 
15662                         case 't':
15663                                 do_templates = 1;
15664                                 break;
15665 
15666                         case '?':
15667                                 goto usage;
15668 
15669                         default:
15670                                 bad_error("getopt", ret);
15671                         }
15672                 }
15673 
15674                 pattern = argv[optind];
15675         }
15676 
15677         if (cur_inst == NULL && cur_svc == NULL) {
15678                 semerr(emsg_entity_not_selected);
15679                 ret = -1;
15680                 goto out;
15681         }
15682 
15683         /*
15684          * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15685          * output if their last parameter is set to 2.  Less information is
15686          * produced if the parameter is set to 1.
15687          */
15688         if (pattern == NULL) {
15689                 if (do_verbose == 1)
15690                         list_entity_tmpl(2);
15691                 else
15692                         list_entity_tmpl(1);
15693         }
15694 
15695         if (do_templates == 0) {
15696                 if (do_verbose == 1)
15697                         listprop(pattern, 0, 2);
15698                 else
15699                         listprop(pattern, 0, 1);
15700         } else {
15701                 if (do_verbose == 1)
15702                         listtmpl(pattern, 2);
15703                 else
15704                         listtmpl(pattern, 1);
15705         }
15706 
15707         ret = 0;
15708 out:
15709         if (argv != NULL)
15710                 free(argv);
15711         return (ret);
15712 usage:
15713         ret = -2;
15714         goto out;
15715 }
15716 
15717 #define PARAM_ACTIVE    ((const char *) "active")
15718 #define PARAM_INACTIVE  ((const char *) "inactive")
15719 #define PARAM_SMTP_TO   ((const char *) "to")
15720 
15721 /*
15722  * tokenize()
15723  * Breaks down the string according to the tokens passed.
15724  * Caller is responsible for freeing array of pointers returned.
15725  * Returns NULL on failure
15726  */
15727 char **
15728 tokenize(char *str, const char *sep)
15729 {
15730         char *token, *lasts;
15731         char **buf;
15732         int n = 0;      /* number of elements */
15733         int size = 8;   /* size of the array (initial) */
15734 
15735         buf = safe_malloc(size * sizeof (char *));
15736 
15737         for (token = strtok_r(str, sep, &lasts); token != NULL;
15738             token = strtok_r(NULL, sep, &lasts), ++n) {
15739                 if (n + 1 >= size) {
15740                         size *= 2;
15741                         if ((buf = realloc(buf, size * sizeof (char *))) ==
15742                             NULL) {
15743                                 uu_die(gettext("Out of memory"));
15744                         }
15745                 }
15746                 buf[n] = token;
15747         }
15748         /* NULL terminate the pointer array */
15749         buf[n] = NULL;
15750 
15751         return (buf);
15752 }
15753 
15754 int32_t
15755 check_tokens(char **p)
15756 {
15757         int32_t smf = 0;
15758         int32_t fma = 0;
15759 
15760         while (*p) {
15761                 int32_t t = string_to_tset(*p);
15762 
15763                 if (t == 0) {
15764                         if (is_fma_token(*p) == 0)
15765                                 return (INVALID_TOKENS);
15766                         fma = 1; /* this token is an fma event */
15767                 } else {
15768                         smf |= t;
15769                 }
15770 
15771                 if (smf != 0 && fma == 1)
15772                         return (MIXED_TOKENS);
15773                 ++p;
15774         }
15775 
15776         if (smf > 0)
15777                 return (smf);
15778         else if (fma == 1)
15779                 return (FMA_TOKENS);
15780 
15781         return (INVALID_TOKENS);
15782 }
15783 
15784 static int
15785 get_selection_str(char *fmri, size_t sz)
15786 {
15787         if (g_hndl == NULL) {
15788                 semerr(emsg_entity_not_selected);
15789                 return (-1);
15790         } else if (cur_level != NULL) {
15791                 semerr(emsg_invalid_for_snapshot);
15792                 return (-1);
15793         } else {
15794                 lscf_get_selection_str(fmri, sz);
15795         }
15796 
15797         return (0);
15798 }
15799 
15800 void
15801 lscf_delnotify(const char *set, int global)
15802 {
15803         char *str = strdup(set);
15804         char **pgs;
15805         char **p;
15806         int32_t tset;
15807         char *fmri = NULL;
15808 
15809         if (str == NULL)
15810                 uu_die(gettext("Out of memory.\n"));
15811 
15812         pgs = tokenize(str, ",");
15813 
15814         if ((tset = check_tokens(pgs)) > 0) {
15815                 size_t sz = max_scf_fmri_len + 1;
15816 
15817                 fmri = safe_malloc(sz);
15818                 if (global) {
15819                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15820                 } else if (get_selection_str(fmri, sz) != 0) {
15821                         goto out;
15822                 }
15823 
15824                 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15825                     tset) != SCF_SUCCESS) {
15826                         uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15827                             scf_strerror(scf_error()));
15828                 }
15829         } else if (tset == FMA_TOKENS) {
15830                 if (global) {
15831                         semerr(gettext("Can't use option '-g' with FMA event "
15832                             "definitions\n"));
15833                         goto out;
15834                 }
15835 
15836                 for (p = pgs; *p; ++p) {
15837                         if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15838                             SCF_SUCCESS) {
15839                                 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15840                                     scf_strerror(scf_error()));
15841                                 goto out;
15842                         }
15843                 }
15844         } else if (tset == MIXED_TOKENS) {
15845                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15846                 goto out;
15847         } else {
15848                 uu_die(gettext("Invalid input.\n"));
15849         }
15850 
15851 out:
15852         free(fmri);
15853         free(pgs);
15854         free(str);
15855 }
15856 
15857 void
15858 lscf_listnotify(const char *set, int global)
15859 {
15860         char *str = safe_strdup(set);
15861         char **pgs;
15862         char **p;
15863         int32_t tset;
15864         nvlist_t *nvl;
15865         char *fmri = NULL;
15866 
15867         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15868                 uu_die(gettext("Out of memory.\n"));
15869 
15870         pgs = tokenize(str, ",");
15871 
15872         if ((tset = check_tokens(pgs)) > 0) {
15873                 size_t sz = max_scf_fmri_len + 1;
15874 
15875                 fmri = safe_malloc(sz);
15876                 if (global) {
15877                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15878                 } else if (get_selection_str(fmri, sz) != 0) {
15879                         goto out;
15880                 }
15881 
15882                 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15883                     SCF_SUCCESS) {
15884                         if (scf_error() != SCF_ERROR_NOT_FOUND &&
15885                             scf_error() != SCF_ERROR_DELETED)
15886                                 uu_warn(gettext(
15887                                     "Failed listnotify: %s\n"),
15888                                     scf_strerror(scf_error()));
15889                         goto out;
15890                 }
15891 
15892                 listnotify_print(nvl, NULL);
15893         } else if (tset == FMA_TOKENS) {
15894                 if (global) {
15895                         semerr(gettext("Can't use option '-g' with FMA event "
15896                             "definitions\n"));
15897                         goto out;
15898                 }
15899 
15900                 for (p = pgs; *p; ++p) {
15901                         if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15902                             SCF_SUCCESS) {
15903                                 /*
15904                                  * if the preferences have just been deleted
15905                                  * or does not exist, just skip.
15906                                  */
15907                                 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15908                                     scf_error() == SCF_ERROR_DELETED)
15909                                         continue;
15910                                 uu_warn(gettext(
15911                                     "Failed listnotify: %s\n"),
15912                                     scf_strerror(scf_error()));
15913                                 goto out;
15914                         }
15915                         listnotify_print(nvl, re_tag(*p));
15916                 }
15917         } else if (tset == MIXED_TOKENS) {
15918                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15919                 goto out;
15920         } else {
15921                 semerr(gettext("Invalid input.\n"));
15922         }
15923 
15924 out:
15925         nvlist_free(nvl);
15926         free(fmri);
15927         free(pgs);
15928         free(str);
15929 }
15930 
15931 static char *
15932 strip_quotes_and_blanks(char *s)
15933 {
15934         char *start = s;
15935         char *end = strrchr(s, '\"');
15936 
15937         if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15938                 start = s + 1;
15939                 while (isblank(*start))
15940                         start++;
15941                 while (isblank(*(end - 1)) && end > start) {
15942                         end--;
15943                 }
15944                 *end = '\0';
15945         }
15946 
15947         return (start);
15948 }
15949 
15950 static int
15951 set_active(nvlist_t *mech, const char *hier_part)
15952 {
15953         boolean_t b;
15954 
15955         if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15956                 b = B_TRUE;
15957         } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15958                 b = B_FALSE;
15959         } else {
15960                 return (-1);
15961         }
15962 
15963         if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15964                 uu_die(gettext("Out of memory.\n"));
15965 
15966         return (0);
15967 }
15968 
15969 static int
15970 add_snmp_params(nvlist_t *mech, char *hier_part)
15971 {
15972         return (set_active(mech, hier_part));
15973 }
15974 
15975 static int
15976 add_syslog_params(nvlist_t *mech, char *hier_part)
15977 {
15978         return (set_active(mech, hier_part));
15979 }
15980 
15981 /*
15982  * add_mailto_paramas()
15983  * parse the hier_part of mailto URI
15984  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15985  * or mailto:{[active]|inactive}
15986  */
15987 static int
15988 add_mailto_params(nvlist_t *mech, char *hier_part)
15989 {
15990         const char *tok = "?&";
15991         char *p;
15992         char *lasts;
15993         char *param;
15994         char *val;
15995 
15996         /*
15997          * If the notification parametes are in the form of
15998          *
15999          *   malito:{[active]|inactive}
16000          *
16001          * we set the property accordingly and return.
16002          * Otherwise, we make the notification type active and
16003          * process the hier_part.
16004          */
16005         if (set_active(mech, hier_part) == 0)
16006                 return (0);
16007         else if (set_active(mech, PARAM_ACTIVE) != 0)
16008                 return (-1);
16009 
16010         if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16011                 /*
16012                  * sanity check: we only get here if hier_part = "", but
16013                  * that's handled by set_active
16014                  */
16015                 uu_die("strtok_r");
16016         }
16017 
16018         if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16019                 uu_die(gettext("Out of memory.\n"));
16020 
16021         while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16022                 if ((param = strtok_r(p, "=", &val)) != NULL)
16023                         if (nvlist_add_string(mech, param, val) != 0)
16024                                 uu_die(gettext("Out of memory.\n"));
16025 
16026         return (0);
16027 }
16028 
16029 static int
16030 uri_split(char *uri, char **scheme, char **hier_part)
16031 {
16032         int r = -1;
16033 
16034         if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16035             *hier_part == NULL) {
16036                 semerr(gettext("'%s' is not an URI\n"), uri);
16037                 return (r);
16038         }
16039 
16040         if ((r = check_uri_scheme(*scheme)) < 0) {
16041                 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16042                 return (r);
16043         }
16044 
16045         return (r);
16046 }
16047 
16048 static int
16049 process_uri(nvlist_t *params, char *uri)
16050 {
16051         char *scheme;
16052         char *hier_part;
16053         nvlist_t *mech;
16054         int index;
16055         int r;
16056 
16057         if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16058                 return (-1);
16059 
16060         if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16061                 uu_die(gettext("Out of memory.\n"));
16062 
16063         switch (index) {
16064         case 0:
16065                 /* error messages displayed by called function */
16066                 r = add_mailto_params(mech, hier_part);
16067                 break;
16068 
16069         case 1:
16070                 if ((r = add_snmp_params(mech, hier_part)) != 0)
16071                         semerr(gettext("Not valid parameters: '%s'\n"),
16072                             hier_part);
16073                 break;
16074 
16075         case 2:
16076                 if ((r = add_syslog_params(mech, hier_part)) != 0)
16077                         semerr(gettext("Not valid parameters: '%s'\n"),
16078                             hier_part);
16079                 break;
16080 
16081         default:
16082                 r = -1;
16083         }
16084 
16085         if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16086             mech) != 0)
16087                 uu_die(gettext("Out of memory.\n"));
16088 
16089         nvlist_free(mech);
16090         return (r);
16091 }
16092 
16093 static int
16094 set_params(nvlist_t *params, char **p)
16095 {
16096         char *uri;
16097 
16098         if (p == NULL)
16099                 /* sanity check */
16100                 uu_die("set_params");
16101 
16102         while (*p) {
16103                 uri = strip_quotes_and_blanks(*p);
16104                 if (process_uri(params, uri) != 0)
16105                         return (-1);
16106 
16107                 ++p;
16108         }
16109 
16110         return (0);
16111 }
16112 
16113 static int
16114 setnotify(const char *e, char **p, int global)
16115 {
16116         char *str = safe_strdup(e);
16117         char **events;
16118         int32_t tset;
16119         int r = -1;
16120         nvlist_t *nvl, *params;
16121         char *fmri = NULL;
16122 
16123         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16124             nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16125             nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16126             SCF_NOTIFY_PARAMS_VERSION) != 0)
16127                 uu_die(gettext("Out of memory.\n"));
16128 
16129         events = tokenize(str, ",");
16130 
16131         if ((tset = check_tokens(events)) > 0) {
16132                 /* SMF state transitions parameters */
16133                 size_t sz = max_scf_fmri_len + 1;
16134 
16135                 fmri = safe_malloc(sz);
16136                 if (global) {
16137                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16138                 } else if (get_selection_str(fmri, sz) != 0) {
16139                         goto out;
16140                 }
16141 
16142                 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16143                     nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16144                         uu_die(gettext("Out of memory.\n"));
16145 
16146                 if ((r = set_params(params, p)) == 0) {
16147                         if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16148                             params) != 0)
16149                                 uu_die(gettext("Out of memory.\n"));
16150 
16151                         if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16152                             nvl) != SCF_SUCCESS) {
16153                                 r = -1;
16154                                 uu_warn(gettext(
16155                                     "Failed smf_notify_set_params(3SCF): %s\n"),
16156                                     scf_strerror(scf_error()));
16157                         }
16158                 }
16159         } else if (tset == FMA_TOKENS) {
16160                 /* FMA event parameters */
16161                 if (global) {
16162                         semerr(gettext("Can't use option '-g' with FMA event "
16163                             "definitions\n"));
16164                         goto out;
16165                 }
16166 
16167                 if ((r = set_params(params, p)) != 0)
16168                         goto out;
16169 
16170                 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16171                         uu_die(gettext("Out of memory.\n"));
16172 
16173                 while (*events) {
16174                         if (smf_notify_set_params(de_tag(*events), nvl) !=
16175                             SCF_SUCCESS)
16176                                 uu_warn(gettext(
16177                                     "Failed smf_notify_set_params(3SCF) for "
16178                                     "event %s: %s\n"), *events,
16179                                     scf_strerror(scf_error()));
16180                         events++;
16181                 }
16182         } else if (tset == MIXED_TOKENS) {
16183                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16184         } else {
16185                 /* Sanity check */
16186                 uu_die(gettext("Invalid input.\n"));
16187         }
16188 
16189 out:
16190         nvlist_free(nvl);
16191         nvlist_free(params);
16192         free(fmri);
16193         free(str);
16194 
16195         return (r);
16196 }
16197 
16198 int
16199 lscf_setnotify(uu_list_t *args)
16200 {
16201         int argc;
16202         char **argv = NULL;
16203         string_list_t *slp;
16204         int global;
16205         char *events;
16206         char **p;
16207         int i;
16208         int ret;
16209 
16210         if ((argc = uu_list_numnodes(args)) < 2)
16211                 goto usage;
16212 
16213         argv = calloc(argc + 1, sizeof (char *));
16214         if (argv == NULL)
16215                 uu_die(gettext("Out of memory.\n"));
16216 
16217         for (slp = uu_list_first(args), i = 0;
16218             slp != NULL;
16219             slp = uu_list_next(args, slp), ++i)
16220                 argv[i] = slp->str;
16221 
16222         argv[i] = NULL;
16223 
16224         if (strcmp(argv[0], "-g") == 0) {
16225                 global = 1;
16226                 events = argv[1];
16227                 p = argv + 2;
16228         } else {
16229                 global = 0;
16230                 events = argv[0];
16231                 p = argv + 1;
16232         }
16233 
16234         ret = setnotify(events, p, global);
16235 
16236 out:
16237         free(argv);
16238         return (ret);
16239 
16240 usage:
16241         ret = -2;
16242         goto out;
16243 }
16244 
16245 /*
16246  * Creates a list of instance name strings associated with a service. If
16247  * wohandcrafted flag is set, get only instances that have a last-import
16248  * snapshot, instances that were imported via svccfg.
16249  */
16250 static uu_list_t *
16251 create_instance_list(scf_service_t *svc, int wohandcrafted)
16252 {
16253         scf_snapshot_t  *snap = NULL;
16254         scf_instance_t  *inst;
16255         scf_iter_t      *inst_iter;
16256         uu_list_t       *instances;
16257         char            *instname;
16258         int             r;
16259 
16260         inst_iter = scf_iter_create(g_hndl);
16261         inst = scf_instance_create(g_hndl);
16262         if (inst_iter == NULL || inst == NULL) {
16263                 uu_warn(gettext("Could not create instance or iterator\n"));
16264                 scfdie();
16265         }
16266 
16267         if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16268                 return (instances);
16269 
16270         if (scf_iter_service_instances(inst_iter, svc) != 0) {
16271                 switch (scf_error()) {
16272                 case SCF_ERROR_CONNECTION_BROKEN:
16273                 case SCF_ERROR_DELETED:
16274                         uu_list_destroy(instances);
16275                         instances = NULL;
16276                         goto out;
16277 
16278                 case SCF_ERROR_HANDLE_MISMATCH:
16279                 case SCF_ERROR_NOT_BOUND:
16280                 case SCF_ERROR_NOT_SET:
16281                 default:
16282                         bad_error("scf_iter_service_instances", scf_error());
16283                 }
16284         }
16285 
16286         instname = safe_malloc(max_scf_name_len + 1);
16287         while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16288                 if (r == -1) {
16289                         (void) uu_warn(gettext("Unable to iterate through "
16290                             "instances to create instance list : %s\n"),
16291                             scf_strerror(scf_error()));
16292 
16293                         uu_list_destroy(instances);
16294                         instances = NULL;
16295                         goto out;
16296                 }
16297 
16298                 /*
16299                  * If the instance does not have a last-import snapshot
16300                  * then do not add it to the list as it is a hand-crafted
16301                  * instance that should not be managed.
16302                  */
16303                 if (wohandcrafted) {
16304                         if (snap == NULL &&
16305                             (snap = scf_snapshot_create(g_hndl)) == NULL) {
16306                                 uu_warn(gettext("Unable to create snapshot "
16307                                     "entity\n"));
16308                                 scfdie();
16309                         }
16310 
16311                         if (scf_instance_get_snapshot(inst,
16312                             snap_lastimport, snap) != 0) {
16313                                 switch (scf_error()) {
16314                                 case SCF_ERROR_NOT_FOUND :
16315                                 case SCF_ERROR_DELETED:
16316                                         continue;
16317 
16318                                 case SCF_ERROR_CONNECTION_BROKEN:
16319                                         uu_list_destroy(instances);
16320                                         instances = NULL;
16321                                         goto out;
16322 
16323                                 case SCF_ERROR_HANDLE_MISMATCH:
16324                                 case SCF_ERROR_NOT_BOUND:
16325                                 case SCF_ERROR_NOT_SET:
16326                                 default:
16327                                         bad_error("scf_iter_service_instances",
16328                                             scf_error());
16329                                 }
16330                         }
16331                 }
16332 
16333                 if (scf_instance_get_name(inst, instname,
16334                     max_scf_name_len + 1) < 0) {
16335                         switch (scf_error()) {
16336                         case SCF_ERROR_NOT_FOUND :
16337                                 continue;
16338 
16339                         case SCF_ERROR_CONNECTION_BROKEN:
16340                         case SCF_ERROR_DELETED:
16341                                 uu_list_destroy(instances);
16342                                 instances = NULL;
16343                                 goto out;
16344 
16345                         case SCF_ERROR_HANDLE_MISMATCH:
16346                         case SCF_ERROR_NOT_BOUND:
16347                         case SCF_ERROR_NOT_SET:
16348                         default:
16349                                 bad_error("scf_iter_service_instances",
16350                                     scf_error());
16351                         }
16352                 }
16353 
16354                 add_string(instances, instname);
16355         }
16356 
16357 out:
16358         if (snap)
16359                 scf_snapshot_destroy(snap);
16360 
16361         scf_instance_destroy(inst);
16362         scf_iter_destroy(inst_iter);
16363         free(instname);
16364         return (instances);
16365 }
16366 
16367 /*
16368  * disable an instance but wait for the instance to
16369  * move out of the running state.
16370  *
16371  * Returns 0 : if the instance did not disable
16372  * Returns non-zero : if the instance disabled.
16373  *
16374  */
16375 static int
16376 disable_instance(scf_instance_t *instance)
16377 {
16378         char    *fmribuf;
16379         int     enabled = 10000;
16380 
16381         if (inst_is_running(instance)) {
16382                 fmribuf = safe_malloc(max_scf_name_len + 1);
16383                 if (scf_instance_to_fmri(instance, fmribuf,
16384                     max_scf_name_len + 1) < 0) {
16385                         free(fmribuf);
16386                         return (0);
16387                 }
16388 
16389                 /*
16390                  * If the instance cannot be disabled then return
16391                  * failure to disable and let the caller decide
16392                  * if that is of importance.
16393                  */
16394                 if (smf_disable_instance(fmribuf, 0) != 0) {
16395                         free(fmribuf);
16396                         return (0);
16397                 }
16398 
16399                 while (enabled) {
16400                         if (!inst_is_running(instance))
16401                                 break;
16402 
16403                         (void) poll(NULL, 0, 5);
16404                         enabled = enabled - 5;
16405                 }
16406 
16407                 free(fmribuf);
16408         }
16409 
16410         return (enabled);
16411 }
16412 
16413 /*
16414  * Function to compare two service_manifest structures.
16415  */
16416 /* ARGSUSED2 */
16417 static int
16418 service_manifest_compare(const void *left, const void *right, void *unused)
16419 {
16420         service_manifest_t *l = (service_manifest_t *)left;
16421         service_manifest_t *r = (service_manifest_t *)right;
16422         int rc;
16423 
16424         rc = strcmp(l->servicename, r->servicename);
16425 
16426         return (rc);
16427 }
16428 
16429 /*
16430  * Look for the provided service in the service to manifest
16431  * tree.  If the service exists, and a manifest was provided
16432  * then add the manifest to that service.  If the service
16433  * does not exist, then add the service and manifest to the
16434  * list.
16435  *
16436  * If the manifest is NULL, return the element if found.  If
16437  * the service is not found return NULL.
16438  */
16439 service_manifest_t *
16440 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16441 {
16442         service_manifest_t      elem;
16443         service_manifest_t      *fnelem;
16444         uu_avl_index_t          marker;
16445 
16446         elem.servicename = svnbuf;
16447         fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16448 
16449         if (mfst) {
16450                 if (fnelem) {
16451                         add_string(fnelem->mfstlist, strdup(mfst));
16452                 } else {
16453                         fnelem = safe_malloc(sizeof (*fnelem));
16454                         fnelem->servicename = safe_strdup(svnbuf);
16455                         if ((fnelem->mfstlist =
16456                             uu_list_create(string_pool, NULL, 0)) == NULL)
16457                                 uu_die(gettext("Could not create property "
16458                                     "list: %s\n"), uu_strerror(uu_error()));
16459 
16460                         add_string(fnelem->mfstlist, safe_strdup(mfst));
16461 
16462                         uu_avl_insert(service_manifest_tree, fnelem, marker);
16463                 }
16464         }
16465 
16466         return (fnelem);
16467 }
16468 
16469 /*
16470  * Create the service to manifest avl tree.
16471  *
16472  * Walk each of the manifests currently installed in the supported
16473  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16474  * each of the manifests, inventory the services and add them to
16475  * the tree.
16476  *
16477  * Code that calls this function should make sure fileystem/minimal is online,
16478  * /var is available, since this function walks the /var/svc/manifest directory.
16479  */
16480 static void
16481 create_manifest_tree(void)
16482 {
16483         manifest_info_t **entry;
16484         manifest_info_t **manifests;
16485         uu_list_walk_t  *svcs;
16486         bundle_t        *b;
16487         entity_t        *mfsvc;
16488         char            *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16489         int             c, status;
16490 
16491         if (service_manifest_pool)
16492                 return;
16493 
16494         /*
16495          * Create the list pool for the service manifest list
16496          */
16497         service_manifest_pool = uu_avl_pool_create("service_manifest",
16498             sizeof (service_manifest_t),
16499             offsetof(service_manifest_t, svcmfst_node),
16500             service_manifest_compare, UU_DEFAULT);
16501         if (service_manifest_pool == NULL)
16502                 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16503                     uu_strerror(uu_error()));
16504 
16505         /*
16506          * Create the list
16507          */
16508         service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16509             UU_DEFAULT);
16510         if (service_manifest_tree == NULL)
16511                 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16512                     uu_strerror(uu_error()));
16513 
16514         /*
16515          * Walk the manifests adding the service(s) from each manifest.
16516          *
16517          * If a service already exists add the manifest to the manifest
16518          * list for that service.  This covers the case of a service that
16519          * is supported by multiple manifest files.
16520          */
16521         for (c = 0; dirs[c]; c++) {
16522                 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16523                 if (status < 0) {
16524                         uu_warn(gettext("file tree walk of %s encountered "
16525                             "error %s\n"), dirs[c], strerror(errno));
16526 
16527                         uu_avl_destroy(service_manifest_tree);
16528                         service_manifest_tree = NULL;
16529                         return;
16530                 }
16531 
16532                 /*
16533                  * If a manifest that was in the list is not found
16534                  * then skip and go to the next manifest file.
16535                  */
16536                 if (manifests != NULL) {
16537                         for (entry = manifests; *entry != NULL; entry++) {
16538                                 b = internal_bundle_new();
16539                                 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16540                                     SVCCFG_OP_IMPORT) != 0) {
16541                                         internal_bundle_free(b);
16542                                         continue;
16543                                 }
16544 
16545                                 svcs = uu_list_walk_start(b->sc_bundle_services,
16546                                     0);
16547                                 if (svcs == NULL) {
16548                                         internal_bundle_free(b);
16549                                         continue;
16550                                 }
16551 
16552                                 while ((mfsvc = uu_list_walk_next(svcs)) !=
16553                                     NULL) {
16554                                         /* Add manifest to service */
16555                                         (void) find_add_svc_mfst(mfsvc->sc_name,
16556                                             (*entry)->mi_path);
16557                                 }
16558 
16559                                 uu_list_walk_end(svcs);
16560                                 internal_bundle_free(b);
16561                         }
16562 
16563                         free_manifest_array(manifests);
16564                 }
16565         }
16566 }
16567 
16568 /*
16569  * Check the manifest history file to see
16570  * if the service was ever installed from
16571  * one of the supported directories.
16572  *
16573  * Return Values :
16574  *      -1 - if there's error reading manifest history file
16575  *       1 - if the service is not found
16576  *       0 - if the service is found
16577  */
16578 static int
16579 check_mfst_history(const char *svcname)
16580 {
16581         struct stat     st;
16582         caddr_t         mfsthist_start;
16583         char            *svnbuf;
16584         int             fd;
16585         int             r = 1;
16586 
16587         fd = open(MFSTHISTFILE, O_RDONLY);
16588         if (fd == -1) {
16589                 uu_warn(gettext("Unable to open the history file\n"));
16590                 return (-1);
16591         }
16592 
16593         if (fstat(fd, &st) == -1) {
16594                 uu_warn(gettext("Unable to stat the history file\n"));
16595                 return (-1);
16596         }
16597 
16598         mfsthist_start = mmap(0, st.st_size, PROT_READ,
16599             MAP_PRIVATE, fd, 0);
16600 
16601         (void) close(fd);
16602         if (mfsthist_start == MAP_FAILED ||
16603             *(mfsthist_start + st.st_size) != '\0') {
16604                 (void) munmap(mfsthist_start, st.st_size);
16605                 return (-1);
16606         }
16607 
16608         /*
16609          * The manifest history file is a space delimited list
16610          * of service and instance to manifest linkage.  Adding
16611          * a space to the end of the service name so to get only
16612          * the service that is being searched for.
16613          */
16614         svnbuf = uu_msprintf("%s ", svcname);
16615         if (svnbuf == NULL)
16616                 uu_die(gettext("Out of memory"));
16617 
16618         if (strstr(mfsthist_start, svnbuf) != NULL)
16619                 r = 0;
16620 
16621         (void) munmap(mfsthist_start, st.st_size);
16622         uu_free(svnbuf);
16623         return (r);
16624 }
16625 
16626 /*
16627  * Take down each of the instances in the service
16628  * and remove them, then delete the service.
16629  */
16630 static void
16631 teardown_service(scf_service_t *svc, const char *svnbuf)
16632 {
16633         scf_instance_t  *instance;
16634         scf_iter_t      *iter;
16635         int             r;
16636 
16637         safe_printf(gettext("Delete service %s as there are no "
16638             "supporting manifests\n"), svnbuf);
16639 
16640         instance = scf_instance_create(g_hndl);
16641         iter = scf_iter_create(g_hndl);
16642         if (iter == NULL || instance == NULL) {
16643                 uu_warn(gettext("Unable to create supporting entities to "
16644                     "teardown the service\n"));
16645                 uu_warn(gettext("scf error is : %s\n"),
16646                     scf_strerror(scf_error()));
16647                 scfdie();
16648         }
16649 
16650         if (scf_iter_service_instances(iter, svc) != 0) {
16651                 switch (scf_error()) {
16652                 case SCF_ERROR_CONNECTION_BROKEN:
16653                 case SCF_ERROR_DELETED:
16654                         goto out;
16655 
16656                 case SCF_ERROR_HANDLE_MISMATCH:
16657                 case SCF_ERROR_NOT_BOUND:
16658                 case SCF_ERROR_NOT_SET:
16659                 default:
16660                         bad_error("scf_iter_service_instances",
16661                             scf_error());
16662                 }
16663         }
16664 
16665         while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16666                 if (r == -1) {
16667                         uu_warn(gettext("Error - %s\n"),
16668                             scf_strerror(scf_error()));
16669                         goto out;
16670                 }
16671 
16672                 (void) disable_instance(instance);
16673         }
16674 
16675         /*
16676          * Delete the service... forcing the deletion in case
16677          * any of the instances did not disable.
16678          */
16679         (void) lscf_service_delete(svc, 1);
16680 out:
16681         scf_instance_destroy(instance);
16682         scf_iter_destroy(iter);
16683 }
16684 
16685 /*
16686  * Get the list of instances supported by the manifest
16687  * file.
16688  *
16689  * Return 0 if there are no instances.
16690  *
16691  * Return -1 if there are errors attempting to collect instances.
16692  *
16693  * Return the count of instances found if there are no errors.
16694  *
16695  */
16696 static int
16697 check_instance_support(char *mfstfile, const char *svcname,
16698     uu_list_t *instances)
16699 {
16700         uu_list_walk_t  *svcs, *insts;
16701         uu_list_t       *ilist;
16702         bundle_t        *b;
16703         entity_t        *mfsvc, *mfinst;
16704         const char      *svcn;
16705         int             rminstcnt = 0;
16706 
16707 
16708         b = internal_bundle_new();
16709 
16710         if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16711                 /*
16712                  * Unable to process the manifest file for
16713                  * instance support, so just return as
16714                  * don't want to remove instances that could
16715                  * not be accounted for that might exist here.
16716                  */
16717                 internal_bundle_free(b);
16718                 return (0);
16719         }
16720 
16721         svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16722         if (svcs == NULL) {
16723                 internal_bundle_free(b);
16724                 return (0);
16725         }
16726 
16727         svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16728             (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16729 
16730         while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16731                 if (strcmp(mfsvc->sc_name, svcn) == 0)
16732                         break;
16733         }
16734         uu_list_walk_end(svcs);
16735 
16736         if (mfsvc == NULL) {
16737                 internal_bundle_free(b);
16738                 return (-1);
16739         }
16740 
16741         ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16742         if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16743                 internal_bundle_free(b);
16744                 return (0);
16745         }
16746 
16747         while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16748                 /*
16749                  * Remove the instance from the instances list.
16750                  * The unaccounted for instances will be removed
16751                  * from the service once all manifests are
16752                  * processed.
16753                  */
16754                 (void) remove_string(instances,
16755                     mfinst->sc_name);
16756                 rminstcnt++;
16757         }
16758 
16759         uu_list_walk_end(insts);
16760         internal_bundle_free(b);
16761 
16762         return (rminstcnt);
16763 }
16764 
16765 /*
16766  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16767  * 'false' to indicate there's no manifest file(s) found for the service.
16768  */
16769 static void
16770 svc_add_no_support(scf_service_t *svc)
16771 {
16772         char    *pname;
16773 
16774         /* Add no support */
16775         cur_svc = svc;
16776         if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16777                 return;
16778 
16779         pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16780         if (pname == NULL)
16781                 uu_die(gettext("Out of memory.\n"));
16782 
16783         (void) lscf_addpropvalue(pname, "boolean:", "0");
16784 
16785         uu_free(pname);
16786         cur_svc = NULL;
16787 }
16788 
16789 /*
16790  * This function handles all upgrade scenarios for a service that doesn't have
16791  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16792  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16793  * manifest(s) mapping. Manifests under supported directories are inventoried
16794  * and a property is added for each file that delivers configuration to the
16795  * service.  A service that has no corresponding manifest files (deleted) are
16796  * removed from repository.
16797  *
16798  * Unsupported services:
16799  *
16800  * A service is considered unsupported if there is no corresponding manifest
16801  * in the supported directories for that service and the service isn't in the
16802  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16803  * services and instances that were delivered by Solaris before the introduction
16804  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16805  * the path to the manifest file that defined the service or instance.
16806  *
16807  * Another type of unsupported services is 'handcrafted' services,
16808  * programmatically created services or services created by dependent entries
16809  * in other manifests. A handcrafted service is identified by its lack of any
16810  * instance containing last-import snapshot which is created during svccfg
16811  * import.
16812  *
16813  * This function sets a flag for unsupported services by setting services'
16814  * SCF_PG_MANIFESTFILES/support property to false.
16815  */
16816 static void
16817 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16818 {
16819         service_manifest_t      *elem;
16820         uu_list_walk_t          *mfwalk;
16821         string_list_t           *mfile;
16822         uu_list_t               *instances;
16823         const char              *sname;
16824         char                    *pname;
16825         int                     r;
16826 
16827         /*
16828          * Since there's no guarantee manifests under /var are available during
16829          * early import, don't perform any upgrade during early import.
16830          */
16831         if (IGNORE_VAR)
16832                 return;
16833 
16834         if (service_manifest_tree == NULL) {
16835                 create_manifest_tree();
16836         }
16837 
16838         /*
16839          * Find service's supporting manifest(s) after
16840          * stripping off the svc:/ prefix that is part
16841          * of the fmri that is not used in the service
16842          * manifest bundle list.
16843          */
16844         sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16845             strlen(SCF_FMRI_SERVICE_PREFIX);
16846         elem = find_add_svc_mfst(sname, NULL);
16847         if (elem == NULL) {
16848 
16849                 /*
16850                  * A handcrafted service, one that has no instance containing
16851                  * last-import snapshot, should get unsupported flag.
16852                  */
16853                 instances = create_instance_list(svc, 1);
16854                 if (instances == NULL) {
16855                         uu_warn(gettext("Unable to create instance list %s\n"),
16856                             svcname);
16857                         return;
16858                 }
16859 
16860                 if (uu_list_numnodes(instances) == 0) {
16861                         svc_add_no_support(svc);
16862                         return;
16863                 }
16864 
16865                 /*
16866                  * If the service is in the history file, and its supporting
16867                  * manifests are not found, we can safely delete the service
16868                  * because its manifests are removed from the system.
16869                  *
16870                  * Services not found in the history file are not delivered by
16871                  * Solaris and/or delivered outside supported directories, set
16872                  * unsupported flag for these services.
16873                  */
16874                 r = check_mfst_history(svcname);
16875                 if (r == -1)
16876                         return;
16877 
16878                 if (r) {
16879                         /* Set unsupported flag for service  */
16880                         svc_add_no_support(svc);
16881                 } else {
16882                         /* Delete the service */
16883                         teardown_service(svc, svcname);
16884                 }
16885 
16886                 return;
16887         }
16888 
16889         /*
16890          * Walk through the list of manifests and add them
16891          * to the service.
16892          *
16893          * Create a manifestfiles pg and add the property.
16894          */
16895         mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16896         if (mfwalk == NULL)
16897                 return;
16898 
16899         cur_svc = svc;
16900         r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16901         if (r != 0) {
16902                 cur_svc = NULL;
16903                 return;
16904         }
16905 
16906         while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16907                 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16908                     mhash_filename_to_propname(mfile->str, 0));
16909                 if (pname == NULL)
16910                         uu_die(gettext("Out of memory.\n"));
16911 
16912                 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16913                 uu_free(pname);
16914         }
16915         uu_list_walk_end(mfwalk);
16916 
16917         cur_svc = NULL;
16918 }
16919 
16920 /*
16921  * Take a service and process the manifest file entires to see if
16922  * there is continued support for the service and instances.  If
16923  * not cleanup as appropriate.
16924  *
16925  * If a service does not have a manifest files entry flag it for
16926  * upgrade and return.
16927  *
16928  * For each manifestfiles property check if the manifest file is
16929  * under the supported /lib/svc/manifest or /var/svc/manifest path
16930  * and if not then return immediately as this service is not supported
16931  * by the cleanup mechanism and should be ignored.
16932  *
16933  * For each manifest file that is supported, check to see if the
16934  * file exists.  If not then remove the manifest file property
16935  * from the service and the smf/manifest hash table.  If the manifest
16936  * file exists then verify that it supports the instances that are
16937  * part of the service.
16938  *
16939  * Once all manifest files have been accounted for remove any instances
16940  * that are no longer supported in the service.
16941  *
16942  * Return values :
16943  * 0 - Successfully processed the service
16944  * non-zero - failed to process the service
16945  *
16946  * On most errors, will just return to wait and get the next service,
16947  * unless in case of unable to create the needed structures which is
16948  * most likely a fatal error that is not going to be recoverable.
16949  */
16950 int
16951 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16952 {
16953         struct mpg_mfile        *mpntov = NULL;
16954         struct mpg_mfile        **mpvarry = NULL;
16955         scf_service_t           *svc;
16956         scf_propertygroup_t     *mpg;
16957         scf_property_t          *mp;
16958         scf_value_t             *mv;
16959         scf_iter_t              *mi;
16960         scf_instance_t          *instance;
16961         uu_list_walk_t          *insts;
16962         uu_list_t               *instances = NULL;
16963         boolean_t               activity = (boolean_t)act;
16964         char                    *mpnbuf = NULL;
16965         char                    *mpvbuf = NULL;
16966         char                    *pgpropbuf;
16967         int                     mfstcnt, rminstct, instct, mfstmax;
16968         int                     index;
16969         int                     r = 0;
16970 
16971         assert(g_hndl != NULL);
16972         assert(wip->svc != NULL);
16973         assert(wip->fmri != NULL);
16974 
16975         svc = wip->svc;
16976 
16977         mpg = scf_pg_create(g_hndl);
16978         mp = scf_property_create(g_hndl);
16979         mi = scf_iter_create(g_hndl);
16980         mv = scf_value_create(g_hndl);
16981         instance = scf_instance_create(g_hndl);
16982 
16983         if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16984             instance == NULL) {
16985                 uu_warn(gettext("Unable to create the supporting entities\n"));
16986                 uu_warn(gettext("scf error is : %s\n"),
16987                     scf_strerror(scf_error()));
16988                 scfdie();
16989         }
16990 
16991         /*
16992          * Get the manifestfiles property group to be parsed for
16993          * files existence.
16994          */
16995         if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16996                 switch (scf_error()) {
16997                 case SCF_ERROR_NOT_FOUND:
16998                         upgrade_svc_mfst_connection(svc, wip->fmri);
16999                         break;
17000                 case SCF_ERROR_DELETED:
17001                 case SCF_ERROR_CONNECTION_BROKEN:
17002                         goto out;
17003 
17004                 case SCF_ERROR_HANDLE_MISMATCH:
17005                 case SCF_ERROR_NOT_BOUND:
17006                 case SCF_ERROR_NOT_SET:
17007                 default:
17008                         bad_error("scf_iter_pg_properties",
17009                             scf_error());
17010                 }
17011 
17012                 goto out;
17013         }
17014 
17015         /*
17016          * Iterate through each of the manifestfiles properties
17017          * to determine what manifestfiles are available.
17018          *
17019          * If a manifest file is supported then increment the
17020          * count and therefore the service is safe.
17021          */
17022         if (scf_iter_pg_properties(mi, mpg) != 0) {
17023                 switch (scf_error()) {
17024                 case SCF_ERROR_DELETED:
17025                 case SCF_ERROR_CONNECTION_BROKEN:
17026                         goto out;
17027 
17028                 case SCF_ERROR_HANDLE_MISMATCH:
17029                 case SCF_ERROR_NOT_BOUND:
17030                 case SCF_ERROR_NOT_SET:
17031                 default:
17032                         bad_error("scf_iter_pg_properties",
17033                             scf_error());
17034                 }
17035         }
17036 
17037         mfstcnt = 0;
17038         mfstmax = MFSTFILE_MAX;
17039         mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17040         while ((r = scf_iter_next_property(mi, mp)) != 0) {
17041                 if (r == -1)
17042                         bad_error(gettext("Unable to iterate through "
17043                             "manifestfiles properties : %s"),
17044                             scf_error());
17045 
17046                 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17047                 mpnbuf = safe_malloc(max_scf_name_len + 1);
17048                 mpvbuf = safe_malloc(max_scf_value_len + 1);
17049                 mpntov->mpg = mpnbuf;
17050                 mpntov->mfile = mpvbuf;
17051                 mpntov->access = 1;
17052                 if (scf_property_get_name(mp, mpnbuf,
17053                     max_scf_name_len + 1) < 0) {
17054                         uu_warn(gettext("Unable to get manifest file "
17055                             "property : %s\n"),
17056                             scf_strerror(scf_error()));
17057 
17058                         switch (scf_error()) {
17059                         case SCF_ERROR_DELETED:
17060                         case SCF_ERROR_CONNECTION_BROKEN:
17061                                 r = scferror2errno(scf_error());
17062                                 goto out_free;
17063 
17064                         case SCF_ERROR_HANDLE_MISMATCH:
17065                         case SCF_ERROR_NOT_BOUND:
17066                         case SCF_ERROR_NOT_SET:
17067                         default:
17068                                 bad_error("scf_iter_pg_properties",
17069                                     scf_error());
17070                         }
17071                 }
17072 
17073                 /*
17074                  * The support property is a boolean value that indicates
17075                  * if the service is supported for manifest file deletion.
17076                  * Currently at this time there is no code that sets this
17077                  * value to true.  So while we could just let this be caught
17078                  * by the support check below, in the future this by be set
17079                  * to true and require processing.  So for that, go ahead
17080                  * and check here, and just return if false.  Otherwise,
17081                  * fall through expecting that other support checks will
17082                  * handle the entries.
17083                  */
17084                 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17085                         uint8_t support;
17086 
17087                         if (scf_property_get_value(mp, mv) != 0 ||
17088                             scf_value_get_boolean(mv, &support) != 0) {
17089                                 uu_warn(gettext("Unable to get the manifest "
17090                                     "support value: %s\n"),
17091                                     scf_strerror(scf_error()));
17092 
17093                                 switch (scf_error()) {
17094                                 case SCF_ERROR_DELETED:
17095                                 case SCF_ERROR_CONNECTION_BROKEN:
17096                                         r = scferror2errno(scf_error());
17097                                         goto out_free;
17098 
17099                                 case SCF_ERROR_HANDLE_MISMATCH:
17100                                 case SCF_ERROR_NOT_BOUND:
17101                                 case SCF_ERROR_NOT_SET:
17102                                 default:
17103                                         bad_error("scf_iter_pg_properties",
17104                                             scf_error());
17105                                 }
17106                         }
17107 
17108                         if (support == B_FALSE)
17109                                 goto out_free;
17110                 }
17111 
17112                 /*
17113                  * Anything with a manifest outside of the supported
17114                  * directories, immediately bail out because that makes
17115                  * this service non-supported.  We don't even want
17116                  * to do instance processing in this case because the
17117                  * instances could be part of the non-supported manifest.
17118                  */
17119                 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17120                         /*
17121                          * Manifest is not in /lib/svc, so we need to
17122                          * consider the /var/svc case.
17123                          */
17124                         if (strncmp(mpnbuf, VARSVC_PR,
17125                             strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17126                                 /*
17127                                  * Either the manifest is not in /var/svc or
17128                                  * /var is not yet mounted.  We ignore the
17129                                  * manifest either because it is not in a
17130                                  * standard location or because we cannot
17131                                  * currently access the manifest.
17132                                  */
17133                                 goto out_free;
17134                         }
17135                 }
17136 
17137                 /*
17138                  * Get the value to of the manifest file for this entry
17139                  * for access verification and instance support
17140                  * verification if it still exists.
17141                  *
17142                  * During Early Manifest Import if the manifest is in
17143                  * /var/svc then it may not yet be available for checking
17144                  * so we must determine if /var/svc is available.  If not
17145                  * then defer until Late Manifest Import to cleanup.
17146                  */
17147                 if (scf_property_get_value(mp, mv) != 0) {
17148                         uu_warn(gettext("Unable to get the manifest file "
17149                             "value: %s\n"),
17150                             scf_strerror(scf_error()));
17151 
17152                         switch (scf_error()) {
17153                         case SCF_ERROR_DELETED:
17154                         case SCF_ERROR_CONNECTION_BROKEN:
17155                                 r = scferror2errno(scf_error());
17156                                 goto out_free;
17157 
17158                         case SCF_ERROR_HANDLE_MISMATCH:
17159                         case SCF_ERROR_NOT_BOUND:
17160                         case SCF_ERROR_NOT_SET:
17161                         default:
17162                                 bad_error("scf_property_get_value",
17163                                     scf_error());
17164                         }
17165                 }
17166 
17167                 if (scf_value_get_astring(mv, mpvbuf,
17168                     max_scf_value_len + 1) < 0) {
17169                         uu_warn(gettext("Unable to get the manifest "
17170                             "file : %s\n"),
17171                             scf_strerror(scf_error()));
17172 
17173                         switch (scf_error()) {
17174                         case SCF_ERROR_DELETED:
17175                         case SCF_ERROR_CONNECTION_BROKEN:
17176                                 r = scferror2errno(scf_error());
17177                                 goto out_free;
17178 
17179                         case SCF_ERROR_HANDLE_MISMATCH:
17180                         case SCF_ERROR_NOT_BOUND:
17181                         case SCF_ERROR_NOT_SET:
17182                         default:
17183                                 bad_error("scf_value_get_astring",
17184                                     scf_error());
17185                         }
17186                 }
17187 
17188                 mpvarry[mfstcnt] = mpntov;
17189                 mfstcnt++;
17190 
17191                 /*
17192                  * Check for the need to reallocate array
17193                  */
17194                 if (mfstcnt >= (mfstmax - 1)) {
17195                         struct mpg_mfile **newmpvarry;
17196 
17197                         mfstmax = mfstmax * 2;
17198                         newmpvarry = realloc(mpvarry,
17199                             sizeof (struct mpg_mfile *) * mfstmax);
17200 
17201                         if (newmpvarry == NULL)
17202                                 goto out_free;
17203 
17204                         mpvarry = newmpvarry;
17205                 }
17206 
17207                 mpvarry[mfstcnt] = NULL;
17208         }
17209 
17210         for (index = 0; mpvarry[index]; index++) {
17211                 mpntov = mpvarry[index];
17212 
17213                 /*
17214                  * Check to see if the manifestfile is accessable, if so hand
17215                  * this service and manifestfile off to be processed for
17216                  * instance support.
17217                  */
17218                 mpnbuf = mpntov->mpg;
17219                 mpvbuf = mpntov->mfile;
17220                 if (access(mpvbuf, F_OK) != 0) {
17221                         mpntov->access = 0;
17222                         activity++;
17223                         mfstcnt--;
17224                         /* Remove the entry from the service */
17225                         cur_svc = svc;
17226                         pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17227                             mpnbuf);
17228                         if (pgpropbuf == NULL)
17229                                 uu_die(gettext("Out of memory.\n"));
17230 
17231                         lscf_delprop(pgpropbuf);
17232                         cur_svc = NULL;
17233 
17234                         uu_free(pgpropbuf);
17235                 }
17236         }
17237 
17238         /*
17239          * If mfstcnt is 0, none of the manifests that supported the service
17240          * existed so remove the service.
17241          */
17242         if (mfstcnt == 0) {
17243                 teardown_service(svc, wip->fmri);
17244 
17245                 goto out_free;
17246         }
17247 
17248         if (activity) {
17249                 int     nosvcsupport = 0;
17250 
17251                 /*
17252                  * If the list of service instances is NULL then
17253                  * create the list.
17254                  */
17255                 instances = create_instance_list(svc, 1);
17256                 if (instances == NULL) {
17257                         uu_warn(gettext("Unable to create instance list %s\n"),
17258                             wip->fmri);
17259                         goto out_free;
17260                 }
17261 
17262                 rminstct = uu_list_numnodes(instances);
17263                 instct = rminstct;
17264 
17265                 for (index = 0; mpvarry[index]; index++) {
17266                         mpntov = mpvarry[index];
17267                         if (mpntov->access == 0)
17268                                 continue;
17269 
17270                         mpnbuf = mpntov->mpg;
17271                         mpvbuf = mpntov->mfile;
17272                         r = check_instance_support(mpvbuf, wip->fmri,
17273                             instances);
17274                         if (r == -1) {
17275                                 nosvcsupport++;
17276                         } else {
17277                                 rminstct -= r;
17278                         }
17279                 }
17280 
17281                 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17282                         teardown_service(svc, wip->fmri);
17283 
17284                         goto out_free;
17285                 }
17286         }
17287 
17288         /*
17289          * If there are instances left on the instance list, then
17290          * we must remove them.
17291          */
17292         if (instances != NULL && uu_list_numnodes(instances)) {
17293                 string_list_t *sp;
17294 
17295                 insts = uu_list_walk_start(instances, 0);
17296                 while ((sp = uu_list_walk_next(insts)) != NULL) {
17297                         /*
17298                          * Remove the instance from the instances list.
17299                          */
17300                         safe_printf(gettext("Delete instance %s from "
17301                             "service %s\n"), sp->str, wip->fmri);
17302                         if (scf_service_get_instance(svc, sp->str,
17303                             instance) != SCF_SUCCESS) {
17304                                 (void) uu_warn("scf_error - %s\n",
17305                                     scf_strerror(scf_error()));
17306 
17307                                 continue;
17308                         }
17309 
17310                         (void) disable_instance(instance);
17311 
17312                         (void) lscf_instance_delete(instance, 1);
17313                 }
17314                 scf_instance_destroy(instance);
17315                 uu_list_walk_end(insts);
17316         }
17317 
17318 out_free:
17319         if (mpvarry) {
17320                 struct mpg_mfile *fmpntov;
17321 
17322                 for (index = 0; mpvarry[index]; index++) {
17323                         fmpntov  = mpvarry[index];
17324                         if (fmpntov->mpg == mpnbuf)
17325                                 mpnbuf = NULL;
17326                         free(fmpntov->mpg);
17327 
17328                         if (fmpntov->mfile == mpvbuf)
17329                                 mpvbuf = NULL;
17330                         free(fmpntov->mfile);
17331 
17332                         if (fmpntov == mpntov)
17333                                 mpntov = NULL;
17334                         free(fmpntov);
17335                 }
17336                 if (mpnbuf)
17337                         free(mpnbuf);
17338                 if (mpvbuf)
17339                         free(mpvbuf);
17340                 if (mpntov)
17341                         free(mpntov);
17342 
17343                 free(mpvarry);
17344         }
17345 out:
17346         scf_pg_destroy(mpg);
17347         scf_property_destroy(mp);
17348         scf_iter_destroy(mi);
17349         scf_value_destroy(mv);
17350 
17351         return (0);
17352 }
17353 
17354 /*
17355  * Take the service and search for the manifestfiles property
17356  * in each of the property groups.  If the manifest file
17357  * associated with the property does not exist then remove
17358  * the property group.
17359  */
17360 int
17361 lscf_hash_cleanup()
17362 {
17363         scf_service_t           *svc;
17364         scf_scope_t             *scope;
17365         scf_propertygroup_t     *pg;
17366         scf_property_t          *prop;
17367         scf_value_t             *val;
17368         scf_iter_t              *iter;
17369         char                    *pgname = NULL;
17370         char                    *mfile = NULL;
17371         int                     r;
17372 
17373         svc = scf_service_create(g_hndl);
17374         scope = scf_scope_create(g_hndl);
17375         pg = scf_pg_create(g_hndl);
17376         prop = scf_property_create(g_hndl);
17377         val = scf_value_create(g_hndl);
17378         iter = scf_iter_create(g_hndl);
17379         if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17380             svc == NULL || scope == NULL) {
17381                 uu_warn(gettext("Unable to create a property group, or "
17382                     "property\n"));
17383                 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17384                     "pg is not NULL");
17385                 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17386                     "prop is not NULL");
17387                 uu_warn("%s\n", val == NULL ? "val is NULL" :
17388                     "val is not NULL");
17389                 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17390                     "iter is not NULL");
17391                 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17392                     "svc is not NULL");
17393                 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17394                     "scope is not NULL");
17395                 uu_warn(gettext("scf error is : %s\n"),
17396                     scf_strerror(scf_error()));
17397                 scfdie();
17398         }
17399 
17400         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17401                 switch (scf_error()) {
17402                 case SCF_ERROR_CONNECTION_BROKEN:
17403                 case SCF_ERROR_NOT_FOUND:
17404                         goto out;
17405 
17406                 case SCF_ERROR_HANDLE_MISMATCH:
17407                 case SCF_ERROR_NOT_BOUND:
17408                 case SCF_ERROR_INVALID_ARGUMENT:
17409                 default:
17410                         bad_error("scf_handle_get_scope", scf_error());
17411                 }
17412         }
17413 
17414         if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17415                 uu_warn(gettext("Unable to process the hash service, %s\n"),
17416                     HASH_SVC);
17417                 goto out;
17418         }
17419 
17420         pgname = safe_malloc(max_scf_name_len + 1);
17421         mfile = safe_malloc(max_scf_value_len + 1);
17422 
17423         if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17424                 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17425                     scf_strerror(scf_error()));
17426                 goto out;
17427         }
17428 
17429         while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17430                 if (r == -1)
17431                         goto out;
17432 
17433                 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17434                         switch (scf_error()) {
17435                         case SCF_ERROR_DELETED:
17436                                 return (ENODEV);
17437 
17438                         case SCF_ERROR_CONNECTION_BROKEN:
17439                                 return (ECONNABORTED);
17440 
17441                         case SCF_ERROR_NOT_SET:
17442                         case SCF_ERROR_NOT_BOUND:
17443                         default:
17444                                 bad_error("scf_pg_get_name", scf_error());
17445                         }
17446                 }
17447                 if (IGNORE_VAR) {
17448                         if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17449                                 continue;
17450                 }
17451 
17452                 /*
17453                  * If unable to get the property continue as this is an
17454                  * entry that has no location to check against.
17455                  */
17456                 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17457                         continue;
17458                 }
17459 
17460                 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17461                         uu_warn(gettext("Unable to get value from %s\n"),
17462                             pgname);
17463 
17464                         switch (scf_error()) {
17465                         case SCF_ERROR_DELETED:
17466                         case SCF_ERROR_CONSTRAINT_VIOLATED:
17467                         case SCF_ERROR_NOT_FOUND:
17468                         case SCF_ERROR_NOT_SET:
17469                                 continue;
17470 
17471                         case SCF_ERROR_CONNECTION_BROKEN:
17472                                 r = scferror2errno(scf_error());
17473                                 goto out;
17474 
17475                         case SCF_ERROR_HANDLE_MISMATCH:
17476                         case SCF_ERROR_NOT_BOUND:
17477                         default:
17478                                 bad_error("scf_property_get_value",
17479                                     scf_error());
17480                         }
17481                 }
17482 
17483                 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17484                     == -1) {
17485                         uu_warn(gettext("Unable to get astring from %s : %s\n"),
17486                             pgname, scf_strerror(scf_error()));
17487 
17488                         switch (scf_error()) {
17489                         case SCF_ERROR_NOT_SET:
17490                         case SCF_ERROR_TYPE_MISMATCH:
17491                                 continue;
17492 
17493                         default:
17494                                 bad_error("scf_value_get_astring", scf_error());
17495                         }
17496                 }
17497 
17498                 if (access(mfile, F_OK) == 0)
17499                         continue;
17500 
17501                 (void) scf_pg_delete(pg);
17502         }
17503 
17504 out:
17505         scf_scope_destroy(scope);
17506         scf_service_destroy(svc);
17507         scf_pg_destroy(pg);
17508         scf_property_destroy(prop);
17509         scf_value_destroy(val);
17510         scf_iter_destroy(iter);
17511         free(pgname);
17512         free(mfile);
17513 
17514         return (0);
17515 }
17516 
17517 #ifndef NATIVE_BUILD
17518 /* ARGSUSED */
17519 CPL_MATCH_FN(complete_select)
17520 {
17521         const char *arg0, *arg1, *arg1end;
17522         int word_start, err = 0, r;
17523         size_t len;
17524         char *buf;
17525 
17526         lscf_prep_hndl();
17527 
17528         arg0 = line + strspn(line, " \t");
17529         assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17530 
17531         arg1 = arg0 + sizeof ("select") - 1;
17532         arg1 += strspn(arg1, " \t");
17533         word_start = arg1 - line;
17534 
17535         arg1end = arg1 + strcspn(arg1, " \t");
17536         if (arg1end < line + word_end)
17537                 return (0);
17538 
17539         len = line + word_end - arg1;
17540 
17541         buf = safe_malloc(max_scf_name_len + 1);
17542 
17543         if (cur_snap != NULL) {
17544                 return (0);
17545         } else if (cur_inst != NULL) {
17546                 return (0);
17547         } else if (cur_svc != NULL) {
17548                 scf_instance_t *inst;
17549                 scf_iter_t *iter;
17550 
17551                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17552                     (iter = scf_iter_create(g_hndl)) == NULL)
17553                         scfdie();
17554 
17555                 if (scf_iter_service_instances(iter, cur_svc) != 0)
17556                         scfdie();
17557 
17558                 for (;;) {
17559                         r = scf_iter_next_instance(iter, inst);
17560                         if (r == 0)
17561                                 break;
17562                         if (r != 1)
17563                                 scfdie();
17564 
17565                         if (scf_instance_get_name(inst, buf,
17566                             max_scf_name_len + 1) < 0)
17567                                 scfdie();
17568 
17569                         if (strncmp(buf, arg1, len) == 0) {
17570                                 err = cpl_add_completion(cpl, line, word_start,
17571                                     word_end, buf + len, "", " ");
17572                                 if (err != 0)
17573                                         break;
17574                         }
17575                 }
17576 
17577                 scf_iter_destroy(iter);
17578                 scf_instance_destroy(inst);
17579 
17580                 return (err);
17581         } else {
17582                 scf_service_t *svc;
17583                 scf_iter_t *iter;
17584 
17585                 assert(cur_scope != NULL);
17586 
17587                 if ((svc = scf_service_create(g_hndl)) == NULL ||
17588                     (iter = scf_iter_create(g_hndl)) == NULL)
17589                         scfdie();
17590 
17591                 if (scf_iter_scope_services(iter, cur_scope) != 0)
17592                         scfdie();
17593 
17594                 for (;;) {
17595                         r = scf_iter_next_service(iter, svc);
17596                         if (r == 0)
17597                                 break;
17598                         if (r != 1)
17599                                 scfdie();
17600 
17601                         if (scf_service_get_name(svc, buf,
17602                             max_scf_name_len + 1) < 0)
17603                                 scfdie();
17604 
17605                         if (strncmp(buf, arg1, len) == 0) {
17606                                 err = cpl_add_completion(cpl, line, word_start,
17607                                     word_end, buf + len, "", " ");
17608                                 if (err != 0)
17609                                         break;
17610                         }
17611                 }
17612 
17613                 scf_iter_destroy(iter);
17614                 scf_service_destroy(svc);
17615 
17616                 return (err);
17617         }
17618 }
17619 
17620 /* ARGSUSED */
17621 CPL_MATCH_FN(complete_command)
17622 {
17623         uint32_t scope = 0;
17624 
17625         if (cur_snap != NULL)
17626                 scope = CS_SNAP;
17627         else if (cur_inst != NULL)
17628                 scope = CS_INST;
17629         else if (cur_svc != NULL)
17630                 scope = CS_SVC;
17631         else
17632                 scope = CS_SCOPE;
17633 
17634         return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17635 }
17636 #endif  /* NATIVE_BUILD */