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 2019 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_RESTARTER) == 0) {
10526                         xmlNodePtr rnode, sfnode;
10527 
10528                         rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10529                         if (rnode == NULL)
10530                                 uu_die(emsg_create_xml);
10531 
10532                         sfnode = xmlNewChild(rnode, NULL,
10533                             (xmlChar *)"service_fmri", NULL);
10534                         if (sfnode == NULL)
10535                                 uu_die(emsg_create_xml);
10536 
10537                         if (set_attr_from_prop(exp_prop, sfnode,
10538                             value_attr) == 0) {
10539                                 elts->restarter = rnode;
10540                                 continue;
10541                         }
10542 
10543                         xmlFreeNode(rnode);
10544                 }
10545 
10546                 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10547         }
10548         if (ret == -1)
10549                 scfdie();
10550 
10551         if (pgelts.propvals != NULL || pgelts.properties != NULL)
10552                 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10553                     elts);
10554 }
10555 
10556 /*
10557  * Put an instance element for the given instance into selts.
10558  */
10559 static void
10560 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10561 {
10562         xmlNodePtr n;
10563         boolean_t isdefault;
10564         struct entity_elts elts;
10565         struct template_elts template_elts;
10566         int ret;
10567 
10568         n = xmlNewNode(NULL, (xmlChar *)"instance");
10569         if (n == NULL)
10570                 uu_die(emsg_create_xml);
10571 
10572         /* name */
10573         if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10574                 scfdie();
10575         safe_setprop(n, name_attr, exp_str);
10576         isdefault = strcmp(exp_str, "default") == 0;
10577 
10578         /* check existance of general pg (since general/enabled is required) */
10579         if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10580                 if (scf_error() != SCF_ERROR_NOT_FOUND)
10581                         scfdie();
10582 
10583                 if (g_verbose) {
10584                         if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10585                                 scfdie();
10586 
10587                         warn(gettext("Instance %s has no general property "
10588                             "group; it will be marked disabled.\n"), exp_str);
10589                 }
10590 
10591                 safe_setprop(n, enabled_attr, false);
10592         } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10593             strcmp(exp_str, scf_group_framework) != 0) {
10594                 if (g_verbose) {
10595                         if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10596                                 scfdie();
10597 
10598                         warn(gettext("Property group %s is not of type "
10599                             "framework; the instance will be marked "
10600                             "disabled.\n"), exp_str);
10601                 }
10602 
10603                 safe_setprop(n, enabled_attr, false);
10604         }
10605 
10606         /* property groups */
10607         if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10608                 scfdie();
10609 
10610         (void) memset(&elts, 0, sizeof (elts));
10611         (void) memset(&template_elts, 0, sizeof (template_elts));
10612 
10613         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10614                 uint32_t pgflags;
10615 
10616                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10617                         scfdie();
10618 
10619                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10620                         continue;
10621 
10622                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10623                         scfdie();
10624 
10625                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10626                         export_dependency(exp_pg, &elts);
10627                         continue;
10628                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10629                         export_method(exp_pg, &elts);
10630                         continue;
10631                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10632                         if (scf_pg_get_name(exp_pg, exp_str,
10633                             max_scf_name_len + 1) < 0)
10634                                 scfdie();
10635 
10636                         if (strcmp(exp_str, scf_pg_general) == 0) {
10637                                 export_inst_general(exp_pg, n, &elts);
10638                                 continue;
10639                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10640                             0) {
10641                                 export_method_context(exp_pg, &elts);
10642                                 continue;
10643                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10644                                 export_dependents(exp_pg, &elts);
10645                                 continue;
10646                         }
10647                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10648                         export_template(exp_pg, &elts, &template_elts);
10649                         continue;
10650                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10651                         export_notify_params(exp_pg, &elts);
10652                         continue;
10653                 }
10654 
10655                 /* Ordinary pg. */
10656                 export_pg(exp_pg, &elts, flags);
10657         }
10658         if (ret == -1)
10659                 scfdie();
10660 
10661         if (template_elts.common_name != NULL) {
10662                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10663                 (void) xmlAddChild(elts.template, template_elts.common_name);
10664                 (void) xmlAddChild(elts.template, template_elts.description);
10665                 (void) xmlAddChild(elts.template, template_elts.documentation);
10666         } else {
10667                 xmlFreeNode(template_elts.description);
10668                 xmlFreeNode(template_elts.documentation);
10669         }
10670 
10671         if (isdefault && elts.restarter == NULL &&
10672             elts.dependencies == NULL && elts.method_context == NULL &&
10673             elts.exec_methods == NULL && elts.notify_params == NULL &&
10674             elts.property_groups == NULL && elts.template == NULL) {
10675                 xmlChar *eval;
10676 
10677                 /* This is a default instance */
10678                 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10679 
10680                 xmlFreeNode(n);
10681 
10682                 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10683                 if (n == NULL)
10684                         uu_die(emsg_create_xml);
10685 
10686                 safe_setprop(n, enabled_attr, (char *)eval);
10687                 xmlFree(eval);
10688 
10689                 selts->create_default_instance = n;
10690         } else {
10691                 /* Assemble the children in order. */
10692                 (void) xmlAddChild(n, elts.restarter);
10693                 (void) xmlAddChildList(n, elts.dependencies);
10694                 (void) xmlAddChildList(n, elts.dependents);
10695                 (void) xmlAddChild(n, elts.method_context);
10696                 (void) xmlAddChildList(n, elts.exec_methods);
10697                 (void) xmlAddChildList(n, elts.notify_params);
10698                 (void) xmlAddChildList(n, elts.property_groups);
10699                 (void) xmlAddChild(n, elts.template);
10700 
10701                 if (selts->instances == NULL)
10702                         selts->instances = n;
10703                 else
10704                         (void) xmlAddSibling(selts->instances, n);
10705         }
10706 }
10707 
10708 /*
10709  * Return a service element for the given service.
10710  */
10711 static xmlNodePtr
10712 export_service(scf_service_t *svc, int flags)
10713 {
10714         xmlNodePtr snode;
10715         struct entity_elts elts;
10716         struct template_elts template_elts;
10717         int ret;
10718 
10719         snode = xmlNewNode(NULL, (xmlChar *)"service");
10720         if (snode == NULL)
10721                 uu_die(emsg_create_xml);
10722 
10723         /* Get & set name attribute */
10724         if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10725                 scfdie();
10726         safe_setprop(snode, name_attr, exp_str);
10727 
10728         safe_setprop(snode, type_attr, "service");
10729         safe_setprop(snode, "version", "0");
10730 
10731         /* Acquire child elements. */
10732         if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10733                 scfdie();
10734 
10735         (void) memset(&elts, 0, sizeof (elts));
10736         (void) memset(&template_elts, 0, sizeof (template_elts));
10737 
10738         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10739                 uint32_t pgflags;
10740 
10741                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10742                         scfdie();
10743 
10744                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10745                         continue;
10746 
10747                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10748                         scfdie();
10749 
10750                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10751                         export_dependency(exp_pg, &elts);
10752                         continue;
10753                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10754                         export_method(exp_pg, &elts);
10755                         continue;
10756                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10757                         if (scf_pg_get_name(exp_pg, exp_str,
10758                             max_scf_name_len + 1) < 0)
10759                                 scfdie();
10760 
10761                         if (strcmp(exp_str, scf_pg_general) == 0) {
10762                                 export_svc_general(exp_pg, &elts);
10763                                 continue;
10764                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10765                             0) {
10766                                 export_method_context(exp_pg, &elts);
10767                                 continue;
10768                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10769                                 export_dependents(exp_pg, &elts);
10770                                 continue;
10771                         } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10772                                 continue;
10773                         }
10774                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10775                         export_template(exp_pg, &elts, &template_elts);
10776                         continue;
10777                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10778                         export_notify_params(exp_pg, &elts);
10779                         continue;
10780                 }
10781 
10782                 export_pg(exp_pg, &elts, flags);
10783         }
10784         if (ret == -1)
10785                 scfdie();
10786 
10787         if (template_elts.common_name != NULL) {
10788                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10789                 (void) xmlAddChild(elts.template, template_elts.common_name);
10790                 (void) xmlAddChild(elts.template, template_elts.description);
10791                 (void) xmlAddChild(elts.template, template_elts.documentation);
10792         } else {
10793                 xmlFreeNode(template_elts.description);
10794                 xmlFreeNode(template_elts.documentation);
10795         }
10796 
10797         /* Iterate instances */
10798         if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10799                 scfdie();
10800 
10801         while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10802                 export_instance(exp_inst, &elts, flags);
10803         if (ret == -1)
10804                 scfdie();
10805 
10806         /* Now add all of the accumulated elements in order. */
10807         (void) xmlAddChild(snode, elts.create_default_instance);
10808         (void) xmlAddChild(snode, elts.single_instance);
10809         (void) xmlAddChild(snode, elts.restarter);
10810         (void) xmlAddChildList(snode, elts.dependencies);
10811         (void) xmlAddChildList(snode, elts.dependents);
10812         (void) xmlAddChild(snode, elts.method_context);
10813         (void) xmlAddChildList(snode, elts.exec_methods);
10814         (void) xmlAddChildList(snode, elts.notify_params);
10815         (void) xmlAddChildList(snode, elts.property_groups);
10816         (void) xmlAddChildList(snode, elts.instances);
10817         (void) xmlAddChild(snode, elts.stability);
10818         (void) xmlAddChild(snode, elts.template);
10819 
10820         return (snode);
10821 }
10822 
10823 static int
10824 export_callback(void *data, scf_walkinfo_t *wip)
10825 {
10826         FILE *f;
10827         xmlDocPtr doc;
10828         xmlNodePtr sb;
10829         int result;
10830         struct export_args *argsp = (struct export_args *)data;
10831 
10832         if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10833             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10834             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10835             (exp_val = scf_value_create(g_hndl)) == NULL ||
10836             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10837             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10838             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10839             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10840                 scfdie();
10841 
10842         exp_str_sz = max_scf_len + 1;
10843         exp_str = safe_malloc(exp_str_sz);
10844 
10845         if (argsp->filename != NULL) {
10846                 errno = 0;
10847                 f = fopen(argsp->filename, "wb");
10848                 if (f == NULL) {
10849                         if (errno == 0)
10850                                 uu_die(gettext("Could not open \"%s\": no free "
10851                                     "stdio streams.\n"), argsp->filename);
10852                         else
10853                                 uu_die(gettext("Could not open \"%s\""),
10854                                     argsp->filename);
10855                 }
10856         } else
10857                 f = stdout;
10858 
10859         doc = xmlNewDoc((xmlChar *)"1.0");
10860         if (doc == NULL)
10861                 uu_die(gettext("Could not create XML document.\n"));
10862 
10863         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10864             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10865                 uu_die(emsg_create_xml);
10866 
10867         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10868         if (sb == NULL)
10869                 uu_die(emsg_create_xml);
10870         safe_setprop(sb, type_attr, "manifest");
10871         safe_setprop(sb, name_attr, "export");
10872         (void) xmlAddSibling(doc->children, sb);
10873 
10874         (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10875 
10876         result = write_service_bundle(doc, f);
10877 
10878         free(exp_str);
10879         scf_iter_destroy(exp_val_iter);
10880         scf_iter_destroy(exp_prop_iter);
10881         scf_iter_destroy(exp_pg_iter);
10882         scf_iter_destroy(exp_inst_iter);
10883         scf_value_destroy(exp_val);
10884         scf_property_destroy(exp_prop);
10885         scf_pg_destroy(exp_pg);
10886         scf_instance_destroy(exp_inst);
10887 
10888         xmlFreeDoc(doc);
10889 
10890         if (f != stdout)
10891                 (void) fclose(f);
10892 
10893         return (result);
10894 }
10895 
10896 /*
10897  * Get the service named by fmri, build an XML tree which represents it, and
10898  * dump it into filename (or stdout if filename is NULL).
10899  */
10900 int
10901 lscf_service_export(char *fmri, const char *filename, int flags)
10902 {
10903         struct export_args args;
10904         char *fmridup;
10905         const char *scope, *svc, *inst;
10906         size_t cblen = 3 * max_scf_name_len;
10907         char *canonbuf = alloca(cblen);
10908         int ret, err;
10909 
10910         lscf_prep_hndl();
10911 
10912         bzero(&args, sizeof (args));
10913         args.filename = filename;
10914         args.flags = flags;
10915 
10916         /*
10917          * If some poor user has passed an exact instance FMRI, of the sort
10918          * one might cut and paste from svcs(1) or an error message, warn
10919          * and chop off the instance instead of failing.
10920          */
10921         fmridup = alloca(strlen(fmri) + 1);
10922         (void) strcpy(fmridup, fmri);
10923         if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10924             sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10925             scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10926             inst != NULL) {
10927                 (void) strlcpy(canonbuf, "svc:/", cblen);
10928                 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10929                         (void) strlcat(canonbuf, "/", cblen);
10930                         (void) strlcat(canonbuf, scope, cblen);
10931                 }
10932                 (void) strlcat(canonbuf, svc, cblen);
10933                 fmri = canonbuf;
10934 
10935                 warn(gettext("Only services may be exported; ignoring "
10936                     "instance portion of argument.\n"));
10937         }
10938 
10939         err = 0;
10940         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10941             SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10942             &args, &err, semerr)) != 0) {
10943                 if (ret != -1)
10944                         semerr(gettext("Failed to walk instances: %s\n"),
10945                             scf_strerror(ret));
10946                 return (-1);
10947         }
10948 
10949         /*
10950          * Error message has already been printed.
10951          */
10952         if (err != 0)
10953                 return (-1);
10954 
10955         return (0);
10956 }
10957 
10958 
10959 /*
10960  * Archive
10961  */
10962 
10963 static xmlNodePtr
10964 make_archive(int flags)
10965 {
10966         xmlNodePtr sb;
10967         scf_scope_t *scope;
10968         scf_service_t *svc;
10969         scf_iter_t *iter;
10970         int r;
10971 
10972         if ((scope = scf_scope_create(g_hndl)) == NULL ||
10973             (svc = scf_service_create(g_hndl)) == NULL ||
10974             (iter = scf_iter_create(g_hndl)) == NULL ||
10975             (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10976             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10977             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10978             (exp_val = scf_value_create(g_hndl)) == NULL ||
10979             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10980             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10981             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10982             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10983                 scfdie();
10984 
10985         exp_str_sz = max_scf_len + 1;
10986         exp_str = safe_malloc(exp_str_sz);
10987 
10988         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10989         if (sb == NULL)
10990                 uu_die(emsg_create_xml);
10991         safe_setprop(sb, type_attr, "archive");
10992         safe_setprop(sb, name_attr, "none");
10993 
10994         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10995                 scfdie();
10996         if (scf_iter_scope_services(iter, scope) != 0)
10997                 scfdie();
10998 
10999         for (;;) {
11000                 r = scf_iter_next_service(iter, svc);
11001                 if (r == 0)
11002                         break;
11003                 if (r != 1)
11004                         scfdie();
11005 
11006                 if (scf_service_get_name(svc, exp_str,
11007                     max_scf_name_len + 1) < 0)
11008                         scfdie();
11009 
11010                 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11011                         continue;
11012 
11013                 (void) xmlAddChild(sb, export_service(svc, flags));
11014         }
11015 
11016         free(exp_str);
11017 
11018         scf_iter_destroy(exp_val_iter);
11019         scf_iter_destroy(exp_prop_iter);
11020         scf_iter_destroy(exp_pg_iter);
11021         scf_iter_destroy(exp_inst_iter);
11022         scf_value_destroy(exp_val);
11023         scf_property_destroy(exp_prop);
11024         scf_pg_destroy(exp_pg);
11025         scf_instance_destroy(exp_inst);
11026         scf_iter_destroy(iter);
11027         scf_service_destroy(svc);
11028         scf_scope_destroy(scope);
11029 
11030         return (sb);
11031 }
11032 
11033 int
11034 lscf_archive(const char *filename, int flags)
11035 {
11036         FILE *f;
11037         xmlDocPtr doc;
11038         int result;
11039 
11040         lscf_prep_hndl();
11041 
11042         if (filename != NULL) {
11043                 errno = 0;
11044                 f = fopen(filename, "wb");
11045                 if (f == NULL) {
11046                         if (errno == 0)
11047                                 uu_die(gettext("Could not open \"%s\": no free "
11048                                     "stdio streams.\n"), filename);
11049                         else
11050                                 uu_die(gettext("Could not open \"%s\""),
11051                                     filename);
11052                 }
11053         } else
11054                 f = stdout;
11055 
11056         doc = xmlNewDoc((xmlChar *)"1.0");
11057         if (doc == NULL)
11058                 uu_die(gettext("Could not create XML document.\n"));
11059 
11060         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11061             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11062                 uu_die(emsg_create_xml);
11063 
11064         (void) xmlAddSibling(doc->children, make_archive(flags));
11065 
11066         result = write_service_bundle(doc, f);
11067 
11068         xmlFreeDoc(doc);
11069 
11070         if (f != stdout)
11071                 (void) fclose(f);
11072 
11073         return (result);
11074 }
11075 
11076 
11077 /*
11078  * "Extract" a profile.
11079  */
11080 int
11081 lscf_profile_extract(const char *filename)
11082 {
11083         FILE *f;
11084         xmlDocPtr doc;
11085         xmlNodePtr sb, snode, inode;
11086         scf_scope_t *scope;
11087         scf_service_t *svc;
11088         scf_instance_t *inst;
11089         scf_propertygroup_t *pg;
11090         scf_property_t *prop;
11091         scf_value_t *val;
11092         scf_iter_t *siter, *iiter;
11093         int r, s;
11094         char *namebuf;
11095         uint8_t b;
11096         int result;
11097 
11098         lscf_prep_hndl();
11099 
11100         if (filename != NULL) {
11101                 errno = 0;
11102                 f = fopen(filename, "wb");
11103                 if (f == NULL) {
11104                         if (errno == 0)
11105                                 uu_die(gettext("Could not open \"%s\": no "
11106                                     "free stdio streams.\n"), filename);
11107                         else
11108                                 uu_die(gettext("Could not open \"%s\""),
11109                                     filename);
11110                 }
11111         } else
11112                 f = stdout;
11113 
11114         doc = xmlNewDoc((xmlChar *)"1.0");
11115         if (doc == NULL)
11116                 uu_die(gettext("Could not create XML document.\n"));
11117 
11118         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11119             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11120                 uu_die(emsg_create_xml);
11121 
11122         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11123         if (sb == NULL)
11124                 uu_die(emsg_create_xml);
11125         safe_setprop(sb, type_attr, "profile");
11126         safe_setprop(sb, name_attr, "extract");
11127         (void) xmlAddSibling(doc->children, sb);
11128 
11129         if ((scope = scf_scope_create(g_hndl)) == NULL ||
11130             (svc = scf_service_create(g_hndl)) == NULL ||
11131             (inst = scf_instance_create(g_hndl)) == NULL ||
11132             (pg = scf_pg_create(g_hndl)) == NULL ||
11133             (prop = scf_property_create(g_hndl)) == NULL ||
11134             (val = scf_value_create(g_hndl)) == NULL ||
11135             (siter = scf_iter_create(g_hndl)) == NULL ||
11136             (iiter = scf_iter_create(g_hndl)) == NULL)
11137                 scfdie();
11138 
11139         if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11140                 scfdie();
11141 
11142         if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11143                 scfdie();
11144 
11145         namebuf = safe_malloc(max_scf_name_len + 1);
11146 
11147         while ((r = scf_iter_next_service(siter, svc)) == 1) {
11148                 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11149                         scfdie();
11150 
11151                 snode = xmlNewNode(NULL, (xmlChar *)"service");
11152                 if (snode == NULL)
11153                         uu_die(emsg_create_xml);
11154 
11155                 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11156                     0)
11157                         scfdie();
11158 
11159                 safe_setprop(snode, name_attr, namebuf);
11160 
11161                 safe_setprop(snode, type_attr, "service");
11162                 safe_setprop(snode, "version", "0");
11163 
11164                 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11165                         if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11166                             SCF_SUCCESS) {
11167                                 if (scf_error() != SCF_ERROR_NOT_FOUND)
11168                                         scfdie();
11169 
11170                                 if (g_verbose) {
11171                                         ssize_t len;
11172                                         char *fmri;
11173 
11174                                         len =
11175                                             scf_instance_to_fmri(inst, NULL, 0);
11176                                         if (len < 0)
11177                                                 scfdie();
11178 
11179                                         fmri = safe_malloc(len + 1);
11180 
11181                                         if (scf_instance_to_fmri(inst, fmri,
11182                                             len + 1) < 0)
11183                                                 scfdie();
11184 
11185                                         warn("Instance %s has no \"%s\" "
11186                                             "property group.\n", fmri,
11187                                             scf_pg_general);
11188 
11189                                         free(fmri);
11190                                 }
11191 
11192                                 continue;
11193                         }
11194 
11195                         if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11196                             prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11197                             prop_get_val(prop, val) != 0)
11198                                 continue;
11199 
11200                         inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11201                             NULL);
11202                         if (inode == NULL)
11203                                 uu_die(emsg_create_xml);
11204 
11205                         if (scf_instance_get_name(inst, namebuf,
11206                             max_scf_name_len + 1) < 0)
11207                                 scfdie();
11208 
11209                         safe_setprop(inode, name_attr, namebuf);
11210 
11211                         if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11212                                 scfdie();
11213 
11214                         safe_setprop(inode, enabled_attr, b ? true : false);
11215                 }
11216                 if (s < 0)
11217                         scfdie();
11218 
11219                 if (snode->children != NULL)
11220                         (void) xmlAddChild(sb, snode);
11221                 else
11222                         xmlFreeNode(snode);
11223         }
11224         if (r < 0)
11225                 scfdie();
11226 
11227         free(namebuf);
11228 
11229         result = write_service_bundle(doc, f);
11230 
11231         xmlFreeDoc(doc);
11232 
11233         if (f != stdout)
11234                 (void) fclose(f);
11235 
11236         return (result);
11237 }
11238 
11239 
11240 /*
11241  * Entity manipulation commands
11242  */
11243 
11244 /*
11245  * Entity selection.  If no entity is selected, then the current scope is in
11246  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11247  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11248  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11249  * cur_inst will be non-NULL.
11250  */
11251 
11252 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11253 static int
11254 select_inst(const char *name)
11255 {
11256         scf_instance_t *inst;
11257         scf_error_t err;
11258 
11259         assert(cur_svc != NULL);
11260 
11261         inst = scf_instance_create(g_hndl);
11262         if (inst == NULL)
11263                 scfdie();
11264 
11265         if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11266                 cur_inst = inst;
11267                 return (0);
11268         }
11269 
11270         err = scf_error();
11271         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11272                 scfdie();
11273 
11274         scf_instance_destroy(inst);
11275         return (1);
11276 }
11277 
11278 /* Returns as above. */
11279 static int
11280 select_svc(const char *name)
11281 {
11282         scf_service_t *svc;
11283         scf_error_t err;
11284 
11285         assert(cur_scope != NULL);
11286 
11287         svc = scf_service_create(g_hndl);
11288         if (svc == NULL)
11289                 scfdie();
11290 
11291         if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11292                 cur_svc = svc;
11293                 return (0);
11294         }
11295 
11296         err = scf_error();
11297         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11298                 scfdie();
11299 
11300         scf_service_destroy(svc);
11301         return (1);
11302 }
11303 
11304 /* ARGSUSED */
11305 static int
11306 select_callback(void *unused, scf_walkinfo_t *wip)
11307 {
11308         scf_instance_t *inst;
11309         scf_service_t *svc;
11310         scf_scope_t *scope;
11311 
11312         if (wip->inst != NULL) {
11313                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11314                     (svc = scf_service_create(g_hndl)) == NULL ||
11315                     (inst = scf_instance_create(g_hndl)) == NULL)
11316                         scfdie();
11317 
11318                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11319                     inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11320                         scfdie();
11321         } else {
11322                 assert(wip->svc != NULL);
11323 
11324                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11325                     (svc = scf_service_create(g_hndl)) == NULL)
11326                         scfdie();
11327 
11328                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11329                     NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11330                         scfdie();
11331 
11332                 inst = NULL;
11333         }
11334 
11335         /* Clear out the current selection */
11336         assert(cur_scope != NULL);
11337         scf_scope_destroy(cur_scope);
11338         scf_service_destroy(cur_svc);
11339         scf_instance_destroy(cur_inst);
11340 
11341         cur_scope = scope;
11342         cur_svc = svc;
11343         cur_inst = inst;
11344 
11345         return (0);
11346 }
11347 
11348 static int
11349 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11350 {
11351         char **fmri = fmri_p;
11352 
11353         *fmri = strdup(wip->fmri);
11354         if (*fmri == NULL)
11355                 uu_die(gettext("Out of memory.\n"));
11356 
11357         return (0);
11358 }
11359 
11360 /*
11361  * validate [fmri]
11362  * Perform the validation of an FMRI instance.
11363  */
11364 void
11365 lscf_validate_fmri(const char *fmri)
11366 {
11367         int ret = 0;
11368         size_t inst_sz;
11369         char *inst_fmri = NULL;
11370         scf_tmpl_errors_t *errs = NULL;
11371         char *snapbuf = NULL;
11372 
11373         lscf_prep_hndl();
11374 
11375         if (fmri == NULL) {
11376                 inst_sz = max_scf_fmri_len + 1;
11377                 inst_fmri = safe_malloc(inst_sz);
11378 
11379                 if (cur_snap != NULL) {
11380                         snapbuf = safe_malloc(max_scf_name_len + 1);
11381                         if (scf_snapshot_get_name(cur_snap, snapbuf,
11382                             max_scf_name_len + 1) < 0)
11383                                 scfdie();
11384                 }
11385                 if (cur_inst == NULL) {
11386                         semerr(gettext("No instance selected\n"));
11387                         goto cleanup;
11388                 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11389                     inst_sz) >= inst_sz) {
11390                         /* sanity check. Should never get here */
11391                         uu_die(gettext("Unexpected error! file %s, line %d\n"),
11392                             __FILE__, __LINE__);
11393                 }
11394         } else {
11395                 scf_error_t scf_err;
11396                 int err = 0;
11397 
11398                 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11399                     validate_callback, &inst_fmri, &err, semerr)) != 0) {
11400                         uu_warn("Failed to walk instances: %s\n",
11401                             scf_strerror(scf_err));
11402                         goto cleanup;
11403                 }
11404                 if (err != 0) {
11405                         /* error message displayed by scf_walk_fmri */
11406                         goto cleanup;
11407                 }
11408         }
11409 
11410         ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11411             SCF_TMPL_VALIDATE_FLAG_CURRENT);
11412         if (ret == -1) {
11413                 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11414                         warn(gettext("Template data for %s is invalid. "
11415                             "Consider reverting to a previous snapshot or "
11416                             "restoring original configuration.\n"), inst_fmri);
11417                 } else {
11418                         uu_warn("%s: %s\n",
11419                             gettext("Error validating the instance"),
11420                             scf_strerror(scf_error()));
11421                 }
11422         } else if (ret == 1 && errs != NULL) {
11423                 scf_tmpl_error_t *err = NULL;
11424                 char *msg;
11425                 size_t len = 256;       /* initial error buffer size */
11426                 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11427                     SCF_TMPL_STRERROR_HUMAN : 0;
11428 
11429                 msg = safe_malloc(len);
11430 
11431                 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11432                         int ret;
11433 
11434                         if ((ret = scf_tmpl_strerror(err, msg, len,
11435                             flag)) >= len) {
11436                                 len = ret + 1;
11437                                 msg = realloc(msg, len);
11438                                 if (msg == NULL)
11439                                         uu_die(gettext(
11440                                             "Out of memory.\n"));
11441                                 (void) scf_tmpl_strerror(err, msg, len,
11442                                     flag);
11443                         }
11444                         (void) fprintf(stderr, "%s\n", msg);
11445                 }
11446                 if (msg != NULL)
11447                         free(msg);
11448         }
11449         if (errs != NULL)
11450                 scf_tmpl_errors_destroy(errs);
11451 
11452 cleanup:
11453         free(inst_fmri);
11454         free(snapbuf);
11455 }
11456 
11457 static void
11458 lscf_validate_file(const char *filename)
11459 {
11460         tmpl_errors_t *errs;
11461 
11462         bundle_t *b = internal_bundle_new();
11463         if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11464                 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11465                         tmpl_errors_print(stderr, errs, "");
11466                         semerr(gettext("Validation failed.\n"));
11467                 }
11468                 tmpl_errors_destroy(errs);
11469         }
11470         (void) internal_bundle_free(b);
11471 }
11472 
11473 /*
11474  * validate [fmri|file]
11475  */
11476 void
11477 lscf_validate(const char *arg)
11478 {
11479         const char *str;
11480 
11481         if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11482             sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11483                 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11484                 lscf_validate_file(str);
11485         } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11486             sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11487                 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11488                 lscf_validate_fmri(str);
11489         } else if (access(arg, R_OK | F_OK) == 0) {
11490                 lscf_validate_file(arg);
11491         } else {
11492                 lscf_validate_fmri(arg);
11493         }
11494 }
11495 
11496 void
11497 lscf_select(const char *fmri)
11498 {
11499         int ret, err;
11500 
11501         lscf_prep_hndl();
11502 
11503         if (cur_snap != NULL) {
11504                 struct snaplevel *elt;
11505                 char *buf;
11506 
11507                 /* Error unless name is that of the next level. */
11508                 elt = uu_list_next(cur_levels, cur_elt);
11509                 if (elt == NULL) {
11510                         semerr(gettext("No children.\n"));
11511                         return;
11512                 }
11513 
11514                 buf = safe_malloc(max_scf_name_len + 1);
11515 
11516                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11517                     max_scf_name_len + 1) < 0)
11518                         scfdie();
11519 
11520                 if (strcmp(buf, fmri) != 0) {
11521                         semerr(gettext("No such child.\n"));
11522                         free(buf);
11523                         return;
11524                 }
11525 
11526                 free(buf);
11527 
11528                 cur_elt = elt;
11529                 cur_level = elt->sl;
11530                 return;
11531         }
11532 
11533         /*
11534          * Special case for 'svc:', which takes the user to the scope level.
11535          */
11536         if (strcmp(fmri, "svc:") == 0) {
11537                 scf_instance_destroy(cur_inst);
11538                 scf_service_destroy(cur_svc);
11539                 cur_inst = NULL;
11540                 cur_svc = NULL;
11541                 return;
11542         }
11543 
11544         /*
11545          * Special case for ':properties'.  This appears as part of 'list' but
11546          * can't be selected.  Give a more helpful error message in this case.
11547          */
11548         if (strcmp(fmri, ":properties") == 0) {
11549                 semerr(gettext(":properties is not an entity.  Try 'listprop' "
11550                     "to list properties.\n"));
11551                 return;
11552         }
11553 
11554         /*
11555          * First try the argument as relative to the current selection.
11556          */
11557         if (cur_inst != NULL) {
11558                 /* EMPTY */;
11559         } else if (cur_svc != NULL) {
11560                 if (select_inst(fmri) != 1)
11561                         return;
11562         } else {
11563                 if (select_svc(fmri) != 1)
11564                         return;
11565         }
11566 
11567         err = 0;
11568         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11569             select_callback, NULL, &err, semerr)) != 0) {
11570                 semerr(gettext("Failed to walk instances: %s\n"),
11571                     scf_strerror(ret));
11572         }
11573 }
11574 
11575 void
11576 lscf_unselect(void)
11577 {
11578         lscf_prep_hndl();
11579 
11580         if (cur_snap != NULL) {
11581                 struct snaplevel *elt;
11582 
11583                 elt = uu_list_prev(cur_levels, cur_elt);
11584                 if (elt == NULL) {
11585                         semerr(gettext("No parent levels.\n"));
11586                 } else {
11587                         cur_elt = elt;
11588                         cur_level = elt->sl;
11589                 }
11590         } else if (cur_inst != NULL) {
11591                 scf_instance_destroy(cur_inst);
11592                 cur_inst = NULL;
11593         } else if (cur_svc != NULL) {
11594                 scf_service_destroy(cur_svc);
11595                 cur_svc = NULL;
11596         } else {
11597                 semerr(gettext("Cannot unselect at scope level.\n"));
11598         }
11599 }
11600 
11601 /*
11602  * Return the FMRI of the current selection, for the prompt.
11603  */
11604 void
11605 lscf_get_selection_str(char *buf, size_t bufsz)
11606 {
11607         char *cp;
11608         ssize_t fmrilen, szret;
11609         boolean_t deleted = B_FALSE;
11610 
11611         if (g_hndl == NULL) {
11612                 (void) strlcpy(buf, "svc:", bufsz);
11613                 return;
11614         }
11615 
11616         if (cur_level != NULL) {
11617                 assert(cur_snap != NULL);
11618 
11619                 /* [ snapshot ] FMRI [: instance ] */
11620                 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11621                     + 2 + max_scf_name_len + 1 + 1);
11622 
11623                 buf[0] = '[';
11624 
11625                 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11626                     max_scf_name_len + 1);
11627                 if (szret < 0) {
11628                         if (scf_error() != SCF_ERROR_DELETED)
11629                                 scfdie();
11630 
11631                         goto snap_deleted;
11632                 }
11633 
11634                 (void) strcat(buf, "]svc:/");
11635 
11636                 cp = strchr(buf, '\0');
11637 
11638                 szret = scf_snaplevel_get_service_name(cur_level, cp,
11639                     max_scf_name_len + 1);
11640                 if (szret < 0) {
11641                         if (scf_error() != SCF_ERROR_DELETED)
11642                                 scfdie();
11643 
11644                         goto snap_deleted;
11645                 }
11646 
11647                 cp = strchr(cp, '\0');
11648 
11649                 if (snaplevel_is_instance(cur_level)) {
11650                         *cp++ = ':';
11651 
11652                         if (scf_snaplevel_get_instance_name(cur_level, cp,
11653                             max_scf_name_len + 1) < 0) {
11654                                 if (scf_error() != SCF_ERROR_DELETED)
11655                                         scfdie();
11656 
11657                                 goto snap_deleted;
11658                         }
11659                 } else {
11660                         *cp++ = '[';
11661                         *cp++ = ':';
11662 
11663                         if (scf_instance_get_name(cur_inst, cp,
11664                             max_scf_name_len + 1) < 0) {
11665                                 if (scf_error() != SCF_ERROR_DELETED)
11666                                         scfdie();
11667 
11668                                 goto snap_deleted;
11669                         }
11670 
11671                         (void) strcat(buf, "]");
11672                 }
11673 
11674                 return;
11675 
11676 snap_deleted:
11677                 deleted = B_TRUE;
11678                 free(buf);
11679                 unselect_cursnap();
11680         }
11681 
11682         assert(cur_snap == NULL);
11683 
11684         if (cur_inst != NULL) {
11685                 assert(cur_svc != NULL);
11686                 assert(cur_scope != NULL);
11687 
11688                 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11689                 if (fmrilen >= 0) {
11690                         assert(fmrilen < bufsz);
11691                         if (deleted)
11692                                 warn(emsg_deleted);
11693                         return;
11694                 }
11695 
11696                 if (scf_error() != SCF_ERROR_DELETED)
11697                         scfdie();
11698 
11699                 deleted = B_TRUE;
11700 
11701                 scf_instance_destroy(cur_inst);
11702                 cur_inst = NULL;
11703         }
11704 
11705         if (cur_svc != NULL) {
11706                 assert(cur_scope != NULL);
11707 
11708                 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11709                 if (szret >= 0) {
11710                         assert(szret < bufsz);
11711                         if (deleted)
11712                                 warn(emsg_deleted);
11713                         return;
11714                 }
11715 
11716                 if (scf_error() != SCF_ERROR_DELETED)
11717                         scfdie();
11718 
11719                 deleted = B_TRUE;
11720                 scf_service_destroy(cur_svc);
11721                 cur_svc = NULL;
11722         }
11723 
11724         assert(cur_scope != NULL);
11725         fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11726 
11727         if (fmrilen < 0)
11728                 scfdie();
11729 
11730         assert(fmrilen < bufsz);
11731         if (deleted)
11732                 warn(emsg_deleted);
11733 }
11734 
11735 /*
11736  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11737  * :statistics) are listed for the current selection.
11738  */
11739 void
11740 lscf_list(const char *pattern)
11741 {
11742         scf_iter_t *iter;
11743         char *buf;
11744         int ret;
11745 
11746         lscf_prep_hndl();
11747 
11748         if (cur_level != NULL) {
11749                 struct snaplevel *elt;
11750 
11751                 (void) fputs(COLON_NAMESPACES, stdout);
11752 
11753                 elt = uu_list_next(cur_levels, cur_elt);
11754                 if (elt == NULL)
11755                         return;
11756 
11757                 /*
11758                  * For now, we know that the next level is an instance.  But
11759                  * if we ever have multiple scopes, this could be complicated.
11760                  */
11761                 buf = safe_malloc(max_scf_name_len + 1);
11762                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11763                     max_scf_name_len + 1) >= 0) {
11764                         (void) puts(buf);
11765                 } else {
11766                         if (scf_error() != SCF_ERROR_DELETED)
11767                                 scfdie();
11768                 }
11769 
11770                 free(buf);
11771 
11772                 return;
11773         }
11774 
11775         if (cur_inst != NULL) {
11776                 (void) fputs(COLON_NAMESPACES, stdout);
11777                 return;
11778         }
11779 
11780         iter = scf_iter_create(g_hndl);
11781         if (iter == NULL)
11782                 scfdie();
11783 
11784         buf = safe_malloc(max_scf_name_len + 1);
11785 
11786         if (cur_svc != NULL) {
11787                 /* List the instances in this service. */
11788                 scf_instance_t *inst;
11789 
11790                 inst = scf_instance_create(g_hndl);
11791                 if (inst == NULL)
11792                         scfdie();
11793 
11794                 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11795                         safe_printf(COLON_NAMESPACES);
11796 
11797                         for (;;) {
11798                                 ret = scf_iter_next_instance(iter, inst);
11799                                 if (ret == 0)
11800                                         break;
11801                                 if (ret != 1) {
11802                                         if (scf_error() != SCF_ERROR_DELETED)
11803                                                 scfdie();
11804 
11805                                         break;
11806                                 }
11807 
11808                                 if (scf_instance_get_name(inst, buf,
11809                                     max_scf_name_len + 1) >= 0) {
11810                                         if (pattern == NULL ||
11811                                             fnmatch(pattern, buf, 0) == 0)
11812                                                 (void) puts(buf);
11813                                 } else {
11814                                         if (scf_error() != SCF_ERROR_DELETED)
11815                                                 scfdie();
11816                                 }
11817                         }
11818                 } else {
11819                         if (scf_error() != SCF_ERROR_DELETED)
11820                                 scfdie();
11821                 }
11822 
11823                 scf_instance_destroy(inst);
11824         } else {
11825                 /* List the services in this scope. */
11826                 scf_service_t *svc;
11827 
11828                 assert(cur_scope != NULL);
11829 
11830                 svc = scf_service_create(g_hndl);
11831                 if (svc == NULL)
11832                         scfdie();
11833 
11834                 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11835                         scfdie();
11836 
11837                 for (;;) {
11838                         ret = scf_iter_next_service(iter, svc);
11839                         if (ret == 0)
11840                                 break;
11841                         if (ret != 1)
11842                                 scfdie();
11843 
11844                         if (scf_service_get_name(svc, buf,
11845                             max_scf_name_len + 1) >= 0) {
11846                                 if (pattern == NULL ||
11847                                     fnmatch(pattern, buf, 0) == 0)
11848                                         safe_printf("%s\n", buf);
11849                         } else {
11850                                 if (scf_error() != SCF_ERROR_DELETED)
11851                                         scfdie();
11852                         }
11853                 }
11854 
11855                 scf_service_destroy(svc);
11856         }
11857 
11858         free(buf);
11859         scf_iter_destroy(iter);
11860 }
11861 
11862 /*
11863  * Entity addition.  Creates an empty entity in the current selection.
11864  */
11865 void
11866 lscf_add(const char *name)
11867 {
11868         lscf_prep_hndl();
11869 
11870         if (cur_snap != NULL) {
11871                 semerr(emsg_cant_modify_snapshots);
11872         } else if (cur_inst != NULL) {
11873                 semerr(gettext("Cannot add entities to an instance.\n"));
11874         } else if (cur_svc != NULL) {
11875 
11876                 if (scf_service_add_instance(cur_svc, name, NULL) !=
11877                     SCF_SUCCESS) {
11878                         switch (scf_error()) {
11879                         case SCF_ERROR_INVALID_ARGUMENT:
11880                                 semerr(gettext("Invalid name.\n"));
11881                                 break;
11882 
11883                         case SCF_ERROR_EXISTS:
11884                                 semerr(gettext("Instance already exists.\n"));
11885                                 break;
11886 
11887                         case SCF_ERROR_PERMISSION_DENIED:
11888                                 semerr(emsg_permission_denied);
11889                                 break;
11890 
11891                         default:
11892                                 scfdie();
11893                         }
11894                 }
11895         } else {
11896                 assert(cur_scope != NULL);
11897 
11898                 if (scf_scope_add_service(cur_scope, name, NULL) !=
11899                     SCF_SUCCESS) {
11900                         switch (scf_error()) {
11901                         case SCF_ERROR_INVALID_ARGUMENT:
11902                                 semerr(gettext("Invalid name.\n"));
11903                                 break;
11904 
11905                         case SCF_ERROR_EXISTS:
11906                                 semerr(gettext("Service already exists.\n"));
11907                                 break;
11908 
11909                         case SCF_ERROR_PERMISSION_DENIED:
11910                                 semerr(emsg_permission_denied);
11911                                 break;
11912 
11913                         case SCF_ERROR_BACKEND_READONLY:
11914                                 semerr(emsg_read_only);
11915                                 break;
11916 
11917                         default:
11918                                 scfdie();
11919                         }
11920                 }
11921         }
11922 }
11923 
11924 /* return 1 if the entity has no persistent pgs, else return 0 */
11925 static int
11926 entity_has_no_pgs(void *ent, int isservice)
11927 {
11928         scf_iter_t *iter = NULL;
11929         scf_propertygroup_t *pg = NULL;
11930         uint32_t flags;
11931         int err;
11932         int ret = 1;
11933 
11934         if ((iter = scf_iter_create(g_hndl)) == NULL ||
11935             (pg = scf_pg_create(g_hndl)) == NULL)
11936                 scfdie();
11937 
11938         if (isservice) {
11939                 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11940                         scfdie();
11941         } else {
11942                 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11943                         scfdie();
11944         }
11945 
11946         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11947                 if (scf_pg_get_flags(pg, &flags) != 0)
11948                         scfdie();
11949 
11950                 /* skip nonpersistent pgs */
11951                 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11952                         continue;
11953 
11954                 ret = 0;
11955                 break;
11956         }
11957 
11958         if (err == -1)
11959                 scfdie();
11960 
11961         scf_pg_destroy(pg);
11962         scf_iter_destroy(iter);
11963 
11964         return (ret);
11965 }
11966 
11967 /* return 1 if the service has no instances, else return 0 */
11968 static int
11969 svc_has_no_insts(scf_service_t *svc)
11970 {
11971         scf_instance_t *inst;
11972         scf_iter_t *iter;
11973         int r;
11974         int ret = 1;
11975 
11976         if ((inst = scf_instance_create(g_hndl)) == NULL ||
11977             (iter = scf_iter_create(g_hndl)) == NULL)
11978                 scfdie();
11979 
11980         if (scf_iter_service_instances(iter, svc) != 0)
11981                 scfdie();
11982 
11983         r = scf_iter_next_instance(iter, inst);
11984         if (r == 1) {
11985                 ret = 0;
11986         } else if (r == 0) {
11987                 ret = 1;
11988         } else if (r == -1) {
11989                 scfdie();
11990         } else {
11991                 bad_error("scf_iter_next_instance", r);
11992         }
11993 
11994         scf_iter_destroy(iter);
11995         scf_instance_destroy(inst);
11996 
11997         return (ret);
11998 }
11999 
12000 /*
12001  * Entity deletion.
12002  */
12003 
12004 /*
12005  * Delete the property group <fmri>/:properties/<name>.  Returns
12006  * SCF_ERROR_NONE on success (or if the entity is not found),
12007  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12008  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12009  * denied.
12010  */
12011 static scf_error_t
12012 delete_dependency_pg(const char *fmri, const char *name)
12013 {
12014         void *entity = NULL;
12015         int isservice;
12016         scf_propertygroup_t *pg = NULL;
12017         scf_error_t result;
12018         char *pgty;
12019         scf_service_t *svc = NULL;
12020         scf_instance_t *inst = NULL;
12021         scf_iter_t *iter = NULL;
12022         char *name_buf = NULL;
12023 
12024         result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12025         switch (result) {
12026         case SCF_ERROR_NONE:
12027                 break;
12028 
12029         case SCF_ERROR_NO_MEMORY:
12030                 uu_die(gettext("Out of memory.\n"));
12031                 /* NOTREACHED */
12032 
12033         case SCF_ERROR_INVALID_ARGUMENT:
12034         case SCF_ERROR_CONSTRAINT_VIOLATED:
12035                 return (SCF_ERROR_INVALID_ARGUMENT);
12036 
12037         case SCF_ERROR_NOT_FOUND:
12038                 result = SCF_ERROR_NONE;
12039                 goto out;
12040 
12041         default:
12042                 bad_error("fmri_to_entity", result);
12043         }
12044 
12045         pg = scf_pg_create(g_hndl);
12046         if (pg == NULL)
12047                 scfdie();
12048 
12049         if (entity_get_pg(entity, isservice, name, pg) != 0) {
12050                 if (scf_error() != SCF_ERROR_NOT_FOUND)
12051                         scfdie();
12052 
12053                 result = SCF_ERROR_NONE;
12054                 goto out;
12055         }
12056 
12057         pgty = safe_malloc(max_scf_pg_type_len + 1);
12058 
12059         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12060                 scfdie();
12061 
12062         if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12063                 result = SCF_ERROR_TYPE_MISMATCH;
12064                 free(pgty);
12065                 goto out;
12066         }
12067 
12068         free(pgty);
12069 
12070         if (scf_pg_delete(pg) != 0) {
12071                 result = scf_error();
12072                 if (result != SCF_ERROR_PERMISSION_DENIED)
12073                         scfdie();
12074                 goto out;
12075         }
12076 
12077         /*
12078          * We have to handle the case where we've just deleted the last
12079          * property group of a "dummy" entity (instance or service).
12080          * A "dummy" entity is an entity only present to hold an
12081          * external dependency.
12082          * So, in the case we deleted the last property group then we
12083          * can also delete the entity. If the entity is an instance then
12084          * we must verify if this was the last instance for the service
12085          * and if it is, we can also delete the service if it doesn't
12086          * have any property group either.
12087          */
12088 
12089         result = SCF_ERROR_NONE;
12090 
12091         if (isservice) {
12092                 svc = (scf_service_t *)entity;
12093 
12094                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12095                     (iter = scf_iter_create(g_hndl)) == NULL)
12096                         scfdie();
12097 
12098                 name_buf = safe_malloc(max_scf_name_len + 1);
12099         } else {
12100                 inst = (scf_instance_t *)entity;
12101         }
12102 
12103         /*
12104          * If the entity is an instance and we've just deleted its last
12105          * property group then we should delete it.
12106          */
12107         if (!isservice && entity_has_no_pgs(entity, isservice)) {
12108                 /* find the service before deleting the inst. - needed later */
12109                 if ((svc = scf_service_create(g_hndl)) == NULL)
12110                         scfdie();
12111 
12112                 if (scf_instance_get_parent(inst, svc) != 0)
12113                         scfdie();
12114 
12115                 /* delete the instance */
12116                 if (scf_instance_delete(inst) != 0) {
12117                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12118                                 scfdie();
12119 
12120                         result = SCF_ERROR_PERMISSION_DENIED;
12121                         goto out;
12122                 }
12123                 /* no need to refresh the instance */
12124                 inst = NULL;
12125         }
12126 
12127         /*
12128          * If the service has no more instances and pgs or we just deleted the
12129          * last instance and the service doesn't have anymore propery groups
12130          * then the service should be deleted.
12131          */
12132         if (svc != NULL &&
12133             svc_has_no_insts(svc) &&
12134             entity_has_no_pgs((void *)svc, 1)) {
12135                 if (scf_service_delete(svc) == 0) {
12136                         if (isservice) {
12137                                 /* no need to refresh the service */
12138                                 svc = NULL;
12139                         }
12140 
12141                         goto out;
12142                 }
12143 
12144                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12145                         scfdie();
12146 
12147                 result = SCF_ERROR_PERMISSION_DENIED;
12148         }
12149 
12150         /* if the entity has not been deleted, refresh it */
12151         if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12152                 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12153                     name_buf);
12154         }
12155 
12156 out:
12157         if (isservice && (inst != NULL && iter != NULL)) {
12158                 free(name_buf);
12159                 scf_iter_destroy(iter);
12160                 scf_instance_destroy(inst);
12161         }
12162 
12163         if (!isservice && svc != NULL) {
12164                 scf_service_destroy(svc);
12165         }
12166 
12167         scf_pg_destroy(pg);
12168         if (entity != NULL)
12169                 entity_destroy(entity, isservice);
12170 
12171         return (result);
12172 }
12173 
12174 static int
12175 delete_dependents(scf_propertygroup_t *pg)
12176 {
12177         char *pgty, *name, *fmri;
12178         scf_property_t *prop;
12179         scf_value_t *val;
12180         scf_iter_t *iter;
12181         int r;
12182         scf_error_t err;
12183 
12184         /* Verify that the pg has the correct type. */
12185         pgty = safe_malloc(max_scf_pg_type_len + 1);
12186         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12187                 scfdie();
12188 
12189         if (strcmp(pgty, scf_group_framework) != 0) {
12190                 if (g_verbose) {
12191                         fmri = safe_malloc(max_scf_fmri_len + 1);
12192                         if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12193                                 scfdie();
12194 
12195                         warn(gettext("Property group %s is not of expected "
12196                             "type %s.\n"), fmri, scf_group_framework);
12197 
12198                         free(fmri);
12199                 }
12200 
12201                 free(pgty);
12202                 return (-1);
12203         }
12204 
12205         free(pgty);
12206 
12207         /* map delete_dependency_pg onto the properties. */
12208         if ((prop = scf_property_create(g_hndl)) == NULL ||
12209             (val = scf_value_create(g_hndl)) == NULL ||
12210             (iter = scf_iter_create(g_hndl)) == NULL)
12211                 scfdie();
12212 
12213         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12214                 scfdie();
12215 
12216         name = safe_malloc(max_scf_name_len + 1);
12217         fmri = safe_malloc(max_scf_fmri_len + 2);
12218 
12219         while ((r = scf_iter_next_property(iter, prop)) == 1) {
12220                 scf_type_t ty;
12221 
12222                 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12223                         scfdie();
12224 
12225                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12226                         scfdie();
12227 
12228                 if ((ty != SCF_TYPE_ASTRING &&
12229                     prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12230                     prop_get_val(prop, val) != 0)
12231                         continue;
12232 
12233                 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12234                         scfdie();
12235 
12236                 err = delete_dependency_pg(fmri, name);
12237                 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12238                         if (scf_property_to_fmri(prop, fmri,
12239                             max_scf_fmri_len + 2) < 0)
12240                                 scfdie();
12241 
12242                         warn(gettext("Value of %s is not a valid FMRI.\n"),
12243                             fmri);
12244                 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12245                         warn(gettext("Property group \"%s\" of entity \"%s\" "
12246                             "does not have dependency type.\n"), name, fmri);
12247                 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12248                         warn(gettext("Could not delete property group \"%s\" "
12249                             "of entity \"%s\" (permission denied).\n"), name,
12250                             fmri);
12251                 }
12252         }
12253         if (r == -1)
12254                 scfdie();
12255 
12256         scf_value_destroy(val);
12257         scf_property_destroy(prop);
12258 
12259         return (0);
12260 }
12261 
12262 /*
12263  * Returns 1 if the instance may be running, and 0 otherwise.
12264  */
12265 static int
12266 inst_is_running(scf_instance_t *inst)
12267 {
12268         scf_propertygroup_t *pg;
12269         scf_property_t *prop;
12270         scf_value_t *val;
12271         char buf[MAX_SCF_STATE_STRING_SZ];
12272         int ret = 0;
12273         ssize_t szret;
12274 
12275         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12276             (prop = scf_property_create(g_hndl)) == NULL ||
12277             (val = scf_value_create(g_hndl)) == NULL)
12278                 scfdie();
12279 
12280         if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12281                 if (scf_error() != SCF_ERROR_NOT_FOUND)
12282                         scfdie();
12283                 goto out;
12284         }
12285 
12286         if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12287             prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12288             prop_get_val(prop, val) != 0)
12289                 goto out;
12290 
12291         szret = scf_value_get_astring(val, buf, sizeof (buf));
12292         assert(szret >= 0);
12293 
12294         ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12295             strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12296 
12297 out:
12298         scf_value_destroy(val);
12299         scf_property_destroy(prop);
12300         scf_pg_destroy(pg);
12301         return (ret);
12302 }
12303 
12304 static uint8_t
12305 pg_is_external_dependency(scf_propertygroup_t *pg)
12306 {
12307         char *type;
12308         scf_value_t *val;
12309         scf_property_t *prop;
12310         uint8_t b = B_FALSE;
12311 
12312         type = safe_malloc(max_scf_pg_type_len + 1);
12313 
12314         if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12315                 scfdie();
12316 
12317         if ((prop = scf_property_create(g_hndl)) == NULL ||
12318             (val = scf_value_create(g_hndl)) == NULL)
12319                 scfdie();
12320 
12321         if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12322                 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12323                         if (scf_property_get_value(prop, val) != 0)
12324                                 scfdie();
12325                         if (scf_value_get_boolean(val, &b) != 0)
12326                                 scfdie();
12327                 }
12328         }
12329 
12330         free(type);
12331         (void) scf_value_destroy(val);
12332         (void) scf_property_destroy(prop);
12333 
12334         return (b);
12335 }
12336 
12337 #define DELETE_FAILURE                  -1
12338 #define DELETE_SUCCESS_NOEXTDEPS        0
12339 #define DELETE_SUCCESS_EXTDEPS          1
12340 
12341 /*
12342  * lscf_instance_delete() deletes an instance.  Before calling
12343  * scf_instance_delete(), though, we make sure the instance isn't
12344  * running and delete dependencies in other entities which the instance
12345  * declared as "dependents".  If there are dependencies which were
12346  * created for other entities, then instead of deleting the instance we
12347  * make it "empty" by deleting all other property groups and all
12348  * snapshots.
12349  *
12350  * lscf_instance_delete() verifies that there is no external dependency pgs
12351  * before suppressing the instance. If there is, then we must not remove them
12352  * now in case the instance is re-created otherwise the dependencies would be
12353  * lost. The external dependency pgs will be removed if the dependencies are
12354  * removed.
12355  *
12356  * Returns:
12357  *  DELETE_FAILURE              on failure
12358  *  DELETE_SUCCESS_NOEXTDEPS    on success - no external dependencies
12359  *  DELETE_SUCCESS_EXTDEPS      on success - external dependencies
12360  */
12361 static int
12362 lscf_instance_delete(scf_instance_t *inst, int force)
12363 {
12364         scf_propertygroup_t *pg;
12365         scf_snapshot_t *snap;
12366         scf_iter_t *iter;
12367         int err;
12368         int external = 0;
12369 
12370         /* If we're not forcing and the instance is running, refuse. */
12371         if (!force && inst_is_running(inst)) {
12372                 char *fmri;
12373 
12374                 fmri = safe_malloc(max_scf_fmri_len + 1);
12375 
12376                 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12377                         scfdie();
12378 
12379                 semerr(gettext("Instance %s may be running.  "
12380                     "Use delete -f if it is not.\n"), fmri);
12381 
12382                 free(fmri);
12383                 return (DELETE_FAILURE);
12384         }
12385 
12386         pg = scf_pg_create(g_hndl);
12387         if (pg == NULL)
12388                 scfdie();
12389 
12390         if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12391                 (void) delete_dependents(pg);
12392         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12393                 scfdie();
12394 
12395         scf_pg_destroy(pg);
12396 
12397         /*
12398          * If the instance has some external dependencies then we must
12399          * keep them in case the instance is reimported otherwise the
12400          * dependencies would be lost on reimport.
12401          */
12402         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12403             (pg = scf_pg_create(g_hndl)) == NULL)
12404                 scfdie();
12405 
12406         if (scf_iter_instance_pgs(iter, inst) < 0)
12407                 scfdie();
12408 
12409         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12410                 if (pg_is_external_dependency(pg)) {
12411                         external = 1;
12412                         continue;
12413                 }
12414 
12415                 if (scf_pg_delete(pg) != 0) {
12416                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12417                                 scfdie();
12418                         else {
12419                                 semerr(emsg_permission_denied);
12420 
12421                                 (void) scf_iter_destroy(iter);
12422                                 (void) scf_pg_destroy(pg);
12423                                 return (DELETE_FAILURE);
12424                         }
12425                 }
12426         }
12427 
12428         if (err == -1)
12429                 scfdie();
12430 
12431         (void) scf_iter_destroy(iter);
12432         (void) scf_pg_destroy(pg);
12433 
12434         if (external) {
12435                 /*
12436                  * All the pgs have been deleted for the instance except
12437                  * the ones holding the external dependencies.
12438                  * For the job to be complete, we must also delete the
12439                  * snapshots associated with the instance.
12440                  */
12441                 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12442                     NULL)
12443                         scfdie();
12444                 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12445                         scfdie();
12446 
12447                 if (scf_iter_instance_snapshots(iter, inst) == -1)
12448                         scfdie();
12449 
12450                 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12451                         if (_scf_snapshot_delete(snap) != 0) {
12452                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12453                                         scfdie();
12454 
12455                                 semerr(emsg_permission_denied);
12456 
12457                                 (void) scf_iter_destroy(iter);
12458                                 (void) scf_snapshot_destroy(snap);
12459                                 return (DELETE_FAILURE);
12460                         }
12461                 }
12462 
12463                 if (err == -1)
12464                         scfdie();
12465 
12466                 (void) scf_iter_destroy(iter);
12467                 (void) scf_snapshot_destroy(snap);
12468                 return (DELETE_SUCCESS_EXTDEPS);
12469         }
12470 
12471         if (scf_instance_delete(inst) != 0) {
12472                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12473                         scfdie();
12474 
12475                 semerr(emsg_permission_denied);
12476 
12477                 return (DELETE_FAILURE);
12478         }
12479 
12480         return (DELETE_SUCCESS_NOEXTDEPS);
12481 }
12482 
12483 /*
12484  * lscf_service_delete() deletes a service.  Before calling
12485  * scf_service_delete(), though, we call lscf_instance_delete() for
12486  * each of the instances and delete dependencies in other entities
12487  * which were created as "dependents" of this service.  If there are
12488  * dependencies which were created for other entities, then we delete
12489  * all other property groups in the service and leave it as "empty".
12490  *
12491  * lscf_service_delete() verifies that there is no external dependency
12492  * pgs at the instance & service level before suppressing the service.
12493  * If there is, then we must not remove them now in case the service
12494  * is re-imported otherwise the dependencies would be lost. The external
12495  * dependency pgs will be removed if the dependencies are removed.
12496  *
12497  * Returns:
12498  *   DELETE_FAILURE             on failure
12499  *   DELETE_SUCCESS_NOEXTDEPS   on success - no external dependencies
12500  *   DELETE_SUCCESS_EXTDEPS     on success - external dependencies
12501  */
12502 static int
12503 lscf_service_delete(scf_service_t *svc, int force)
12504 {
12505         int r;
12506         scf_instance_t *inst;
12507         scf_propertygroup_t *pg;
12508         scf_iter_t *iter;
12509         int ret;
12510         int external = 0;
12511 
12512         if ((inst = scf_instance_create(g_hndl)) == NULL ||
12513             (pg = scf_pg_create(g_hndl)) == NULL ||
12514             (iter = scf_iter_create(g_hndl)) == NULL)
12515                 scfdie();
12516 
12517         if (scf_iter_service_instances(iter, svc) != 0)
12518                 scfdie();
12519 
12520         for (r = scf_iter_next_instance(iter, inst);
12521             r == 1;
12522             r = scf_iter_next_instance(iter, inst)) {
12523 
12524                 ret = lscf_instance_delete(inst, force);
12525                 if (ret == DELETE_FAILURE) {
12526                         scf_iter_destroy(iter);
12527                         scf_pg_destroy(pg);
12528                         scf_instance_destroy(inst);
12529                         return (DELETE_FAILURE);
12530                 }
12531 
12532                 /*
12533                  * Record the fact that there is some external dependencies
12534                  * at the instance level.
12535                  */
12536                 if (ret == DELETE_SUCCESS_EXTDEPS)
12537                         external |= 1;
12538         }
12539 
12540         if (r != 0)
12541                 scfdie();
12542 
12543         /* Delete dependency property groups in dependent services. */
12544         if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12545                 (void) delete_dependents(pg);
12546         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12547                 scfdie();
12548 
12549         scf_iter_destroy(iter);
12550         scf_pg_destroy(pg);
12551         scf_instance_destroy(inst);
12552 
12553         /*
12554          * If the service has some external dependencies then we don't
12555          * want to remove them in case the service is re-imported.
12556          */
12557         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12558             (iter = scf_iter_create(g_hndl)) == NULL)
12559                 scfdie();
12560 
12561         if (scf_iter_service_pgs(iter, svc) < 0)
12562                 scfdie();
12563 
12564         while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12565                 if (pg_is_external_dependency(pg)) {
12566                         external |= 2;
12567                         continue;
12568                 }
12569 
12570                 if (scf_pg_delete(pg) != 0) {
12571                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12572                                 scfdie();
12573                         else {
12574                                 semerr(emsg_permission_denied);
12575 
12576                                 (void) scf_iter_destroy(iter);
12577                                 (void) scf_pg_destroy(pg);
12578                                 return (DELETE_FAILURE);
12579                         }
12580                 }
12581         }
12582 
12583         if (r == -1)
12584                 scfdie();
12585 
12586         (void) scf_iter_destroy(iter);
12587         (void) scf_pg_destroy(pg);
12588 
12589         if (external != 0)
12590                 return (DELETE_SUCCESS_EXTDEPS);
12591 
12592         if (scf_service_delete(svc) == 0)
12593                 return (DELETE_SUCCESS_NOEXTDEPS);
12594 
12595         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12596                 scfdie();
12597 
12598         semerr(emsg_permission_denied);
12599         return (DELETE_FAILURE);
12600 }
12601 
12602 static int
12603 delete_callback(void *data, scf_walkinfo_t *wip)
12604 {
12605         int force = (int)data;
12606 
12607         if (wip->inst != NULL)
12608                 (void) lscf_instance_delete(wip->inst, force);
12609         else
12610                 (void) lscf_service_delete(wip->svc, force);
12611 
12612         return (0);
12613 }
12614 
12615 void
12616 lscf_delete(const char *fmri, int force)
12617 {
12618         scf_service_t *svc;
12619         scf_instance_t *inst;
12620         int ret;
12621 
12622         lscf_prep_hndl();
12623 
12624         if (cur_snap != NULL) {
12625                 if (!snaplevel_is_instance(cur_level)) {
12626                         char *buf;
12627 
12628                         buf = safe_malloc(max_scf_name_len + 1);
12629                         if (scf_instance_get_name(cur_inst, buf,
12630                             max_scf_name_len + 1) >= 0) {
12631                                 if (strcmp(buf, fmri) == 0) {
12632                                         semerr(emsg_cant_modify_snapshots);
12633                                         free(buf);
12634                                         return;
12635                                 }
12636                         } else if (scf_error() != SCF_ERROR_DELETED) {
12637                                 scfdie();
12638                         }
12639                         free(buf);
12640                 }
12641         } else if (cur_inst != NULL) {
12642                 /* EMPTY */;
12643         } else if (cur_svc != NULL) {
12644                 inst = scf_instance_create(g_hndl);
12645                 if (inst == NULL)
12646                         scfdie();
12647 
12648                 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12649                     SCF_SUCCESS) {
12650                         (void) lscf_instance_delete(inst, force);
12651                         scf_instance_destroy(inst);
12652                         return;
12653                 }
12654 
12655                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12656                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12657                         scfdie();
12658 
12659                 scf_instance_destroy(inst);
12660         } else {
12661                 assert(cur_scope != NULL);
12662 
12663                 svc = scf_service_create(g_hndl);
12664                 if (svc == NULL)
12665                         scfdie();
12666 
12667                 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12668                     SCF_SUCCESS) {
12669                         (void) lscf_service_delete(svc, force);
12670                         scf_service_destroy(svc);
12671                         return;
12672                 }
12673 
12674                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12675                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12676                         scfdie();
12677 
12678                 scf_service_destroy(svc);
12679         }
12680 
12681         /*
12682          * Match FMRI to entity.
12683          */
12684         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12685             delete_callback, (void *)force, NULL, semerr)) != 0) {
12686                 semerr(gettext("Failed to walk instances: %s\n"),
12687                     scf_strerror(ret));
12688         }
12689 }
12690 
12691 
12692 
12693 /*
12694  * :properties commands.  These all end with "pg" or "prop" and generally
12695  * operate on the currently selected entity.
12696  */
12697 
12698 /*
12699  * Property listing.  List the property groups, properties, their types and
12700  * their values for the currently selected entity.
12701  */
12702 static void
12703 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12704 {
12705         char *buf;
12706         uint32_t flags;
12707 
12708         buf = safe_malloc(max_scf_pg_type_len + 1);
12709 
12710         if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12711                 scfdie();
12712 
12713         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12714                 scfdie();
12715 
12716         safe_printf("%-*s  %s", namewidth, name, buf);
12717 
12718         if (flags & SCF_PG_FLAG_NONPERSISTENT)
12719                 safe_printf("\tNONPERSISTENT");
12720 
12721         safe_printf("\n");
12722 
12723         free(buf);
12724 }
12725 
12726 static boolean_t
12727 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12728 {
12729         if (scf_property_get_value(prop, val) == 0) {
12730                 return (B_FALSE);
12731         } else {
12732                 switch (scf_error()) {
12733                 case SCF_ERROR_NOT_FOUND:
12734                         return (B_FALSE);
12735                 case SCF_ERROR_PERMISSION_DENIED:
12736                 case SCF_ERROR_CONSTRAINT_VIOLATED:
12737                         return (B_TRUE);
12738                 default:
12739                         scfdie();
12740                         /*NOTREACHED*/
12741                 }
12742         }
12743 }
12744 
12745 static void
12746 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12747 {
12748         scf_iter_t *iter;
12749         scf_value_t *val;
12750         const char *type;
12751         int multiple_strings = 0;
12752         int ret;
12753 
12754         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12755             (val = scf_value_create(g_hndl)) == NULL)
12756                 scfdie();
12757 
12758         type = prop_to_typestr(prop);
12759         assert(type != NULL);
12760 
12761         safe_printf("%-*s  %-7s ", len, name, type);
12762 
12763         if (prop_has_multiple_values(prop, val) &&
12764             (scf_value_type(val) == SCF_TYPE_ASTRING ||
12765             scf_value_type(val) == SCF_TYPE_USTRING))
12766                 multiple_strings = 1;
12767 
12768         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12769                 scfdie();
12770 
12771         while ((ret = scf_iter_next_value(iter, val)) == 1) {
12772                 char *buf;
12773                 ssize_t vlen, szret;
12774 
12775                 vlen = scf_value_get_as_string(val, NULL, 0);
12776                 if (vlen < 0)
12777                         scfdie();
12778 
12779                 buf = safe_malloc(vlen + 1);
12780 
12781                 szret = scf_value_get_as_string(val, buf, vlen + 1);
12782                 if (szret < 0)
12783                         scfdie();
12784                 assert(szret <= vlen);
12785 
12786                 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12787                 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12788                         safe_printf(" \"");
12789                         (void) quote_and_print(buf, stdout, 0);
12790                         (void) putchar('"');
12791                         if (ferror(stdout)) {
12792                                 (void) putchar('\n');
12793                                 uu_die(gettext("Error writing to stdout.\n"));
12794                         }
12795                 } else {
12796                         safe_printf(" %s", buf);
12797                 }
12798 
12799                 free(buf);
12800         }
12801         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12802                 scfdie();
12803 
12804         if (putchar('\n') != '\n')
12805                 uu_die(gettext("Could not output newline"));
12806 }
12807 
12808 /*
12809  * Outputs template property group info for the describe subcommand.
12810  * If 'templates' == 2, verbose output is printed in the format expected
12811  * for describe -v, which includes all templates fields.  If pg is
12812  * not NULL, we're describing the template data, not an existing property
12813  * group, and formatting should be appropriate for describe -t.
12814  */
12815 static void
12816 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12817 {
12818         char *buf;
12819         uint8_t required;
12820         scf_property_t *stability_prop;
12821         scf_value_t *stability_val;
12822 
12823         if (templates == 0)
12824                 return;
12825 
12826         if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12827             (stability_val = scf_value_create(g_hndl)) == NULL)
12828                 scfdie();
12829 
12830         if (templates == 2 && pg != NULL) {
12831                 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12832                     stability_prop) == 0) {
12833                         if (prop_check_type(stability_prop,
12834                             SCF_TYPE_ASTRING) == 0 &&
12835                             prop_get_val(stability_prop, stability_val) == 0) {
12836                                 char *stability;
12837 
12838                                 stability = safe_malloc(max_scf_value_len + 1);
12839 
12840                                 if (scf_value_get_astring(stability_val,
12841                                     stability, max_scf_value_len + 1) == -1 &&
12842                                     scf_error() != SCF_ERROR_NOT_FOUND)
12843                                         scfdie();
12844 
12845                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
12846                                     gettext("stability"), stability);
12847 
12848                                 free(stability);
12849                         }
12850                 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12851                         scfdie();
12852         }
12853 
12854         scf_property_destroy(stability_prop);
12855         scf_value_destroy(stability_val);
12856 
12857         if (pgt == NULL)
12858                 return;
12859 
12860         if (pg == NULL || templates == 2) {
12861                 /* print type info only if scf_tmpl_pg_name succeeds */
12862                 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12863                         if (pg != NULL)
12864                                 safe_printf("%s", TMPL_INDENT);
12865                         safe_printf("%s: ", gettext("name"));
12866                         safe_printf("%s\n", buf);
12867                         free(buf);
12868                 }
12869 
12870                 /* print type info only if scf_tmpl_pg_type succeeds */
12871                 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12872                         if (pg != NULL)
12873                                 safe_printf("%s", TMPL_INDENT);
12874                         safe_printf("%s: ", gettext("type"));
12875                         safe_printf("%s\n", buf);
12876                         free(buf);
12877                 }
12878         }
12879 
12880         if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12881                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12882                     required ? "true" : "false");
12883 
12884         if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12885                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12886                     buf);
12887                 free(buf);
12888         }
12889 
12890         if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12891                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12892                     buf);
12893                 free(buf);
12894         }
12895 
12896         if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12897                 if (templates == 2)
12898                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12899                             gettext("description"), buf);
12900                 else
12901                         safe_printf("%s%s\n", TMPL_INDENT, buf);
12902                 free(buf);
12903         }
12904 
12905 }
12906 
12907 /*
12908  * With as_value set to true, indent as appropriate for the value level.
12909  * If false, indent to appropriate level for inclusion in constraint
12910  * or choice printout.
12911  */
12912 static void
12913 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12914     int as_value)
12915 {
12916         char *buf;
12917 
12918         if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12919                 if (as_value == 0)
12920                         safe_printf("%s", TMPL_CHOICE_INDENT);
12921                 else
12922                         safe_printf("%s", TMPL_INDENT);
12923                 safe_printf("%s: %s\n", gettext("value common name"), buf);
12924                 free(buf);
12925         }
12926 
12927         if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12928                 if (as_value == 0)
12929                         safe_printf("%s", TMPL_CHOICE_INDENT);
12930                 else
12931                         safe_printf("%s", TMPL_INDENT);
12932                 safe_printf("%s: %s\n", gettext("value description"), buf);
12933                 free(buf);
12934         }
12935 }
12936 
12937 static void
12938 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12939 {
12940         safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12941         /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12942         safe_printf("%s\n", val_buf);
12943 
12944         print_template_value_details(prt, val_buf, 1);
12945 }
12946 
12947 static void
12948 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12949 {
12950         int i, printed = 0;
12951         scf_values_t values;
12952         scf_count_ranges_t c_ranges;
12953         scf_int_ranges_t i_ranges;
12954 
12955         printed = 0;
12956         i = 0;
12957         if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12958                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12959                     gettext("value constraints"));
12960                 printed++;
12961                 for (i = 0; i < values.value_count; ++i) {
12962                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12963                             gettext("value name"), values.values_as_strings[i]);
12964                         if (verbose == 1)
12965                                 print_template_value_details(prt,
12966                                     values.values_as_strings[i], 0);
12967                 }
12968 
12969                 scf_values_destroy(&values);
12970         }
12971 
12972         if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12973                 if (printed++ == 0)
12974                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12975                             gettext("value constraints"));
12976                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12977                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12978                             gettext("range"), c_ranges.scr_min[i],
12979                             c_ranges.scr_max[i]);
12980                 }
12981                 scf_count_ranges_destroy(&c_ranges);
12982         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12983             scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12984                 if (printed++ == 0)
12985                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12986                             gettext("value constraints"));
12987                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12988                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12989                             gettext("range"), i_ranges.sir_min[i],
12990                             i_ranges.sir_max[i]);
12991                 }
12992                 scf_int_ranges_destroy(&i_ranges);
12993         }
12994 }
12995 
12996 static void
12997 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12998 {
12999         int i = 0, printed = 0;
13000         scf_values_t values;
13001         scf_count_ranges_t c_ranges;
13002         scf_int_ranges_t i_ranges;
13003 
13004         printed = 0;
13005         if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13006                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13007                     gettext("value constraints"));
13008                 printed++;
13009                 for (i = 0; i < values.value_count; i++) {
13010                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13011                             gettext("value name"), values.values_as_strings[i]);
13012                         if (verbose == 1)
13013                                 print_template_value_details(prt,
13014                                     values.values_as_strings[i], 0);
13015                 }
13016 
13017                 scf_values_destroy(&values);
13018         }
13019 
13020         if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13021                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13022                         if (printed++ == 0)
13023                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13024                                     gettext("value choices"));
13025                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13026                             gettext("range"), c_ranges.scr_min[i],
13027                             c_ranges.scr_max[i]);
13028                 }
13029                 scf_count_ranges_destroy(&c_ranges);
13030         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13031             scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13032                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13033                         if (printed++ == 0)
13034                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13035                                     gettext("value choices"));
13036                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13037                             gettext("range"), i_ranges.sir_min[i],
13038                             i_ranges.sir_max[i]);
13039                 }
13040                 scf_int_ranges_destroy(&i_ranges);
13041         }
13042 }
13043 
13044 static void
13045 list_values_by_template(scf_prop_tmpl_t *prt)
13046 {
13047         print_template_constraints(prt, 1);
13048         print_template_choices(prt, 1);
13049 }
13050 
13051 static void
13052 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13053 {
13054         char *val_buf;
13055         scf_iter_t *iter;
13056         scf_value_t *val;
13057         int ret;
13058 
13059         if ((iter = scf_iter_create(g_hndl)) == NULL ||
13060             (val = scf_value_create(g_hndl)) == NULL)
13061                 scfdie();
13062 
13063         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13064                 scfdie();
13065 
13066         val_buf = safe_malloc(max_scf_value_len + 1);
13067 
13068         while ((ret = scf_iter_next_value(iter, val)) == 1) {
13069                 if (scf_value_get_as_string(val, val_buf,
13070                     max_scf_value_len + 1) < 0)
13071                         scfdie();
13072 
13073                 print_template_value(prt, val_buf);
13074         }
13075         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13076                 scfdie();
13077         free(val_buf);
13078 
13079         print_template_constraints(prt, 0);
13080         print_template_choices(prt, 0);
13081 
13082 }
13083 
13084 /*
13085  * Outputs property info for the describe subcommand
13086  * Verbose output if templates == 2, -v option of svccfg describe
13087  * Displays template data if prop is not NULL, -t option of svccfg describe
13088  */
13089 static void
13090 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13091 {
13092         char *buf;
13093         uint8_t u_buf;
13094         int i;
13095         uint64_t min, max;
13096         scf_values_t values;
13097 
13098         if (prt == NULL || templates == 0)
13099                 return;
13100 
13101         if (prop == NULL) {
13102                 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13103                 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13104                         safe_printf("%s\n", buf);
13105                         free(buf);
13106                 } else
13107                         safe_printf("(%s)\n", gettext("any"));
13108         }
13109 
13110         if (prop == NULL || templates == 2) {
13111                 if (prop != NULL)
13112                         safe_printf("%s", TMPL_INDENT);
13113                 else
13114                         safe_printf("%s", TMPL_VALUE_INDENT);
13115                 safe_printf("%s: ", gettext("type"));
13116                 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13117                         safe_printf("%s\n", buf);
13118                         free(buf);
13119                 } else
13120                         safe_printf("(%s)\n", gettext("any"));
13121         }
13122 
13123         if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13124                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13125                     u_buf ? "true" : "false");
13126 
13127         if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13128                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13129                     buf);
13130                 free(buf);
13131         }
13132 
13133         if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13134                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13135                     buf);
13136                 free(buf);
13137         }
13138 
13139         if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13140                 safe_printf("%s%s\n", TMPL_INDENT, buf);
13141                 free(buf);
13142         }
13143 
13144         if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13145                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13146                     scf_tmpl_visibility_to_string(u_buf));
13147 
13148         if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13149                 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13150                     gettext("minimum number of values"), min);
13151                 if (max == ULLONG_MAX) {
13152                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13153                             gettext("maximum number of values"),
13154                             gettext("unlimited"));
13155                 } else {
13156                         safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13157                             gettext("maximum number of values"), max);
13158                 }
13159         }
13160 
13161         if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13162                 for (i = 0; i < values.value_count; i++) {
13163                         if (i == 0) {
13164                                 safe_printf("%s%s:", TMPL_INDENT,
13165                                     gettext("internal separators"));
13166                         }
13167                         safe_printf(" \"%s\"", values.values_as_strings[i]);
13168                 }
13169                 safe_printf("\n");
13170         }
13171 
13172         if (templates != 2)
13173                 return;
13174 
13175         if (prop != NULL)
13176                 list_values_tmpl(prt, prop);
13177         else
13178                 list_values_by_template(prt);
13179 }
13180 
13181 static char *
13182 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13183 {
13184         char *rv;
13185 
13186         rv = _scf_read_single_astring_from_pg(pg, prop_name);
13187         if (rv == NULL) {
13188                 switch (scf_error()) {
13189                 case SCF_ERROR_NOT_FOUND:
13190                         break;
13191                 default:
13192                         scfdie();
13193                 }
13194         }
13195         return (rv);
13196 }
13197 
13198 static void
13199 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13200 {
13201         size_t doc_len;
13202         size_t man_len;
13203         char *pg_name;
13204         char *text = NULL;
13205         int rv;
13206 
13207         doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13208         man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13209         pg_name = safe_malloc(max_scf_name_len + 1);
13210         while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13211                 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13212                         scfdie();
13213                 }
13214                 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13215                         /* Display doc_link and and uri */
13216                         safe_printf("%s%s:\n", TMPL_INDENT,
13217                             gettext("doc_link"));
13218                         text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13219                         if (text != NULL) {
13220                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13221                                     TMPL_INDENT, gettext("name"), text);
13222                                 uu_free(text);
13223                         }
13224                         text = read_astring(pg, SCF_PROPERTY_TM_URI);
13225                         if (text != NULL) {
13226                                 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13227                                     gettext("uri"), text);
13228                                 uu_free(text);
13229                         }
13230                 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13231                     man_len) == 0) {
13232                         /* Display manpage title, section and path */
13233                         safe_printf("%s%s:\n", TMPL_INDENT,
13234                             gettext("manpage"));
13235                         text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13236                         if (text != NULL) {
13237                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13238                                     TMPL_INDENT, gettext("title"), text);
13239                                 uu_free(text);
13240                         }
13241                         text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13242                         if (text != NULL) {
13243                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13244                                     TMPL_INDENT, gettext("section"), text);
13245                                 uu_free(text);
13246                         }
13247                         text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13248                         if (text != NULL) {
13249                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13250                                     TMPL_INDENT, gettext("manpath"), text);
13251                                 uu_free(text);
13252                         }
13253                 }
13254         }
13255         if (rv == -1)
13256                 scfdie();
13257 
13258 done:
13259         free(pg_name);
13260 }
13261 
13262 static void
13263 list_entity_tmpl(int templates)
13264 {
13265         char *common_name = NULL;
13266         char *description = NULL;
13267         char *locale = NULL;
13268         scf_iter_t *iter;
13269         scf_propertygroup_t *pg;
13270         scf_property_t *prop;
13271         int r;
13272         scf_value_t *val;
13273 
13274         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13275             (prop = scf_property_create(g_hndl)) == NULL ||
13276             (val = scf_value_create(g_hndl)) == NULL ||
13277             (iter = scf_iter_create(g_hndl)) == NULL)
13278                 scfdie();
13279 
13280         locale = setlocale(LC_MESSAGES, NULL);
13281 
13282         if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13283                 common_name = safe_malloc(max_scf_value_len + 1);
13284 
13285                 /* Try both the current locale and the "C" locale. */
13286                 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13287                     (scf_error() == SCF_ERROR_NOT_FOUND &&
13288                     scf_pg_get_property(pg, "C", prop) == 0)) {
13289                         if (prop_get_val(prop, val) == 0 &&
13290                             scf_value_get_ustring(val, common_name,
13291                             max_scf_value_len + 1) != -1) {
13292                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
13293                                     gettext("common name"), common_name);
13294                         }
13295                 }
13296         }
13297 
13298         /*
13299          * Do description, manpages, and doc links if templates == 2.
13300          */
13301         if (templates == 2) {
13302                 /* Get the description. */
13303                 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13304                         description = safe_malloc(max_scf_value_len + 1);
13305 
13306                         /* Try both the current locale and the "C" locale. */
13307                         if (scf_pg_get_property(pg, locale, prop) == 0 ||
13308                             (scf_error() == SCF_ERROR_NOT_FOUND &&
13309                             scf_pg_get_property(pg, "C", prop) == 0)) {
13310                                 if (prop_get_val(prop, val) == 0 &&
13311                                     scf_value_get_ustring(val, description,
13312                                     max_scf_value_len + 1) != -1) {
13313                                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13314                                             gettext("description"),
13315                                             description);
13316                                 }
13317                         }
13318                 }
13319 
13320                 /* Process doc_link & manpage elements. */
13321                 if (cur_level != NULL) {
13322                         r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13323                             SCF_GROUP_TEMPLATE);
13324                 } else if (cur_inst != NULL) {
13325                         r = scf_iter_instance_pgs_typed(iter, cur_inst,
13326                             SCF_GROUP_TEMPLATE);
13327                 } else {
13328                         r = scf_iter_service_pgs_typed(iter, cur_svc,
13329                             SCF_GROUP_TEMPLATE);
13330                 }
13331                 if (r == 0) {
13332                         display_documentation(iter, pg);
13333                 }
13334         }
13335 
13336         free(common_name);
13337         free(description);
13338         scf_pg_destroy(pg);
13339         scf_property_destroy(prop);
13340         scf_value_destroy(val);
13341         scf_iter_destroy(iter);
13342 }
13343 
13344 static void
13345 listtmpl(const char *pattern, int templates)
13346 {
13347         scf_pg_tmpl_t *pgt;
13348         scf_prop_tmpl_t *prt;
13349         char *snapbuf = NULL;
13350         char *fmribuf;
13351         char *pg_name = NULL, *prop_name = NULL;
13352         ssize_t prop_name_size;
13353         char *qual_prop_name;
13354         char *search_name;
13355         int listed = 0;
13356 
13357         if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13358             (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13359                 scfdie();
13360 
13361         fmribuf = safe_malloc(max_scf_name_len + 1);
13362         qual_prop_name = safe_malloc(max_scf_name_len + 1);
13363 
13364         if (cur_snap != NULL) {
13365                 snapbuf = safe_malloc(max_scf_name_len + 1);
13366                 if (scf_snapshot_get_name(cur_snap, snapbuf,
13367                     max_scf_name_len + 1) < 0)
13368                         scfdie();
13369         }
13370 
13371         if (cur_inst != NULL) {
13372                 if (scf_instance_to_fmri(cur_inst, fmribuf,
13373                     max_scf_name_len + 1) < 0)
13374                         scfdie();
13375         } else if (cur_svc != NULL) {
13376                 if (scf_service_to_fmri(cur_svc, fmribuf,
13377                     max_scf_name_len + 1) < 0)
13378                         scfdie();
13379         } else
13380                 abort();
13381 
13382         /* If pattern is specified, we want to list only those items. */
13383         while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13384                 listed = 0;
13385                 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13386                     fnmatch(pattern, pg_name, 0) == 0)) {
13387                         list_pg_tmpl(pgt, NULL, templates);
13388                         listed++;
13389                 }
13390 
13391                 scf_tmpl_prop_reset(prt);
13392 
13393                 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13394                         search_name = NULL;
13395                         prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13396                         if ((prop_name_size > 0) && (pg_name != NULL)) {
13397                                 if (snprintf(qual_prop_name,
13398                                     max_scf_name_len + 1, "%s/%s",
13399                                     pg_name, prop_name) >=
13400                                     max_scf_name_len + 1) {
13401                                         prop_name_size = -1;
13402                                 } else {
13403                                         search_name = qual_prop_name;
13404                                 }
13405                         }
13406                         if (listed > 0 || pattern == NULL ||
13407                             (prop_name_size > 0 &&
13408                             fnmatch(pattern, search_name,
13409                             FNM_PATHNAME) == 0))
13410                                 list_prop_tmpl(prt, NULL, templates);
13411                         if (prop_name != NULL) {
13412                                 free(prop_name);
13413                                 prop_name = NULL;
13414                         }
13415                 }
13416                 if (pg_name != NULL) {
13417                         free(pg_name);
13418                         pg_name = NULL;
13419                 }
13420         }
13421 
13422         scf_tmpl_prop_destroy(prt);
13423         scf_tmpl_pg_destroy(pgt);
13424         free(snapbuf);
13425         free(fmribuf);
13426         free(qual_prop_name);
13427 }
13428 
13429 static void
13430 listprop(const char *pattern, int only_pgs, int templates)
13431 {
13432         scf_propertygroup_t *pg;
13433         scf_property_t *prop;
13434         scf_iter_t *iter, *piter;
13435         char *pgnbuf, *prnbuf, *ppnbuf;
13436         scf_pg_tmpl_t *pgt, *pgtp;
13437         scf_prop_tmpl_t *prt;
13438 
13439         void **objects;
13440         char **names;
13441         void **tmpls;
13442         int allocd, i;
13443 
13444         int ret;
13445         ssize_t pgnlen, prnlen, szret;
13446         size_t max_len = 0;
13447 
13448         if (cur_svc == NULL && cur_inst == NULL) {
13449                 semerr(emsg_entity_not_selected);
13450                 return;
13451         }
13452 
13453         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13454             (prop = scf_property_create(g_hndl)) == NULL ||
13455             (iter = scf_iter_create(g_hndl)) == NULL ||
13456             (piter = scf_iter_create(g_hndl)) == NULL ||
13457             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13458             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13459                 scfdie();
13460 
13461         prnbuf = safe_malloc(max_scf_name_len + 1);
13462 
13463         if (cur_level != NULL)
13464                 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13465         else if (cur_inst != NULL)
13466                 ret = scf_iter_instance_pgs(iter, cur_inst);
13467         else
13468                 ret = scf_iter_service_pgs(iter, cur_svc);
13469         if (ret != 0) {
13470                 return;
13471         }
13472 
13473         /*
13474          * We want to only list items which match pattern, and we want the
13475          * second column to line up, so during the first pass we'll save
13476          * matching items, their names, and their templates in objects,
13477          * names, and tmpls, computing the maximum name length as we go,
13478          * and then we'll print them out.
13479          *
13480          * Note: We always keep an extra slot available so the array can be
13481          * NULL-terminated.
13482          */
13483         i = 0;
13484         allocd = 1;
13485         objects = safe_malloc(sizeof (*objects));
13486         names = safe_malloc(sizeof (*names));
13487         tmpls = safe_malloc(sizeof (*tmpls));
13488 
13489         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13490                 int new_pg = 0;
13491                 int print_props = 0;
13492                 pgtp = NULL;
13493 
13494                 pgnlen = scf_pg_get_name(pg, NULL, 0);
13495                 if (pgnlen < 0)
13496                         scfdie();
13497 
13498                 pgnbuf = safe_malloc(pgnlen + 1);
13499 
13500                 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13501                 if (szret < 0)
13502                         scfdie();
13503                 assert(szret <= pgnlen);
13504 
13505                 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13506                         if (scf_error() != SCF_ERROR_NOT_FOUND)
13507                                 scfdie();
13508                         pgtp = NULL;
13509                 } else {
13510                         pgtp = pgt;
13511                 }
13512 
13513                 if (pattern == NULL ||
13514                     fnmatch(pattern, pgnbuf, 0) == 0) {
13515                         if (i+1 >= allocd) {
13516                                 allocd *= 2;
13517                                 objects = realloc(objects,
13518                                     sizeof (*objects) * allocd);
13519                                 names =
13520                                     realloc(names, sizeof (*names) * allocd);
13521                                 tmpls = realloc(tmpls,
13522                                     sizeof (*tmpls) * allocd);
13523                                 if (objects == NULL || names == NULL ||
13524                                     tmpls == NULL)
13525                                         uu_die(gettext("Out of memory"));
13526                         }
13527                         objects[i] = pg;
13528                         names[i] = pgnbuf;
13529 
13530                         if (pgtp == NULL)
13531                                 tmpls[i] = NULL;
13532                         else
13533                                 tmpls[i] = pgt;
13534 
13535                         ++i;
13536 
13537                         if (pgnlen > max_len)
13538                                 max_len = pgnlen;
13539 
13540                         new_pg = 1;
13541                         print_props = 1;
13542                 }
13543 
13544                 if (only_pgs) {
13545                         if (new_pg) {
13546                                 pg = scf_pg_create(g_hndl);
13547                                 if (pg == NULL)
13548                                         scfdie();
13549                                 pgt = scf_tmpl_pg_create(g_hndl);
13550                                 if (pgt == NULL)
13551                                         scfdie();
13552                         } else
13553                                 free(pgnbuf);
13554 
13555                         continue;
13556                 }
13557 
13558                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13559                         scfdie();
13560 
13561                 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13562                         prnlen = scf_property_get_name(prop, prnbuf,
13563                             max_scf_name_len + 1);
13564                         if (prnlen < 0)
13565                                 scfdie();
13566 
13567                         /* Will prepend the property group name and a slash. */
13568                         prnlen += pgnlen + 1;
13569 
13570                         ppnbuf = safe_malloc(prnlen + 1);
13571 
13572                         if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13573                             prnbuf) < 0)
13574                                 uu_die("snprintf");
13575 
13576                         if (pattern == NULL || print_props == 1 ||
13577                             fnmatch(pattern, ppnbuf, 0) == 0) {
13578                                 if (i+1 >= allocd) {
13579                                         allocd *= 2;
13580                                         objects = realloc(objects,
13581                                             sizeof (*objects) * allocd);
13582                                         names = realloc(names,
13583                                             sizeof (*names) * allocd);
13584                                         tmpls = realloc(tmpls,
13585                                             sizeof (*tmpls) * allocd);
13586                                         if (objects == NULL || names == NULL ||
13587                                             tmpls == NULL)
13588                                                 uu_die(gettext(
13589                                                     "Out of memory"));
13590                                 }
13591 
13592                                 objects[i] = prop;
13593                                 names[i] = ppnbuf;
13594 
13595                                 if (pgtp != NULL) {
13596                                         if (scf_tmpl_get_by_prop(pgt, prnbuf,
13597                                             prt, 0) < 0) {
13598                                                 if (scf_error() !=
13599                                                     SCF_ERROR_NOT_FOUND)
13600                                                         scfdie();
13601                                                 tmpls[i] = NULL;
13602                                         } else {
13603                                                 tmpls[i] = prt;
13604                                         }
13605                                 } else {
13606                                         tmpls[i] = NULL;
13607                                 }
13608 
13609                                 ++i;
13610 
13611                                 if (prnlen > max_len)
13612                                         max_len = prnlen;
13613 
13614                                 prop = scf_property_create(g_hndl);
13615                                 prt = scf_tmpl_prop_create(g_hndl);
13616                         } else {
13617                                 free(ppnbuf);
13618                         }
13619                 }
13620 
13621                 if (new_pg) {
13622                         pg = scf_pg_create(g_hndl);
13623                         if (pg == NULL)
13624                                 scfdie();
13625                         pgt = scf_tmpl_pg_create(g_hndl);
13626                         if (pgt == NULL)
13627                                 scfdie();
13628                 } else
13629                         free(pgnbuf);
13630         }
13631         if (ret != 0)
13632                 scfdie();
13633 
13634         objects[i] = NULL;
13635 
13636         scf_pg_destroy(pg);
13637         scf_tmpl_pg_destroy(pgt);
13638         scf_property_destroy(prop);
13639         scf_tmpl_prop_destroy(prt);
13640 
13641         for (i = 0; objects[i] != NULL; ++i) {
13642                 if (strchr(names[i], '/') == NULL) {
13643                         /* property group */
13644                         pg = (scf_propertygroup_t *)objects[i];
13645                         pgt = (scf_pg_tmpl_t *)tmpls[i];
13646                         list_pg_info(pg, names[i], max_len);
13647                         list_pg_tmpl(pgt, pg, templates);
13648                         free(names[i]);
13649                         scf_pg_destroy(pg);
13650                         if (pgt != NULL)
13651                                 scf_tmpl_pg_destroy(pgt);
13652                 } else {
13653                         /* property */
13654                         prop = (scf_property_t *)objects[i];
13655                         prt = (scf_prop_tmpl_t *)tmpls[i];
13656                         list_prop_info(prop, names[i], max_len);
13657                         list_prop_tmpl(prt, prop, templates);
13658                         free(names[i]);
13659                         scf_property_destroy(prop);
13660                         if (prt != NULL)
13661                                 scf_tmpl_prop_destroy(prt);
13662                 }
13663         }
13664 
13665         free(names);
13666         free(objects);
13667         free(tmpls);
13668 }
13669 
13670 void
13671 lscf_listpg(const char *pattern)
13672 {
13673         lscf_prep_hndl();
13674 
13675         listprop(pattern, 1, 0);
13676 }
13677 
13678 /*
13679  * Property group and property creation, setting, and deletion.  setprop (and
13680  * its alias, addprop) can either create a property group of a given type, or
13681  * it can create or set a property to a given type and list of values.
13682  */
13683 void
13684 lscf_addpg(const char *name, const char *type, const char *flags)
13685 {
13686         scf_propertygroup_t *pg;
13687         int ret;
13688         uint32_t flgs = 0;
13689         const char *cp;
13690 
13691 
13692         lscf_prep_hndl();
13693 
13694         if (cur_snap != NULL) {
13695                 semerr(emsg_cant_modify_snapshots);
13696                 return;
13697         }
13698 
13699         if (cur_inst == NULL && cur_svc == NULL) {
13700                 semerr(emsg_entity_not_selected);
13701                 return;
13702         }
13703 
13704         if (flags != NULL) {
13705                 for (cp = flags; *cp != '\0'; ++cp) {
13706                         switch (*cp) {
13707                         case 'P':
13708                                 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13709                                 break;
13710 
13711                         case 'p':
13712                                 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13713                                 break;
13714 
13715                         default:
13716                                 semerr(gettext("Invalid property group flag "
13717                                     "%c."), *cp);
13718                                 return;
13719                         }
13720                 }
13721         }
13722 
13723         pg = scf_pg_create(g_hndl);
13724         if (pg == NULL)
13725                 scfdie();
13726 
13727         if (cur_inst != NULL)
13728                 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13729         else
13730                 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13731 
13732         if (ret != SCF_SUCCESS) {
13733                 switch (scf_error()) {
13734                 case SCF_ERROR_INVALID_ARGUMENT:
13735                         semerr(gettext("Name, type, or flags are invalid.\n"));
13736                         break;
13737 
13738                 case SCF_ERROR_EXISTS:
13739                         semerr(gettext("Property group already exists.\n"));
13740                         break;
13741 
13742                 case SCF_ERROR_PERMISSION_DENIED:
13743                         semerr(emsg_permission_denied);
13744                         break;
13745 
13746                 case SCF_ERROR_BACKEND_ACCESS:
13747                         semerr(gettext("Backend refused access.\n"));
13748                         break;
13749 
13750                 default:
13751                         scfdie();
13752                 }
13753         }
13754 
13755         scf_pg_destroy(pg);
13756 
13757         private_refresh();
13758 }
13759 
13760 void
13761 lscf_delpg(char *name)
13762 {
13763         lscf_prep_hndl();
13764 
13765         if (cur_snap != NULL) {
13766                 semerr(emsg_cant_modify_snapshots);
13767                 return;
13768         }
13769 
13770         if (cur_inst == NULL && cur_svc == NULL) {
13771                 semerr(emsg_entity_not_selected);
13772                 return;
13773         }
13774 
13775         if (strchr(name, '/') != NULL) {
13776                 semerr(emsg_invalid_pg_name, name);
13777                 return;
13778         }
13779 
13780         lscf_delprop(name);
13781 }
13782 
13783 /*
13784  * scf_delhash() is used to remove the property group related to the
13785  * hash entry for a specific manifest in the repository. pgname will be
13786  * constructed from the location of the manifest file. If deathrow isn't 0,
13787  * manifest file doesn't need to exist (manifest string will be used as
13788  * an absolute path).
13789  */
13790 void
13791 lscf_delhash(char *manifest, int deathrow)
13792 {
13793         char *pgname;
13794 
13795         if (cur_snap != NULL ||
13796             cur_inst != NULL || cur_svc != NULL) {
13797                 warn(gettext("error, an entity is selected\n"));
13798                 return;
13799         }
13800 
13801         /* select smf/manifest */
13802         lscf_select(HASH_SVC);
13803         /*
13804          * Translate the manifest file name to property name. In the deathrow
13805          * case, the manifest file does not need to exist.
13806          */
13807         pgname = mhash_filename_to_propname(manifest,
13808             deathrow ? B_TRUE : B_FALSE);
13809         if (pgname == NULL) {
13810                 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13811                 return;
13812         }
13813         /* delete the hash property name */
13814         lscf_delpg(pgname);
13815 }
13816 
13817 void
13818 lscf_listprop(const char *pattern)
13819 {
13820         lscf_prep_hndl();
13821 
13822         listprop(pattern, 0, 0);
13823 }
13824 
13825 int
13826 lscf_setprop(const char *pgname, const char *type, const char *value,
13827     const uu_list_t *values)
13828 {
13829         scf_type_t ty, current_ty;
13830         scf_service_t *svc;
13831         scf_propertygroup_t *pg, *parent_pg;
13832         scf_property_t *prop, *parent_prop;
13833         scf_pg_tmpl_t *pgt;
13834         scf_prop_tmpl_t *prt;
13835         int ret, result = 0;
13836         scf_transaction_t *tx;
13837         scf_transaction_entry_t *e;
13838         scf_value_t *v;
13839         uu_list_walk_t *walk;
13840         string_list_t *sp;
13841         char *propname;
13842         int req_quotes = 0;
13843 
13844         lscf_prep_hndl();
13845 
13846         if ((e = scf_entry_create(g_hndl)) == NULL ||
13847             (svc = scf_service_create(g_hndl)) == NULL ||
13848             (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13849             (pg = scf_pg_create(g_hndl)) == NULL ||
13850             (parent_prop = scf_property_create(g_hndl)) == NULL ||
13851             (prop = scf_property_create(g_hndl)) == NULL ||
13852             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13853             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13854             (tx = scf_transaction_create(g_hndl)) == NULL)
13855                 scfdie();
13856 
13857         if (cur_snap != NULL) {
13858                 semerr(emsg_cant_modify_snapshots);
13859                 goto fail;
13860         }
13861 
13862         if (cur_inst == NULL && cur_svc == NULL) {
13863                 semerr(emsg_entity_not_selected);
13864                 goto fail;
13865         }
13866 
13867         propname = strchr(pgname, '/');
13868         if (propname == NULL) {
13869                 semerr(gettext("Property names must contain a `/'.\n"));
13870                 goto fail;
13871         }
13872 
13873         *propname = '\0';
13874         ++propname;
13875 
13876         if (type != NULL) {
13877                 ty = string_to_type(type);
13878                 if (ty == SCF_TYPE_INVALID) {
13879                         semerr(gettext("Unknown type \"%s\".\n"), type);
13880                         goto fail;
13881                 }
13882         }
13883 
13884         if (cur_inst != NULL)
13885                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13886         else
13887                 ret = scf_service_get_pg(cur_svc, pgname, pg);
13888         if (ret != SCF_SUCCESS) {
13889                 switch (scf_error()) {
13890                 case SCF_ERROR_NOT_FOUND:
13891                         semerr(emsg_no_such_pg, pgname);
13892                         goto fail;
13893 
13894                 case SCF_ERROR_INVALID_ARGUMENT:
13895                         semerr(emsg_invalid_pg_name, pgname);
13896                         goto fail;
13897 
13898                 default:
13899                         scfdie();
13900                         break;
13901                 }
13902         }
13903 
13904         do {
13905                 if (scf_pg_update(pg) == -1)
13906                         scfdie();
13907                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13908                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13909                                 scfdie();
13910 
13911                         semerr(emsg_permission_denied);
13912                         goto fail;
13913                 }
13914 
13915                 ret = scf_pg_get_property(pg, propname, prop);
13916                 if (ret == SCF_SUCCESS) {
13917                         if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13918                                 scfdie();
13919 
13920                         if (type == NULL)
13921                                 ty = current_ty;
13922                         if (scf_transaction_property_change_type(tx, e,
13923                             propname, ty) == -1)
13924                                 scfdie();
13925 
13926                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13927                         /* Infer the type, if possible. */
13928                         if (type == NULL) {
13929                                 /*
13930                                  * First check if we're an instance and the
13931                                  * property is set on the service.
13932                                  */
13933                                 if (cur_inst != NULL &&
13934                                     scf_instance_get_parent(cur_inst,
13935                                     svc) == 0 &&
13936                                     scf_service_get_pg(cur_svc, pgname,
13937                                     parent_pg) == 0 &&
13938                                     scf_pg_get_property(parent_pg, propname,
13939                                     parent_prop) == 0 &&
13940                                     scf_property_type(parent_prop,
13941                                     &current_ty) == 0) {
13942                                         ty = current_ty;
13943 
13944                                 /* Then check for a type set in a template. */
13945                                 } else if (scf_tmpl_get_by_pg(pg, pgt,
13946                                     0) == 0 &&
13947                                     scf_tmpl_get_by_prop(pgt, propname, prt,
13948                                     0) == 0 &&
13949                                     scf_tmpl_prop_type(prt, &current_ty) == 0) {
13950                                         ty = current_ty;
13951 
13952                                 /* If type can't be inferred, fail. */
13953                                 } else {
13954                                         semerr(gettext("Type required for new "
13955                                             "properties.\n"));
13956                                         goto fail;
13957                                 }
13958                         }
13959                         if (scf_transaction_property_new(tx, e, propname,
13960                             ty) == -1)
13961                                 scfdie();
13962                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13963                         semerr(emsg_invalid_prop_name, propname);
13964                         goto fail;
13965                 } else {
13966                         scfdie();
13967                 }
13968 
13969                 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13970                         req_quotes = 1;
13971 
13972                 if (value != NULL) {
13973                         v = string_to_value(value, ty, 0);
13974 
13975                         if (v == NULL)
13976                                 goto fail;
13977 
13978                         ret = scf_entry_add_value(e, v);
13979                         assert(ret == SCF_SUCCESS);
13980                 } else {
13981                         assert(values != NULL);
13982 
13983                         walk = uu_list_walk_start((uu_list_t *)values,
13984                             UU_DEFAULT);
13985                         if (walk == NULL)
13986                                 uu_die(gettext("Could not walk list"));
13987 
13988                         for (sp = uu_list_walk_next(walk); sp != NULL;
13989                             sp = uu_list_walk_next(walk)) {
13990                                 v = string_to_value(sp->str, ty, req_quotes);
13991 
13992                                 if (v == NULL) {
13993                                         scf_entry_destroy_children(e);
13994                                         goto fail;
13995                                 }
13996 
13997                                 ret = scf_entry_add_value(e, v);
13998                                 assert(ret == SCF_SUCCESS);
13999                         }
14000                         uu_list_walk_end(walk);
14001                 }
14002                 result = scf_transaction_commit(tx);
14003 
14004                 scf_transaction_reset(tx);
14005                 scf_entry_destroy_children(e);
14006         } while (result == 0);
14007 
14008         if (result < 0) {
14009                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14010                         scfdie();
14011 
14012                 semerr(emsg_permission_denied);
14013                 goto fail;
14014         }
14015 
14016         ret = 0;
14017 
14018         private_refresh();
14019 
14020         goto cleanup;
14021 
14022 fail:
14023         ret = -1;
14024 
14025 cleanup:
14026         scf_transaction_destroy(tx);
14027         scf_entry_destroy(e);
14028         scf_service_destroy(svc);
14029         scf_pg_destroy(parent_pg);
14030         scf_pg_destroy(pg);
14031         scf_property_destroy(parent_prop);
14032         scf_property_destroy(prop);
14033         scf_tmpl_pg_destroy(pgt);
14034         scf_tmpl_prop_destroy(prt);
14035 
14036         return (ret);
14037 }
14038 
14039 void
14040 lscf_delprop(char *pgn)
14041 {
14042         char *slash, *pn;
14043         scf_propertygroup_t *pg;
14044         scf_transaction_t *tx;
14045         scf_transaction_entry_t *e;
14046         int ret;
14047 
14048 
14049         lscf_prep_hndl();
14050 
14051         if (cur_snap != NULL) {
14052                 semerr(emsg_cant_modify_snapshots);
14053                 return;
14054         }
14055 
14056         if (cur_inst == NULL && cur_svc == NULL) {
14057                 semerr(emsg_entity_not_selected);
14058                 return;
14059         }
14060 
14061         pg = scf_pg_create(g_hndl);
14062         if (pg == NULL)
14063                 scfdie();
14064 
14065         slash = strchr(pgn, '/');
14066         if (slash == NULL) {
14067                 pn = NULL;
14068         } else {
14069                 *slash = '\0';
14070                 pn = slash + 1;
14071         }
14072 
14073         if (cur_inst != NULL)
14074                 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14075         else
14076                 ret = scf_service_get_pg(cur_svc, pgn, pg);
14077         if (ret != SCF_SUCCESS) {
14078                 switch (scf_error()) {
14079                 case SCF_ERROR_NOT_FOUND:
14080                         semerr(emsg_no_such_pg, pgn);
14081                         break;
14082 
14083                 case SCF_ERROR_INVALID_ARGUMENT:
14084                         semerr(emsg_invalid_pg_name, pgn);
14085                         break;
14086 
14087                 default:
14088                         scfdie();
14089                 }
14090 
14091                 scf_pg_destroy(pg);
14092 
14093                 return;
14094         }
14095 
14096         if (pn == NULL) {
14097                 /* Try to delete the property group. */
14098                 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14099                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14100                                 scfdie();
14101 
14102                         semerr(emsg_permission_denied);
14103                 } else {
14104                         private_refresh();
14105                 }
14106 
14107                 scf_pg_destroy(pg);
14108                 return;
14109         }
14110 
14111         e = scf_entry_create(g_hndl);
14112         tx = scf_transaction_create(g_hndl);
14113 
14114         do {
14115                 if (scf_pg_update(pg) == -1)
14116                         scfdie();
14117                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14118                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14119                                 scfdie();
14120 
14121                         semerr(emsg_permission_denied);
14122                         break;
14123                 }
14124 
14125                 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14126                         if (scf_error() == SCF_ERROR_NOT_FOUND) {
14127                                 semerr(gettext("No such property %s/%s.\n"),
14128                                     pgn, pn);
14129                                 break;
14130                         } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14131                                 semerr(emsg_invalid_prop_name, pn);
14132                                 break;
14133                         } else {
14134                                 scfdie();
14135                         }
14136                 }
14137 
14138                 ret = scf_transaction_commit(tx);
14139 
14140                 if (ret == 0)
14141                         scf_transaction_reset(tx);
14142         } while (ret == 0);
14143 
14144         if (ret < 0) {
14145                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14146                         scfdie();
14147 
14148                 semerr(emsg_permission_denied);
14149         } else {
14150                 private_refresh();
14151         }
14152 
14153         scf_transaction_destroy(tx);
14154         scf_entry_destroy(e);
14155         scf_pg_destroy(pg);
14156 }
14157 
14158 /*
14159  * Property editing.
14160  */
14161 
14162 static int
14163 write_edit_script(FILE *strm)
14164 {
14165         char *fmribuf;
14166         ssize_t fmrilen;
14167 
14168         scf_propertygroup_t *pg;
14169         scf_property_t *prop;
14170         scf_value_t *val;
14171         scf_type_t ty;
14172         int ret, result = 0;
14173         scf_iter_t *iter, *piter, *viter;
14174         char *buf, *tybuf, *pname;
14175         const char *emsg_write_error;
14176 
14177 
14178         emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14179 
14180 
14181         /* select fmri */
14182         if (cur_inst != NULL) {
14183                 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14184                 if (fmrilen < 0)
14185                         scfdie();
14186                 fmribuf = safe_malloc(fmrilen + 1);
14187                 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14188                         scfdie();
14189         } else {
14190                 assert(cur_svc != NULL);
14191                 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14192                 if (fmrilen < 0)
14193                         scfdie();
14194                 fmribuf = safe_malloc(fmrilen + 1);
14195                 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14196                         scfdie();
14197         }
14198 
14199         if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14200                 warn(emsg_write_error, strerror(errno));
14201                 free(fmribuf);
14202                 return (-1);
14203         }
14204 
14205         free(fmribuf);
14206 
14207 
14208         if ((pg = scf_pg_create(g_hndl)) == NULL ||
14209             (prop = scf_property_create(g_hndl)) == NULL ||
14210             (val = scf_value_create(g_hndl)) == NULL ||
14211             (iter = scf_iter_create(g_hndl)) == NULL ||
14212             (piter = scf_iter_create(g_hndl)) == NULL ||
14213             (viter = scf_iter_create(g_hndl)) == NULL)
14214                 scfdie();
14215 
14216         buf = safe_malloc(max_scf_name_len + 1);
14217         tybuf = safe_malloc(max_scf_pg_type_len + 1);
14218         pname = safe_malloc(max_scf_name_len + 1);
14219 
14220         if (cur_inst != NULL)
14221                 ret = scf_iter_instance_pgs(iter, cur_inst);
14222         else
14223                 ret = scf_iter_service_pgs(iter, cur_svc);
14224         if (ret != SCF_SUCCESS)
14225                 scfdie();
14226 
14227         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14228                 int ret2;
14229 
14230                 /*
14231                  * # delprop pg
14232                  * # addpg pg type
14233                  */
14234                 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14235                         scfdie();
14236 
14237                 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14238                         scfdie();
14239 
14240                 if (fprintf(strm, "# Property group \"%s\"\n"
14241                     "# delprop %s\n"
14242                     "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14243                         warn(emsg_write_error, strerror(errno));
14244                         result = -1;
14245                         goto out;
14246                 }
14247 
14248                 /* # setprop pg/prop = (values) */
14249 
14250                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14251                         scfdie();
14252 
14253                 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14254                         int first = 1;
14255                         int ret3;
14256                         int multiple;
14257                         int is_str;
14258                         scf_type_t bty;
14259 
14260                         if (scf_property_get_name(prop, pname,
14261                             max_scf_name_len + 1) < 0)
14262                                 scfdie();
14263 
14264                         if (scf_property_type(prop, &ty) != 0)
14265                                 scfdie();
14266 
14267                         multiple = prop_has_multiple_values(prop, val);
14268 
14269                         if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14270                             pname, scf_type_to_string(ty), multiple ? "(" : "")
14271                             < 0) {
14272                                 warn(emsg_write_error, strerror(errno));
14273                                 result = -1;
14274                                 goto out;
14275                         }
14276 
14277                         (void) scf_type_base_type(ty, &bty);
14278                         is_str = (bty == SCF_TYPE_ASTRING);
14279 
14280                         if (scf_iter_property_values(viter, prop) !=
14281                             SCF_SUCCESS)
14282                                 scfdie();
14283 
14284                         while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14285                                 char *buf;
14286                                 ssize_t buflen;
14287 
14288                                 buflen = scf_value_get_as_string(val, NULL, 0);
14289                                 if (buflen < 0)
14290                                         scfdie();
14291 
14292                                 buf = safe_malloc(buflen + 1);
14293 
14294                                 if (scf_value_get_as_string(val, buf,
14295                                     buflen + 1) < 0)
14296                                         scfdie();
14297 
14298                                 if (first)
14299                                         first = 0;
14300                                 else {
14301                                         if (putc(' ', strm) != ' ') {
14302                                                 warn(emsg_write_error,
14303                                                     strerror(errno));
14304                                                 result = -1;
14305                                                 goto out;
14306                                         }
14307                                 }
14308 
14309                                 if ((is_str && multiple) ||
14310                                     strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14311                                         (void) putc('"', strm);
14312                                         (void) quote_and_print(buf, strm, 1);
14313                                         (void) putc('"', strm);
14314 
14315                                         if (ferror(strm)) {
14316                                                 warn(emsg_write_error,
14317                                                     strerror(errno));
14318                                                 result = -1;
14319                                                 goto out;
14320                                         }
14321                                 } else {
14322                                         if (fprintf(strm, "%s", buf) < 0) {
14323                                                 warn(emsg_write_error,
14324                                                     strerror(errno));
14325                                                 result = -1;
14326                                                 goto out;
14327                                         }
14328                                 }
14329 
14330                                 free(buf);
14331                         }
14332                         if (ret3 < 0 &&
14333                             scf_error() != SCF_ERROR_PERMISSION_DENIED)
14334                                 scfdie();
14335 
14336                         /* Write closing paren if mult-value property */
14337                         if ((multiple && putc(')', strm) == EOF) ||
14338 
14339                             /* Write final newline */
14340                             fputc('\n', strm) == EOF) {
14341                                 warn(emsg_write_error, strerror(errno));
14342                                 result = -1;
14343                                 goto out;
14344                         }
14345                 }
14346                 if (ret2 < 0)
14347                         scfdie();
14348 
14349                 if (fputc('\n', strm) == EOF) {
14350                         warn(emsg_write_error, strerror(errno));
14351                         result = -1;
14352                         goto out;
14353                 }
14354         }
14355         if (ret < 0)
14356                 scfdie();
14357 
14358 out:
14359         free(pname);
14360         free(tybuf);
14361         free(buf);
14362         scf_iter_destroy(viter);
14363         scf_iter_destroy(piter);
14364         scf_iter_destroy(iter);
14365         scf_value_destroy(val);
14366         scf_property_destroy(prop);
14367         scf_pg_destroy(pg);
14368 
14369         if (result == 0) {
14370                 if (fflush(strm) != 0) {
14371                         warn(emsg_write_error, strerror(errno));
14372                         return (-1);
14373                 }
14374         }
14375 
14376         return (result);
14377 }
14378 
14379 int
14380 lscf_editprop()
14381 {
14382         char *buf, *editor;
14383         size_t bufsz;
14384         int tmpfd;
14385         char tempname[] = TEMP_FILE_PATTERN;
14386 
14387         lscf_prep_hndl();
14388 
14389         if (cur_snap != NULL) {
14390                 semerr(emsg_cant_modify_snapshots);
14391                 return (-1);
14392         }
14393 
14394         if (cur_svc == NULL && cur_inst == NULL) {
14395                 semerr(emsg_entity_not_selected);
14396                 return (-1);
14397         }
14398 
14399         tmpfd = mkstemp(tempname);
14400         if (tmpfd == -1) {
14401                 semerr(gettext("Could not create temporary file.\n"));
14402                 return (-1);
14403         }
14404 
14405         (void) strcpy(tempfilename, tempname);
14406 
14407         tempfile = fdopen(tmpfd, "r+");
14408         if (tempfile == NULL) {
14409                 warn(gettext("Could not create temporary file.\n"));
14410                 if (close(tmpfd) == -1)
14411                         warn(gettext("Could not close temporary file: %s.\n"),
14412                             strerror(errno));
14413 
14414                 remove_tempfile();
14415 
14416                 return (-1);
14417         }
14418 
14419         if (write_edit_script(tempfile) == -1) {
14420                 remove_tempfile();
14421                 return (-1);
14422         }
14423 
14424         editor = getenv("EDITOR");
14425         if (editor == NULL)
14426                 editor = "vi";
14427 
14428         bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14429         buf = safe_malloc(bufsz);
14430 
14431         if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14432                 uu_die(gettext("Error creating editor command"));
14433 
14434         if (system(buf) == -1) {
14435                 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14436                     strerror(errno));
14437                 free(buf);
14438                 remove_tempfile();
14439                 return (-1);
14440         }
14441 
14442         free(buf);
14443 
14444         (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14445 
14446         remove_tempfile();
14447 
14448         return (0);
14449 }
14450 
14451 static void
14452 add_string(uu_list_t *strlist, const char *str)
14453 {
14454         string_list_t *elem;
14455         elem = safe_malloc(sizeof (*elem));
14456         uu_list_node_init(elem, &elem->node, string_pool);
14457         elem->str = safe_strdup(str);
14458         if (uu_list_append(strlist, elem) != 0)
14459                 uu_die(gettext("libuutil error: %s\n"),
14460                     uu_strerror(uu_error()));
14461 }
14462 
14463 static int
14464 remove_string(uu_list_t *strlist, const char *str)
14465 {
14466         uu_list_walk_t  *elems;
14467         string_list_t   *sp;
14468 
14469         /*
14470          * Find the element that needs to be removed.
14471          */
14472         elems = uu_list_walk_start(strlist, UU_DEFAULT);
14473         while ((sp = uu_list_walk_next(elems)) != NULL) {
14474                 if (strcmp(sp->str, str) == 0)
14475                         break;
14476         }
14477         uu_list_walk_end(elems);
14478 
14479         /*
14480          * Returning 1 here as the value was not found, this
14481          * might not be an error.  Leave it to the caller to
14482          * decide.
14483          */
14484         if (sp == NULL) {
14485                 return (1);
14486         }
14487 
14488         uu_list_remove(strlist, sp);
14489 
14490         free(sp->str);
14491         free(sp);
14492 
14493         return (0);
14494 }
14495 
14496 /*
14497  * Get all property values that don't match the given glob pattern,
14498  * if a pattern is specified.
14499  */
14500 static void
14501 get_prop_values(scf_property_t *prop, uu_list_t *values,
14502     const char *pattern)
14503 {
14504         scf_iter_t *iter;
14505         scf_value_t *val;
14506         int ret;
14507 
14508         if ((iter = scf_iter_create(g_hndl)) == NULL ||
14509             (val = scf_value_create(g_hndl)) == NULL)
14510                 scfdie();
14511 
14512         if (scf_iter_property_values(iter, prop) != 0)
14513                 scfdie();
14514 
14515         while ((ret = scf_iter_next_value(iter, val)) == 1) {
14516                 char *buf;
14517                 ssize_t vlen, szret;
14518 
14519                 vlen = scf_value_get_as_string(val, NULL, 0);
14520                 if (vlen < 0)
14521                         scfdie();
14522 
14523                 buf = safe_malloc(vlen + 1);
14524 
14525                 szret = scf_value_get_as_string(val, buf, vlen + 1);
14526                 if (szret < 0)
14527                         scfdie();
14528                 assert(szret <= vlen);
14529 
14530                 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14531                         add_string(values, buf);
14532 
14533                 free(buf);
14534         }
14535 
14536         if (ret == -1)
14537                 scfdie();
14538 
14539         scf_value_destroy(val);
14540         scf_iter_destroy(iter);
14541 }
14542 
14543 static int
14544 lscf_setpropvalue(const char *pgname, const char *type,
14545     const char *arg, int isadd, int isnotfoundok)
14546 {
14547         scf_type_t ty;
14548         scf_propertygroup_t *pg;
14549         scf_property_t *prop;
14550         int ret, result = 0;
14551         scf_transaction_t *tx;
14552         scf_transaction_entry_t *e;
14553         scf_value_t *v;
14554         string_list_t *sp;
14555         char *propname;
14556         uu_list_t *values;
14557         uu_list_walk_t *walk;
14558         void *cookie = NULL;
14559         char *pattern = NULL;
14560 
14561         lscf_prep_hndl();
14562 
14563         if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14564                 uu_die(gettext("Could not create property list: %s\n"),
14565                     uu_strerror(uu_error()));
14566 
14567         if (!isadd)
14568                 pattern = safe_strdup(arg);
14569 
14570         if ((e = scf_entry_create(g_hndl)) == NULL ||
14571             (pg = scf_pg_create(g_hndl)) == NULL ||
14572             (prop = scf_property_create(g_hndl)) == NULL ||
14573             (tx = scf_transaction_create(g_hndl)) == NULL)
14574                 scfdie();
14575 
14576         if (cur_snap != NULL) {
14577                 semerr(emsg_cant_modify_snapshots);
14578                 goto fail;
14579         }
14580 
14581         if (cur_inst == NULL && cur_svc == NULL) {
14582                 semerr(emsg_entity_not_selected);
14583                 goto fail;
14584         }
14585 
14586         propname = strchr(pgname, '/');
14587         if (propname == NULL) {
14588                 semerr(gettext("Property names must contain a `/'.\n"));
14589                 goto fail;
14590         }
14591 
14592         *propname = '\0';
14593         ++propname;
14594 
14595         if (type != NULL) {
14596                 ty = string_to_type(type);
14597                 if (ty == SCF_TYPE_INVALID) {
14598                         semerr(gettext("Unknown type \"%s\".\n"), type);
14599                         goto fail;
14600                 }
14601         }
14602 
14603         if (cur_inst != NULL)
14604                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14605         else
14606                 ret = scf_service_get_pg(cur_svc, pgname, pg);
14607         if (ret != 0) {
14608                 switch (scf_error()) {
14609                 case SCF_ERROR_NOT_FOUND:
14610                         if (isnotfoundok) {
14611                                 result = 0;
14612                         } else {
14613                                 semerr(emsg_no_such_pg, pgname);
14614                                 result = -1;
14615                         }
14616                         goto out;
14617 
14618                 case SCF_ERROR_INVALID_ARGUMENT:
14619                         semerr(emsg_invalid_pg_name, pgname);
14620                         goto fail;
14621 
14622                 default:
14623                         scfdie();
14624                 }
14625         }
14626 
14627         do {
14628                 if (scf_pg_update(pg) == -1)
14629                         scfdie();
14630                 if (scf_transaction_start(tx, pg) != 0) {
14631                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14632                                 scfdie();
14633 
14634                         semerr(emsg_permission_denied);
14635                         goto fail;
14636                 }
14637 
14638                 ret = scf_pg_get_property(pg, propname, prop);
14639                 if (ret == 0) {
14640                         scf_type_t ptype;
14641                         char *pat = pattern;
14642 
14643                         if (scf_property_type(prop, &ptype) != 0)
14644                                 scfdie();
14645 
14646                         if (isadd) {
14647                                 if (type != NULL && ptype != ty) {
14648                                         semerr(gettext("Property \"%s\" is not "
14649                                             "of type \"%s\".\n"), propname,
14650                                             type);
14651                                         goto fail;
14652                                 }
14653 
14654                                 pat = NULL;
14655                         } else {
14656                                 size_t len = strlen(pat);
14657                                 if (len > 0 && pat[len - 1] == '\"')
14658                                         pat[len - 1] = '\0';
14659                                 if (len > 0 && pat[0] == '\"')
14660                                         pat++;
14661                         }
14662 
14663                         ty = ptype;
14664 
14665                         get_prop_values(prop, values, pat);
14666 
14667                         if (isadd)
14668                                 add_string(values, arg);
14669 
14670                         if (scf_transaction_property_change(tx, e,
14671                             propname, ty) == -1)
14672                                 scfdie();
14673                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14674                         if (isadd) {
14675                                 if (type == NULL) {
14676                                         semerr(gettext("Type required "
14677                                             "for new properties.\n"));
14678                                         goto fail;
14679                                 }
14680 
14681                                 add_string(values, arg);
14682 
14683                                 if (scf_transaction_property_new(tx, e,
14684                                     propname, ty) == -1)
14685                                         scfdie();
14686                         } else if (isnotfoundok) {
14687                                 result = 0;
14688                                 goto out;
14689                         } else {
14690                                 semerr(gettext("No such property %s/%s.\n"),
14691                                     pgname, propname);
14692                                 result = -1;
14693                                 goto out;
14694                         }
14695                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14696                         semerr(emsg_invalid_prop_name, propname);
14697                         goto fail;
14698                 } else {
14699                         scfdie();
14700                 }
14701 
14702                 walk = uu_list_walk_start(values, UU_DEFAULT);
14703                 if (walk == NULL)
14704                         uu_die(gettext("Could not walk property list.\n"));
14705 
14706                 for (sp = uu_list_walk_next(walk); sp != NULL;
14707                     sp = uu_list_walk_next(walk)) {
14708                         v = string_to_value(sp->str, ty, 0);
14709 
14710                         if (v == NULL) {
14711                                 scf_entry_destroy_children(e);
14712                                 goto fail;
14713                         }
14714                         ret = scf_entry_add_value(e, v);
14715                         assert(ret == 0);
14716                 }
14717                 uu_list_walk_end(walk);
14718 
14719                 result = scf_transaction_commit(tx);
14720 
14721                 scf_transaction_reset(tx);
14722                 scf_entry_destroy_children(e);
14723         } while (result == 0);
14724 
14725         if (result < 0) {
14726                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14727                         scfdie();
14728 
14729                 semerr(emsg_permission_denied);
14730                 goto fail;
14731         }
14732 
14733         result = 0;
14734 
14735         private_refresh();
14736 
14737 out:
14738         scf_transaction_destroy(tx);
14739         scf_entry_destroy(e);
14740         scf_pg_destroy(pg);
14741         scf_property_destroy(prop);
14742         free(pattern);
14743 
14744         while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14745                 free(sp->str);
14746                 free(sp);
14747         }
14748 
14749         uu_list_destroy(values);
14750 
14751         return (result);
14752 
14753 fail:
14754         result = -1;
14755         goto out;
14756 }
14757 
14758 int
14759 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14760 {
14761         return (lscf_setpropvalue(pgname, type, value, 1, 0));
14762 }
14763 
14764 int
14765 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14766 {
14767         return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14768 }
14769 
14770 /*
14771  * Look for a standard start method, first in the instance (if any),
14772  * then the service.
14773  */
14774 static const char *
14775 start_method_name(int *in_instance)
14776 {
14777         scf_propertygroup_t *pg;
14778         char **p;
14779         int ret;
14780         scf_instance_t *inst = cur_inst;
14781 
14782         if ((pg = scf_pg_create(g_hndl)) == NULL)
14783                 scfdie();
14784 
14785 again:
14786         for (p = start_method_names; *p != NULL; p++) {
14787                 if (inst != NULL)
14788                         ret = scf_instance_get_pg(inst, *p, pg);
14789                 else
14790                         ret = scf_service_get_pg(cur_svc, *p, pg);
14791 
14792                 if (ret == 0) {
14793                         size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14794                         char *buf = safe_malloc(bufsz);
14795 
14796                         if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14797                                 free(buf);
14798                                 continue;
14799                         }
14800                         if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14801                                 free(buf);
14802                                 continue;
14803                         }
14804 
14805                         free(buf);
14806                         *in_instance = (inst != NULL);
14807                         scf_pg_destroy(pg);
14808                         return (*p);
14809                 }
14810 
14811                 if (scf_error() == SCF_ERROR_NOT_FOUND)
14812                         continue;
14813 
14814                 scfdie();
14815         }
14816 
14817         if (inst != NULL) {
14818                 inst = NULL;
14819                 goto again;
14820         }
14821 
14822         scf_pg_destroy(pg);
14823         return (NULL);
14824 }
14825 
14826 static int
14827 addpg(const char *name, const char *type)
14828 {
14829         scf_propertygroup_t *pg;
14830         int ret;
14831 
14832         pg = scf_pg_create(g_hndl);
14833         if (pg == NULL)
14834                 scfdie();
14835 
14836         if (cur_inst != NULL)
14837                 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14838         else
14839                 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14840 
14841         if (ret != 0) {
14842                 switch (scf_error()) {
14843                 case SCF_ERROR_EXISTS:
14844                         ret = 0;
14845                         break;
14846 
14847                 case SCF_ERROR_PERMISSION_DENIED:
14848                         semerr(emsg_permission_denied);
14849                         break;
14850 
14851                 default:
14852                         scfdie();
14853                 }
14854         }
14855 
14856         scf_pg_destroy(pg);
14857         return (ret);
14858 }
14859 
14860 int
14861 lscf_setenv(uu_list_t *args, int isunset)
14862 {
14863         int ret = 0;
14864         size_t i;
14865         int argc;
14866         char **argv = NULL;
14867         string_list_t *slp;
14868         char *pattern;
14869         char *prop;
14870         int do_service = 0;
14871         int do_instance = 0;
14872         const char *method = NULL;
14873         const char *name = NULL;
14874         const char *value = NULL;
14875         scf_instance_t *saved_cur_inst = cur_inst;
14876 
14877         lscf_prep_hndl();
14878 
14879         argc = uu_list_numnodes(args);
14880         if (argc < 1)
14881                 goto usage;
14882 
14883         argv = calloc(argc + 1, sizeof (char *));
14884         if (argv == NULL)
14885                 uu_die(gettext("Out of memory.\n"));
14886 
14887         for (slp = uu_list_first(args), i = 0;
14888             slp != NULL;
14889             slp = uu_list_next(args, slp), ++i)
14890                 argv[i] = slp->str;
14891 
14892         argv[i] = NULL;
14893 
14894         opterr = 0;
14895         optind = 0;
14896         for (;;) {
14897                 ret = getopt(argc, argv, "sim:");
14898                 if (ret == -1)
14899                         break;
14900 
14901                 switch (ret) {
14902                 case 's':
14903                         do_service = 1;
14904                         cur_inst = NULL;
14905                         break;
14906 
14907                 case 'i':
14908                         do_instance = 1;
14909                         break;
14910 
14911                 case 'm':
14912                         method = optarg;
14913                         break;
14914 
14915                 case '?':
14916                         goto usage;
14917 
14918                 default:
14919                         bad_error("getopt", ret);
14920                 }
14921         }
14922 
14923         argc -= optind;
14924         if ((do_service && do_instance) ||
14925             (isunset && argc != 1) ||
14926             (!isunset && argc != 2))
14927                 goto usage;
14928 
14929         name = argv[optind];
14930         if (!isunset)
14931                 value = argv[optind + 1];
14932 
14933         if (cur_snap != NULL) {
14934                 semerr(emsg_cant_modify_snapshots);
14935                 ret = -1;
14936                 goto out;
14937         }
14938 
14939         if (cur_inst == NULL && cur_svc == NULL) {
14940                 semerr(emsg_entity_not_selected);
14941                 ret = -1;
14942                 goto out;
14943         }
14944 
14945         if (do_instance && cur_inst == NULL) {
14946                 semerr(gettext("No instance is selected.\n"));
14947                 ret = -1;
14948                 goto out;
14949         }
14950 
14951         if (do_service && cur_svc == NULL) {
14952                 semerr(gettext("No service is selected.\n"));
14953                 ret = -1;
14954                 goto out;
14955         }
14956 
14957         if (method == NULL) {
14958                 if (do_instance || do_service) {
14959                         method = "method_context";
14960                         if (!isunset) {
14961                                 ret = addpg("method_context",
14962                                     SCF_GROUP_FRAMEWORK);
14963                                 if (ret != 0)
14964                                         goto out;
14965                         }
14966                 } else {
14967                         int in_instance;
14968                         method = start_method_name(&in_instance);
14969                         if (method == NULL) {
14970                                 semerr(gettext(
14971                                     "Couldn't find start method; please "
14972                                     "specify a method with '-m'.\n"));
14973                                 ret = -1;
14974                                 goto out;
14975                         }
14976                         if (!in_instance)
14977                                 cur_inst = NULL;
14978                 }
14979         } else {
14980                 scf_propertygroup_t *pg;
14981                 size_t bufsz;
14982                 char *buf;
14983                 int ret;
14984 
14985                 if ((pg = scf_pg_create(g_hndl)) == NULL)
14986                         scfdie();
14987 
14988                 if (cur_inst != NULL)
14989                         ret = scf_instance_get_pg(cur_inst, method, pg);
14990                 else
14991                         ret = scf_service_get_pg(cur_svc, method, pg);
14992 
14993                 if (ret != 0) {
14994                         scf_pg_destroy(pg);
14995                         switch (scf_error()) {
14996                         case SCF_ERROR_NOT_FOUND:
14997                                 semerr(gettext("Couldn't find the method "
14998                                     "\"%s\".\n"), method);
14999                                 goto out;
15000 
15001                         case SCF_ERROR_INVALID_ARGUMENT:
15002                                 semerr(gettext("Invalid method name \"%s\".\n"),
15003                                     method);
15004                                 goto out;
15005 
15006                         default:
15007                                 scfdie();
15008                         }
15009                 }
15010 
15011                 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15012                 buf = safe_malloc(bufsz);
15013 
15014                 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15015                     strcmp(buf, SCF_GROUP_METHOD) != 0) {
15016                         semerr(gettext("Property group \"%s\" is not of type "
15017                             "\"method\".\n"), method);
15018                         ret = -1;
15019                         free(buf);
15020                         scf_pg_destroy(pg);
15021                         goto out;
15022                 }
15023 
15024                 free(buf);
15025                 scf_pg_destroy(pg);
15026         }
15027 
15028         prop = uu_msprintf("%s/environment", method);
15029         pattern = uu_msprintf("%s=*", name);
15030 
15031         if (prop == NULL || pattern == NULL)
15032                 uu_die(gettext("Out of memory.\n"));
15033 
15034         ret = lscf_delpropvalue(prop, pattern, !isunset);
15035 
15036         if (ret == 0 && !isunset) {
15037                 uu_free(pattern);
15038                 uu_free(prop);
15039                 prop = uu_msprintf("%s/environment", method);
15040                 pattern = uu_msprintf("%s=%s", name, value);
15041                 if (prop == NULL || pattern == NULL)
15042                         uu_die(gettext("Out of memory.\n"));
15043                 ret = lscf_addpropvalue(prop, "astring:", pattern);
15044         }
15045         uu_free(pattern);
15046         uu_free(prop);
15047 
15048 out:
15049         cur_inst = saved_cur_inst;
15050 
15051         free(argv);
15052         return (ret);
15053 usage:
15054         ret = -2;
15055         goto out;
15056 }
15057 
15058 /*
15059  * Snapshot commands
15060  */
15061 
15062 void
15063 lscf_listsnap()
15064 {
15065         scf_snapshot_t *snap;
15066         scf_iter_t *iter;
15067         char *nb;
15068         int r;
15069 
15070         lscf_prep_hndl();
15071 
15072         if (cur_inst == NULL) {
15073                 semerr(gettext("Instance not selected.\n"));
15074                 return;
15075         }
15076 
15077         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15078             (iter = scf_iter_create(g_hndl)) == NULL)
15079                 scfdie();
15080 
15081         if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15082                 scfdie();
15083 
15084         nb = safe_malloc(max_scf_name_len + 1);
15085 
15086         while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15087                 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15088                         scfdie();
15089 
15090                 (void) puts(nb);
15091         }
15092         if (r < 0)
15093                 scfdie();
15094 
15095         free(nb);
15096         scf_iter_destroy(iter);
15097         scf_snapshot_destroy(snap);
15098 }
15099 
15100 void
15101 lscf_selectsnap(const char *name)
15102 {
15103         scf_snapshot_t *snap;
15104         scf_snaplevel_t *level;
15105 
15106         lscf_prep_hndl();
15107 
15108         if (cur_inst == NULL) {
15109                 semerr(gettext("Instance not selected.\n"));
15110                 return;
15111         }
15112 
15113         if (cur_snap != NULL) {
15114                 if (name != NULL) {
15115                         char *cur_snap_name;
15116                         boolean_t nochange;
15117 
15118                         cur_snap_name = safe_malloc(max_scf_name_len + 1);
15119 
15120                         if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15121                             max_scf_name_len + 1) < 0)
15122                                 scfdie();
15123 
15124                         nochange = strcmp(name, cur_snap_name) == 0;
15125 
15126                         free(cur_snap_name);
15127 
15128                         if (nochange)
15129                                 return;
15130                 }
15131 
15132                 unselect_cursnap();
15133         }
15134 
15135         if (name == NULL)
15136                 return;
15137 
15138         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15139             (level = scf_snaplevel_create(g_hndl)) == NULL)
15140                 scfdie();
15141 
15142         if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15143             SCF_SUCCESS) {
15144                 switch (scf_error()) {
15145                 case SCF_ERROR_INVALID_ARGUMENT:
15146                         semerr(gettext("Invalid name \"%s\".\n"), name);
15147                         break;
15148 
15149                 case SCF_ERROR_NOT_FOUND:
15150                         semerr(gettext("No such snapshot \"%s\".\n"), name);
15151                         break;
15152 
15153                 default:
15154                         scfdie();
15155                 }
15156 
15157                 scf_snaplevel_destroy(level);
15158                 scf_snapshot_destroy(snap);
15159                 return;
15160         }
15161 
15162         /* Load the snaplevels into our list. */
15163         cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15164         if (cur_levels == NULL)
15165                 uu_die(gettext("Could not create list: %s\n"),
15166                     uu_strerror(uu_error()));
15167 
15168         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15169                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15170                         scfdie();
15171 
15172                 semerr(gettext("Snapshot has no snaplevels.\n"));
15173 
15174                 scf_snaplevel_destroy(level);
15175                 scf_snapshot_destroy(snap);
15176                 return;
15177         }
15178 
15179         cur_snap = snap;
15180 
15181         for (;;) {
15182                 cur_elt = safe_malloc(sizeof (*cur_elt));
15183                 uu_list_node_init(cur_elt, &cur_elt->list_node,
15184                     snaplevel_pool);
15185                 cur_elt->sl = level;
15186                 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15187                         uu_die(gettext("libuutil error: %s\n"),
15188                             uu_strerror(uu_error()));
15189 
15190                 level = scf_snaplevel_create(g_hndl);
15191                 if (level == NULL)
15192                         scfdie();
15193 
15194                 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15195                     level) != SCF_SUCCESS) {
15196                         if (scf_error() != SCF_ERROR_NOT_FOUND)
15197                                 scfdie();
15198 
15199                         scf_snaplevel_destroy(level);
15200                         break;
15201                 }
15202         }
15203 
15204         cur_elt = uu_list_last(cur_levels);
15205         cur_level = cur_elt->sl;
15206 }
15207 
15208 /*
15209  * Copies the properties & values in src to dst.  Assumes src won't change.
15210  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15211  * and 0 on success.
15212  *
15213  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15214  * property, if it is copied and has type boolean.  (See comment in
15215  * lscf_revert()).
15216  */
15217 static int
15218 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15219     uint8_t enabled)
15220 {
15221         scf_transaction_t *tx;
15222         scf_iter_t *iter, *viter;
15223         scf_property_t *prop;
15224         scf_value_t *v;
15225         char *nbuf;
15226         int r;
15227 
15228         tx = scf_transaction_create(g_hndl);
15229         if (tx == NULL)
15230                 scfdie();
15231 
15232         if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15233                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15234                         scfdie();
15235 
15236                 scf_transaction_destroy(tx);
15237 
15238                 return (-1);
15239         }
15240 
15241         if ((iter = scf_iter_create(g_hndl)) == NULL ||
15242             (prop = scf_property_create(g_hndl)) == NULL ||
15243             (viter = scf_iter_create(g_hndl)) == NULL)
15244                 scfdie();
15245 
15246         nbuf = safe_malloc(max_scf_name_len + 1);
15247 
15248         if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15249                 scfdie();
15250 
15251         for (;;) {
15252                 scf_transaction_entry_t *e;
15253                 scf_type_t ty;
15254 
15255                 r = scf_iter_next_property(iter, prop);
15256                 if (r == -1)
15257                         scfdie();
15258                 if (r == 0)
15259                         break;
15260 
15261                 e = scf_entry_create(g_hndl);
15262                 if (e == NULL)
15263                         scfdie();
15264 
15265                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15266                         scfdie();
15267 
15268                 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15269                         scfdie();
15270 
15271                 if (scf_transaction_property_new(tx, e, nbuf,
15272                     ty) != SCF_SUCCESS)
15273                         scfdie();
15274 
15275                 if ((enabled == 0 || enabled == 1) &&
15276                     strcmp(nbuf, scf_property_enabled) == 0 &&
15277                     ty == SCF_TYPE_BOOLEAN) {
15278                         v = scf_value_create(g_hndl);
15279                         if (v == NULL)
15280                                 scfdie();
15281 
15282                         scf_value_set_boolean(v, enabled);
15283 
15284                         if (scf_entry_add_value(e, v) != 0)
15285                                 scfdie();
15286                 } else {
15287                         if (scf_iter_property_values(viter, prop) != 0)
15288                                 scfdie();
15289 
15290                         for (;;) {
15291                                 v = scf_value_create(g_hndl);
15292                                 if (v == NULL)
15293                                         scfdie();
15294 
15295                                 r = scf_iter_next_value(viter, v);
15296                                 if (r == -1)
15297                                         scfdie();
15298                                 if (r == 0) {
15299                                         scf_value_destroy(v);
15300                                         break;
15301                                 }
15302 
15303                                 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15304                                         scfdie();
15305                         }
15306                 }
15307         }
15308 
15309         free(nbuf);
15310         scf_iter_destroy(viter);
15311         scf_property_destroy(prop);
15312         scf_iter_destroy(iter);
15313 
15314         r = scf_transaction_commit(tx);
15315         if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15316                 scfdie();
15317 
15318         scf_transaction_destroy_children(tx);
15319         scf_transaction_destroy(tx);
15320 
15321         switch (r) {
15322         case 1:         return (0);
15323         case 0:         return (-2);
15324         case -1:        return (-1);
15325 
15326         default:
15327                 abort();
15328         }
15329 
15330         /* NOTREACHED */
15331 }
15332 
15333 void
15334 lscf_revert(const char *snapname)
15335 {
15336         scf_snapshot_t *snap, *prev;
15337         scf_snaplevel_t *level, *nlevel;
15338         scf_iter_t *iter;
15339         scf_propertygroup_t *pg, *npg;
15340         scf_property_t *prop;
15341         scf_value_t *val;
15342         char *nbuf, *tbuf;
15343         uint8_t enabled;
15344 
15345         lscf_prep_hndl();
15346 
15347         if (cur_inst == NULL) {
15348                 semerr(gettext("Instance not selected.\n"));
15349                 return;
15350         }
15351 
15352         if (snapname != NULL) {
15353                 snap = scf_snapshot_create(g_hndl);
15354                 if (snap == NULL)
15355                         scfdie();
15356 
15357                 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15358                     SCF_SUCCESS) {
15359                         switch (scf_error()) {
15360                         case SCF_ERROR_INVALID_ARGUMENT:
15361                                 semerr(gettext("Invalid snapshot name "
15362                                     "\"%s\".\n"), snapname);
15363                                 break;
15364 
15365                         case SCF_ERROR_NOT_FOUND:
15366                                 semerr(gettext("No such snapshot.\n"));
15367                                 break;
15368 
15369                         default:
15370                                 scfdie();
15371                         }
15372 
15373                         scf_snapshot_destroy(snap);
15374                         return;
15375                 }
15376         } else {
15377                 if (cur_snap != NULL) {
15378                         snap = cur_snap;
15379                 } else {
15380                         semerr(gettext("No snapshot selected.\n"));
15381                         return;
15382                 }
15383         }
15384 
15385         if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15386             (level = scf_snaplevel_create(g_hndl)) == NULL ||
15387             (iter = scf_iter_create(g_hndl)) == NULL ||
15388             (pg = scf_pg_create(g_hndl)) == NULL ||
15389             (npg = scf_pg_create(g_hndl)) == NULL ||
15390             (prop = scf_property_create(g_hndl)) == NULL ||
15391             (val = scf_value_create(g_hndl)) == NULL)
15392                 scfdie();
15393 
15394         nbuf = safe_malloc(max_scf_name_len + 1);
15395         tbuf = safe_malloc(max_scf_pg_type_len + 1);
15396 
15397         /* Take the "previous" snapshot before we blow away the properties. */
15398         if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15399                 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15400                         scfdie();
15401         } else {
15402                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15403                         scfdie();
15404 
15405                 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15406                         scfdie();
15407         }
15408 
15409         /* Save general/enabled, since we're probably going to replace it. */
15410         enabled = 2;
15411         if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15412             scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15413             scf_property_get_value(prop, val) == 0)
15414                 (void) scf_value_get_boolean(val, &enabled);
15415 
15416         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15417                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15418                         scfdie();
15419 
15420                 goto out;
15421         }
15422 
15423         for (;;) {
15424                 boolean_t isinst;
15425                 uint32_t flags;
15426                 int r;
15427 
15428                 /* Clear the properties from the corresponding entity. */
15429                 isinst = snaplevel_is_instance(level);
15430 
15431                 if (!isinst)
15432                         r = scf_iter_service_pgs(iter, cur_svc);
15433                 else
15434                         r = scf_iter_instance_pgs(iter, cur_inst);
15435                 if (r != SCF_SUCCESS)
15436                         scfdie();
15437 
15438                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15439                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15440                                 scfdie();
15441 
15442                         /* Skip nonpersistent pgs. */
15443                         if (flags & SCF_PG_FLAG_NONPERSISTENT)
15444                                 continue;
15445 
15446                         if (scf_pg_delete(pg) != SCF_SUCCESS) {
15447                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15448                                         scfdie();
15449 
15450                                 semerr(emsg_permission_denied);
15451                                 goto out;
15452                         }
15453                 }
15454                 if (r == -1)
15455                         scfdie();
15456 
15457                 /* Copy the properties to the corresponding entity. */
15458                 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15459                         scfdie();
15460 
15461                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15462                         if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15463                                 scfdie();
15464 
15465                         if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15466                             0)
15467                                 scfdie();
15468 
15469                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15470                                 scfdie();
15471 
15472                         if (!isinst)
15473                                 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15474                                     flags, npg);
15475                         else
15476                                 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15477                                     flags, npg);
15478                         if (r != SCF_SUCCESS) {
15479                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15480                                         scfdie();
15481 
15482                                 semerr(emsg_permission_denied);
15483                                 goto out;
15484                         }
15485 
15486                         if ((enabled == 0 || enabled == 1) &&
15487                             strcmp(nbuf, scf_pg_general) == 0)
15488                                 r = pg_copy(pg, npg, enabled);
15489                         else
15490                                 r = pg_copy(pg, npg, 2);
15491 
15492                         switch (r) {
15493                         case 0:
15494                                 break;
15495 
15496                         case -1:
15497                                 semerr(emsg_permission_denied);
15498                                 goto out;
15499 
15500                         case -2:
15501                                 semerr(gettext(
15502                                     "Interrupted by another change.\n"));
15503                                 goto out;
15504 
15505                         default:
15506                                 abort();
15507                         }
15508                 }
15509                 if (r == -1)
15510                         scfdie();
15511 
15512                 /* Get next level. */
15513                 nlevel = scf_snaplevel_create(g_hndl);
15514                 if (nlevel == NULL)
15515                         scfdie();
15516 
15517                 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15518                     SCF_SUCCESS) {
15519                         if (scf_error() != SCF_ERROR_NOT_FOUND)
15520                                 scfdie();
15521 
15522                         scf_snaplevel_destroy(nlevel);
15523                         break;
15524                 }
15525 
15526                 scf_snaplevel_destroy(level);
15527                 level = nlevel;
15528         }
15529 
15530         if (snapname == NULL) {
15531                 lscf_selectsnap(NULL);
15532                 snap = NULL;            /* cur_snap has been destroyed */
15533         }
15534 
15535 out:
15536         free(tbuf);
15537         free(nbuf);
15538         scf_value_destroy(val);
15539         scf_property_destroy(prop);
15540         scf_pg_destroy(npg);
15541         scf_pg_destroy(pg);
15542         scf_iter_destroy(iter);
15543         scf_snaplevel_destroy(level);
15544         scf_snapshot_destroy(prev);
15545         if (snap != cur_snap)
15546                 scf_snapshot_destroy(snap);
15547 }
15548 
15549 void
15550 lscf_refresh(void)
15551 {
15552         ssize_t fmrilen;
15553         size_t bufsz;
15554         char *fmribuf;
15555         int r;
15556 
15557         lscf_prep_hndl();
15558 
15559         if (cur_inst == NULL) {
15560                 semerr(gettext("Instance not selected.\n"));
15561                 return;
15562         }
15563 
15564         bufsz = max_scf_fmri_len + 1;
15565         fmribuf = safe_malloc(bufsz);
15566         fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15567         if (fmrilen < 0) {
15568                 free(fmribuf);
15569                 if (scf_error() != SCF_ERROR_DELETED)
15570                         scfdie();
15571                 scf_instance_destroy(cur_inst);
15572                 cur_inst = NULL;
15573                 warn(emsg_deleted);
15574                 return;
15575         }
15576         assert(fmrilen < bufsz);
15577 
15578         r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15579         switch (r) {
15580         case 0:
15581                 break;
15582 
15583         case ECONNABORTED:
15584                 warn(gettext("Could not refresh %s "
15585                     "(repository connection broken).\n"), fmribuf);
15586                 break;
15587 
15588         case ECANCELED:
15589                 warn(emsg_deleted);
15590                 break;
15591 
15592         case EPERM:
15593                 warn(gettext("Could not refresh %s "
15594                     "(permission denied).\n"), fmribuf);
15595                 break;
15596 
15597         case ENOSPC:
15598                 warn(gettext("Could not refresh %s "
15599                     "(repository server out of resources).\n"),
15600                     fmribuf);
15601                 break;
15602 
15603         case EACCES:
15604         default:
15605                 bad_error("refresh_entity", scf_error());
15606         }
15607 
15608         free(fmribuf);
15609 }
15610 
15611 /*
15612  * describe [-v] [-t] [pg/prop]
15613  */
15614 int
15615 lscf_describe(uu_list_t *args, int hasargs)
15616 {
15617         int ret = 0;
15618         size_t i;
15619         int argc;
15620         char **argv = NULL;
15621         string_list_t *slp;
15622         int do_verbose = 0;
15623         int do_templates = 0;
15624         char *pattern = NULL;
15625 
15626         lscf_prep_hndl();
15627 
15628         if (hasargs != 0)  {
15629                 argc = uu_list_numnodes(args);
15630                 if (argc < 1)
15631                         goto usage;
15632 
15633                 argv = calloc(argc + 1, sizeof (char *));
15634                 if (argv == NULL)
15635                         uu_die(gettext("Out of memory.\n"));
15636 
15637                 for (slp = uu_list_first(args), i = 0;
15638                     slp != NULL;
15639                     slp = uu_list_next(args, slp), ++i)
15640                         argv[i] = slp->str;
15641 
15642                 argv[i] = NULL;
15643 
15644                 /*
15645                  * We start optind = 0 because our list of arguments
15646                  * starts at argv[0]
15647                  */
15648                 optind = 0;
15649                 opterr = 0;
15650                 for (;;) {
15651                         ret = getopt(argc, argv, "vt");
15652                         if (ret == -1)
15653                                 break;
15654 
15655                         switch (ret) {
15656                         case 'v':
15657                                 do_verbose = 1;
15658                                 break;
15659 
15660                         case 't':
15661                                 do_templates = 1;
15662                                 break;
15663 
15664                         case '?':
15665                                 goto usage;
15666 
15667                         default:
15668                                 bad_error("getopt", ret);
15669                         }
15670                 }
15671 
15672                 pattern = argv[optind];
15673         }
15674 
15675         if (cur_inst == NULL && cur_svc == NULL) {
15676                 semerr(emsg_entity_not_selected);
15677                 ret = -1;
15678                 goto out;
15679         }
15680 
15681         /*
15682          * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15683          * output if their last parameter is set to 2.  Less information is
15684          * produced if the parameter is set to 1.
15685          */
15686         if (pattern == NULL) {
15687                 if (do_verbose == 1)
15688                         list_entity_tmpl(2);
15689                 else
15690                         list_entity_tmpl(1);
15691         }
15692 
15693         if (do_templates == 0) {
15694                 if (do_verbose == 1)
15695                         listprop(pattern, 0, 2);
15696                 else
15697                         listprop(pattern, 0, 1);
15698         } else {
15699                 if (do_verbose == 1)
15700                         listtmpl(pattern, 2);
15701                 else
15702                         listtmpl(pattern, 1);
15703         }
15704 
15705         ret = 0;
15706 out:
15707         if (argv != NULL)
15708                 free(argv);
15709         return (ret);
15710 usage:
15711         ret = -2;
15712         goto out;
15713 }
15714 
15715 #define PARAM_ACTIVE    ((const char *) "active")
15716 #define PARAM_INACTIVE  ((const char *) "inactive")
15717 #define PARAM_SMTP_TO   ((const char *) "to")
15718 
15719 /*
15720  * tokenize()
15721  * Breaks down the string according to the tokens passed.
15722  * Caller is responsible for freeing array of pointers returned.
15723  * Returns NULL on failure
15724  */
15725 char **
15726 tokenize(char *str, const char *sep)
15727 {
15728         char *token, *lasts;
15729         char **buf;
15730         int n = 0;      /* number of elements */
15731         int size = 8;   /* size of the array (initial) */
15732 
15733         buf = safe_malloc(size * sizeof (char *));
15734 
15735         for (token = strtok_r(str, sep, &lasts); token != NULL;
15736             token = strtok_r(NULL, sep, &lasts), ++n) {
15737                 if (n + 1 >= size) {
15738                         size *= 2;
15739                         if ((buf = realloc(buf, size * sizeof (char *))) ==
15740                             NULL) {
15741                                 uu_die(gettext("Out of memory"));
15742                         }
15743                 }
15744                 buf[n] = token;
15745         }
15746         /* NULL terminate the pointer array */
15747         buf[n] = NULL;
15748 
15749         return (buf);
15750 }
15751 
15752 int32_t
15753 check_tokens(char **p)
15754 {
15755         int32_t smf = 0;
15756         int32_t fma = 0;
15757 
15758         while (*p) {
15759                 int32_t t = string_to_tset(*p);
15760 
15761                 if (t == 0) {
15762                         if (is_fma_token(*p) == 0)
15763                                 return (INVALID_TOKENS);
15764                         fma = 1; /* this token is an fma event */
15765                 } else {
15766                         smf |= t;
15767                 }
15768 
15769                 if (smf != 0 && fma == 1)
15770                         return (MIXED_TOKENS);
15771                 ++p;
15772         }
15773 
15774         if (smf > 0)
15775                 return (smf);
15776         else if (fma == 1)
15777                 return (FMA_TOKENS);
15778 
15779         return (INVALID_TOKENS);
15780 }
15781 
15782 static int
15783 get_selection_str(char *fmri, size_t sz)
15784 {
15785         if (g_hndl == NULL) {
15786                 semerr(emsg_entity_not_selected);
15787                 return (-1);
15788         } else if (cur_level != NULL) {
15789                 semerr(emsg_invalid_for_snapshot);
15790                 return (-1);
15791         } else {
15792                 lscf_get_selection_str(fmri, sz);
15793         }
15794 
15795         return (0);
15796 }
15797 
15798 void
15799 lscf_delnotify(const char *set, int global)
15800 {
15801         char *str = strdup(set);
15802         char **pgs;
15803         char **p;
15804         int32_t tset;
15805         char *fmri = NULL;
15806 
15807         if (str == NULL)
15808                 uu_die(gettext("Out of memory.\n"));
15809 
15810         pgs = tokenize(str, ",");
15811 
15812         if ((tset = check_tokens(pgs)) > 0) {
15813                 size_t sz = max_scf_fmri_len + 1;
15814 
15815                 fmri = safe_malloc(sz);
15816                 if (global) {
15817                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15818                 } else if (get_selection_str(fmri, sz) != 0) {
15819                         goto out;
15820                 }
15821 
15822                 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15823                     tset) != SCF_SUCCESS) {
15824                         uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15825                             scf_strerror(scf_error()));
15826                 }
15827         } else if (tset == FMA_TOKENS) {
15828                 if (global) {
15829                         semerr(gettext("Can't use option '-g' with FMA event "
15830                             "definitions\n"));
15831                         goto out;
15832                 }
15833 
15834                 for (p = pgs; *p; ++p) {
15835                         if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15836                             SCF_SUCCESS) {
15837                                 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15838                                     scf_strerror(scf_error()));
15839                                 goto out;
15840                         }
15841                 }
15842         } else if (tset == MIXED_TOKENS) {
15843                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15844                 goto out;
15845         } else {
15846                 uu_die(gettext("Invalid input.\n"));
15847         }
15848 
15849 out:
15850         free(fmri);
15851         free(pgs);
15852         free(str);
15853 }
15854 
15855 void
15856 lscf_listnotify(const char *set, int global)
15857 {
15858         char *str = safe_strdup(set);
15859         char **pgs;
15860         char **p;
15861         int32_t tset;
15862         nvlist_t *nvl;
15863         char *fmri = NULL;
15864 
15865         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15866                 uu_die(gettext("Out of memory.\n"));
15867 
15868         pgs = tokenize(str, ",");
15869 
15870         if ((tset = check_tokens(pgs)) > 0) {
15871                 size_t sz = max_scf_fmri_len + 1;
15872 
15873                 fmri = safe_malloc(sz);
15874                 if (global) {
15875                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15876                 } else if (get_selection_str(fmri, sz) != 0) {
15877                         goto out;
15878                 }
15879 
15880                 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15881                     SCF_SUCCESS) {
15882                         if (scf_error() != SCF_ERROR_NOT_FOUND &&
15883                             scf_error() != SCF_ERROR_DELETED)
15884                                 uu_warn(gettext(
15885                                     "Failed listnotify: %s\n"),
15886                                     scf_strerror(scf_error()));
15887                         goto out;
15888                 }
15889 
15890                 listnotify_print(nvl, NULL);
15891         } else if (tset == FMA_TOKENS) {
15892                 if (global) {
15893                         semerr(gettext("Can't use option '-g' with FMA event "
15894                             "definitions\n"));
15895                         goto out;
15896                 }
15897 
15898                 for (p = pgs; *p; ++p) {
15899                         if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15900                             SCF_SUCCESS) {
15901                                 /*
15902                                  * if the preferences have just been deleted
15903                                  * or does not exist, just skip.
15904                                  */
15905                                 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15906                                     scf_error() == SCF_ERROR_DELETED)
15907                                         continue;
15908                                 uu_warn(gettext(
15909                                     "Failed listnotify: %s\n"),
15910                                     scf_strerror(scf_error()));
15911                                 goto out;
15912                         }
15913                         listnotify_print(nvl, re_tag(*p));
15914                 }
15915         } else if (tset == MIXED_TOKENS) {
15916                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15917                 goto out;
15918         } else {
15919                 semerr(gettext("Invalid input.\n"));
15920         }
15921 
15922 out:
15923         nvlist_free(nvl);
15924         free(fmri);
15925         free(pgs);
15926         free(str);
15927 }
15928 
15929 static char *
15930 strip_quotes_and_blanks(char *s)
15931 {
15932         char *start = s;
15933         char *end = strrchr(s, '\"');
15934 
15935         if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15936                 start = s + 1;
15937                 while (isblank(*start))
15938                         start++;
15939                 while (isblank(*(end - 1)) && end > start) {
15940                         end--;
15941                 }
15942                 *end = '\0';
15943         }
15944 
15945         return (start);
15946 }
15947 
15948 static int
15949 set_active(nvlist_t *mech, const char *hier_part)
15950 {
15951         boolean_t b;
15952 
15953         if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15954                 b = B_TRUE;
15955         } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15956                 b = B_FALSE;
15957         } else {
15958                 return (-1);
15959         }
15960 
15961         if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15962                 uu_die(gettext("Out of memory.\n"));
15963 
15964         return (0);
15965 }
15966 
15967 static int
15968 add_snmp_params(nvlist_t *mech, char *hier_part)
15969 {
15970         return (set_active(mech, hier_part));
15971 }
15972 
15973 static int
15974 add_syslog_params(nvlist_t *mech, char *hier_part)
15975 {
15976         return (set_active(mech, hier_part));
15977 }
15978 
15979 /*
15980  * add_mailto_paramas()
15981  * parse the hier_part of mailto URI
15982  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15983  * or mailto:{[active]|inactive}
15984  */
15985 static int
15986 add_mailto_params(nvlist_t *mech, char *hier_part)
15987 {
15988         const char *tok = "?&";
15989         char *p;
15990         char *lasts;
15991         char *param;
15992         char *val;
15993 
15994         /*
15995          * If the notification parametes are in the form of
15996          *
15997          *   malito:{[active]|inactive}
15998          *
15999          * we set the property accordingly and return.
16000          * Otherwise, we make the notification type active and
16001          * process the hier_part.
16002          */
16003         if (set_active(mech, hier_part) == 0)
16004                 return (0);
16005         else if (set_active(mech, PARAM_ACTIVE) != 0)
16006                 return (-1);
16007 
16008         if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16009                 /*
16010                  * sanity check: we only get here if hier_part = "", but
16011                  * that's handled by set_active
16012                  */
16013                 uu_die("strtok_r");
16014         }
16015 
16016         if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16017                 uu_die(gettext("Out of memory.\n"));
16018 
16019         while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16020                 if ((param = strtok_r(p, "=", &val)) != NULL)
16021                         if (nvlist_add_string(mech, param, val) != 0)
16022                                 uu_die(gettext("Out of memory.\n"));
16023 
16024         return (0);
16025 }
16026 
16027 static int
16028 uri_split(char *uri, char **scheme, char **hier_part)
16029 {
16030         int r = -1;
16031 
16032         if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16033             *hier_part == NULL) {
16034                 semerr(gettext("'%s' is not an URI\n"), uri);
16035                 return (r);
16036         }
16037 
16038         if ((r = check_uri_scheme(*scheme)) < 0) {
16039                 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16040                 return (r);
16041         }
16042 
16043         return (r);
16044 }
16045 
16046 static int
16047 process_uri(nvlist_t *params, char *uri)
16048 {
16049         char *scheme;
16050         char *hier_part;
16051         nvlist_t *mech;
16052         int index;
16053         int r;
16054 
16055         if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16056                 return (-1);
16057 
16058         if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16059                 uu_die(gettext("Out of memory.\n"));
16060 
16061         switch (index) {
16062         case 0:
16063                 /* error messages displayed by called function */
16064                 r = add_mailto_params(mech, hier_part);
16065                 break;
16066 
16067         case 1:
16068                 if ((r = add_snmp_params(mech, hier_part)) != 0)
16069                         semerr(gettext("Not valid parameters: '%s'\n"),
16070                             hier_part);
16071                 break;
16072 
16073         case 2:
16074                 if ((r = add_syslog_params(mech, hier_part)) != 0)
16075                         semerr(gettext("Not valid parameters: '%s'\n"),
16076                             hier_part);
16077                 break;
16078 
16079         default:
16080                 r = -1;
16081         }
16082 
16083         if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16084             mech) != 0)
16085                 uu_die(gettext("Out of memory.\n"));
16086 
16087         nvlist_free(mech);
16088         return (r);
16089 }
16090 
16091 static int
16092 set_params(nvlist_t *params, char **p)
16093 {
16094         char *uri;
16095 
16096         if (p == NULL)
16097                 /* sanity check */
16098                 uu_die("set_params");
16099 
16100         while (*p) {
16101                 uri = strip_quotes_and_blanks(*p);
16102                 if (process_uri(params, uri) != 0)
16103                         return (-1);
16104 
16105                 ++p;
16106         }
16107 
16108         return (0);
16109 }
16110 
16111 static int
16112 setnotify(const char *e, char **p, int global)
16113 {
16114         char *str = safe_strdup(e);
16115         char **events;
16116         int32_t tset;
16117         int r = -1;
16118         nvlist_t *nvl, *params;
16119         char *fmri = NULL;
16120 
16121         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16122             nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16123             nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16124             SCF_NOTIFY_PARAMS_VERSION) != 0)
16125                 uu_die(gettext("Out of memory.\n"));
16126 
16127         events = tokenize(str, ",");
16128 
16129         if ((tset = check_tokens(events)) > 0) {
16130                 /* SMF state transitions parameters */
16131                 size_t sz = max_scf_fmri_len + 1;
16132 
16133                 fmri = safe_malloc(sz);
16134                 if (global) {
16135                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16136                 } else if (get_selection_str(fmri, sz) != 0) {
16137                         goto out;
16138                 }
16139 
16140                 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16141                     nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16142                         uu_die(gettext("Out of memory.\n"));
16143 
16144                 if ((r = set_params(params, p)) == 0) {
16145                         if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16146                             params) != 0)
16147                                 uu_die(gettext("Out of memory.\n"));
16148 
16149                         if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16150                             nvl) != SCF_SUCCESS) {
16151                                 r = -1;
16152                                 uu_warn(gettext(
16153                                     "Failed smf_notify_set_params(3SCF): %s\n"),
16154                                     scf_strerror(scf_error()));
16155                         }
16156                 }
16157         } else if (tset == FMA_TOKENS) {
16158                 /* FMA event parameters */
16159                 if (global) {
16160                         semerr(gettext("Can't use option '-g' with FMA event "
16161                             "definitions\n"));
16162                         goto out;
16163                 }
16164 
16165                 if ((r = set_params(params, p)) != 0)
16166                         goto out;
16167 
16168                 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16169                         uu_die(gettext("Out of memory.\n"));
16170 
16171                 while (*events) {
16172                         if (smf_notify_set_params(de_tag(*events), nvl) !=
16173                             SCF_SUCCESS)
16174                                 uu_warn(gettext(
16175                                     "Failed smf_notify_set_params(3SCF) for "
16176                                     "event %s: %s\n"), *events,
16177                                     scf_strerror(scf_error()));
16178                         events++;
16179                 }
16180         } else if (tset == MIXED_TOKENS) {
16181                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16182         } else {
16183                 /* Sanity check */
16184                 uu_die(gettext("Invalid input.\n"));
16185         }
16186 
16187 out:
16188         nvlist_free(nvl);
16189         nvlist_free(params);
16190         free(fmri);
16191         free(str);
16192 
16193         return (r);
16194 }
16195 
16196 int
16197 lscf_setnotify(uu_list_t *args)
16198 {
16199         int argc;
16200         char **argv = NULL;
16201         string_list_t *slp;
16202         int global;
16203         char *events;
16204         char **p;
16205         int i;
16206         int ret;
16207 
16208         if ((argc = uu_list_numnodes(args)) < 2)
16209                 goto usage;
16210 
16211         argv = calloc(argc + 1, sizeof (char *));
16212         if (argv == NULL)
16213                 uu_die(gettext("Out of memory.\n"));
16214 
16215         for (slp = uu_list_first(args), i = 0;
16216             slp != NULL;
16217             slp = uu_list_next(args, slp), ++i)
16218                 argv[i] = slp->str;
16219 
16220         argv[i] = NULL;
16221 
16222         if (strcmp(argv[0], "-g") == 0) {
16223                 global = 1;
16224                 events = argv[1];
16225                 p = argv + 2;
16226         } else {
16227                 global = 0;
16228                 events = argv[0];
16229                 p = argv + 1;
16230         }
16231 
16232         ret = setnotify(events, p, global);
16233 
16234 out:
16235         free(argv);
16236         return (ret);
16237 
16238 usage:
16239         ret = -2;
16240         goto out;
16241 }
16242 
16243 /*
16244  * Creates a list of instance name strings associated with a service. If
16245  * wohandcrafted flag is set, get only instances that have a last-import
16246  * snapshot, instances that were imported via svccfg.
16247  */
16248 static uu_list_t *
16249 create_instance_list(scf_service_t *svc, int wohandcrafted)
16250 {
16251         scf_snapshot_t  *snap = NULL;
16252         scf_instance_t  *inst;
16253         scf_iter_t      *inst_iter;
16254         uu_list_t       *instances;
16255         char            *instname;
16256         int             r;
16257 
16258         inst_iter = scf_iter_create(g_hndl);
16259         inst = scf_instance_create(g_hndl);
16260         if (inst_iter == NULL || inst == NULL) {
16261                 uu_warn(gettext("Could not create instance or iterator\n"));
16262                 scfdie();
16263         }
16264 
16265         if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16266                 return (instances);
16267 
16268         if (scf_iter_service_instances(inst_iter, svc) != 0) {
16269                 switch (scf_error()) {
16270                 case SCF_ERROR_CONNECTION_BROKEN:
16271                 case SCF_ERROR_DELETED:
16272                         uu_list_destroy(instances);
16273                         instances = NULL;
16274                         goto out;
16275 
16276                 case SCF_ERROR_HANDLE_MISMATCH:
16277                 case SCF_ERROR_NOT_BOUND:
16278                 case SCF_ERROR_NOT_SET:
16279                 default:
16280                         bad_error("scf_iter_service_instances", scf_error());
16281                 }
16282         }
16283 
16284         instname = safe_malloc(max_scf_name_len + 1);
16285         while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16286                 if (r == -1) {
16287                         (void) uu_warn(gettext("Unable to iterate through "
16288                             "instances to create instance list : %s\n"),
16289                             scf_strerror(scf_error()));
16290 
16291                         uu_list_destroy(instances);
16292                         instances = NULL;
16293                         goto out;
16294                 }
16295 
16296                 /*
16297                  * If the instance does not have a last-import snapshot
16298                  * then do not add it to the list as it is a hand-crafted
16299                  * instance that should not be managed.
16300                  */
16301                 if (wohandcrafted) {
16302                         if (snap == NULL &&
16303                             (snap = scf_snapshot_create(g_hndl)) == NULL) {
16304                                 uu_warn(gettext("Unable to create snapshot "
16305                                     "entity\n"));
16306                                 scfdie();
16307                         }
16308 
16309                         if (scf_instance_get_snapshot(inst,
16310                             snap_lastimport, snap) != 0) {
16311                                 switch (scf_error()) {
16312                                 case SCF_ERROR_NOT_FOUND :
16313                                 case SCF_ERROR_DELETED:
16314                                         continue;
16315 
16316                                 case SCF_ERROR_CONNECTION_BROKEN:
16317                                         uu_list_destroy(instances);
16318                                         instances = NULL;
16319                                         goto out;
16320 
16321                                 case SCF_ERROR_HANDLE_MISMATCH:
16322                                 case SCF_ERROR_NOT_BOUND:
16323                                 case SCF_ERROR_NOT_SET:
16324                                 default:
16325                                         bad_error("scf_iter_service_instances",
16326                                             scf_error());
16327                                 }
16328                         }
16329                 }
16330 
16331                 if (scf_instance_get_name(inst, instname,
16332                     max_scf_name_len + 1) < 0) {
16333                         switch (scf_error()) {
16334                         case SCF_ERROR_NOT_FOUND :
16335                                 continue;
16336 
16337                         case SCF_ERROR_CONNECTION_BROKEN:
16338                         case SCF_ERROR_DELETED:
16339                                 uu_list_destroy(instances);
16340                                 instances = NULL;
16341                                 goto out;
16342 
16343                         case SCF_ERROR_HANDLE_MISMATCH:
16344                         case SCF_ERROR_NOT_BOUND:
16345                         case SCF_ERROR_NOT_SET:
16346                         default:
16347                                 bad_error("scf_iter_service_instances",
16348                                     scf_error());
16349                         }
16350                 }
16351 
16352                 add_string(instances, instname);
16353         }
16354 
16355 out:
16356         if (snap)
16357                 scf_snapshot_destroy(snap);
16358 
16359         scf_instance_destroy(inst);
16360         scf_iter_destroy(inst_iter);
16361         free(instname);
16362         return (instances);
16363 }
16364 
16365 /*
16366  * disable an instance but wait for the instance to
16367  * move out of the running state.
16368  *
16369  * Returns 0 : if the instance did not disable
16370  * Returns non-zero : if the instance disabled.
16371  *
16372  */
16373 static int
16374 disable_instance(scf_instance_t *instance)
16375 {
16376         char    *fmribuf;
16377         int     enabled = 10000;
16378 
16379         if (inst_is_running(instance)) {
16380                 fmribuf = safe_malloc(max_scf_name_len + 1);
16381                 if (scf_instance_to_fmri(instance, fmribuf,
16382                     max_scf_name_len + 1) < 0) {
16383                         free(fmribuf);
16384                         return (0);
16385                 }
16386 
16387                 /*
16388                  * If the instance cannot be disabled then return
16389                  * failure to disable and let the caller decide
16390                  * if that is of importance.
16391                  */
16392                 if (smf_disable_instance(fmribuf, 0) != 0) {
16393                         free(fmribuf);
16394                         return (0);
16395                 }
16396 
16397                 while (enabled) {
16398                         if (!inst_is_running(instance))
16399                                 break;
16400 
16401                         (void) poll(NULL, 0, 5);
16402                         enabled = enabled - 5;
16403                 }
16404 
16405                 free(fmribuf);
16406         }
16407 
16408         return (enabled);
16409 }
16410 
16411 /*
16412  * Function to compare two service_manifest structures.
16413  */
16414 /* ARGSUSED2 */
16415 static int
16416 service_manifest_compare(const void *left, const void *right, void *unused)
16417 {
16418         service_manifest_t *l = (service_manifest_t *)left;
16419         service_manifest_t *r = (service_manifest_t *)right;
16420         int rc;
16421 
16422         rc = strcmp(l->servicename, r->servicename);
16423 
16424         return (rc);
16425 }
16426 
16427 /*
16428  * Look for the provided service in the service to manifest
16429  * tree.  If the service exists, and a manifest was provided
16430  * then add the manifest to that service.  If the service
16431  * does not exist, then add the service and manifest to the
16432  * list.
16433  *
16434  * If the manifest is NULL, return the element if found.  If
16435  * the service is not found return NULL.
16436  */
16437 service_manifest_t *
16438 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16439 {
16440         service_manifest_t      elem;
16441         service_manifest_t      *fnelem;
16442         uu_avl_index_t          marker;
16443 
16444         elem.servicename = svnbuf;
16445         fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16446 
16447         if (mfst) {
16448                 if (fnelem) {
16449                         add_string(fnelem->mfstlist, strdup(mfst));
16450                 } else {
16451                         fnelem = safe_malloc(sizeof (*fnelem));
16452                         fnelem->servicename = safe_strdup(svnbuf);
16453                         if ((fnelem->mfstlist =
16454                             uu_list_create(string_pool, NULL, 0)) == NULL)
16455                                 uu_die(gettext("Could not create property "
16456                                     "list: %s\n"), uu_strerror(uu_error()));
16457 
16458                         add_string(fnelem->mfstlist, safe_strdup(mfst));
16459 
16460                         uu_avl_insert(service_manifest_tree, fnelem, marker);
16461                 }
16462         }
16463 
16464         return (fnelem);
16465 }
16466 
16467 /*
16468  * Create the service to manifest avl tree.
16469  *
16470  * Walk each of the manifests currently installed in the supported
16471  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16472  * each of the manifests, inventory the services and add them to
16473  * the tree.
16474  *
16475  * Code that calls this function should make sure fileystem/minimal is online,
16476  * /var is available, since this function walks the /var/svc/manifest directory.
16477  */
16478 static void
16479 create_manifest_tree(void)
16480 {
16481         manifest_info_t **entry;
16482         manifest_info_t **manifests;
16483         uu_list_walk_t  *svcs;
16484         bundle_t        *b;
16485         entity_t        *mfsvc;
16486         char            *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16487         int             c, status;
16488 
16489         if (service_manifest_pool)
16490                 return;
16491 
16492         /*
16493          * Create the list pool for the service manifest list
16494          */
16495         service_manifest_pool = uu_avl_pool_create("service_manifest",
16496             sizeof (service_manifest_t),
16497             offsetof(service_manifest_t, svcmfst_node),
16498             service_manifest_compare, UU_DEFAULT);
16499         if (service_manifest_pool == NULL)
16500                 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16501                     uu_strerror(uu_error()));
16502 
16503         /*
16504          * Create the list
16505          */
16506         service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16507             UU_DEFAULT);
16508         if (service_manifest_tree == NULL)
16509                 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16510                     uu_strerror(uu_error()));
16511 
16512         /*
16513          * Walk the manifests adding the service(s) from each manifest.
16514          *
16515          * If a service already exists add the manifest to the manifest
16516          * list for that service.  This covers the case of a service that
16517          * is supported by multiple manifest files.
16518          */
16519         for (c = 0; dirs[c]; c++) {
16520                 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16521                 if (status < 0) {
16522                         uu_warn(gettext("file tree walk of %s encountered "
16523                             "error %s\n"), dirs[c], strerror(errno));
16524 
16525                         uu_avl_destroy(service_manifest_tree);
16526                         service_manifest_tree = NULL;
16527                         return;
16528                 }
16529 
16530                 /*
16531                  * If a manifest that was in the list is not found
16532                  * then skip and go to the next manifest file.
16533                  */
16534                 if (manifests != NULL) {
16535                         for (entry = manifests; *entry != NULL; entry++) {
16536                                 b = internal_bundle_new();
16537                                 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16538                                     SVCCFG_OP_IMPORT) != 0) {
16539                                         internal_bundle_free(b);
16540                                         continue;
16541                                 }
16542 
16543                                 svcs = uu_list_walk_start(b->sc_bundle_services,
16544                                     0);
16545                                 if (svcs == NULL) {
16546                                         internal_bundle_free(b);
16547                                         continue;
16548                                 }
16549 
16550                                 while ((mfsvc = uu_list_walk_next(svcs)) !=
16551                                     NULL) {
16552                                         /* Add manifest to service */
16553                                         (void) find_add_svc_mfst(mfsvc->sc_name,
16554                                             (*entry)->mi_path);
16555                                 }
16556 
16557                                 uu_list_walk_end(svcs);
16558                                 internal_bundle_free(b);
16559                         }
16560 
16561                         free_manifest_array(manifests);
16562                 }
16563         }
16564 }
16565 
16566 /*
16567  * Check the manifest history file to see
16568  * if the service was ever installed from
16569  * one of the supported directories.
16570  *
16571  * Return Values :
16572  *      -1 - if there's error reading manifest history file
16573  *       1 - if the service is not found
16574  *       0 - if the service is found
16575  */
16576 static int
16577 check_mfst_history(const char *svcname)
16578 {
16579         struct stat     st;
16580         caddr_t         mfsthist_start;
16581         char            *svnbuf;
16582         int             fd;
16583         int             r = 1;
16584 
16585         fd = open(MFSTHISTFILE, O_RDONLY);
16586         if (fd == -1) {
16587                 uu_warn(gettext("Unable to open the history file\n"));
16588                 return (-1);
16589         }
16590 
16591         if (fstat(fd, &st) == -1) {
16592                 uu_warn(gettext("Unable to stat the history file\n"));
16593                 return (-1);
16594         }
16595 
16596         mfsthist_start = mmap(0, st.st_size, PROT_READ,
16597             MAP_PRIVATE, fd, 0);
16598 
16599         (void) close(fd);
16600         if (mfsthist_start == MAP_FAILED ||
16601             *(mfsthist_start + st.st_size) != '\0') {
16602                 (void) munmap(mfsthist_start, st.st_size);
16603                 return (-1);
16604         }
16605 
16606         /*
16607          * The manifest history file is a space delimited list
16608          * of service and instance to manifest linkage.  Adding
16609          * a space to the end of the service name so to get only
16610          * the service that is being searched for.
16611          */
16612         svnbuf = uu_msprintf("%s ", svcname);
16613         if (svnbuf == NULL)
16614                 uu_die(gettext("Out of memory"));
16615 
16616         if (strstr(mfsthist_start, svnbuf) != NULL)
16617                 r = 0;
16618 
16619         (void) munmap(mfsthist_start, st.st_size);
16620         uu_free(svnbuf);
16621         return (r);
16622 }
16623 
16624 /*
16625  * Take down each of the instances in the service
16626  * and remove them, then delete the service.
16627  */
16628 static void
16629 teardown_service(scf_service_t *svc, const char *svnbuf)
16630 {
16631         scf_instance_t  *instance;
16632         scf_iter_t      *iter;
16633         int             r;
16634 
16635         safe_printf(gettext("Delete service %s as there are no "
16636             "supporting manifests\n"), svnbuf);
16637 
16638         instance = scf_instance_create(g_hndl);
16639         iter = scf_iter_create(g_hndl);
16640         if (iter == NULL || instance == NULL) {
16641                 uu_warn(gettext("Unable to create supporting entities to "
16642                     "teardown the service\n"));
16643                 uu_warn(gettext("scf error is : %s\n"),
16644                     scf_strerror(scf_error()));
16645                 scfdie();
16646         }
16647 
16648         if (scf_iter_service_instances(iter, svc) != 0) {
16649                 switch (scf_error()) {
16650                 case SCF_ERROR_CONNECTION_BROKEN:
16651                 case SCF_ERROR_DELETED:
16652                         goto out;
16653 
16654                 case SCF_ERROR_HANDLE_MISMATCH:
16655                 case SCF_ERROR_NOT_BOUND:
16656                 case SCF_ERROR_NOT_SET:
16657                 default:
16658                         bad_error("scf_iter_service_instances",
16659                             scf_error());
16660                 }
16661         }
16662 
16663         while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16664                 if (r == -1) {
16665                         uu_warn(gettext("Error - %s\n"),
16666                             scf_strerror(scf_error()));
16667                         goto out;
16668                 }
16669 
16670                 (void) disable_instance(instance);
16671         }
16672 
16673         /*
16674          * Delete the service... forcing the deletion in case
16675          * any of the instances did not disable.
16676          */
16677         (void) lscf_service_delete(svc, 1);
16678 out:
16679         scf_instance_destroy(instance);
16680         scf_iter_destroy(iter);
16681 }
16682 
16683 /*
16684  * Get the list of instances supported by the manifest
16685  * file.
16686  *
16687  * Return 0 if there are no instances.
16688  *
16689  * Return -1 if there are errors attempting to collect instances.
16690  *
16691  * Return the count of instances found if there are no errors.
16692  *
16693  */
16694 static int
16695 check_instance_support(char *mfstfile, const char *svcname,
16696     uu_list_t *instances)
16697 {
16698         uu_list_walk_t  *svcs, *insts;
16699         uu_list_t       *ilist;
16700         bundle_t        *b;
16701         entity_t        *mfsvc, *mfinst;
16702         const char      *svcn;
16703         int             rminstcnt = 0;
16704 
16705 
16706         b = internal_bundle_new();
16707 
16708         if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16709                 /*
16710                  * Unable to process the manifest file for
16711                  * instance support, so just return as
16712                  * don't want to remove instances that could
16713                  * not be accounted for that might exist here.
16714                  */
16715                 internal_bundle_free(b);
16716                 return (0);
16717         }
16718 
16719         svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16720         if (svcs == NULL) {
16721                 internal_bundle_free(b);
16722                 return (0);
16723         }
16724 
16725         svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16726             (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16727 
16728         while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16729                 if (strcmp(mfsvc->sc_name, svcn) == 0)
16730                         break;
16731         }
16732         uu_list_walk_end(svcs);
16733 
16734         if (mfsvc == NULL) {
16735                 internal_bundle_free(b);
16736                 return (-1);
16737         }
16738 
16739         ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16740         if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16741                 internal_bundle_free(b);
16742                 return (0);
16743         }
16744 
16745         while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16746                 /*
16747                  * Remove the instance from the instances list.
16748                  * The unaccounted for instances will be removed
16749                  * from the service once all manifests are
16750                  * processed.
16751                  */
16752                 (void) remove_string(instances,
16753                     mfinst->sc_name);
16754                 rminstcnt++;
16755         }
16756 
16757         uu_list_walk_end(insts);
16758         internal_bundle_free(b);
16759 
16760         return (rminstcnt);
16761 }
16762 
16763 /*
16764  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16765  * 'false' to indicate there's no manifest file(s) found for the service.
16766  */
16767 static void
16768 svc_add_no_support(scf_service_t *svc)
16769 {
16770         char    *pname;
16771 
16772         /* Add no support */
16773         cur_svc = svc;
16774         if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16775                 return;
16776 
16777         pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16778         if (pname == NULL)
16779                 uu_die(gettext("Out of memory.\n"));
16780 
16781         (void) lscf_addpropvalue(pname, "boolean:", "0");
16782 
16783         uu_free(pname);
16784         cur_svc = NULL;
16785 }
16786 
16787 /*
16788  * This function handles all upgrade scenarios for a service that doesn't have
16789  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16790  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16791  * manifest(s) mapping. Manifests under supported directories are inventoried
16792  * and a property is added for each file that delivers configuration to the
16793  * service.  A service that has no corresponding manifest files (deleted) are
16794  * removed from repository.
16795  *
16796  * Unsupported services:
16797  *
16798  * A service is considered unsupported if there is no corresponding manifest
16799  * in the supported directories for that service and the service isn't in the
16800  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16801  * services and instances that were delivered by Solaris before the introduction
16802  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16803  * the path to the manifest file that defined the service or instance.
16804  *
16805  * Another type of unsupported services is 'handcrafted' services,
16806  * programmatically created services or services created by dependent entries
16807  * in other manifests. A handcrafted service is identified by its lack of any
16808  * instance containing last-import snapshot which is created during svccfg
16809  * import.
16810  *
16811  * This function sets a flag for unsupported services by setting services'
16812  * SCF_PG_MANIFESTFILES/support property to false.
16813  */
16814 static void
16815 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16816 {
16817         service_manifest_t      *elem;
16818         uu_list_walk_t          *mfwalk;
16819         string_list_t           *mfile;
16820         uu_list_t               *instances;
16821         const char              *sname;
16822         char                    *pname;
16823         int                     r;
16824 
16825         /*
16826          * Since there's no guarantee manifests under /var are available during
16827          * early import, don't perform any upgrade during early import.
16828          */
16829         if (IGNORE_VAR)
16830                 return;
16831 
16832         if (service_manifest_tree == NULL) {
16833                 create_manifest_tree();
16834         }
16835 
16836         /*
16837          * Find service's supporting manifest(s) after
16838          * stripping off the svc:/ prefix that is part
16839          * of the fmri that is not used in the service
16840          * manifest bundle list.
16841          */
16842         sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16843             strlen(SCF_FMRI_SERVICE_PREFIX);
16844         elem = find_add_svc_mfst(sname, NULL);
16845         if (elem == NULL) {
16846 
16847                 /*
16848                  * A handcrafted service, one that has no instance containing
16849                  * last-import snapshot, should get unsupported flag.
16850                  */
16851                 instances = create_instance_list(svc, 1);
16852                 if (instances == NULL) {
16853                         uu_warn(gettext("Unable to create instance list %s\n"),
16854                             svcname);
16855                         return;
16856                 }
16857 
16858                 if (uu_list_numnodes(instances) == 0) {
16859                         svc_add_no_support(svc);
16860                         return;
16861                 }
16862 
16863                 /*
16864                  * If the service is in the history file, and its supporting
16865                  * manifests are not found, we can safely delete the service
16866                  * because its manifests are removed from the system.
16867                  *
16868                  * Services not found in the history file are not delivered by
16869                  * Solaris and/or delivered outside supported directories, set
16870                  * unsupported flag for these services.
16871                  */
16872                 r = check_mfst_history(svcname);
16873                 if (r == -1)
16874                         return;
16875 
16876                 if (r) {
16877                         /* Set unsupported flag for service  */
16878                         svc_add_no_support(svc);
16879                 } else {
16880                         /* Delete the service */
16881                         teardown_service(svc, svcname);
16882                 }
16883 
16884                 return;
16885         }
16886 
16887         /*
16888          * Walk through the list of manifests and add them
16889          * to the service.
16890          *
16891          * Create a manifestfiles pg and add the property.
16892          */
16893         mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16894         if (mfwalk == NULL)
16895                 return;
16896 
16897         cur_svc = svc;
16898         r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16899         if (r != 0) {
16900                 cur_svc = NULL;
16901                 return;
16902         }
16903 
16904         while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16905                 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16906                     mhash_filename_to_propname(mfile->str, 0));
16907                 if (pname == NULL)
16908                         uu_die(gettext("Out of memory.\n"));
16909 
16910                 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16911                 uu_free(pname);
16912         }
16913         uu_list_walk_end(mfwalk);
16914 
16915         cur_svc = NULL;
16916 }
16917 
16918 /*
16919  * Take a service and process the manifest file entires to see if
16920  * there is continued support for the service and instances.  If
16921  * not cleanup as appropriate.
16922  *
16923  * If a service does not have a manifest files entry flag it for
16924  * upgrade and return.
16925  *
16926  * For each manifestfiles property check if the manifest file is
16927  * under the supported /lib/svc/manifest or /var/svc/manifest path
16928  * and if not then return immediately as this service is not supported
16929  * by the cleanup mechanism and should be ignored.
16930  *
16931  * For each manifest file that is supported, check to see if the
16932  * file exists.  If not then remove the manifest file property
16933  * from the service and the smf/manifest hash table.  If the manifest
16934  * file exists then verify that it supports the instances that are
16935  * part of the service.
16936  *
16937  * Once all manifest files have been accounted for remove any instances
16938  * that are no longer supported in the service.
16939  *
16940  * Return values :
16941  * 0 - Successfully processed the service
16942  * non-zero - failed to process the service
16943  *
16944  * On most errors, will just return to wait and get the next service,
16945  * unless in case of unable to create the needed structures which is
16946  * most likely a fatal error that is not going to be recoverable.
16947  */
16948 int
16949 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16950 {
16951         struct mpg_mfile        *mpntov = NULL;
16952         struct mpg_mfile        **mpvarry = NULL;
16953         scf_service_t           *svc;
16954         scf_propertygroup_t     *mpg;
16955         scf_property_t          *mp;
16956         scf_value_t             *mv;
16957         scf_iter_t              *mi;
16958         scf_instance_t          *instance;
16959         uu_list_walk_t          *insts;
16960         uu_list_t               *instances = NULL;
16961         boolean_t               activity = (boolean_t)act;
16962         char                    *mpnbuf = NULL;
16963         char                    *mpvbuf = NULL;
16964         char                    *pgpropbuf;
16965         int                     mfstcnt, rminstct, instct, mfstmax;
16966         int                     index;
16967         int                     r = 0;
16968 
16969         assert(g_hndl != NULL);
16970         assert(wip->svc != NULL);
16971         assert(wip->fmri != NULL);
16972 
16973         svc = wip->svc;
16974 
16975         mpg = scf_pg_create(g_hndl);
16976         mp = scf_property_create(g_hndl);
16977         mi = scf_iter_create(g_hndl);
16978         mv = scf_value_create(g_hndl);
16979         instance = scf_instance_create(g_hndl);
16980 
16981         if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16982             instance == NULL) {
16983                 uu_warn(gettext("Unable to create the supporting entities\n"));
16984                 uu_warn(gettext("scf error is : %s\n"),
16985                     scf_strerror(scf_error()));
16986                 scfdie();
16987         }
16988 
16989         /*
16990          * Get the manifestfiles property group to be parsed for
16991          * files existence.
16992          */
16993         if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16994                 switch (scf_error()) {
16995                 case SCF_ERROR_NOT_FOUND:
16996                         upgrade_svc_mfst_connection(svc, wip->fmri);
16997                         break;
16998                 case SCF_ERROR_DELETED:
16999                 case SCF_ERROR_CONNECTION_BROKEN:
17000                         goto out;
17001 
17002                 case SCF_ERROR_HANDLE_MISMATCH:
17003                 case SCF_ERROR_NOT_BOUND:
17004                 case SCF_ERROR_NOT_SET:
17005                 default:
17006                         bad_error("scf_iter_pg_properties",
17007                             scf_error());
17008                 }
17009 
17010                 goto out;
17011         }
17012 
17013         /*
17014          * Iterate through each of the manifestfiles properties
17015          * to determine what manifestfiles are available.
17016          *
17017          * If a manifest file is supported then increment the
17018          * count and therefore the service is safe.
17019          */
17020         if (scf_iter_pg_properties(mi, mpg) != 0) {
17021                 switch (scf_error()) {
17022                 case SCF_ERROR_DELETED:
17023                 case SCF_ERROR_CONNECTION_BROKEN:
17024                         goto out;
17025 
17026                 case SCF_ERROR_HANDLE_MISMATCH:
17027                 case SCF_ERROR_NOT_BOUND:
17028                 case SCF_ERROR_NOT_SET:
17029                 default:
17030                         bad_error("scf_iter_pg_properties",
17031                             scf_error());
17032                 }
17033         }
17034 
17035         mfstcnt = 0;
17036         mfstmax = MFSTFILE_MAX;
17037         mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17038         while ((r = scf_iter_next_property(mi, mp)) != 0) {
17039                 if (r == -1)
17040                         bad_error(gettext("Unable to iterate through "
17041                             "manifestfiles properties : %s"),
17042                             scf_error());
17043 
17044                 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17045                 mpnbuf = safe_malloc(max_scf_name_len + 1);
17046                 mpvbuf = safe_malloc(max_scf_value_len + 1);
17047                 mpntov->mpg = mpnbuf;
17048                 mpntov->mfile = mpvbuf;
17049                 mpntov->access = 1;
17050                 if (scf_property_get_name(mp, mpnbuf,
17051                     max_scf_name_len + 1) < 0) {
17052                         uu_warn(gettext("Unable to get manifest file "
17053                             "property : %s\n"),
17054                             scf_strerror(scf_error()));
17055 
17056                         switch (scf_error()) {
17057                         case SCF_ERROR_DELETED:
17058                         case SCF_ERROR_CONNECTION_BROKEN:
17059                                 r = scferror2errno(scf_error());
17060                                 goto out_free;
17061 
17062                         case SCF_ERROR_HANDLE_MISMATCH:
17063                         case SCF_ERROR_NOT_BOUND:
17064                         case SCF_ERROR_NOT_SET:
17065                         default:
17066                                 bad_error("scf_iter_pg_properties",
17067                                     scf_error());
17068                         }
17069                 }
17070 
17071                 /*
17072                  * The support property is a boolean value that indicates
17073                  * if the service is supported for manifest file deletion.
17074                  * Currently at this time there is no code that sets this
17075                  * value to true.  So while we could just let this be caught
17076                  * by the support check below, in the future this by be set
17077                  * to true and require processing.  So for that, go ahead
17078                  * and check here, and just return if false.  Otherwise,
17079                  * fall through expecting that other support checks will
17080                  * handle the entries.
17081                  */
17082                 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17083                         uint8_t support;
17084 
17085                         if (scf_property_get_value(mp, mv) != 0 ||
17086                             scf_value_get_boolean(mv, &support) != 0) {
17087                                 uu_warn(gettext("Unable to get the manifest "
17088                                     "support value: %s\n"),
17089                                     scf_strerror(scf_error()));
17090 
17091                                 switch (scf_error()) {
17092                                 case SCF_ERROR_DELETED:
17093                                 case SCF_ERROR_CONNECTION_BROKEN:
17094                                         r = scferror2errno(scf_error());
17095                                         goto out_free;
17096 
17097                                 case SCF_ERROR_HANDLE_MISMATCH:
17098                                 case SCF_ERROR_NOT_BOUND:
17099                                 case SCF_ERROR_NOT_SET:
17100                                 default:
17101                                         bad_error("scf_iter_pg_properties",
17102                                             scf_error());
17103                                 }
17104                         }
17105 
17106                         if (support == B_FALSE)
17107                                 goto out_free;
17108                 }
17109 
17110                 /*
17111                  * Anything with a manifest outside of the supported
17112                  * directories, immediately bail out because that makes
17113                  * this service non-supported.  We don't even want
17114                  * to do instance processing in this case because the
17115                  * instances could be part of the non-supported manifest.
17116                  */
17117                 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17118                         /*
17119                          * Manifest is not in /lib/svc, so we need to
17120                          * consider the /var/svc case.
17121                          */
17122                         if (strncmp(mpnbuf, VARSVC_PR,
17123                             strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17124                                 /*
17125                                  * Either the manifest is not in /var/svc or
17126                                  * /var is not yet mounted.  We ignore the
17127                                  * manifest either because it is not in a
17128                                  * standard location or because we cannot
17129                                  * currently access the manifest.
17130                                  */
17131                                 goto out_free;
17132                         }
17133                 }
17134 
17135                 /*
17136                  * Get the value to of the manifest file for this entry
17137                  * for access verification and instance support
17138                  * verification if it still exists.
17139                  *
17140                  * During Early Manifest Import if the manifest is in
17141                  * /var/svc then it may not yet be available for checking
17142                  * so we must determine if /var/svc is available.  If not
17143                  * then defer until Late Manifest Import to cleanup.
17144                  */
17145                 if (scf_property_get_value(mp, mv) != 0) {
17146                         uu_warn(gettext("Unable to get the manifest file "
17147                             "value: %s\n"),
17148                             scf_strerror(scf_error()));
17149 
17150                         switch (scf_error()) {
17151                         case SCF_ERROR_DELETED:
17152                         case SCF_ERROR_CONNECTION_BROKEN:
17153                                 r = scferror2errno(scf_error());
17154                                 goto out_free;
17155 
17156                         case SCF_ERROR_HANDLE_MISMATCH:
17157                         case SCF_ERROR_NOT_BOUND:
17158                         case SCF_ERROR_NOT_SET:
17159                         default:
17160                                 bad_error("scf_property_get_value",
17161                                     scf_error());
17162                         }
17163                 }
17164 
17165                 if (scf_value_get_astring(mv, mpvbuf,
17166                     max_scf_value_len + 1) < 0) {
17167                         uu_warn(gettext("Unable to get the manifest "
17168                             "file : %s\n"),
17169                             scf_strerror(scf_error()));
17170 
17171                         switch (scf_error()) {
17172                         case SCF_ERROR_DELETED:
17173                         case SCF_ERROR_CONNECTION_BROKEN:
17174                                 r = scferror2errno(scf_error());
17175                                 goto out_free;
17176 
17177                         case SCF_ERROR_HANDLE_MISMATCH:
17178                         case SCF_ERROR_NOT_BOUND:
17179                         case SCF_ERROR_NOT_SET:
17180                         default:
17181                                 bad_error("scf_value_get_astring",
17182                                     scf_error());
17183                         }
17184                 }
17185 
17186                 mpvarry[mfstcnt] = mpntov;
17187                 mfstcnt++;
17188 
17189                 /*
17190                  * Check for the need to reallocate array
17191                  */
17192                 if (mfstcnt >= (mfstmax - 1)) {
17193                         struct mpg_mfile **newmpvarry;
17194 
17195                         mfstmax = mfstmax * 2;
17196                         newmpvarry = realloc(mpvarry,
17197                             sizeof (struct mpg_mfile *) * mfstmax);
17198 
17199                         if (newmpvarry == NULL)
17200                                 goto out_free;
17201 
17202                         mpvarry = newmpvarry;
17203                 }
17204 
17205                 mpvarry[mfstcnt] = NULL;
17206         }
17207 
17208         for (index = 0; mpvarry[index]; index++) {
17209                 mpntov = mpvarry[index];
17210 
17211                 /*
17212                  * Check to see if the manifestfile is accessable, if so hand
17213                  * this service and manifestfile off to be processed for
17214                  * instance support.
17215                  */
17216                 mpnbuf = mpntov->mpg;
17217                 mpvbuf = mpntov->mfile;
17218                 if (access(mpvbuf, F_OK) != 0) {
17219                         mpntov->access = 0;
17220                         activity++;
17221                         mfstcnt--;
17222                         /* Remove the entry from the service */
17223                         cur_svc = svc;
17224                         pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17225                             mpnbuf);
17226                         if (pgpropbuf == NULL)
17227                                 uu_die(gettext("Out of memory.\n"));
17228 
17229                         lscf_delprop(pgpropbuf);
17230                         cur_svc = NULL;
17231 
17232                         uu_free(pgpropbuf);
17233                 }
17234         }
17235 
17236         /*
17237          * If mfstcnt is 0, none of the manifests that supported the service
17238          * existed so remove the service.
17239          */
17240         if (mfstcnt == 0) {
17241                 teardown_service(svc, wip->fmri);
17242 
17243                 goto out_free;
17244         }
17245 
17246         if (activity) {
17247                 int     nosvcsupport = 0;
17248 
17249                 /*
17250                  * If the list of service instances is NULL then
17251                  * create the list.
17252                  */
17253                 instances = create_instance_list(svc, 1);
17254                 if (instances == NULL) {
17255                         uu_warn(gettext("Unable to create instance list %s\n"),
17256                             wip->fmri);
17257                         goto out_free;
17258                 }
17259 
17260                 rminstct = uu_list_numnodes(instances);
17261                 instct = rminstct;
17262 
17263                 for (index = 0; mpvarry[index]; index++) {
17264                         mpntov = mpvarry[index];
17265                         if (mpntov->access == 0)
17266                                 continue;
17267 
17268                         mpnbuf = mpntov->mpg;
17269                         mpvbuf = mpntov->mfile;
17270                         r = check_instance_support(mpvbuf, wip->fmri,
17271                             instances);
17272                         if (r == -1) {
17273                                 nosvcsupport++;
17274                         } else {
17275                                 rminstct -= r;
17276                         }
17277                 }
17278 
17279                 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17280                         teardown_service(svc, wip->fmri);
17281 
17282                         goto out_free;
17283                 }
17284         }
17285 
17286         /*
17287          * If there are instances left on the instance list, then
17288          * we must remove them.
17289          */
17290         if (instances != NULL && uu_list_numnodes(instances)) {
17291                 string_list_t *sp;
17292 
17293                 insts = uu_list_walk_start(instances, 0);
17294                 while ((sp = uu_list_walk_next(insts)) != NULL) {
17295                         /*
17296                          * Remove the instance from the instances list.
17297                          */
17298                         safe_printf(gettext("Delete instance %s from "
17299                             "service %s\n"), sp->str, wip->fmri);
17300                         if (scf_service_get_instance(svc, sp->str,
17301                             instance) != SCF_SUCCESS) {
17302                                 (void) uu_warn("scf_error - %s\n",
17303                                     scf_strerror(scf_error()));
17304 
17305                                 continue;
17306                         }
17307 
17308                         (void) disable_instance(instance);
17309 
17310                         (void) lscf_instance_delete(instance, 1);
17311                 }
17312                 scf_instance_destroy(instance);
17313                 uu_list_walk_end(insts);
17314         }
17315 
17316 out_free:
17317         if (mpvarry) {
17318                 struct mpg_mfile *fmpntov;
17319 
17320                 for (index = 0; mpvarry[index]; index++) {
17321                         fmpntov  = mpvarry[index];
17322                         if (fmpntov->mpg == mpnbuf)
17323                                 mpnbuf = NULL;
17324                         free(fmpntov->mpg);
17325 
17326                         if (fmpntov->mfile == mpvbuf)
17327                                 mpvbuf = NULL;
17328                         free(fmpntov->mfile);
17329 
17330                         if (fmpntov == mpntov)
17331                                 mpntov = NULL;
17332                         free(fmpntov);
17333                 }
17334                 if (mpnbuf)
17335                         free(mpnbuf);
17336                 if (mpvbuf)
17337                         free(mpvbuf);
17338                 if (mpntov)
17339                         free(mpntov);
17340 
17341                 free(mpvarry);
17342         }
17343 out:
17344         scf_pg_destroy(mpg);
17345         scf_property_destroy(mp);
17346         scf_iter_destroy(mi);
17347         scf_value_destroy(mv);
17348 
17349         return (0);
17350 }
17351 
17352 /*
17353  * Take the service and search for the manifestfiles property
17354  * in each of the property groups.  If the manifest file
17355  * associated with the property does not exist then remove
17356  * the property group.
17357  */
17358 int
17359 lscf_hash_cleanup()
17360 {
17361         scf_service_t           *svc;
17362         scf_scope_t             *scope;
17363         scf_propertygroup_t     *pg;
17364         scf_property_t          *prop;
17365         scf_value_t             *val;
17366         scf_iter_t              *iter;
17367         char                    *pgname = NULL;
17368         char                    *mfile = NULL;
17369         int                     r;
17370 
17371         svc = scf_service_create(g_hndl);
17372         scope = scf_scope_create(g_hndl);
17373         pg = scf_pg_create(g_hndl);
17374         prop = scf_property_create(g_hndl);
17375         val = scf_value_create(g_hndl);
17376         iter = scf_iter_create(g_hndl);
17377         if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17378             svc == NULL || scope == NULL) {
17379                 uu_warn(gettext("Unable to create a property group, or "
17380                     "property\n"));
17381                 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17382                     "pg is not NULL");
17383                 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17384                     "prop is not NULL");
17385                 uu_warn("%s\n", val == NULL ? "val is NULL" :
17386                     "val is not NULL");
17387                 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17388                     "iter is not NULL");
17389                 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17390                     "svc is not NULL");
17391                 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17392                     "scope is not NULL");
17393                 uu_warn(gettext("scf error is : %s\n"),
17394                     scf_strerror(scf_error()));
17395                 scfdie();
17396         }
17397 
17398         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17399                 switch (scf_error()) {
17400                 case SCF_ERROR_CONNECTION_BROKEN:
17401                 case SCF_ERROR_NOT_FOUND:
17402                         goto out;
17403 
17404                 case SCF_ERROR_HANDLE_MISMATCH:
17405                 case SCF_ERROR_NOT_BOUND:
17406                 case SCF_ERROR_INVALID_ARGUMENT:
17407                 default:
17408                         bad_error("scf_handle_get_scope", scf_error());
17409                 }
17410         }
17411 
17412         if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17413                 uu_warn(gettext("Unable to process the hash service, %s\n"),
17414                     HASH_SVC);
17415                 goto out;
17416         }
17417 
17418         pgname = safe_malloc(max_scf_name_len + 1);
17419         mfile = safe_malloc(max_scf_value_len + 1);
17420 
17421         if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17422                 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17423                     scf_strerror(scf_error()));
17424                 goto out;
17425         }
17426 
17427         while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17428                 if (r == -1)
17429                         goto out;
17430 
17431                 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17432                         switch (scf_error()) {
17433                         case SCF_ERROR_DELETED:
17434                                 return (ENODEV);
17435 
17436                         case SCF_ERROR_CONNECTION_BROKEN:
17437                                 return (ECONNABORTED);
17438 
17439                         case SCF_ERROR_NOT_SET:
17440                         case SCF_ERROR_NOT_BOUND:
17441                         default:
17442                                 bad_error("scf_pg_get_name", scf_error());
17443                         }
17444                 }
17445                 if (IGNORE_VAR) {
17446                         if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17447                                 continue;
17448                 }
17449 
17450                 /*
17451                  * If unable to get the property continue as this is an
17452                  * entry that has no location to check against.
17453                  */
17454                 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17455                         continue;
17456                 }
17457 
17458                 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17459                         uu_warn(gettext("Unable to get value from %s\n"),
17460                             pgname);
17461 
17462                         switch (scf_error()) {
17463                         case SCF_ERROR_DELETED:
17464                         case SCF_ERROR_CONSTRAINT_VIOLATED:
17465                         case SCF_ERROR_NOT_FOUND:
17466                         case SCF_ERROR_NOT_SET:
17467                                 continue;
17468 
17469                         case SCF_ERROR_CONNECTION_BROKEN:
17470                                 r = scferror2errno(scf_error());
17471                                 goto out;
17472 
17473                         case SCF_ERROR_HANDLE_MISMATCH:
17474                         case SCF_ERROR_NOT_BOUND:
17475                         default:
17476                                 bad_error("scf_property_get_value",
17477                                     scf_error());
17478                         }
17479                 }
17480 
17481                 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17482                     == -1) {
17483                         uu_warn(gettext("Unable to get astring from %s : %s\n"),
17484                             pgname, scf_strerror(scf_error()));
17485 
17486                         switch (scf_error()) {
17487                         case SCF_ERROR_NOT_SET:
17488                         case SCF_ERROR_TYPE_MISMATCH:
17489                                 continue;
17490 
17491                         default:
17492                                 bad_error("scf_value_get_astring", scf_error());
17493                         }
17494                 }
17495 
17496                 if (access(mfile, F_OK) == 0)
17497                         continue;
17498 
17499                 (void) scf_pg_delete(pg);
17500         }
17501 
17502 out:
17503         scf_scope_destroy(scope);
17504         scf_service_destroy(svc);
17505         scf_pg_destroy(pg);
17506         scf_property_destroy(prop);
17507         scf_value_destroy(val);
17508         scf_iter_destroy(iter);
17509         free(pgname);
17510         free(mfile);
17511 
17512         return (0);
17513 }
17514 
17515 #ifndef NATIVE_BUILD
17516 /* ARGSUSED */
17517 CPL_MATCH_FN(complete_select)
17518 {
17519         const char *arg0, *arg1, *arg1end;
17520         int word_start, err = 0, r;
17521         size_t len;
17522         char *buf;
17523 
17524         lscf_prep_hndl();
17525 
17526         arg0 = line + strspn(line, " \t");
17527         assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17528 
17529         arg1 = arg0 + sizeof ("select") - 1;
17530         arg1 += strspn(arg1, " \t");
17531         word_start = arg1 - line;
17532 
17533         arg1end = arg1 + strcspn(arg1, " \t");
17534         if (arg1end < line + word_end)
17535                 return (0);
17536 
17537         len = line + word_end - arg1;
17538 
17539         buf = safe_malloc(max_scf_name_len + 1);
17540 
17541         if (cur_snap != NULL) {
17542                 return (0);
17543         } else if (cur_inst != NULL) {
17544                 return (0);
17545         } else if (cur_svc != NULL) {
17546                 scf_instance_t *inst;
17547                 scf_iter_t *iter;
17548 
17549                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17550                     (iter = scf_iter_create(g_hndl)) == NULL)
17551                         scfdie();
17552 
17553                 if (scf_iter_service_instances(iter, cur_svc) != 0)
17554                         scfdie();
17555 
17556                 for (;;) {
17557                         r = scf_iter_next_instance(iter, inst);
17558                         if (r == 0)
17559                                 break;
17560                         if (r != 1)
17561                                 scfdie();
17562 
17563                         if (scf_instance_get_name(inst, buf,
17564                             max_scf_name_len + 1) < 0)
17565                                 scfdie();
17566 
17567                         if (strncmp(buf, arg1, len) == 0) {
17568                                 err = cpl_add_completion(cpl, line, word_start,
17569                                     word_end, buf + len, "", " ");
17570                                 if (err != 0)
17571                                         break;
17572                         }
17573                 }
17574 
17575                 scf_iter_destroy(iter);
17576                 scf_instance_destroy(inst);
17577 
17578                 return (err);
17579         } else {
17580                 scf_service_t *svc;
17581                 scf_iter_t *iter;
17582 
17583                 assert(cur_scope != NULL);
17584 
17585                 if ((svc = scf_service_create(g_hndl)) == NULL ||
17586                     (iter = scf_iter_create(g_hndl)) == NULL)
17587                         scfdie();
17588 
17589                 if (scf_iter_scope_services(iter, cur_scope) != 0)
17590                         scfdie();
17591 
17592                 for (;;) {
17593                         r = scf_iter_next_service(iter, svc);
17594                         if (r == 0)
17595                                 break;
17596                         if (r != 1)
17597                                 scfdie();
17598 
17599                         if (scf_service_get_name(svc, buf,
17600                             max_scf_name_len + 1) < 0)
17601                                 scfdie();
17602 
17603                         if (strncmp(buf, arg1, len) == 0) {
17604                                 err = cpl_add_completion(cpl, line, word_start,
17605                                     word_end, buf + len, "", " ");
17606                                 if (err != 0)
17607                                         break;
17608                         }
17609                 }
17610 
17611                 scf_iter_destroy(iter);
17612                 scf_service_destroy(svc);
17613 
17614                 return (err);
17615         }
17616 }
17617 
17618 /* ARGSUSED */
17619 CPL_MATCH_FN(complete_command)
17620 {
17621         uint32_t scope = 0;
17622 
17623         if (cur_snap != NULL)
17624                 scope = CS_SNAP;
17625         else if (cur_inst != NULL)
17626                 scope = CS_INST;
17627         else if (cur_svc != NULL)
17628                 scope = CS_SVC;
17629         else
17630                 scope = CS_SCOPE;
17631 
17632         return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17633 }
17634 #endif  /* NATIVE_BUILD */