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