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  */
  27 
  28 
  29 #include <alloca.h>
  30 #include <assert.h>
  31 #include <ctype.h>
  32 #include <door.h>
  33 #include <errno.h>
  34 #include <fcntl.h>
  35 #include <fnmatch.h>
  36 #include <inttypes.h>
  37 #include <libintl.h>
  38 #include <libnvpair.h>
  39 #include <libscf.h>
  40 #include <libscf_priv.h>
  41 #include <libtecla.h>
  42 #include <libuutil.h>
  43 #include <limits.h>
  44 #include <locale.h>
  45 #include <stdarg.h>
  46 #include <string.h>
  47 #include <strings.h>
  48 #include <time.h>
  49 #include <unistd.h>
  50 #include <wait.h>
  51 #include <poll.h>
  52 
  53 #include <libxml/tree.h>
  54 
  55 #include <sys/param.h>
  56 
  57 #include <sys/stat.h>
  58 #include <sys/mman.h>
  59 
  60 #include "svccfg.h"
  61 #include "notify_params.h"
  62 #include "manifest_hash.h"
  63 #include "manifest_find.h"
  64 
  65 /* The colon namespaces in each entity (each followed by a newline). */
  66 #define COLON_NAMESPACES        ":properties\n"
  67 
  68 #define TEMP_FILE_PATTERN       "/tmp/svccfg-XXXXXX"
  69 
  70 /* These are characters which the lexer requires to be in double-quotes. */
  71 #define CHARS_TO_QUOTE          " \t\n\\>=\"()"
  72 
  73 #define HASH_SIZE               16
  74 #define HASH_PG_TYPE            "framework"
  75 #define HASH_PG_FLAGS           0
  76 #define HASH_PROP               "md5sum"
  77 
  78 /*
  79  * Indentation used in the output of the describe subcommand.
  80  */
  81 #define TMPL_VALUE_INDENT       "  "
  82 #define TMPL_INDENT             "    "
  83 #define TMPL_INDENT_2X          "        "
  84 #define TMPL_CHOICE_INDENT      "      "
  85 
  86 /*
  87  * Directory locations for manifests
  88  */
  89 #define VARSVC_DIR              "/var/svc/manifest"
  90 #define LIBSVC_DIR              "/lib/svc/manifest"
  91 #define VARSVC_PR               "var_svc_manifest"
  92 #define LIBSVC_PR               "lib_svc_manifest"
  93 #define MFSTFILEPR              "manifestfile"
  94 
  95 #define SUPPORTPROP             "support"
  96 
  97 #define MFSTHISTFILE            "/lib/svc/share/mfsthistory"
  98 
  99 #define MFSTFILE_MAX            16
 100 
 101 /*
 102  * These are the classes of elements which may appear as children of service
 103  * or instance elements in XML manifests.
 104  */
 105 struct entity_elts {
 106         xmlNodePtr      create_default_instance;
 107         xmlNodePtr      single_instance;
 108         xmlNodePtr      restarter;
 109         xmlNodePtr      dependencies;
 110         xmlNodePtr      dependents;
 111         xmlNodePtr      method_context;
 112         xmlNodePtr      exec_methods;
 113         xmlNodePtr      notify_params;
 114         xmlNodePtr      property_groups;
 115         xmlNodePtr      instances;
 116         xmlNodePtr      stability;
 117         xmlNodePtr      template;
 118 };
 119 
 120 /*
 121  * Likewise for property_group elements.
 122  */
 123 struct pg_elts {
 124         xmlNodePtr      stability;
 125         xmlNodePtr      propvals;
 126         xmlNodePtr      properties;
 127 };
 128 
 129 /*
 130  * Likewise for template elements.
 131  */
 132 struct template_elts {
 133         xmlNodePtr      common_name;
 134         xmlNodePtr      description;
 135         xmlNodePtr      documentation;
 136 };
 137 
 138 /*
 139  * Likewise for type (for notification parameters) elements.
 140  */
 141 struct params_elts {
 142         xmlNodePtr      paramval;
 143         xmlNodePtr      parameter;
 144 };
 145 
 146 /*
 147  * This structure is for snaplevel lists.  They are convenient because libscf
 148  * only allows traversing snaplevels in one direction.
 149  */
 150 struct snaplevel {
 151         uu_list_node_t  list_node;
 152         scf_snaplevel_t *sl;
 153 };
 154 
 155 /*
 156  * This is used for communication between lscf_service_export and
 157  * export_callback.
 158  */
 159 struct export_args {
 160         const char      *filename;
 161         int             flags;
 162 };
 163 
 164 /*
 165  * The service_manifest structure is used by the upgrade process
 166  * to create a list of service to manifest linkages from the manifests
 167  * in a set of given directories.
 168  */
 169 typedef struct service_manifest {
 170         const char      *servicename;
 171         uu_list_t       *mfstlist;
 172         size_t  mfstlist_sz;
 173 
 174         uu_avl_node_t   svcmfst_node;
 175 } service_manifest_t;
 176 
 177 /*
 178  * Structure to track the manifest file property group
 179  * and the manifest file associated with that property
 180  * group.  Also, a flag to keep the access once it has
 181  * been checked.
 182  */
 183 struct mpg_mfile {
 184         char    *mpg;
 185         char    *mfile;
 186         int     access;
 187 };
 188 
 189 const char * const scf_pg_general = SCF_PG_GENERAL;
 190 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
 191 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
 192 const char * const scf_property_external = "external";
 193 
 194 const char * const snap_initial = "initial";
 195 const char * const snap_lastimport = "last-import";
 196 const char * const snap_previous = "previous";
 197 const char * const snap_running = "running";
 198 
 199 scf_handle_t *g_hndl = NULL;    /* only valid after lscf_prep_hndl() */
 200 
 201 ssize_t max_scf_fmri_len;
 202 ssize_t max_scf_name_len;
 203 ssize_t max_scf_pg_type_len;
 204 ssize_t max_scf_value_len;
 205 static size_t max_scf_len;
 206 
 207 static scf_scope_t *cur_scope;
 208 static scf_service_t *cur_svc = NULL;
 209 static scf_instance_t *cur_inst = NULL;
 210 static scf_snapshot_t *cur_snap = NULL;
 211 static scf_snaplevel_t *cur_level = NULL;
 212 
 213 static uu_list_pool_t *snaplevel_pool;
 214 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
 215 static uu_list_t *cur_levels;
 216 static struct snaplevel *cur_elt;               /* cur_elt->sl == cur_level */
 217 
 218 static FILE *tempfile = NULL;
 219 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
 220 
 221 static const char *emsg_entity_not_selected;
 222 static const char *emsg_permission_denied;
 223 static const char *emsg_create_xml;
 224 static const char *emsg_cant_modify_snapshots;
 225 static const char *emsg_invalid_for_snapshot;
 226 static const char *emsg_read_only;
 227 static const char *emsg_deleted;
 228 static const char *emsg_invalid_pg_name;
 229 static const char *emsg_invalid_prop_name;
 230 static const char *emsg_no_such_pg;
 231 static const char *emsg_fmri_invalid_pg_name;
 232 static const char *emsg_fmri_invalid_pg_name_type;
 233 static const char *emsg_pg_added;
 234 static const char *emsg_pg_changed;
 235 static const char *emsg_pg_deleted;
 236 static const char *emsg_pg_mod_perm;
 237 static const char *emsg_pg_add_perm;
 238 static const char *emsg_pg_del_perm;
 239 static const char *emsg_snap_perm;
 240 static const char *emsg_dpt_dangling;
 241 static const char *emsg_dpt_no_dep;
 242 
 243 static int li_only = 0;
 244 static int no_refresh = 0;
 245 
 246 /* how long in ns we should wait between checks for a pg */
 247 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
 248 
 249 /* import globals, to minimize allocations */
 250 static scf_scope_t *imp_scope = NULL;
 251 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
 252 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
 253 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
 254 static scf_snapshot_t *imp_rsnap = NULL;
 255 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
 256 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
 257 static scf_property_t *imp_prop = NULL;
 258 static scf_iter_t *imp_iter = NULL;
 259 static scf_iter_t *imp_rpg_iter = NULL;
 260 static scf_iter_t *imp_up_iter = NULL;
 261 static scf_transaction_t *imp_tx = NULL;        /* always reset this */
 262 static char *imp_str = NULL;
 263 static size_t imp_str_sz;
 264 static char *imp_tsname = NULL;
 265 static char *imp_fe1 = NULL;            /* for fmri_equal() */
 266 static char *imp_fe2 = NULL;
 267 static uu_list_t *imp_deleted_dpts = NULL;      /* pgroup_t's to refresh */
 268 
 269 /* upgrade_dependents() globals */
 270 static scf_instance_t *ud_inst = NULL;
 271 static scf_snaplevel_t *ud_snpl = NULL;
 272 static scf_propertygroup_t *ud_pg = NULL;
 273 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
 274 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
 275 static int ud_run_dpts_pg_set = 0;
 276 static scf_property_t *ud_prop = NULL;
 277 static scf_property_t *ud_dpt_prop = NULL;
 278 static scf_value_t *ud_val = NULL;
 279 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
 280 static scf_transaction_t *ud_tx = NULL;
 281 static char *ud_ctarg = NULL;
 282 static char *ud_oldtarg = NULL;
 283 static char *ud_name = NULL;
 284 
 285 /* export globals */
 286 static scf_instance_t *exp_inst;
 287 static scf_propertygroup_t *exp_pg;
 288 static scf_property_t *exp_prop;
 289 static scf_value_t *exp_val;
 290 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
 291 static char *exp_str;
 292 static size_t exp_str_sz;
 293 
 294 /* cleanup globals */
 295 static uu_avl_pool_t *service_manifest_pool = NULL;
 296 static uu_avl_t *service_manifest_tree = NULL;
 297 
 298 static void scfdie_lineno(int lineno) __NORETURN;
 299 
 300 static char *start_method_names[] = {
 301         "start",
 302         "inetd_start",
 303         NULL
 304 };
 305 
 306 static struct uri_scheme {
 307         const char *scheme;
 308         const char *protocol;
 309 } uri_scheme[] = {
 310         { "mailto", "smtp" },
 311         { "snmp", "snmp" },
 312         { "syslog", "syslog" },
 313         { NULL, NULL }
 314 };
 315 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
 316     sizeof (struct uri_scheme)) - 1)
 317 
 318 static int
 319 check_uri_scheme(const char *scheme)
 320 {
 321         int i;
 322 
 323         for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
 324                 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
 325                         return (i);
 326         }
 327 
 328         return (-1);
 329 }
 330 
 331 static int
 332 check_uri_protocol(const char *p)
 333 {
 334         int i;
 335 
 336         for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
 337                 if (strcmp(p, uri_scheme[i].protocol) == 0)
 338                         return (i);
 339         }
 340 
 341         return (-1);
 342 }
 343 
 344 /*
 345  * For unexpected libscf errors.
 346  */
 347 #ifdef NDEBUG
 348 
 349 static void scfdie(void) __NORETURN;
 350 
 351 static void
 352 scfdie(void)
 353 {
 354         scf_error_t err = scf_error();
 355 
 356         if (err == SCF_ERROR_CONNECTION_BROKEN)
 357                 uu_die(gettext("Repository connection broken.  Exiting.\n"));
 358 
 359         uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
 360             scf_strerror(err));
 361 }
 362 
 363 #else
 364 
 365 #define scfdie()        scfdie_lineno(__LINE__)
 366 
 367 static void
 368 scfdie_lineno(int lineno)
 369 {
 370         scf_error_t err = scf_error();
 371 
 372         if (err == SCF_ERROR_CONNECTION_BROKEN)
 373                 uu_die(gettext("Repository connection broken.  Exiting.\n"));
 374 
 375         uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
 376             ": %s.\n"), lineno, scf_strerror(err));
 377 }
 378 
 379 #endif
 380 
 381 static void
 382 scfwarn(void)
 383 {
 384         warn(gettext("Unexpected libscf error: %s.\n"),
 385             scf_strerror(scf_error()));
 386 }
 387 
 388 /*
 389  * Clear a field of a structure.
 390  */
 391 static int
 392 clear_int(void *a, void *b)
 393 {
 394         /* LINTED */
 395         *(int *)((char *)a + (size_t)b) = 0;
 396 
 397         return (UU_WALK_NEXT);
 398 }
 399 
 400 static int
 401 scferror2errno(scf_error_t err)
 402 {
 403         switch (err) {
 404         case SCF_ERROR_BACKEND_ACCESS:
 405                 return (EACCES);
 406 
 407         case SCF_ERROR_BACKEND_READONLY:
 408                 return (EROFS);
 409 
 410         case SCF_ERROR_CONNECTION_BROKEN:
 411                 return (ECONNABORTED);
 412 
 413         case SCF_ERROR_CONSTRAINT_VIOLATED:
 414         case SCF_ERROR_INVALID_ARGUMENT:
 415                 return (EINVAL);
 416 
 417         case SCF_ERROR_DELETED:
 418                 return (ECANCELED);
 419 
 420         case SCF_ERROR_EXISTS:
 421                 return (EEXIST);
 422 
 423         case SCF_ERROR_NO_MEMORY:
 424                 return (ENOMEM);
 425 
 426         case SCF_ERROR_NO_RESOURCES:
 427                 return (ENOSPC);
 428 
 429         case SCF_ERROR_NOT_FOUND:
 430                 return (ENOENT);
 431 
 432         case SCF_ERROR_PERMISSION_DENIED:
 433                 return (EPERM);
 434 
 435         default:
 436 #ifndef NDEBUG
 437                 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
 438                     __FILE__, __LINE__, err);
 439 #else
 440                 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
 441 #endif
 442                 abort();
 443                 /* NOTREACHED */
 444         }
 445 }
 446 
 447 static int
 448 entity_get_pg(void *ent, int issvc, const char *name,
 449     scf_propertygroup_t *pg)
 450 {
 451         if (issvc)
 452                 return (scf_service_get_pg(ent, name, pg));
 453         else
 454                 return (scf_instance_get_pg(ent, name, pg));
 455 }
 456 
 457 static void
 458 entity_destroy(void *ent, int issvc)
 459 {
 460         if (issvc)
 461                 scf_service_destroy(ent);
 462         else
 463                 scf_instance_destroy(ent);
 464 }
 465 
 466 static int
 467 get_pg(const char *pg_name, scf_propertygroup_t *pg)
 468 {
 469         int ret;
 470 
 471         if (cur_level != NULL)
 472                 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
 473         else if (cur_inst != NULL)
 474                 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
 475         else
 476                 ret = scf_service_get_pg(cur_svc, pg_name, pg);
 477 
 478         return (ret);
 479 }
 480 
 481 /*
 482  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
 483  * snaplevel.  Otherwise find the instance snaplevel.
 484  *
 485  * Returns
 486  *   0 - success
 487  *   ECONNABORTED - repository connection broken
 488  *   ECANCELED - instance containing snap was deleted
 489  *   ENOENT - snap has no snaplevels
 490  *          - requested snaplevel not found
 491  */
 492 static int
 493 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
 494 {
 495         if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
 496                 switch (scf_error()) {
 497                 case SCF_ERROR_CONNECTION_BROKEN:
 498                 case SCF_ERROR_DELETED:
 499                 case SCF_ERROR_NOT_FOUND:
 500                         return (scferror2errno(scf_error()));
 501 
 502                 case SCF_ERROR_HANDLE_MISMATCH:
 503                 case SCF_ERROR_NOT_BOUND:
 504                 case SCF_ERROR_NOT_SET:
 505                 default:
 506                         bad_error("scf_snapshot_get_base_snaplevel",
 507                             scf_error());
 508                 }
 509         }
 510 
 511         for (;;) {
 512                 ssize_t ssz;
 513 
 514                 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
 515                 if (ssz >= 0) {
 516                         if (!get_svc)
 517                                 return (0);
 518                 } else {
 519                         switch (scf_error()) {
 520                         case SCF_ERROR_CONSTRAINT_VIOLATED:
 521                                 if (get_svc)
 522                                         return (0);
 523                                 break;
 524 
 525                         case SCF_ERROR_DELETED:
 526                         case SCF_ERROR_CONNECTION_BROKEN:
 527                                 return (scferror2errno(scf_error()));
 528 
 529                         case SCF_ERROR_NOT_SET:
 530                         case SCF_ERROR_NOT_BOUND:
 531                         default:
 532                                 bad_error("scf_snaplevel_get_instance_name",
 533                                     scf_error());
 534                         }
 535                 }
 536 
 537                 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
 538                         switch (scf_error()) {
 539                         case SCF_ERROR_NOT_FOUND:
 540                         case SCF_ERROR_CONNECTION_BROKEN:
 541                         case SCF_ERROR_DELETED:
 542                                 return (scferror2errno(scf_error()));
 543 
 544                         case SCF_ERROR_HANDLE_MISMATCH:
 545                         case SCF_ERROR_NOT_BOUND:
 546                         case SCF_ERROR_NOT_SET:
 547                         case SCF_ERROR_INVALID_ARGUMENT:
 548                         default:
 549                                 bad_error("scf_snaplevel_get_next_snaplevel",
 550                                     scf_error());
 551                         }
 552                 }
 553         }
 554 }
 555 
 556 /*
 557  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
 558  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
 559  * the property group named name in it.  If it doesn't have a running
 560  * snapshot, set pg to the instance's current property group named name.
 561  *
 562  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
 563  * its instances.  If one has a running snapshot with a service snaplevel, set
 564  * pg to the property group named name in it.  If no such snaplevel could be
 565  * found, set pg to the service's current property group named name.
 566  *
 567  * iter, inst, snap, and snpl are required scratch objects.
 568  *
 569  * Returns
 570  *   0 - success
 571  *   ECONNABORTED - repository connection broken
 572  *   ECANCELED - ent was deleted
 573  *   ENOENT - no such property group
 574  *   EINVAL - name is an invalid property group name
 575  *   EBADF - found running snapshot is missing a snaplevel
 576  */
 577 static int
 578 entity_get_running_pg(void *ent, int issvc, const char *name,
 579     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
 580     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
 581 {
 582         int r;
 583 
 584         if (issvc) {
 585                 /* Search for an instance with a running snapshot. */
 586                 if (scf_iter_service_instances(iter, ent) != 0) {
 587                         switch (scf_error()) {
 588                         case SCF_ERROR_DELETED:
 589                         case SCF_ERROR_CONNECTION_BROKEN:
 590                                 return (scferror2errno(scf_error()));
 591 
 592                         case SCF_ERROR_NOT_SET:
 593                         case SCF_ERROR_NOT_BOUND:
 594                         case SCF_ERROR_HANDLE_MISMATCH:
 595                         default:
 596                                 bad_error("scf_iter_service_instances",
 597                                     scf_error());
 598                         }
 599                 }
 600 
 601                 for (;;) {
 602                         r = scf_iter_next_instance(iter, inst);
 603                         if (r == 0) {
 604                                 if (scf_service_get_pg(ent, name, pg) == 0)
 605                                         return (0);
 606 
 607                                 switch (scf_error()) {
 608                                 case SCF_ERROR_DELETED:
 609                                 case SCF_ERROR_NOT_FOUND:
 610                                 case SCF_ERROR_INVALID_ARGUMENT:
 611                                 case SCF_ERROR_CONNECTION_BROKEN:
 612                                         return (scferror2errno(scf_error()));
 613 
 614                                 case SCF_ERROR_NOT_BOUND:
 615                                 case SCF_ERROR_HANDLE_MISMATCH:
 616                                 case SCF_ERROR_NOT_SET:
 617                                 default:
 618                                         bad_error("scf_service_get_pg",
 619                                             scf_error());
 620                                 }
 621                         }
 622                         if (r != 1) {
 623                                 switch (scf_error()) {
 624                                 case SCF_ERROR_DELETED:
 625                                 case SCF_ERROR_CONNECTION_BROKEN:
 626                                         return (scferror2errno(scf_error()));
 627 
 628                                 case SCF_ERROR_INVALID_ARGUMENT:
 629                                 case SCF_ERROR_NOT_SET:
 630                                 case SCF_ERROR_NOT_BOUND:
 631                                 case SCF_ERROR_HANDLE_MISMATCH:
 632                                 default:
 633                                         bad_error("scf_iter_next_instance",
 634                                             scf_error());
 635                                 }
 636                         }
 637 
 638                         if (scf_instance_get_snapshot(inst, snap_running,
 639                             snap) == 0)
 640                                 break;
 641 
 642                         switch (scf_error()) {
 643                         case SCF_ERROR_NOT_FOUND:
 644                         case SCF_ERROR_DELETED:
 645                                 continue;
 646 
 647                         case SCF_ERROR_CONNECTION_BROKEN:
 648                                 return (ECONNABORTED);
 649 
 650                         case SCF_ERROR_HANDLE_MISMATCH:
 651                         case SCF_ERROR_INVALID_ARGUMENT:
 652                         case SCF_ERROR_NOT_SET:
 653                         case SCF_ERROR_NOT_BOUND:
 654                         default:
 655                                 bad_error("scf_instance_get_snapshot",
 656                                     scf_error());
 657                         }
 658                 }
 659         } else {
 660                 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
 661                         switch (scf_error()) {
 662                         case SCF_ERROR_NOT_FOUND:
 663                                 break;
 664 
 665                         case SCF_ERROR_DELETED:
 666                         case SCF_ERROR_CONNECTION_BROKEN:
 667                                 return (scferror2errno(scf_error()));
 668 
 669                         case SCF_ERROR_NOT_BOUND:
 670                         case SCF_ERROR_HANDLE_MISMATCH:
 671                         case SCF_ERROR_INVALID_ARGUMENT:
 672                         case SCF_ERROR_NOT_SET:
 673                         default:
 674                                 bad_error("scf_instance_get_snapshot",
 675                                     scf_error());
 676                         }
 677 
 678                         if (scf_instance_get_pg(ent, name, pg) == 0)
 679                                 return (0);
 680 
 681                         switch (scf_error()) {
 682                         case SCF_ERROR_DELETED:
 683                         case SCF_ERROR_NOT_FOUND:
 684                         case SCF_ERROR_INVALID_ARGUMENT:
 685                         case SCF_ERROR_CONNECTION_BROKEN:
 686                                 return (scferror2errno(scf_error()));
 687 
 688                         case SCF_ERROR_NOT_BOUND:
 689                         case SCF_ERROR_HANDLE_MISMATCH:
 690                         case SCF_ERROR_NOT_SET:
 691                         default:
 692                                 bad_error("scf_instance_get_pg", scf_error());
 693                         }
 694                 }
 695         }
 696 
 697         r = get_snaplevel(snap, issvc, snpl);
 698         switch (r) {
 699         case 0:
 700                 break;
 701 
 702         case ECONNABORTED:
 703         case ECANCELED:
 704                 return (r);
 705 
 706         case ENOENT:
 707                 return (EBADF);
 708 
 709         default:
 710                 bad_error("get_snaplevel", r);
 711         }
 712 
 713         if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
 714                 return (0);
 715 
 716         switch (scf_error()) {
 717         case SCF_ERROR_DELETED:
 718         case SCF_ERROR_INVALID_ARGUMENT:
 719         case SCF_ERROR_CONNECTION_BROKEN:
 720         case SCF_ERROR_NOT_FOUND:
 721                 return (scferror2errno(scf_error()));
 722 
 723         case SCF_ERROR_NOT_BOUND:
 724         case SCF_ERROR_HANDLE_MISMATCH:
 725         case SCF_ERROR_NOT_SET:
 726         default:
 727                 bad_error("scf_snaplevel_get_pg", scf_error());
 728                 /* NOTREACHED */
 729         }
 730 }
 731 
 732 /*
 733  * To be registered with atexit().
 734  */
 735 static void
 736 remove_tempfile(void)
 737 {
 738         int ret;
 739 
 740         if (tempfile != NULL) {
 741                 if (fclose(tempfile) == EOF)
 742                         (void) warn(gettext("Could not close temporary file"));
 743                 tempfile = NULL;
 744         }
 745 
 746         if (tempfilename[0] != '\0') {
 747                 do {
 748                         ret = remove(tempfilename);
 749                 } while (ret == -1 && errno == EINTR);
 750                 if (ret == -1)
 751                         warn(gettext("Could not remove temporary file"));
 752                 tempfilename[0] = '\0';
 753         }
 754 }
 755 
 756 /*
 757  * Launch private svc.configd(1M) for manipulating alternate repositories.
 758  */
 759 static void
 760 start_private_repository(engine_state_t *est)
 761 {
 762         int fd, stat;
 763         struct door_info info;
 764         pid_t pid;
 765 
 766         /*
 767          * 1.  Create a temporary file for the door.
 768          */
 769         if (est->sc_repo_doorname != NULL)
 770                 free((void *)est->sc_repo_doorname);
 771 
 772         est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
 773         if (est->sc_repo_doorname == NULL)
 774                 uu_die(gettext("Could not acquire temporary filename"));
 775 
 776         fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
 777         if (fd < 0)
 778                 uu_die(gettext("Could not create temporary file for "
 779                     "repository server"));
 780 
 781         (void) close(fd);
 782 
 783         /*
 784          * 2.  Launch a configd with that door, using the specified
 785          * repository.
 786          */
 787         if ((est->sc_repo_pid = fork()) == 0) {
 788                 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
 789                     "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
 790                     NULL);
 791                 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
 792         } else if (est->sc_repo_pid == -1)
 793                 uu_die(gettext("Attempt to fork failed"));
 794 
 795         do {
 796                 pid = waitpid(est->sc_repo_pid, &stat, 0);
 797         } while (pid == -1 && errno == EINTR);
 798 
 799         if (pid == -1)
 800                 uu_die(gettext("Could not waitpid() for repository server"));
 801 
 802         if (!WIFEXITED(stat)) {
 803                 uu_die(gettext("Repository server failed (status %d).\n"),
 804                     stat);
 805         } else if (WEXITSTATUS(stat) != 0) {
 806                 uu_die(gettext("Repository server failed (exit %d).\n"),
 807                     WEXITSTATUS(stat));
 808         }
 809 
 810         /*
 811          * See if it was successful by checking if the door is a door.
 812          */
 813 
 814         fd = open(est->sc_repo_doorname, O_RDWR);
 815         if (fd < 0)
 816                 uu_die(gettext("Could not open door \"%s\""),
 817                     est->sc_repo_doorname);
 818 
 819         if (door_info(fd, &info) < 0)
 820                 uu_die(gettext("Unexpected door_info() error"));
 821 
 822         if (close(fd) == -1)
 823                 warn(gettext("Could not close repository door"),
 824                     strerror(errno));
 825 
 826         est->sc_repo_pid = info.di_target;
 827 }
 828 
 829 void
 830 lscf_cleanup(void)
 831 {
 832         /*
 833          * In the case where we've launched a private svc.configd(1M)
 834          * instance, we must terminate our child and remove the temporary
 835          * rendezvous point.
 836          */
 837         if (est->sc_repo_pid > 0) {
 838                 (void) kill(est->sc_repo_pid, SIGTERM);
 839                 (void) waitpid(est->sc_repo_pid, NULL, 0);
 840                 (void) unlink(est->sc_repo_doorname);
 841 
 842                 est->sc_repo_pid = 0;
 843         }
 844 }
 845 
 846 void
 847 unselect_cursnap(void)
 848 {
 849         void *cookie;
 850 
 851         cur_level = NULL;
 852 
 853         cookie = NULL;
 854         while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
 855                 scf_snaplevel_destroy(cur_elt->sl);
 856                 free(cur_elt);
 857         }
 858 
 859         scf_snapshot_destroy(cur_snap);
 860         cur_snap = NULL;
 861 }
 862 
 863 void
 864 lscf_prep_hndl(void)
 865 {
 866         if (g_hndl != NULL)
 867                 return;
 868 
 869         g_hndl = scf_handle_create(SCF_VERSION);
 870         if (g_hndl == NULL)
 871                 scfdie();
 872 
 873         if (est->sc_repo_filename != NULL)
 874                 start_private_repository(est);
 875 
 876         if (est->sc_repo_doorname != NULL) {
 877                 scf_value_t *repo_value;
 878                 int ret;
 879 
 880                 repo_value = scf_value_create(g_hndl);
 881                 if (repo_value == NULL)
 882                         scfdie();
 883 
 884                 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
 885                 assert(ret == SCF_SUCCESS);
 886 
 887                 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
 888                     SCF_SUCCESS)
 889                         scfdie();
 890 
 891                 scf_value_destroy(repo_value);
 892         }
 893 
 894         if (scf_handle_bind(g_hndl) != 0)
 895                 uu_die(gettext("Could not connect to repository server: %s.\n"),
 896                     scf_strerror(scf_error()));
 897 
 898         cur_scope = scf_scope_create(g_hndl);
 899         if (cur_scope == NULL)
 900                 scfdie();
 901 
 902         if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
 903                 scfdie();
 904 }
 905 
 906 static void
 907 repository_teardown(void)
 908 {
 909         if (g_hndl != NULL) {
 910                 if (cur_snap != NULL)
 911                         unselect_cursnap();
 912                 scf_instance_destroy(cur_inst);
 913                 scf_service_destroy(cur_svc);
 914                 scf_scope_destroy(cur_scope);
 915                 scf_handle_destroy(g_hndl);
 916                 cur_inst = NULL;
 917                 cur_svc = NULL;
 918                 cur_scope = NULL;
 919                 g_hndl = NULL;
 920                 lscf_cleanup();
 921         }
 922 }
 923 
 924 void
 925 lscf_set_repository(const char *repfile, int force)
 926 {
 927         repository_teardown();
 928 
 929         if (est->sc_repo_filename != NULL) {
 930                 free((void *)est->sc_repo_filename);
 931                 est->sc_repo_filename = NULL;
 932         }
 933 
 934         if ((force == 0) && (access(repfile, R_OK) != 0)) {
 935                 /*
 936                  * Repository file does not exist
 937                  * or has no read permission.
 938                  */
 939                 warn(gettext("Cannot access \"%s\": %s\n"),
 940                     repfile, strerror(errno));
 941         } else {
 942                 est->sc_repo_filename = safe_strdup(repfile);
 943         }
 944 
 945         lscf_prep_hndl();
 946 }
 947 
 948 void
 949 lscf_init()
 950 {
 951         if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
 952             (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
 953             (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
 954             0 ||
 955             (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
 956                 scfdie();
 957 
 958         max_scf_len = max_scf_fmri_len;
 959         if (max_scf_name_len > max_scf_len)
 960                 max_scf_len = max_scf_name_len;
 961         if (max_scf_pg_type_len > max_scf_len)
 962                 max_scf_len = max_scf_pg_type_len;
 963         /*
 964          * When a value of type opaque is represented as a string, the
 965          * string contains 2 characters for every byte of data.  That is
 966          * because the string contains the hex representation of the opaque
 967          * value.
 968          */
 969         if (2 * max_scf_value_len > max_scf_len)
 970                 max_scf_len = 2 * max_scf_value_len;
 971 
 972         if (atexit(remove_tempfile) != 0)
 973                 uu_die(gettext("Could not register atexit() function"));
 974 
 975         emsg_entity_not_selected = gettext("An entity is not selected.\n");
 976         emsg_permission_denied = gettext("Permission denied.\n");
 977         emsg_create_xml = gettext("Could not create XML node.\n");
 978         emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
 979         emsg_invalid_for_snapshot =
 980             gettext("Invalid operation on a snapshot.\n");
 981         emsg_read_only = gettext("Backend read-only.\n");
 982         emsg_deleted = gettext("Current selection has been deleted.\n");
 983         emsg_invalid_pg_name =
 984             gettext("Invalid property group name \"%s\".\n");
 985         emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
 986         emsg_no_such_pg = gettext("No such property group \"%s\".\n");
 987         emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
 988             "with invalid name \"%s\".\n");
 989         emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
 990             "group with invalid name \"%s\" or type \"%s\".\n");
 991         emsg_pg_added = gettext("%s changed unexpectedly "
 992             "(property group \"%s\" added).\n");
 993         emsg_pg_changed = gettext("%s changed unexpectedly "
 994             "(property group \"%s\" changed).\n");
 995         emsg_pg_deleted = gettext("%s changed unexpectedly "
 996             "(property group \"%s\" or an ancestor was deleted).\n");
 997         emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
 998             "in %s (permission denied).\n");
 999         emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1000             "in %s (permission denied).\n");
1001         emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1002             "in %s (permission denied).\n");
1003         emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1004             "(permission denied).\n");
1005         emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1006             "new dependent \"%s\" because it already exists).  Warning: The "
1007             "current dependent's target (%s) does not exist.\n");
1008         emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1009             "dependent \"%s\" because it already exists).  Warning: The "
1010             "current dependent's target (%s) does not have a dependency named "
1011             "\"%s\" as expected.\n");
1012 
1013         string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1014             offsetof(string_list_t, node), NULL, 0);
1015         snaplevel_pool = uu_list_pool_create("snaplevels",
1016             sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1017             NULL, 0);
1018 }
1019 
1020 
1021 static const char *
1022 prop_to_typestr(const scf_property_t *prop)
1023 {
1024         scf_type_t ty;
1025 
1026         if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1027                 scfdie();
1028 
1029         return (scf_type_to_string(ty));
1030 }
1031 
1032 static scf_type_t
1033 string_to_type(const char *type)
1034 {
1035         size_t len = strlen(type);
1036         char *buf;
1037 
1038         if (len == 0 || type[len - 1] != ':')
1039                 return (SCF_TYPE_INVALID);
1040 
1041         buf = (char *)alloca(len + 1);
1042         (void) strlcpy(buf, type, len + 1);
1043         buf[len - 1] = 0;
1044 
1045         return (scf_string_to_type(buf));
1046 }
1047 
1048 static scf_value_t *
1049 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1050 {
1051         scf_value_t *v;
1052         char *dup, *nstr;
1053         size_t len;
1054 
1055         v = scf_value_create(g_hndl);
1056         if (v == NULL)
1057                 scfdie();
1058 
1059         len = strlen(str);
1060         if (require_quotes &&
1061             (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1062                 semerr(gettext("Multiple string values or string values "
1063                     "with spaces must be quoted with '\"'.\n"));
1064                 scf_value_destroy(v);
1065                 return (NULL);
1066         }
1067 
1068         nstr = dup = safe_strdup(str);
1069         if (dup[0] == '\"') {
1070                 /*
1071                  * Strip out the first and the last quote.
1072                  */
1073                 dup[len - 1] = '\0';
1074                 nstr = dup + 1;
1075         }
1076 
1077         if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1078                 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1079                 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1080                     scf_type_to_string(ty), nstr);
1081                 scf_value_destroy(v);
1082                 v = NULL;
1083         }
1084         free(dup);
1085         return (v);
1086 }
1087 
1088 /*
1089  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1090  * Optionally append a comment prefix ('#') to newlines ('\n').
1091  */
1092 static int
1093 quote_and_print(const char *str, FILE *strm, int commentnl)
1094 {
1095         const char *cp;
1096 
1097         for (cp = str; *cp != '\0'; ++cp) {
1098                 if (*cp == '"' || *cp == '\\')
1099                         (void) putc('\\', strm);
1100 
1101                 (void) putc(*cp, strm);
1102 
1103                 if (commentnl && *cp == '\n') {
1104                         (void) putc('#', strm);
1105                 }
1106         }
1107 
1108         return (ferror(strm));
1109 }
1110 
1111 /*
1112  * These wrappers around lowlevel functions provide consistent error checking
1113  * and warnings.
1114  */
1115 static int
1116 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1117 {
1118         if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1119                 return (0);
1120 
1121         if (scf_error() != SCF_ERROR_NOT_FOUND)
1122                 scfdie();
1123 
1124         if (g_verbose) {
1125                 ssize_t len;
1126                 char *fmri;
1127 
1128                 len = scf_pg_to_fmri(pg, NULL, 0);
1129                 if (len < 0)
1130                         scfdie();
1131 
1132                 fmri = safe_malloc(len + 1);
1133 
1134                 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1135                         scfdie();
1136 
1137                 warn(gettext("Expected property %s of property group %s is "
1138                     "missing.\n"), propname, fmri);
1139 
1140                 free(fmri);
1141         }
1142 
1143         return (-1);
1144 }
1145 
1146 static int
1147 prop_check_type(scf_property_t *prop, scf_type_t ty)
1148 {
1149         scf_type_t pty;
1150 
1151         if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1152                 scfdie();
1153 
1154         if (ty == pty)
1155                 return (0);
1156 
1157         if (g_verbose) {
1158                 ssize_t len;
1159                 char *fmri;
1160                 const char *tystr;
1161 
1162                 len = scf_property_to_fmri(prop, NULL, 0);
1163                 if (len < 0)
1164                         scfdie();
1165 
1166                 fmri = safe_malloc(len + 1);
1167 
1168                 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1169                         scfdie();
1170 
1171                 tystr = scf_type_to_string(ty);
1172                 if (tystr == NULL)
1173                         tystr = "?";
1174 
1175                 warn(gettext("Property %s is not of expected type %s.\n"),
1176                     fmri, tystr);
1177 
1178                 free(fmri);
1179         }
1180 
1181         return (-1);
1182 }
1183 
1184 static int
1185 prop_get_val(scf_property_t *prop, scf_value_t *val)
1186 {
1187         scf_error_t err;
1188 
1189         if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1190                 return (0);
1191 
1192         err = scf_error();
1193 
1194         if (err != SCF_ERROR_NOT_FOUND &&
1195             err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1196             err != SCF_ERROR_PERMISSION_DENIED)
1197                 scfdie();
1198 
1199         if (g_verbose) {
1200                 ssize_t len;
1201                 char *fmri, *emsg;
1202 
1203                 len = scf_property_to_fmri(prop, NULL, 0);
1204                 if (len < 0)
1205                         scfdie();
1206 
1207                 fmri = safe_malloc(len + 1);
1208 
1209                 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1210                         scfdie();
1211 
1212                 if (err == SCF_ERROR_NOT_FOUND)
1213                         emsg = gettext("Property %s has no values; expected "
1214                             "one.\n");
1215                 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1216                         emsg = gettext("Property %s has multiple values; "
1217                             "expected one.\n");
1218                 else
1219                         emsg = gettext("No permission to read property %s.\n");
1220 
1221                 warn(emsg, fmri);
1222 
1223                 free(fmri);
1224         }
1225 
1226         return (-1);
1227 }
1228 
1229 
1230 static boolean_t
1231 snaplevel_is_instance(const scf_snaplevel_t *level)
1232 {
1233         if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1234                 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1235                         scfdie();
1236                 return (0);
1237         } else {
1238                 return (1);
1239         }
1240 }
1241 
1242 /*
1243  * Decode FMRI into a service or instance, and put the result in *ep.  If
1244  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1245  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1246  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1247  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1248  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1249  * whether *ep is a service.
1250  */
1251 static scf_error_t
1252 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1253 {
1254         char *fmri_copy;
1255         const char *sstr, *istr, *pgstr;
1256         scf_service_t *svc;
1257         scf_instance_t *inst;
1258 
1259         fmri_copy = strdup(fmri);
1260         if (fmri_copy == NULL)
1261                 return (SCF_ERROR_NO_MEMORY);
1262 
1263         if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1264             SCF_SUCCESS) {
1265                 free(fmri_copy);
1266                 return (SCF_ERROR_INVALID_ARGUMENT);
1267         }
1268 
1269         free(fmri_copy);
1270 
1271         if (sstr == NULL || pgstr != NULL)
1272                 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1273 
1274         if (istr == NULL) {
1275                 svc = scf_service_create(h);
1276                 if (svc == NULL)
1277                         return (SCF_ERROR_NO_MEMORY);
1278 
1279                 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1280                     SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1281                         if (scf_error() != SCF_ERROR_NOT_FOUND)
1282                                 scfdie();
1283 
1284                         return (SCF_ERROR_NOT_FOUND);
1285                 }
1286 
1287                 *ep = svc;
1288                 *isservice = 1;
1289         } else {
1290                 inst = scf_instance_create(h);
1291                 if (inst == NULL)
1292                         return (SCF_ERROR_NO_MEMORY);
1293 
1294                 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1295                     NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1296                         if (scf_error() != SCF_ERROR_NOT_FOUND)
1297                                 scfdie();
1298 
1299                         return (SCF_ERROR_NOT_FOUND);
1300                 }
1301 
1302                 *ep = inst;
1303                 *isservice = 0;
1304         }
1305 
1306         return (SCF_ERROR_NONE);
1307 }
1308 
1309 /*
1310  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1311  * *ep, and set or clear *isservicep if it is a service or an instance.
1312  * Returns
1313  *   SCF_ERROR_NONE - success
1314  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1315  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1316  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1317  *   SCF_ERROR_NOT_FOUND - no such scope
1318  *   SCF_ERROR_PERMISSION_DENIED
1319  *   SCF_ERROR_BACKEND_READONLY
1320  *   SCF_ERROR_BACKEND_ACCESS
1321  */
1322 static scf_error_t
1323 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1324 {
1325         char *fmri_copy;
1326         const char *scstr, *sstr, *istr, *pgstr;
1327         scf_scope_t *scope = NULL;
1328         scf_service_t *svc = NULL;
1329         scf_instance_t *inst = NULL;
1330         scf_error_t scfe;
1331 
1332         fmri_copy = safe_strdup(fmri);
1333 
1334         if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1335             0) {
1336                 free(fmri_copy);
1337                 return (SCF_ERROR_INVALID_ARGUMENT);
1338         }
1339 
1340         if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1341                 free(fmri_copy);
1342                 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1343         }
1344 
1345         *ep = NULL;
1346 
1347         if ((scope = scf_scope_create(h)) == NULL ||
1348             (svc = scf_service_create(h)) == NULL ||
1349             (inst = scf_instance_create(h)) == NULL) {
1350                 scfe = SCF_ERROR_NO_MEMORY;
1351                 goto out;
1352         }
1353 
1354 get_scope:
1355         if (scf_handle_get_scope(h, scstr, scope) != 0) {
1356                 switch (scf_error()) {
1357                 case SCF_ERROR_CONNECTION_BROKEN:
1358                         scfdie();
1359                         /* NOTREACHED */
1360 
1361                 case SCF_ERROR_NOT_FOUND:
1362                         scfe = SCF_ERROR_NOT_FOUND;
1363                         goto out;
1364 
1365                 case SCF_ERROR_HANDLE_MISMATCH:
1366                 case SCF_ERROR_NOT_BOUND:
1367                 case SCF_ERROR_INVALID_ARGUMENT:
1368                 default:
1369                         bad_error("scf_handle_get_scope", scf_error());
1370                 }
1371         }
1372 
1373 get_svc:
1374         if (scf_scope_get_service(scope, sstr, svc) != 0) {
1375                 switch (scf_error()) {
1376                 case SCF_ERROR_CONNECTION_BROKEN:
1377                         scfdie();
1378                         /* NOTREACHED */
1379 
1380                 case SCF_ERROR_DELETED:
1381                         goto get_scope;
1382 
1383                 case SCF_ERROR_NOT_FOUND:
1384                         break;
1385 
1386                 case SCF_ERROR_HANDLE_MISMATCH:
1387                 case SCF_ERROR_INVALID_ARGUMENT:
1388                 case SCF_ERROR_NOT_BOUND:
1389                 case SCF_ERROR_NOT_SET:
1390                 default:
1391                         bad_error("scf_scope_get_service", scf_error());
1392                 }
1393 
1394                 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1395                         switch (scf_error()) {
1396                         case SCF_ERROR_CONNECTION_BROKEN:
1397                                 scfdie();
1398                                 /* NOTREACHED */
1399 
1400                         case SCF_ERROR_DELETED:
1401                                 goto get_scope;
1402 
1403                         case SCF_ERROR_PERMISSION_DENIED:
1404                         case SCF_ERROR_BACKEND_READONLY:
1405                         case SCF_ERROR_BACKEND_ACCESS:
1406                                 scfe = scf_error();
1407                                 goto out;
1408 
1409                         case SCF_ERROR_HANDLE_MISMATCH:
1410                         case SCF_ERROR_INVALID_ARGUMENT:
1411                         case SCF_ERROR_NOT_BOUND:
1412                         case SCF_ERROR_NOT_SET:
1413                         default:
1414                                 bad_error("scf_scope_get_service", scf_error());
1415                         }
1416                 }
1417         }
1418 
1419         if (istr == NULL) {
1420                 scfe = SCF_ERROR_NONE;
1421                 *ep = svc;
1422                 *isservicep = 1;
1423                 goto out;
1424         }
1425 
1426 get_inst:
1427         if (scf_service_get_instance(svc, istr, inst) != 0) {
1428                 switch (scf_error()) {
1429                 case SCF_ERROR_CONNECTION_BROKEN:
1430                         scfdie();
1431                         /* NOTREACHED */
1432 
1433                 case SCF_ERROR_DELETED:
1434                         goto get_svc;
1435 
1436                 case SCF_ERROR_NOT_FOUND:
1437                         break;
1438 
1439                 case SCF_ERROR_HANDLE_MISMATCH:
1440                 case SCF_ERROR_INVALID_ARGUMENT:
1441                 case SCF_ERROR_NOT_BOUND:
1442                 case SCF_ERROR_NOT_SET:
1443                 default:
1444                         bad_error("scf_service_get_instance", scf_error());
1445                 }
1446 
1447                 if (scf_service_add_instance(svc, istr, inst) != 0) {
1448                         switch (scf_error()) {
1449                         case SCF_ERROR_CONNECTION_BROKEN:
1450                                 scfdie();
1451                                 /* NOTREACHED */
1452 
1453                         case SCF_ERROR_DELETED:
1454                                 goto get_svc;
1455 
1456                         case SCF_ERROR_PERMISSION_DENIED:
1457                         case SCF_ERROR_BACKEND_READONLY:
1458                         case SCF_ERROR_BACKEND_ACCESS:
1459                                 scfe = scf_error();
1460                                 goto out;
1461 
1462                         case SCF_ERROR_HANDLE_MISMATCH:
1463                         case SCF_ERROR_INVALID_ARGUMENT:
1464                         case SCF_ERROR_NOT_BOUND:
1465                         case SCF_ERROR_NOT_SET:
1466                         default:
1467                                 bad_error("scf_service_add_instance",
1468                                     scf_error());
1469                         }
1470                 }
1471         }
1472 
1473         scfe = SCF_ERROR_NONE;
1474         *ep = inst;
1475         *isservicep = 0;
1476 
1477 out:
1478         if (*ep != inst)
1479                 scf_instance_destroy(inst);
1480         if (*ep != svc)
1481                 scf_service_destroy(svc);
1482         scf_scope_destroy(scope);
1483         free(fmri_copy);
1484         return (scfe);
1485 }
1486 
1487 /*
1488  * Create or update a snapshot of inst.  snap is a required scratch object.
1489  *
1490  * Returns
1491  *   0 - success
1492  *   ECONNABORTED - repository connection broken
1493  *   EPERM - permission denied
1494  *   ENOSPC - configd is out of resources
1495  *   ECANCELED - inst was deleted
1496  *   -1 - unknown libscf error (message printed)
1497  */
1498 static int
1499 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1500 {
1501 again:
1502         if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1503                 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1504                         switch (scf_error()) {
1505                         case SCF_ERROR_CONNECTION_BROKEN:
1506                         case SCF_ERROR_PERMISSION_DENIED:
1507                         case SCF_ERROR_NO_RESOURCES:
1508                                 return (scferror2errno(scf_error()));
1509 
1510                         case SCF_ERROR_NOT_SET:
1511                         case SCF_ERROR_INVALID_ARGUMENT:
1512                         default:
1513                                 bad_error("_scf_snapshot_take_attach",
1514                                     scf_error());
1515                         }
1516                 }
1517         } else {
1518                 switch (scf_error()) {
1519                 case SCF_ERROR_NOT_FOUND:
1520                         break;
1521 
1522                 case SCF_ERROR_DELETED:
1523                 case SCF_ERROR_CONNECTION_BROKEN:
1524                         return (scferror2errno(scf_error()));
1525 
1526                 case SCF_ERROR_HANDLE_MISMATCH:
1527                 case SCF_ERROR_NOT_BOUND:
1528                 case SCF_ERROR_INVALID_ARGUMENT:
1529                 case SCF_ERROR_NOT_SET:
1530                 default:
1531                         bad_error("scf_instance_get_snapshot", scf_error());
1532                 }
1533 
1534                 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1535                         switch (scf_error()) {
1536                         case SCF_ERROR_EXISTS:
1537                                 goto again;
1538 
1539                         case SCF_ERROR_CONNECTION_BROKEN:
1540                         case SCF_ERROR_NO_RESOURCES:
1541                         case SCF_ERROR_PERMISSION_DENIED:
1542                                 return (scferror2errno(scf_error()));
1543 
1544                         default:
1545                                 scfwarn();
1546                                 return (-1);
1547 
1548                         case SCF_ERROR_NOT_SET:
1549                         case SCF_ERROR_INTERNAL:
1550                         case SCF_ERROR_INVALID_ARGUMENT:
1551                         case SCF_ERROR_HANDLE_MISMATCH:
1552                                 bad_error("_scf_snapshot_take_new",
1553                                     scf_error());
1554                         }
1555                 }
1556         }
1557 
1558         return (0);
1559 }
1560 
1561 static int
1562 refresh_running_snapshot(void *entity)
1563 {
1564         scf_snapshot_t *snap;
1565         int r;
1566 
1567         if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1568                 scfdie();
1569         r = take_snap(entity, snap_running, snap);
1570         scf_snapshot_destroy(snap);
1571 
1572         return (r);
1573 }
1574 
1575 /*
1576  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1577  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1578  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1579  * for scratch space.  Returns
1580  *   0 - success
1581  *   ECONNABORTED - repository connection broken
1582  *   ECANCELED - entity was deleted
1583  *   EACCES - backend denied access
1584  *   EPERM - permission denied
1585  *   ENOSPC - repository server out of resources
1586  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1587  */
1588 static int
1589 refresh_entity(int isservice, void *entity, const char *fmri,
1590     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1591 {
1592         scf_error_t scfe;
1593         int r;
1594 
1595         if (!isservice) {
1596                 /*
1597                  * Let restarter handles refreshing and making new running
1598                  * snapshot only if operating on a live repository and not
1599                  * running in early import.
1600                  */
1601                 if (est->sc_repo_filename == NULL &&
1602                     est->sc_repo_doorname == NULL &&
1603                     est->sc_in_emi == 0) {
1604                         if (_smf_refresh_instance_i(entity) == 0) {
1605                                 if (g_verbose)
1606                                         warn(gettext("Refreshed %s.\n"), fmri);
1607                                 return (0);
1608                         }
1609 
1610                         switch (scf_error()) {
1611                         case SCF_ERROR_BACKEND_ACCESS:
1612                                 return (EACCES);
1613 
1614                         case SCF_ERROR_PERMISSION_DENIED:
1615                                 return (EPERM);
1616 
1617                         default:
1618                                 return (-1);
1619                         }
1620                 } else {
1621                         r = refresh_running_snapshot(entity);
1622                         switch (r) {
1623                         case 0:
1624                                 break;
1625 
1626                         case ECONNABORTED:
1627                         case ECANCELED:
1628                         case EPERM:
1629                         case ENOSPC:
1630                                 break;
1631 
1632                         default:
1633                                 bad_error("refresh_running_snapshot",
1634                                     scf_error());
1635                         }
1636 
1637                         return (r);
1638                 }
1639         }
1640 
1641         if (scf_iter_service_instances(iter, entity) != 0) {
1642                 switch (scf_error()) {
1643                 case SCF_ERROR_CONNECTION_BROKEN:
1644                         return (ECONNABORTED);
1645 
1646                 case SCF_ERROR_DELETED:
1647                         return (ECANCELED);
1648 
1649                 case SCF_ERROR_HANDLE_MISMATCH:
1650                 case SCF_ERROR_NOT_BOUND:
1651                 case SCF_ERROR_NOT_SET:
1652                 default:
1653                         bad_error("scf_iter_service_instances", scf_error());
1654                 }
1655         }
1656 
1657         for (;;) {
1658                 r = scf_iter_next_instance(iter, inst);
1659                 if (r == 0)
1660                         break;
1661                 if (r != 1) {
1662                         switch (scf_error()) {
1663                         case SCF_ERROR_CONNECTION_BROKEN:
1664                                 return (ECONNABORTED);
1665 
1666                         case SCF_ERROR_DELETED:
1667                                 return (ECANCELED);
1668 
1669                         case SCF_ERROR_HANDLE_MISMATCH:
1670                         case SCF_ERROR_NOT_BOUND:
1671                         case SCF_ERROR_NOT_SET:
1672                         case SCF_ERROR_INVALID_ARGUMENT:
1673                         default:
1674                                 bad_error("scf_iter_next_instance",
1675                                     scf_error());
1676                         }
1677                 }
1678 
1679                 /*
1680                  * Similarly, just take a new running snapshot if operating on
1681                  * a non-live repository or running during early import.
1682                  */
1683                 if (est->sc_repo_filename != NULL ||
1684                     est->sc_repo_doorname != NULL ||
1685                     est->sc_in_emi == 1) {
1686                         r = refresh_running_snapshot(inst);
1687                         switch (r) {
1688                         case 0:
1689                                 continue;
1690 
1691                         case ECONNABORTED:
1692                         case ECANCELED:
1693                         case EPERM:
1694                         case ENOSPC:
1695                                 break;
1696                         default:
1697                                 bad_error("refresh_running_snapshot",
1698                                     scf_error());
1699                         }
1700 
1701                         return (r);
1702 
1703                 }
1704 
1705                 if (_smf_refresh_instance_i(inst) == 0) {
1706                         if (g_verbose) {
1707                                 if (scf_instance_get_name(inst, name_buf,
1708                                     max_scf_name_len + 1) < 0)
1709                                         (void) strcpy(name_buf, "?");
1710 
1711                                 warn(gettext("Refreshed %s:%s.\n"),
1712                                     fmri, name_buf);
1713                         }
1714                 } else {
1715                         if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1716                             g_verbose) {
1717                                 scfe = scf_error();
1718 
1719                                 if (scf_instance_to_fmri(inst, name_buf,
1720                                     max_scf_name_len + 1) < 0)
1721                                         (void) strcpy(name_buf, "?");
1722 
1723                                 warn(gettext(
1724                                     "Refresh of %s:%s failed: %s.\n"), fmri,
1725                                     name_buf, scf_strerror(scfe));
1726                         }
1727                 }
1728         }
1729 
1730         return (0);
1731 }
1732 
1733 static void
1734 private_refresh(void)
1735 {
1736         scf_instance_t *pinst = NULL;
1737         scf_iter_t *piter = NULL;
1738         ssize_t fmrilen;
1739         size_t bufsz;
1740         char *fmribuf;
1741         void *ent;
1742         int issvc;
1743         int r;
1744 
1745         if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1746                 return;
1747 
1748         assert(cur_svc != NULL);
1749 
1750         bufsz = max_scf_fmri_len + 1;
1751         fmribuf = safe_malloc(bufsz);
1752         if (cur_inst) {
1753                 issvc = 0;
1754                 ent = cur_inst;
1755                 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1756         } else {
1757                 issvc = 1;
1758                 ent = cur_svc;
1759                 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1760                 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1761                         scfdie();
1762 
1763                 if ((piter = scf_iter_create(g_hndl)) == NULL)
1764                         scfdie();
1765         }
1766         if (fmrilen < 0) {
1767                 free(fmribuf);
1768                 if (scf_error() != SCF_ERROR_DELETED)
1769                         scfdie();
1770 
1771                 warn(emsg_deleted);
1772                 return;
1773         }
1774         assert(fmrilen < bufsz);
1775 
1776         r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1777         switch (r) {
1778         case 0:
1779                 break;
1780 
1781         case ECONNABORTED:
1782                 warn(gettext("Could not refresh %s "
1783                     "(repository connection broken).\n"), fmribuf);
1784                 break;
1785 
1786         case ECANCELED:
1787                 warn(emsg_deleted);
1788                 break;
1789 
1790         case EPERM:
1791                 warn(gettext("Could not refresh %s "
1792                     "(permission denied).\n"), fmribuf);
1793                 break;
1794 
1795         case ENOSPC:
1796                 warn(gettext("Could not refresh %s "
1797                     "(repository server out of resources).\n"),
1798                     fmribuf);
1799                 break;
1800 
1801         case EACCES:
1802         default:
1803                 bad_error("refresh_entity", scf_error());
1804         }
1805 
1806         if (issvc) {
1807                 scf_instance_destroy(pinst);
1808                 scf_iter_destroy(piter);
1809         }
1810 
1811         free(fmribuf);
1812 }
1813 
1814 
1815 static int
1816 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1817 {
1818         cbp->sc_err = scferror2errno(err);
1819         return (UU_WALK_ERROR);
1820 }
1821 
1822 static int
1823 stash_scferror(scf_callback_t *cbp)
1824 {
1825         return (stash_scferror_err(cbp, scf_error()));
1826 }
1827 
1828 static int select_inst(const char *);
1829 static int select_svc(const char *);
1830 
1831 /*
1832  * Take a property that does not have a type and check to see if a type
1833  * exists or can be gleened from the current data.  Set the type.
1834  *
1835  * Check the current level (instance) and then check the higher level
1836  * (service).  This could be the case for adding a new property to
1837  * the instance that's going to "override" a service level property.
1838  *
1839  * For a property :
1840  * 1. Take the type from an existing property
1841  * 2. Take the type from a template entry
1842  *
1843  * If the type can not be found, then leave the type as is, and let the import
1844  * report the problem of the missing type.
1845  */
1846 static int
1847 find_current_prop_type(void *p, void *g)
1848 {
1849         property_t *prop = p;
1850         scf_callback_t *lcb = g;
1851         pgroup_t *pg = NULL;
1852 
1853         const char *fmri = NULL;
1854         char *lfmri = NULL;
1855         char *cur_selection = NULL;
1856 
1857         scf_propertygroup_t *sc_pg = NULL;
1858         scf_property_t *sc_prop = NULL;
1859         scf_pg_tmpl_t *t_pg = NULL;
1860         scf_prop_tmpl_t *t_prop = NULL;
1861         scf_type_t prop_type;
1862 
1863         value_t *vp;
1864         int issvc = lcb->sc_service;
1865         int r = UU_WALK_ERROR;
1866 
1867         if (prop->sc_value_type != SCF_TYPE_INVALID)
1868                 return (UU_WALK_NEXT);
1869 
1870         t_prop = scf_tmpl_prop_create(g_hndl);
1871         sc_prop = scf_property_create(g_hndl);
1872         if (sc_prop == NULL || t_prop == NULL) {
1873                 warn(gettext("Unable to create the property to attempt and "
1874                     "find a missing type.\n"));
1875 
1876                 scf_property_destroy(sc_prop);
1877                 scf_tmpl_prop_destroy(t_prop);
1878 
1879                 return (UU_WALK_ERROR);
1880         }
1881 
1882         if (lcb->sc_flags == 1) {
1883                 pg = lcb->sc_parent;
1884                 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1885                 fmri = pg->sc_parent->sc_fmri;
1886 retry_pg:
1887                 if (cur_svc && cur_selection == NULL) {
1888                         cur_selection = safe_malloc(max_scf_fmri_len + 1);
1889                         lscf_get_selection_str(cur_selection,
1890                             max_scf_fmri_len + 1);
1891 
1892                         if (strcmp(cur_selection, fmri) != 0) {
1893                                 lscf_select(fmri);
1894                         } else {
1895                                 free(cur_selection);
1896                                 cur_selection = NULL;
1897                         }
1898                 } else {
1899                         lscf_select(fmri);
1900                 }
1901 
1902                 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1903                         warn(gettext("Unable to create property group to "
1904                             "find a missing property type.\n"));
1905 
1906                         goto out;
1907                 }
1908 
1909                 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1910                         /*
1911                          * If this is the sc_pg from the parent
1912                          * let the caller clean up the sc_pg,
1913                          * and just throw it away in this case.
1914                          */
1915                         if (sc_pg != lcb->sc_parent)
1916                                 scf_pg_destroy(sc_pg);
1917 
1918                         sc_pg = NULL;
1919                         if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1920                                 warn(gettext("Unable to create template "
1921                                     "property group to find a property "
1922                                     "type.\n"));
1923 
1924                                 goto out;
1925                         }
1926 
1927                         if (scf_tmpl_get_by_pg_name(fmri, NULL,
1928                             pg->sc_pgroup_name, NULL, t_pg,
1929                             SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1930                                 /*
1931                                  * if instance get service and jump back
1932                                  */
1933                                 scf_tmpl_pg_destroy(t_pg);
1934                                 t_pg = NULL;
1935                                 if (issvc == 0) {
1936                                         entity_t *e = pg->sc_parent->sc_parent;
1937 
1938                                         fmri = e->sc_fmri;
1939                                         issvc = 1;
1940                                         goto retry_pg;
1941                                 } else {
1942                                         goto out;
1943                                 }
1944                         }
1945                 }
1946         } else {
1947                 sc_pg = lcb->sc_parent;
1948         }
1949 
1950         /*
1951          * Attempt to get the type from an existing property.  If the property
1952          * cannot be found then attempt to get the type from a template entry
1953          * for the property.
1954          *
1955          * Finally, if at the instance level look at the service level.
1956          */
1957         if (sc_pg != NULL &&
1958             pg_get_prop(sc_pg, prop->sc_property_name,
1959             sc_prop) == SCF_SUCCESS &&
1960             scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1961                 prop->sc_value_type = prop_type;
1962 
1963                 /*
1964                  * Found a type, update the value types and validate
1965                  * the actual value against this type.
1966                  */
1967                 for (vp = uu_list_first(prop->sc_property_values);
1968                     vp != NULL;
1969                     vp = uu_list_next(prop->sc_property_values, vp)) {
1970                         vp->sc_type = prop->sc_value_type;
1971                         lxml_store_value(vp, 0, NULL);
1972                 }
1973 
1974                 r = UU_WALK_NEXT;
1975                 goto out;
1976         }
1977 
1978         /*
1979          * If we get here with t_pg set to NULL then we had to have
1980          * gotten an sc_pg but that sc_pg did not have the property
1981          * we are looking for.   So if the t_pg is not null look up
1982          * the template entry for the property.
1983          *
1984          * If the t_pg is null then need to attempt to get a matching
1985          * template entry for the sc_pg, and see if there is a property
1986          * entry for that template entry.
1987          */
1988 do_tmpl :
1989         if (t_pg != NULL &&
1990             scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1991             t_prop, 0) == SCF_SUCCESS) {
1992                 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1993                         prop->sc_value_type = prop_type;
1994 
1995                         /*
1996                          * Found a type, update the value types and validate
1997                          * the actual value against this type.
1998                          */
1999                         for (vp = uu_list_first(prop->sc_property_values);
2000                             vp != NULL;
2001                             vp = uu_list_next(prop->sc_property_values, vp)) {
2002                                 vp->sc_type = prop->sc_value_type;
2003                                 lxml_store_value(vp, 0, NULL);
2004                         }
2005 
2006                         r = UU_WALK_NEXT;
2007                         goto out;
2008                 }
2009         } else {
2010                 if (t_pg == NULL && sc_pg) {
2011                         if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2012                                 warn(gettext("Unable to create template "
2013                                     "property group to find a property "
2014                                     "type.\n"));
2015 
2016                                 goto out;
2017                         }
2018 
2019                         if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2020                                 scf_tmpl_pg_destroy(t_pg);
2021                                 t_pg = NULL;
2022                         } else {
2023                                 goto do_tmpl;
2024                         }
2025                 }
2026         }
2027 
2028         if (issvc == 0) {
2029                 scf_instance_t *i;
2030                 scf_service_t *s;
2031 
2032                 issvc = 1;
2033                 if (lcb->sc_flags == 1) {
2034                         entity_t *e = pg->sc_parent->sc_parent;
2035 
2036                         fmri = e->sc_fmri;
2037                         goto retry_pg;
2038                 }
2039 
2040                 /*
2041                  * because lcb->sc_flags was not set then this means
2042                  * the pg was not used and can be used here.
2043                  */
2044                 if ((pg = internal_pgroup_new()) == NULL) {
2045                         warn(gettext("Could not create internal property group "
2046                             "to find a missing type."));
2047 
2048                         goto out;
2049                 }
2050 
2051                 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2052                 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2053                     max_scf_name_len + 1) < 0)
2054                                 goto out;
2055 
2056                 i = scf_instance_create(g_hndl);
2057                 s = scf_service_create(g_hndl);
2058                 if (i == NULL || s == NULL ||
2059                     scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2060                         warn(gettext("Could not get a service for the instance "
2061                             "to find a missing type."));
2062 
2063                         goto out;
2064                 }
2065 
2066                 /*
2067                  * Check to see truly at the instance level.
2068                  */
2069                 lfmri = safe_malloc(max_scf_fmri_len + 1);
2070                 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2071                     scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2072                         goto out;
2073                 else
2074                         fmri = (const char *)lfmri;
2075 
2076                 goto retry_pg;
2077         }
2078 
2079 out :
2080         if (sc_pg != lcb->sc_parent) {
2081                 scf_pg_destroy(sc_pg);
2082         }
2083 
2084         /*
2085          * If this is true then the pg was allocated
2086          * here, and the name was set so need to free
2087          * the name and the pg.
2088          */
2089         if (pg != NULL && pg != lcb->sc_parent) {
2090                 free((char *)pg->sc_pgroup_name);
2091                 internal_pgroup_free(pg);
2092         }
2093 
2094         if (cur_selection) {
2095                 lscf_select(cur_selection);
2096                 free(cur_selection);
2097         }
2098 
2099         scf_tmpl_pg_destroy(t_pg);
2100         scf_tmpl_prop_destroy(t_prop);
2101         scf_property_destroy(sc_prop);
2102 
2103         if (r != UU_WALK_NEXT)
2104                 warn(gettext("Could not find property type for \"%s\" "
2105                     "from \"%s\"\n"), prop->sc_property_name,
2106                     fmri != NULL ? fmri : lcb->sc_source_fmri);
2107 
2108         free(lfmri);
2109 
2110         return (r);
2111 }
2112 
2113 /*
2114  * Take a property group that does not have a type and check to see if a type
2115  * exists or can be gleened from the current data.  Set the type.
2116  *
2117  * Check the current level (instance) and then check the higher level
2118  * (service).  This could be the case for adding a new property to
2119  * the instance that's going to "override" a service level property.
2120  *
2121  * For a property group
2122  * 1. Take the type from an existing property group
2123  * 2. Take the type from a template entry
2124  *
2125  * If the type can not be found, then leave the type as is, and let the import
2126  * report the problem of the missing type.
2127  */
2128 static int
2129 find_current_pg_type(void *p, void *sori)
2130 {
2131         entity_t *si = sori;
2132         pgroup_t *pg = p;
2133 
2134         const char *ofmri, *fmri;
2135         char *cur_selection = NULL;
2136         char *pg_type = NULL;
2137 
2138         scf_propertygroup_t *sc_pg = NULL;
2139         scf_pg_tmpl_t *t_pg = NULL;
2140 
2141         int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2142         int r = UU_WALK_ERROR;
2143 
2144         ofmri = fmri = si->sc_fmri;
2145         if (pg->sc_pgroup_type != NULL) {
2146                 r = UU_WALK_NEXT;
2147 
2148                 goto out;
2149         }
2150 
2151         sc_pg = scf_pg_create(g_hndl);
2152         if (sc_pg == NULL) {
2153                 warn(gettext("Unable to create property group to attempt "
2154                     "and find a missing type.\n"));
2155 
2156                 return (UU_WALK_ERROR);
2157         }
2158 
2159         /*
2160          * Using get_pg() requires that the cur_svc/cur_inst be
2161          * via lscf_select.  Need to preserve the current selection
2162          * if going to use lscf_select() to set up the cur_svc/cur_inst
2163          */
2164         if (cur_svc) {
2165                 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2166                 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2167         }
2168 
2169         /*
2170          * If the property group exists get the type, and set
2171          * the pgroup_t type of that type.
2172          *
2173          * If not the check for a template pg_pattern entry
2174          * and take the type from that.
2175          */
2176 retry_svc:
2177         lscf_select(fmri);
2178 
2179         if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2180                 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2181                 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2182                     max_scf_pg_type_len + 1) != -1) {
2183                         pg->sc_pgroup_type = pg_type;
2184 
2185                         r = UU_WALK_NEXT;
2186                         goto out;
2187                 } else {
2188                         free(pg_type);
2189                 }
2190         } else {
2191                 if ((t_pg == NULL) &&
2192                     (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2193                         goto out;
2194 
2195                 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2196                     NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2197                     scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2198                         pg->sc_pgroup_type = pg_type;
2199 
2200                         r = UU_WALK_NEXT;
2201                         goto out;
2202                 }
2203         }
2204 
2205         /*
2206          * If type is not found at the instance level then attempt to
2207          * find the type at the service level.
2208          */
2209         if (!issvc) {
2210                 si = si->sc_parent;
2211                 fmri = si->sc_fmri;
2212                 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2213                 goto retry_svc;
2214         }
2215 
2216 out :
2217         if (cur_selection) {
2218                 lscf_select(cur_selection);
2219                 free(cur_selection);
2220         }
2221 
2222         /*
2223          * Now walk the properties of the property group to make sure that
2224          * all properties have the correct type and values are valid for
2225          * those types.
2226          */
2227         if (r == UU_WALK_NEXT) {
2228                 scf_callback_t cb;
2229 
2230                 cb.sc_service = issvc;
2231                 cb.sc_source_fmri = ofmri;
2232                 if (sc_pg != NULL) {
2233                         cb.sc_parent = sc_pg;
2234                         cb.sc_flags = 0;
2235                 } else {
2236                         cb.sc_parent = pg;
2237                         cb.sc_flags = 1;
2238                 }
2239 
2240                 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2241                     &cb, UU_DEFAULT) != 0) {
2242                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2243                                 bad_error("uu_list_walk", uu_error());
2244 
2245                         r = UU_WALK_ERROR;
2246                 }
2247         } else {
2248                 warn(gettext("Could not find property group type for "
2249                     "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2250         }
2251 
2252         scf_tmpl_pg_destroy(t_pg);
2253         scf_pg_destroy(sc_pg);
2254 
2255         return (r);
2256 }
2257 
2258 /*
2259  * Import.  These functions import a bundle into the repository.
2260  */
2261 
2262 /*
2263  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2264  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2265  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2266  * lcbdata->sc_err to
2267  *   ENOMEM - out of memory
2268  *   ECONNABORTED - repository connection broken
2269  *   ECANCELED - sc_trans's property group was deleted
2270  *   EINVAL - p's name is invalid (error printed)
2271  *          - p has an invalid value (error printed)
2272  */
2273 static int
2274 lscf_property_import(void *v, void *pvt)
2275 {
2276         property_t *p = v;
2277         scf_callback_t *lcbdata = pvt;
2278         value_t *vp;
2279         scf_transaction_t *trans = lcbdata->sc_trans;
2280         scf_transaction_entry_t *entr;
2281         scf_value_t *val;
2282         scf_type_t tp;
2283 
2284         if ((lcbdata->sc_flags & SCI_NOENABLED ||
2285             lcbdata->sc_flags & SCI_DELAYENABLE) &&
2286             strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2287                 lcbdata->sc_enable = p;
2288                 return (UU_WALK_NEXT);
2289         }
2290 
2291         entr = scf_entry_create(lcbdata->sc_handle);
2292         if (entr == NULL) {
2293                 switch (scf_error()) {
2294                 case SCF_ERROR_NO_MEMORY:
2295                         return (stash_scferror(lcbdata));
2296 
2297                 case SCF_ERROR_INVALID_ARGUMENT:
2298                 default:
2299                         bad_error("scf_entry_create", scf_error());
2300                 }
2301         }
2302 
2303         tp = p->sc_value_type;
2304 
2305         if (scf_transaction_property_new(trans, entr,
2306             p->sc_property_name, tp) != 0) {
2307                 switch (scf_error()) {
2308                 case SCF_ERROR_INVALID_ARGUMENT:
2309                         semerr(emsg_invalid_prop_name, p->sc_property_name);
2310                         scf_entry_destroy(entr);
2311                         return (stash_scferror(lcbdata));
2312 
2313                 case SCF_ERROR_EXISTS:
2314                         break;
2315 
2316                 case SCF_ERROR_DELETED:
2317                 case SCF_ERROR_CONNECTION_BROKEN:
2318                         scf_entry_destroy(entr);
2319                         return (stash_scferror(lcbdata));
2320 
2321                 case SCF_ERROR_NOT_BOUND:
2322                 case SCF_ERROR_HANDLE_MISMATCH:
2323                 case SCF_ERROR_NOT_SET:
2324                 default:
2325                         bad_error("scf_transaction_property_new", scf_error());
2326                 }
2327 
2328                 if (scf_transaction_property_change_type(trans, entr,
2329                     p->sc_property_name, tp) != 0) {
2330                         switch (scf_error()) {
2331                         case SCF_ERROR_DELETED:
2332                         case SCF_ERROR_CONNECTION_BROKEN:
2333                                 scf_entry_destroy(entr);
2334                                 return (stash_scferror(lcbdata));
2335 
2336                         case SCF_ERROR_INVALID_ARGUMENT:
2337                                 semerr(emsg_invalid_prop_name,
2338                                     p->sc_property_name);
2339                                 scf_entry_destroy(entr);
2340                                 return (stash_scferror(lcbdata));
2341 
2342                         case SCF_ERROR_NOT_FOUND:
2343                         case SCF_ERROR_NOT_SET:
2344                         case SCF_ERROR_HANDLE_MISMATCH:
2345                         case SCF_ERROR_NOT_BOUND:
2346                         default:
2347                                 bad_error(
2348                                     "scf_transaction_property_change_type",
2349                                     scf_error());
2350                         }
2351                 }
2352         }
2353 
2354         for (vp = uu_list_first(p->sc_property_values);
2355             vp != NULL;
2356             vp = uu_list_next(p->sc_property_values, vp)) {
2357                 val = scf_value_create(g_hndl);
2358                 if (val == NULL) {
2359                         switch (scf_error()) {
2360                         case SCF_ERROR_NO_MEMORY:
2361                                 return (stash_scferror(lcbdata));
2362 
2363                         case SCF_ERROR_INVALID_ARGUMENT:
2364                         default:
2365                                 bad_error("scf_value_create", scf_error());
2366                         }
2367                 }
2368 
2369                 switch (tp) {
2370                 case SCF_TYPE_BOOLEAN:
2371                         scf_value_set_boolean(val, vp->sc_u.sc_count);
2372                         break;
2373                 case SCF_TYPE_COUNT:
2374                         scf_value_set_count(val, vp->sc_u.sc_count);
2375                         break;
2376                 case SCF_TYPE_INTEGER:
2377                         scf_value_set_integer(val, vp->sc_u.sc_integer);
2378                         break;
2379                 default:
2380                         assert(vp->sc_u.sc_string != NULL);
2381                         if (scf_value_set_from_string(val, tp,
2382                             vp->sc_u.sc_string) != 0) {
2383                                 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2384                                         bad_error("scf_value_set_from_string",
2385                                             scf_error());
2386 
2387                                 warn(gettext("Value \"%s\" is not a valid "
2388                                     "%s.\n"), vp->sc_u.sc_string,
2389                                     scf_type_to_string(tp));
2390                                 scf_value_destroy(val);
2391                                 return (stash_scferror(lcbdata));
2392                         }
2393                         break;
2394                 }
2395 
2396                 if (scf_entry_add_value(entr, val) != 0)
2397                         bad_error("scf_entry_add_value", scf_error());
2398         }
2399 
2400         return (UU_WALK_NEXT);
2401 }
2402 
2403 /*
2404  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2405  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2406  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2407  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2408  * lcbdata->sc_err to
2409  *   ECONNABORTED - repository connection broken
2410  *   ENOMEM - out of memory
2411  *   ENOSPC - svc.configd is out of resources
2412  *   ECANCELED - sc_parent was deleted
2413  *   EPERM - could not create property group (permission denied) (error printed)
2414  *         - could not modify property group (permission denied) (error printed)
2415  *         - could not delete property group (permission denied) (error printed)
2416  *   EROFS - could not create property group (repository is read-only)
2417  *         - could not delete property group (repository is read-only)
2418  *   EACCES - could not create property group (backend access denied)
2419  *          - could not delete property group (backend access denied)
2420  *   EEXIST - could not create property group (already exists)
2421  *   EINVAL - invalid property group name (error printed)
2422  *          - invalid property name (error printed)
2423  *          - invalid value (error printed)
2424  *   EBUSY - new property group deleted (error printed)
2425  *         - new property group changed (error printed)
2426  *         - property group added (error printed)
2427  *         - property group deleted (error printed)
2428  */
2429 static int
2430 entity_pgroup_import(void *v, void *pvt)
2431 {
2432         pgroup_t *p = v;
2433         scf_callback_t cbdata;
2434         scf_callback_t *lcbdata = pvt;
2435         void *ent = lcbdata->sc_parent;
2436         int issvc = lcbdata->sc_service;
2437         int r;
2438 
2439         const char * const pg_changed = gettext("%s changed unexpectedly "
2440             "(new property group \"%s\" changed).\n");
2441 
2442         /* Never import deleted property groups. */
2443         if (p->sc_pgroup_delete) {
2444                 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2445                     entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2446                         goto delete_pg;
2447                 }
2448                 return (UU_WALK_NEXT);
2449         }
2450 
2451         if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2452             strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2453                 lcbdata->sc_general = p;
2454                 return (UU_WALK_NEXT);
2455         }
2456 
2457 add_pg:
2458         if (issvc)
2459                 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2460                     p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2461         else
2462                 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2463                     p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2464         if (r != 0) {
2465                 switch (scf_error()) {
2466                 case SCF_ERROR_DELETED:
2467                 case SCF_ERROR_CONNECTION_BROKEN:
2468                 case SCF_ERROR_BACKEND_READONLY:
2469                 case SCF_ERROR_BACKEND_ACCESS:
2470                 case SCF_ERROR_NO_RESOURCES:
2471                         return (stash_scferror(lcbdata));
2472 
2473                 case SCF_ERROR_EXISTS:
2474                         if (lcbdata->sc_flags & SCI_FORCE)
2475                                 break;
2476                         return (stash_scferror(lcbdata));
2477 
2478                 case SCF_ERROR_INVALID_ARGUMENT:
2479                         warn(emsg_fmri_invalid_pg_name_type,
2480                             lcbdata->sc_source_fmri,
2481                             p->sc_pgroup_name, p->sc_pgroup_type);
2482                         return (stash_scferror(lcbdata));
2483 
2484                 case SCF_ERROR_PERMISSION_DENIED:
2485                         warn(emsg_pg_add_perm, p->sc_pgroup_name,
2486                             lcbdata->sc_target_fmri);
2487                         return (stash_scferror(lcbdata));
2488 
2489                 case SCF_ERROR_NOT_BOUND:
2490                 case SCF_ERROR_HANDLE_MISMATCH:
2491                 case SCF_ERROR_NOT_SET:
2492                 default:
2493                         bad_error("scf_service_add_pg", scf_error());
2494                 }
2495 
2496                 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2497                         switch (scf_error()) {
2498                         case SCF_ERROR_CONNECTION_BROKEN:
2499                         case SCF_ERROR_DELETED:
2500                                 return (stash_scferror(lcbdata));
2501 
2502                         case SCF_ERROR_INVALID_ARGUMENT:
2503                                 warn(emsg_fmri_invalid_pg_name,
2504                                     lcbdata->sc_source_fmri,
2505                                     p->sc_pgroup_name);
2506                                 return (stash_scferror(lcbdata));
2507 
2508                         case SCF_ERROR_NOT_FOUND:
2509                                 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2510                                     p->sc_pgroup_name);
2511                                 lcbdata->sc_err = EBUSY;
2512                                 return (UU_WALK_ERROR);
2513 
2514                         case SCF_ERROR_NOT_BOUND:
2515                         case SCF_ERROR_HANDLE_MISMATCH:
2516                         case SCF_ERROR_NOT_SET:
2517                         default:
2518                                 bad_error("entity_get_pg", scf_error());
2519                         }
2520                 }
2521 
2522                 if (lcbdata->sc_flags & SCI_KEEP)
2523                         goto props;
2524 
2525 delete_pg:
2526                 if (scf_pg_delete(imp_pg) != 0) {
2527                         switch (scf_error()) {
2528                         case SCF_ERROR_DELETED:
2529                                 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2530                                     p->sc_pgroup_name);
2531                                 lcbdata->sc_err = EBUSY;
2532                                 return (UU_WALK_ERROR);
2533 
2534                         case SCF_ERROR_PERMISSION_DENIED:
2535                                 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2536                                     lcbdata->sc_target_fmri);
2537                                 return (stash_scferror(lcbdata));
2538 
2539                         case SCF_ERROR_BACKEND_READONLY:
2540                         case SCF_ERROR_BACKEND_ACCESS:
2541                         case SCF_ERROR_CONNECTION_BROKEN:
2542                                 return (stash_scferror(lcbdata));
2543 
2544                         case SCF_ERROR_NOT_SET:
2545                         default:
2546                                 bad_error("scf_pg_delete", scf_error());
2547                         }
2548                 }
2549 
2550                 if (p->sc_pgroup_delete)
2551                         return (UU_WALK_NEXT);
2552 
2553                 goto add_pg;
2554         }
2555 
2556 props:
2557 
2558         /*
2559          * Add properties to property group, if any.
2560          */
2561         cbdata.sc_handle = lcbdata->sc_handle;
2562         cbdata.sc_parent = imp_pg;
2563         cbdata.sc_flags = lcbdata->sc_flags;
2564         cbdata.sc_trans = imp_tx;
2565         cbdata.sc_enable = NULL;
2566 
2567         if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2568                 switch (scf_error()) {
2569                 case SCF_ERROR_BACKEND_ACCESS:
2570                 case SCF_ERROR_BACKEND_READONLY:
2571                 case SCF_ERROR_CONNECTION_BROKEN:
2572                         return (stash_scferror(lcbdata));
2573 
2574                 case SCF_ERROR_DELETED:
2575                         warn(pg_changed, lcbdata->sc_target_fmri,
2576                             p->sc_pgroup_name);
2577                         lcbdata->sc_err = EBUSY;
2578                         return (UU_WALK_ERROR);
2579 
2580                 case SCF_ERROR_PERMISSION_DENIED:
2581                         warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2582                             lcbdata->sc_target_fmri);
2583                         return (stash_scferror(lcbdata));
2584 
2585                 case SCF_ERROR_NOT_BOUND:
2586                 case SCF_ERROR_NOT_SET:
2587                 case SCF_ERROR_IN_USE:
2588                 case SCF_ERROR_HANDLE_MISMATCH:
2589                 default:
2590                         bad_error("scf_transaction_start", scf_error());
2591                 }
2592         }
2593 
2594         if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2595             UU_DEFAULT) != 0) {
2596                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2597                         bad_error("uu_list_walk", uu_error());
2598                 scf_transaction_reset(imp_tx);
2599 
2600                 lcbdata->sc_err = cbdata.sc_err;
2601                 if (cbdata.sc_err == ECANCELED) {
2602                         warn(pg_changed, lcbdata->sc_target_fmri,
2603                             p->sc_pgroup_name);
2604                         lcbdata->sc_err = EBUSY;
2605                 }
2606                 return (UU_WALK_ERROR);
2607         }
2608 
2609         if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2610                 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2611 
2612                 /*
2613                  * take the snapshot running snapshot then
2614                  * import the stored general/enable property
2615                  */
2616                 r = take_snap(ent, snap_running, imp_rsnap);
2617                 switch (r) {
2618                 case 0:
2619                         break;
2620 
2621                 case ECONNABORTED:
2622                         warn(gettext("Could not take %s snapshot on import "
2623                             "(repository connection broken).\n"),
2624                             snap_running);
2625                         lcbdata->sc_err = r;
2626                         return (UU_WALK_ERROR);
2627                 case ECANCELED:
2628                         warn(emsg_deleted);
2629                         lcbdata->sc_err = r;
2630                         return (UU_WALK_ERROR);
2631 
2632                 case EPERM:
2633                         warn(gettext("Could not take %s snapshot "
2634                             "(permission denied).\n"), snap_running);
2635                         lcbdata->sc_err = r;
2636                         return (UU_WALK_ERROR);
2637 
2638                 case ENOSPC:
2639                         warn(gettext("Could not take %s snapshot"
2640                             "(repository server out of resources).\n"),
2641                             snap_running);
2642                         lcbdata->sc_err = r;
2643                         return (UU_WALK_ERROR);
2644 
2645                 default:
2646                         bad_error("take_snap", r);
2647                 }
2648 
2649                 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2650                 if (r != UU_WALK_NEXT) {
2651                         if (r != UU_WALK_ERROR)
2652                                 bad_error("lscf_property_import", r);
2653                         return (EINVAL);
2654                 }
2655         }
2656 
2657         r = scf_transaction_commit(imp_tx);
2658         switch (r) {
2659         case 1:
2660                 r = UU_WALK_NEXT;
2661                 break;
2662 
2663         case 0:
2664                 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2665                 lcbdata->sc_err = EBUSY;
2666                 r = UU_WALK_ERROR;
2667                 break;
2668 
2669         case -1:
2670                 switch (scf_error()) {
2671                 case SCF_ERROR_BACKEND_READONLY:
2672                 case SCF_ERROR_BACKEND_ACCESS:
2673                 case SCF_ERROR_CONNECTION_BROKEN:
2674                 case SCF_ERROR_NO_RESOURCES:
2675                         r = stash_scferror(lcbdata);
2676                         break;
2677 
2678                 case SCF_ERROR_DELETED:
2679                         warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2680                             p->sc_pgroup_name);
2681                         lcbdata->sc_err = EBUSY;
2682                         r = UU_WALK_ERROR;
2683                         break;
2684 
2685                 case SCF_ERROR_PERMISSION_DENIED:
2686                         warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2687                             lcbdata->sc_target_fmri);
2688                         r = stash_scferror(lcbdata);
2689                         break;
2690 
2691                 case SCF_ERROR_NOT_SET:
2692                 case SCF_ERROR_INVALID_ARGUMENT:
2693                 case SCF_ERROR_NOT_BOUND:
2694                 default:
2695                         bad_error("scf_transaction_commit", scf_error());
2696                 }
2697                 break;
2698 
2699         default:
2700                 bad_error("scf_transaction_commit", r);
2701         }
2702 
2703         scf_transaction_destroy_children(imp_tx);
2704 
2705         return (r);
2706 }
2707 
2708 /*
2709  * Returns
2710  *   0 - success
2711  *   ECONNABORTED - repository connection broken
2712  *   ENOMEM - out of memory
2713  *   ENOSPC - svc.configd is out of resources
2714  *   ECANCELED - inst was deleted
2715  *   EPERM - could not create property group (permission denied) (error printed)
2716  *         - could not modify property group (permission denied) (error printed)
2717  *   EROFS - could not create property group (repository is read-only)
2718  *   EACCES - could not create property group (backend access denied)
2719  *   EEXIST - could not create property group (already exists)
2720  *   EINVAL - invalid property group name (error printed)
2721  *          - invalid property name (error printed)
2722  *          - invalid value (error printed)
2723  *   EBUSY - new property group changed (error printed)
2724  */
2725 static int
2726 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2727     const entity_t *isvc, int flags)
2728 {
2729         scf_callback_t cbdata;
2730 
2731         cbdata.sc_handle = scf_service_handle(svc);
2732         cbdata.sc_parent = svc;
2733         cbdata.sc_service = 1;
2734         cbdata.sc_general = 0;
2735         cbdata.sc_enable = 0;
2736         cbdata.sc_flags = flags;
2737         cbdata.sc_source_fmri = isvc->sc_fmri;
2738         cbdata.sc_target_fmri = target_fmri;
2739 
2740         /*
2741          * If the op is set, then add the flag to the callback
2742          * flags for later use.
2743          */
2744         if (isvc->sc_op != SVCCFG_OP_NONE) {
2745                 switch (isvc->sc_op) {
2746                 case SVCCFG_OP_IMPORT :
2747                         cbdata.sc_flags |= SCI_OP_IMPORT;
2748                         break;
2749                 case SVCCFG_OP_APPLY :
2750                         cbdata.sc_flags |= SCI_OP_APPLY;
2751                         break;
2752                 case SVCCFG_OP_RESTORE :
2753                         cbdata.sc_flags |= SCI_OP_RESTORE;
2754                         break;
2755                 default :
2756                         uu_die(gettext("lscf_import_service_pgs : "
2757                             "Unknown op stored in the service entity\n"));
2758 
2759                 }
2760         }
2761 
2762         if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2763             UU_DEFAULT) != 0) {
2764                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2765                         bad_error("uu_list_walk", uu_error());
2766 
2767                 return (cbdata.sc_err);
2768         }
2769 
2770         return (0);
2771 }
2772 
2773 /*
2774  * Returns
2775  *   0 - success
2776  *   ECONNABORTED - repository connection broken
2777  *   ENOMEM - out of memory
2778  *   ENOSPC - svc.configd is out of resources
2779  *   ECANCELED - inst was deleted
2780  *   EPERM - could not create property group (permission denied) (error printed)
2781  *         - could not modify property group (permission denied) (error printed)
2782  *   EROFS - could not create property group (repository is read-only)
2783  *   EACCES - could not create property group (backend access denied)
2784  *   EEXIST - could not create property group (already exists)
2785  *   EINVAL - invalid property group name (error printed)
2786  *          - invalid property name (error printed)
2787  *          - invalid value (error printed)
2788  *   EBUSY - new property group changed (error printed)
2789  */
2790 static int
2791 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2792     const entity_t *iinst, int flags)
2793 {
2794         scf_callback_t cbdata;
2795 
2796         cbdata.sc_handle = scf_instance_handle(inst);
2797         cbdata.sc_parent = inst;
2798         cbdata.sc_service = 0;
2799         cbdata.sc_general = NULL;
2800         cbdata.sc_enable = NULL;
2801         cbdata.sc_flags = flags;
2802         cbdata.sc_source_fmri = iinst->sc_fmri;
2803         cbdata.sc_target_fmri = target_fmri;
2804 
2805         /*
2806          * If the op is set, then add the flag to the callback
2807          * flags for later use.
2808          */
2809         if (iinst->sc_op != SVCCFG_OP_NONE) {
2810                 switch (iinst->sc_op) {
2811                 case SVCCFG_OP_IMPORT :
2812                         cbdata.sc_flags |= SCI_OP_IMPORT;
2813                         break;
2814                 case SVCCFG_OP_APPLY :
2815                         cbdata.sc_flags |= SCI_OP_APPLY;
2816                         break;
2817                 case SVCCFG_OP_RESTORE :
2818                         cbdata.sc_flags |= SCI_OP_RESTORE;
2819                         break;
2820                 default :
2821                         uu_die(gettext("lscf_import_instance_pgs : "
2822                             "Unknown op stored in the instance entity\n"));
2823                 }
2824         }
2825 
2826         if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2827             UU_DEFAULT) != 0) {
2828                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2829                         bad_error("uu_list_walk", uu_error());
2830 
2831                 return (cbdata.sc_err);
2832         }
2833 
2834         if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2835                 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2836                 /*
2837                  * If importing with the SCI_NOENABLED flag then
2838                  * skip the delay, but if not then add the delay
2839                  * of the enable property.
2840                  */
2841                 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2842                         cbdata.sc_flags |= SCI_DELAYENABLE;
2843                 }
2844 
2845                 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2846                     != UU_WALK_NEXT)
2847                         return (cbdata.sc_err);
2848         }
2849 
2850         return (0);
2851 }
2852 
2853 /*
2854  * Report the reasons why we can't upgrade pg2 to pg1.
2855  */
2856 static void
2857 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2858     int new)
2859 {
2860         property_t *p1, *p2;
2861 
2862         assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2863 
2864         if (!pg_attrs_equal(pg1, pg2, fmri, new))
2865                 return;
2866 
2867         for (p1 = uu_list_first(pg1->sc_pgroup_props);
2868             p1 != NULL;
2869             p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2870                 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2871                 if (p2 != NULL) {
2872                         (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2873                             new);
2874                         continue;
2875                 }
2876 
2877                 if (new)
2878                         warn(gettext("Conflict upgrading %s (new property "
2879                             "group \"%s\" is missing property \"%s\").\n"),
2880                             fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2881                 else
2882                         warn(gettext("Conflict upgrading %s (property "
2883                             "\"%s/%s\" is missing).\n"), fmri,
2884                             pg1->sc_pgroup_name, p1->sc_property_name);
2885         }
2886 
2887         /*
2888          * Since pg1 should be from the manifest, any properties in pg2 which
2889          * aren't in pg1 shouldn't be reported as conflicts.
2890          */
2891 }
2892 
2893 /*
2894  * Add transaction entries to tx which will upgrade cur's pg according to old
2895  * & new.
2896  *
2897  * Returns
2898  *   0 - success
2899  *   EINVAL - new has a property with an invalid name or value (message emitted)
2900  *   ENOMEM - out of memory
2901  */
2902 static int
2903 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2904     pgroup_t *cur, int speak, const char *fmri)
2905 {
2906         property_t *p, *new_p, *cur_p;
2907         scf_transaction_entry_t *e;
2908         int r;
2909         int is_general;
2910         int is_protected;
2911 
2912         if (uu_list_walk(new->sc_pgroup_props, clear_int,
2913             (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2914                 bad_error("uu_list_walk", uu_error());
2915 
2916         is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2917 
2918         for (p = uu_list_first(old->sc_pgroup_props);
2919             p != NULL;
2920             p = uu_list_next(old->sc_pgroup_props, p)) {
2921                 /* p is a property in the old property group. */
2922 
2923                 /* Protect live properties. */
2924                 is_protected = 0;
2925                 if (is_general) {
2926                         if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2927                             0 ||
2928                             strcmp(p->sc_property_name,
2929                             SCF_PROPERTY_RESTARTER) == 0)
2930                                 is_protected = 1;
2931                 }
2932 
2933                 /* Look for the same property in the new properties. */
2934                 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2935                 if (new_p != NULL) {
2936                         new_p->sc_seen = 1;
2937 
2938                         /*
2939                          * If the new property is the same as the old, don't do
2940                          * anything (leave any user customizations).
2941                          */
2942                         if (prop_equal(p, new_p, NULL, NULL, 0))
2943                                 continue;
2944 
2945                         if (new_p->sc_property_override)
2946                                 goto upgrade;
2947                 }
2948 
2949                 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2950                 if (cur_p == NULL) {
2951                         /*
2952                          * p has been deleted from the repository.  If we were
2953                          * going to delete it anyway, do nothing.  Otherwise
2954                          * report a conflict.
2955                          */
2956                         if (new_p == NULL)
2957                                 continue;
2958 
2959                         if (is_protected)
2960                                 continue;
2961 
2962                         warn(gettext("Conflict upgrading %s "
2963                             "(property \"%s/%s\" is missing).\n"), fmri,
2964                             old->sc_pgroup_name, p->sc_property_name);
2965                         continue;
2966                 }
2967 
2968                 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2969                         /*
2970                          * Conflict.  Don't warn if the property is already the
2971                          * way we want it, though.
2972                          */
2973                         if (is_protected)
2974                                 continue;
2975 
2976                         if (new_p == NULL)
2977                                 (void) prop_equal(p, cur_p, fmri,
2978                                     old->sc_pgroup_name, 0);
2979                         else
2980                                 (void) prop_equal(cur_p, new_p, fmri,
2981                                     old->sc_pgroup_name, 0);
2982                         continue;
2983                 }
2984 
2985                 if (is_protected) {
2986                         if (speak)
2987                                 warn(gettext("%s: Refusing to upgrade "
2988                                     "\"%s/%s\" (live property).\n"), fmri,
2989                                     old->sc_pgroup_name, p->sc_property_name);
2990                         continue;
2991                 }
2992 
2993 upgrade:
2994                 /* p hasn't been customized in the repository.  Upgrade it. */
2995                 if (new_p == NULL) {
2996                         /* p was deleted.  Delete from cur if unchanged. */
2997                         if (speak)
2998                                 warn(gettext(
2999                                     "%s: Deleting property \"%s/%s\".\n"),
3000                                     fmri, old->sc_pgroup_name,
3001                                     p->sc_property_name);
3002 
3003                         e = scf_entry_create(g_hndl);
3004                         if (e == NULL)
3005                                 return (ENOMEM);
3006 
3007                         if (scf_transaction_property_delete(tx, e,
3008                             p->sc_property_name) != 0) {
3009                                 switch (scf_error()) {
3010                                 case SCF_ERROR_DELETED:
3011                                         scf_entry_destroy(e);
3012                                         return (ECANCELED);
3013 
3014                                 case SCF_ERROR_CONNECTION_BROKEN:
3015                                         scf_entry_destroy(e);
3016                                         return (ECONNABORTED);
3017 
3018                                 case SCF_ERROR_NOT_FOUND:
3019                                         /*
3020                                          * This can happen if cur is from the
3021                                          * running snapshot (and it differs
3022                                          * from the live properties).
3023                                          */
3024                                         scf_entry_destroy(e);
3025                                         break;
3026 
3027                                 case SCF_ERROR_HANDLE_MISMATCH:
3028                                 case SCF_ERROR_NOT_BOUND:
3029                                 case SCF_ERROR_NOT_SET:
3030                                 case SCF_ERROR_INVALID_ARGUMENT:
3031                                 default:
3032                                         bad_error(
3033                                             "scf_transaction_property_delete",
3034                                             scf_error());
3035                                 }
3036                         }
3037                 } else {
3038                         scf_callback_t ctx;
3039 
3040                         if (speak)
3041                                 warn(gettext(
3042                                     "%s: Upgrading property \"%s/%s\".\n"),
3043                                     fmri, old->sc_pgroup_name,
3044                                     p->sc_property_name);
3045 
3046                         ctx.sc_handle = g_hndl;
3047                         ctx.sc_trans = tx;
3048                         ctx.sc_flags = 0;
3049 
3050                         r = lscf_property_import(new_p, &ctx);
3051                         if (r != UU_WALK_NEXT) {
3052                                 if (r != UU_WALK_ERROR)
3053                                         bad_error("lscf_property_import", r);
3054                                 return (EINVAL);
3055                         }
3056                 }
3057         }
3058 
3059         /* Go over the properties which were added. */
3060         for (new_p = uu_list_first(new->sc_pgroup_props);
3061             new_p != NULL;
3062             new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3063                 if (new_p->sc_seen)
3064                         continue;
3065 
3066                 /* This is a new property. */
3067                 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3068                 if (cur_p == NULL) {
3069                         scf_callback_t ctx;
3070 
3071                         ctx.sc_handle = g_hndl;
3072                         ctx.sc_trans = tx;
3073                         ctx.sc_flags = 0;
3074 
3075                         r = lscf_property_import(new_p, &ctx);
3076                         if (r != UU_WALK_NEXT) {
3077                                 if (r != UU_WALK_ERROR)
3078                                         bad_error("lscf_property_import", r);
3079                                 return (EINVAL);
3080                         }
3081                         continue;
3082                 }
3083 
3084                 /*
3085                  * Report a conflict if the new property differs from the
3086                  * current one.  Unless it's general/enabled, since that's
3087                  * never in the last-import snapshot.
3088                  */
3089                 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3090                     0 &&
3091                     strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3092                         continue;
3093 
3094                 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3095         }
3096 
3097         return (0);
3098 }
3099 
3100 /*
3101  * Upgrade pg according to old & new.
3102  *
3103  * Returns
3104  *   0 - success
3105  *   ECONNABORTED - repository connection broken
3106  *   ENOMEM - out of memory
3107  *   ENOSPC - svc.configd is out of resources
3108  *   ECANCELED - pg was deleted
3109  *   EPERM - couldn't modify pg (permission denied)
3110  *   EROFS - couldn't modify pg (backend read-only)
3111  *   EACCES - couldn't modify pg (backend access denied)
3112  *   EINVAL - new has a property with invalid name or value (error printed)
3113  *   EBUSY - pg changed unexpectedly
3114  */
3115 static int
3116 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3117     pgroup_t *new, int speak, const char *fmri)
3118 {
3119         int r;
3120 
3121         if (scf_transaction_start(imp_tx, pg) != 0) {
3122                 switch (scf_error()) {
3123                 case SCF_ERROR_CONNECTION_BROKEN:
3124                 case SCF_ERROR_DELETED:
3125                 case SCF_ERROR_PERMISSION_DENIED:
3126                 case SCF_ERROR_BACKEND_READONLY:
3127                 case SCF_ERROR_BACKEND_ACCESS:
3128                         return (scferror2errno(scf_error()));
3129 
3130                 case SCF_ERROR_HANDLE_MISMATCH:
3131                 case SCF_ERROR_IN_USE:
3132                 case SCF_ERROR_NOT_BOUND:
3133                 case SCF_ERROR_NOT_SET:
3134                 default:
3135                         bad_error("scf_transaction_start", scf_error());
3136                 }
3137         }
3138 
3139         r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3140         switch (r) {
3141         case 0:
3142                 break;
3143 
3144         case EINVAL:
3145         case ENOMEM:
3146                 scf_transaction_destroy_children(imp_tx);
3147                 return (r);
3148 
3149         default:
3150                 bad_error("add_upgrade_entries", r);
3151         }
3152 
3153         r = scf_transaction_commit(imp_tx);
3154 
3155         scf_transaction_destroy_children(imp_tx);
3156 
3157         switch (r) {
3158         case 1:
3159                 break;
3160 
3161         case 0:
3162                 return (EBUSY);
3163 
3164         case -1:
3165                 switch (scf_error()) {
3166                 case SCF_ERROR_CONNECTION_BROKEN:
3167                 case SCF_ERROR_NO_RESOURCES:
3168                 case SCF_ERROR_PERMISSION_DENIED:
3169                 case SCF_ERROR_BACKEND_READONLY:
3170                 case SCF_ERROR_BACKEND_ACCESS:
3171                 case SCF_ERROR_DELETED:
3172                         return (scferror2errno(scf_error()));
3173 
3174                 case SCF_ERROR_NOT_BOUND:
3175                 case SCF_ERROR_INVALID_ARGUMENT:
3176                 case SCF_ERROR_NOT_SET:
3177                 default:
3178                         bad_error("scf_transaction_commit", scf_error());
3179                 }
3180 
3181         default:
3182                 bad_error("scf_transaction_commit", r);
3183         }
3184 
3185         return (0);
3186 }
3187 
3188 /*
3189  * Compares two entity FMRIs.  Returns
3190  *
3191  *   1 - equal
3192  *   0 - not equal
3193  *   -1 - f1 is invalid or not an entity
3194  *   -2 - f2 is invalid or not an entity
3195  */
3196 static int
3197 fmri_equal(const char *f1, const char *f2)
3198 {
3199         int r;
3200         const char *s1, *i1, *pg1;
3201         const char *s2, *i2, *pg2;
3202 
3203         if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3204                 return (-1);
3205         if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3206                 return (-1);
3207 
3208         if (s1 == NULL || pg1 != NULL)
3209                 return (-1);
3210 
3211         if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3212                 return (-2);
3213         if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3214                 return (-2);
3215 
3216         if (s2 == NULL || pg2 != NULL)
3217                 return (-2);
3218 
3219         r = strcmp(s1, s2);
3220         if (r != 0)
3221                 return (0);
3222 
3223         if (i1 == NULL && i2 == NULL)
3224                 return (1);
3225 
3226         if (i1 == NULL || i2 == NULL)
3227                 return (0);
3228 
3229         return (strcmp(i1, i2) == 0);
3230 }
3231 
3232 /*
3233  * Import a dependent by creating a dependency property group in the dependent
3234  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3235  * dependents pg, and add an entry to create a new property for this
3236  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3237  *
3238  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3239  * lcbdata->sc_err to
3240  *   ECONNABORTED - repository connection broken
3241  *   ENOMEM - out of memory
3242  *   ENOSPC - configd is out of resources
3243  *   EINVAL - target is invalid (error printed)
3244  *          - target is not an entity (error printed)
3245  *          - dependent has invalid name (error printed)
3246  *          - invalid property name (error printed)
3247  *          - invalid value (error printed)
3248  *          - scope of target does not exist (error printed)
3249  *   EPERM - couldn't create target (permission denied) (error printed)
3250  *         - couldn't create dependency pg (permission denied) (error printed)
3251  *         - couldn't modify dependency pg (permission denied) (error printed)
3252  *   EROFS - couldn't create target (repository read-only)
3253  *         - couldn't create dependency pg (repository read-only)
3254  *   EACCES - couldn't create target (backend access denied)
3255  *          - couldn't create dependency pg (backend access denied)
3256  *   ECANCELED - sc_trans's pg was deleted
3257  *   EALREADY - property for dependent already exists in sc_trans's pg
3258  *   EEXIST - dependency pg already exists in target (error printed)
3259  *   EBUSY - target deleted (error printed)
3260  *         - property group changed during import (error printed)
3261  */
3262 static int
3263 lscf_dependent_import(void *a1, void *pvt)
3264 {
3265         pgroup_t *pgrp = a1;
3266         scf_callback_t *lcbdata = pvt;
3267 
3268         int isservice;
3269         int ret;
3270         scf_transaction_entry_t *e;
3271         scf_value_t *val;
3272         scf_callback_t dependent_cbdata;
3273         scf_error_t scfe;
3274 
3275         /*
3276          * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3277          * it's invalid, we fail before modifying the repository.
3278          */
3279         scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3280             &dependent_cbdata.sc_parent, &isservice);
3281         switch (scfe) {
3282         case SCF_ERROR_NONE:
3283                 break;
3284 
3285         case SCF_ERROR_NO_MEMORY:
3286                 return (stash_scferror_err(lcbdata, scfe));
3287 
3288         case SCF_ERROR_INVALID_ARGUMENT:
3289                 semerr(gettext("The FMRI for the \"%s\" dependent is "
3290                     "invalid.\n"), pgrp->sc_pgroup_name);
3291                 return (stash_scferror_err(lcbdata, scfe));
3292 
3293         case SCF_ERROR_CONSTRAINT_VIOLATED:
3294                 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3295                     "specifies neither a service nor an instance.\n"),
3296                     pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3297                 return (stash_scferror_err(lcbdata, scfe));
3298 
3299         case SCF_ERROR_NOT_FOUND:
3300                 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3301                     &dependent_cbdata.sc_parent, &isservice);
3302                 switch (scfe) {
3303                 case SCF_ERROR_NONE:
3304                         break;
3305 
3306                 case SCF_ERROR_NO_MEMORY:
3307                 case SCF_ERROR_BACKEND_READONLY:
3308                 case SCF_ERROR_BACKEND_ACCESS:
3309                         return (stash_scferror_err(lcbdata, scfe));
3310 
3311                 case SCF_ERROR_NOT_FOUND:
3312                         semerr(gettext("The scope in FMRI \"%s\" for the "
3313                             "\"%s\" dependent does not exist.\n"),
3314                             pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3315                         lcbdata->sc_err = EINVAL;
3316                         return (UU_WALK_ERROR);
3317 
3318                 case SCF_ERROR_PERMISSION_DENIED:
3319                         warn(gettext(
3320                             "Could not create %s (permission denied).\n"),
3321                             pgrp->sc_pgroup_fmri);
3322                         return (stash_scferror_err(lcbdata, scfe));
3323 
3324                 case SCF_ERROR_INVALID_ARGUMENT:
3325                 case SCF_ERROR_CONSTRAINT_VIOLATED:
3326                 default:
3327                         bad_error("create_entity", scfe);
3328                 }
3329                 break;
3330 
3331         default:
3332                 bad_error("fmri_to_entity", scfe);
3333         }
3334 
3335         if (lcbdata->sc_trans != NULL) {
3336                 e = scf_entry_create(lcbdata->sc_handle);
3337                 if (e == NULL) {
3338                         if (scf_error() != SCF_ERROR_NO_MEMORY)
3339                                 bad_error("scf_entry_create", scf_error());
3340 
3341                         entity_destroy(dependent_cbdata.sc_parent, isservice);
3342                         return (stash_scferror(lcbdata));
3343                 }
3344 
3345                 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3346                     pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3347                         switch (scf_error()) {
3348                         case SCF_ERROR_INVALID_ARGUMENT:
3349                                 warn(gettext("Dependent of %s has invalid name "
3350                                     "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3351                                     pgrp->sc_pgroup_name);
3352                                 /* FALLTHROUGH */
3353 
3354                         case SCF_ERROR_DELETED:
3355                         case SCF_ERROR_CONNECTION_BROKEN:
3356                                 scf_entry_destroy(e);
3357                                 entity_destroy(dependent_cbdata.sc_parent,
3358                                     isservice);
3359                                 return (stash_scferror(lcbdata));
3360 
3361                         case SCF_ERROR_EXISTS:
3362                                 scf_entry_destroy(e);
3363                                 entity_destroy(dependent_cbdata.sc_parent,
3364                                     isservice);
3365                                 lcbdata->sc_err = EALREADY;
3366                                 return (UU_WALK_ERROR);
3367 
3368                         case SCF_ERROR_NOT_BOUND:
3369                         case SCF_ERROR_HANDLE_MISMATCH:
3370                         case SCF_ERROR_NOT_SET:
3371                         default:
3372                                 bad_error("scf_transaction_property_new",
3373                                     scf_error());
3374                         }
3375                 }
3376 
3377                 val = scf_value_create(lcbdata->sc_handle);
3378                 if (val == NULL) {
3379                         if (scf_error() != SCF_ERROR_NO_MEMORY)
3380                                 bad_error("scf_value_create", scf_error());
3381 
3382                         entity_destroy(dependent_cbdata.sc_parent, isservice);
3383                         return (stash_scferror(lcbdata));
3384                 }
3385 
3386                 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3387                     pgrp->sc_pgroup_fmri) != 0)
3388                         /* invalid should have been caught above */
3389                         bad_error("scf_value_set_from_string", scf_error());
3390 
3391                 if (scf_entry_add_value(e, val) != 0)
3392                         bad_error("scf_entry_add_value", scf_error());
3393         }
3394 
3395         /* Add the property group to the target entity. */
3396 
3397         dependent_cbdata.sc_handle = lcbdata->sc_handle;
3398         dependent_cbdata.sc_flags = lcbdata->sc_flags;
3399         dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3400         dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3401 
3402         ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3403 
3404         entity_destroy(dependent_cbdata.sc_parent, isservice);
3405 
3406         if (ret == UU_WALK_NEXT)
3407                 return (ret);
3408 
3409         if (ret != UU_WALK_ERROR)
3410                 bad_error("entity_pgroup_import", ret);
3411 
3412         switch (dependent_cbdata.sc_err) {
3413         case ECANCELED:
3414                 warn(gettext("%s deleted unexpectedly.\n"),
3415                     pgrp->sc_pgroup_fmri);
3416                 lcbdata->sc_err = EBUSY;
3417                 break;
3418 
3419         case EEXIST:
3420                 warn(gettext("Could not create \"%s\" dependency in %s "
3421                     "(already exists).\n"), pgrp->sc_pgroup_name,
3422                     pgrp->sc_pgroup_fmri);
3423                 /* FALLTHROUGH */
3424 
3425         default:
3426                 lcbdata->sc_err = dependent_cbdata.sc_err;
3427         }
3428 
3429         return (UU_WALK_ERROR);
3430 }
3431 
3432 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3433     const scf_snaplevel_t *, scf_transaction_t *);
3434 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3435     const pgroup_t *);
3436 
3437 /*
3438  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3439  * the current dependent targets from running (the snaplevel of a running
3440  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3441  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3442  * dependent targets and dependency properties from li_dpts_pg (the
3443  * "dependents" property group in snpl) and snpl (the snaplevel which
3444  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3445  * snpl doesn't have a "dependents" property group, and any dependents in ient
3446  * are new.
3447  *
3448  * Returns
3449  *   0 - success
3450  *   ECONNABORTED - repository connection broken
3451  *   ENOMEM - out of memory
3452  *   ENOSPC - configd is out of resources
3453  *   ECANCELED - ent was deleted
3454  *   ENODEV - the entity containing li_dpts_pg was deleted
3455  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3456  *         - couldn't upgrade dependent (permission denied) (error printed)
3457  *         - couldn't create dependent (permission denied) (error printed)
3458  *   EROFS - could not modify dependents pg (repository read-only)
3459  *         - couldn't upgrade dependent (repository read-only)
3460  *         - couldn't create dependent (repository read-only)
3461  *   EACCES - could not modify dependents pg (backend access denied)
3462  *          - could not upgrade dependent (backend access denied)
3463  *          - could not create dependent (backend access denied)
3464  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3465  *         - dependent target deleted (error printed)
3466  *         - dependent pg changed (error printed)
3467  *   EINVAL - new dependent is invalid (error printed)
3468  *   EBADF - snpl is corrupt (error printed)
3469  *         - snpl has corrupt pg (error printed)
3470  *         - dependency pg in target is corrupt (error printed)
3471  *         - target has corrupt snapshot (error printed)
3472  *   EEXIST - dependency pg already existed in target service (error printed)
3473  */
3474 static int
3475 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3476     const scf_snaplevel_t *snpl, const entity_t *ient,
3477     const scf_snaplevel_t *running, void *ent)
3478 {
3479         pgroup_t *new_dpt_pgroup;
3480         scf_callback_t cbdata;
3481         int r, unseen, tx_started = 0;
3482         int have_cur_depts;
3483 
3484         const char * const dependents = "dependents";
3485 
3486         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3487 
3488         if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3489                 /* Nothing to do. */
3490                 return (0);
3491 
3492         /* Fetch the current version of the "dependents" property group. */
3493         have_cur_depts = 1;
3494         if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3495                 switch (scf_error()) {
3496                 case SCF_ERROR_NOT_FOUND:
3497                         break;
3498 
3499                 case SCF_ERROR_DELETED:
3500                 case SCF_ERROR_CONNECTION_BROKEN:
3501                         return (scferror2errno(scf_error()));
3502 
3503                 case SCF_ERROR_NOT_SET:
3504                 case SCF_ERROR_INVALID_ARGUMENT:
3505                 case SCF_ERROR_HANDLE_MISMATCH:
3506                 case SCF_ERROR_NOT_BOUND:
3507                 default:
3508                         bad_error("entity_get_pg", scf_error());
3509                 }
3510 
3511                 have_cur_depts = 0;
3512         }
3513 
3514         /* Fetch the running version of the "dependents" property group. */
3515         ud_run_dpts_pg_set = 0;
3516         if (running != NULL)
3517                 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3518         else
3519                 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3520         if (r == 0) {
3521                 ud_run_dpts_pg_set = 1;
3522         } else {
3523                 switch (scf_error()) {
3524                 case SCF_ERROR_NOT_FOUND:
3525                         break;
3526 
3527                 case SCF_ERROR_DELETED:
3528                 case SCF_ERROR_CONNECTION_BROKEN:
3529                         return (scferror2errno(scf_error()));
3530 
3531                 case SCF_ERROR_NOT_SET:
3532                 case SCF_ERROR_INVALID_ARGUMENT:
3533                 case SCF_ERROR_HANDLE_MISMATCH:
3534                 case SCF_ERROR_NOT_BOUND:
3535                 default:
3536                         bad_error(running ? "scf_snaplevel_get_pg" :
3537                             "entity_get_pg", scf_error());
3538                 }
3539         }
3540 
3541         /*
3542          * Clear the seen fields of the dependents, so we can tell which ones
3543          * are new.
3544          */
3545         if (uu_list_walk(ient->sc_dependents, clear_int,
3546             (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3547                 bad_error("uu_list_walk", uu_error());
3548 
3549         if (li_dpts_pg != NULL) {
3550                 /*
3551                  * Each property in li_dpts_pg represents a dependent tag in
3552                  * the old manifest.  For each, call upgrade_dependent(),
3553                  * which will change ud_cur_depts_pg or dependencies in other
3554                  * services as appropriate.  Note (a) that changes to
3555                  * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3556                  * made en masse, and (b) it's ok if the entity doesn't have
3557                  * a current version of the "dependents" property group,
3558                  * because we'll just consider all dependents as customized
3559                  * (by being deleted).
3560                  */
3561 
3562                 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3563                         switch (scf_error()) {
3564                         case SCF_ERROR_DELETED:
3565                                 return (ENODEV);
3566 
3567                         case SCF_ERROR_CONNECTION_BROKEN:
3568                                 return (ECONNABORTED);
3569 
3570                         case SCF_ERROR_HANDLE_MISMATCH:
3571                         case SCF_ERROR_NOT_BOUND:
3572                         case SCF_ERROR_NOT_SET:
3573                         default:
3574                                 bad_error("scf_iter_pg_properties",
3575                                     scf_error());
3576                         }
3577                 }
3578 
3579                 if (have_cur_depts &&
3580                     scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3581                         switch (scf_error()) {
3582                         case SCF_ERROR_BACKEND_ACCESS:
3583                         case SCF_ERROR_BACKEND_READONLY:
3584                         case SCF_ERROR_CONNECTION_BROKEN:
3585                                 return (scferror2errno(scf_error()));
3586 
3587                         case SCF_ERROR_DELETED:
3588                                 warn(emsg_pg_deleted, ient->sc_fmri,
3589                                     dependents);
3590                                 return (EBUSY);
3591 
3592                         case SCF_ERROR_PERMISSION_DENIED:
3593                                 warn(emsg_pg_mod_perm, dependents,
3594                                     ient->sc_fmri);
3595                                 return (scferror2errno(scf_error()));
3596 
3597                         case SCF_ERROR_HANDLE_MISMATCH:
3598                         case SCF_ERROR_IN_USE:
3599                         case SCF_ERROR_NOT_BOUND:
3600                         case SCF_ERROR_NOT_SET:
3601                         default:
3602                                 bad_error("scf_transaction_start", scf_error());
3603                         }
3604                 }
3605                 tx_started = have_cur_depts;
3606 
3607                 for (;;) {
3608                         r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3609                         if (r == 0)
3610                                 break;
3611                         if (r == 1) {
3612                                 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3613                                     tx_started ? ud_tx : NULL);
3614                                 switch (r) {
3615                                 case 0:
3616                                         continue;
3617 
3618                                 case ECONNABORTED:
3619                                 case ENOMEM:
3620                                 case ENOSPC:
3621                                 case EBADF:
3622                                 case EBUSY:
3623                                 case EINVAL:
3624                                 case EPERM:
3625                                 case EROFS:
3626                                 case EACCES:
3627                                 case EEXIST:
3628                                         break;
3629 
3630                                 case ECANCELED:
3631                                         r = ENODEV;
3632                                         break;
3633 
3634                                 default:
3635                                         bad_error("upgrade_dependent", r);
3636                                 }
3637 
3638                                 if (tx_started)
3639                                         scf_transaction_destroy_children(ud_tx);
3640                                 return (r);
3641                         }
3642                         if (r != -1)
3643                                 bad_error("scf_iter_next_property", r);
3644 
3645                         switch (scf_error()) {
3646                         case SCF_ERROR_DELETED:
3647                                 r = ENODEV;
3648                                 break;
3649 
3650                         case SCF_ERROR_CONNECTION_BROKEN:
3651                                 r = ECONNABORTED;
3652                                 break;
3653 
3654                         case SCF_ERROR_NOT_SET:
3655                         case SCF_ERROR_INVALID_ARGUMENT:
3656                         case SCF_ERROR_NOT_BOUND:
3657                         case SCF_ERROR_HANDLE_MISMATCH:
3658                         default:
3659                                 bad_error("scf_iter_next_property",
3660                                     scf_error());
3661                         }
3662 
3663                         if (tx_started)
3664                                 scf_transaction_destroy_children(ud_tx);
3665                         return (r);
3666                 }
3667         }
3668 
3669         /* import unseen dependents */
3670         unseen = 0;
3671         for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3672             new_dpt_pgroup != NULL;
3673             new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3674             new_dpt_pgroup)) {
3675                 if (!new_dpt_pgroup->sc_pgroup_seen) {
3676                         unseen = 1;
3677                         break;
3678                 }
3679         }
3680 
3681         /* If there are none, exit early. */
3682         if (unseen == 0)
3683                 goto commit;
3684 
3685         /* Set up for lscf_dependent_import() */
3686         cbdata.sc_handle = g_hndl;
3687         cbdata.sc_parent = ent;
3688         cbdata.sc_service = issvc;
3689         cbdata.sc_flags = 0;
3690 
3691         if (!have_cur_depts) {
3692                 /*
3693                  * We have new dependents to import, so we need a "dependents"
3694                  * property group.
3695                  */
3696                 if (issvc)
3697                         r = scf_service_add_pg(ent, dependents,
3698                             SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3699                 else
3700                         r = scf_instance_add_pg(ent, dependents,
3701                             SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3702                 if (r != 0) {
3703                         switch (scf_error()) {
3704                         case SCF_ERROR_DELETED:
3705                         case SCF_ERROR_CONNECTION_BROKEN:
3706                         case SCF_ERROR_BACKEND_READONLY:
3707                         case SCF_ERROR_BACKEND_ACCESS:
3708                         case SCF_ERROR_NO_RESOURCES:
3709                                 return (scferror2errno(scf_error()));
3710 
3711                         case SCF_ERROR_EXISTS:
3712                                 warn(emsg_pg_added, ient->sc_fmri, dependents);
3713                                 return (EBUSY);
3714 
3715                         case SCF_ERROR_PERMISSION_DENIED:
3716                                 warn(emsg_pg_add_perm, dependents,
3717                                     ient->sc_fmri);
3718                                 return (scferror2errno(scf_error()));
3719 
3720                         case SCF_ERROR_NOT_BOUND:
3721                         case SCF_ERROR_HANDLE_MISMATCH:
3722                         case SCF_ERROR_INVALID_ARGUMENT:
3723                         case SCF_ERROR_NOT_SET:
3724                         default:
3725                                 bad_error("scf_service_add_pg", scf_error());
3726                         }
3727                 }
3728         }
3729 
3730         cbdata.sc_trans = ud_tx;
3731 
3732         if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3733                 switch (scf_error()) {
3734                 case SCF_ERROR_CONNECTION_BROKEN:
3735                 case SCF_ERROR_BACKEND_ACCESS:
3736                 case SCF_ERROR_BACKEND_READONLY:
3737                         return (scferror2errno(scf_error()));
3738 
3739                 case SCF_ERROR_DELETED:
3740                         warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3741                         return (EBUSY);
3742 
3743                 case SCF_ERROR_PERMISSION_DENIED:
3744                         warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3745                         return (scferror2errno(scf_error()));
3746 
3747                 case SCF_ERROR_HANDLE_MISMATCH:
3748                 case SCF_ERROR_IN_USE:
3749                 case SCF_ERROR_NOT_BOUND:
3750                 case SCF_ERROR_NOT_SET:
3751                 default:
3752                         bad_error("scf_transaction_start", scf_error());
3753                 }
3754         }
3755         tx_started = 1;
3756 
3757         for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3758             new_dpt_pgroup != NULL;
3759             new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3760             new_dpt_pgroup)) {
3761                 if (new_dpt_pgroup->sc_pgroup_seen)
3762                         continue;
3763 
3764                 if (ud_run_dpts_pg_set) {
3765                         /*
3766                          * If the dependent is already there, then we have
3767                          * a conflict.
3768                          */
3769                         if (scf_pg_get_property(ud_run_dpts_pg,
3770                             new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3771                                 r = handle_dependent_conflict(ient, ud_prop,
3772                                     new_dpt_pgroup);
3773                                 switch (r) {
3774                                 case 0:
3775                                         continue;
3776 
3777                                 case ECONNABORTED:
3778                                 case ENOMEM:
3779                                 case EBUSY:
3780                                 case EBADF:
3781                                 case EINVAL:
3782                                         scf_transaction_destroy_children(ud_tx);
3783                                         return (r);
3784 
3785                                 default:
3786                                         bad_error("handle_dependent_conflict",
3787                                             r);
3788                                 }
3789                         } else {
3790                                 switch (scf_error()) {
3791                                 case SCF_ERROR_NOT_FOUND:
3792                                         break;
3793 
3794                                 case SCF_ERROR_INVALID_ARGUMENT:
3795                                         warn(emsg_fmri_invalid_pg_name,
3796                                             ient->sc_fmri,
3797                                             new_dpt_pgroup->sc_pgroup_name);
3798                                         scf_transaction_destroy_children(ud_tx);
3799                                         return (EINVAL);
3800 
3801                                 case SCF_ERROR_DELETED:
3802                                         warn(emsg_pg_deleted, ient->sc_fmri,
3803                                             new_dpt_pgroup->sc_pgroup_name);
3804                                         scf_transaction_destroy_children(ud_tx);
3805                                         return (EBUSY);
3806 
3807                                 case SCF_ERROR_CONNECTION_BROKEN:
3808                                         scf_transaction_destroy_children(ud_tx);
3809                                         return (ECONNABORTED);
3810 
3811                                 case SCF_ERROR_NOT_BOUND:
3812                                 case SCF_ERROR_HANDLE_MISMATCH:
3813                                 case SCF_ERROR_NOT_SET:
3814                                 default:
3815                                         bad_error("scf_pg_get_property",
3816                                             scf_error());
3817                                 }
3818                         }
3819                 }
3820 
3821                 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3822                 if (r != UU_WALK_NEXT) {
3823                         if (r != UU_WALK_ERROR)
3824                                 bad_error("lscf_dependent_import", r);
3825 
3826                         if (cbdata.sc_err == EALREADY) {
3827                                 /* Collisions were handled preemptively. */
3828                                 bad_error("lscf_dependent_import",
3829                                     cbdata.sc_err);
3830                         }
3831 
3832                         scf_transaction_destroy_children(ud_tx);
3833                         return (cbdata.sc_err);
3834                 }
3835         }
3836 
3837 commit:
3838         if (!tx_started)
3839                 return (0);
3840 
3841         r = scf_transaction_commit(ud_tx);
3842 
3843         scf_transaction_destroy_children(ud_tx);
3844 
3845         switch (r) {
3846         case 1:
3847                 return (0);
3848 
3849         case 0:
3850                 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3851                 return (EBUSY);
3852 
3853         case -1:
3854                 break;
3855 
3856         default:
3857                 bad_error("scf_transaction_commit", r);
3858         }
3859 
3860         switch (scf_error()) {
3861         case SCF_ERROR_CONNECTION_BROKEN:
3862         case SCF_ERROR_BACKEND_READONLY:
3863         case SCF_ERROR_BACKEND_ACCESS:
3864         case SCF_ERROR_NO_RESOURCES:
3865                 return (scferror2errno(scf_error()));
3866 
3867         case SCF_ERROR_DELETED:
3868                 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3869                 return (EBUSY);
3870 
3871         case SCF_ERROR_PERMISSION_DENIED:
3872                 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3873                 return (scferror2errno(scf_error()));
3874 
3875         case SCF_ERROR_NOT_BOUND:
3876         case SCF_ERROR_INVALID_ARGUMENT:
3877         case SCF_ERROR_NOT_SET:
3878         default:
3879                 bad_error("scf_transaction_destroy", scf_error());
3880                 /* NOTREACHED */
3881         }
3882 }
3883 
3884 /*
3885  * Used to add the manifests to the list of currently supported manifests.
3886  * We can modify the existing manifest list removing entries if the files
3887  * don't exist.
3888  *
3889  * Get the old list and the new file name
3890  * If the new file name is in the list return
3891  * If not then add the file to the list.
3892  * As we process the list check to see if the files in the old list exist
3893  *      if not then remove the file from the list.
3894  * Commit the list of manifest file names.
3895  *
3896  */
3897 static int
3898 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3899     const scf_snaplevel_t *running, void *ent)
3900 {
3901         scf_propertygroup_t *ud_mfsts_pg = NULL;
3902         scf_property_t *ud_prop = NULL;
3903         scf_iter_t *ud_prop_iter;
3904         scf_value_t *fname_value;
3905         scf_callback_t cbdata;
3906         pgroup_t *mfst_pgroup;
3907         property_t *mfst_prop;
3908         property_t *old_prop;
3909         char *pname;
3910         char *fval;
3911         char *old_pname;
3912         char *old_fval;
3913         int no_upgrade_pg;
3914         int mfst_seen;
3915         int r;
3916 
3917         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3918 
3919         /*
3920          * This should always be the service base on the code
3921          * path, and the fact that the manifests pg is a service
3922          * level property group only.
3923          */
3924         ud_mfsts_pg = scf_pg_create(g_hndl);
3925         ud_prop = scf_property_create(g_hndl);
3926         ud_prop_iter = scf_iter_create(g_hndl);
3927         fname_value = scf_value_create(g_hndl);
3928 
3929         /* Fetch the "manifests" property group */
3930         no_upgrade_pg = 0;
3931         r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3932             ud_mfsts_pg);
3933         if (r != 0) {
3934                 switch (scf_error()) {
3935                 case SCF_ERROR_NOT_FOUND:
3936                         no_upgrade_pg = 1;
3937                         break;
3938 
3939                 case SCF_ERROR_DELETED:
3940                 case SCF_ERROR_CONNECTION_BROKEN:
3941                         return (scferror2errno(scf_error()));
3942 
3943                 case SCF_ERROR_NOT_SET:
3944                 case SCF_ERROR_INVALID_ARGUMENT:
3945                 case SCF_ERROR_HANDLE_MISMATCH:
3946                 case SCF_ERROR_NOT_BOUND:
3947                 default:
3948                         bad_error(running ? "scf_snaplevel_get_pg" :
3949                             "entity_get_pg", scf_error());
3950                 }
3951         }
3952 
3953         if (no_upgrade_pg) {
3954                 cbdata.sc_handle = g_hndl;
3955                 cbdata.sc_parent = ent;
3956                 cbdata.sc_service = issvc;
3957                 cbdata.sc_flags = SCI_FORCE;
3958                 cbdata.sc_source_fmri = ient->sc_fmri;
3959                 cbdata.sc_target_fmri = ient->sc_fmri;
3960 
3961                 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3962                         return (cbdata.sc_err);
3963 
3964                 return (0);
3965         }
3966 
3967         /* Fetch the new manifests property group */
3968         for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3969             mfst_pgroup != NULL;
3970             mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3971                 if (strcmp(mfst_pgroup->sc_pgroup_name,
3972                     SCF_PG_MANIFESTFILES) == 0)
3973                         break;
3974         }
3975 
3976         if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3977             SCF_SUCCESS)
3978                 return (-1);
3979 
3980         if ((pname = malloc(MAXPATHLEN)) == NULL)
3981                 return (ENOMEM);
3982         if ((fval = malloc(MAXPATHLEN)) == NULL) {
3983                 free(pname);
3984                 return (ENOMEM);
3985         }
3986 
3987         while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3988                 mfst_seen = 0;
3989                 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3990                         continue;
3991 
3992                 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3993                     mfst_prop != NULL;
3994                     mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3995                     mfst_prop)) {
3996                         if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3997                                 mfst_seen = 1;
3998                         }
3999                 }
4000 
4001                 /*
4002                  * If the manifest is not seen then add it to the new mfst
4003                  * property list to get proccessed into the repo.
4004                  */
4005                 if (mfst_seen == 0) {
4006                         /*
4007                          * If we cannot get the value then there is no
4008                          * reason to attempt to attach the value to
4009                          * the property group
4010                          */
4011                         if (prop_get_val(ud_prop, fname_value) == 0 &&
4012                             scf_value_get_astring(fname_value, fval,
4013                             MAXPATHLEN) != -1)  {
4014                                 old_pname = safe_strdup(pname);
4015                                 old_fval = safe_strdup(fval);
4016                                 old_prop = internal_property_create(old_pname,
4017                                     SCF_TYPE_ASTRING, 1, old_fval);
4018 
4019                                 /*
4020                                  * Already checked to see if the property exists
4021                                  * in the group, and it does not.
4022                                  */
4023                                 (void) internal_attach_property(mfst_pgroup,
4024                                     old_prop);
4025                         }
4026                 }
4027         }
4028         free(pname);
4029         free(fval);
4030 
4031         cbdata.sc_handle = g_hndl;
4032         cbdata.sc_parent = ent;
4033         cbdata.sc_service = issvc;
4034         cbdata.sc_flags = SCI_FORCE;
4035         cbdata.sc_source_fmri = ient->sc_fmri;
4036         cbdata.sc_target_fmri = ient->sc_fmri;
4037 
4038         if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4039                 return (cbdata.sc_err);
4040 
4041         return (r);
4042 }
4043 
4044 /*
4045  * prop is taken to be a property in the "dependents" property group of snpl,
4046  * which is taken to be the snaplevel of a last-import snapshot corresponding
4047  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4048  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4049  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4050  * of the entity ient represents (possibly in the running snapshot).  If it
4051  * needs to be changed, an entry will be added to tx, if not NULL.
4052  *
4053  * Returns
4054  *   0 - success
4055  *   ECONNABORTED - repository connection broken
4056  *   ENOMEM - out of memory
4057  *   ENOSPC - configd was out of resources
4058  *   ECANCELED - snpl's entity was deleted
4059  *   EINVAL - dependent target is invalid (error printed)
4060  *          - dependent is invalid (error printed)
4061  *   EBADF - snpl is corrupt (error printed)
4062  *         - snpl has corrupt pg (error printed)
4063  *         - dependency pg in target is corrupt (error printed)
4064  *         - running snapshot in dependent is missing snaplevel (error printed)
4065  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4066  *         - couldn't create dependent (permission denied) (error printed)
4067  *         - couldn't modify dependent pg (permission denied) (error printed)
4068  *   EROFS - couldn't delete dependency pg (repository read-only)
4069  *         - couldn't create dependent (repository read-only)
4070  *   EACCES - couldn't delete dependency pg (backend access denied)
4071  *          - couldn't create dependent (backend access denied)
4072  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4073  *         - tx's pg was deleted (error printed)
4074  *         - dependent pg was changed or deleted (error printed)
4075  *   EEXIST - dependency pg already exists in new target (error printed)
4076  */
4077 static int
4078 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4079     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4080 {
4081         pgroup_t pgrp;
4082         scf_type_t ty;
4083         pgroup_t *new_dpt_pgroup;
4084         pgroup_t *old_dpt_pgroup = NULL;
4085         pgroup_t *current_pg;
4086         pgroup_t *dpt;
4087         scf_callback_t cbdata;
4088         int tissvc;
4089         void *target_ent;
4090         scf_error_t serr;
4091         int r;
4092         scf_transaction_entry_t *ent;
4093 
4094         const char * const cf_inval = gettext("Conflict upgrading %s "
4095             "(dependent \"%s\" has invalid dependents property).\n");
4096         const char * const cf_missing = gettext("Conflict upgrading %s "
4097             "(dependent \"%s\" is missing).\n");
4098         const char * const cf_newdpg = gettext("Conflict upgrading %s "
4099             "(dependent \"%s\" has new dependency property group).\n");
4100         const char * const cf_newtarg = gettext("Conflict upgrading %s "
4101             "(dependent \"%s\" has new target).\n");
4102         const char * const li_corrupt =
4103             gettext("%s: \"last-import\" snapshot is corrupt.\n");
4104         const char * const upgrading =
4105             gettext("%s: Upgrading dependent \"%s\".\n");
4106         const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4107             "corrupt (missing snaplevel).\n");
4108 
4109         if (scf_property_type(prop, &ty) != 0) {
4110                 switch (scf_error()) {
4111                 case SCF_ERROR_DELETED:
4112                 case SCF_ERROR_CONNECTION_BROKEN:
4113                         return (scferror2errno(scf_error()));
4114 
4115                 case SCF_ERROR_NOT_BOUND:
4116                 case SCF_ERROR_NOT_SET:
4117                 default:
4118                         bad_error("scf_property_type", scf_error());
4119                 }
4120         }
4121 
4122         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4123                 warn(li_corrupt, ient->sc_fmri);
4124                 return (EBADF);
4125         }
4126 
4127         /*
4128          * prop represents a dependent in the old manifest.  It is named after
4129          * the dependent.
4130          */
4131         if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4132                 switch (scf_error()) {
4133                 case SCF_ERROR_DELETED:
4134                 case SCF_ERROR_CONNECTION_BROKEN:
4135                         return (scferror2errno(scf_error()));
4136 
4137                 case SCF_ERROR_NOT_BOUND:
4138                 case SCF_ERROR_NOT_SET:
4139                 default:
4140                         bad_error("scf_property_get_name", scf_error());
4141                 }
4142         }
4143 
4144         /* See if it's in the new manifest. */
4145         pgrp.sc_pgroup_name = ud_name;
4146         new_dpt_pgroup =
4147             uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4148 
4149         /* If it's not, delete it... if it hasn't been customized. */
4150         if (new_dpt_pgroup == NULL) {
4151                 if (!ud_run_dpts_pg_set)
4152                         return (0);
4153 
4154                 if (scf_property_get_value(prop, ud_val) != 0) {
4155                         switch (scf_error()) {
4156                         case SCF_ERROR_NOT_FOUND:
4157                         case SCF_ERROR_CONSTRAINT_VIOLATED:
4158                                 warn(li_corrupt, ient->sc_fmri);
4159                                 return (EBADF);
4160 
4161                         case SCF_ERROR_DELETED:
4162                         case SCF_ERROR_CONNECTION_BROKEN:
4163                                 return (scferror2errno(scf_error()));
4164 
4165                         case SCF_ERROR_HANDLE_MISMATCH:
4166                         case SCF_ERROR_NOT_BOUND:
4167                         case SCF_ERROR_NOT_SET:
4168                         case SCF_ERROR_PERMISSION_DENIED:
4169                         default:
4170                                 bad_error("scf_property_get_value",
4171                                     scf_error());
4172                         }
4173                 }
4174 
4175                 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4176                     max_scf_value_len + 1) < 0)
4177                         bad_error("scf_value_get_as_string", scf_error());
4178 
4179                 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4180                     0) {
4181                         switch (scf_error()) {
4182                         case SCF_ERROR_NOT_FOUND:
4183                                 return (0);
4184 
4185                         case SCF_ERROR_CONNECTION_BROKEN:
4186                                 return (scferror2errno(scf_error()));
4187 
4188                         case SCF_ERROR_DELETED:
4189                                 warn(emsg_pg_deleted, ient->sc_fmri,
4190                                     "dependents");
4191                                 return (EBUSY);
4192 
4193                         case SCF_ERROR_INVALID_ARGUMENT:
4194                         case SCF_ERROR_NOT_BOUND:
4195                         case SCF_ERROR_HANDLE_MISMATCH:
4196                         case SCF_ERROR_NOT_SET:
4197                         default:
4198                                 bad_error("scf_pg_get_property", scf_error());
4199                         }
4200                 }
4201                 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4202                         switch (scf_error()) {
4203                         case SCF_ERROR_NOT_FOUND:
4204                         case SCF_ERROR_CONSTRAINT_VIOLATED:
4205                                 warn(cf_inval, ient->sc_fmri, ud_name);
4206                                 return (0);
4207 
4208                         case SCF_ERROR_DELETED:
4209                         case SCF_ERROR_CONNECTION_BROKEN:
4210                                 return (scferror2errno(scf_error()));
4211 
4212                         case SCF_ERROR_HANDLE_MISMATCH:
4213                         case SCF_ERROR_NOT_BOUND:
4214                         case SCF_ERROR_NOT_SET:
4215                         case SCF_ERROR_PERMISSION_DENIED:
4216                         default:
4217                                 bad_error("scf_property_get_value",
4218                                     scf_error());
4219                         }
4220                 }
4221 
4222                 ty = scf_value_type(ud_val);
4223                 assert(ty != SCF_TYPE_INVALID);
4224                 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4225                         warn(cf_inval, ient->sc_fmri, ud_name);
4226                         return (0);
4227                 }
4228 
4229                 if (scf_value_get_as_string(ud_val, ud_ctarg,
4230                     max_scf_value_len + 1) < 0)
4231                         bad_error("scf_value_get_as_string", scf_error());
4232 
4233                 r = fmri_equal(ud_ctarg, ud_oldtarg);
4234                 switch (r) {
4235                 case 1:
4236                         break;
4237 
4238                 case 0:
4239                 case -1:        /* warn? */
4240                         warn(cf_newtarg, ient->sc_fmri, ud_name);
4241                         return (0);
4242 
4243                 case -2:
4244                         warn(li_corrupt, ient->sc_fmri);
4245                         return (EBADF);
4246 
4247                 default:
4248                         bad_error("fmri_equal", r);
4249                 }
4250 
4251                 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4252                         switch (scf_error()) {
4253                         case SCF_ERROR_NOT_FOUND:
4254                                 warn(li_corrupt, ient->sc_fmri);
4255                                 return (EBADF);
4256 
4257                         case SCF_ERROR_DELETED:
4258                         case SCF_ERROR_CONNECTION_BROKEN:
4259                                 return (scferror2errno(scf_error()));
4260 
4261                         case SCF_ERROR_NOT_BOUND:
4262                         case SCF_ERROR_HANDLE_MISMATCH:
4263                         case SCF_ERROR_INVALID_ARGUMENT:
4264                         case SCF_ERROR_NOT_SET:
4265                         default:
4266                                 bad_error("scf_snaplevel_get_pg", scf_error());
4267                         }
4268                 }
4269 
4270                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4271                     snap_lastimport);
4272                 switch (r) {
4273                 case 0:
4274                         break;
4275 
4276                 case ECANCELED:
4277                 case ECONNABORTED:
4278                 case ENOMEM:
4279                 case EBADF:
4280                         return (r);
4281 
4282                 case EACCES:
4283                 default:
4284                         bad_error("load_pg", r);
4285                 }
4286 
4287                 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4288                 switch (serr) {
4289                 case SCF_ERROR_NONE:
4290                         break;
4291 
4292                 case SCF_ERROR_NO_MEMORY:
4293                         internal_pgroup_free(old_dpt_pgroup);
4294                         return (ENOMEM);
4295 
4296                 case SCF_ERROR_NOT_FOUND:
4297                         internal_pgroup_free(old_dpt_pgroup);
4298                         goto delprop;
4299 
4300                 case SCF_ERROR_CONSTRAINT_VIOLATED:     /* caught above */
4301                 case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
4302                 default:
4303                         bad_error("fmri_to_entity", serr);
4304                 }
4305 
4306                 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4307                     ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4308                 switch (r) {
4309                 case 0:
4310                         break;
4311 
4312                 case ECONNABORTED:
4313                         internal_pgroup_free(old_dpt_pgroup);
4314                         return (r);
4315 
4316                 case ECANCELED:
4317                 case ENOENT:
4318                         internal_pgroup_free(old_dpt_pgroup);
4319                         goto delprop;
4320 
4321                 case EBADF:
4322                         warn(r_no_lvl, ud_ctarg);
4323                         internal_pgroup_free(old_dpt_pgroup);
4324                         return (r);
4325 
4326                 case EINVAL:
4327                 default:
4328                         bad_error("entity_get_running_pg", r);
4329                 }
4330 
4331                 /* load it */
4332                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4333                 switch (r) {
4334                 case 0:
4335                         break;
4336 
4337                 case ECANCELED:
4338                         internal_pgroup_free(old_dpt_pgroup);
4339                         goto delprop;
4340 
4341                 case ECONNABORTED:
4342                 case ENOMEM:
4343                 case EBADF:
4344                         internal_pgroup_free(old_dpt_pgroup);
4345                         return (r);
4346 
4347                 case EACCES:
4348                 default:
4349                         bad_error("load_pg", r);
4350                 }
4351 
4352                 /* compare property groups */
4353                 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4354                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4355                         internal_pgroup_free(old_dpt_pgroup);
4356                         internal_pgroup_free(current_pg);
4357                         return (0);
4358                 }
4359 
4360                 internal_pgroup_free(old_dpt_pgroup);
4361                 internal_pgroup_free(current_pg);
4362 
4363                 if (g_verbose)
4364                         warn(gettext("%s: Deleting dependent \"%s\".\n"),
4365                             ient->sc_fmri, ud_name);
4366 
4367                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4368                         switch (scf_error()) {
4369                         case SCF_ERROR_NOT_FOUND:
4370                         case SCF_ERROR_DELETED:
4371                                 internal_pgroup_free(old_dpt_pgroup);
4372                                 goto delprop;
4373 
4374                         case SCF_ERROR_CONNECTION_BROKEN:
4375                                 internal_pgroup_free(old_dpt_pgroup);
4376                                 return (ECONNABORTED);
4377 
4378                         case SCF_ERROR_NOT_SET:
4379                         case SCF_ERROR_INVALID_ARGUMENT:
4380                         case SCF_ERROR_HANDLE_MISMATCH:
4381                         case SCF_ERROR_NOT_BOUND:
4382                         default:
4383                                 bad_error("entity_get_pg", scf_error());
4384                         }
4385                 }
4386 
4387                 if (scf_pg_delete(ud_pg) != 0) {
4388                         switch (scf_error()) {
4389                         case SCF_ERROR_DELETED:
4390                                 break;
4391 
4392                         case SCF_ERROR_CONNECTION_BROKEN:
4393                         case SCF_ERROR_BACKEND_READONLY:
4394                         case SCF_ERROR_BACKEND_ACCESS:
4395                                 return (scferror2errno(scf_error()));
4396 
4397                         case SCF_ERROR_PERMISSION_DENIED:
4398                                 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4399                                 return (scferror2errno(scf_error()));
4400 
4401                         case SCF_ERROR_NOT_SET:
4402                         default:
4403                                 bad_error("scf_pg_delete", scf_error());
4404                         }
4405                 }
4406 
4407                 /*
4408                  * This service was changed, so it must be refreshed.  But
4409                  * since it's not mentioned in the new manifest, we have to
4410                  * record its FMRI here for use later.  We record the name
4411                  * & the entity (via sc_parent) in case we need to print error
4412                  * messages during the refresh.
4413                  */
4414                 dpt = internal_pgroup_new();
4415                 if (dpt == NULL)
4416                         return (ENOMEM);
4417                 dpt->sc_pgroup_name = strdup(ud_name);
4418                 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4419                 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4420                         return (ENOMEM);
4421                 dpt->sc_parent = (entity_t *)ient;
4422                 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4423                         uu_die(gettext("libuutil error: %s\n"),
4424                             uu_strerror(uu_error()));
4425 
4426 delprop:
4427                 if (tx == NULL)
4428                         return (0);
4429 
4430                 ent = scf_entry_create(g_hndl);
4431                 if (ent == NULL)
4432                         return (ENOMEM);
4433 
4434                 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4435                         scf_entry_destroy(ent);
4436                         switch (scf_error()) {
4437                         case SCF_ERROR_DELETED:
4438                                 warn(emsg_pg_deleted, ient->sc_fmri,
4439                                     "dependents");
4440                                 return (EBUSY);
4441 
4442                         case SCF_ERROR_CONNECTION_BROKEN:
4443                                 return (scferror2errno(scf_error()));
4444 
4445                         case SCF_ERROR_NOT_FOUND:
4446                                 break;
4447 
4448                         case SCF_ERROR_HANDLE_MISMATCH:
4449                         case SCF_ERROR_NOT_BOUND:
4450                         case SCF_ERROR_INVALID_ARGUMENT:
4451                         case SCF_ERROR_NOT_SET:
4452                         default:
4453                                 bad_error("scf_transaction_property_delete",
4454                                     scf_error());
4455                         }
4456                 }
4457 
4458                 return (0);
4459         }
4460 
4461         new_dpt_pgroup->sc_pgroup_seen = 1;
4462 
4463         /*
4464          * Decide whether the dependent has changed in the manifest.
4465          */
4466         /* Compare the target. */
4467         if (scf_property_get_value(prop, ud_val) != 0) {
4468                 switch (scf_error()) {
4469                 case SCF_ERROR_NOT_FOUND:
4470                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4471                         warn(li_corrupt, ient->sc_fmri);
4472                         return (EBADF);
4473 
4474                 case SCF_ERROR_DELETED:
4475                 case SCF_ERROR_CONNECTION_BROKEN:
4476                         return (scferror2errno(scf_error()));
4477 
4478                 case SCF_ERROR_HANDLE_MISMATCH:
4479                 case SCF_ERROR_NOT_BOUND:
4480                 case SCF_ERROR_NOT_SET:
4481                 case SCF_ERROR_PERMISSION_DENIED:
4482                 default:
4483                         bad_error("scf_property_get_value", scf_error());
4484                 }
4485         }
4486 
4487         if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4488             0)
4489                 bad_error("scf_value_get_as_string", scf_error());
4490 
4491         /*
4492          * If the fmri's are not equal then the old fmri will need to
4493          * be refreshed to ensure that the changes are properly updated
4494          * in that service.
4495          */
4496         r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4497         switch (r) {
4498         case 0:
4499                 dpt = internal_pgroup_new();
4500                 if (dpt == NULL)
4501                         return (ENOMEM);
4502                 dpt->sc_pgroup_name = strdup(ud_name);
4503                 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4504                 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4505                         return (ENOMEM);
4506                 dpt->sc_parent = (entity_t *)ient;
4507                 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4508                         uu_die(gettext("libuutil error: %s\n"),
4509                             uu_strerror(uu_error()));
4510                 break;
4511 
4512         case 1:
4513                 /* Compare the dependency pgs. */
4514                 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4515                         switch (scf_error()) {
4516                         case SCF_ERROR_NOT_FOUND:
4517                                 warn(li_corrupt, ient->sc_fmri);
4518                                 return (EBADF);
4519 
4520                         case SCF_ERROR_DELETED:
4521                         case SCF_ERROR_CONNECTION_BROKEN:
4522                                 return (scferror2errno(scf_error()));
4523 
4524                         case SCF_ERROR_NOT_BOUND:
4525                         case SCF_ERROR_HANDLE_MISMATCH:
4526                         case SCF_ERROR_INVALID_ARGUMENT:
4527                         case SCF_ERROR_NOT_SET:
4528                         default:
4529                                 bad_error("scf_snaplevel_get_pg", scf_error());
4530                         }
4531                 }
4532 
4533                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4534                     snap_lastimport);
4535                 switch (r) {
4536                 case 0:
4537                         break;
4538 
4539                 case ECANCELED:
4540                 case ECONNABORTED:
4541                 case ENOMEM:
4542                 case EBADF:
4543                         return (r);
4544 
4545                 case EACCES:
4546                 default:
4547                         bad_error("load_pg", r);
4548                 }
4549 
4550                 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4551                         /* no change, leave customizations */
4552                         internal_pgroup_free(old_dpt_pgroup);
4553                         return (0);
4554                 }
4555                 break;
4556 
4557         case -1:
4558                 warn(li_corrupt, ient->sc_fmri);
4559                 return (EBADF);
4560 
4561         case -2:
4562                 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4563                     ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4564                 return (EINVAL);
4565 
4566         default:
4567                 bad_error("fmri_equal", r);
4568         }
4569 
4570         /*
4571          * The dependent has changed in the manifest.  Upgrade the current
4572          * properties if they haven't been customized.
4573          */
4574 
4575         /*
4576          * If new_dpt_pgroup->sc_override, then act as though the property
4577          * group hasn't been customized.
4578          */
4579         if (new_dpt_pgroup->sc_pgroup_override) {
4580                 (void) strcpy(ud_ctarg, ud_oldtarg);
4581                 goto nocust;
4582         }
4583 
4584         if (!ud_run_dpts_pg_set) {
4585                 warn(cf_missing, ient->sc_fmri, ud_name);
4586                 r = 0;
4587                 goto out;
4588         } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4589                 switch (scf_error()) {
4590                 case SCF_ERROR_NOT_FOUND:
4591                         warn(cf_missing, ient->sc_fmri, ud_name);
4592                         r = 0;
4593                         goto out;
4594 
4595                 case SCF_ERROR_CONNECTION_BROKEN:
4596                         r = scferror2errno(scf_error());
4597                         goto out;
4598 
4599                 case SCF_ERROR_DELETED:
4600                         warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4601                         r = EBUSY;
4602                         goto out;
4603 
4604                 case SCF_ERROR_INVALID_ARGUMENT:
4605                 case SCF_ERROR_NOT_BOUND:
4606                 case SCF_ERROR_HANDLE_MISMATCH:
4607                 case SCF_ERROR_NOT_SET:
4608                 default:
4609                         bad_error("scf_pg_get_property", scf_error());
4610                 }
4611         }
4612 
4613         if (scf_property_get_value(ud_prop, ud_val) != 0) {
4614                 switch (scf_error()) {
4615                 case SCF_ERROR_NOT_FOUND:
4616                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4617                         warn(cf_inval, ient->sc_fmri, ud_name);
4618                         r = 0;
4619                         goto out;
4620 
4621                 case SCF_ERROR_DELETED:
4622                 case SCF_ERROR_CONNECTION_BROKEN:
4623                         r = scferror2errno(scf_error());
4624                         goto out;
4625 
4626                 case SCF_ERROR_HANDLE_MISMATCH:
4627                 case SCF_ERROR_NOT_BOUND:
4628                 case SCF_ERROR_NOT_SET:
4629                 case SCF_ERROR_PERMISSION_DENIED:
4630                 default:
4631                         bad_error("scf_property_get_value", scf_error());
4632                 }
4633         }
4634 
4635         ty = scf_value_type(ud_val);
4636         assert(ty != SCF_TYPE_INVALID);
4637         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4638                 warn(cf_inval, ient->sc_fmri, ud_name);
4639                 r = 0;
4640                 goto out;
4641         }
4642         if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4643             0)
4644                 bad_error("scf_value_get_as_string", scf_error());
4645 
4646         r = fmri_equal(ud_ctarg, ud_oldtarg);
4647         if (r == -1) {
4648                 warn(cf_inval, ient->sc_fmri, ud_name);
4649                 r = 0;
4650                 goto out;
4651         } else if (r == -2) {
4652                 warn(li_corrupt, ient->sc_fmri);
4653                 r = EBADF;
4654                 goto out;
4655         } else if (r == 0) {
4656                 /*
4657                  * Target has been changed.  Only abort now if it's been
4658                  * changed to something other than what's in the manifest.
4659                  */
4660                 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4661                 if (r == -1) {
4662                         warn(cf_inval, ient->sc_fmri, ud_name);
4663                         r = 0;
4664                         goto out;
4665                 } else if (r == 0) {
4666                         warn(cf_newtarg, ient->sc_fmri, ud_name);
4667                         r = 0;
4668                         goto out;
4669                 } else if (r != 1) {
4670                         /* invalid sc_pgroup_fmri caught above */
4671                         bad_error("fmri_equal", r);
4672                 }
4673 
4674                 /*
4675                  * Fetch the current dependency pg.  If it's what the manifest
4676                  * says, then no problem.
4677                  */
4678                 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4679                 switch (serr) {
4680                 case SCF_ERROR_NONE:
4681                         break;
4682 
4683                 case SCF_ERROR_NOT_FOUND:
4684                         warn(cf_missing, ient->sc_fmri, ud_name);
4685                         r = 0;
4686                         goto out;
4687 
4688                 case SCF_ERROR_NO_MEMORY:
4689                         r = ENOMEM;
4690                         goto out;
4691 
4692                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4693                 case SCF_ERROR_INVALID_ARGUMENT:
4694                 default:
4695                         bad_error("fmri_to_entity", serr);
4696                 }
4697 
4698                 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4699                     ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4700                 switch (r) {
4701                 case 0:
4702                         break;
4703 
4704                 case ECONNABORTED:
4705                         goto out;
4706 
4707                 case ECANCELED:
4708                 case ENOENT:
4709                         warn(cf_missing, ient->sc_fmri, ud_name);
4710                         r = 0;
4711                         goto out;
4712 
4713                 case EBADF:
4714                         warn(r_no_lvl, ud_ctarg);
4715                         goto out;
4716 
4717                 case EINVAL:
4718                 default:
4719                         bad_error("entity_get_running_pg", r);
4720                 }
4721 
4722                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4723                 switch (r) {
4724                 case 0:
4725                         break;
4726 
4727                 case ECANCELED:
4728                         warn(cf_missing, ient->sc_fmri, ud_name);
4729                         r = 0;
4730                         goto out;
4731 
4732                 case ECONNABORTED:
4733                 case ENOMEM:
4734                 case EBADF:
4735                         goto out;
4736 
4737                 case EACCES:
4738                 default:
4739                         bad_error("load_pg", r);
4740                 }
4741 
4742                 if (!pg_equal(current_pg, new_dpt_pgroup))
4743                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4744                 internal_pgroup_free(current_pg);
4745                 r = 0;
4746                 goto out;
4747         } else if (r != 1) {
4748                 bad_error("fmri_equal", r);
4749         }
4750 
4751 nocust:
4752         /*
4753          * Target has not been customized.  Check the dependency property
4754          * group.
4755          */
4756 
4757         if (old_dpt_pgroup == NULL) {
4758                 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4759                     ud_pg) != 0) {
4760                         switch (scf_error()) {
4761                         case SCF_ERROR_NOT_FOUND:
4762                                 warn(li_corrupt, ient->sc_fmri);
4763                                 return (EBADF);
4764 
4765                         case SCF_ERROR_DELETED:
4766                         case SCF_ERROR_CONNECTION_BROKEN:
4767                                 return (scferror2errno(scf_error()));
4768 
4769                         case SCF_ERROR_NOT_BOUND:
4770                         case SCF_ERROR_HANDLE_MISMATCH:
4771                         case SCF_ERROR_INVALID_ARGUMENT:
4772                         case SCF_ERROR_NOT_SET:
4773                         default:
4774                                 bad_error("scf_snaplevel_get_pg", scf_error());
4775                         }
4776                 }
4777 
4778                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4779                     snap_lastimport);
4780                 switch (r) {
4781                 case 0:
4782                         break;
4783 
4784                 case ECANCELED:
4785                 case ECONNABORTED:
4786                 case ENOMEM:
4787                 case EBADF:
4788                         return (r);
4789 
4790                 case EACCES:
4791                 default:
4792                         bad_error("load_pg", r);
4793                 }
4794         }
4795         serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4796         switch (serr) {
4797         case SCF_ERROR_NONE:
4798                 break;
4799 
4800         case SCF_ERROR_NOT_FOUND:
4801                 warn(cf_missing, ient->sc_fmri, ud_name);
4802                 r = 0;
4803                 goto out;
4804 
4805         case SCF_ERROR_NO_MEMORY:
4806                 r = ENOMEM;
4807                 goto out;
4808 
4809         case SCF_ERROR_CONSTRAINT_VIOLATED:
4810         case SCF_ERROR_INVALID_ARGUMENT:
4811         default:
4812                 bad_error("fmri_to_entity", serr);
4813         }
4814 
4815         r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4816             ud_iter2, ud_inst, imp_snap, ud_snpl);
4817         switch (r) {
4818         case 0:
4819                 break;
4820 
4821         case ECONNABORTED:
4822                 goto out;
4823 
4824         case ECANCELED:
4825         case ENOENT:
4826                 warn(cf_missing, ient->sc_fmri, ud_name);
4827                 r = 0;
4828                 goto out;
4829 
4830         case EBADF:
4831                 warn(r_no_lvl, ud_ctarg);
4832                 goto out;
4833 
4834         case EINVAL:
4835         default:
4836                 bad_error("entity_get_running_pg", r);
4837         }
4838 
4839         r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4840         switch (r) {
4841         case 0:
4842                 break;
4843 
4844         case ECANCELED:
4845                 warn(cf_missing, ient->sc_fmri, ud_name);
4846                 goto out;
4847 
4848         case ECONNABORTED:
4849         case ENOMEM:
4850         case EBADF:
4851                 goto out;
4852 
4853         case EACCES:
4854         default:
4855                 bad_error("load_pg", r);
4856         }
4857 
4858         if (!pg_equal(current_pg, old_dpt_pgroup)) {
4859                 if (!pg_equal(current_pg, new_dpt_pgroup))
4860                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4861                 internal_pgroup_free(current_pg);
4862                 r = 0;
4863                 goto out;
4864         }
4865 
4866         /* Uncustomized.  Upgrade. */
4867 
4868         r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4869         switch (r) {
4870         case 1:
4871                 if (pg_equal(current_pg, new_dpt_pgroup)) {
4872                         /* Already upgraded. */
4873                         internal_pgroup_free(current_pg);
4874                         r = 0;
4875                         goto out;
4876                 }
4877 
4878                 internal_pgroup_free(current_pg);
4879 
4880                 /* upgrade current_pg */
4881                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4882                         switch (scf_error()) {
4883                         case SCF_ERROR_CONNECTION_BROKEN:
4884                                 r = scferror2errno(scf_error());
4885                                 goto out;
4886 
4887                         case SCF_ERROR_DELETED:
4888                                 warn(cf_missing, ient->sc_fmri, ud_name);
4889                                 r = 0;
4890                                 goto out;
4891 
4892                         case SCF_ERROR_NOT_FOUND:
4893                                 break;
4894 
4895                         case SCF_ERROR_INVALID_ARGUMENT:
4896                         case SCF_ERROR_NOT_BOUND:
4897                         case SCF_ERROR_NOT_SET:
4898                         case SCF_ERROR_HANDLE_MISMATCH:
4899                         default:
4900                                 bad_error("entity_get_pg", scf_error());
4901                         }
4902 
4903                         if (tissvc)
4904                                 r = scf_service_add_pg(target_ent, ud_name,
4905                                     SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906                         else
4907                                 r = scf_instance_add_pg(target_ent, ud_name,
4908                                     SCF_GROUP_DEPENDENCY, 0, ud_pg);
4909                         if (r != 0) {
4910                                 switch (scf_error()) {
4911                                 case SCF_ERROR_CONNECTION_BROKEN:
4912                                 case SCF_ERROR_NO_RESOURCES:
4913                                 case SCF_ERROR_BACKEND_READONLY:
4914                                 case SCF_ERROR_BACKEND_ACCESS:
4915                                         r = scferror2errno(scf_error());
4916                                         goto out;
4917 
4918                                 case SCF_ERROR_DELETED:
4919                                         warn(cf_missing, ient->sc_fmri,
4920                                             ud_name);
4921                                         r = 0;
4922                                         goto out;
4923 
4924                                 case SCF_ERROR_PERMISSION_DENIED:
4925                                         warn(emsg_pg_deleted, ud_ctarg,
4926                                             ud_name);
4927                                         r = EPERM;
4928                                         goto out;
4929 
4930                                 case SCF_ERROR_EXISTS:
4931                                         warn(emsg_pg_added, ud_ctarg, ud_name);
4932                                         r = EBUSY;
4933                                         goto out;
4934 
4935                                 case SCF_ERROR_NOT_BOUND:
4936                                 case SCF_ERROR_HANDLE_MISMATCH:
4937                                 case SCF_ERROR_INVALID_ARGUMENT:
4938                                 case SCF_ERROR_NOT_SET:
4939                                 default:
4940                                         bad_error("entity_add_pg", scf_error());
4941                                 }
4942                         }
4943                 }
4944 
4945                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4946                 switch (r) {
4947                 case 0:
4948                         break;
4949 
4950                 case ECANCELED:
4951                         warn(cf_missing, ient->sc_fmri, ud_name);
4952                         goto out;
4953 
4954                 case ECONNABORTED:
4955                 case ENOMEM:
4956                 case EBADF:
4957                         goto out;
4958 
4959                 case EACCES:
4960                 default:
4961                         bad_error("load_pg", r);
4962                 }
4963 
4964                 if (g_verbose)
4965                         warn(upgrading, ient->sc_fmri, ud_name);
4966 
4967                 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4968                     new_dpt_pgroup, 0, ient->sc_fmri);
4969                 switch (r) {
4970                 case 0:
4971                         break;
4972 
4973                 case ECANCELED:
4974                         warn(emsg_pg_deleted, ud_ctarg, ud_name);
4975                         r = EBUSY;
4976                         goto out;
4977 
4978                 case EPERM:
4979                         warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4980                         goto out;
4981 
4982                 case EBUSY:
4983                         warn(emsg_pg_changed, ud_ctarg, ud_name);
4984                         goto out;
4985 
4986                 case ECONNABORTED:
4987                 case ENOMEM:
4988                 case ENOSPC:
4989                 case EROFS:
4990                 case EACCES:
4991                 case EINVAL:
4992                         goto out;
4993 
4994                 default:
4995                         bad_error("upgrade_pg", r);
4996                 }
4997                 break;
4998 
4999         case 0: {
5000                 scf_transaction_entry_t *ent;
5001                 scf_value_t *val;
5002 
5003                 internal_pgroup_free(current_pg);
5004 
5005                 /* delete old pg */
5006                 if (g_verbose)
5007                         warn(upgrading, ient->sc_fmri, ud_name);
5008 
5009                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5010                         switch (scf_error()) {
5011                         case SCF_ERROR_CONNECTION_BROKEN:
5012                                 r = scferror2errno(scf_error());
5013                                 goto out;
5014 
5015                         case SCF_ERROR_DELETED:
5016                                 warn(cf_missing, ient->sc_fmri, ud_name);
5017                                 r = 0;
5018                                 goto out;
5019 
5020                         case SCF_ERROR_NOT_FOUND:
5021                                 break;
5022 
5023                         case SCF_ERROR_INVALID_ARGUMENT:
5024                         case SCF_ERROR_NOT_BOUND:
5025                         case SCF_ERROR_NOT_SET:
5026                         case SCF_ERROR_HANDLE_MISMATCH:
5027                         default:
5028                                 bad_error("entity_get_pg", scf_error());
5029                         }
5030                 } else if (scf_pg_delete(ud_pg) != 0) {
5031                         switch (scf_error()) {
5032                         case SCF_ERROR_DELETED:
5033                                 break;
5034 
5035                         case SCF_ERROR_CONNECTION_BROKEN:
5036                         case SCF_ERROR_BACKEND_READONLY:
5037                         case SCF_ERROR_BACKEND_ACCESS:
5038                                 r = scferror2errno(scf_error());
5039                                 goto out;
5040 
5041                         case SCF_ERROR_PERMISSION_DENIED:
5042                                 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5043                                 r = scferror2errno(scf_error());
5044                                 goto out;
5045 
5046                         case SCF_ERROR_NOT_SET:
5047                         default:
5048                                 bad_error("scf_pg_delete", scf_error());
5049                         }
5050                 }
5051 
5052                 /* import new one */
5053                 cbdata.sc_handle = g_hndl;
5054                 cbdata.sc_trans = NULL;         /* handled below */
5055                 cbdata.sc_flags = 0;
5056 
5057                 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5058                 if (r != UU_WALK_NEXT) {
5059                         if (r != UU_WALK_ERROR)
5060                                 bad_error("lscf_dependent_import", r);
5061 
5062                         r = cbdata.sc_err;
5063                         goto out;
5064                 }
5065 
5066                 if (tx == NULL)
5067                         break;
5068 
5069                 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5070                     (val = scf_value_create(g_hndl)) == NULL) {
5071                         if (scf_error() == SCF_ERROR_NO_MEMORY)
5072                                 return (ENOMEM);
5073 
5074                         bad_error("scf_entry_create", scf_error());
5075                 }
5076 
5077                 if (scf_transaction_property_change_type(tx, ent, ud_name,
5078                     SCF_TYPE_FMRI) != 0) {
5079                         switch (scf_error()) {
5080                         case SCF_ERROR_CONNECTION_BROKEN:
5081                                 r = scferror2errno(scf_error());
5082                                 goto out;
5083 
5084                         case SCF_ERROR_DELETED:
5085                                 warn(emsg_pg_deleted, ient->sc_fmri,
5086                                     "dependents");
5087                                 r = EBUSY;
5088                                 goto out;
5089 
5090                         case SCF_ERROR_NOT_FOUND:
5091                                 break;
5092 
5093                         case SCF_ERROR_NOT_BOUND:
5094                         case SCF_ERROR_HANDLE_MISMATCH:
5095                         case SCF_ERROR_INVALID_ARGUMENT:
5096                         case SCF_ERROR_NOT_SET:
5097                         default:
5098                                 bad_error("scf_transaction_property_"
5099                                     "change_type", scf_error());
5100                         }
5101 
5102                         if (scf_transaction_property_new(tx, ent, ud_name,
5103                             SCF_TYPE_FMRI) != 0) {
5104                                 switch (scf_error()) {
5105                                 case SCF_ERROR_CONNECTION_BROKEN:
5106                                         r = scferror2errno(scf_error());
5107                                         goto out;
5108 
5109                                 case SCF_ERROR_DELETED:
5110                                         warn(emsg_pg_deleted, ient->sc_fmri,
5111                                             "dependents");
5112                                         r = EBUSY;
5113                                         goto out;
5114 
5115                                 case SCF_ERROR_EXISTS:
5116                                         warn(emsg_pg_changed, ient->sc_fmri,
5117                                             "dependents");
5118                                         r = EBUSY;
5119                                         goto out;
5120 
5121                                 case SCF_ERROR_INVALID_ARGUMENT:
5122                                 case SCF_ERROR_HANDLE_MISMATCH:
5123                                 case SCF_ERROR_NOT_BOUND:
5124                                 case SCF_ERROR_NOT_SET:
5125                                 default:
5126                                         bad_error("scf_transaction_property_"
5127                                             "new", scf_error());
5128                                 }
5129                         }
5130                 }
5131 
5132                 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5133                     new_dpt_pgroup->sc_pgroup_fmri) != 0)
5134                         /* invalid sc_pgroup_fmri caught above */
5135                         bad_error("scf_value_set_from_string",
5136                             scf_error());
5137 
5138                 if (scf_entry_add_value(ent, val) != 0)
5139                         bad_error("scf_entry_add_value", scf_error());
5140                 break;
5141         }
5142 
5143         case -2:
5144                 warn(li_corrupt, ient->sc_fmri);
5145                 internal_pgroup_free(current_pg);
5146                 r = EBADF;
5147                 goto out;
5148 
5149         case -1:
5150         default:
5151                 /* invalid sc_pgroup_fmri caught above */
5152                 bad_error("fmri_equal", r);
5153         }
5154 
5155         r = 0;
5156 
5157 out:
5158         if (old_dpt_pgroup != NULL)
5159                 internal_pgroup_free(old_dpt_pgroup);
5160 
5161         return (r);
5162 }
5163 
5164 /*
5165  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5166  * would import it, except it seems to exist in the service anyway.  Compare
5167  * the existent dependent with the one we would import, and report any
5168  * differences (if there are none, be silent).  prop is the property which
5169  * represents the existent dependent (in the dependents property group) in the
5170  * entity corresponding to ient.
5171  *
5172  * Returns
5173  *   0 - success (Sort of.  At least, we can continue importing.)
5174  *   ECONNABORTED - repository connection broken
5175  *   EBUSY - ancestor of prop was deleted (error printed)
5176  *   ENOMEM - out of memory
5177  *   EBADF - corrupt property group (error printed)
5178  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5179  */
5180 static int
5181 handle_dependent_conflict(const entity_t * const ient,
5182     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5183 {
5184         int r;
5185         scf_type_t ty;
5186         scf_error_t scfe;
5187         void *tptr;
5188         int tissvc;
5189         pgroup_t *pgroup;
5190 
5191         if (scf_property_get_value(prop, ud_val) != 0) {
5192                 switch (scf_error()) {
5193                 case SCF_ERROR_CONNECTION_BROKEN:
5194                         return (scferror2errno(scf_error()));
5195 
5196                 case SCF_ERROR_DELETED:
5197                         warn(emsg_pg_deleted, ient->sc_fmri,
5198                             new_dpt_pgroup->sc_pgroup_name);
5199                         return (EBUSY);
5200 
5201                 case SCF_ERROR_CONSTRAINT_VIOLATED:
5202                 case SCF_ERROR_NOT_FOUND:
5203                         warn(gettext("Conflict upgrading %s (not importing "
5204                             "dependent \"%s\" because it already exists.)  "
5205                             "Warning: The \"%s/%2$s\" property has more or "
5206                             "fewer than one value)).\n"), ient->sc_fmri,
5207                             new_dpt_pgroup->sc_pgroup_name, "dependents");
5208                         return (0);
5209 
5210                 case SCF_ERROR_HANDLE_MISMATCH:
5211                 case SCF_ERROR_NOT_BOUND:
5212                 case SCF_ERROR_NOT_SET:
5213                 case SCF_ERROR_PERMISSION_DENIED:
5214                 default:
5215                         bad_error("scf_property_get_value",
5216                             scf_error());
5217                 }
5218         }
5219 
5220         ty = scf_value_type(ud_val);
5221         assert(ty != SCF_TYPE_INVALID);
5222         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5223                 warn(gettext("Conflict upgrading %s (not importing dependent "
5224                     "\"%s\" because it already exists).  Warning: The "
5225                     "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5226                     ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5227                     scf_type_to_string(ty), "dependents");
5228                 return (0);
5229         }
5230 
5231         if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5232             0)
5233                 bad_error("scf_value_get_as_string", scf_error());
5234 
5235         r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5236         switch (r) {
5237         case 0:
5238                 warn(gettext("Conflict upgrading %s (not importing dependent "
5239                     "\"%s\" (target \"%s\") because it already exists with "
5240                     "target \"%s\").\n"), ient->sc_fmri,
5241                     new_dpt_pgroup->sc_pgroup_name,
5242                     new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5243                 return (0);
5244 
5245         case 1:
5246                 break;
5247 
5248         case -1:
5249                 warn(gettext("Conflict upgrading %s (not importing dependent "
5250                     "\"%s\" because it already exists).  Warning: The current "
5251                     "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5252                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5253                 return (0);
5254 
5255         case -2:
5256                 warn(gettext("Dependent \"%s\" of %s has invalid target "
5257                     "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5258                     new_dpt_pgroup->sc_pgroup_fmri);
5259                 return (EINVAL);
5260 
5261         default:
5262                 bad_error("fmri_equal", r);
5263         }
5264 
5265         /* compare dependency pgs in target */
5266         scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5267         switch (scfe) {
5268         case SCF_ERROR_NONE:
5269                 break;
5270 
5271         case SCF_ERROR_NO_MEMORY:
5272                 return (ENOMEM);
5273 
5274         case SCF_ERROR_NOT_FOUND:
5275                 warn(emsg_dpt_dangling, ient->sc_fmri,
5276                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5277                 return (0);
5278 
5279         case SCF_ERROR_CONSTRAINT_VIOLATED:
5280         case SCF_ERROR_INVALID_ARGUMENT:
5281         default:
5282                 bad_error("fmri_to_entity", scfe);
5283         }
5284 
5285         r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5286             ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5287         switch (r) {
5288         case 0:
5289                 break;
5290 
5291         case ECONNABORTED:
5292                 return (r);
5293 
5294         case ECANCELED:
5295                 warn(emsg_dpt_dangling, ient->sc_fmri,
5296                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5297                 return (0);
5298 
5299         case EBADF:
5300                 if (tissvc)
5301                         warn(gettext("%s has an instance with a \"%s\" "
5302                             "snapshot which is missing a snaplevel.\n"),
5303                             ud_ctarg, "running");
5304                 else
5305                         warn(gettext("%s has a \"%s\" snapshot which is "
5306                             "missing a snaplevel.\n"), ud_ctarg, "running");
5307                 /* FALLTHROUGH */
5308 
5309         case ENOENT:
5310                 warn(emsg_dpt_no_dep, ient->sc_fmri,
5311                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5312                     new_dpt_pgroup->sc_pgroup_name);
5313                 return (0);
5314 
5315         case EINVAL:
5316         default:
5317                 bad_error("entity_get_running_pg", r);
5318         }
5319 
5320         pgroup = internal_pgroup_new();
5321         if (pgroup == NULL)
5322                 return (ENOMEM);
5323 
5324         r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5325         switch (r) {
5326         case 0:
5327                 break;
5328 
5329         case ECONNABORTED:
5330         case EBADF:
5331         case ENOMEM:
5332                 internal_pgroup_free(pgroup);
5333                 return (r);
5334 
5335         case ECANCELED:
5336                 warn(emsg_dpt_no_dep, ient->sc_fmri,
5337                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5338                     new_dpt_pgroup->sc_pgroup_name);
5339                 internal_pgroup_free(pgroup);
5340                 return (0);
5341 
5342         case EACCES:
5343         default:
5344                 bad_error("load_pg", r);
5345         }
5346 
5347         /* report differences */
5348         report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5349         internal_pgroup_free(pgroup);
5350         return (0);
5351 }
5352 
5353 /*
5354  * lipg is a property group in the last-import snapshot of ent, which is an
5355  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5356  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5357  * in ents's property groups, compare and upgrade ent appropriately.
5358  *
5359  * Returns
5360  *   0 - success
5361  *   ECONNABORTED - repository connection broken
5362  *   ENOMEM - out of memory
5363  *   ENOSPC - configd is out of resources
5364  *   EINVAL - ient has invalid dependent (error printed)
5365  *          - ient has invalid pgroup_t (error printed)
5366  *   ECANCELED - ent has been deleted
5367  *   ENODEV - entity containing lipg has been deleted
5368  *          - entity containing running has been deleted
5369  *   EPERM - could not delete pg (permission denied) (error printed)
5370  *         - couldn't upgrade dependents (permission denied) (error printed)
5371  *         - couldn't import pg (permission denied) (error printed)
5372  *         - couldn't upgrade pg (permission denied) (error printed)
5373  *   EROFS - could not delete pg (repository read-only)
5374  *         - couldn't upgrade dependents (repository read-only)
5375  *         - couldn't import pg (repository read-only)
5376  *         - couldn't upgrade pg (repository read-only)
5377  *   EACCES - could not delete pg (backend access denied)
5378  *          - couldn't upgrade dependents (backend access denied)
5379  *          - couldn't import pg (backend access denied)
5380  *          - couldn't upgrade pg (backend access denied)
5381  *          - couldn't read property (backend access denied)
5382  *   EBUSY - property group was added (error printed)
5383  *         - property group was deleted (error printed)
5384  *         - property group changed (error printed)
5385  *         - "dependents" pg was added, changed, or deleted (error printed)
5386  *         - dependent target deleted (error printed)
5387  *         - dependent pg changed (error printed)
5388  *   EBADF - imp_snpl is corrupt (error printed)
5389  *         - ent has bad pg (error printed)
5390  *   EEXIST - dependent collision in target service (error printed)
5391  */
5392 static int
5393 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5394     const scf_snaplevel_t *running)
5395 {
5396         int r;
5397         pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5398         scf_callback_t cbdata;
5399 
5400         const char * const cf_pg_missing =
5401             gettext("Conflict upgrading %s (property group %s is missing)\n");
5402         const char * const deleting =
5403             gettext("%s: Deleting property group \"%s\".\n");
5404 
5405         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5406 
5407         /* Skip dependent property groups. */
5408         if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5409                 switch (scf_error()) {
5410                 case SCF_ERROR_DELETED:
5411                         return (ENODEV);
5412 
5413                 case SCF_ERROR_CONNECTION_BROKEN:
5414                         return (ECONNABORTED);
5415 
5416                 case SCF_ERROR_NOT_SET:
5417                 case SCF_ERROR_NOT_BOUND:
5418                 default:
5419                         bad_error("scf_pg_get_type", scf_error());
5420                 }
5421         }
5422 
5423         if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5424                 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5425                         return (0);
5426 
5427                 switch (scf_error()) {
5428                 case SCF_ERROR_NOT_FOUND:
5429                         break;
5430 
5431                 case SCF_ERROR_CONNECTION_BROKEN:
5432                         return (ECONNABORTED);
5433 
5434                 case SCF_ERROR_DELETED:
5435                         return (ENODEV);
5436 
5437                 case SCF_ERROR_INVALID_ARGUMENT:
5438                 case SCF_ERROR_NOT_BOUND:
5439                 case SCF_ERROR_HANDLE_MISMATCH:
5440                 case SCF_ERROR_NOT_SET:
5441                 default:
5442                         bad_error("scf_pg_get_property", scf_error());
5443                 }
5444         }
5445 
5446         /* lookup pg in new properties */
5447         if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5448                 switch (scf_error()) {
5449                 case SCF_ERROR_DELETED:
5450                         return (ENODEV);
5451 
5452                 case SCF_ERROR_CONNECTION_BROKEN:
5453                         return (ECONNABORTED);
5454 
5455                 case SCF_ERROR_NOT_SET:
5456                 case SCF_ERROR_NOT_BOUND:
5457                 default:
5458                         bad_error("scf_pg_get_name", scf_error());
5459                 }
5460         }
5461 
5462         pgrp.sc_pgroup_name = imp_str;
5463         mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5464 
5465         if (mpg != NULL)
5466                 mpg->sc_pgroup_seen = 1;
5467 
5468         /* Special handling for dependents */
5469         if (strcmp(imp_str, "dependents") == 0)
5470                 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5471 
5472         if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5473                 return (upgrade_manifestfiles(NULL, ient, running, ent));
5474 
5475         if (mpg == NULL || mpg->sc_pgroup_delete) {
5476                 /* property group was deleted from manifest */
5477                 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5478                         switch (scf_error()) {
5479                         case SCF_ERROR_NOT_FOUND:
5480                                 return (0);
5481 
5482                         case SCF_ERROR_DELETED:
5483                         case SCF_ERROR_CONNECTION_BROKEN:
5484                                 return (scferror2errno(scf_error()));
5485 
5486                         case SCF_ERROR_INVALID_ARGUMENT:
5487                         case SCF_ERROR_HANDLE_MISMATCH:
5488                         case SCF_ERROR_NOT_BOUND:
5489                         case SCF_ERROR_NOT_SET:
5490                         default:
5491                                 bad_error("entity_get_pg", scf_error());
5492                         }
5493                 }
5494 
5495                 if (mpg != NULL && mpg->sc_pgroup_delete) {
5496                         if (g_verbose)
5497                                 warn(deleting, ient->sc_fmri, imp_str);
5498                         if (scf_pg_delete(imp_pg2) == 0)
5499                                 return (0);
5500 
5501                         switch (scf_error()) {
5502                         case SCF_ERROR_DELETED:
5503                                 return (0);
5504 
5505                         case SCF_ERROR_CONNECTION_BROKEN:
5506                         case SCF_ERROR_BACKEND_READONLY:
5507                         case SCF_ERROR_BACKEND_ACCESS:
5508                                 return (scferror2errno(scf_error()));
5509 
5510                         case SCF_ERROR_PERMISSION_DENIED:
5511                                 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5512                                 return (scferror2errno(scf_error()));
5513 
5514                         case SCF_ERROR_NOT_SET:
5515                         default:
5516                                 bad_error("scf_pg_delete", scf_error());
5517                         }
5518                 }
5519 
5520                 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5521                 switch (r) {
5522                 case 0:
5523                         break;
5524 
5525                 case ECANCELED:
5526                         return (ENODEV);
5527 
5528                 case ECONNABORTED:
5529                 case ENOMEM:
5530                 case EBADF:
5531                 case EACCES:
5532                         return (r);
5533 
5534                 default:
5535                         bad_error("load_pg", r);
5536                 }
5537 
5538                 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5539                 switch (r) {
5540                 case 0:
5541                         break;
5542 
5543                 case ECANCELED:
5544                 case ECONNABORTED:
5545                 case ENOMEM:
5546                 case EBADF:
5547                 case EACCES:
5548                         internal_pgroup_free(lipg_i);
5549                         return (r);
5550 
5551                 default:
5552                         bad_error("load_pg", r);
5553                 }
5554 
5555                 if (pg_equal(lipg_i, curpg_i)) {
5556                         if (g_verbose)
5557                                 warn(deleting, ient->sc_fmri, imp_str);
5558                         if (scf_pg_delete(imp_pg2) != 0) {
5559                                 switch (scf_error()) {
5560                                 case SCF_ERROR_DELETED:
5561                                         break;
5562 
5563                                 case SCF_ERROR_CONNECTION_BROKEN:
5564                                         internal_pgroup_free(lipg_i);
5565                                         internal_pgroup_free(curpg_i);
5566                                         return (ECONNABORTED);
5567 
5568                                 case SCF_ERROR_NOT_SET:
5569                                 case SCF_ERROR_NOT_BOUND:
5570                                 default:
5571                                         bad_error("scf_pg_delete", scf_error());
5572                                 }
5573                         }
5574                 } else {
5575                         report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5576                 }
5577 
5578                 internal_pgroup_free(lipg_i);
5579                 internal_pgroup_free(curpg_i);
5580 
5581                 return (0);
5582         }
5583 
5584         /*
5585          * Only dependent pgs can have override set, and we skipped those
5586          * above.
5587          */
5588         assert(!mpg->sc_pgroup_override);
5589 
5590         /* compare */
5591         r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5592         switch (r) {
5593         case 0:
5594                 break;
5595 
5596         case ECANCELED:
5597                 return (ENODEV);
5598 
5599         case ECONNABORTED:
5600         case EBADF:
5601         case ENOMEM:
5602         case EACCES:
5603                 return (r);
5604 
5605         default:
5606                 bad_error("load_pg", r);
5607         }
5608 
5609         if (pg_equal(mpg, lipg_i)) {
5610                 /* The manifest pg has not changed.  Move on. */
5611                 r = 0;
5612                 goto out;
5613         }
5614 
5615         /* upgrade current properties according to lipg & mpg */
5616         if (running != NULL)
5617                 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5618         else
5619                 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5620         if (r != 0) {
5621                 switch (scf_error()) {
5622                 case SCF_ERROR_CONNECTION_BROKEN:
5623                         r = scferror2errno(scf_error());
5624                         goto out;
5625 
5626                 case SCF_ERROR_DELETED:
5627                         if (running != NULL)
5628                                 r = ENODEV;
5629                         else
5630                                 r = ECANCELED;
5631                         goto out;
5632 
5633                 case SCF_ERROR_NOT_FOUND:
5634                         break;
5635 
5636                 case SCF_ERROR_INVALID_ARGUMENT:
5637                 case SCF_ERROR_HANDLE_MISMATCH:
5638                 case SCF_ERROR_NOT_BOUND:
5639                 case SCF_ERROR_NOT_SET:
5640                 default:
5641                         bad_error("entity_get_pg", scf_error());
5642                 }
5643 
5644                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5645 
5646                 r = 0;
5647                 goto out;
5648         }
5649 
5650         r = load_pg_attrs(imp_pg2, &curpg_i);
5651         switch (r) {
5652         case 0:
5653                 break;
5654 
5655         case ECANCELED:
5656                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5657                 r = 0;
5658                 goto out;
5659 
5660         case ECONNABORTED:
5661         case ENOMEM:
5662                 goto out;
5663 
5664         default:
5665                 bad_error("load_pg_attrs", r);
5666         }
5667 
5668         if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5669                 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5670                 internal_pgroup_free(curpg_i);
5671                 r = 0;
5672                 goto out;
5673         }
5674 
5675         internal_pgroup_free(curpg_i);
5676 
5677         r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5678         switch (r) {
5679         case 0:
5680                 break;
5681 
5682         case ECANCELED:
5683                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5684                 r = 0;
5685                 goto out;
5686 
5687         case ECONNABORTED:
5688         case EBADF:
5689         case ENOMEM:
5690         case EACCES:
5691                 goto out;
5692 
5693         default:
5694                 bad_error("load_pg", r);
5695         }
5696 
5697         if (pg_equal(lipg_i, curpg_i) &&
5698             !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5699                 int do_delete = 1;
5700 
5701                 if (g_verbose)
5702                         warn(gettext("%s: Upgrading property group \"%s\".\n"),
5703                             ient->sc_fmri, mpg->sc_pgroup_name);
5704 
5705                 internal_pgroup_free(curpg_i);
5706 
5707                 if (running != NULL &&
5708                     entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5709                         switch (scf_error()) {
5710                         case SCF_ERROR_DELETED:
5711                                 r = ECANCELED;
5712                                 goto out;
5713 
5714                         case SCF_ERROR_NOT_FOUND:
5715                                 do_delete = 0;
5716                                 break;
5717 
5718                         case SCF_ERROR_CONNECTION_BROKEN:
5719                                 r = scferror2errno(scf_error());
5720                                 goto out;
5721 
5722                         case SCF_ERROR_HANDLE_MISMATCH:
5723                         case SCF_ERROR_INVALID_ARGUMENT:
5724                         case SCF_ERROR_NOT_SET:
5725                         case SCF_ERROR_NOT_BOUND:
5726                         default:
5727                                 bad_error("entity_get_pg", scf_error());
5728                         }
5729                 }
5730 
5731                 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5732                         switch (scf_error()) {
5733                         case SCF_ERROR_DELETED:
5734                                 break;
5735 
5736                         case SCF_ERROR_CONNECTION_BROKEN:
5737                         case SCF_ERROR_BACKEND_READONLY:
5738                         case SCF_ERROR_BACKEND_ACCESS:
5739                                 r = scferror2errno(scf_error());
5740                                 goto out;
5741 
5742                         case SCF_ERROR_PERMISSION_DENIED:
5743                                 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5744                                     ient->sc_fmri);
5745                                 r = scferror2errno(scf_error());
5746                                 goto out;
5747 
5748                         case SCF_ERROR_NOT_SET:
5749                         case SCF_ERROR_NOT_BOUND:
5750                         default:
5751                                 bad_error("scf_pg_delete", scf_error());
5752                         }
5753                 }
5754 
5755                 cbdata.sc_handle = g_hndl;
5756                 cbdata.sc_parent = ent;
5757                 cbdata.sc_service = issvc;
5758                 cbdata.sc_flags = 0;
5759                 cbdata.sc_source_fmri = ient->sc_fmri;
5760                 cbdata.sc_target_fmri = ient->sc_fmri;
5761 
5762                 r = entity_pgroup_import(mpg, &cbdata);
5763                 switch (r) {
5764                 case UU_WALK_NEXT:
5765                         r = 0;
5766                         goto out;
5767 
5768                 case UU_WALK_ERROR:
5769                         if (cbdata.sc_err == EEXIST) {
5770                                 warn(emsg_pg_added, ient->sc_fmri,
5771                                     mpg->sc_pgroup_name);
5772                                 r = EBUSY;
5773                         } else {
5774                                 r = cbdata.sc_err;
5775                         }
5776                         goto out;
5777 
5778                 default:
5779                         bad_error("entity_pgroup_import", r);
5780                 }
5781         }
5782 
5783         if (running != NULL &&
5784             entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5785                 switch (scf_error()) {
5786                 case SCF_ERROR_CONNECTION_BROKEN:
5787                 case SCF_ERROR_DELETED:
5788                         r = scferror2errno(scf_error());
5789                         goto out;
5790 
5791                 case SCF_ERROR_NOT_FOUND:
5792                         break;
5793 
5794                 case SCF_ERROR_HANDLE_MISMATCH:
5795                 case SCF_ERROR_INVALID_ARGUMENT:
5796                 case SCF_ERROR_NOT_SET:
5797                 case SCF_ERROR_NOT_BOUND:
5798                 default:
5799                         bad_error("entity_get_pg", scf_error());
5800                 }
5801 
5802                 cbdata.sc_handle = g_hndl;
5803                 cbdata.sc_parent = ent;
5804                 cbdata.sc_service = issvc;
5805                 cbdata.sc_flags = SCI_FORCE;
5806                 cbdata.sc_source_fmri = ient->sc_fmri;
5807                 cbdata.sc_target_fmri = ient->sc_fmri;
5808 
5809                 r = entity_pgroup_import(mpg, &cbdata);
5810                 switch (r) {
5811                 case UU_WALK_NEXT:
5812                         r = 0;
5813                         goto out;
5814 
5815                 case UU_WALK_ERROR:
5816                         if (cbdata.sc_err == EEXIST) {
5817                                 warn(emsg_pg_added, ient->sc_fmri,
5818                                     mpg->sc_pgroup_name);
5819                                 r = EBUSY;
5820                         } else {
5821                                 r = cbdata.sc_err;
5822                         }
5823                         goto out;
5824 
5825                 default:
5826                         bad_error("entity_pgroup_import", r);
5827                 }
5828         }
5829 
5830         r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5831         internal_pgroup_free(curpg_i);
5832         switch (r) {
5833         case 0:
5834                 ient->sc_import_state = IMPORT_PROP_BEGUN;
5835                 break;
5836 
5837         case ECANCELED:
5838                 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5839                 r = EBUSY;
5840                 break;
5841 
5842         case EPERM:
5843                 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5844                 break;
5845 
5846         case EBUSY:
5847                 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5848                 break;
5849 
5850         case ECONNABORTED:
5851         case ENOMEM:
5852         case ENOSPC:
5853         case EROFS:
5854         case EACCES:
5855         case EINVAL:
5856                 break;
5857 
5858         default:
5859                 bad_error("upgrade_pg", r);
5860         }
5861 
5862 out:
5863         internal_pgroup_free(lipg_i);
5864         return (r);
5865 }
5866 
5867 /*
5868  * Upgrade the properties of ent according to snpl & ient.
5869  *
5870  * Returns
5871  *   0 - success
5872  *   ECONNABORTED - repository connection broken
5873  *   ENOMEM - out of memory
5874  *   ENOSPC - configd is out of resources
5875  *   ECANCELED - ent was deleted
5876  *   ENODEV - entity containing snpl was deleted
5877  *          - entity containing running was deleted
5878  *   EBADF - imp_snpl is corrupt (error printed)
5879  *         - ent has corrupt pg (error printed)
5880  *         - dependent has corrupt pg (error printed)
5881  *         - dependent target has a corrupt snapshot (error printed)
5882  *   EBUSY - pg was added, changed, or deleted (error printed)
5883  *         - dependent target was deleted (error printed)
5884  *         - dependent pg changed (error printed)
5885  *   EINVAL - invalid property group name (error printed)
5886  *          - invalid property name (error printed)
5887  *          - invalid value (error printed)
5888  *          - ient has invalid pgroup or dependent (error printed)
5889  *   EPERM - could not create property group (permission denied) (error printed)
5890  *         - could not modify property group (permission denied) (error printed)
5891  *         - couldn't delete, upgrade, or import pg or dependent (error printed)
5892  *   EROFS - could not create property group (repository read-only)
5893  *         - couldn't delete, upgrade, or import pg or dependent
5894  *   EACCES - could not create property group (backend access denied)
5895  *          - couldn't delete, upgrade, or import pg or dependent
5896  *   EEXIST - dependent collision in target service (error printed)
5897  */
5898 static int
5899 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5900     entity_t *ient)
5901 {
5902         pgroup_t *pg, *rpg;
5903         int r;
5904         uu_list_t *pgs = ient->sc_pgroups;
5905 
5906         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5907 
5908         /* clear sc_sceen for pgs */
5909         if (uu_list_walk(pgs, clear_int,
5910             (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5911                 bad_error("uu_list_walk", uu_error());
5912 
5913         if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5914                 switch (scf_error()) {
5915                 case SCF_ERROR_DELETED:
5916                         return (ENODEV);
5917 
5918                 case SCF_ERROR_CONNECTION_BROKEN:
5919                         return (ECONNABORTED);
5920 
5921                 case SCF_ERROR_NOT_SET:
5922                 case SCF_ERROR_NOT_BOUND:
5923                 case SCF_ERROR_HANDLE_MISMATCH:
5924                 default:
5925                         bad_error("scf_iter_snaplevel_pgs", scf_error());
5926                 }
5927         }
5928 
5929         for (;;) {
5930                 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5931                 if (r == 0)
5932                         break;
5933                 if (r == 1) {
5934                         r = process_old_pg(imp_pg, ient, ent, running);
5935                         switch (r) {
5936                         case 0:
5937                                 break;
5938 
5939                         case ECONNABORTED:
5940                         case ENOMEM:
5941                         case ENOSPC:
5942                         case ECANCELED:
5943                         case ENODEV:
5944                         case EPERM:
5945                         case EROFS:
5946                         case EACCES:
5947                         case EBADF:
5948                         case EBUSY:
5949                         case EINVAL:
5950                         case EEXIST:
5951                                 return (r);
5952 
5953                         default:
5954                                 bad_error("process_old_pg", r);
5955                         }
5956                         continue;
5957                 }
5958                 if (r != -1)
5959                         bad_error("scf_iter_next_pg", r);
5960 
5961                 switch (scf_error()) {
5962                 case SCF_ERROR_DELETED:
5963                         return (ENODEV);
5964 
5965                 case SCF_ERROR_CONNECTION_BROKEN:
5966                         return (ECONNABORTED);
5967 
5968                 case SCF_ERROR_HANDLE_MISMATCH:
5969                 case SCF_ERROR_NOT_BOUND:
5970                 case SCF_ERROR_NOT_SET:
5971                 case SCF_ERROR_INVALID_ARGUMENT:
5972                 default:
5973                         bad_error("scf_iter_next_pg", scf_error());
5974                 }
5975         }
5976 
5977         for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5978                 if (pg->sc_pgroup_seen)
5979                         continue;
5980 
5981                 /* pg is new */
5982 
5983                 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5984                         r = upgrade_dependents(NULL, imp_snpl, ient, running,
5985                             ent);
5986                         switch (r) {
5987                         case 0:
5988                                 break;
5989 
5990                         case ECONNABORTED:
5991                         case ENOMEM:
5992                         case ENOSPC:
5993                         case ECANCELED:
5994                         case ENODEV:
5995                         case EBADF:
5996                         case EBUSY:
5997                         case EINVAL:
5998                         case EPERM:
5999                         case EROFS:
6000                         case EACCES:
6001                         case EEXIST:
6002                                 return (r);
6003 
6004                         default:
6005                                 bad_error("upgrade_dependents", r);
6006                         }
6007                         continue;
6008                 }
6009 
6010                 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6011                         r = upgrade_manifestfiles(pg, ient, running, ent);
6012                         switch (r) {
6013                         case 0:
6014                                 break;
6015 
6016                         case ECONNABORTED:
6017                         case ENOMEM:
6018                         case ENOSPC:
6019                         case ECANCELED:
6020                         case ENODEV:
6021                         case EBADF:
6022                         case EBUSY:
6023                         case EINVAL:
6024                         case EPERM:
6025                         case EROFS:
6026                         case EACCES:
6027                         case EEXIST:
6028                                 return (r);
6029 
6030                         default:
6031                                 bad_error("upgrade_manifestfiles", r);
6032                         }
6033                         continue;
6034                 }
6035 
6036                 if (running != NULL) {
6037                         r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6038                             imp_pg);
6039                 } else {
6040                         r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6041                             imp_pg);
6042                 }
6043                 if (r != 0) {
6044                         scf_callback_t cbdata;
6045 
6046                         switch (scf_error()) {
6047                         case SCF_ERROR_NOT_FOUND:
6048                                 break;
6049 
6050                         case SCF_ERROR_CONNECTION_BROKEN:
6051                                 return (scferror2errno(scf_error()));
6052 
6053                         case SCF_ERROR_DELETED:
6054                                 if (running != NULL)
6055                                         return (ENODEV);
6056                                 else
6057                                         return (scferror2errno(scf_error()));
6058 
6059                         case SCF_ERROR_INVALID_ARGUMENT:
6060                                 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6061                                     pg->sc_pgroup_name);
6062                                 return (EINVAL);
6063 
6064                         case SCF_ERROR_NOT_SET:
6065                         case SCF_ERROR_HANDLE_MISMATCH:
6066                         case SCF_ERROR_NOT_BOUND:
6067                         default:
6068                                 bad_error("entity_get_pg", scf_error());
6069                         }
6070 
6071                         /* User doesn't have pg, so import it. */
6072 
6073                         cbdata.sc_handle = g_hndl;
6074                         cbdata.sc_parent = ent;
6075                         cbdata.sc_service = issvc;
6076                         cbdata.sc_flags = SCI_FORCE;
6077                         cbdata.sc_source_fmri = ient->sc_fmri;
6078                         cbdata.sc_target_fmri = ient->sc_fmri;
6079 
6080                         r = entity_pgroup_import(pg, &cbdata);
6081                         switch (r) {
6082                         case UU_WALK_NEXT:
6083                                 ient->sc_import_state = IMPORT_PROP_BEGUN;
6084                                 continue;
6085 
6086                         case UU_WALK_ERROR:
6087                                 if (cbdata.sc_err == EEXIST) {
6088                                         warn(emsg_pg_added, ient->sc_fmri,
6089                                             pg->sc_pgroup_name);
6090                                         return (EBUSY);
6091                                 }
6092                                 return (cbdata.sc_err);
6093 
6094                         default:
6095                                 bad_error("entity_pgroup_import", r);
6096                         }
6097                 }
6098 
6099                 /* report differences between pg & current */
6100                 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6101                 switch (r) {
6102                 case 0:
6103                         break;
6104 
6105                 case ECANCELED:
6106                         warn(emsg_pg_deleted, ient->sc_fmri,
6107                             pg->sc_pgroup_name);
6108                         return (EBUSY);
6109 
6110                 case ECONNABORTED:
6111                 case EBADF:
6112                 case ENOMEM:
6113                 case EACCES:
6114                         return (r);
6115 
6116                 default:
6117                         bad_error("load_pg", r);
6118                 }
6119                 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6120                 internal_pgroup_free(rpg);
6121                 rpg = NULL;
6122         }
6123 
6124         return (0);
6125 }
6126 
6127 /*
6128  * Import an instance.  If it doesn't exist, create it.  If it has
6129  * a last-import snapshot, upgrade its properties.  Finish by updating its
6130  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6131  * could have been created for a dependent tag in another manifest.  Import the
6132  * new properties.  If there's a conflict, don't override, like now?
6133  *
6134  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6135  * lcbdata->sc_err to
6136  *   ECONNABORTED - repository connection broken
6137  *   ENOMEM - out of memory
6138  *   ENOSPC - svc.configd is out of resources
6139  *   EEXIST - dependency collision in dependent service (error printed)
6140  *   EPERM - couldn't create temporary instance (permission denied)
6141  *         - couldn't import into temporary instance (permission denied)
6142  *         - couldn't take snapshot (permission denied)
6143  *         - couldn't upgrade properties (permission denied)
6144  *         - couldn't import properties (permission denied)
6145  *         - couldn't import dependents (permission denied)
6146  *   EROFS - couldn't create temporary instance (repository read-only)
6147  *         - couldn't import into temporary instance (repository read-only)
6148  *         - couldn't upgrade properties (repository read-only)
6149  *         - couldn't import properties (repository read-only)
6150  *         - couldn't import dependents (repository read-only)
6151  *   EACCES - couldn't create temporary instance (backend access denied)
6152  *          - couldn't import into temporary instance (backend access denied)
6153  *          - couldn't upgrade properties (backend access denied)
6154  *          - couldn't import properties (backend access denied)
6155  *          - couldn't import dependents (backend access denied)
6156  *   EINVAL - invalid instance name (error printed)
6157  *          - invalid pgroup_t's (error printed)
6158  *          - invalid dependents (error printed)
6159  *   EBUSY - temporary service deleted (error printed)
6160  *         - temporary instance deleted (error printed)
6161  *         - temporary instance changed (error printed)
6162  *         - temporary instance already exists (error printed)
6163  *         - instance deleted (error printed)
6164  *   EBADF - instance has corrupt last-import snapshot (error printed)
6165  *         - instance is corrupt (error printed)
6166  *         - dependent has corrupt pg (error printed)
6167  *         - dependent target has a corrupt snapshot (error printed)
6168  *   -1 - unknown libscf error (error printed)
6169  */
6170 static int
6171 lscf_instance_import(void *v, void *pvt)
6172 {
6173         entity_t *inst = v;
6174         scf_callback_t ctx;
6175         scf_callback_t *lcbdata = pvt;
6176         scf_service_t *rsvc = lcbdata->sc_parent;
6177         int r;
6178         scf_snaplevel_t *running;
6179         int flags = lcbdata->sc_flags;
6180 
6181         const char * const emsg_tdel =
6182             gettext("Temporary instance svc:/%s:%s was deleted.\n");
6183         const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6184             "changed unexpectedly.\n");
6185         const char * const emsg_del = gettext("%s changed unexpectedly "
6186             "(instance \"%s\" was deleted.)\n");
6187         const char * const emsg_badsnap = gettext(
6188             "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6189 
6190         /*
6191          * prepare last-import snapshot:
6192          * create temporary instance (service was precreated)
6193          * populate with properties from bundle
6194          * take snapshot
6195          */
6196         if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6197                 switch (scf_error()) {
6198                 case SCF_ERROR_CONNECTION_BROKEN:
6199                 case SCF_ERROR_NO_RESOURCES:
6200                 case SCF_ERROR_BACKEND_READONLY:
6201                 case SCF_ERROR_BACKEND_ACCESS:
6202                         return (stash_scferror(lcbdata));
6203 
6204                 case SCF_ERROR_EXISTS:
6205                         warn(gettext("Temporary service svc:/%s "
6206                             "changed unexpectedly (instance \"%s\" added).\n"),
6207                             imp_tsname, inst->sc_name);
6208                         lcbdata->sc_err = EBUSY;
6209                         return (UU_WALK_ERROR);
6210 
6211                 case SCF_ERROR_DELETED:
6212                         warn(gettext("Temporary service svc:/%s "
6213                             "was deleted unexpectedly.\n"), imp_tsname);
6214                         lcbdata->sc_err = EBUSY;
6215                         return (UU_WALK_ERROR);
6216 
6217                 case SCF_ERROR_INVALID_ARGUMENT:
6218                         warn(gettext("Invalid instance name \"%s\".\n"),
6219                             inst->sc_name);
6220                         return (stash_scferror(lcbdata));
6221 
6222                 case SCF_ERROR_PERMISSION_DENIED:
6223                         warn(gettext("Could not create temporary instance "
6224                             "\"%s\" in svc:/%s (permission denied).\n"),
6225                             inst->sc_name, imp_tsname);
6226                         return (stash_scferror(lcbdata));
6227 
6228                 case SCF_ERROR_HANDLE_MISMATCH:
6229                 case SCF_ERROR_NOT_BOUND:
6230                 case SCF_ERROR_NOT_SET:
6231                 default:
6232                         bad_error("scf_service_add_instance", scf_error());
6233                 }
6234         }
6235 
6236         r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6237             inst->sc_name);
6238         if (r < 0)
6239                 bad_error("snprintf", errno);
6240 
6241         r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6242             lcbdata->sc_flags | SCI_NOENABLED);
6243         switch (r) {
6244         case 0:
6245                 break;
6246 
6247         case ECANCELED:
6248                 warn(emsg_tdel, imp_tsname, inst->sc_name);
6249                 lcbdata->sc_err = EBUSY;
6250                 r = UU_WALK_ERROR;
6251                 goto deltemp;
6252 
6253         case EEXIST:
6254                 warn(emsg_tchg, imp_tsname, inst->sc_name);
6255                 lcbdata->sc_err = EBUSY;
6256                 r = UU_WALK_ERROR;
6257                 goto deltemp;
6258 
6259         case ECONNABORTED:
6260                 goto connaborted;
6261 
6262         case ENOMEM:
6263         case ENOSPC:
6264         case EPERM:
6265         case EROFS:
6266         case EACCES:
6267         case EINVAL:
6268         case EBUSY:
6269                 lcbdata->sc_err = r;
6270                 r = UU_WALK_ERROR;
6271                 goto deltemp;
6272 
6273         default:
6274                 bad_error("lscf_import_instance_pgs", r);
6275         }
6276 
6277         r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6278             inst->sc_name);
6279         if (r < 0)
6280                 bad_error("snprintf", errno);
6281 
6282         ctx.sc_handle = lcbdata->sc_handle;
6283         ctx.sc_parent = imp_tinst;
6284         ctx.sc_service = 0;
6285         ctx.sc_source_fmri = inst->sc_fmri;
6286         ctx.sc_target_fmri = imp_str;
6287         if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6288             UU_DEFAULT) != 0) {
6289                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6290                         bad_error("uu_list_walk", uu_error());
6291 
6292                 switch (ctx.sc_err) {
6293                 case ECONNABORTED:
6294                         goto connaborted;
6295 
6296                 case ECANCELED:
6297                         warn(emsg_tdel, imp_tsname, inst->sc_name);
6298                         lcbdata->sc_err = EBUSY;
6299                         break;
6300 
6301                 case EEXIST:
6302                         warn(emsg_tchg, imp_tsname, inst->sc_name);
6303                         lcbdata->sc_err = EBUSY;
6304                         break;
6305 
6306                 default:
6307                         lcbdata->sc_err = ctx.sc_err;
6308                 }
6309                 r = UU_WALK_ERROR;
6310                 goto deltemp;
6311         }
6312 
6313         if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6314             inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6315                 switch (scf_error()) {
6316                 case SCF_ERROR_CONNECTION_BROKEN:
6317                         goto connaborted;
6318 
6319                 case SCF_ERROR_NO_RESOURCES:
6320                         r = stash_scferror(lcbdata);
6321                         goto deltemp;
6322 
6323                 case SCF_ERROR_EXISTS:
6324                         warn(emsg_tchg, imp_tsname, inst->sc_name);
6325                         lcbdata->sc_err = EBUSY;
6326                         r = UU_WALK_ERROR;
6327                         goto deltemp;
6328 
6329                 case SCF_ERROR_PERMISSION_DENIED:
6330                         warn(gettext("Could not take \"%s\" snapshot of %s "
6331                             "(permission denied).\n"), snap_lastimport,
6332                             imp_str);
6333                         r = stash_scferror(lcbdata);
6334                         goto deltemp;
6335 
6336                 default:
6337                         scfwarn();
6338                         lcbdata->sc_err = -1;
6339                         r = UU_WALK_ERROR;
6340                         goto deltemp;
6341 
6342                 case SCF_ERROR_HANDLE_MISMATCH:
6343                 case SCF_ERROR_INVALID_ARGUMENT:
6344                 case SCF_ERROR_NOT_SET:
6345                         bad_error("_scf_snapshot_take_new_named", scf_error());
6346                 }
6347         }
6348 
6349         if (lcbdata->sc_flags & SCI_FRESH)
6350                 goto fresh;
6351 
6352         if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6353                 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6354                     imp_lisnap) != 0) {
6355                         switch (scf_error()) {
6356                         case SCF_ERROR_DELETED:
6357                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6358                                     inst->sc_name);
6359                                 lcbdata->sc_err = EBUSY;
6360                                 r = UU_WALK_ERROR;
6361                                 goto deltemp;
6362 
6363                         case SCF_ERROR_NOT_FOUND:
6364                                 flags |= SCI_FORCE;
6365                                 goto nosnap;
6366 
6367                         case SCF_ERROR_CONNECTION_BROKEN:
6368                                 goto connaborted;
6369 
6370                         case SCF_ERROR_INVALID_ARGUMENT:
6371                         case SCF_ERROR_HANDLE_MISMATCH:
6372                         case SCF_ERROR_NOT_BOUND:
6373                         case SCF_ERROR_NOT_SET:
6374                         default:
6375                                 bad_error("scf_instance_get_snapshot",
6376                                     scf_error());
6377                         }
6378                 }
6379 
6380                 /* upgrade */
6381 
6382                 /*
6383                  * compare new properties with last-import properties
6384                  * upgrade current properties
6385                  */
6386                 /* clear sc_sceen for pgs */
6387                 if (uu_list_walk(inst->sc_pgroups, clear_int,
6388                     (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6389                     0)
6390                         bad_error("uu_list_walk", uu_error());
6391 
6392                 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6393                 switch (r) {
6394                 case 0:
6395                         break;
6396 
6397                 case ECONNABORTED:
6398                         goto connaborted;
6399 
6400                 case ECANCELED:
6401                         warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6402                         lcbdata->sc_err = EBUSY;
6403                         r = UU_WALK_ERROR;
6404                         goto deltemp;
6405 
6406                 case ENOENT:
6407                         warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6408                         lcbdata->sc_err = EBADF;
6409                         r = UU_WALK_ERROR;
6410                         goto deltemp;
6411 
6412                 default:
6413                         bad_error("get_snaplevel", r);
6414                 }
6415 
6416                 if (scf_instance_get_snapshot(imp_inst, snap_running,
6417                     imp_rsnap) != 0) {
6418                         switch (scf_error()) {
6419                         case SCF_ERROR_DELETED:
6420                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6421                                     inst->sc_name);
6422                                 lcbdata->sc_err = EBUSY;
6423                                 r = UU_WALK_ERROR;
6424                                 goto deltemp;
6425 
6426                         case SCF_ERROR_NOT_FOUND:
6427                                 break;
6428 
6429                         case SCF_ERROR_CONNECTION_BROKEN:
6430                                 goto connaborted;
6431 
6432                         case SCF_ERROR_INVALID_ARGUMENT:
6433                         case SCF_ERROR_HANDLE_MISMATCH:
6434                         case SCF_ERROR_NOT_BOUND:
6435                         case SCF_ERROR_NOT_SET:
6436                         default:
6437                                 bad_error("scf_instance_get_snapshot",
6438                                     scf_error());
6439                         }
6440 
6441                         running = NULL;
6442                 } else {
6443                         r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6444                         switch (r) {
6445                         case 0:
6446                                 running = imp_rsnpl;
6447                                 break;
6448 
6449                         case ECONNABORTED:
6450                                 goto connaborted;
6451 
6452                         case ECANCELED:
6453                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6454                                     inst->sc_name);
6455                                 lcbdata->sc_err = EBUSY;
6456                                 r = UU_WALK_ERROR;
6457                                 goto deltemp;
6458 
6459                         case ENOENT:
6460                                 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6461                                 lcbdata->sc_err = EBADF;
6462                                 r = UU_WALK_ERROR;
6463                                 goto deltemp;
6464 
6465                         default:
6466                                 bad_error("get_snaplevel", r);
6467                         }
6468                 }
6469 
6470                 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6471                 switch (r) {
6472                 case 0:
6473                         break;
6474 
6475                 case ECANCELED:
6476                 case ENODEV:
6477                         warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6478                         lcbdata->sc_err = EBUSY;
6479                         r = UU_WALK_ERROR;
6480                         goto deltemp;
6481 
6482                 case ECONNABORTED:
6483                         goto connaborted;
6484 
6485                 case ENOMEM:
6486                 case ENOSPC:
6487                 case EBADF:
6488                 case EBUSY:
6489                 case EINVAL:
6490                 case EPERM:
6491                 case EROFS:
6492                 case EACCES:
6493                 case EEXIST:
6494                         lcbdata->sc_err = r;
6495                         r = UU_WALK_ERROR;
6496                         goto deltemp;
6497 
6498                 default:
6499                         bad_error("upgrade_props", r);
6500                 }
6501 
6502                 inst->sc_import_state = IMPORT_PROP_DONE;
6503         } else {
6504                 switch (scf_error()) {
6505                 case SCF_ERROR_CONNECTION_BROKEN:
6506                         goto connaborted;
6507 
6508                 case SCF_ERROR_NOT_FOUND:
6509                         break;
6510 
6511                 case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
6512                 case SCF_ERROR_HANDLE_MISMATCH:
6513                 case SCF_ERROR_NOT_BOUND:
6514                 case SCF_ERROR_NOT_SET:
6515                 default:
6516                         bad_error("scf_service_get_instance", scf_error());
6517                 }
6518 
6519 fresh:
6520                 /* create instance */
6521                 if (scf_service_add_instance(rsvc, inst->sc_name,
6522                     imp_inst) != 0) {
6523                         switch (scf_error()) {
6524                         case SCF_ERROR_CONNECTION_BROKEN:
6525                                 goto connaborted;
6526 
6527                         case SCF_ERROR_NO_RESOURCES:
6528                         case SCF_ERROR_BACKEND_READONLY:
6529                         case SCF_ERROR_BACKEND_ACCESS:
6530                                 r = stash_scferror(lcbdata);
6531                                 goto deltemp;
6532 
6533                         case SCF_ERROR_EXISTS:
6534                                 warn(gettext("%s changed unexpectedly "
6535                                     "(instance \"%s\" added).\n"),
6536                                     inst->sc_parent->sc_fmri, inst->sc_name);
6537                                 lcbdata->sc_err = EBUSY;
6538                                 r = UU_WALK_ERROR;
6539                                 goto deltemp;
6540 
6541                         case SCF_ERROR_PERMISSION_DENIED:
6542                                 warn(gettext("Could not create \"%s\" instance "
6543                                     "in %s (permission denied).\n"),
6544                                     inst->sc_name, inst->sc_parent->sc_fmri);
6545                                 r = stash_scferror(lcbdata);
6546                                 goto deltemp;
6547 
6548                         case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6549                         case SCF_ERROR_HANDLE_MISMATCH:
6550                         case SCF_ERROR_NOT_BOUND:
6551                         case SCF_ERROR_NOT_SET:
6552                         default:
6553                                 bad_error("scf_service_add_instance",
6554                                     scf_error());
6555                         }
6556                 }
6557 
6558 nosnap:
6559                 /*
6560                  * Create a last-import snapshot to serve as an attachment
6561                  * point for the real one from the temporary instance.  Since
6562                  * the contents is irrelevant, take it now, while the instance
6563                  * is empty, to minimize svc.configd's work.
6564                  */
6565                 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6566                     imp_lisnap) != 0) {
6567                         switch (scf_error()) {
6568                         case SCF_ERROR_CONNECTION_BROKEN:
6569                                 goto connaborted;
6570 
6571                         case SCF_ERROR_NO_RESOURCES:
6572                                 r = stash_scferror(lcbdata);
6573                                 goto deltemp;
6574 
6575                         case SCF_ERROR_EXISTS:
6576                                 warn(gettext("%s changed unexpectedly "
6577                                     "(snapshot \"%s\" added).\n"),
6578                                     inst->sc_fmri, snap_lastimport);
6579                                 lcbdata->sc_err = EBUSY;
6580                                 r = UU_WALK_ERROR;
6581                                 goto deltemp;
6582 
6583                         case SCF_ERROR_PERMISSION_DENIED:
6584                                 warn(gettext("Could not take \"%s\" snapshot "
6585                                     "of %s (permission denied).\n"),
6586                                     snap_lastimport, inst->sc_fmri);
6587                                 r = stash_scferror(lcbdata);
6588                                 goto deltemp;
6589 
6590                         default:
6591                                 scfwarn();
6592                                 lcbdata->sc_err = -1;
6593                                 r = UU_WALK_ERROR;
6594                                 goto deltemp;
6595 
6596                         case SCF_ERROR_NOT_SET:
6597                         case SCF_ERROR_INTERNAL:
6598                         case SCF_ERROR_INVALID_ARGUMENT:
6599                         case SCF_ERROR_HANDLE_MISMATCH:
6600                                 bad_error("_scf_snapshot_take_new",
6601                                     scf_error());
6602                         }
6603                 }
6604 
6605                 if (li_only)
6606                         goto lionly;
6607 
6608                 inst->sc_import_state = IMPORT_PROP_BEGUN;
6609 
6610                 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6611                     flags);
6612                 switch (r) {
6613                 case 0:
6614                         break;
6615 
6616                 case ECONNABORTED:
6617                         goto connaborted;
6618 
6619                 case ECANCELED:
6620                         warn(gettext("%s changed unexpectedly "
6621                             "(instance \"%s\" deleted).\n"),
6622                             inst->sc_parent->sc_fmri, inst->sc_name);
6623                         lcbdata->sc_err = EBUSY;
6624                         r = UU_WALK_ERROR;
6625                         goto deltemp;
6626 
6627                 case EEXIST:
6628                         warn(gettext("%s changed unexpectedly "
6629                             "(property group added).\n"), inst->sc_fmri);
6630                         lcbdata->sc_err = EBUSY;
6631                         r = UU_WALK_ERROR;
6632                         goto deltemp;
6633 
6634                 default:
6635                         lcbdata->sc_err = r;
6636                         r = UU_WALK_ERROR;
6637                         goto deltemp;
6638 
6639                 case EINVAL:    /* caught above */
6640                         bad_error("lscf_import_instance_pgs", r);
6641                 }
6642 
6643                 ctx.sc_parent = imp_inst;
6644                 ctx.sc_service = 0;
6645                 ctx.sc_trans = NULL;
6646                 ctx.sc_flags = 0;
6647                 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6648                     &ctx, UU_DEFAULT) != 0) {
6649                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6650                                 bad_error("uu_list_walk", uu_error());
6651 
6652                         if (ctx.sc_err == ECONNABORTED)
6653                                 goto connaborted;
6654                         lcbdata->sc_err = ctx.sc_err;
6655                         r = UU_WALK_ERROR;
6656                         goto deltemp;
6657                 }
6658 
6659                 inst->sc_import_state = IMPORT_PROP_DONE;
6660 
6661                 if (g_verbose)
6662                         warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6663                             snap_initial, inst->sc_fmri);
6664                 r = take_snap(imp_inst, snap_initial, imp_snap);
6665                 switch (r) {
6666                 case 0:
6667                         break;
6668 
6669                 case ECONNABORTED:
6670                         goto connaborted;
6671 
6672                 case ENOSPC:
6673                 case -1:
6674                         lcbdata->sc_err = r;
6675                         r = UU_WALK_ERROR;
6676                         goto deltemp;
6677 
6678                 case ECANCELED:
6679                         warn(gettext("%s changed unexpectedly "
6680                             "(instance %s deleted).\n"),
6681                             inst->sc_parent->sc_fmri, inst->sc_name);
6682                         lcbdata->sc_err = r;
6683                         r = UU_WALK_ERROR;
6684                         goto deltemp;
6685 
6686                 case EPERM:
6687                         warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6688                         lcbdata->sc_err = r;
6689                         r = UU_WALK_ERROR;
6690                         goto deltemp;
6691 
6692                 default:
6693                         bad_error("take_snap", r);
6694                 }
6695         }
6696 
6697 lionly:
6698         if (lcbdata->sc_flags & SCI_NOSNAP)
6699                 goto deltemp;
6700 
6701         /* transfer snapshot from temporary instance */
6702         if (g_verbose)
6703                 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6704                     snap_lastimport, inst->sc_fmri);
6705         if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6706                 switch (scf_error()) {
6707                 case SCF_ERROR_CONNECTION_BROKEN:
6708                         goto connaborted;
6709 
6710                 case SCF_ERROR_NO_RESOURCES:
6711                         r = stash_scferror(lcbdata);
6712                         goto deltemp;
6713 
6714                 case SCF_ERROR_PERMISSION_DENIED:
6715                         warn(gettext("Could not take \"%s\" snapshot for %s "
6716                             "(permission denied).\n"), snap_lastimport,
6717                             inst->sc_fmri);
6718                         r = stash_scferror(lcbdata);
6719                         goto deltemp;
6720 
6721                 case SCF_ERROR_NOT_SET:
6722                 case SCF_ERROR_HANDLE_MISMATCH:
6723                 default:
6724                         bad_error("_scf_snapshot_attach", scf_error());
6725                 }
6726         }
6727 
6728         inst->sc_import_state = IMPORT_COMPLETE;
6729 
6730         r = UU_WALK_NEXT;
6731 
6732 deltemp:
6733         /* delete temporary instance */
6734         if (scf_instance_delete(imp_tinst) != 0) {
6735                 switch (scf_error()) {
6736                 case SCF_ERROR_DELETED:
6737                         break;
6738 
6739                 case SCF_ERROR_CONNECTION_BROKEN:
6740                         goto connaborted;
6741 
6742                 case SCF_ERROR_NOT_SET:
6743                 case SCF_ERROR_NOT_BOUND:
6744                 default:
6745                         bad_error("scf_instance_delete", scf_error());
6746                 }
6747         }
6748 
6749         return (r);
6750 
6751 connaborted:
6752         warn(gettext("Could not delete svc:/%s:%s "
6753             "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6754         lcbdata->sc_err = ECONNABORTED;
6755         return (UU_WALK_ERROR);
6756 }
6757 
6758 /*
6759  * When an instance is imported we end up telling configd about it. Once we tell
6760  * configd about these changes, startd eventually notices. If this is a new
6761  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6762  * property group. However, many of the other tools expect that this property
6763  * group exists and has certain values.
6764  *
6765  * These values are added asynchronously by startd. We should not return from
6766  * this routine until we can verify that the property group we need is there.
6767  *
6768  * Before we go ahead and verify this, we have to ask ourselves an important
6769  * question: Is the early manifest service currently running?  Because if it is
6770  * running and it has invoked us, then the service will never get a restarter
6771  * property because svc.startd is blocked on EMI finishing before it lets itself
6772  * fully connect to svc.configd. Of course, this means that this race condition
6773  * is in fact impossible to 100% eliminate.
6774  *
6775  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6776  * the state of the EMI instance. If it is online it bails out and makes sure
6777  * that it doesn't run again. In this case, we're going to do something similar,
6778  * only if the state is online, then we're going to actually verify. EMI always
6779  * has to be present, but it can be explicitly disabled to reduce the amount of
6780  * damage it can cause. If EMI has been disabled then we no longer have to worry
6781  * about the implicit race condition and can go ahead and check things. If EMI
6782  * is in some state that isn't online or disabled and isn't runinng, then we
6783  * assume that things are rather bad and we're not going to get in your way,
6784  * even if the rest of SMF does.
6785  *
6786  * Returns 0 on success or returns an errno.
6787  */
6788 #ifndef NATIVE_BUILD
6789 static int
6790 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6791 {
6792         int ret, err;
6793         struct timespec ts;
6794         char *emi_state;
6795 
6796         /*
6797          * smf_get_state does not distinguish between its different failure
6798          * modes: memory allocation failures, SMF internal failures, and a lack
6799          * of EMI entirely because it's been removed. In these cases, we're
6800          * going to be conservative and opt to say that if we don't know, better
6801          * to not block import or falsely warn to the user.
6802          */
6803         if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6804                 return (0);
6805         }
6806 
6807         /*
6808          * As per the block comment for this function check the state of EMI
6809          */
6810         if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6811             strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6812                 warn(gettext("Not validating instance %s:%s because EMI's "
6813                     "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6814                 free(emi_state);
6815                 return (0);
6816         }
6817 
6818         free(emi_state);
6819 
6820         /*
6821          * First we have to get the property.
6822          */
6823         if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6824                 ret = scf_error();
6825                 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6826                 return (ret);
6827         }
6828 
6829         /*
6830          * We should always be able to get the instance. It should already
6831          * exist because we just created it or got it. There probably is a
6832          * slim chance that someone may have come in and deleted it though from
6833          * under us.
6834          */
6835         if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6836             != 0) {
6837                 ret = scf_error();
6838                 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6839                 switch (ret) {
6840                 case SCF_ERROR_DELETED:
6841                         err = ENODEV;
6842                         break;
6843                 case SCF_ERROR_CONNECTION_BROKEN:
6844                         warn(gettext("Lost repository connection\n"));
6845                         err = ECONNABORTED;
6846                         break;
6847                 case SCF_ERROR_NOT_FOUND:
6848                         warn(gettext("Instance \"%s\" disappeared out from "
6849                             "under us.\n"), inst->sc_name);
6850                         err = ENOENT;
6851                         break;
6852                 default:
6853                         bad_error("scf_service_get_instance", ret);
6854                 }
6855 
6856                 return (err);
6857         }
6858 
6859         /*
6860          * An astute observer may want to use _scf_wait_pg which would notify us
6861          * of a property group change, unfortunately that does not work if the
6862          * property group in question does not exist. So instead we have to
6863          * manually poll and ask smf the best way to get to it.
6864          */
6865         while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6866             != SCF_SUCCESS) {
6867                 ret = scf_error();
6868                 if (ret != SCF_ERROR_NOT_FOUND) {
6869                         warn(gettext("Failed to get restarter property "
6870                             "group for instance: %s\n"), inst->sc_name);
6871                         switch (ret) {
6872                         case SCF_ERROR_DELETED:
6873                                 err = ENODEV;
6874                                 break;
6875                         case SCF_ERROR_CONNECTION_BROKEN:
6876                                 warn(gettext("Lost repository connection\n"));
6877                                 err = ECONNABORTED;
6878                                 break;
6879                         default:
6880                                 bad_error("scf_service_get_instance", ret);
6881                         }
6882 
6883                         return (err);
6884                 }
6885 
6886                 ts.tv_sec = pg_timeout / NANOSEC;
6887                 ts.tv_nsec = pg_timeout % NANOSEC;
6888 
6889                 (void) nanosleep(&ts, NULL);
6890         }
6891 
6892         /*
6893          * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6894          * So in addition to the property group being present, we need to wait
6895          * for the property to be there in some form.
6896          *
6897          * Note that a property group is a frozen snapshot in time. To properly
6898          * get beyond this, you have to refresh the property group each time.
6899          */
6900         while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6901             imp_prop)) != 0) {
6902 
6903                 ret = scf_error();
6904                 if (ret != SCF_ERROR_NOT_FOUND) {
6905                         warn(gettext("Failed to get property %s from the "
6906                             "restarter property group of instance %s\n"),
6907                             SCF_PROPERTY_STATE, inst->sc_name);
6908                         switch (ret) {
6909                         case SCF_ERROR_CONNECTION_BROKEN:
6910                                 warn(gettext("Lost repository connection\n"));
6911                                 err = ECONNABORTED;
6912                                 break;
6913                         case SCF_ERROR_DELETED:
6914                                 err = ENODEV;
6915                                 break;
6916                         default:
6917                                 bad_error("scf_pg_get_property", ret);
6918                         }
6919 
6920                         return (err);
6921                 }
6922 
6923                 ts.tv_sec = pg_timeout / NANOSEC;
6924                 ts.tv_nsec = pg_timeout % NANOSEC;
6925 
6926                 (void) nanosleep(&ts, NULL);
6927 
6928                 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6929                 if (ret != SCF_SUCCESS) {
6930                         warn(gettext("Failed to get restarter property "
6931                             "group for instance: %s\n"), inst->sc_name);
6932                         switch (ret) {
6933                         case SCF_ERROR_DELETED:
6934                                 err = ENODEV;
6935                                 break;
6936                         case SCF_ERROR_CONNECTION_BROKEN:
6937                                 warn(gettext("Lost repository connection\n"));
6938                                 err = ECONNABORTED;
6939                                 break;
6940                         default:
6941                                 bad_error("scf_service_get_instance", ret);
6942                         }
6943 
6944                         return (err);
6945                 }
6946         }
6947 
6948         /*
6949          * We don't have to free the property groups or other values that we got
6950          * because we stored them in global variables that are allocated and
6951          * freed by the routines that call into these functions. Unless of
6952          * course the rest of the code here that we are basing this on is
6953          * mistaken.
6954          */
6955         return (0);
6956 }
6957 #endif
6958 
6959 /*
6960  * If the service is missing, create it, import its properties, and import the
6961  * instances.  Since the service is brand new, it should be empty, and if we
6962  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6963  *
6964  * If the service exists, we want to upgrade its properties and import the
6965  * instances.  Upgrade requires a last-import snapshot, though, which are
6966  * children of instances, so first we'll have to go through the instances
6967  * looking for a last-import snapshot.  If we don't find one then we'll just
6968  * override-import the service properties (but don't delete existing
6969  * properties: another service might have declared us as a dependent).  Before
6970  * we change anything, though, we want to take the previous snapshots.  We
6971  * also give lscf_instance_import() a leg up on taking last-import snapshots
6972  * by importing the manifest's service properties into a temporary service.
6973  *
6974  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6975  * sets lcbdata->sc_err to
6976  *   ECONNABORTED - repository connection broken
6977  *   ENOMEM - out of memory
6978  *   ENOSPC - svc.configd is out of resources
6979  *   EPERM - couldn't create temporary service (error printed)
6980  *         - couldn't import into temp service (error printed)
6981  *         - couldn't create service (error printed)
6982  *         - couldn't import dependent (error printed)
6983  *         - couldn't take snapshot (error printed)
6984  *         - couldn't create instance (error printed)
6985  *         - couldn't create, modify, or delete pg (error printed)
6986  *         - couldn't create, modify, or delete dependent (error printed)
6987  *         - couldn't import instance (error printed)
6988  *   EROFS - couldn't create temporary service (repository read-only)
6989  *         - couldn't import into temporary service (repository read-only)
6990  *         - couldn't create service (repository read-only)
6991  *         - couldn't import dependent (repository read-only)
6992  *         - couldn't create instance (repository read-only)
6993  *         - couldn't create, modify, or delete pg or dependent
6994  *         - couldn't import instance (repository read-only)
6995  *   EACCES - couldn't create temporary service (backend access denied)
6996  *          - couldn't import into temporary service (backend access denied)
6997  *          - couldn't create service (backend access denied)
6998  *          - couldn't import dependent (backend access denied)
6999  *          - couldn't create instance (backend access denied)
7000  *          - couldn't create, modify, or delete pg or dependent
7001  *          - couldn't import instance (backend access denied)
7002  *   EINVAL - service name is invalid (error printed)
7003  *          - service name is too long (error printed)
7004  *          - s has invalid pgroup (error printed)
7005  *          - s has invalid dependent (error printed)
7006  *          - instance name is invalid (error printed)
7007  *          - instance entity_t is invalid (error printed)
7008  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7009  *          - couldn't import dependent (dependency pg already exists) (printed)
7010  *          - dependency collision in dependent service (error printed)
7011  *   EBUSY - temporary service deleted (error printed)
7012  *         - property group added to temporary service (error printed)
7013  *         - new property group changed or was deleted (error printed)
7014  *         - service was added unexpectedly (error printed)
7015  *         - service was deleted unexpectedly (error printed)
7016  *         - property group added to new service (error printed)
7017  *         - instance added unexpectedly (error printed)
7018  *         - instance deleted unexpectedly (error printed)
7019  *         - dependent service deleted unexpectedly (error printed)
7020  *         - pg was added, changed, or deleted (error printed)
7021  *         - dependent pg changed (error printed)
7022  *         - temporary instance added, changed, or deleted (error printed)
7023  *   EBADF - a last-import snapshot is corrupt (error printed)
7024  *         - the service is corrupt (error printed)
7025  *         - a dependent is corrupt (error printed)
7026  *         - an instance is corrupt (error printed)
7027  *         - an instance has a corrupt last-import snapshot (error printed)
7028  *         - dependent target has a corrupt snapshot (error printed)
7029  *   -1 - unknown libscf error (error printed)
7030  */
7031 static int
7032 lscf_service_import(void *v, void *pvt)
7033 {
7034         entity_t *s = v;
7035         scf_callback_t cbdata;
7036         scf_callback_t *lcbdata = pvt;
7037         scf_scope_t *scope = lcbdata->sc_parent;
7038         entity_t *inst, linst;
7039         int r;
7040         int fresh = 0;
7041         scf_snaplevel_t *running;
7042         int have_ge = 0;
7043         boolean_t retried = B_FALSE;
7044 
7045         const char * const ts_deleted = gettext("Temporary service svc:/%s "
7046             "was deleted unexpectedly.\n");
7047         const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7048             "changed unexpectedly (property group added).\n");
7049         const char * const s_deleted =
7050             gettext("%s was deleted unexpectedly.\n");
7051         const char * const i_deleted =
7052             gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7053         const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7054             "is corrupt (missing service snaplevel).\n");
7055         const char * const s_mfile_upd =
7056             gettext("Unable to update the manifest file connection "
7057             "for %s\n");
7058 
7059         li_only = 0;
7060         /* Validate the service name */
7061         if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7062                 switch (scf_error()) {
7063                 case SCF_ERROR_CONNECTION_BROKEN:
7064                         return (stash_scferror(lcbdata));
7065 
7066                 case SCF_ERROR_INVALID_ARGUMENT:
7067                         warn(gettext("\"%s\" is an invalid service name.  "
7068                             "Cannot import.\n"), s->sc_name);
7069                         return (stash_scferror(lcbdata));
7070 
7071                 case SCF_ERROR_NOT_FOUND:
7072                         break;
7073 
7074                 case SCF_ERROR_HANDLE_MISMATCH:
7075                 case SCF_ERROR_NOT_BOUND:
7076                 case SCF_ERROR_NOT_SET:
7077                 default:
7078                         bad_error("scf_scope_get_service", scf_error());
7079                 }
7080         }
7081 
7082         /* create temporary service */
7083         /*
7084          * the size of the buffer was reduced to max_scf_name_len to prevent
7085          * hitting bug 6681151.  After the bug fix, the size of the buffer
7086          * should be restored to its original value (max_scf_name_len +1)
7087          */
7088         r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7089         if (r < 0)
7090                 bad_error("snprintf", errno);
7091         if (r > max_scf_name_len) {
7092                 warn(gettext(
7093                     "Service name \"%s\" is too long.  Cannot import.\n"),
7094                     s->sc_name);
7095                 lcbdata->sc_err = EINVAL;
7096                 return (UU_WALK_ERROR);
7097         }
7098 
7099 retry:
7100         if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7101                 switch (scf_error()) {
7102                 case SCF_ERROR_CONNECTION_BROKEN:
7103                 case SCF_ERROR_NO_RESOURCES:
7104                 case SCF_ERROR_BACKEND_READONLY:
7105                 case SCF_ERROR_BACKEND_ACCESS:
7106                         return (stash_scferror(lcbdata));
7107 
7108                 case SCF_ERROR_EXISTS:
7109                         if (!retried) {
7110                                 lscf_delete(imp_tsname, 0);
7111                                 retried = B_TRUE;
7112                                 goto retry;
7113                         }
7114                         warn(gettext(
7115                             "Temporary service \"%s\" must be deleted before "
7116                             "this manifest can be imported.\n"), imp_tsname);
7117                         return (stash_scferror(lcbdata));
7118 
7119                 case SCF_ERROR_PERMISSION_DENIED:
7120                         warn(gettext("Could not create temporary service "
7121                             "\"%s\" (permission denied).\n"), imp_tsname);
7122                         return (stash_scferror(lcbdata));
7123 
7124                 case SCF_ERROR_INVALID_ARGUMENT:
7125                 case SCF_ERROR_HANDLE_MISMATCH:
7126                 case SCF_ERROR_NOT_BOUND:
7127                 case SCF_ERROR_NOT_SET:
7128                 default:
7129                         bad_error("scf_scope_add_service", scf_error());
7130                 }
7131         }
7132 
7133         r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7134         if (r < 0)
7135                 bad_error("snprintf", errno);
7136 
7137         cbdata.sc_handle = lcbdata->sc_handle;
7138         cbdata.sc_parent = imp_tsvc;
7139         cbdata.sc_service = 1;
7140         cbdata.sc_source_fmri = s->sc_fmri;
7141         cbdata.sc_target_fmri = imp_str;
7142         cbdata.sc_flags = 0;
7143 
7144         if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7145             UU_DEFAULT) != 0) {
7146                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7147                         bad_error("uu_list_walk", uu_error());
7148 
7149                 lcbdata->sc_err = cbdata.sc_err;
7150                 switch (cbdata.sc_err) {
7151                 case ECONNABORTED:
7152                         goto connaborted;
7153 
7154                 case ECANCELED:
7155                         warn(ts_deleted, imp_tsname);
7156                         lcbdata->sc_err = EBUSY;
7157                         return (UU_WALK_ERROR);
7158 
7159                 case EEXIST:
7160                         warn(ts_pg_added, imp_tsname);
7161                         lcbdata->sc_err = EBUSY;
7162                         return (UU_WALK_ERROR);
7163                 }
7164 
7165                 r = UU_WALK_ERROR;
7166                 goto deltemp;
7167         }
7168 
7169         if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7170             UU_DEFAULT) != 0) {
7171                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7172                         bad_error("uu_list_walk", uu_error());
7173 
7174                 lcbdata->sc_err = cbdata.sc_err;
7175                 switch (cbdata.sc_err) {
7176                 case ECONNABORTED:
7177                         goto connaborted;
7178 
7179                 case ECANCELED:
7180                         warn(ts_deleted, imp_tsname);
7181                         lcbdata->sc_err = EBUSY;
7182                         return (UU_WALK_ERROR);
7183 
7184                 case EEXIST:
7185                         warn(ts_pg_added, imp_tsname);
7186                         lcbdata->sc_err = EBUSY;
7187                         return (UU_WALK_ERROR);
7188                 }
7189 
7190                 r = UU_WALK_ERROR;
7191                 goto deltemp;
7192         }
7193 
7194         if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7195                 switch (scf_error()) {
7196                 case SCF_ERROR_NOT_FOUND:
7197                         break;
7198 
7199                 case SCF_ERROR_CONNECTION_BROKEN:
7200                         goto connaborted;
7201 
7202                 case SCF_ERROR_INVALID_ARGUMENT:
7203                 case SCF_ERROR_HANDLE_MISMATCH:
7204                 case SCF_ERROR_NOT_BOUND:
7205                 case SCF_ERROR_NOT_SET:
7206                 default:
7207                         bad_error("scf_scope_get_service", scf_error());
7208                 }
7209 
7210                 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7211                         switch (scf_error()) {
7212                         case SCF_ERROR_CONNECTION_BROKEN:
7213                                 goto connaborted;
7214 
7215                         case SCF_ERROR_NO_RESOURCES:
7216                         case SCF_ERROR_BACKEND_READONLY:
7217                         case SCF_ERROR_BACKEND_ACCESS:
7218                                 r = stash_scferror(lcbdata);
7219                                 goto deltemp;
7220 
7221                         case SCF_ERROR_EXISTS:
7222                                 warn(gettext("Scope \"%s\" changed unexpectedly"
7223                                     " (service \"%s\" added).\n"),
7224                                     SCF_SCOPE_LOCAL, s->sc_name);
7225                                 lcbdata->sc_err = EBUSY;
7226                                 goto deltemp;
7227 
7228                         case SCF_ERROR_PERMISSION_DENIED:
7229                                 warn(gettext("Could not create service \"%s\" "
7230                                     "(permission denied).\n"), s->sc_name);
7231                                 goto deltemp;
7232 
7233                         case SCF_ERROR_INVALID_ARGUMENT:
7234                         case SCF_ERROR_HANDLE_MISMATCH:
7235                         case SCF_ERROR_NOT_BOUND:
7236                         case SCF_ERROR_NOT_SET:
7237                         default:
7238                                 bad_error("scf_scope_add_service", scf_error());
7239                         }
7240                 }
7241 
7242                 s->sc_import_state = IMPORT_PROP_BEGUN;
7243 
7244                 /* import service properties */
7245                 cbdata.sc_handle = lcbdata->sc_handle;
7246                 cbdata.sc_parent = imp_svc;
7247                 cbdata.sc_service = 1;
7248                 cbdata.sc_flags = lcbdata->sc_flags;
7249                 cbdata.sc_source_fmri = s->sc_fmri;
7250                 cbdata.sc_target_fmri = s->sc_fmri;
7251 
7252                 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7253                     &cbdata, UU_DEFAULT) != 0) {
7254                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7255                                 bad_error("uu_list_walk", uu_error());
7256 
7257                         lcbdata->sc_err = cbdata.sc_err;
7258                         switch (cbdata.sc_err) {
7259                         case ECONNABORTED:
7260                                 goto connaborted;
7261 
7262                         case ECANCELED:
7263                                 warn(s_deleted, s->sc_fmri);
7264                                 lcbdata->sc_err = EBUSY;
7265                                 return (UU_WALK_ERROR);
7266 
7267                         case EEXIST:
7268                                 warn(gettext("%s changed unexpectedly "
7269                                     "(property group added).\n"), s->sc_fmri);
7270                                 lcbdata->sc_err = EBUSY;
7271                                 return (UU_WALK_ERROR);
7272 
7273                         case EINVAL:
7274                                 /* caught above */
7275                                 bad_error("entity_pgroup_import",
7276                                     cbdata.sc_err);
7277                         }
7278 
7279                         r = UU_WALK_ERROR;
7280                         goto deltemp;
7281                 }
7282 
7283                 cbdata.sc_trans = NULL;
7284                 cbdata.sc_flags = 0;
7285                 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7286                     &cbdata, UU_DEFAULT) != 0) {
7287                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7288                                 bad_error("uu_list_walk", uu_error());
7289 
7290                         lcbdata->sc_err = cbdata.sc_err;
7291                         if (cbdata.sc_err == ECONNABORTED)
7292                                 goto connaborted;
7293                         r = UU_WALK_ERROR;
7294                         goto deltemp;
7295                 }
7296 
7297                 s->sc_import_state = IMPORT_PROP_DONE;
7298 
7299                 /*
7300                  * This is a new service, so we can't take previous snapshots
7301                  * or upgrade service properties.
7302                  */
7303                 fresh = 1;
7304                 goto instances;
7305         }
7306 
7307         /* Clear sc_seen for the instances. */
7308         if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7309             (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7310                 bad_error("uu_list_walk", uu_error());
7311 
7312         /*
7313          * Take previous snapshots for all instances.  Even for ones not
7314          * mentioned in the bundle, since we might change their service
7315          * properties.
7316          */
7317         if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7318                 switch (scf_error()) {
7319                 case SCF_ERROR_CONNECTION_BROKEN:
7320                         goto connaborted;
7321 
7322                 case SCF_ERROR_DELETED:
7323                         warn(s_deleted, s->sc_fmri);
7324                         lcbdata->sc_err = EBUSY;
7325                         r = UU_WALK_ERROR;
7326                         goto deltemp;
7327 
7328                 case SCF_ERROR_HANDLE_MISMATCH:
7329                 case SCF_ERROR_NOT_BOUND:
7330                 case SCF_ERROR_NOT_SET:
7331                 default:
7332                         bad_error("scf_iter_service_instances", scf_error());
7333                 }
7334         }
7335 
7336         for (;;) {
7337                 r = scf_iter_next_instance(imp_iter, imp_inst);
7338                 if (r == 0)
7339                         break;
7340                 if (r != 1) {
7341                         switch (scf_error()) {
7342                         case SCF_ERROR_DELETED:
7343                                 warn(s_deleted, s->sc_fmri);
7344                                 lcbdata->sc_err = EBUSY;
7345                                 r = UU_WALK_ERROR;
7346                                 goto deltemp;
7347 
7348                         case SCF_ERROR_CONNECTION_BROKEN:
7349                                 goto connaborted;
7350 
7351                         case SCF_ERROR_NOT_BOUND:
7352                         case SCF_ERROR_HANDLE_MISMATCH:
7353                         case SCF_ERROR_INVALID_ARGUMENT:
7354                         case SCF_ERROR_NOT_SET:
7355                         default:
7356                                 bad_error("scf_iter_next_instance",
7357                                     scf_error());
7358                         }
7359                 }
7360 
7361                 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7362                         switch (scf_error()) {
7363                         case SCF_ERROR_DELETED:
7364                                 continue;
7365 
7366                         case SCF_ERROR_CONNECTION_BROKEN:
7367                                 goto connaborted;
7368 
7369                         case SCF_ERROR_NOT_SET:
7370                         case SCF_ERROR_NOT_BOUND:
7371                         default:
7372                                 bad_error("scf_instance_get_name", scf_error());
7373                         }
7374                 }
7375 
7376                 if (g_verbose)
7377                         warn(gettext(
7378                             "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7379                             snap_previous, s->sc_name, imp_str);
7380 
7381                 r = take_snap(imp_inst, snap_previous, imp_snap);
7382                 switch (r) {
7383                 case 0:
7384                         break;
7385 
7386                 case ECANCELED:
7387                         continue;
7388 
7389                 case ECONNABORTED:
7390                         goto connaborted;
7391 
7392                 case EPERM:
7393                         warn(gettext("Could not take \"%s\" snapshot of "
7394                             "svc:/%s:%s (permission denied).\n"),
7395                             snap_previous, s->sc_name, imp_str);
7396                         lcbdata->sc_err = r;
7397                         return (UU_WALK_ERROR);
7398 
7399                 case ENOSPC:
7400                 case -1:
7401                         lcbdata->sc_err = r;
7402                         r = UU_WALK_ERROR;
7403                         goto deltemp;
7404 
7405                 default:
7406                         bad_error("take_snap", r);
7407                 }
7408 
7409                 linst.sc_name = imp_str;
7410                 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7411                     &linst, NULL, NULL);
7412                 if (inst != NULL) {
7413                         inst->sc_import_state = IMPORT_PREVIOUS;
7414                         inst->sc_seen = 1;
7415                 }
7416         }
7417 
7418         /*
7419          * Create the new instances and take previous snapshots of
7420          * them.  This is not necessary, but it maximizes data preservation.
7421          */
7422         for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7423             inst != NULL;
7424             inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7425             inst)) {
7426                 if (inst->sc_seen)
7427                         continue;
7428 
7429                 if (scf_service_add_instance(imp_svc, inst->sc_name,
7430                     imp_inst) != 0) {
7431                         switch (scf_error()) {
7432                         case SCF_ERROR_CONNECTION_BROKEN:
7433                                 goto connaborted;
7434 
7435                         case SCF_ERROR_BACKEND_READONLY:
7436                         case SCF_ERROR_BACKEND_ACCESS:
7437                         case SCF_ERROR_NO_RESOURCES:
7438                                 r = stash_scferror(lcbdata);
7439                                 goto deltemp;
7440 
7441                         case SCF_ERROR_EXISTS:
7442                                 warn(gettext("%s changed unexpectedly "
7443                                     "(instance \"%s\" added).\n"), s->sc_fmri,
7444                                     inst->sc_name);
7445                                 lcbdata->sc_err = EBUSY;
7446                                 r = UU_WALK_ERROR;
7447                                 goto deltemp;
7448 
7449                         case SCF_ERROR_INVALID_ARGUMENT:
7450                                 warn(gettext("Service \"%s\" has instance with "
7451                                     "invalid name \"%s\".\n"), s->sc_name,
7452                                     inst->sc_name);
7453                                 r = stash_scferror(lcbdata);
7454                                 goto deltemp;
7455 
7456                         case SCF_ERROR_PERMISSION_DENIED:
7457                                 warn(gettext("Could not create instance \"%s\" "
7458                                     "in %s (permission denied).\n"),
7459                                     inst->sc_name, s->sc_fmri);
7460                                 r = stash_scferror(lcbdata);
7461                                 goto deltemp;
7462 
7463                         case SCF_ERROR_HANDLE_MISMATCH:
7464                         case SCF_ERROR_NOT_BOUND:
7465                         case SCF_ERROR_NOT_SET:
7466                         default:
7467                                 bad_error("scf_service_add_instance",
7468                                     scf_error());
7469                         }
7470                 }
7471 
7472                 if (g_verbose)
7473                         warn(gettext("Taking \"%s\" snapshot for "
7474                             "new service %s.\n"), snap_previous, inst->sc_fmri);
7475                 r = take_snap(imp_inst, snap_previous, imp_snap);
7476                 switch (r) {
7477                 case 0:
7478                         break;
7479 
7480                 case ECANCELED:
7481                         warn(i_deleted, s->sc_fmri, inst->sc_name);
7482                         lcbdata->sc_err = EBUSY;
7483                         r = UU_WALK_ERROR;
7484                         goto deltemp;
7485 
7486                 case ECONNABORTED:
7487                         goto connaborted;
7488 
7489                 case EPERM:
7490                         warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7491                         lcbdata->sc_err = r;
7492                         r = UU_WALK_ERROR;
7493                         goto deltemp;
7494 
7495                 case ENOSPC:
7496                 case -1:
7497                         r = UU_WALK_ERROR;
7498                         goto deltemp;
7499 
7500                 default:
7501                         bad_error("take_snap", r);
7502                 }
7503         }
7504 
7505         s->sc_import_state = IMPORT_PREVIOUS;
7506 
7507         /*
7508          * Upgrade service properties, if we can find a last-import snapshot.
7509          * Any will do because we don't support different service properties
7510          * in different manifests, so all snaplevels of the service in all of
7511          * the last-import snapshots of the instances should be the same.
7512          */
7513         if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7514                 switch (scf_error()) {
7515                 case SCF_ERROR_CONNECTION_BROKEN:
7516                         goto connaborted;
7517 
7518                 case SCF_ERROR_DELETED:
7519                         warn(s_deleted, s->sc_fmri);
7520                         lcbdata->sc_err = EBUSY;
7521                         r = UU_WALK_ERROR;
7522                         goto deltemp;
7523 
7524                 case SCF_ERROR_HANDLE_MISMATCH:
7525                 case SCF_ERROR_NOT_BOUND:
7526                 case SCF_ERROR_NOT_SET:
7527                 default:
7528                         bad_error("scf_iter_service_instances", scf_error());
7529                 }
7530         }
7531 
7532         for (;;) {
7533                 r = scf_iter_next_instance(imp_iter, imp_inst);
7534                 if (r == -1) {
7535                         switch (scf_error()) {
7536                         case SCF_ERROR_DELETED:
7537                                 warn(s_deleted, s->sc_fmri);
7538                                 lcbdata->sc_err = EBUSY;
7539                                 r = UU_WALK_ERROR;
7540                                 goto deltemp;
7541 
7542                         case SCF_ERROR_CONNECTION_BROKEN:
7543                                 goto connaborted;
7544 
7545                         case SCF_ERROR_NOT_BOUND:
7546                         case SCF_ERROR_HANDLE_MISMATCH:
7547                         case SCF_ERROR_INVALID_ARGUMENT:
7548                         case SCF_ERROR_NOT_SET:
7549                         default:
7550                                 bad_error("scf_iter_next_instance",
7551                                     scf_error());
7552                         }
7553                 }
7554 
7555                 if (r == 0) {
7556                         /*
7557                          * Didn't find any last-import snapshots.  Override-
7558                          * import the properties.  Unless one of the instances
7559                          * has a general/enabled property, in which case we're
7560                          * probably running a last-import-capable svccfg for
7561                          * the first time, and we should only take the
7562                          * last-import snapshot.
7563                          */
7564                         if (have_ge) {
7565                                 pgroup_t *mfpg;
7566                                 scf_callback_t mfcbdata;
7567 
7568                                 li_only = 1;
7569                                 no_refresh = 1;
7570                                 /*
7571                                  * Need to go ahead and import the manifestfiles
7572                                  * pg if it exists. If the last-import snapshot
7573                                  * upgrade code is ever removed this code can
7574                                  * be removed as well.
7575                                  */
7576                                 mfpg = internal_pgroup_find(s,
7577                                     SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7578 
7579                                 if (mfpg) {
7580                                         mfcbdata.sc_handle = g_hndl;
7581                                         mfcbdata.sc_parent = imp_svc;
7582                                         mfcbdata.sc_service = 1;
7583                                         mfcbdata.sc_flags = SCI_FORCE;
7584                                         mfcbdata.sc_source_fmri = s->sc_fmri;
7585                                         mfcbdata.sc_target_fmri = s->sc_fmri;
7586                                         if (entity_pgroup_import(mfpg,
7587                                             &mfcbdata) != UU_WALK_NEXT) {
7588                                                 warn(s_mfile_upd, s->sc_fmri);
7589                                                 r = UU_WALK_ERROR;
7590                                                 goto deltemp;
7591                                         }
7592                                 }
7593                                 break;
7594                         }
7595 
7596                         s->sc_import_state = IMPORT_PROP_BEGUN;
7597 
7598                         cbdata.sc_handle = g_hndl;
7599                         cbdata.sc_parent = imp_svc;
7600                         cbdata.sc_service = 1;
7601                         cbdata.sc_flags = SCI_FORCE;
7602                         cbdata.sc_source_fmri = s->sc_fmri;
7603                         cbdata.sc_target_fmri = s->sc_fmri;
7604                         if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7605                             &cbdata, UU_DEFAULT) != 0) {
7606                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7607                                         bad_error("uu_list_walk", uu_error());
7608                                 lcbdata->sc_err = cbdata.sc_err;
7609                                 switch (cbdata.sc_err) {
7610                                 case ECONNABORTED:
7611                                         goto connaborted;
7612 
7613                                 case ECANCELED:
7614                                         warn(s_deleted, s->sc_fmri);
7615                                         lcbdata->sc_err = EBUSY;
7616                                         break;
7617 
7618                                 case EINVAL:    /* caught above */
7619                                 case EEXIST:
7620                                         bad_error("entity_pgroup_import",
7621                                             cbdata.sc_err);
7622                                 }
7623 
7624                                 r = UU_WALK_ERROR;
7625                                 goto deltemp;
7626                         }
7627 
7628                         cbdata.sc_trans = NULL;
7629                         cbdata.sc_flags = 0;
7630                         if (uu_list_walk(s->sc_dependents,
7631                             lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7632                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7633                                         bad_error("uu_list_walk", uu_error());
7634                                 lcbdata->sc_err = cbdata.sc_err;
7635                                 if (cbdata.sc_err == ECONNABORTED)
7636                                         goto connaborted;
7637                                 r = UU_WALK_ERROR;
7638                                 goto deltemp;
7639                         }
7640                         break;
7641                 }
7642 
7643                 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7644                     imp_snap) != 0) {
7645                         switch (scf_error()) {
7646                         case SCF_ERROR_DELETED:
7647                                 continue;
7648 
7649                         case SCF_ERROR_NOT_FOUND:
7650                                 break;
7651 
7652                         case SCF_ERROR_CONNECTION_BROKEN:
7653                                 goto connaborted;
7654 
7655                         case SCF_ERROR_HANDLE_MISMATCH:
7656                         case SCF_ERROR_NOT_BOUND:
7657                         case SCF_ERROR_INVALID_ARGUMENT:
7658                         case SCF_ERROR_NOT_SET:
7659                         default:
7660                                 bad_error("scf_instance_get_snapshot",
7661                                     scf_error());
7662                         }
7663 
7664                         if (have_ge)
7665                                 continue;
7666 
7667                         /*
7668                          * Check for a general/enabled property.  This is how
7669                          * we tell whether to import if there turn out to be
7670                          * no last-import snapshots.
7671                          */
7672                         if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7673                             imp_pg) == 0) {
7674                                 if (scf_pg_get_property(imp_pg,
7675                                     SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7676                                         have_ge = 1;
7677                                 } else {
7678                                         switch (scf_error()) {
7679                                         case SCF_ERROR_DELETED:
7680                                         case SCF_ERROR_NOT_FOUND:
7681                                                 continue;
7682 
7683                                         case SCF_ERROR_INVALID_ARGUMENT:
7684                                         case SCF_ERROR_HANDLE_MISMATCH:
7685                                         case SCF_ERROR_CONNECTION_BROKEN:
7686                                         case SCF_ERROR_NOT_BOUND:
7687                                         case SCF_ERROR_NOT_SET:
7688                                         default:
7689                                                 bad_error("scf_pg_get_property",
7690                                                     scf_error());
7691                                         }
7692                                 }
7693                         } else {
7694                                 switch (scf_error()) {
7695                                 case SCF_ERROR_DELETED:
7696                                 case SCF_ERROR_NOT_FOUND:
7697                                         continue;
7698 
7699                                 case SCF_ERROR_CONNECTION_BROKEN:
7700                                         goto connaborted;
7701 
7702                                 case SCF_ERROR_NOT_BOUND:
7703                                 case SCF_ERROR_NOT_SET:
7704                                 case SCF_ERROR_INVALID_ARGUMENT:
7705                                 case SCF_ERROR_HANDLE_MISMATCH:
7706                                 default:
7707                                         bad_error("scf_instance_get_pg",
7708                                             scf_error());
7709                                 }
7710                         }
7711                         continue;
7712                 }
7713 
7714                 /* find service snaplevel */
7715                 r = get_snaplevel(imp_snap, 1, imp_snpl);
7716                 switch (r) {
7717                 case 0:
7718                         break;
7719 
7720                 case ECONNABORTED:
7721                         goto connaborted;
7722 
7723                 case ECANCELED:
7724                         continue;
7725 
7726                 case ENOENT:
7727                         if (scf_instance_get_name(imp_inst, imp_str,
7728                             imp_str_sz) < 0)
7729                                 (void) strcpy(imp_str, "?");
7730                         warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7731                         lcbdata->sc_err = EBADF;
7732                         r = UU_WALK_ERROR;
7733                         goto deltemp;
7734 
7735                 default:
7736                         bad_error("get_snaplevel", r);
7737                 }
7738 
7739                 if (scf_instance_get_snapshot(imp_inst, snap_running,
7740                     imp_rsnap) != 0) {
7741                         switch (scf_error()) {
7742                         case SCF_ERROR_DELETED:
7743                                 continue;
7744 
7745                         case SCF_ERROR_NOT_FOUND:
7746                                 break;
7747 
7748                         case SCF_ERROR_CONNECTION_BROKEN:
7749                                 goto connaborted;
7750 
7751                         case SCF_ERROR_INVALID_ARGUMENT:
7752                         case SCF_ERROR_HANDLE_MISMATCH:
7753                         case SCF_ERROR_NOT_BOUND:
7754                         case SCF_ERROR_NOT_SET:
7755                         default:
7756                                 bad_error("scf_instance_get_snapshot",
7757                                     scf_error());
7758                         }
7759                         running = NULL;
7760                 } else {
7761                         r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7762                         switch (r) {
7763                         case 0:
7764                                 running = imp_rsnpl;
7765                                 break;
7766 
7767                         case ECONNABORTED:
7768                                 goto connaborted;
7769 
7770                         case ECANCELED:
7771                                 continue;
7772 
7773                         case ENOENT:
7774                                 if (scf_instance_get_name(imp_inst, imp_str,
7775                                     imp_str_sz) < 0)
7776                                         (void) strcpy(imp_str, "?");
7777                                 warn(badsnap, snap_running, s->sc_name,
7778                                     imp_str);
7779                                 lcbdata->sc_err = EBADF;
7780                                 r = UU_WALK_ERROR;
7781                                 goto deltemp;
7782 
7783                         default:
7784                                 bad_error("get_snaplevel", r);
7785                         }
7786                 }
7787 
7788                 if (g_verbose) {
7789                         if (scf_instance_get_name(imp_inst, imp_str,
7790                             imp_str_sz) < 0)
7791                                 (void) strcpy(imp_str, "?");
7792                         warn(gettext("Upgrading properties of %s according to "
7793                             "instance \"%s\".\n"), s->sc_fmri, imp_str);
7794                 }
7795 
7796                 /* upgrade service properties */
7797                 r = upgrade_props(imp_svc, running, imp_snpl, s);
7798                 if (r == 0)
7799                         break;
7800 
7801                 switch (r) {
7802                 case ECONNABORTED:
7803                         goto connaborted;
7804 
7805                 case ECANCELED:
7806                         warn(s_deleted, s->sc_fmri);
7807                         lcbdata->sc_err = EBUSY;
7808                         break;
7809 
7810                 case ENODEV:
7811                         if (scf_instance_get_name(imp_inst, imp_str,
7812                             imp_str_sz) < 0)
7813                                 (void) strcpy(imp_str, "?");
7814                         warn(i_deleted, s->sc_fmri, imp_str);
7815                         lcbdata->sc_err = EBUSY;
7816                         break;
7817 
7818                 default:
7819                         lcbdata->sc_err = r;
7820                 }
7821 
7822                 r = UU_WALK_ERROR;
7823                 goto deltemp;
7824         }
7825 
7826         s->sc_import_state = IMPORT_PROP_DONE;
7827 
7828 instances:
7829         /* import instances */
7830         cbdata.sc_handle = lcbdata->sc_handle;
7831         cbdata.sc_parent = imp_svc;
7832         cbdata.sc_service = 1;
7833         cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7834         cbdata.sc_general = NULL;
7835 
7836         if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7837             lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7838                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7839                         bad_error("uu_list_walk", uu_error());
7840 
7841                 lcbdata->sc_err = cbdata.sc_err;
7842                 if (cbdata.sc_err == ECONNABORTED)
7843                         goto connaborted;
7844                 r = UU_WALK_ERROR;
7845                 goto deltemp;
7846         }
7847 
7848         s->sc_import_state = IMPORT_COMPLETE;
7849         r = UU_WALK_NEXT;
7850 
7851 deltemp:
7852         /* delete temporary service */
7853         if (scf_service_delete(imp_tsvc) != 0) {
7854                 switch (scf_error()) {
7855                 case SCF_ERROR_DELETED:
7856                         break;
7857 
7858                 case SCF_ERROR_CONNECTION_BROKEN:
7859                         goto connaborted;
7860 
7861                 case SCF_ERROR_EXISTS:
7862                         warn(gettext(
7863                             "Could not delete svc:/%s (instances exist).\n"),
7864                             imp_tsname);
7865                         break;
7866 
7867                 case SCF_ERROR_NOT_SET:
7868                 case SCF_ERROR_NOT_BOUND:
7869                 default:
7870                         bad_error("scf_service_delete", scf_error());
7871                 }
7872         }
7873 
7874         return (r);
7875 
7876 connaborted:
7877         warn(gettext("Could not delete svc:/%s "
7878             "(repository connection broken).\n"), imp_tsname);
7879         lcbdata->sc_err = ECONNABORTED;
7880         return (UU_WALK_ERROR);
7881 }
7882 
7883 static const char *
7884 import_progress(int st)
7885 {
7886         switch (st) {
7887         case 0:
7888                 return (gettext("not reached."));
7889 
7890         case IMPORT_PREVIOUS:
7891                 return (gettext("previous snapshot taken."));
7892 
7893         case IMPORT_PROP_BEGUN:
7894                 return (gettext("some properties imported."));
7895 
7896         case IMPORT_PROP_DONE:
7897                 return (gettext("properties imported."));
7898 
7899         case IMPORT_COMPLETE:
7900                 return (gettext("imported."));
7901 
7902         case IMPORT_REFRESHED:
7903                 return (gettext("refresh requested."));
7904 
7905         default:
7906 #ifndef NDEBUG
7907                 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7908                     __FILE__, __LINE__, st);
7909 #endif
7910                 abort();
7911                 /* NOTREACHED */
7912         }
7913 }
7914 
7915 /*
7916  * Returns
7917  *   0 - success
7918  *     - fmri wasn't found (error printed)
7919  *     - entity was deleted (error printed)
7920  *     - backend denied access (error printed)
7921  *   ENOMEM - out of memory (error printed)
7922  *   ECONNABORTED - repository connection broken (error printed)
7923  *   EPERM - permission denied (error printed)
7924  *   -1 - unknown libscf error (error printed)
7925  */
7926 static int
7927 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7928 {
7929         scf_error_t serr;
7930         void *ent;
7931         int issvc;
7932         int r;
7933 
7934         const char *deleted = gettext("Could not refresh %s (deleted).\n");
7935         const char *dpt_deleted = gettext("Could not refresh %s "
7936             "(dependent \"%s\" of %s) (deleted).\n");
7937 
7938         serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7939         switch (serr) {
7940         case SCF_ERROR_NONE:
7941                 break;
7942 
7943         case SCF_ERROR_NO_MEMORY:
7944                 if (name == NULL)
7945                         warn(gettext("Could not refresh %s (out of memory).\n"),
7946                             fmri);
7947                 else
7948                         warn(gettext("Could not refresh %s "
7949                             "(dependent \"%s\" of %s) (out of memory).\n"),
7950                             fmri, name, d_fmri);
7951                 return (ENOMEM);
7952 
7953         case SCF_ERROR_NOT_FOUND:
7954                 if (name == NULL)
7955                         warn(deleted, fmri);
7956                 else
7957                         warn(dpt_deleted, fmri, name, d_fmri);
7958                 return (0);
7959 
7960         case SCF_ERROR_INVALID_ARGUMENT:
7961         case SCF_ERROR_CONSTRAINT_VIOLATED:
7962         default:
7963                 bad_error("fmri_to_entity", serr);
7964         }
7965 
7966         r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7967         switch (r) {
7968         case 0:
7969                 break;
7970 
7971         case ECONNABORTED:
7972                 if (name != NULL)
7973                         warn(gettext("Could not refresh %s "
7974                             "(dependent \"%s\" of %s) "
7975                             "(repository connection broken).\n"), fmri, name,
7976                             d_fmri);
7977                 return (r);
7978 
7979         case ECANCELED:
7980                 if (name == NULL)
7981                         warn(deleted, fmri);
7982                 else
7983                         warn(dpt_deleted, fmri, name, d_fmri);
7984                 return (0);
7985 
7986         case EACCES:
7987                 if (!g_verbose)
7988                         return (0);
7989                 if (name == NULL)
7990                         warn(gettext("Could not refresh %s "
7991                             "(backend access denied).\n"), fmri);
7992                 else
7993                         warn(gettext("Could not refresh %s "
7994                             "(dependent \"%s\" of %s) "
7995                             "(backend access denied).\n"), fmri, name, d_fmri);
7996                 return (0);
7997 
7998         case EPERM:
7999                 if (name == NULL)
8000                         warn(gettext("Could not refresh %s "
8001                             "(permission denied).\n"), fmri);
8002                 else
8003                         warn(gettext("Could not refresh %s "
8004                             "(dependent \"%s\" of %s) "
8005                             "(permission denied).\n"), fmri, name, d_fmri);
8006                 return (r);
8007 
8008         case ENOSPC:
8009                 if (name == NULL)
8010                         warn(gettext("Could not refresh %s "
8011                             "(repository server out of resources).\n"),
8012                             fmri);
8013                 else
8014                         warn(gettext("Could not refresh %s "
8015                             "(dependent \"%s\" of %s) "
8016                             "(repository server out of resources).\n"),
8017                             fmri, name, d_fmri);
8018                 return (r);
8019 
8020         case -1:
8021                 scfwarn();
8022                 return (r);
8023 
8024         default:
8025                 bad_error("refresh_entity", r);
8026         }
8027 
8028         if (issvc)
8029                 scf_service_destroy(ent);
8030         else
8031                 scf_instance_destroy(ent);
8032 
8033         return (0);
8034 }
8035 
8036 static int
8037 alloc_imp_globals()
8038 {
8039         int r;
8040 
8041         const char * const emsg_nomem = gettext("Out of memory.\n");
8042         const char * const emsg_nores =
8043             gettext("svc.configd is out of resources.\n");
8044 
8045         imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8046             max_scf_name_len : max_scf_fmri_len) + 1;
8047 
8048         if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8049             (imp_svc = scf_service_create(g_hndl)) == NULL ||
8050             (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8051             (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8052             (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8053             (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8054             (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8055             (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8056             (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8057             (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8058             (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8059             (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8060             (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8061             (imp_prop = scf_property_create(g_hndl)) == NULL ||
8062             (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8063             (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8064             (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8065             (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8066             (imp_str = malloc(imp_str_sz)) == NULL ||
8067             (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8068             (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8069             (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8070             (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8071             (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8072             (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8073             (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8074             (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8075             (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8076             (ud_prop = scf_property_create(g_hndl)) == NULL ||
8077             (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8078             (ud_val = scf_value_create(g_hndl)) == NULL ||
8079             (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8080             (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8081             (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8082             (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8083             (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8084             (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8085                 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8086                         warn(emsg_nores);
8087                 else
8088                         warn(emsg_nomem);
8089 
8090                 return (-1);
8091         }
8092 
8093         r = load_init();
8094         switch (r) {
8095         case 0:
8096                 break;
8097 
8098         case ENOMEM:
8099                 warn(emsg_nomem);
8100                 return (-1);
8101 
8102         default:
8103                 bad_error("load_init", r);
8104         }
8105 
8106         return (0);
8107 }
8108 
8109 static void
8110 free_imp_globals()
8111 {
8112         pgroup_t *old_dpt;
8113         void *cookie;
8114 
8115         load_fini();
8116 
8117         free(ud_ctarg);
8118         free(ud_oldtarg);
8119         free(ud_name);
8120         ud_ctarg = ud_oldtarg = ud_name = NULL;
8121 
8122         scf_transaction_destroy(ud_tx);
8123         ud_tx = NULL;
8124         scf_iter_destroy(ud_iter);
8125         scf_iter_destroy(ud_iter2);
8126         ud_iter = ud_iter2 = NULL;
8127         scf_value_destroy(ud_val);
8128         ud_val = NULL;
8129         scf_property_destroy(ud_prop);
8130         scf_property_destroy(ud_dpt_prop);
8131         ud_prop = ud_dpt_prop = NULL;
8132         scf_pg_destroy(ud_pg);
8133         scf_pg_destroy(ud_cur_depts_pg);
8134         scf_pg_destroy(ud_run_dpts_pg);
8135         ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8136         scf_snaplevel_destroy(ud_snpl);
8137         ud_snpl = NULL;
8138         scf_instance_destroy(ud_inst);
8139         ud_inst = NULL;
8140 
8141         free(imp_str);
8142         free(imp_tsname);
8143         free(imp_fe1);
8144         free(imp_fe2);
8145         imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8146 
8147         cookie = NULL;
8148         while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8149             NULL) {
8150                 free((char *)old_dpt->sc_pgroup_name);
8151                 free((char *)old_dpt->sc_pgroup_fmri);
8152                 internal_pgroup_free(old_dpt);
8153         }
8154         uu_list_destroy(imp_deleted_dpts);
8155 
8156         scf_transaction_destroy(imp_tx);
8157         imp_tx = NULL;
8158         scf_iter_destroy(imp_iter);
8159         scf_iter_destroy(imp_rpg_iter);
8160         scf_iter_destroy(imp_up_iter);
8161         imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8162         scf_property_destroy(imp_prop);
8163         imp_prop = NULL;
8164         scf_pg_destroy(imp_pg);
8165         scf_pg_destroy(imp_pg2);
8166         imp_pg = imp_pg2 = NULL;
8167         scf_snaplevel_destroy(imp_snpl);
8168         scf_snaplevel_destroy(imp_rsnpl);
8169         imp_snpl = imp_rsnpl = NULL;
8170         scf_snapshot_destroy(imp_snap);
8171         scf_snapshot_destroy(imp_lisnap);
8172         scf_snapshot_destroy(imp_tlisnap);
8173         scf_snapshot_destroy(imp_rsnap);
8174         imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8175         scf_instance_destroy(imp_inst);
8176         scf_instance_destroy(imp_tinst);
8177         imp_inst = imp_tinst = NULL;
8178         scf_service_destroy(imp_svc);
8179         scf_service_destroy(imp_tsvc);
8180         imp_svc = imp_tsvc = NULL;
8181         scf_scope_destroy(imp_scope);
8182         imp_scope = NULL;
8183 
8184         load_fini();
8185 }
8186 
8187 int
8188 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8189 {
8190         scf_callback_t cbdata;
8191         int result = 0;
8192         entity_t *svc, *inst;
8193         uu_list_t *insts;
8194         int r;
8195         pgroup_t *old_dpt;
8196         int annotation_set = 0;
8197 
8198         const char * const emsg_nomem = gettext("Out of memory.\n");
8199         const char * const emsg_nores =
8200             gettext("svc.configd is out of resources.\n");
8201 
8202         lscf_prep_hndl();
8203 
8204         if (alloc_imp_globals())
8205                 goto out;
8206 
8207         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8208                 switch (scf_error()) {
8209                 case SCF_ERROR_CONNECTION_BROKEN:
8210                         warn(gettext("Repository connection broken.\n"));
8211                         repository_teardown();
8212                         result = -1;
8213                         goto out;
8214 
8215                 case SCF_ERROR_NOT_FOUND:
8216                 case SCF_ERROR_INVALID_ARGUMENT:
8217                 case SCF_ERROR_NOT_BOUND:
8218                 case SCF_ERROR_HANDLE_MISMATCH:
8219                 default:
8220                         bad_error("scf_handle_get_scope", scf_error());
8221                 }
8222         }
8223 
8224         /* Set up the auditing annotation. */
8225         if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8226                 annotation_set = 1;
8227         } else {
8228                 switch (scf_error()) {
8229                 case SCF_ERROR_CONNECTION_BROKEN:
8230                         warn(gettext("Repository connection broken.\n"));
8231                         repository_teardown();
8232                         result = -1;
8233                         goto out;
8234 
8235                 case SCF_ERROR_INVALID_ARGUMENT:
8236                 case SCF_ERROR_NOT_BOUND:
8237                 case SCF_ERROR_NO_RESOURCES:
8238                 case SCF_ERROR_INTERNAL:
8239                         bad_error("_scf_set_annotation", scf_error());
8240                         /* NOTREACHED */
8241 
8242                 default:
8243                         /*
8244                          * Do not terminate import because of inability to
8245                          * generate annotation audit event.
8246                          */
8247                         warn(gettext("_scf_set_annotation() unexpectedly "
8248                             "failed with return code of %d\n"), scf_error());
8249                         break;
8250                 }
8251         }
8252 
8253         /*
8254          * Clear the sc_import_state's of all services & instances so we can
8255          * report how far we got if we fail.
8256          */
8257         for (svc = uu_list_first(bndl->sc_bundle_services);
8258             svc != NULL;
8259             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8260                 svc->sc_import_state = 0;
8261 
8262                 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8263                     clear_int, (void *)offsetof(entity_t, sc_import_state),
8264                     UU_DEFAULT) != 0)
8265                         bad_error("uu_list_walk", uu_error());
8266         }
8267 
8268         cbdata.sc_handle = g_hndl;
8269         cbdata.sc_parent = imp_scope;
8270         cbdata.sc_flags = flags;
8271         cbdata.sc_general = NULL;
8272 
8273         if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8274             &cbdata, UU_DEFAULT) == 0) {
8275                 char *eptr;
8276                 /* Success.  Refresh everything. */
8277 
8278                 if (flags & SCI_NOREFRESH || no_refresh) {
8279                         no_refresh = 0;
8280                         result = 0;
8281                         goto out;
8282                 }
8283 
8284                 for (svc = uu_list_first(bndl->sc_bundle_services);
8285                     svc != NULL;
8286                     svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8287                         pgroup_t *dpt;
8288 
8289                         insts = svc->sc_u.sc_service.sc_service_instances;
8290 
8291                         for (inst = uu_list_first(insts);
8292                             inst != NULL;
8293                             inst = uu_list_next(insts, inst)) {
8294                                 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8295                                 switch (r) {
8296                                 case 0:
8297                                         break;
8298 
8299                                 case ENOMEM:
8300                                 case ECONNABORTED:
8301                                 case EPERM:
8302                                 case -1:
8303                                         goto progress;
8304 
8305                                 default:
8306                                         bad_error("imp_refresh_fmri", r);
8307                                 }
8308 
8309                                 inst->sc_import_state = IMPORT_REFRESHED;
8310 
8311                                 for (dpt = uu_list_first(inst->sc_dependents);
8312                                     dpt != NULL;
8313                                     dpt = uu_list_next(inst->sc_dependents,
8314                                     dpt))
8315                                         if (imp_refresh_fmri(
8316                                             dpt->sc_pgroup_fmri,
8317                                             dpt->sc_pgroup_name,
8318                                             inst->sc_fmri) != 0)
8319                                                 goto progress;
8320                         }
8321 
8322                         for (dpt = uu_list_first(svc->sc_dependents);
8323                             dpt != NULL;
8324                             dpt = uu_list_next(svc->sc_dependents, dpt))
8325                                 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8326                                     dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8327                                         goto progress;
8328                 }
8329 
8330                 for (old_dpt = uu_list_first(imp_deleted_dpts);
8331                     old_dpt != NULL;
8332                     old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8333                         if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8334                             old_dpt->sc_pgroup_name,
8335                             old_dpt->sc_parent->sc_fmri) != 0)
8336                                 goto progress;
8337 
8338                 result = 0;
8339 
8340                 /*
8341                  * This snippet of code assumes that we are running svccfg as we
8342                  * normally do -- witih svc.startd running. Of course, that is
8343                  * not actually the case all the time because we also use a
8344                  * varient of svc.configd and svccfg which are only meant to
8345                  * run during the build process. During this time we have no
8346                  * svc.startd, so this check would hang the build process.
8347                  *
8348                  * However, we've also given other consolidations, a bit of a
8349                  * means to tie themselves into a knot. They're not properly
8350                  * using the native build equivalents, but they've been getting
8351                  * away with it anyways. Therefore, if we've found that
8352                  * SVCCFG_REPOSITORY is set indicating that a separate configd
8353                  * should be spun up, then we have to assume it's not using a
8354                  * startd and we should not do this check.
8355                  */
8356 #ifndef NATIVE_BUILD
8357                 /*
8358                  * Verify that the restarter group is preset
8359                  */
8360                 eptr = getenv("SVCCFG_REPOSITORY");
8361                 for (svc = uu_list_first(bndl->sc_bundle_services);
8362                     svc != NULL && eptr == NULL;
8363                     svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8364 
8365                         insts = svc->sc_u.sc_service.sc_service_instances;
8366 
8367                         for (inst = uu_list_first(insts);
8368                             inst != NULL;
8369                             inst = uu_list_next(insts, inst)) {
8370                                 if (lscf_instance_verify(imp_scope, svc,
8371                                     inst) != 0)
8372                                         goto progress;
8373                         }
8374                 }
8375 #endif
8376                 goto out;
8377 
8378         }
8379 
8380         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8381                 bad_error("uu_list_walk", uu_error());
8382 
8383 printerr:
8384         /* If the error hasn't been printed yet, do so here. */
8385         switch (cbdata.sc_err) {
8386         case ECONNABORTED:
8387                 warn(gettext("Repository connection broken.\n"));
8388                 break;
8389 
8390         case ENOMEM:
8391                 warn(emsg_nomem);
8392                 break;
8393 
8394         case ENOSPC:
8395                 warn(emsg_nores);
8396                 break;
8397 
8398         case EROFS:
8399                 warn(gettext("Repository is read-only.\n"));
8400                 break;
8401 
8402         case EACCES:
8403                 warn(gettext("Repository backend denied access.\n"));
8404                 break;
8405 
8406         case EPERM:
8407         case EINVAL:
8408         case EEXIST:
8409         case EBUSY:
8410         case EBADF:
8411         case -1:
8412                 break;
8413 
8414         default:
8415                 bad_error("lscf_service_import", cbdata.sc_err);
8416         }
8417 
8418 progress:
8419         warn(gettext("Import of %s failed.  Progress:\n"), filename);
8420 
8421         for (svc = uu_list_first(bndl->sc_bundle_services);
8422             svc != NULL;
8423             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8424                 insts = svc->sc_u.sc_service.sc_service_instances;
8425 
8426                 warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8427                     import_progress(svc->sc_import_state));
8428 
8429                 for (inst = uu_list_first(insts);
8430                     inst != NULL;
8431                     inst = uu_list_next(insts, inst))
8432                         warn(gettext("    Instance \"%s\": %s\n"),
8433                             inst->sc_name,
8434                             import_progress(inst->sc_import_state));
8435         }
8436 
8437         if (cbdata.sc_err == ECONNABORTED)
8438                 repository_teardown();
8439 
8440 
8441         result = -1;
8442 
8443 out:
8444         if (annotation_set != 0) {
8445                 /* Turn off annotation.  It is no longer needed. */
8446                 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8447         }
8448 
8449         free_imp_globals();
8450 
8451         return (result);
8452 }
8453 
8454 /*
8455  * _lscf_import_err() summarize the error handling returned by
8456  * lscf_import_{instance | service}_pgs
8457  * Return values are:
8458  * IMPORT_NEXT
8459  * IMPORT_OUT
8460  * IMPORT_BAD
8461  */
8462 
8463 #define IMPORT_BAD      -1
8464 #define IMPORT_NEXT     0
8465 #define IMPORT_OUT      1
8466 
8467 static int
8468 _lscf_import_err(int err, const char *fmri)
8469 {
8470         switch (err) {
8471         case 0:
8472                 if (g_verbose)
8473                         warn(gettext("%s updated.\n"), fmri);
8474                 return (IMPORT_NEXT);
8475 
8476         case ECONNABORTED:
8477                 warn(gettext("Could not update %s "
8478                     "(repository connection broken).\n"), fmri);
8479                 return (IMPORT_OUT);
8480 
8481         case ENOMEM:
8482                 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8483                 return (IMPORT_OUT);
8484 
8485         case ENOSPC:
8486                 warn(gettext("Could not update %s "
8487                     "(repository server out of resources).\n"), fmri);
8488                 return (IMPORT_OUT);
8489 
8490         case ECANCELED:
8491                 warn(gettext(
8492                     "Could not update %s (deleted).\n"), fmri);
8493                 return (IMPORT_NEXT);
8494 
8495         case EPERM:
8496         case EINVAL:
8497         case EBUSY:
8498                 return (IMPORT_NEXT);
8499 
8500         case EROFS:
8501                 warn(gettext("Could not update %s (repository read-only).\n"),
8502                     fmri);
8503                 return (IMPORT_OUT);
8504 
8505         case EACCES:
8506                 warn(gettext("Could not update %s "
8507                     "(backend access denied).\n"), fmri);
8508                 return (IMPORT_NEXT);
8509 
8510         case EEXIST:
8511         default:
8512                 return (IMPORT_BAD);
8513         }
8514 
8515         /*NOTREACHED*/
8516 }
8517 
8518 /*
8519  * The global imp_svc and imp_inst should be set by the caller in the
8520  * check to make sure the service and instance exist that the apply is
8521  * working on.
8522  */
8523 static int
8524 lscf_dependent_apply(void *dpg, void *e)
8525 {
8526         scf_callback_t cb;
8527         pgroup_t *dpt_pgroup = dpg;
8528         pgroup_t *deldpt;
8529         entity_t *ent = e;
8530         int tissvc;
8531         void *sc_ent, *tent;
8532         scf_error_t serr;
8533         int r;
8534 
8535         const char * const dependents = "dependents";
8536         const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8537 
8538         if (issvc)
8539                 sc_ent = imp_svc;
8540         else
8541                 sc_ent = imp_inst;
8542 
8543         if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8544             imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8545             scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8546             imp_prop) != 0) {
8547                 switch (scf_error()) {
8548                 case SCF_ERROR_NOT_FOUND:
8549                 case SCF_ERROR_DELETED:
8550                         break;
8551 
8552                 case SCF_ERROR_CONNECTION_BROKEN:
8553                 case SCF_ERROR_NOT_SET:
8554                 case SCF_ERROR_INVALID_ARGUMENT:
8555                 case SCF_ERROR_HANDLE_MISMATCH:
8556                 case SCF_ERROR_NOT_BOUND:
8557                 default:
8558                         bad_error("entity_get_pg", scf_error());
8559                 }
8560         } else {
8561                 /*
8562                  * Found the dependents/<wip dep> so check to
8563                  * see if the service is different.  If so
8564                  * store the service for later refresh, and
8565                  * delete the wip dependency from the service
8566                  */
8567                 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8568                         switch (scf_error()) {
8569                                 case SCF_ERROR_DELETED:
8570                                         break;
8571 
8572                                 case SCF_ERROR_CONNECTION_BROKEN:
8573                                 case SCF_ERROR_NOT_SET:
8574                                 case SCF_ERROR_INVALID_ARGUMENT:
8575                                 case SCF_ERROR_HANDLE_MISMATCH:
8576                                 case SCF_ERROR_NOT_BOUND:
8577                                 default:
8578                                         bad_error("scf_property_get_value",
8579                                             scf_error());
8580                         }
8581                 }
8582 
8583                 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8584                     max_scf_value_len + 1) < 0)
8585                         bad_error("scf_value_get_as_string", scf_error());
8586 
8587                 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8588                 switch (r) {
8589                 case 1:
8590                         break;
8591                 case 0:
8592                         if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8593                             &tissvc)) != SCF_ERROR_NONE) {
8594                                 if (serr == SCF_ERROR_NOT_FOUND) {
8595                                         break;
8596                                 } else {
8597                                         bad_error("fmri_to_entity", serr);
8598                                 }
8599                         }
8600 
8601                         if (entity_get_pg(tent, tissvc,
8602                             dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8603                                 serr = scf_error();
8604                                 if (serr == SCF_ERROR_NOT_FOUND ||
8605                                     serr == SCF_ERROR_DELETED) {
8606                                         break;
8607                                 } else {
8608                                         bad_error("entity_get_pg", scf_error());
8609                                 }
8610                         }
8611 
8612                         if (scf_pg_delete(imp_pg) != 0) {
8613                                 serr = scf_error();
8614                                 if (serr == SCF_ERROR_NOT_FOUND ||
8615                                     serr == SCF_ERROR_DELETED) {
8616                                         break;
8617                                 } else {
8618                                         bad_error("scf_pg_delete", scf_error());
8619                                 }
8620                         }
8621 
8622                         deldpt = internal_pgroup_new();
8623                         if (deldpt == NULL)
8624                                 return (ENOMEM);
8625                         deldpt->sc_pgroup_name =
8626                             strdup(dpt_pgroup->sc_pgroup_name);
8627                         deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8628                         if (deldpt->sc_pgroup_name == NULL ||
8629                             deldpt->sc_pgroup_fmri == NULL)
8630                                 return (ENOMEM);
8631                         deldpt->sc_parent = (entity_t *)ent;
8632                         if (uu_list_insert_after(imp_deleted_dpts, NULL,
8633                             deldpt) != 0)
8634                                 uu_die(gettext("libuutil error: %s\n"),
8635                                     uu_strerror(uu_error()));
8636 
8637                         break;
8638                 default:
8639                         bad_error("fmri_equal", r);
8640                 }
8641         }
8642 
8643         cb.sc_handle = g_hndl;
8644         cb.sc_parent = ent;
8645         cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8646         cb.sc_source_fmri = ent->sc_fmri;
8647         cb.sc_target_fmri = ent->sc_fmri;
8648         cb.sc_trans = NULL;
8649         cb.sc_flags = SCI_FORCE;
8650 
8651         if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8652                 return (UU_WALK_ERROR);
8653 
8654         r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8655         switch (r) {
8656         case 0:
8657                 break;
8658 
8659         case ENOMEM:
8660         case ECONNABORTED:
8661         case EPERM:
8662         case -1:
8663                 warn(gettext("Unable to refresh \"%s\"\n"),
8664                     dpt_pgroup->sc_pgroup_fmri);
8665                 return (UU_WALK_ERROR);
8666 
8667         default:
8668                 bad_error("imp_refresh_fmri", r);
8669         }
8670 
8671         return (UU_WALK_NEXT);
8672 }
8673 
8674 /*
8675  * Returns
8676  *   0 - success
8677  *   -1 - lscf_import_instance_pgs() failed.
8678  */
8679 int
8680 lscf_bundle_apply(bundle_t *bndl, const char *file)
8681 {
8682         pgroup_t *old_dpt;
8683         entity_t *svc, *inst;
8684         int annotation_set = 0;
8685         int ret = 0;
8686         int r = 0;
8687 
8688         lscf_prep_hndl();
8689 
8690         if ((ret = alloc_imp_globals()))
8691                 goto out;
8692 
8693         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8694                 scfdie();
8695 
8696         /*
8697          * Set the strings to be used for the security audit annotation
8698          * event.
8699          */
8700         if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8701                 annotation_set = 1;
8702         } else {
8703                 switch (scf_error()) {
8704                 case SCF_ERROR_CONNECTION_BROKEN:
8705                         warn(gettext("Repository connection broken.\n"));
8706                         goto out;
8707 
8708                 case SCF_ERROR_INVALID_ARGUMENT:
8709                 case SCF_ERROR_NOT_BOUND:
8710                 case SCF_ERROR_NO_RESOURCES:
8711                 case SCF_ERROR_INTERNAL:
8712                         bad_error("_scf_set_annotation", scf_error());
8713                         /* NOTREACHED */
8714 
8715                 default:
8716                         /*
8717                          * Do not abort apply operation because of
8718                          * inability to create annotation audit event.
8719                          */
8720                         warn(gettext("_scf_set_annotation() unexpectedly "
8721                             "failed with return code of %d\n"), scf_error());
8722                         break;
8723                 }
8724         }
8725 
8726         for (svc = uu_list_first(bndl->sc_bundle_services);
8727             svc != NULL;
8728             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8729                 int refresh = 0;
8730 
8731                 if (scf_scope_get_service(imp_scope, svc->sc_name,
8732                     imp_svc) != 0) {
8733                         switch (scf_error()) {
8734                         case SCF_ERROR_NOT_FOUND:
8735                                 if (g_verbose)
8736                                         warn(gettext("Ignoring nonexistent "
8737                                             "service %s.\n"), svc->sc_name);
8738                                 continue;
8739 
8740                         default:
8741                                 scfdie();
8742                         }
8743                 }
8744 
8745                 /*
8746                  * If there were missing types in the profile, then need to
8747                  * attempt to find the types.
8748                  */
8749                 if (svc->sc_miss_type) {
8750                         if (uu_list_numnodes(svc->sc_pgroups) &&
8751                             uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8752                             svc, UU_DEFAULT) != 0) {
8753                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8754                                         bad_error("uu_list_walk", uu_error());
8755 
8756                                 ret = -1;
8757                                 continue;
8758                         }
8759 
8760                         for (inst = uu_list_first(
8761                             svc->sc_u.sc_service.sc_service_instances);
8762                             inst != NULL;
8763                             inst = uu_list_next(
8764                             svc->sc_u.sc_service.sc_service_instances, inst)) {
8765                                 /*
8766                                  * If the instance doesn't exist just
8767                                  * skip to the next instance and let the
8768                                  * import note the missing instance.
8769                                  */
8770                                 if (scf_service_get_instance(imp_svc,
8771                                     inst->sc_name, imp_inst) != 0)
8772                                         continue;
8773 
8774                                 if (uu_list_walk(inst->sc_pgroups,
8775                                     find_current_pg_type, inst,
8776                                     UU_DEFAULT) != 0) {
8777                                         if (uu_error() !=
8778                                             UU_ERROR_CALLBACK_FAILED)
8779                                                 bad_error("uu_list_walk",
8780                                                     uu_error());
8781 
8782                                         ret = -1;
8783                                         inst->sc_miss_type = B_TRUE;
8784                                 }
8785                         }
8786                 }
8787 
8788                 /*
8789                  * if we have pgs in the profile, we need to refresh ALL
8790                  * instances of the service
8791                  */
8792                 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8793                         refresh = 1;
8794                         r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8795                             SCI_FORCE | SCI_KEEP);
8796                         switch (_lscf_import_err(r, svc->sc_fmri)) {
8797                         case IMPORT_NEXT:
8798                                 break;
8799 
8800                         case IMPORT_OUT:
8801                                 goto out;
8802 
8803                         case IMPORT_BAD:
8804                         default:
8805                                 bad_error("lscf_import_service_pgs", r);
8806                         }
8807                 }
8808 
8809                 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8810                         uu_list_walk(svc->sc_dependents,
8811                             lscf_dependent_apply, svc, UU_DEFAULT);
8812                 }
8813 
8814                 for (inst = uu_list_first(
8815                     svc->sc_u.sc_service.sc_service_instances);
8816                     inst != NULL;
8817                     inst = uu_list_next(
8818                     svc->sc_u.sc_service.sc_service_instances, inst)) {
8819                         /*
8820                          * This instance still has missing types
8821                          * so skip it.
8822                          */
8823                         if (inst->sc_miss_type) {
8824                                 if (g_verbose)
8825                                         warn(gettext("Ignoring instance "
8826                                             "%s:%s with missing types\n"),
8827                                             inst->sc_parent->sc_name,
8828                                             inst->sc_name);
8829 
8830                                 continue;
8831                         }
8832 
8833                         if (scf_service_get_instance(imp_svc, inst->sc_name,
8834                             imp_inst) != 0) {
8835                                 switch (scf_error()) {
8836                                 case SCF_ERROR_NOT_FOUND:
8837                                         if (g_verbose)
8838                                                 warn(gettext("Ignoring "
8839                                                     "nonexistant instance "
8840                                                     "%s:%s.\n"),
8841                                                     inst->sc_parent->sc_name,
8842                                                     inst->sc_name);
8843                                         continue;
8844 
8845                                 default:
8846                                         scfdie();
8847                                 }
8848                         }
8849 
8850                         /*
8851                          * If the instance does not have a general/enabled
8852                          * property and no last-import snapshot then the
8853                          * instance is not a fully installed instance and
8854                          * should not have a profile applied to it.
8855                          *
8856                          * This could happen if a service/instance declares
8857                          * a dependent on behalf of another service/instance.
8858                          *
8859                          */
8860                         if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8861                             imp_snap) != 0) {
8862                                 if (scf_instance_get_pg(imp_inst,
8863                                     SCF_PG_GENERAL, imp_pg) != 0 ||
8864                                     scf_pg_get_property(imp_pg,
8865                                     SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8866                                         if (g_verbose)
8867                                                 warn(gettext("Ignoreing "
8868                                                     "partial instance "
8869                                                     "%s:%s.\n"),
8870                                                     inst->sc_parent->sc_name,
8871                                                     inst->sc_name);
8872                                         continue;
8873                                 }
8874                         }
8875 
8876                         r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8877                             inst, SCI_FORCE | SCI_KEEP);
8878                         switch (_lscf_import_err(r, inst->sc_fmri)) {
8879                         case IMPORT_NEXT:
8880                                 break;
8881 
8882                         case IMPORT_OUT:
8883                                 goto out;
8884 
8885                         case IMPORT_BAD:
8886                         default:
8887                                 bad_error("lscf_import_instance_pgs", r);
8888                         }
8889 
8890                         if (uu_list_numnodes(inst->sc_dependents) != 0) {
8891                                 uu_list_walk(inst->sc_dependents,
8892                                     lscf_dependent_apply, inst, UU_DEFAULT);
8893                         }
8894 
8895                         /* refresh only if there is no pgs in the service */
8896                         if (refresh == 0)
8897                                 (void) refresh_entity(0, imp_inst,
8898                                     inst->sc_fmri, NULL, NULL, NULL);
8899                 }
8900 
8901                 if (refresh == 1) {
8902                         char *name_buf = safe_malloc(max_scf_name_len + 1);
8903 
8904                         (void) refresh_entity(1, imp_svc, svc->sc_name,
8905                             imp_inst, imp_iter, name_buf);
8906                         free(name_buf);
8907                 }
8908 
8909                 for (old_dpt = uu_list_first(imp_deleted_dpts);
8910                     old_dpt != NULL;
8911                     old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8912                         if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8913                             old_dpt->sc_pgroup_name,
8914                             old_dpt->sc_parent->sc_fmri) != 0) {
8915                                 warn(gettext("Unable to refresh \"%s\"\n"),
8916                                     old_dpt->sc_pgroup_fmri);
8917                         }
8918                 }
8919         }
8920 
8921 out:
8922         if (annotation_set) {
8923                 /* Remove security audit annotation strings. */
8924                 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8925         }
8926 
8927         free_imp_globals();
8928         return (ret);
8929 }
8930 
8931 
8932 /*
8933  * Export.  These functions create and output an XML tree of a service
8934  * description from the repository.  This is largely the inverse of
8935  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8936  *
8937  * - We must include any properties which are not represented specifically by
8938  *   a service manifest, e.g., properties created by an admin post-import.  To
8939  *   do so we'll iterate through all properties and deal with each
8940  *   apropriately.
8941  *
8942  * - Children of services and instances must must be in the order set by the
8943  *   DTD, but we iterate over the properties in undefined order.  The elements
8944  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8945  *   number of classes of them, however, we'll keep the classes separate and
8946  *   assemble them in order.
8947  */
8948 
8949 /*
8950  * Convenience function to handle xmlSetProp errors (and type casting).
8951  */
8952 static void
8953 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8954 {
8955         if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8956                 uu_die(gettext("Could not set XML property.\n"));
8957 }
8958 
8959 /*
8960  * Convenience function to set an XML attribute to the single value of an
8961  * astring property.  If the value happens to be the default, don't set the
8962  * attribute.  "dval" should be the default value supplied by the DTD, or
8963  * NULL for no default.
8964  */
8965 static int
8966 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8967     const char *name, const char *dval)
8968 {
8969         scf_value_t *val;
8970         ssize_t len;
8971         char *str;
8972 
8973         val = scf_value_create(g_hndl);
8974         if (val == NULL)
8975                 scfdie();
8976 
8977         if (prop_get_val(prop, val) != 0) {
8978                 scf_value_destroy(val);
8979                 return (-1);
8980         }
8981 
8982         len = scf_value_get_as_string(val, NULL, 0);
8983         if (len < 0)
8984                 scfdie();
8985 
8986         str = safe_malloc(len + 1);
8987 
8988         if (scf_value_get_as_string(val, str, len + 1) < 0)
8989                 scfdie();
8990 
8991         scf_value_destroy(val);
8992 
8993         if (dval == NULL || strcmp(str, dval) != 0)
8994                 safe_setprop(n, name, str);
8995 
8996         free(str);
8997 
8998         return (0);
8999 }
9000 
9001 /*
9002  * As above, but the attribute is always set.
9003  */
9004 static int
9005 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9006 {
9007         return (set_attr_from_prop_default(prop, n, name, NULL));
9008 }
9009 
9010 /*
9011  * Dump the given document onto f, with "'s replaced by ''s.
9012  */
9013 static int
9014 write_service_bundle(xmlDocPtr doc, FILE *f)
9015 {
9016         xmlChar *mem;
9017         int sz, i;
9018 
9019         mem = NULL;
9020         xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9021 
9022         if (mem == NULL) {
9023                 semerr(gettext("Could not dump XML tree.\n"));
9024                 return (-1);
9025         }
9026 
9027         /*
9028          * Fortunately libxml produces &quot; instead of ", so we can blindly
9029          * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9030          * &apos; code?!
9031          */
9032         for (i = 0; i < sz; ++i) {
9033                 char c = (char)mem[i];
9034 
9035                 if (c == '"')
9036                         (void) fputc('\'', f);
9037                 else if (c == '\'')
9038                         (void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9039                 else
9040                         (void) fputc(c, f);
9041         }
9042 
9043         return (0);
9044 }
9045 
9046 /*
9047  * Create the DOM elements in elts necessary to (generically) represent prop
9048  * (i.e., a property or propval element).  If the name of the property is
9049  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9050  */
9051 static void
9052 export_property(scf_property_t *prop, const char *name_arg,
9053     struct pg_elts *elts, int flags)
9054 {
9055         const char *type;
9056         scf_error_t err = 0;
9057         xmlNodePtr pnode, lnode;
9058         char *lnname;
9059         int ret;
9060 
9061         /* name */
9062         if (name_arg != NULL) {
9063                 (void) strcpy(exp_str, name_arg);
9064         } else {
9065                 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9066                         scfdie();
9067         }
9068 
9069         /* type */
9070         type = prop_to_typestr(prop);
9071         if (type == NULL)
9072                 uu_die(gettext("Can't export property %s: unknown type.\n"),
9073                     exp_str);
9074 
9075         /* If we're exporting values, and there's just one, export it here. */
9076         if (!(flags & SCE_ALL_VALUES))
9077                 goto empty;
9078 
9079         if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9080                 xmlNodePtr n;
9081 
9082                 /* Single value, so use propval */
9083                 n = xmlNewNode(NULL, (xmlChar *)"propval");
9084                 if (n == NULL)
9085                         uu_die(emsg_create_xml);
9086 
9087                 safe_setprop(n, name_attr, exp_str);
9088                 safe_setprop(n, type_attr, type);
9089 
9090                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9091                         scfdie();
9092                 safe_setprop(n, value_attr, exp_str);
9093 
9094                 if (elts->propvals == NULL)
9095                         elts->propvals = n;
9096                 else
9097                         (void) xmlAddSibling(elts->propvals, n);
9098 
9099                 return;
9100         }
9101 
9102         err = scf_error();
9103 
9104         if (err == SCF_ERROR_PERMISSION_DENIED) {
9105                 semerr(emsg_permission_denied);
9106                 return;
9107         }
9108 
9109         if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9110             err != SCF_ERROR_NOT_FOUND &&
9111             err != SCF_ERROR_PERMISSION_DENIED)
9112                 scfdie();
9113 
9114 empty:
9115         /* Multiple (or no) values, so use property */
9116         pnode = xmlNewNode(NULL, (xmlChar *)"property");
9117         if (pnode == NULL)
9118                 uu_die(emsg_create_xml);
9119 
9120         safe_setprop(pnode, name_attr, exp_str);
9121         safe_setprop(pnode, type_attr, type);
9122 
9123         if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9124                 lnname = uu_msprintf("%s_list", type);
9125                 if (lnname == NULL)
9126                         uu_die(gettext("Could not create string"));
9127 
9128                 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9129                 if (lnode == NULL)
9130                         uu_die(emsg_create_xml);
9131 
9132                 uu_free(lnname);
9133 
9134                 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9135                         scfdie();
9136 
9137                 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9138                     1) {
9139                         xmlNodePtr vn;
9140 
9141                         vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9142                             NULL);
9143                         if (vn == NULL)
9144                                 uu_die(emsg_create_xml);
9145 
9146                         if (scf_value_get_as_string(exp_val, exp_str,
9147                             exp_str_sz) < 0)
9148                                 scfdie();
9149                         safe_setprop(vn, value_attr, exp_str);
9150                 }
9151                 if (ret != 0)
9152                         scfdie();
9153         }
9154 
9155         if (elts->properties == NULL)
9156                 elts->properties = pnode;
9157         else
9158                 (void) xmlAddSibling(elts->properties, pnode);
9159 }
9160 
9161 /*
9162  * Add a property_group element for this property group to elts.
9163  */
9164 static void
9165 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9166 {
9167         xmlNodePtr n;
9168         struct pg_elts elts;
9169         int ret;
9170         boolean_t read_protected;
9171 
9172         n = xmlNewNode(NULL, (xmlChar *)"property_group");
9173 
9174         /* name */
9175         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9176                 scfdie();
9177         safe_setprop(n, name_attr, exp_str);
9178 
9179         /* type */
9180         if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9181                 scfdie();
9182         safe_setprop(n, type_attr, exp_str);
9183 
9184         /* properties */
9185         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9186                 scfdie();
9187 
9188         (void) memset(&elts, 0, sizeof (elts));
9189 
9190         /*
9191          * If this property group is not read protected, we always want to
9192          * output all the values.  Otherwise, we only output the values if the
9193          * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9194          */
9195         if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9196                 scfdie();
9197 
9198         if (!read_protected)
9199                 flags |= SCE_ALL_VALUES;
9200 
9201         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9202                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9203                         scfdie();
9204 
9205                 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9206                         xmlNodePtr m;
9207 
9208                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9209                         if (m == NULL)
9210                                 uu_die(emsg_create_xml);
9211 
9212                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9213                                 elts.stability = m;
9214                                 continue;
9215                         }
9216 
9217                         xmlFreeNode(m);
9218                 }
9219 
9220                 export_property(exp_prop, NULL, &elts, flags);
9221         }
9222         if (ret == -1)
9223                 scfdie();
9224 
9225         (void) xmlAddChild(n, elts.stability);
9226         (void) xmlAddChildList(n, elts.propvals);
9227         (void) xmlAddChildList(n, elts.properties);
9228 
9229         if (eelts->property_groups == NULL)
9230                 eelts->property_groups = n;
9231         else
9232                 (void) xmlAddSibling(eelts->property_groups, n);
9233 }
9234 
9235 /*
9236  * Create an XML node representing the dependency described by the given
9237  * property group and put it in eelts.  Unless the dependency is not valid, in
9238  * which case create a generic property_group element which represents it and
9239  * put it in eelts.
9240  */
9241 static void
9242 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9243 {
9244         xmlNodePtr n;
9245         int err = 0, ret;
9246         struct pg_elts elts;
9247 
9248         n = xmlNewNode(NULL, (xmlChar *)"dependency");
9249         if (n == NULL)
9250                 uu_die(emsg_create_xml);
9251 
9252         /*
9253          * If the external flag is present, skip this dependency because it
9254          * should have been created by another manifest.
9255          */
9256         if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9257                 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9258                     prop_get_val(exp_prop, exp_val) == 0) {
9259                         uint8_t b;
9260 
9261                         if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9262                                 scfdie();
9263 
9264                         if (b)
9265                                 return;
9266                 }
9267         } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9268                 scfdie();
9269 
9270         /* Get the required attributes. */
9271 
9272         /* name */
9273         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9274                 scfdie();
9275         safe_setprop(n, name_attr, exp_str);
9276 
9277         /* grouping */
9278         if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9279             set_attr_from_prop(exp_prop, n, "grouping") != 0)
9280                 err = 1;
9281 
9282         /* restart_on */
9283         if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9284             set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9285                 err = 1;
9286 
9287         /* type */
9288         if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9289             set_attr_from_prop(exp_prop, n, type_attr) != 0)
9290                 err = 1;
9291 
9292         /*
9293          * entities: Not required, but if we create no children, it will be
9294          * created as empty on import, so fail if it's missing.
9295          */
9296         if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9297             prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9298                 scf_iter_t *eiter;
9299                 int ret2;
9300 
9301                 eiter = scf_iter_create(g_hndl);
9302                 if (eiter == NULL)
9303                         scfdie();
9304 
9305                 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9306                         scfdie();
9307 
9308                 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9309                         xmlNodePtr ch;
9310 
9311                         if (scf_value_get_astring(exp_val, exp_str,
9312                             exp_str_sz) < 0)
9313                                 scfdie();
9314 
9315                         /*
9316                          * service_fmri's must be first, so we can add them
9317                          * here.
9318                          */
9319                         ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9320                             NULL);
9321                         if (ch == NULL)
9322                                 uu_die(emsg_create_xml);
9323 
9324                         safe_setprop(ch, value_attr, exp_str);
9325                 }
9326                 if (ret2 == -1)
9327                         scfdie();
9328 
9329                 scf_iter_destroy(eiter);
9330         } else
9331                 err = 1;
9332 
9333         if (err) {
9334                 xmlFreeNode(n);
9335 
9336                 export_pg(pg, eelts, SCE_ALL_VALUES);
9337 
9338                 return;
9339         }
9340 
9341         /* Iterate through the properties & handle each. */
9342         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9343                 scfdie();
9344 
9345         (void) memset(&elts, 0, sizeof (elts));
9346 
9347         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9348                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9349                         scfdie();
9350 
9351                 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9352                     strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9353                     strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9354                     strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9355                         continue;
9356                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9357                         xmlNodePtr m;
9358 
9359                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9360                         if (m == NULL)
9361                                 uu_die(emsg_create_xml);
9362 
9363                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9364                                 elts.stability = m;
9365                                 continue;
9366                         }
9367 
9368                         xmlFreeNode(m);
9369                 }
9370 
9371                 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9372         }
9373         if (ret == -1)
9374                 scfdie();
9375 
9376         (void) xmlAddChild(n, elts.stability);
9377         (void) xmlAddChildList(n, elts.propvals);
9378         (void) xmlAddChildList(n, elts.properties);
9379 
9380         if (eelts->dependencies == NULL)
9381                 eelts->dependencies = n;
9382         else
9383                 (void) xmlAddSibling(eelts->dependencies, n);
9384 }
9385 
9386 static xmlNodePtr
9387 export_method_environment(scf_propertygroup_t *pg)
9388 {
9389         xmlNodePtr env;
9390         int ret;
9391         int children = 0;
9392 
9393         if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9394                 return (NULL);
9395 
9396         env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9397         if (env == NULL)
9398                 uu_die(emsg_create_xml);
9399 
9400         if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9401                 scfdie();
9402 
9403         if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9404                 scfdie();
9405 
9406         while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9407                 xmlNodePtr ev;
9408                 char *cp;
9409 
9410                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9411                         scfdie();
9412 
9413                 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9414                         warn(gettext("Invalid environment variable \"%s\".\n"),
9415                             exp_str);
9416                         continue;
9417                 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9418                         warn(gettext("Invalid environment variable \"%s\"; "
9419                             "\"SMF_\" prefix is reserved.\n"), exp_str);
9420                         continue;
9421                 }
9422 
9423                 *cp = '\0';
9424                 cp++;
9425 
9426                 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9427                 if (ev == NULL)
9428                         uu_die(emsg_create_xml);
9429 
9430                 safe_setprop(ev, name_attr, exp_str);
9431                 safe_setprop(ev, value_attr, cp);
9432                 children++;
9433         }
9434 
9435         if (ret != 0)
9436                 scfdie();
9437 
9438         if (children == 0) {
9439                 xmlFreeNode(env);
9440                 return (NULL);
9441         }
9442 
9443         return (env);
9444 }
9445 
9446 /*
9447  * As above, but for a method property group.
9448  */
9449 static void
9450 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9451 {
9452         xmlNodePtr n, env;
9453         char *str;
9454         int err = 0, nonenv, ret;
9455         uint8_t use_profile;
9456         struct pg_elts elts;
9457         xmlNodePtr ctxt = NULL;
9458 
9459         n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9460 
9461         /* Get the required attributes. */
9462 
9463         /* name */
9464         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9465                 scfdie();
9466         safe_setprop(n, name_attr, exp_str);
9467 
9468         /* type */
9469         if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9470             set_attr_from_prop(exp_prop, n, type_attr) != 0)
9471                 err = 1;
9472 
9473         /* exec */
9474         if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9475             set_attr_from_prop(exp_prop, n, "exec") != 0)
9476                 err = 1;
9477 
9478         /* timeout */
9479         if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9480             prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9481             prop_get_val(exp_prop, exp_val) == 0) {
9482                 uint64_t c;
9483 
9484                 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9485                         scfdie();
9486 
9487                 str = uu_msprintf("%llu", c);
9488                 if (str == NULL)
9489                         uu_die(gettext("Could not create string"));
9490 
9491                 safe_setprop(n, "timeout_seconds", str);
9492                 free(str);
9493         } else
9494                 err = 1;
9495 
9496         if (err) {
9497                 xmlFreeNode(n);
9498 
9499                 export_pg(pg, eelts, SCE_ALL_VALUES);
9500 
9501                 return;
9502         }
9503 
9504 
9505         /*
9506          * If we're going to have a method_context child, we need to know
9507          * before we iterate through the properties.  Since method_context's
9508          * are optional, we don't want to complain about any properties
9509          * missing if none of them are there.  Thus we can't use the
9510          * convenience functions.
9511          */
9512         nonenv =
9513             scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9514             SCF_SUCCESS ||
9515             scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9516             SCF_SUCCESS ||
9517             scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, 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                  * We only want to complain about profile or credential
9545                  * properties if we will use them.  To determine that we must
9546                  * examine USE_PROFILE.
9547                  */
9548                 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9549                     prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9550                     prop_get_val(exp_prop, exp_val) == 0) {
9551                         if (scf_value_get_boolean(exp_val, &use_profile) !=
9552                             SCF_SUCCESS) {
9553                                 scfdie();
9554                         }
9555 
9556                         if (use_profile) {
9557                                 xmlNodePtr prof;
9558 
9559                                 prof = xmlNewChild(ctxt, NULL,
9560                                     (xmlChar *)"method_profile", NULL);
9561                                 if (prof == NULL)
9562                                         uu_die(emsg_create_xml);
9563 
9564                                 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9565                                     exp_prop) != 0 ||
9566                                     set_attr_from_prop(exp_prop, prof,
9567                                     name_attr) != 0)
9568                                         err = 1;
9569                         } else {
9570                                 xmlNodePtr cred;
9571 
9572                                 cred = xmlNewChild(ctxt, NULL,
9573                                     (xmlChar *)"method_credential", NULL);
9574                                 if (cred == NULL)
9575                                         uu_die(emsg_create_xml);
9576 
9577                                 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9578                                     exp_prop) != 0 ||
9579                                     set_attr_from_prop(exp_prop, cred,
9580                                     "user") != 0) {
9581                                         err = 1;
9582                                 }
9583 
9584                                 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9585                                     exp_prop) == 0 &&
9586                                     set_attr_from_prop_default(exp_prop, cred,
9587                                     "group", ":default") != 0)
9588                                         err = 1;
9589 
9590                                 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9591                                     exp_prop) == 0 &&
9592                                     set_attr_from_prop_default(exp_prop, cred,
9593                                     "supp_groups", ":default") != 0)
9594                                         err = 1;
9595 
9596                                 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9597                                     exp_prop) == 0 &&
9598                                     set_attr_from_prop_default(exp_prop, cred,
9599                                     "privileges", ":default") != 0)
9600                                         err = 1;
9601 
9602                                 if (pg_get_prop(pg,
9603                                     SCF_PROPERTY_LIMIT_PRIVILEGES,
9604                                     exp_prop) == 0 &&
9605                                     set_attr_from_prop_default(exp_prop, cred,
9606                                     "limit_privileges", ":default") != 0)
9607                                         err = 1;
9608                         }
9609                 }
9610         }
9611 
9612         if ((env = export_method_environment(pg)) != NULL) {
9613                 if (ctxt == NULL) {
9614                         ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9615                         if (ctxt == NULL)
9616                                 uu_die(emsg_create_xml);
9617                 }
9618                 (void) xmlAddChild(ctxt, env);
9619         }
9620 
9621         if (env != NULL || (nonenv && err == 0))
9622                 (void) xmlAddChild(n, ctxt);
9623         else
9624                 xmlFreeNode(ctxt);
9625 
9626         nonenv = (err == 0);
9627 
9628         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9629                 scfdie();
9630 
9631         (void) memset(&elts, 0, sizeof (elts));
9632 
9633         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9634                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9635                         scfdie();
9636 
9637                 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9638                     strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9639                     strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9640                         continue;
9641                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9642                         xmlNodePtr m;
9643 
9644                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9645                         if (m == NULL)
9646                                 uu_die(emsg_create_xml);
9647 
9648                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9649                                 elts.stability = m;
9650                                 continue;
9651                         }
9652 
9653                         xmlFreeNode(m);
9654                 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9655                     0 ||
9656                     strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9657                     strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9658                     strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9659                         if (nonenv)
9660                                 continue;
9661                 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9662                     strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9663                     strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9664                     strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9665                     strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9666                         if (nonenv && !use_profile)
9667                                 continue;
9668                 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9669                         if (nonenv && use_profile)
9670                                 continue;
9671                 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9672                         if (env != NULL)
9673                                 continue;
9674                 }
9675 
9676                 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9677         }
9678         if (ret == -1)
9679                 scfdie();
9680 
9681         (void) xmlAddChild(n, elts.stability);
9682         (void) xmlAddChildList(n, elts.propvals);
9683         (void) xmlAddChildList(n, elts.properties);
9684 
9685         if (eelts->exec_methods == NULL)
9686                 eelts->exec_methods = n;
9687         else
9688                 (void) xmlAddSibling(eelts->exec_methods, n);
9689 }
9690 
9691 static void
9692 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9693     struct entity_elts *eelts)
9694 {
9695         xmlNodePtr pgnode;
9696 
9697         pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9698         if (pgnode == NULL)
9699                 uu_die(emsg_create_xml);
9700 
9701         safe_setprop(pgnode, name_attr, name);
9702         safe_setprop(pgnode, type_attr, type);
9703 
9704         (void) xmlAddChildList(pgnode, elts->propvals);
9705         (void) xmlAddChildList(pgnode, elts->properties);
9706 
9707         if (eelts->property_groups == NULL)
9708                 eelts->property_groups = pgnode;
9709         else
9710                 (void) xmlAddSibling(eelts->property_groups, pgnode);
9711 }
9712 
9713 /*
9714  * Process the general property group for a service.  This is the one with the
9715  * goodies.
9716  */
9717 static void
9718 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9719 {
9720         struct pg_elts elts;
9721         int ret;
9722 
9723         /*
9724          * In case there are properties which don't correspond to child
9725          * entities of the service entity, we'll set up a pg_elts structure to
9726          * put them in.
9727          */
9728         (void) memset(&elts, 0, sizeof (elts));
9729 
9730         /* Walk the properties, looking for special ones. */
9731         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9732                 scfdie();
9733 
9734         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9735                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9736                         scfdie();
9737 
9738                 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9739                         if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9740                             prop_get_val(exp_prop, exp_val) == 0) {
9741                                 uint8_t b;
9742 
9743                                 if (scf_value_get_boolean(exp_val, &b) !=
9744                                     SCF_SUCCESS)
9745                                         scfdie();
9746 
9747                                 if (b) {
9748                                         selts->single_instance =
9749                                             xmlNewNode(NULL,
9750                                             (xmlChar *)"single_instance");
9751                                         if (selts->single_instance == NULL)
9752                                                 uu_die(emsg_create_xml);
9753                                 }
9754 
9755                                 continue;
9756                         }
9757                 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9758                         xmlNodePtr rnode, sfnode;
9759 
9760                         rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9761                         if (rnode == NULL)
9762                                 uu_die(emsg_create_xml);
9763 
9764                         sfnode = xmlNewChild(rnode, NULL,
9765                             (xmlChar *)"service_fmri", NULL);
9766                         if (sfnode == NULL)
9767                                 uu_die(emsg_create_xml);
9768 
9769                         if (set_attr_from_prop(exp_prop, sfnode,
9770                             value_attr) == 0) {
9771                                 selts->restarter = rnode;
9772                                 continue;
9773                         }
9774 
9775                         xmlFreeNode(rnode);
9776                 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9777                     0) {
9778                         xmlNodePtr s;
9779 
9780                         s = xmlNewNode(NULL, (xmlChar *)"stability");
9781                         if (s == NULL)
9782                                 uu_die(emsg_create_xml);
9783 
9784                         if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9785                                 selts->stability = s;
9786                                 continue;
9787                         }
9788 
9789                         xmlFreeNode(s);
9790                 }
9791 
9792                 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9793         }
9794         if (ret == -1)
9795                 scfdie();
9796 
9797         if (elts.propvals != NULL || elts.properties != NULL)
9798                 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9799                     selts);
9800 }
9801 
9802 static void
9803 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9804 {
9805         xmlNodePtr n, prof, cred, env;
9806         uint8_t use_profile;
9807         int ret, err = 0;
9808 
9809         n = xmlNewNode(NULL, (xmlChar *)"method_context");
9810 
9811         env = export_method_environment(pg);
9812 
9813         /* Need to know whether we'll use a profile or not. */
9814         if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9815             prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9816             prop_get_val(exp_prop, exp_val) == 0) {
9817                 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9818                         scfdie();
9819 
9820                 if (use_profile)
9821                         prof =
9822                             xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9823                             NULL);
9824                 else
9825                         cred =
9826                             xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9827                             NULL);
9828         }
9829 
9830         if (env != NULL)
9831                 (void) xmlAddChild(n, env);
9832 
9833         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9834                 scfdie();
9835 
9836         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9837                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9838                         scfdie();
9839 
9840                 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9841                         if (set_attr_from_prop(exp_prop, n,
9842                             "working_directory") != 0)
9843                                 err = 1;
9844                 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9845                         if (set_attr_from_prop(exp_prop, n, "project") != 0)
9846                                 err = 1;
9847                 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9848                         if (set_attr_from_prop(exp_prop, n,
9849                             "resource_pool") != 0)
9850                                 err = 1;
9851                 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9852                         /* EMPTY */
9853                 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9854                         if (use_profile ||
9855                             set_attr_from_prop(exp_prop, cred, "user") != 0)
9856                                 err = 1;
9857                 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9858                         if (use_profile ||
9859                             set_attr_from_prop(exp_prop, cred, "group") != 0)
9860                                 err = 1;
9861                 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9862                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9863                             "supp_groups") != 0)
9864                                 err = 1;
9865                 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9866                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9867                             "privileges") != 0)
9868                                 err = 1;
9869                 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9870                     0) {
9871                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9872                             "limit_privileges") != 0)
9873                                 err = 1;
9874                 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9875                         if (!use_profile || set_attr_from_prop(exp_prop,
9876                             prof, name_attr) != 0)
9877                                 err = 1;
9878                 } else {
9879                         /* Can't have generic properties in method_context's */
9880                         err = 1;
9881                 }
9882         }
9883         if (ret == -1)
9884                 scfdie();
9885 
9886         if (err && env == NULL) {
9887                 xmlFreeNode(n);
9888                 export_pg(pg, elts, SCE_ALL_VALUES);
9889                 return;
9890         }
9891 
9892         elts->method_context = n;
9893 }
9894 
9895 /*
9896  * Given a dependency property group in the tfmri entity (target fmri), return
9897  * a dependent element which represents it.
9898  */
9899 static xmlNodePtr
9900 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9901 {
9902         uint8_t b;
9903         xmlNodePtr n, sf;
9904         int err = 0, ret;
9905         struct pg_elts pgelts;
9906 
9907         /*
9908          * If external isn't set to true then exporting the service will
9909          * export this as a normal dependency, so we should stop to avoid
9910          * duplication.
9911          */
9912         if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9913             scf_property_get_value(exp_prop, exp_val) != 0 ||
9914             scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9915                 if (g_verbose) {
9916                         warn(gettext("Dependent \"%s\" cannot be exported "
9917                             "properly because the \"%s\" property of the "
9918                             "\"%s\" dependency of %s is not set to true.\n"),
9919                             name, scf_property_external, name, tfmri);
9920                 }
9921 
9922                 return (NULL);
9923         }
9924 
9925         n = xmlNewNode(NULL, (xmlChar *)"dependent");
9926         if (n == NULL)
9927                 uu_die(emsg_create_xml);
9928 
9929         safe_setprop(n, name_attr, name);
9930 
9931         /* Get the required attributes */
9932         if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9933             set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9934                 err = 1;
9935 
9936         if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9937             set_attr_from_prop(exp_prop, n, "grouping") != 0)
9938                 err = 1;
9939 
9940         if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9941             prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9942             prop_get_val(exp_prop, exp_val) == 0) {
9943                 /* EMPTY */
9944         } else
9945                 err = 1;
9946 
9947         if (err) {
9948                 xmlFreeNode(n);
9949                 return (NULL);
9950         }
9951 
9952         sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9953         if (sf == NULL)
9954                 uu_die(emsg_create_xml);
9955 
9956         safe_setprop(sf, value_attr, tfmri);
9957 
9958         /*
9959          * Now add elements for the other properties.
9960          */
9961         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9962                 scfdie();
9963 
9964         (void) memset(&pgelts, 0, sizeof (pgelts));
9965 
9966         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9967                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9968                         scfdie();
9969 
9970                 if (strcmp(exp_str, scf_property_external) == 0 ||
9971                     strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9972                     strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9973                     strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9974                         continue;
9975                 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9976                         if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9977                             prop_get_val(exp_prop, exp_val) == 0) {
9978                                 char type[sizeof ("service") + 1];
9979 
9980                                 if (scf_value_get_astring(exp_val, type,
9981                                     sizeof (type)) < 0)
9982                                         scfdie();
9983 
9984                                 if (strcmp(type, "service") == 0)
9985                                         continue;
9986                         }
9987                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9988                         xmlNodePtr s;
9989 
9990                         s = xmlNewNode(NULL, (xmlChar *)"stability");
9991                         if (s == NULL)
9992                                 uu_die(emsg_create_xml);
9993 
9994                         if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9995                                 pgelts.stability = s;
9996                                 continue;
9997                         }
9998 
9999                         xmlFreeNode(s);
10000                 }
10001 
10002                 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10003         }
10004         if (ret == -1)
10005                 scfdie();
10006 
10007         (void) xmlAddChild(n, pgelts.stability);
10008         (void) xmlAddChildList(n, pgelts.propvals);
10009         (void) xmlAddChildList(n, pgelts.properties);
10010 
10011         return (n);
10012 }
10013 
10014 static void
10015 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10016 {
10017         scf_propertygroup_t *opg;
10018         scf_iter_t *iter;
10019         char *type, *fmri;
10020         int ret;
10021         struct pg_elts pgelts;
10022         xmlNodePtr n;
10023         scf_error_t serr;
10024 
10025         if ((opg = scf_pg_create(g_hndl)) == NULL ||
10026             (iter = scf_iter_create(g_hndl)) == NULL)
10027                 scfdie();
10028 
10029         /* Can't use exp_prop_iter due to export_dependent(). */
10030         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10031                 scfdie();
10032 
10033         type = safe_malloc(max_scf_pg_type_len + 1);
10034 
10035         /* Get an extra byte so we can tell if values are too long. */
10036         fmri = safe_malloc(max_scf_fmri_len + 2);
10037 
10038         (void) memset(&pgelts, 0, sizeof (pgelts));
10039 
10040         while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10041                 void *entity;
10042                 int isservice;
10043                 scf_type_t ty;
10044 
10045                 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10046                         scfdie();
10047 
10048                 if ((ty != SCF_TYPE_ASTRING &&
10049                     prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10050                     prop_get_val(exp_prop, exp_val) != 0) {
10051                         export_property(exp_prop, NULL, &pgelts,
10052                             SCE_ALL_VALUES);
10053                         continue;
10054                 }
10055 
10056                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10057                         scfdie();
10058 
10059                 if (scf_value_get_astring(exp_val, fmri,
10060                     max_scf_fmri_len + 2) < 0)
10061                         scfdie();
10062 
10063                 /* Look for a dependency group in the target fmri. */
10064                 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10065                 switch (serr) {
10066                 case SCF_ERROR_NONE:
10067                         break;
10068 
10069                 case SCF_ERROR_NO_MEMORY:
10070                         uu_die(gettext("Out of memory.\n"));
10071                         /* NOTREACHED */
10072 
10073                 case SCF_ERROR_INVALID_ARGUMENT:
10074                         if (g_verbose) {
10075                                 if (scf_property_to_fmri(exp_prop, fmri,
10076                                     max_scf_fmri_len + 2) < 0)
10077                                         scfdie();
10078 
10079                                 warn(gettext("The value of %s is not a valid "
10080                                     "FMRI.\n"), fmri);
10081                         }
10082 
10083                         export_property(exp_prop, exp_str, &pgelts,
10084                             SCE_ALL_VALUES);
10085                         continue;
10086 
10087                 case SCF_ERROR_CONSTRAINT_VIOLATED:
10088                         if (g_verbose) {
10089                                 if (scf_property_to_fmri(exp_prop, fmri,
10090                                     max_scf_fmri_len + 2) < 0)
10091                                         scfdie();
10092 
10093                                 warn(gettext("The value of %s does not specify "
10094                                     "a service or an instance.\n"), fmri);
10095                         }
10096 
10097                         export_property(exp_prop, exp_str, &pgelts,
10098                             SCE_ALL_VALUES);
10099                         continue;
10100 
10101                 case SCF_ERROR_NOT_FOUND:
10102                         if (g_verbose) {
10103                                 if (scf_property_to_fmri(exp_prop, fmri,
10104                                     max_scf_fmri_len + 2) < 0)
10105                                         scfdie();
10106 
10107                                 warn(gettext("The entity specified by %s does "
10108                                     "not exist.\n"), fmri);
10109                         }
10110 
10111                         export_property(exp_prop, exp_str, &pgelts,
10112                             SCE_ALL_VALUES);
10113                         continue;
10114 
10115                 default:
10116 #ifndef NDEBUG
10117                         (void) fprintf(stderr, "%s:%d: %s() failed with "
10118                             "unexpected error %d.\n", __FILE__, __LINE__,
10119                             "fmri_to_entity", serr);
10120 #endif
10121                         abort();
10122                 }
10123 
10124                 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10125                         if (scf_error() != SCF_ERROR_NOT_FOUND)
10126                                 scfdie();
10127 
10128                         warn(gettext("Entity %s is missing dependency property "
10129                             "group %s.\n"), fmri, exp_str);
10130 
10131                         export_property(exp_prop, NULL, &pgelts,
10132                             SCE_ALL_VALUES);
10133                         continue;
10134                 }
10135 
10136                 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10137                         scfdie();
10138 
10139                 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10140                         if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10141                                 scfdie();
10142 
10143                         warn(gettext("Property group %s is not of "
10144                             "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10145 
10146                         export_property(exp_prop, NULL, &pgelts,
10147                             SCE_ALL_VALUES);
10148                         continue;
10149                 }
10150 
10151                 n = export_dependent(opg, exp_str, fmri);
10152                 if (n == NULL) {
10153                         export_property(exp_prop, exp_str, &pgelts,
10154                             SCE_ALL_VALUES);
10155                 } else {
10156                         if (eelts->dependents == NULL)
10157                                 eelts->dependents = n;
10158                         else
10159                                 (void) xmlAddSibling(eelts->dependents,
10160                                     n);
10161                 }
10162         }
10163         if (ret == -1)
10164                 scfdie();
10165 
10166         free(fmri);
10167         free(type);
10168 
10169         scf_iter_destroy(iter);
10170         scf_pg_destroy(opg);
10171 
10172         if (pgelts.propvals != NULL || pgelts.properties != NULL)
10173                 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10174                     eelts);
10175 }
10176 
10177 static void
10178 make_node(xmlNodePtr *nodep, const char *name)
10179 {
10180         if (*nodep == NULL) {
10181                 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10182                 if (*nodep == NULL)
10183                         uu_die(emsg_create_xml);
10184         }
10185 }
10186 
10187 static xmlNodePtr
10188 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10189 {
10190         int ret;
10191         xmlNodePtr parent = NULL;
10192         xmlNodePtr loctext = NULL;
10193 
10194         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10195                 scfdie();
10196 
10197         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10198                 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10199                     prop_get_val(exp_prop, exp_val) != 0)
10200                         continue;
10201 
10202                 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10203                         scfdie();
10204 
10205                 make_node(&parent, parname);
10206                 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10207                     (xmlChar *)exp_str);
10208                 if (loctext == NULL)
10209                         uu_die(emsg_create_xml);
10210 
10211                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10212                         scfdie();
10213 
10214                 safe_setprop(loctext, "xml:lang", exp_str);
10215         }
10216 
10217         if (ret == -1)
10218                 scfdie();
10219 
10220         return (parent);
10221 }
10222 
10223 static xmlNodePtr
10224 export_tm_manpage(scf_propertygroup_t *pg)
10225 {
10226         xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10227         if (manpage == NULL)
10228                 uu_die(emsg_create_xml);
10229 
10230         if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10231             set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10232             pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10233             set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10234                 xmlFreeNode(manpage);
10235                 return (NULL);
10236         }
10237 
10238         if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10239                 (void) set_attr_from_prop_default(exp_prop,
10240                     manpage, "manpath", ":default");
10241 
10242         return (manpage);
10243 }
10244 
10245 static xmlNodePtr
10246 export_tm_doc_link(scf_propertygroup_t *pg)
10247 {
10248         xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10249         if (doc_link == NULL)
10250                 uu_die(emsg_create_xml);
10251 
10252         if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10253             set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10254             pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10255             set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10256                 xmlFreeNode(doc_link);
10257                 return (NULL);
10258         }
10259         return (doc_link);
10260 }
10261 
10262 /*
10263  * Process template information for a service or instances.
10264  */
10265 static void
10266 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10267     struct template_elts *telts)
10268 {
10269         size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10270         size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10271         xmlNodePtr child = NULL;
10272 
10273         if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10274                 scfdie();
10275 
10276         if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10277                 telts->common_name = export_tm_loctext(pg, "common_name");
10278                 if (telts->common_name == NULL)
10279                         export_pg(pg, elts, SCE_ALL_VALUES);
10280                 return;
10281         } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10282                 telts->description = export_tm_loctext(pg, "description");
10283                 if (telts->description == NULL)
10284                         export_pg(pg, elts, SCE_ALL_VALUES);
10285                 return;
10286         }
10287 
10288         if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10289                 child = export_tm_manpage(pg);
10290         } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10291                 child = export_tm_doc_link(pg);
10292         }
10293 
10294         if (child != NULL) {
10295                 make_node(&telts->documentation, "documentation");
10296                 (void) xmlAddChild(telts->documentation, child);
10297         } else {
10298                 export_pg(pg, elts, SCE_ALL_VALUES);
10299         }
10300 }
10301 
10302 /*
10303  * Process parameter and paramval elements
10304  */
10305 static void
10306 export_parameter(scf_property_t *prop, const char *name,
10307     struct params_elts *elts)
10308 {
10309         xmlNodePtr param;
10310         scf_error_t err = 0;
10311         int ret;
10312 
10313         if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10314                 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10315                         uu_die(emsg_create_xml);
10316 
10317                 safe_setprop(param, name_attr, name);
10318 
10319                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10320                         scfdie();
10321                 safe_setprop(param, value_attr, exp_str);
10322 
10323                 if (elts->paramval == NULL)
10324                         elts->paramval = param;
10325                 else
10326                         (void) xmlAddSibling(elts->paramval, param);
10327 
10328                 return;
10329         }
10330 
10331         err = scf_error();
10332 
10333         if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10334             err != SCF_ERROR_NOT_FOUND)
10335                 scfdie();
10336 
10337         if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10338                 uu_die(emsg_create_xml);
10339 
10340         safe_setprop(param, name_attr, name);
10341 
10342         if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10343                 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10344                         scfdie();
10345 
10346                 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10347                     1) {
10348                         xmlNodePtr vn;
10349 
10350                         if ((vn = xmlNewChild(param, NULL,
10351                             (xmlChar *)"value_node", NULL)) == NULL)
10352                                 uu_die(emsg_create_xml);
10353 
10354                         if (scf_value_get_as_string(exp_val, exp_str,
10355                             exp_str_sz) < 0)
10356                                 scfdie();
10357 
10358                         safe_setprop(vn, value_attr, exp_str);
10359                 }
10360                 if (ret != 0)
10361                         scfdie();
10362         }
10363 
10364         if (elts->parameter == NULL)
10365                 elts->parameter = param;
10366         else
10367                 (void) xmlAddSibling(elts->parameter, param);
10368 }
10369 
10370 /*
10371  * Process notification parameters for a service or instance
10372  */
10373 static void
10374 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10375 {
10376         xmlNodePtr n, event, *type;
10377         struct params_elts *eelts;
10378         int ret, err, i;
10379 
10380         n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10381         event = xmlNewNode(NULL, (xmlChar *)"event");
10382         if (n == NULL || event == NULL)
10383                 uu_die(emsg_create_xml);
10384 
10385         /* event value */
10386         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10387                 scfdie();
10388         safe_setprop(event, value_attr, exp_str);
10389 
10390         (void) xmlAddChild(n, event);
10391 
10392         if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10393             (eelts = calloc(URI_SCHEME_NUM,
10394             sizeof (struct params_elts))) == NULL)
10395                 uu_die(gettext("Out of memory.\n"));
10396 
10397         err = 0;
10398 
10399         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10400                 scfdie();
10401 
10402         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10403                 char *t, *p;
10404 
10405                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10406                         scfdie();
10407 
10408                 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10409                         /*
10410                          * this is not a well formed notification parameters
10411                          * element, we should export as regular pg
10412                          */
10413                         err = 1;
10414                         break;
10415                 }
10416 
10417                 if ((i = check_uri_protocol(t)) < 0) {
10418                         err = 1;
10419                         break;
10420                 }
10421 
10422                 if (type[i] == NULL) {
10423                         if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10424                             NULL)
10425                                 uu_die(emsg_create_xml);
10426 
10427                         safe_setprop(type[i], name_attr, t);
10428                 }
10429                 if (strcmp(p, active_attr) == 0) {
10430                         if (set_attr_from_prop(exp_prop, type[i],
10431                             active_attr) != 0) {
10432                                 err = 1;
10433                                 break;
10434                         }
10435                         continue;
10436                 }
10437                 /*
10438                  * We export the parameter
10439                  */
10440                 export_parameter(exp_prop, p, &eelts[i]);
10441         }
10442 
10443         if (ret == -1)
10444                 scfdie();
10445 
10446         if (err == 1) {
10447                 for (i = 0; i < URI_SCHEME_NUM; ++i)
10448                         xmlFree(type[i]);
10449                 free(type);
10450 
10451                 export_pg(pg, elts, SCE_ALL_VALUES);
10452 
10453                 return;
10454         } else {
10455                 for (i = 0; i < URI_SCHEME_NUM; ++i)
10456                         if (type[i] != NULL) {
10457                                 (void) xmlAddChildList(type[i],
10458                                     eelts[i].paramval);
10459                                 (void) xmlAddChildList(type[i],
10460                                     eelts[i].parameter);
10461                                 (void) xmlAddSibling(event, type[i]);
10462                         }
10463         }
10464         free(type);
10465 
10466         if (elts->notify_params == NULL)
10467                 elts->notify_params = n;
10468         else
10469                 (void) xmlAddSibling(elts->notify_params, n);
10470 }
10471 
10472 /*
10473  * Process the general property group for an instance.
10474  */
10475 static void
10476 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10477     struct entity_elts *elts)
10478 {
10479         uint8_t enabled;
10480         struct pg_elts pgelts;
10481         int ret;
10482 
10483         /* enabled */
10484         if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10485             prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10486             prop_get_val(exp_prop, exp_val) == 0) {
10487                 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10488                         scfdie();
10489         } else {
10490                 enabled = 0;
10491         }
10492 
10493         safe_setprop(inode, enabled_attr, enabled ? true : false);
10494 
10495         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10496                 scfdie();
10497 
10498         (void) memset(&pgelts, 0, sizeof (pgelts));
10499 
10500         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10501                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10502                         scfdie();
10503 
10504                 if (strcmp(exp_str, scf_property_enabled) == 0) {
10505                         continue;
10506                 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10507                         xmlNodePtr rnode, sfnode;
10508 
10509                         rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10510                         if (rnode == NULL)
10511                                 uu_die(emsg_create_xml);
10512 
10513                         sfnode = xmlNewChild(rnode, NULL,
10514                             (xmlChar *)"service_fmri", NULL);
10515                         if (sfnode == NULL)
10516                                 uu_die(emsg_create_xml);
10517 
10518                         if (set_attr_from_prop(exp_prop, sfnode,
10519                             value_attr) == 0) {
10520                                 elts->restarter = rnode;
10521                                 continue;
10522                         }
10523 
10524                         xmlFreeNode(rnode);
10525                 }
10526 
10527                 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10528         }
10529         if (ret == -1)
10530                 scfdie();
10531 
10532         if (pgelts.propvals != NULL || pgelts.properties != NULL)
10533                 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10534                     elts);
10535 }
10536 
10537 /*
10538  * Put an instance element for the given instance into selts.
10539  */
10540 static void
10541 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10542 {
10543         xmlNodePtr n;
10544         boolean_t isdefault;
10545         struct entity_elts elts;
10546         struct template_elts template_elts;
10547         int ret;
10548 
10549         n = xmlNewNode(NULL, (xmlChar *)"instance");
10550         if (n == NULL)
10551                 uu_die(emsg_create_xml);
10552 
10553         /* name */
10554         if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10555                 scfdie();
10556         safe_setprop(n, name_attr, exp_str);
10557         isdefault = strcmp(exp_str, "default") == 0;
10558 
10559         /* check existance of general pg (since general/enabled is required) */
10560         if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10561                 if (scf_error() != SCF_ERROR_NOT_FOUND)
10562                         scfdie();
10563 
10564                 if (g_verbose) {
10565                         if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10566                                 scfdie();
10567 
10568                         warn(gettext("Instance %s has no general property "
10569                             "group; it will be marked disabled.\n"), exp_str);
10570                 }
10571 
10572                 safe_setprop(n, enabled_attr, false);
10573         } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10574             strcmp(exp_str, scf_group_framework) != 0) {
10575                 if (g_verbose) {
10576                         if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10577                                 scfdie();
10578 
10579                         warn(gettext("Property group %s is not of type "
10580                             "framework; the instance will be marked "
10581                             "disabled.\n"), exp_str);
10582                 }
10583 
10584                 safe_setprop(n, enabled_attr, false);
10585         }
10586 
10587         /* property groups */
10588         if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10589                 scfdie();
10590 
10591         (void) memset(&elts, 0, sizeof (elts));
10592         (void) memset(&template_elts, 0, sizeof (template_elts));
10593 
10594         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10595                 uint32_t pgflags;
10596 
10597                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10598                         scfdie();
10599 
10600                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10601                         continue;
10602 
10603                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10604                         scfdie();
10605 
10606                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10607                         export_dependency(exp_pg, &elts);
10608                         continue;
10609                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10610                         export_method(exp_pg, &elts);
10611                         continue;
10612                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10613                         if (scf_pg_get_name(exp_pg, exp_str,
10614                             max_scf_name_len + 1) < 0)
10615                                 scfdie();
10616 
10617                         if (strcmp(exp_str, scf_pg_general) == 0) {
10618                                 export_inst_general(exp_pg, n, &elts);
10619                                 continue;
10620                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10621                             0) {
10622                                 export_method_context(exp_pg, &elts);
10623                                 continue;
10624                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10625                                 export_dependents(exp_pg, &elts);
10626                                 continue;
10627                         }
10628                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10629                         export_template(exp_pg, &elts, &template_elts);
10630                         continue;
10631                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10632                         export_notify_params(exp_pg, &elts);
10633                         continue;
10634                 }
10635 
10636                 /* Ordinary pg. */
10637                 export_pg(exp_pg, &elts, flags);
10638         }
10639         if (ret == -1)
10640                 scfdie();
10641 
10642         if (template_elts.common_name != NULL) {
10643                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10644                 (void) xmlAddChild(elts.template, template_elts.common_name);
10645                 (void) xmlAddChild(elts.template, template_elts.description);
10646                 (void) xmlAddChild(elts.template, template_elts.documentation);
10647         } else {
10648                 xmlFreeNode(template_elts.description);
10649                 xmlFreeNode(template_elts.documentation);
10650         }
10651 
10652         if (isdefault && elts.restarter == NULL &&
10653             elts.dependencies == NULL && elts.method_context == NULL &&
10654             elts.exec_methods == NULL && elts.notify_params == NULL &&
10655             elts.property_groups == NULL && elts.template == NULL) {
10656                 xmlChar *eval;
10657 
10658                 /* This is a default instance */
10659                 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10660 
10661                 xmlFreeNode(n);
10662 
10663                 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10664                 if (n == NULL)
10665                         uu_die(emsg_create_xml);
10666 
10667                 safe_setprop(n, enabled_attr, (char *)eval);
10668                 xmlFree(eval);
10669 
10670                 selts->create_default_instance = n;
10671         } else {
10672                 /* Assemble the children in order. */
10673                 (void) xmlAddChild(n, elts.restarter);
10674                 (void) xmlAddChildList(n, elts.dependencies);
10675                 (void) xmlAddChildList(n, elts.dependents);
10676                 (void) xmlAddChild(n, elts.method_context);
10677                 (void) xmlAddChildList(n, elts.exec_methods);
10678                 (void) xmlAddChildList(n, elts.notify_params);
10679                 (void) xmlAddChildList(n, elts.property_groups);
10680                 (void) xmlAddChild(n, elts.template);
10681 
10682                 if (selts->instances == NULL)
10683                         selts->instances = n;
10684                 else
10685                         (void) xmlAddSibling(selts->instances, n);
10686         }
10687 }
10688 
10689 /*
10690  * Return a service element for the given service.
10691  */
10692 static xmlNodePtr
10693 export_service(scf_service_t *svc, int flags)
10694 {
10695         xmlNodePtr snode;
10696         struct entity_elts elts;
10697         struct template_elts template_elts;
10698         int ret;
10699 
10700         snode = xmlNewNode(NULL, (xmlChar *)"service");
10701         if (snode == NULL)
10702                 uu_die(emsg_create_xml);
10703 
10704         /* Get & set name attribute */
10705         if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10706                 scfdie();
10707         safe_setprop(snode, name_attr, exp_str);
10708 
10709         safe_setprop(snode, type_attr, "service");
10710         safe_setprop(snode, "version", "0");
10711 
10712         /* Acquire child elements. */
10713         if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10714                 scfdie();
10715 
10716         (void) memset(&elts, 0, sizeof (elts));
10717         (void) memset(&template_elts, 0, sizeof (template_elts));
10718 
10719         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10720                 uint32_t pgflags;
10721 
10722                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10723                         scfdie();
10724 
10725                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10726                         continue;
10727 
10728                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10729                         scfdie();
10730 
10731                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10732                         export_dependency(exp_pg, &elts);
10733                         continue;
10734                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10735                         export_method(exp_pg, &elts);
10736                         continue;
10737                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10738                         if (scf_pg_get_name(exp_pg, exp_str,
10739                             max_scf_name_len + 1) < 0)
10740                                 scfdie();
10741 
10742                         if (strcmp(exp_str, scf_pg_general) == 0) {
10743                                 export_svc_general(exp_pg, &elts);
10744                                 continue;
10745                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10746                             0) {
10747                                 export_method_context(exp_pg, &elts);
10748                                 continue;
10749                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10750                                 export_dependents(exp_pg, &elts);
10751                                 continue;
10752                         } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10753                                 continue;
10754                         }
10755                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10756                         export_template(exp_pg, &elts, &template_elts);
10757                         continue;
10758                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10759                         export_notify_params(exp_pg, &elts);
10760                         continue;
10761                 }
10762 
10763                 export_pg(exp_pg, &elts, flags);
10764         }
10765         if (ret == -1)
10766                 scfdie();
10767 
10768         if (template_elts.common_name != NULL) {
10769                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10770                 (void) xmlAddChild(elts.template, template_elts.common_name);
10771                 (void) xmlAddChild(elts.template, template_elts.description);
10772                 (void) xmlAddChild(elts.template, template_elts.documentation);
10773         } else {
10774                 xmlFreeNode(template_elts.description);
10775                 xmlFreeNode(template_elts.documentation);
10776         }
10777 
10778         /* Iterate instances */
10779         if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10780                 scfdie();
10781 
10782         while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10783                 export_instance(exp_inst, &elts, flags);
10784         if (ret == -1)
10785                 scfdie();
10786 
10787         /* Now add all of the accumulated elements in order. */
10788         (void) xmlAddChild(snode, elts.create_default_instance);
10789         (void) xmlAddChild(snode, elts.single_instance);
10790         (void) xmlAddChild(snode, elts.restarter);
10791         (void) xmlAddChildList(snode, elts.dependencies);
10792         (void) xmlAddChildList(snode, elts.dependents);
10793         (void) xmlAddChild(snode, elts.method_context);
10794         (void) xmlAddChildList(snode, elts.exec_methods);
10795         (void) xmlAddChildList(snode, elts.notify_params);
10796         (void) xmlAddChildList(snode, elts.property_groups);
10797         (void) xmlAddChildList(snode, elts.instances);
10798         (void) xmlAddChild(snode, elts.stability);
10799         (void) xmlAddChild(snode, elts.template);
10800 
10801         return (snode);
10802 }
10803 
10804 static int
10805 export_callback(void *data, scf_walkinfo_t *wip)
10806 {
10807         FILE *f;
10808         xmlDocPtr doc;
10809         xmlNodePtr sb;
10810         int result;
10811         struct export_args *argsp = (struct export_args *)data;
10812 
10813         if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10814             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10815             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10816             (exp_val = scf_value_create(g_hndl)) == NULL ||
10817             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10818             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10819             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10820             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10821                 scfdie();
10822 
10823         exp_str_sz = max_scf_len + 1;
10824         exp_str = safe_malloc(exp_str_sz);
10825 
10826         if (argsp->filename != NULL) {
10827                 errno = 0;
10828                 f = fopen(argsp->filename, "wb");
10829                 if (f == NULL) {
10830                         if (errno == 0)
10831                                 uu_die(gettext("Could not open \"%s\": no free "
10832                                     "stdio streams.\n"), argsp->filename);
10833                         else
10834                                 uu_die(gettext("Could not open \"%s\""),
10835                                     argsp->filename);
10836                 }
10837         } else
10838                 f = stdout;
10839 
10840         doc = xmlNewDoc((xmlChar *)"1.0");
10841         if (doc == NULL)
10842                 uu_die(gettext("Could not create XML document.\n"));
10843 
10844         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10845             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10846                 uu_die(emsg_create_xml);
10847 
10848         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10849         if (sb == NULL)
10850                 uu_die(emsg_create_xml);
10851         safe_setprop(sb, type_attr, "manifest");
10852         safe_setprop(sb, name_attr, "export");
10853         (void) xmlAddSibling(doc->children, sb);
10854 
10855         (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10856 
10857         result = write_service_bundle(doc, f);
10858 
10859         free(exp_str);
10860         scf_iter_destroy(exp_val_iter);
10861         scf_iter_destroy(exp_prop_iter);
10862         scf_iter_destroy(exp_pg_iter);
10863         scf_iter_destroy(exp_inst_iter);
10864         scf_value_destroy(exp_val);
10865         scf_property_destroy(exp_prop);
10866         scf_pg_destroy(exp_pg);
10867         scf_instance_destroy(exp_inst);
10868 
10869         xmlFreeDoc(doc);
10870 
10871         if (f != stdout)
10872                 (void) fclose(f);
10873 
10874         return (result);
10875 }
10876 
10877 /*
10878  * Get the service named by fmri, build an XML tree which represents it, and
10879  * dump it into filename (or stdout if filename is NULL).
10880  */
10881 int
10882 lscf_service_export(char *fmri, const char *filename, int flags)
10883 {
10884         struct export_args args;
10885         char *fmridup;
10886         const char *scope, *svc, *inst;
10887         size_t cblen = 3 * max_scf_name_len;
10888         char *canonbuf = alloca(cblen);
10889         int ret, err;
10890 
10891         lscf_prep_hndl();
10892 
10893         bzero(&args, sizeof (args));
10894         args.filename = filename;
10895         args.flags = flags;
10896 
10897         /*
10898          * If some poor user has passed an exact instance FMRI, of the sort
10899          * one might cut and paste from svcs(1) or an error message, warn
10900          * and chop off the instance instead of failing.
10901          */
10902         fmridup = alloca(strlen(fmri) + 1);
10903         (void) strcpy(fmridup, fmri);
10904         if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10905             sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10906             scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10907             inst != NULL) {
10908                 (void) strlcpy(canonbuf, "svc:/", cblen);
10909                 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10910                         (void) strlcat(canonbuf, "/", cblen);
10911                         (void) strlcat(canonbuf, scope, cblen);
10912                 }
10913                 (void) strlcat(canonbuf, svc, cblen);
10914                 fmri = canonbuf;
10915 
10916                 warn(gettext("Only services may be exported; ignoring "
10917                     "instance portion of argument.\n"));
10918         }
10919 
10920         err = 0;
10921         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10922             SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10923             &args, &err, semerr)) != 0) {
10924                 if (ret != -1)
10925                         semerr(gettext("Failed to walk instances: %s\n"),
10926                             scf_strerror(ret));
10927                 return (-1);
10928         }
10929 
10930         /*
10931          * Error message has already been printed.
10932          */
10933         if (err != 0)
10934                 return (-1);
10935 
10936         return (0);
10937 }
10938 
10939 
10940 /*
10941  * Archive
10942  */
10943 
10944 static xmlNodePtr
10945 make_archive(int flags)
10946 {
10947         xmlNodePtr sb;
10948         scf_scope_t *scope;
10949         scf_service_t *svc;
10950         scf_iter_t *iter;
10951         int r;
10952 
10953         if ((scope = scf_scope_create(g_hndl)) == NULL ||
10954             (svc = scf_service_create(g_hndl)) == NULL ||
10955             (iter = scf_iter_create(g_hndl)) == NULL ||
10956             (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10957             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10958             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10959             (exp_val = scf_value_create(g_hndl)) == NULL ||
10960             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10961             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10962             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10963             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10964                 scfdie();
10965 
10966         exp_str_sz = max_scf_len + 1;
10967         exp_str = safe_malloc(exp_str_sz);
10968 
10969         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10970         if (sb == NULL)
10971                 uu_die(emsg_create_xml);
10972         safe_setprop(sb, type_attr, "archive");
10973         safe_setprop(sb, name_attr, "none");
10974 
10975         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10976                 scfdie();
10977         if (scf_iter_scope_services(iter, scope) != 0)
10978                 scfdie();
10979 
10980         for (;;) {
10981                 r = scf_iter_next_service(iter, svc);
10982                 if (r == 0)
10983                         break;
10984                 if (r != 1)
10985                         scfdie();
10986 
10987                 if (scf_service_get_name(svc, exp_str,
10988                     max_scf_name_len + 1) < 0)
10989                         scfdie();
10990 
10991                 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10992                         continue;
10993 
10994                 (void) xmlAddChild(sb, export_service(svc, flags));
10995         }
10996 
10997         free(exp_str);
10998 
10999         scf_iter_destroy(exp_val_iter);
11000         scf_iter_destroy(exp_prop_iter);
11001         scf_iter_destroy(exp_pg_iter);
11002         scf_iter_destroy(exp_inst_iter);
11003         scf_value_destroy(exp_val);
11004         scf_property_destroy(exp_prop);
11005         scf_pg_destroy(exp_pg);
11006         scf_instance_destroy(exp_inst);
11007         scf_iter_destroy(iter);
11008         scf_service_destroy(svc);
11009         scf_scope_destroy(scope);
11010 
11011         return (sb);
11012 }
11013 
11014 int
11015 lscf_archive(const char *filename, int flags)
11016 {
11017         FILE *f;
11018         xmlDocPtr doc;
11019         int result;
11020 
11021         lscf_prep_hndl();
11022 
11023         if (filename != NULL) {
11024                 errno = 0;
11025                 f = fopen(filename, "wb");
11026                 if (f == NULL) {
11027                         if (errno == 0)
11028                                 uu_die(gettext("Could not open \"%s\": no free "
11029                                     "stdio streams.\n"), filename);
11030                         else
11031                                 uu_die(gettext("Could not open \"%s\""),
11032                                     filename);
11033                 }
11034         } else
11035                 f = stdout;
11036 
11037         doc = xmlNewDoc((xmlChar *)"1.0");
11038         if (doc == NULL)
11039                 uu_die(gettext("Could not create XML document.\n"));
11040 
11041         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11042             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11043                 uu_die(emsg_create_xml);
11044 
11045         (void) xmlAddSibling(doc->children, make_archive(flags));
11046 
11047         result = write_service_bundle(doc, f);
11048 
11049         xmlFreeDoc(doc);
11050 
11051         if (f != stdout)
11052                 (void) fclose(f);
11053 
11054         return (result);
11055 }
11056 
11057 
11058 /*
11059  * "Extract" a profile.
11060  */
11061 int
11062 lscf_profile_extract(const char *filename)
11063 {
11064         FILE *f;
11065         xmlDocPtr doc;
11066         xmlNodePtr sb, snode, inode;
11067         scf_scope_t *scope;
11068         scf_service_t *svc;
11069         scf_instance_t *inst;
11070         scf_propertygroup_t *pg;
11071         scf_property_t *prop;
11072         scf_value_t *val;
11073         scf_iter_t *siter, *iiter;
11074         int r, s;
11075         char *namebuf;
11076         uint8_t b;
11077         int result;
11078 
11079         lscf_prep_hndl();
11080 
11081         if (filename != NULL) {
11082                 errno = 0;
11083                 f = fopen(filename, "wb");
11084                 if (f == NULL) {
11085                         if (errno == 0)
11086                                 uu_die(gettext("Could not open \"%s\": no "
11087                                     "free stdio streams.\n"), filename);
11088                         else
11089                                 uu_die(gettext("Could not open \"%s\""),
11090                                     filename);
11091                 }
11092         } else
11093                 f = stdout;
11094 
11095         doc = xmlNewDoc((xmlChar *)"1.0");
11096         if (doc == NULL)
11097                 uu_die(gettext("Could not create XML document.\n"));
11098 
11099         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11100             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11101                 uu_die(emsg_create_xml);
11102 
11103         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11104         if (sb == NULL)
11105                 uu_die(emsg_create_xml);
11106         safe_setprop(sb, type_attr, "profile");
11107         safe_setprop(sb, name_attr, "extract");
11108         (void) xmlAddSibling(doc->children, sb);
11109 
11110         if ((scope = scf_scope_create(g_hndl)) == NULL ||
11111             (svc = scf_service_create(g_hndl)) == NULL ||
11112             (inst = scf_instance_create(g_hndl)) == NULL ||
11113             (pg = scf_pg_create(g_hndl)) == NULL ||
11114             (prop = scf_property_create(g_hndl)) == NULL ||
11115             (val = scf_value_create(g_hndl)) == NULL ||
11116             (siter = scf_iter_create(g_hndl)) == NULL ||
11117             (iiter = scf_iter_create(g_hndl)) == NULL)
11118                 scfdie();
11119 
11120         if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11121                 scfdie();
11122 
11123         if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11124                 scfdie();
11125 
11126         namebuf = safe_malloc(max_scf_name_len + 1);
11127 
11128         while ((r = scf_iter_next_service(siter, svc)) == 1) {
11129                 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11130                         scfdie();
11131 
11132                 snode = xmlNewNode(NULL, (xmlChar *)"service");
11133                 if (snode == NULL)
11134                         uu_die(emsg_create_xml);
11135 
11136                 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11137                     0)
11138                         scfdie();
11139 
11140                 safe_setprop(snode, name_attr, namebuf);
11141 
11142                 safe_setprop(snode, type_attr, "service");
11143                 safe_setprop(snode, "version", "0");
11144 
11145                 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11146                         if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11147                             SCF_SUCCESS) {
11148                                 if (scf_error() != SCF_ERROR_NOT_FOUND)
11149                                         scfdie();
11150 
11151                                 if (g_verbose) {
11152                                         ssize_t len;
11153                                         char *fmri;
11154 
11155                                         len =
11156                                             scf_instance_to_fmri(inst, NULL, 0);
11157                                         if (len < 0)
11158                                                 scfdie();
11159 
11160                                         fmri = safe_malloc(len + 1);
11161 
11162                                         if (scf_instance_to_fmri(inst, fmri,
11163                                             len + 1) < 0)
11164                                                 scfdie();
11165 
11166                                         warn("Instance %s has no \"%s\" "
11167                                             "property group.\n", fmri,
11168                                             scf_pg_general);
11169 
11170                                         free(fmri);
11171                                 }
11172 
11173                                 continue;
11174                         }
11175 
11176                         if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11177                             prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11178                             prop_get_val(prop, val) != 0)
11179                                 continue;
11180 
11181                         inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11182                             NULL);
11183                         if (inode == NULL)
11184                                 uu_die(emsg_create_xml);
11185 
11186                         if (scf_instance_get_name(inst, namebuf,
11187                             max_scf_name_len + 1) < 0)
11188                                 scfdie();
11189 
11190                         safe_setprop(inode, name_attr, namebuf);
11191 
11192                         if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11193                                 scfdie();
11194 
11195                         safe_setprop(inode, enabled_attr, b ? true : false);
11196                 }
11197                 if (s < 0)
11198                         scfdie();
11199 
11200                 if (snode->children != NULL)
11201                         (void) xmlAddChild(sb, snode);
11202                 else
11203                         xmlFreeNode(snode);
11204         }
11205         if (r < 0)
11206                 scfdie();
11207 
11208         free(namebuf);
11209 
11210         result = write_service_bundle(doc, f);
11211 
11212         xmlFreeDoc(doc);
11213 
11214         if (f != stdout)
11215                 (void) fclose(f);
11216 
11217         return (result);
11218 }
11219 
11220 
11221 /*
11222  * Entity manipulation commands
11223  */
11224 
11225 /*
11226  * Entity selection.  If no entity is selected, then the current scope is in
11227  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11228  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11229  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11230  * cur_inst will be non-NULL.
11231  */
11232 
11233 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11234 static int
11235 select_inst(const char *name)
11236 {
11237         scf_instance_t *inst;
11238         scf_error_t err;
11239 
11240         assert(cur_svc != NULL);
11241 
11242         inst = scf_instance_create(g_hndl);
11243         if (inst == NULL)
11244                 scfdie();
11245 
11246         if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11247                 cur_inst = inst;
11248                 return (0);
11249         }
11250 
11251         err = scf_error();
11252         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11253                 scfdie();
11254 
11255         scf_instance_destroy(inst);
11256         return (1);
11257 }
11258 
11259 /* Returns as above. */
11260 static int
11261 select_svc(const char *name)
11262 {
11263         scf_service_t *svc;
11264         scf_error_t err;
11265 
11266         assert(cur_scope != NULL);
11267 
11268         svc = scf_service_create(g_hndl);
11269         if (svc == NULL)
11270                 scfdie();
11271 
11272         if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11273                 cur_svc = svc;
11274                 return (0);
11275         }
11276 
11277         err = scf_error();
11278         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11279                 scfdie();
11280 
11281         scf_service_destroy(svc);
11282         return (1);
11283 }
11284 
11285 /* ARGSUSED */
11286 static int
11287 select_callback(void *unused, scf_walkinfo_t *wip)
11288 {
11289         scf_instance_t *inst;
11290         scf_service_t *svc;
11291         scf_scope_t *scope;
11292 
11293         if (wip->inst != NULL) {
11294                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11295                     (svc = scf_service_create(g_hndl)) == NULL ||
11296                     (inst = scf_instance_create(g_hndl)) == NULL)
11297                         scfdie();
11298 
11299                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11300                     inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11301                         scfdie();
11302         } else {
11303                 assert(wip->svc != NULL);
11304 
11305                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11306                     (svc = scf_service_create(g_hndl)) == NULL)
11307                         scfdie();
11308 
11309                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11310                     NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11311                         scfdie();
11312 
11313                 inst = NULL;
11314         }
11315 
11316         /* Clear out the current selection */
11317         assert(cur_scope != NULL);
11318         scf_scope_destroy(cur_scope);
11319         scf_service_destroy(cur_svc);
11320         scf_instance_destroy(cur_inst);
11321 
11322         cur_scope = scope;
11323         cur_svc = svc;
11324         cur_inst = inst;
11325 
11326         return (0);
11327 }
11328 
11329 static int
11330 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11331 {
11332         char **fmri = fmri_p;
11333 
11334         *fmri = strdup(wip->fmri);
11335         if (*fmri == NULL)
11336                 uu_die(gettext("Out of memory.\n"));
11337 
11338         return (0);
11339 }
11340 
11341 /*
11342  * validate [fmri]
11343  * Perform the validation of an FMRI instance.
11344  */
11345 void
11346 lscf_validate_fmri(const char *fmri)
11347 {
11348         int ret = 0;
11349         size_t inst_sz;
11350         char *inst_fmri = NULL;
11351         scf_tmpl_errors_t *errs = NULL;
11352         char *snapbuf = NULL;
11353 
11354         lscf_prep_hndl();
11355 
11356         if (fmri == NULL) {
11357                 inst_sz = max_scf_fmri_len + 1;
11358                 inst_fmri = safe_malloc(inst_sz);
11359 
11360                 if (cur_snap != NULL) {
11361                         snapbuf = safe_malloc(max_scf_name_len + 1);
11362                         if (scf_snapshot_get_name(cur_snap, snapbuf,
11363                             max_scf_name_len + 1) < 0)
11364                                 scfdie();
11365                 }
11366                 if (cur_inst == NULL) {
11367                         semerr(gettext("No instance selected\n"));
11368                         goto cleanup;
11369                 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11370                     inst_sz) >= inst_sz) {
11371                         /* sanity check. Should never get here */
11372                         uu_die(gettext("Unexpected error! file %s, line %d\n"),
11373                             __FILE__, __LINE__);
11374                 }
11375         } else {
11376                 scf_error_t scf_err;
11377                 int err = 0;
11378 
11379                 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11380                     validate_callback, &inst_fmri, &err, semerr)) != 0) {
11381                         uu_warn("Failed to walk instances: %s\n",
11382                             scf_strerror(scf_err));
11383                         goto cleanup;
11384                 }
11385                 if (err != 0) {
11386                         /* error message displayed by scf_walk_fmri */
11387                         goto cleanup;
11388                 }
11389         }
11390 
11391         ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11392             SCF_TMPL_VALIDATE_FLAG_CURRENT);
11393         if (ret == -1) {
11394                 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11395                         warn(gettext("Template data for %s is invalid. "
11396                             "Consider reverting to a previous snapshot or "
11397                             "restoring original configuration.\n"), inst_fmri);
11398                 } else {
11399                         uu_warn("%s: %s\n",
11400                             gettext("Error validating the instance"),
11401                             scf_strerror(scf_error()));
11402                 }
11403         } else if (ret == 1 && errs != NULL) {
11404                 scf_tmpl_error_t *err = NULL;
11405                 char *msg;
11406                 size_t len = 256;       /* initial error buffer size */
11407                 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11408                     SCF_TMPL_STRERROR_HUMAN : 0;
11409 
11410                 msg = safe_malloc(len);
11411 
11412                 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11413                         int ret;
11414 
11415                         if ((ret = scf_tmpl_strerror(err, msg, len,
11416                             flag)) >= len) {
11417                                 len = ret + 1;
11418                                 msg = realloc(msg, len);
11419                                 if (msg == NULL)
11420                                         uu_die(gettext(
11421                                             "Out of memory.\n"));
11422                                 (void) scf_tmpl_strerror(err, msg, len,
11423                                     flag);
11424                         }
11425                         (void) fprintf(stderr, "%s\n", msg);
11426                 }
11427                 if (msg != NULL)
11428                         free(msg);
11429         }
11430         if (errs != NULL)
11431                 scf_tmpl_errors_destroy(errs);
11432 
11433 cleanup:
11434         free(inst_fmri);
11435         free(snapbuf);
11436 }
11437 
11438 static void
11439 lscf_validate_file(const char *filename)
11440 {
11441         tmpl_errors_t *errs;
11442 
11443         bundle_t *b = internal_bundle_new();
11444         if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11445                 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11446                         tmpl_errors_print(stderr, errs, "");
11447                         semerr(gettext("Validation failed.\n"));
11448                 }
11449                 tmpl_errors_destroy(errs);
11450         }
11451         (void) internal_bundle_free(b);
11452 }
11453 
11454 /*
11455  * validate [fmri|file]
11456  */
11457 void
11458 lscf_validate(const char *arg)
11459 {
11460         const char *str;
11461 
11462         if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11463             sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11464                 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11465                 lscf_validate_file(str);
11466         } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11467             sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11468                 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11469                 lscf_validate_fmri(str);
11470         } else if (access(arg, R_OK | F_OK) == 0) {
11471                 lscf_validate_file(arg);
11472         } else {
11473                 lscf_validate_fmri(arg);
11474         }
11475 }
11476 
11477 void
11478 lscf_select(const char *fmri)
11479 {
11480         int ret, err;
11481 
11482         lscf_prep_hndl();
11483 
11484         if (cur_snap != NULL) {
11485                 struct snaplevel *elt;
11486                 char *buf;
11487 
11488                 /* Error unless name is that of the next level. */
11489                 elt = uu_list_next(cur_levels, cur_elt);
11490                 if (elt == NULL) {
11491                         semerr(gettext("No children.\n"));
11492                         return;
11493                 }
11494 
11495                 buf = safe_malloc(max_scf_name_len + 1);
11496 
11497                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11498                     max_scf_name_len + 1) < 0)
11499                         scfdie();
11500 
11501                 if (strcmp(buf, fmri) != 0) {
11502                         semerr(gettext("No such child.\n"));
11503                         free(buf);
11504                         return;
11505                 }
11506 
11507                 free(buf);
11508 
11509                 cur_elt = elt;
11510                 cur_level = elt->sl;
11511                 return;
11512         }
11513 
11514         /*
11515          * Special case for 'svc:', which takes the user to the scope level.
11516          */
11517         if (strcmp(fmri, "svc:") == 0) {
11518                 scf_instance_destroy(cur_inst);
11519                 scf_service_destroy(cur_svc);
11520                 cur_inst = NULL;
11521                 cur_svc = NULL;
11522                 return;
11523         }
11524 
11525         /*
11526          * Special case for ':properties'.  This appears as part of 'list' but
11527          * can't be selected.  Give a more helpful error message in this case.
11528          */
11529         if (strcmp(fmri, ":properties") == 0) {
11530                 semerr(gettext(":properties is not an entity.  Try 'listprop' "
11531                     "to list properties.\n"));
11532                 return;
11533         }
11534 
11535         /*
11536          * First try the argument as relative to the current selection.
11537          */
11538         if (cur_inst != NULL) {
11539                 /* EMPTY */;
11540         } else if (cur_svc != NULL) {
11541                 if (select_inst(fmri) != 1)
11542                         return;
11543         } else {
11544                 if (select_svc(fmri) != 1)
11545                         return;
11546         }
11547 
11548         err = 0;
11549         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11550             select_callback, NULL, &err, semerr)) != 0) {
11551                 semerr(gettext("Failed to walk instances: %s\n"),
11552                     scf_strerror(ret));
11553         }
11554 }
11555 
11556 void
11557 lscf_unselect(void)
11558 {
11559         lscf_prep_hndl();
11560 
11561         if (cur_snap != NULL) {
11562                 struct snaplevel *elt;
11563 
11564                 elt = uu_list_prev(cur_levels, cur_elt);
11565                 if (elt == NULL) {
11566                         semerr(gettext("No parent levels.\n"));
11567                 } else {
11568                         cur_elt = elt;
11569                         cur_level = elt->sl;
11570                 }
11571         } else if (cur_inst != NULL) {
11572                 scf_instance_destroy(cur_inst);
11573                 cur_inst = NULL;
11574         } else if (cur_svc != NULL) {
11575                 scf_service_destroy(cur_svc);
11576                 cur_svc = NULL;
11577         } else {
11578                 semerr(gettext("Cannot unselect at scope level.\n"));
11579         }
11580 }
11581 
11582 /*
11583  * Return the FMRI of the current selection, for the prompt.
11584  */
11585 void
11586 lscf_get_selection_str(char *buf, size_t bufsz)
11587 {
11588         char *cp;
11589         ssize_t fmrilen, szret;
11590         boolean_t deleted = B_FALSE;
11591 
11592         if (g_hndl == NULL) {
11593                 (void) strlcpy(buf, "svc:", bufsz);
11594                 return;
11595         }
11596 
11597         if (cur_level != NULL) {
11598                 assert(cur_snap != NULL);
11599 
11600                 /* [ snapshot ] FMRI [: instance ] */
11601                 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11602                     + 2 + max_scf_name_len + 1 + 1);
11603 
11604                 buf[0] = '[';
11605 
11606                 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11607                     max_scf_name_len + 1);
11608                 if (szret < 0) {
11609                         if (scf_error() != SCF_ERROR_DELETED)
11610                                 scfdie();
11611 
11612                         goto snap_deleted;
11613                 }
11614 
11615                 (void) strcat(buf, "]svc:/");
11616 
11617                 cp = strchr(buf, '\0');
11618 
11619                 szret = scf_snaplevel_get_service_name(cur_level, cp,
11620                     max_scf_name_len + 1);
11621                 if (szret < 0) {
11622                         if (scf_error() != SCF_ERROR_DELETED)
11623                                 scfdie();
11624 
11625                         goto snap_deleted;
11626                 }
11627 
11628                 cp = strchr(cp, '\0');
11629 
11630                 if (snaplevel_is_instance(cur_level)) {
11631                         *cp++ = ':';
11632 
11633                         if (scf_snaplevel_get_instance_name(cur_level, cp,
11634                             max_scf_name_len + 1) < 0) {
11635                                 if (scf_error() != SCF_ERROR_DELETED)
11636                                         scfdie();
11637 
11638                                 goto snap_deleted;
11639                         }
11640                 } else {
11641                         *cp++ = '[';
11642                         *cp++ = ':';
11643 
11644                         if (scf_instance_get_name(cur_inst, cp,
11645                             max_scf_name_len + 1) < 0) {
11646                                 if (scf_error() != SCF_ERROR_DELETED)
11647                                         scfdie();
11648 
11649                                 goto snap_deleted;
11650                         }
11651 
11652                         (void) strcat(buf, "]");
11653                 }
11654 
11655                 return;
11656 
11657 snap_deleted:
11658                 deleted = B_TRUE;
11659                 free(buf);
11660                 unselect_cursnap();
11661         }
11662 
11663         assert(cur_snap == NULL);
11664 
11665         if (cur_inst != NULL) {
11666                 assert(cur_svc != NULL);
11667                 assert(cur_scope != NULL);
11668 
11669                 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11670                 if (fmrilen >= 0) {
11671                         assert(fmrilen < bufsz);
11672                         if (deleted)
11673                                 warn(emsg_deleted);
11674                         return;
11675                 }
11676 
11677                 if (scf_error() != SCF_ERROR_DELETED)
11678                         scfdie();
11679 
11680                 deleted = B_TRUE;
11681 
11682                 scf_instance_destroy(cur_inst);
11683                 cur_inst = NULL;
11684         }
11685 
11686         if (cur_svc != NULL) {
11687                 assert(cur_scope != NULL);
11688 
11689                 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11690                 if (szret >= 0) {
11691                         assert(szret < bufsz);
11692                         if (deleted)
11693                                 warn(emsg_deleted);
11694                         return;
11695                 }
11696 
11697                 if (scf_error() != SCF_ERROR_DELETED)
11698                         scfdie();
11699 
11700                 deleted = B_TRUE;
11701                 scf_service_destroy(cur_svc);
11702                 cur_svc = NULL;
11703         }
11704 
11705         assert(cur_scope != NULL);
11706         fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11707 
11708         if (fmrilen < 0)
11709                 scfdie();
11710 
11711         assert(fmrilen < bufsz);
11712         if (deleted)
11713                 warn(emsg_deleted);
11714 }
11715 
11716 /*
11717  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11718  * :statistics) are listed for the current selection.
11719  */
11720 void
11721 lscf_list(const char *pattern)
11722 {
11723         scf_iter_t *iter;
11724         char *buf;
11725         int ret;
11726 
11727         lscf_prep_hndl();
11728 
11729         if (cur_level != NULL) {
11730                 struct snaplevel *elt;
11731 
11732                 (void) fputs(COLON_NAMESPACES, stdout);
11733 
11734                 elt = uu_list_next(cur_levels, cur_elt);
11735                 if (elt == NULL)
11736                         return;
11737 
11738                 /*
11739                  * For now, we know that the next level is an instance.  But
11740                  * if we ever have multiple scopes, this could be complicated.
11741                  */
11742                 buf = safe_malloc(max_scf_name_len + 1);
11743                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11744                     max_scf_name_len + 1) >= 0) {
11745                         (void) puts(buf);
11746                 } else {
11747                         if (scf_error() != SCF_ERROR_DELETED)
11748                                 scfdie();
11749                 }
11750 
11751                 free(buf);
11752 
11753                 return;
11754         }
11755 
11756         if (cur_inst != NULL) {
11757                 (void) fputs(COLON_NAMESPACES, stdout);
11758                 return;
11759         }
11760 
11761         iter = scf_iter_create(g_hndl);
11762         if (iter == NULL)
11763                 scfdie();
11764 
11765         buf = safe_malloc(max_scf_name_len + 1);
11766 
11767         if (cur_svc != NULL) {
11768                 /* List the instances in this service. */
11769                 scf_instance_t *inst;
11770 
11771                 inst = scf_instance_create(g_hndl);
11772                 if (inst == NULL)
11773                         scfdie();
11774 
11775                 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11776                         safe_printf(COLON_NAMESPACES);
11777 
11778                         for (;;) {
11779                                 ret = scf_iter_next_instance(iter, inst);
11780                                 if (ret == 0)
11781                                         break;
11782                                 if (ret != 1) {
11783                                         if (scf_error() != SCF_ERROR_DELETED)
11784                                                 scfdie();
11785 
11786                                         break;
11787                                 }
11788 
11789                                 if (scf_instance_get_name(inst, buf,
11790                                     max_scf_name_len + 1) >= 0) {
11791                                         if (pattern == NULL ||
11792                                             fnmatch(pattern, buf, 0) == 0)
11793                                                 (void) puts(buf);
11794                                 } else {
11795                                         if (scf_error() != SCF_ERROR_DELETED)
11796                                                 scfdie();
11797                                 }
11798                         }
11799                 } else {
11800                         if (scf_error() != SCF_ERROR_DELETED)
11801                                 scfdie();
11802                 }
11803 
11804                 scf_instance_destroy(inst);
11805         } else {
11806                 /* List the services in this scope. */
11807                 scf_service_t *svc;
11808 
11809                 assert(cur_scope != NULL);
11810 
11811                 svc = scf_service_create(g_hndl);
11812                 if (svc == NULL)
11813                         scfdie();
11814 
11815                 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11816                         scfdie();
11817 
11818                 for (;;) {
11819                         ret = scf_iter_next_service(iter, svc);
11820                         if (ret == 0)
11821                                 break;
11822                         if (ret != 1)
11823                                 scfdie();
11824 
11825                         if (scf_service_get_name(svc, buf,
11826                             max_scf_name_len + 1) >= 0) {
11827                                 if (pattern == NULL ||
11828                                     fnmatch(pattern, buf, 0) == 0)
11829                                         safe_printf("%s\n", buf);
11830                         } else {
11831                                 if (scf_error() != SCF_ERROR_DELETED)
11832                                         scfdie();
11833                         }
11834                 }
11835 
11836                 scf_service_destroy(svc);
11837         }
11838 
11839         free(buf);
11840         scf_iter_destroy(iter);
11841 }
11842 
11843 /*
11844  * Entity addition.  Creates an empty entity in the current selection.
11845  */
11846 void
11847 lscf_add(const char *name)
11848 {
11849         lscf_prep_hndl();
11850 
11851         if (cur_snap != NULL) {
11852                 semerr(emsg_cant_modify_snapshots);
11853         } else if (cur_inst != NULL) {
11854                 semerr(gettext("Cannot add entities to an instance.\n"));
11855         } else if (cur_svc != NULL) {
11856 
11857                 if (scf_service_add_instance(cur_svc, name, NULL) !=
11858                     SCF_SUCCESS) {
11859                         switch (scf_error()) {
11860                         case SCF_ERROR_INVALID_ARGUMENT:
11861                                 semerr(gettext("Invalid name.\n"));
11862                                 break;
11863 
11864                         case SCF_ERROR_EXISTS:
11865                                 semerr(gettext("Instance already exists.\n"));
11866                                 break;
11867 
11868                         case SCF_ERROR_PERMISSION_DENIED:
11869                                 semerr(emsg_permission_denied);
11870                                 break;
11871 
11872                         default:
11873                                 scfdie();
11874                         }
11875                 }
11876         } else {
11877                 assert(cur_scope != NULL);
11878 
11879                 if (scf_scope_add_service(cur_scope, name, NULL) !=
11880                     SCF_SUCCESS) {
11881                         switch (scf_error()) {
11882                         case SCF_ERROR_INVALID_ARGUMENT:
11883                                 semerr(gettext("Invalid name.\n"));
11884                                 break;
11885 
11886                         case SCF_ERROR_EXISTS:
11887                                 semerr(gettext("Service already exists.\n"));
11888                                 break;
11889 
11890                         case SCF_ERROR_PERMISSION_DENIED:
11891                                 semerr(emsg_permission_denied);
11892                                 break;
11893 
11894                         case SCF_ERROR_BACKEND_READONLY:
11895                                 semerr(emsg_read_only);
11896                                 break;
11897 
11898                         default:
11899                                 scfdie();
11900                         }
11901                 }
11902         }
11903 }
11904 
11905 /* return 1 if the entity has no persistent pgs, else return 0 */
11906 static int
11907 entity_has_no_pgs(void *ent, int isservice)
11908 {
11909         scf_iter_t *iter = NULL;
11910         scf_propertygroup_t *pg = NULL;
11911         uint32_t flags;
11912         int err;
11913         int ret = 1;
11914 
11915         if ((iter = scf_iter_create(g_hndl)) == NULL ||
11916             (pg = scf_pg_create(g_hndl)) == NULL)
11917                 scfdie();
11918 
11919         if (isservice) {
11920                 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11921                         scfdie();
11922         } else {
11923                 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11924                         scfdie();
11925         }
11926 
11927         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11928                 if (scf_pg_get_flags(pg, &flags) != 0)
11929                         scfdie();
11930 
11931                 /* skip nonpersistent pgs */
11932                 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11933                         continue;
11934 
11935                 ret = 0;
11936                 break;
11937         }
11938 
11939         if (err == -1)
11940                 scfdie();
11941 
11942         scf_pg_destroy(pg);
11943         scf_iter_destroy(iter);
11944 
11945         return (ret);
11946 }
11947 
11948 /* return 1 if the service has no instances, else return 0 */
11949 static int
11950 svc_has_no_insts(scf_service_t *svc)
11951 {
11952         scf_instance_t *inst;
11953         scf_iter_t *iter;
11954         int r;
11955         int ret = 1;
11956 
11957         if ((inst = scf_instance_create(g_hndl)) == NULL ||
11958             (iter = scf_iter_create(g_hndl)) == NULL)
11959                 scfdie();
11960 
11961         if (scf_iter_service_instances(iter, svc) != 0)
11962                 scfdie();
11963 
11964         r = scf_iter_next_instance(iter, inst);
11965         if (r == 1) {
11966                 ret = 0;
11967         } else if (r == 0) {
11968                 ret = 1;
11969         } else if (r == -1) {
11970                 scfdie();
11971         } else {
11972                 bad_error("scf_iter_next_instance", r);
11973         }
11974 
11975         scf_iter_destroy(iter);
11976         scf_instance_destroy(inst);
11977 
11978         return (ret);
11979 }
11980 
11981 /*
11982  * Entity deletion.
11983  */
11984 
11985 /*
11986  * Delete the property group <fmri>/:properties/<name>.  Returns
11987  * SCF_ERROR_NONE on success (or if the entity is not found),
11988  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11989  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11990  * denied.
11991  */
11992 static scf_error_t
11993 delete_dependency_pg(const char *fmri, const char *name)
11994 {
11995         void *entity = NULL;
11996         int isservice;
11997         scf_propertygroup_t *pg = NULL;
11998         scf_error_t result;
11999         char *pgty;
12000         scf_service_t *svc = NULL;
12001         scf_instance_t *inst = NULL;
12002         scf_iter_t *iter = NULL;
12003         char *name_buf = NULL;
12004 
12005         result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12006         switch (result) {
12007         case SCF_ERROR_NONE:
12008                 break;
12009 
12010         case SCF_ERROR_NO_MEMORY:
12011                 uu_die(gettext("Out of memory.\n"));
12012                 /* NOTREACHED */
12013 
12014         case SCF_ERROR_INVALID_ARGUMENT:
12015         case SCF_ERROR_CONSTRAINT_VIOLATED:
12016                 return (SCF_ERROR_INVALID_ARGUMENT);
12017 
12018         case SCF_ERROR_NOT_FOUND:
12019                 result = SCF_ERROR_NONE;
12020                 goto out;
12021 
12022         default:
12023                 bad_error("fmri_to_entity", result);
12024         }
12025 
12026         pg = scf_pg_create(g_hndl);
12027         if (pg == NULL)
12028                 scfdie();
12029 
12030         if (entity_get_pg(entity, isservice, name, pg) != 0) {
12031                 if (scf_error() != SCF_ERROR_NOT_FOUND)
12032                         scfdie();
12033 
12034                 result = SCF_ERROR_NONE;
12035                 goto out;
12036         }
12037 
12038         pgty = safe_malloc(max_scf_pg_type_len + 1);
12039 
12040         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12041                 scfdie();
12042 
12043         if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12044                 result = SCF_ERROR_TYPE_MISMATCH;
12045                 free(pgty);
12046                 goto out;
12047         }
12048 
12049         free(pgty);
12050 
12051         if (scf_pg_delete(pg) != 0) {
12052                 result = scf_error();
12053                 if (result != SCF_ERROR_PERMISSION_DENIED)
12054                         scfdie();
12055                 goto out;
12056         }
12057 
12058         /*
12059          * We have to handle the case where we've just deleted the last
12060          * property group of a "dummy" entity (instance or service).
12061          * A "dummy" entity is an entity only present to hold an
12062          * external dependency.
12063          * So, in the case we deleted the last property group then we
12064          * can also delete the entity. If the entity is an instance then
12065          * we must verify if this was the last instance for the service
12066          * and if it is, we can also delete the service if it doesn't
12067          * have any property group either.
12068          */
12069 
12070         result = SCF_ERROR_NONE;
12071 
12072         if (isservice) {
12073                 svc = (scf_service_t *)entity;
12074 
12075                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12076                     (iter = scf_iter_create(g_hndl)) == NULL)
12077                         scfdie();
12078 
12079                 name_buf = safe_malloc(max_scf_name_len + 1);
12080         } else {
12081                 inst = (scf_instance_t *)entity;
12082         }
12083 
12084         /*
12085          * If the entity is an instance and we've just deleted its last
12086          * property group then we should delete it.
12087          */
12088         if (!isservice && entity_has_no_pgs(entity, isservice)) {
12089                 /* find the service before deleting the inst. - needed later */
12090                 if ((svc = scf_service_create(g_hndl)) == NULL)
12091                         scfdie();
12092 
12093                 if (scf_instance_get_parent(inst, svc) != 0)
12094                         scfdie();
12095 
12096                 /* delete the instance */
12097                 if (scf_instance_delete(inst) != 0) {
12098                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12099                                 scfdie();
12100 
12101                         result = SCF_ERROR_PERMISSION_DENIED;
12102                         goto out;
12103                 }
12104                 /* no need to refresh the instance */
12105                 inst = NULL;
12106         }
12107 
12108         /*
12109          * If the service has no more instances and pgs or we just deleted the
12110          * last instance and the service doesn't have anymore propery groups
12111          * then the service should be deleted.
12112          */
12113         if (svc != NULL &&
12114             svc_has_no_insts(svc) &&
12115             entity_has_no_pgs((void *)svc, 1)) {
12116                 if (scf_service_delete(svc) == 0) {
12117                         if (isservice) {
12118                                 /* no need to refresh the service */
12119                                 svc = NULL;
12120                         }
12121 
12122                         goto out;
12123                 }
12124 
12125                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12126                         scfdie();
12127 
12128                 result = SCF_ERROR_PERMISSION_DENIED;
12129         }
12130 
12131         /* if the entity has not been deleted, refresh it */
12132         if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12133                 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12134                     name_buf);
12135         }
12136 
12137 out:
12138         if (isservice && (inst != NULL && iter != NULL)) {
12139                 free(name_buf);
12140                 scf_iter_destroy(iter);
12141                 scf_instance_destroy(inst);
12142         }
12143 
12144         if (!isservice && svc != NULL) {
12145                 scf_service_destroy(svc);
12146         }
12147 
12148         scf_pg_destroy(pg);
12149         if (entity != NULL)
12150                 entity_destroy(entity, isservice);
12151 
12152         return (result);
12153 }
12154 
12155 static int
12156 delete_dependents(scf_propertygroup_t *pg)
12157 {
12158         char *pgty, *name, *fmri;
12159         scf_property_t *prop;
12160         scf_value_t *val;
12161         scf_iter_t *iter;
12162         int r;
12163         scf_error_t err;
12164 
12165         /* Verify that the pg has the correct type. */
12166         pgty = safe_malloc(max_scf_pg_type_len + 1);
12167         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12168                 scfdie();
12169 
12170         if (strcmp(pgty, scf_group_framework) != 0) {
12171                 if (g_verbose) {
12172                         fmri = safe_malloc(max_scf_fmri_len + 1);
12173                         if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12174                                 scfdie();
12175 
12176                         warn(gettext("Property group %s is not of expected "
12177                             "type %s.\n"), fmri, scf_group_framework);
12178 
12179                         free(fmri);
12180                 }
12181 
12182                 free(pgty);
12183                 return (-1);
12184         }
12185 
12186         free(pgty);
12187 
12188         /* map delete_dependency_pg onto the properties. */
12189         if ((prop = scf_property_create(g_hndl)) == NULL ||
12190             (val = scf_value_create(g_hndl)) == NULL ||
12191             (iter = scf_iter_create(g_hndl)) == NULL)
12192                 scfdie();
12193 
12194         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12195                 scfdie();
12196 
12197         name = safe_malloc(max_scf_name_len + 1);
12198         fmri = safe_malloc(max_scf_fmri_len + 2);
12199 
12200         while ((r = scf_iter_next_property(iter, prop)) == 1) {
12201                 scf_type_t ty;
12202 
12203                 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12204                         scfdie();
12205 
12206                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12207                         scfdie();
12208 
12209                 if ((ty != SCF_TYPE_ASTRING &&
12210                     prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12211                     prop_get_val(prop, val) != 0)
12212                         continue;
12213 
12214                 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12215                         scfdie();
12216 
12217                 err = delete_dependency_pg(fmri, name);
12218                 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12219                         if (scf_property_to_fmri(prop, fmri,
12220                             max_scf_fmri_len + 2) < 0)
12221                                 scfdie();
12222 
12223                         warn(gettext("Value of %s is not a valid FMRI.\n"),
12224                             fmri);
12225                 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12226                         warn(gettext("Property group \"%s\" of entity \"%s\" "
12227                             "does not have dependency type.\n"), name, fmri);
12228                 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12229                         warn(gettext("Could not delete property group \"%s\" "
12230                             "of entity \"%s\" (permission denied).\n"), name,
12231                             fmri);
12232                 }
12233         }
12234         if (r == -1)
12235                 scfdie();
12236 
12237         scf_value_destroy(val);
12238         scf_property_destroy(prop);
12239 
12240         return (0);
12241 }
12242 
12243 /*
12244  * Returns 1 if the instance may be running, and 0 otherwise.
12245  */
12246 static int
12247 inst_is_running(scf_instance_t *inst)
12248 {
12249         scf_propertygroup_t *pg;
12250         scf_property_t *prop;
12251         scf_value_t *val;
12252         char buf[MAX_SCF_STATE_STRING_SZ];
12253         int ret = 0;
12254         ssize_t szret;
12255 
12256         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12257             (prop = scf_property_create(g_hndl)) == NULL ||
12258             (val = scf_value_create(g_hndl)) == NULL)
12259                 scfdie();
12260 
12261         if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12262                 if (scf_error() != SCF_ERROR_NOT_FOUND)
12263                         scfdie();
12264                 goto out;
12265         }
12266 
12267         if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12268             prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12269             prop_get_val(prop, val) != 0)
12270                 goto out;
12271 
12272         szret = scf_value_get_astring(val, buf, sizeof (buf));
12273         assert(szret >= 0);
12274 
12275         ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12276             strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12277 
12278 out:
12279         scf_value_destroy(val);
12280         scf_property_destroy(prop);
12281         scf_pg_destroy(pg);
12282         return (ret);
12283 }
12284 
12285 static uint8_t
12286 pg_is_external_dependency(scf_propertygroup_t *pg)
12287 {
12288         char *type;
12289         scf_value_t *val;
12290         scf_property_t *prop;
12291         uint8_t b = B_FALSE;
12292 
12293         type = safe_malloc(max_scf_pg_type_len + 1);
12294 
12295         if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12296                 scfdie();
12297 
12298         if ((prop = scf_property_create(g_hndl)) == NULL ||
12299             (val = scf_value_create(g_hndl)) == NULL)
12300                 scfdie();
12301 
12302         if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12303                 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12304                         if (scf_property_get_value(prop, val) != 0)
12305                                 scfdie();
12306                         if (scf_value_get_boolean(val, &b) != 0)
12307                                 scfdie();
12308                 }
12309         }
12310 
12311         free(type);
12312         (void) scf_value_destroy(val);
12313         (void) scf_property_destroy(prop);
12314 
12315         return (b);
12316 }
12317 
12318 #define DELETE_FAILURE                  -1
12319 #define DELETE_SUCCESS_NOEXTDEPS        0
12320 #define DELETE_SUCCESS_EXTDEPS          1
12321 
12322 /*
12323  * lscf_instance_delete() deletes an instance.  Before calling
12324  * scf_instance_delete(), though, we make sure the instance isn't
12325  * running and delete dependencies in other entities which the instance
12326  * declared as "dependents".  If there are dependencies which were
12327  * created for other entities, then instead of deleting the instance we
12328  * make it "empty" by deleting all other property groups and all
12329  * snapshots.
12330  *
12331  * lscf_instance_delete() verifies that there is no external dependency pgs
12332  * before suppressing the instance. If there is, then we must not remove them
12333  * now in case the instance is re-created otherwise the dependencies would be
12334  * lost. The external dependency pgs will be removed if the dependencies are
12335  * removed.
12336  *
12337  * Returns:
12338  *  DELETE_FAILURE              on failure
12339  *  DELETE_SUCCESS_NOEXTDEPS    on success - no external dependencies
12340  *  DELETE_SUCCESS_EXTDEPS      on success - external dependencies
12341  */
12342 static int
12343 lscf_instance_delete(scf_instance_t *inst, int force)
12344 {
12345         scf_propertygroup_t *pg;
12346         scf_snapshot_t *snap;
12347         scf_iter_t *iter;
12348         int err;
12349         int external = 0;
12350 
12351         /* If we're not forcing and the instance is running, refuse. */
12352         if (!force && inst_is_running(inst)) {
12353                 char *fmri;
12354 
12355                 fmri = safe_malloc(max_scf_fmri_len + 1);
12356 
12357                 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12358                         scfdie();
12359 
12360                 semerr(gettext("Instance %s may be running.  "
12361                     "Use delete -f if it is not.\n"), fmri);
12362 
12363                 free(fmri);
12364                 return (DELETE_FAILURE);
12365         }
12366 
12367         pg = scf_pg_create(g_hndl);
12368         if (pg == NULL)
12369                 scfdie();
12370 
12371         if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12372                 (void) delete_dependents(pg);
12373         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12374                 scfdie();
12375 
12376         scf_pg_destroy(pg);
12377 
12378         /*
12379          * If the instance has some external dependencies then we must
12380          * keep them in case the instance is reimported otherwise the
12381          * dependencies would be lost on reimport.
12382          */
12383         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12384             (pg = scf_pg_create(g_hndl)) == NULL)
12385                 scfdie();
12386 
12387         if (scf_iter_instance_pgs(iter, inst) < 0)
12388                 scfdie();
12389 
12390         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12391                 if (pg_is_external_dependency(pg)) {
12392                         external = 1;
12393                         continue;
12394                 }
12395 
12396                 if (scf_pg_delete(pg) != 0) {
12397                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12398                                 scfdie();
12399                         else {
12400                                 semerr(emsg_permission_denied);
12401 
12402                                 (void) scf_iter_destroy(iter);
12403                                 (void) scf_pg_destroy(pg);
12404                                 return (DELETE_FAILURE);
12405                         }
12406                 }
12407         }
12408 
12409         if (err == -1)
12410                 scfdie();
12411 
12412         (void) scf_iter_destroy(iter);
12413         (void) scf_pg_destroy(pg);
12414 
12415         if (external) {
12416                 /*
12417                  * All the pgs have been deleted for the instance except
12418                  * the ones holding the external dependencies.
12419                  * For the job to be complete, we must also delete the
12420                  * snapshots associated with the instance.
12421                  */
12422                 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12423                     NULL)
12424                         scfdie();
12425                 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12426                         scfdie();
12427 
12428                 if (scf_iter_instance_snapshots(iter, inst) == -1)
12429                         scfdie();
12430 
12431                 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12432                         if (_scf_snapshot_delete(snap) != 0) {
12433                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12434                                         scfdie();
12435 
12436                                 semerr(emsg_permission_denied);
12437 
12438                                 (void) scf_iter_destroy(iter);
12439                                 (void) scf_snapshot_destroy(snap);
12440                                 return (DELETE_FAILURE);
12441                         }
12442                 }
12443 
12444                 if (err == -1)
12445                         scfdie();
12446 
12447                 (void) scf_iter_destroy(iter);
12448                 (void) scf_snapshot_destroy(snap);
12449                 return (DELETE_SUCCESS_EXTDEPS);
12450         }
12451 
12452         if (scf_instance_delete(inst) != 0) {
12453                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12454                         scfdie();
12455 
12456                 semerr(emsg_permission_denied);
12457 
12458                 return (DELETE_FAILURE);
12459         }
12460 
12461         return (DELETE_SUCCESS_NOEXTDEPS);
12462 }
12463 
12464 /*
12465  * lscf_service_delete() deletes a service.  Before calling
12466  * scf_service_delete(), though, we call lscf_instance_delete() for
12467  * each of the instances and delete dependencies in other entities
12468  * which were created as "dependents" of this service.  If there are
12469  * dependencies which were created for other entities, then we delete
12470  * all other property groups in the service and leave it as "empty".
12471  *
12472  * lscf_service_delete() verifies that there is no external dependency
12473  * pgs at the instance & service level before suppressing the service.
12474  * If there is, then we must not remove them now in case the service
12475  * is re-imported otherwise the dependencies would be lost. The external
12476  * dependency pgs will be removed if the dependencies are removed.
12477  *
12478  * Returns:
12479  *   DELETE_FAILURE             on failure
12480  *   DELETE_SUCCESS_NOEXTDEPS   on success - no external dependencies
12481  *   DELETE_SUCCESS_EXTDEPS     on success - external dependencies
12482  */
12483 static int
12484 lscf_service_delete(scf_service_t *svc, int force)
12485 {
12486         int r;
12487         scf_instance_t *inst;
12488         scf_propertygroup_t *pg;
12489         scf_iter_t *iter;
12490         int ret;
12491         int external = 0;
12492 
12493         if ((inst = scf_instance_create(g_hndl)) == NULL ||
12494             (pg = scf_pg_create(g_hndl)) == NULL ||
12495             (iter = scf_iter_create(g_hndl)) == NULL)
12496                 scfdie();
12497 
12498         if (scf_iter_service_instances(iter, svc) != 0)
12499                 scfdie();
12500 
12501         for (r = scf_iter_next_instance(iter, inst);
12502             r == 1;
12503             r = scf_iter_next_instance(iter, inst)) {
12504 
12505                 ret = lscf_instance_delete(inst, force);
12506                 if (ret == DELETE_FAILURE) {
12507                         scf_iter_destroy(iter);
12508                         scf_pg_destroy(pg);
12509                         scf_instance_destroy(inst);
12510                         return (DELETE_FAILURE);
12511                 }
12512 
12513                 /*
12514                  * Record the fact that there is some external dependencies
12515                  * at the instance level.
12516                  */
12517                 if (ret == DELETE_SUCCESS_EXTDEPS)
12518                         external |= 1;
12519         }
12520 
12521         if (r != 0)
12522                 scfdie();
12523 
12524         /* Delete dependency property groups in dependent services. */
12525         if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12526                 (void) delete_dependents(pg);
12527         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12528                 scfdie();
12529 
12530         scf_iter_destroy(iter);
12531         scf_pg_destroy(pg);
12532         scf_instance_destroy(inst);
12533 
12534         /*
12535          * If the service has some external dependencies then we don't
12536          * want to remove them in case the service is re-imported.
12537          */
12538         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12539             (iter = scf_iter_create(g_hndl)) == NULL)
12540                 scfdie();
12541 
12542         if (scf_iter_service_pgs(iter, svc) < 0)
12543                 scfdie();
12544 
12545         while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12546                 if (pg_is_external_dependency(pg)) {
12547                         external |= 2;
12548                         continue;
12549                 }
12550 
12551                 if (scf_pg_delete(pg) != 0) {
12552                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12553                                 scfdie();
12554                         else {
12555                                 semerr(emsg_permission_denied);
12556 
12557                                 (void) scf_iter_destroy(iter);
12558                                 (void) scf_pg_destroy(pg);
12559                                 return (DELETE_FAILURE);
12560                         }
12561                 }
12562         }
12563 
12564         if (r == -1)
12565                 scfdie();
12566 
12567         (void) scf_iter_destroy(iter);
12568         (void) scf_pg_destroy(pg);
12569 
12570         if (external != 0)
12571                 return (DELETE_SUCCESS_EXTDEPS);
12572 
12573         if (scf_service_delete(svc) == 0)
12574                 return (DELETE_SUCCESS_NOEXTDEPS);
12575 
12576         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12577                 scfdie();
12578 
12579         semerr(emsg_permission_denied);
12580         return (DELETE_FAILURE);
12581 }
12582 
12583 static int
12584 delete_callback(void *data, scf_walkinfo_t *wip)
12585 {
12586         int force = (int)data;
12587 
12588         if (wip->inst != NULL)
12589                 (void) lscf_instance_delete(wip->inst, force);
12590         else
12591                 (void) lscf_service_delete(wip->svc, force);
12592 
12593         return (0);
12594 }
12595 
12596 void
12597 lscf_delete(const char *fmri, int force)
12598 {
12599         scf_service_t *svc;
12600         scf_instance_t *inst;
12601         int ret;
12602 
12603         lscf_prep_hndl();
12604 
12605         if (cur_snap != NULL) {
12606                 if (!snaplevel_is_instance(cur_level)) {
12607                         char *buf;
12608 
12609                         buf = safe_malloc(max_scf_name_len + 1);
12610                         if (scf_instance_get_name(cur_inst, buf,
12611                             max_scf_name_len + 1) >= 0) {
12612                                 if (strcmp(buf, fmri) == 0) {
12613                                         semerr(emsg_cant_modify_snapshots);
12614                                         free(buf);
12615                                         return;
12616                                 }
12617                         } else if (scf_error() != SCF_ERROR_DELETED) {
12618                                 scfdie();
12619                         }
12620                         free(buf);
12621                 }
12622         } else if (cur_inst != NULL) {
12623                 /* EMPTY */;
12624         } else if (cur_svc != NULL) {
12625                 inst = scf_instance_create(g_hndl);
12626                 if (inst == NULL)
12627                         scfdie();
12628 
12629                 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12630                     SCF_SUCCESS) {
12631                         (void) lscf_instance_delete(inst, force);
12632                         scf_instance_destroy(inst);
12633                         return;
12634                 }
12635 
12636                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12637                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12638                         scfdie();
12639 
12640                 scf_instance_destroy(inst);
12641         } else {
12642                 assert(cur_scope != NULL);
12643 
12644                 svc = scf_service_create(g_hndl);
12645                 if (svc == NULL)
12646                         scfdie();
12647 
12648                 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12649                     SCF_SUCCESS) {
12650                         (void) lscf_service_delete(svc, force);
12651                         scf_service_destroy(svc);
12652                         return;
12653                 }
12654 
12655                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12656                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12657                         scfdie();
12658 
12659                 scf_service_destroy(svc);
12660         }
12661 
12662         /*
12663          * Match FMRI to entity.
12664          */
12665         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12666             delete_callback, (void *)force, NULL, semerr)) != 0) {
12667                 semerr(gettext("Failed to walk instances: %s\n"),
12668                     scf_strerror(ret));
12669         }
12670 }
12671 
12672 
12673 
12674 /*
12675  * :properties commands.  These all end with "pg" or "prop" and generally
12676  * operate on the currently selected entity.
12677  */
12678 
12679 /*
12680  * Property listing.  List the property groups, properties, their types and
12681  * their values for the currently selected entity.
12682  */
12683 static void
12684 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12685 {
12686         char *buf;
12687         uint32_t flags;
12688 
12689         buf = safe_malloc(max_scf_pg_type_len + 1);
12690 
12691         if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12692                 scfdie();
12693 
12694         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12695                 scfdie();
12696 
12697         safe_printf("%-*s  %s", namewidth, name, buf);
12698 
12699         if (flags & SCF_PG_FLAG_NONPERSISTENT)
12700                 safe_printf("\tNONPERSISTENT");
12701 
12702         safe_printf("\n");
12703 
12704         free(buf);
12705 }
12706 
12707 static boolean_t
12708 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12709 {
12710         if (scf_property_get_value(prop, val) == 0) {
12711                 return (B_FALSE);
12712         } else {
12713                 switch (scf_error()) {
12714                 case SCF_ERROR_NOT_FOUND:
12715                         return (B_FALSE);
12716                 case SCF_ERROR_PERMISSION_DENIED:
12717                 case SCF_ERROR_CONSTRAINT_VIOLATED:
12718                         return (B_TRUE);
12719                 default:
12720                         scfdie();
12721                         /*NOTREACHED*/
12722                 }
12723         }
12724 }
12725 
12726 static void
12727 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12728 {
12729         scf_iter_t *iter;
12730         scf_value_t *val;
12731         const char *type;
12732         int multiple_strings = 0;
12733         int ret;
12734 
12735         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12736             (val = scf_value_create(g_hndl)) == NULL)
12737                 scfdie();
12738 
12739         type = prop_to_typestr(prop);
12740         assert(type != NULL);
12741 
12742         safe_printf("%-*s  %-7s ", len, name, type);
12743 
12744         if (prop_has_multiple_values(prop, val) &&
12745             (scf_value_type(val) == SCF_TYPE_ASTRING ||
12746             scf_value_type(val) == SCF_TYPE_USTRING))
12747                 multiple_strings = 1;
12748 
12749         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12750                 scfdie();
12751 
12752         while ((ret = scf_iter_next_value(iter, val)) == 1) {
12753                 char *buf;
12754                 ssize_t vlen, szret;
12755 
12756                 vlen = scf_value_get_as_string(val, NULL, 0);
12757                 if (vlen < 0)
12758                         scfdie();
12759 
12760                 buf = safe_malloc(vlen + 1);
12761 
12762                 szret = scf_value_get_as_string(val, buf, vlen + 1);
12763                 if (szret < 0)
12764                         scfdie();
12765                 assert(szret <= vlen);
12766 
12767                 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12768                 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12769                         safe_printf(" \"");
12770                         (void) quote_and_print(buf, stdout, 0);
12771                         (void) putchar('"');
12772                         if (ferror(stdout)) {
12773                                 (void) putchar('\n');
12774                                 uu_die(gettext("Error writing to stdout.\n"));
12775                         }
12776                 } else {
12777                         safe_printf(" %s", buf);
12778                 }
12779 
12780                 free(buf);
12781         }
12782         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12783                 scfdie();
12784 
12785         if (putchar('\n') != '\n')
12786                 uu_die(gettext("Could not output newline"));
12787 }
12788 
12789 /*
12790  * Outputs template property group info for the describe subcommand.
12791  * If 'templates' == 2, verbose output is printed in the format expected
12792  * for describe -v, which includes all templates fields.  If pg is
12793  * not NULL, we're describing the template data, not an existing property
12794  * group, and formatting should be appropriate for describe -t.
12795  */
12796 static void
12797 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12798 {
12799         char *buf;
12800         uint8_t required;
12801         scf_property_t *stability_prop;
12802         scf_value_t *stability_val;
12803 
12804         if (templates == 0)
12805                 return;
12806 
12807         if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12808             (stability_val = scf_value_create(g_hndl)) == NULL)
12809                 scfdie();
12810 
12811         if (templates == 2 && pg != NULL) {
12812                 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12813                     stability_prop) == 0) {
12814                         if (prop_check_type(stability_prop,
12815                             SCF_TYPE_ASTRING) == 0 &&
12816                             prop_get_val(stability_prop, stability_val) == 0) {
12817                                 char *stability;
12818 
12819                                 stability = safe_malloc(max_scf_value_len + 1);
12820 
12821                                 if (scf_value_get_astring(stability_val,
12822                                     stability, max_scf_value_len + 1) == -1 &&
12823                                     scf_error() != SCF_ERROR_NOT_FOUND)
12824                                         scfdie();
12825 
12826                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
12827                                     gettext("stability"), stability);
12828 
12829                                 free(stability);
12830                         }
12831                 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12832                         scfdie();
12833         }
12834 
12835         scf_property_destroy(stability_prop);
12836         scf_value_destroy(stability_val);
12837 
12838         if (pgt == NULL)
12839                 return;
12840 
12841         if (pg == NULL || templates == 2) {
12842                 /* print type info only if scf_tmpl_pg_name succeeds */
12843                 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12844                         if (pg != NULL)
12845                                 safe_printf("%s", TMPL_INDENT);
12846                         safe_printf("%s: ", gettext("name"));
12847                         safe_printf("%s\n", buf);
12848                         free(buf);
12849                 }
12850 
12851                 /* print type info only if scf_tmpl_pg_type succeeds */
12852                 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12853                         if (pg != NULL)
12854                                 safe_printf("%s", TMPL_INDENT);
12855                         safe_printf("%s: ", gettext("type"));
12856                         safe_printf("%s\n", buf);
12857                         free(buf);
12858                 }
12859         }
12860 
12861         if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12862                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12863                     required ? "true" : "false");
12864 
12865         if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12866                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12867                     buf);
12868                 free(buf);
12869         }
12870 
12871         if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12872                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12873                     buf);
12874                 free(buf);
12875         }
12876 
12877         if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12878                 if (templates == 2)
12879                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12880                             gettext("description"), buf);
12881                 else
12882                         safe_printf("%s%s\n", TMPL_INDENT, buf);
12883                 free(buf);
12884         }
12885 
12886 }
12887 
12888 /*
12889  * With as_value set to true, indent as appropriate for the value level.
12890  * If false, indent to appropriate level for inclusion in constraint
12891  * or choice printout.
12892  */
12893 static void
12894 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12895     int as_value)
12896 {
12897         char *buf;
12898 
12899         if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12900                 if (as_value == 0)
12901                         safe_printf("%s", TMPL_CHOICE_INDENT);
12902                 else
12903                         safe_printf("%s", TMPL_INDENT);
12904                 safe_printf("%s: %s\n", gettext("value common name"), buf);
12905                 free(buf);
12906         }
12907 
12908         if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12909                 if (as_value == 0)
12910                         safe_printf("%s", TMPL_CHOICE_INDENT);
12911                 else
12912                         safe_printf("%s", TMPL_INDENT);
12913                 safe_printf("%s: %s\n", gettext("value description"), buf);
12914                 free(buf);
12915         }
12916 }
12917 
12918 static void
12919 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12920 {
12921         safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12922         /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12923         safe_printf("%s\n", val_buf);
12924 
12925         print_template_value_details(prt, val_buf, 1);
12926 }
12927 
12928 static void
12929 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12930 {
12931         int i, printed = 0;
12932         scf_values_t values;
12933         scf_count_ranges_t c_ranges;
12934         scf_int_ranges_t i_ranges;
12935 
12936         printed = 0;
12937         i = 0;
12938         if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12939                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12940                     gettext("value constraints"));
12941                 printed++;
12942                 for (i = 0; i < values.value_count; ++i) {
12943                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12944                             gettext("value name"), values.values_as_strings[i]);
12945                         if (verbose == 1)
12946                                 print_template_value_details(prt,
12947                                     values.values_as_strings[i], 0);
12948                 }
12949 
12950                 scf_values_destroy(&values);
12951         }
12952 
12953         if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12954                 if (printed++ == 0)
12955                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12956                             gettext("value constraints"));
12957                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12958                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12959                             gettext("range"), c_ranges.scr_min[i],
12960                             c_ranges.scr_max[i]);
12961                 }
12962                 scf_count_ranges_destroy(&c_ranges);
12963         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12964             scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12965                 if (printed++ == 0)
12966                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12967                             gettext("value constraints"));
12968                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12969                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12970                             gettext("range"), i_ranges.sir_min[i],
12971                             i_ranges.sir_max[i]);
12972                 }
12973                 scf_int_ranges_destroy(&i_ranges);
12974         }
12975 }
12976 
12977 static void
12978 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12979 {
12980         int i = 0, printed = 0;
12981         scf_values_t values;
12982         scf_count_ranges_t c_ranges;
12983         scf_int_ranges_t i_ranges;
12984 
12985         printed = 0;
12986         if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12987                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12988                     gettext("value constraints"));
12989                 printed++;
12990                 for (i = 0; i < values.value_count; i++) {
12991                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12992                             gettext("value name"), values.values_as_strings[i]);
12993                         if (verbose == 1)
12994                                 print_template_value_details(prt,
12995                                     values.values_as_strings[i], 0);
12996                 }
12997 
12998                 scf_values_destroy(&values);
12999         }
13000 
13001         if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13002                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13003                         if (printed++ == 0)
13004                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13005                                     gettext("value choices"));
13006                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13007                             gettext("range"), c_ranges.scr_min[i],
13008                             c_ranges.scr_max[i]);
13009                 }
13010                 scf_count_ranges_destroy(&c_ranges);
13011         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13012             scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13013                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13014                         if (printed++ == 0)
13015                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13016                                     gettext("value choices"));
13017                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13018                             gettext("range"), i_ranges.sir_min[i],
13019                             i_ranges.sir_max[i]);
13020                 }
13021                 scf_int_ranges_destroy(&i_ranges);
13022         }
13023 }
13024 
13025 static void
13026 list_values_by_template(scf_prop_tmpl_t *prt)
13027 {
13028         print_template_constraints(prt, 1);
13029         print_template_choices(prt, 1);
13030 }
13031 
13032 static void
13033 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13034 {
13035         char *val_buf;
13036         scf_iter_t *iter;
13037         scf_value_t *val;
13038         int ret;
13039 
13040         if ((iter = scf_iter_create(g_hndl)) == NULL ||
13041             (val = scf_value_create(g_hndl)) == NULL)
13042                 scfdie();
13043 
13044         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13045                 scfdie();
13046 
13047         val_buf = safe_malloc(max_scf_value_len + 1);
13048 
13049         while ((ret = scf_iter_next_value(iter, val)) == 1) {
13050                 if (scf_value_get_as_string(val, val_buf,
13051                     max_scf_value_len + 1) < 0)
13052                         scfdie();
13053 
13054                 print_template_value(prt, val_buf);
13055         }
13056         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13057                 scfdie();
13058         free(val_buf);
13059 
13060         print_template_constraints(prt, 0);
13061         print_template_choices(prt, 0);
13062 
13063 }
13064 
13065 /*
13066  * Outputs property info for the describe subcommand
13067  * Verbose output if templates == 2, -v option of svccfg describe
13068  * Displays template data if prop is not NULL, -t option of svccfg describe
13069  */
13070 static void
13071 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13072 {
13073         char *buf;
13074         uint8_t u_buf;
13075         int i;
13076         uint64_t min, max;
13077         scf_values_t values;
13078 
13079         if (prt == NULL || templates == 0)
13080                 return;
13081 
13082         if (prop == NULL) {
13083                 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13084                 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13085                         safe_printf("%s\n", buf);
13086                         free(buf);
13087                 } else
13088                         safe_printf("(%s)\n", gettext("any"));
13089         }
13090 
13091         if (prop == NULL || templates == 2) {
13092                 if (prop != NULL)
13093                         safe_printf("%s", TMPL_INDENT);
13094                 else
13095                         safe_printf("%s", TMPL_VALUE_INDENT);
13096                 safe_printf("%s: ", gettext("type"));
13097                 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13098                         safe_printf("%s\n", buf);
13099                         free(buf);
13100                 } else
13101                         safe_printf("(%s)\n", gettext("any"));
13102         }
13103 
13104         if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13105                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13106                     u_buf ? "true" : "false");
13107 
13108         if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13109                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13110                     buf);
13111                 free(buf);
13112         }
13113 
13114         if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13115                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13116                     buf);
13117                 free(buf);
13118         }
13119 
13120         if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13121                 safe_printf("%s%s\n", TMPL_INDENT, buf);
13122                 free(buf);
13123         }
13124 
13125         if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13126                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13127                     scf_tmpl_visibility_to_string(u_buf));
13128 
13129         if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13130                 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13131                     gettext("minimum number of values"), min);
13132                 if (max == ULLONG_MAX) {
13133                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13134                             gettext("maximum number of values"),
13135                             gettext("unlimited"));
13136                 } else {
13137                         safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13138                             gettext("maximum number of values"), max);
13139                 }
13140         }
13141 
13142         if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13143                 for (i = 0; i < values.value_count; i++) {
13144                         if (i == 0) {
13145                                 safe_printf("%s%s:", TMPL_INDENT,
13146                                     gettext("internal separators"));
13147                         }
13148                         safe_printf(" \"%s\"", values.values_as_strings[i]);
13149                 }
13150                 safe_printf("\n");
13151         }
13152 
13153         if (templates != 2)
13154                 return;
13155 
13156         if (prop != NULL)
13157                 list_values_tmpl(prt, prop);
13158         else
13159                 list_values_by_template(prt);
13160 }
13161 
13162 static char *
13163 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13164 {
13165         char *rv;
13166 
13167         rv = _scf_read_single_astring_from_pg(pg, prop_name);
13168         if (rv == NULL) {
13169                 switch (scf_error()) {
13170                 case SCF_ERROR_NOT_FOUND:
13171                         break;
13172                 default:
13173                         scfdie();
13174                 }
13175         }
13176         return (rv);
13177 }
13178 
13179 static void
13180 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13181 {
13182         size_t doc_len;
13183         size_t man_len;
13184         char *pg_name;
13185         char *text = NULL;
13186         int rv;
13187 
13188         doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13189         man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13190         pg_name = safe_malloc(max_scf_name_len + 1);
13191         while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13192                 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13193                         scfdie();
13194                 }
13195                 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13196                         /* Display doc_link and and uri */
13197                         safe_printf("%s%s:\n", TMPL_INDENT,
13198                             gettext("doc_link"));
13199                         text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13200                         if (text != NULL) {
13201                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13202                                     TMPL_INDENT, gettext("name"), text);
13203                                 uu_free(text);
13204                         }
13205                         text = read_astring(pg, SCF_PROPERTY_TM_URI);
13206                         if (text != NULL) {
13207                                 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13208                                     gettext("uri"), text);
13209                                 uu_free(text);
13210                         }
13211                 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13212                     man_len) == 0) {
13213                         /* Display manpage title, section and path */
13214                         safe_printf("%s%s:\n", TMPL_INDENT,
13215                             gettext("manpage"));
13216                         text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13217                         if (text != NULL) {
13218                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13219                                     TMPL_INDENT, gettext("title"), text);
13220                                 uu_free(text);
13221                         }
13222                         text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13223                         if (text != NULL) {
13224                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13225                                     TMPL_INDENT, gettext("section"), text);
13226                                 uu_free(text);
13227                         }
13228                         text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13229                         if (text != NULL) {
13230                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13231                                     TMPL_INDENT, gettext("manpath"), text);
13232                                 uu_free(text);
13233                         }
13234                 }
13235         }
13236         if (rv == -1)
13237                 scfdie();
13238 
13239 done:
13240         free(pg_name);
13241 }
13242 
13243 static void
13244 list_entity_tmpl(int templates)
13245 {
13246         char *common_name = NULL;
13247         char *description = NULL;
13248         char *locale = NULL;
13249         scf_iter_t *iter;
13250         scf_propertygroup_t *pg;
13251         scf_property_t *prop;
13252         int r;
13253         scf_value_t *val;
13254 
13255         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13256             (prop = scf_property_create(g_hndl)) == NULL ||
13257             (val = scf_value_create(g_hndl)) == NULL ||
13258             (iter = scf_iter_create(g_hndl)) == NULL)
13259                 scfdie();
13260 
13261         locale = setlocale(LC_MESSAGES, NULL);
13262 
13263         if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13264                 common_name = safe_malloc(max_scf_value_len + 1);
13265 
13266                 /* Try both the current locale and the "C" locale. */
13267                 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13268                     (scf_error() == SCF_ERROR_NOT_FOUND &&
13269                     scf_pg_get_property(pg, "C", prop) == 0)) {
13270                         if (prop_get_val(prop, val) == 0 &&
13271                             scf_value_get_ustring(val, common_name,
13272                             max_scf_value_len + 1) != -1) {
13273                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
13274                                     gettext("common name"), common_name);
13275                         }
13276                 }
13277         }
13278 
13279         /*
13280          * Do description, manpages, and doc links if templates == 2.
13281          */
13282         if (templates == 2) {
13283                 /* Get the description. */
13284                 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13285                         description = safe_malloc(max_scf_value_len + 1);
13286 
13287                         /* Try both the current locale and the "C" locale. */
13288                         if (scf_pg_get_property(pg, locale, prop) == 0 ||
13289                             (scf_error() == SCF_ERROR_NOT_FOUND &&
13290                             scf_pg_get_property(pg, "C", prop) == 0)) {
13291                                 if (prop_get_val(prop, val) == 0 &&
13292                                     scf_value_get_ustring(val, description,
13293                                     max_scf_value_len + 1) != -1) {
13294                                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13295                                             gettext("description"),
13296                                             description);
13297                                 }
13298                         }
13299                 }
13300 
13301                 /* Process doc_link & manpage elements. */
13302                 if (cur_level != NULL) {
13303                         r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13304                             SCF_GROUP_TEMPLATE);
13305                 } else if (cur_inst != NULL) {
13306                         r = scf_iter_instance_pgs_typed(iter, cur_inst,
13307                             SCF_GROUP_TEMPLATE);
13308                 } else {
13309                         r = scf_iter_service_pgs_typed(iter, cur_svc,
13310                             SCF_GROUP_TEMPLATE);
13311                 }
13312                 if (r == 0) {
13313                         display_documentation(iter, pg);
13314                 }
13315         }
13316 
13317         free(common_name);
13318         free(description);
13319         scf_pg_destroy(pg);
13320         scf_property_destroy(prop);
13321         scf_value_destroy(val);
13322         scf_iter_destroy(iter);
13323 }
13324 
13325 static void
13326 listtmpl(const char *pattern, int templates)
13327 {
13328         scf_pg_tmpl_t *pgt;
13329         scf_prop_tmpl_t *prt;
13330         char *snapbuf = NULL;
13331         char *fmribuf;
13332         char *pg_name = NULL, *prop_name = NULL;
13333         ssize_t prop_name_size;
13334         char *qual_prop_name;
13335         char *search_name;
13336         int listed = 0;
13337 
13338         if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13339             (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13340                 scfdie();
13341 
13342         fmribuf = safe_malloc(max_scf_name_len + 1);
13343         qual_prop_name = safe_malloc(max_scf_name_len + 1);
13344 
13345         if (cur_snap != NULL) {
13346                 snapbuf = safe_malloc(max_scf_name_len + 1);
13347                 if (scf_snapshot_get_name(cur_snap, snapbuf,
13348                     max_scf_name_len + 1) < 0)
13349                         scfdie();
13350         }
13351 
13352         if (cur_inst != NULL) {
13353                 if (scf_instance_to_fmri(cur_inst, fmribuf,
13354                     max_scf_name_len + 1) < 0)
13355                         scfdie();
13356         } else if (cur_svc != NULL) {
13357                 if (scf_service_to_fmri(cur_svc, fmribuf,
13358                     max_scf_name_len + 1) < 0)
13359                         scfdie();
13360         } else
13361                 abort();
13362 
13363         /* If pattern is specified, we want to list only those items. */
13364         while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13365                 listed = 0;
13366                 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13367                     fnmatch(pattern, pg_name, 0) == 0)) {
13368                         list_pg_tmpl(pgt, NULL, templates);
13369                         listed++;
13370                 }
13371 
13372                 scf_tmpl_prop_reset(prt);
13373 
13374                 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13375                         search_name = NULL;
13376                         prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13377                         if ((prop_name_size > 0) && (pg_name != NULL)) {
13378                                 if (snprintf(qual_prop_name,
13379                                     max_scf_name_len + 1, "%s/%s",
13380                                     pg_name, prop_name) >=
13381                                     max_scf_name_len + 1) {
13382                                         prop_name_size = -1;
13383                                 } else {
13384                                         search_name = qual_prop_name;
13385                                 }
13386                         }
13387                         if (listed > 0 || pattern == NULL ||
13388                             (prop_name_size > 0 &&
13389                             fnmatch(pattern, search_name,
13390                             FNM_PATHNAME) == 0))
13391                                 list_prop_tmpl(prt, NULL, templates);
13392                         if (prop_name != NULL) {
13393                                 free(prop_name);
13394                                 prop_name = NULL;
13395                         }
13396                 }
13397                 if (pg_name != NULL) {
13398                         free(pg_name);
13399                         pg_name = NULL;
13400                 }
13401         }
13402 
13403         scf_tmpl_prop_destroy(prt);
13404         scf_tmpl_pg_destroy(pgt);
13405         free(snapbuf);
13406         free(fmribuf);
13407         free(qual_prop_name);
13408 }
13409 
13410 static void
13411 listprop(const char *pattern, int only_pgs, int templates)
13412 {
13413         scf_propertygroup_t *pg;
13414         scf_property_t *prop;
13415         scf_iter_t *iter, *piter;
13416         char *pgnbuf, *prnbuf, *ppnbuf;
13417         scf_pg_tmpl_t *pgt, *pgtp;
13418         scf_prop_tmpl_t *prt;
13419 
13420         void **objects;
13421         char **names;
13422         void **tmpls;
13423         int allocd, i;
13424 
13425         int ret;
13426         ssize_t pgnlen, prnlen, szret;
13427         size_t max_len = 0;
13428 
13429         if (cur_svc == NULL && cur_inst == NULL) {
13430                 semerr(emsg_entity_not_selected);
13431                 return;
13432         }
13433 
13434         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13435             (prop = scf_property_create(g_hndl)) == NULL ||
13436             (iter = scf_iter_create(g_hndl)) == NULL ||
13437             (piter = scf_iter_create(g_hndl)) == NULL ||
13438             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13439             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13440                 scfdie();
13441 
13442         prnbuf = safe_malloc(max_scf_name_len + 1);
13443 
13444         if (cur_level != NULL)
13445                 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13446         else if (cur_inst != NULL)
13447                 ret = scf_iter_instance_pgs(iter, cur_inst);
13448         else
13449                 ret = scf_iter_service_pgs(iter, cur_svc);
13450         if (ret != 0) {
13451                 return;
13452         }
13453 
13454         /*
13455          * We want to only list items which match pattern, and we want the
13456          * second column to line up, so during the first pass we'll save
13457          * matching items, their names, and their templates in objects,
13458          * names, and tmpls, computing the maximum name length as we go,
13459          * and then we'll print them out.
13460          *
13461          * Note: We always keep an extra slot available so the array can be
13462          * NULL-terminated.
13463          */
13464         i = 0;
13465         allocd = 1;
13466         objects = safe_malloc(sizeof (*objects));
13467         names = safe_malloc(sizeof (*names));
13468         tmpls = safe_malloc(sizeof (*tmpls));
13469 
13470         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13471                 int new_pg = 0;
13472                 int print_props = 0;
13473                 pgtp = NULL;
13474 
13475                 pgnlen = scf_pg_get_name(pg, NULL, 0);
13476                 if (pgnlen < 0)
13477                         scfdie();
13478 
13479                 pgnbuf = safe_malloc(pgnlen + 1);
13480 
13481                 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13482                 if (szret < 0)
13483                         scfdie();
13484                 assert(szret <= pgnlen);
13485 
13486                 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13487                         if (scf_error() != SCF_ERROR_NOT_FOUND)
13488                                 scfdie();
13489                         pgtp = NULL;
13490                 } else {
13491                         pgtp = pgt;
13492                 }
13493 
13494                 if (pattern == NULL ||
13495                     fnmatch(pattern, pgnbuf, 0) == 0) {
13496                         if (i+1 >= allocd) {
13497                                 allocd *= 2;
13498                                 objects = realloc(objects,
13499                                     sizeof (*objects) * allocd);
13500                                 names =
13501                                     realloc(names, sizeof (*names) * allocd);
13502                                 tmpls = realloc(tmpls,
13503                                     sizeof (*tmpls) * allocd);
13504                                 if (objects == NULL || names == NULL ||
13505                                     tmpls == NULL)
13506                                         uu_die(gettext("Out of memory"));
13507                         }
13508                         objects[i] = pg;
13509                         names[i] = pgnbuf;
13510 
13511                         if (pgtp == NULL)
13512                                 tmpls[i] = NULL;
13513                         else
13514                                 tmpls[i] = pgt;
13515 
13516                         ++i;
13517 
13518                         if (pgnlen > max_len)
13519                                 max_len = pgnlen;
13520 
13521                         new_pg = 1;
13522                         print_props = 1;
13523                 }
13524 
13525                 if (only_pgs) {
13526                         if (new_pg) {
13527                                 pg = scf_pg_create(g_hndl);
13528                                 if (pg == NULL)
13529                                         scfdie();
13530                                 pgt = scf_tmpl_pg_create(g_hndl);
13531                                 if (pgt == NULL)
13532                                         scfdie();
13533                         } else
13534                                 free(pgnbuf);
13535 
13536                         continue;
13537                 }
13538 
13539                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13540                         scfdie();
13541 
13542                 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13543                         prnlen = scf_property_get_name(prop, prnbuf,
13544                             max_scf_name_len + 1);
13545                         if (prnlen < 0)
13546                                 scfdie();
13547 
13548                         /* Will prepend the property group name and a slash. */
13549                         prnlen += pgnlen + 1;
13550 
13551                         ppnbuf = safe_malloc(prnlen + 1);
13552 
13553                         if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13554                             prnbuf) < 0)
13555                                 uu_die("snprintf");
13556 
13557                         if (pattern == NULL || print_props == 1 ||
13558                             fnmatch(pattern, ppnbuf, 0) == 0) {
13559                                 if (i+1 >= allocd) {
13560                                         allocd *= 2;
13561                                         objects = realloc(objects,
13562                                             sizeof (*objects) * allocd);
13563                                         names = realloc(names,
13564                                             sizeof (*names) * allocd);
13565                                         tmpls = realloc(tmpls,
13566                                             sizeof (*tmpls) * allocd);
13567                                         if (objects == NULL || names == NULL ||
13568                                             tmpls == NULL)
13569                                                 uu_die(gettext(
13570                                                     "Out of memory"));
13571                                 }
13572 
13573                                 objects[i] = prop;
13574                                 names[i] = ppnbuf;
13575 
13576                                 if (pgtp != NULL) {
13577                                         if (scf_tmpl_get_by_prop(pgt, prnbuf,
13578                                             prt, 0) < 0) {
13579                                                 if (scf_error() !=
13580                                                     SCF_ERROR_NOT_FOUND)
13581                                                         scfdie();
13582                                                 tmpls[i] = NULL;
13583                                         } else {
13584                                                 tmpls[i] = prt;
13585                                         }
13586                                 } else {
13587                                         tmpls[i] = NULL;
13588                                 }
13589 
13590                                 ++i;
13591 
13592                                 if (prnlen > max_len)
13593                                         max_len = prnlen;
13594 
13595                                 prop = scf_property_create(g_hndl);
13596                                 prt = scf_tmpl_prop_create(g_hndl);
13597                         } else {
13598                                 free(ppnbuf);
13599                         }
13600                 }
13601 
13602                 if (new_pg) {
13603                         pg = scf_pg_create(g_hndl);
13604                         if (pg == NULL)
13605                                 scfdie();
13606                         pgt = scf_tmpl_pg_create(g_hndl);
13607                         if (pgt == NULL)
13608                                 scfdie();
13609                 } else
13610                         free(pgnbuf);
13611         }
13612         if (ret != 0)
13613                 scfdie();
13614 
13615         objects[i] = NULL;
13616 
13617         scf_pg_destroy(pg);
13618         scf_tmpl_pg_destroy(pgt);
13619         scf_property_destroy(prop);
13620         scf_tmpl_prop_destroy(prt);
13621 
13622         for (i = 0; objects[i] != NULL; ++i) {
13623                 if (strchr(names[i], '/') == NULL) {
13624                         /* property group */
13625                         pg = (scf_propertygroup_t *)objects[i];
13626                         pgt = (scf_pg_tmpl_t *)tmpls[i];
13627                         list_pg_info(pg, names[i], max_len);
13628                         list_pg_tmpl(pgt, pg, templates);
13629                         free(names[i]);
13630                         scf_pg_destroy(pg);
13631                         if (pgt != NULL)
13632                                 scf_tmpl_pg_destroy(pgt);
13633                 } else {
13634                         /* property */
13635                         prop = (scf_property_t *)objects[i];
13636                         prt = (scf_prop_tmpl_t *)tmpls[i];
13637                         list_prop_info(prop, names[i], max_len);
13638                         list_prop_tmpl(prt, prop, templates);
13639                         free(names[i]);
13640                         scf_property_destroy(prop);
13641                         if (prt != NULL)
13642                                 scf_tmpl_prop_destroy(prt);
13643                 }
13644         }
13645 
13646         free(names);
13647         free(objects);
13648         free(tmpls);
13649 }
13650 
13651 void
13652 lscf_listpg(const char *pattern)
13653 {
13654         lscf_prep_hndl();
13655 
13656         listprop(pattern, 1, 0);
13657 }
13658 
13659 /*
13660  * Property group and property creation, setting, and deletion.  setprop (and
13661  * its alias, addprop) can either create a property group of a given type, or
13662  * it can create or set a property to a given type and list of values.
13663  */
13664 void
13665 lscf_addpg(const char *name, const char *type, const char *flags)
13666 {
13667         scf_propertygroup_t *pg;
13668         int ret;
13669         uint32_t flgs = 0;
13670         const char *cp;
13671 
13672 
13673         lscf_prep_hndl();
13674 
13675         if (cur_snap != NULL) {
13676                 semerr(emsg_cant_modify_snapshots);
13677                 return;
13678         }
13679 
13680         if (cur_inst == NULL && cur_svc == NULL) {
13681                 semerr(emsg_entity_not_selected);
13682                 return;
13683         }
13684 
13685         if (flags != NULL) {
13686                 for (cp = flags; *cp != '\0'; ++cp) {
13687                         switch (*cp) {
13688                         case 'P':
13689                                 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13690                                 break;
13691 
13692                         case 'p':
13693                                 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13694                                 break;
13695 
13696                         default:
13697                                 semerr(gettext("Invalid property group flag "
13698                                     "%c."), *cp);
13699                                 return;
13700                         }
13701                 }
13702         }
13703 
13704         pg = scf_pg_create(g_hndl);
13705         if (pg == NULL)
13706                 scfdie();
13707 
13708         if (cur_inst != NULL)
13709                 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13710         else
13711                 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13712 
13713         if (ret != SCF_SUCCESS) {
13714                 switch (scf_error()) {
13715                 case SCF_ERROR_INVALID_ARGUMENT:
13716                         semerr(gettext("Name, type, or flags are invalid.\n"));
13717                         break;
13718 
13719                 case SCF_ERROR_EXISTS:
13720                         semerr(gettext("Property group already exists.\n"));
13721                         break;
13722 
13723                 case SCF_ERROR_PERMISSION_DENIED:
13724                         semerr(emsg_permission_denied);
13725                         break;
13726 
13727                 case SCF_ERROR_BACKEND_ACCESS:
13728                         semerr(gettext("Backend refused access.\n"));
13729                         break;
13730 
13731                 default:
13732                         scfdie();
13733                 }
13734         }
13735 
13736         scf_pg_destroy(pg);
13737 
13738         private_refresh();
13739 }
13740 
13741 void
13742 lscf_delpg(char *name)
13743 {
13744         lscf_prep_hndl();
13745 
13746         if (cur_snap != NULL) {
13747                 semerr(emsg_cant_modify_snapshots);
13748                 return;
13749         }
13750 
13751         if (cur_inst == NULL && cur_svc == NULL) {
13752                 semerr(emsg_entity_not_selected);
13753                 return;
13754         }
13755 
13756         if (strchr(name, '/') != NULL) {
13757                 semerr(emsg_invalid_pg_name, name);
13758                 return;
13759         }
13760 
13761         lscf_delprop(name);
13762 }
13763 
13764 /*
13765  * scf_delhash() is used to remove the property group related to the
13766  * hash entry for a specific manifest in the repository. pgname will be
13767  * constructed from the location of the manifest file. If deathrow isn't 0,
13768  * manifest file doesn't need to exist (manifest string will be used as
13769  * an absolute path).
13770  */
13771 void
13772 lscf_delhash(char *manifest, int deathrow)
13773 {
13774         char *pgname;
13775 
13776         if (cur_snap != NULL ||
13777             cur_inst != NULL || cur_svc != NULL) {
13778                 warn(gettext("error, an entity is selected\n"));
13779                 return;
13780         }
13781 
13782         /* select smf/manifest */
13783         lscf_select(HASH_SVC);
13784         /*
13785          * Translate the manifest file name to property name. In the deathrow
13786          * case, the manifest file does not need to exist.
13787          */
13788         pgname = mhash_filename_to_propname(manifest,
13789             deathrow ? B_TRUE : B_FALSE);
13790         if (pgname == NULL) {
13791                 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13792                 return;
13793         }
13794         /* delete the hash property name */
13795         lscf_delpg(pgname);
13796 }
13797 
13798 void
13799 lscf_listprop(const char *pattern)
13800 {
13801         lscf_prep_hndl();
13802 
13803         listprop(pattern, 0, 0);
13804 }
13805 
13806 int
13807 lscf_setprop(const char *pgname, const char *type, const char *value,
13808     const uu_list_t *values)
13809 {
13810         scf_type_t ty, current_ty;
13811         scf_service_t *svc;
13812         scf_propertygroup_t *pg, *parent_pg;
13813         scf_property_t *prop, *parent_prop;
13814         scf_pg_tmpl_t *pgt;
13815         scf_prop_tmpl_t *prt;
13816         int ret, result = 0;
13817         scf_transaction_t *tx;
13818         scf_transaction_entry_t *e;
13819         scf_value_t *v;
13820         uu_list_walk_t *walk;
13821         string_list_t *sp;
13822         char *propname;
13823         int req_quotes = 0;
13824 
13825         lscf_prep_hndl();
13826 
13827         if ((e = scf_entry_create(g_hndl)) == NULL ||
13828             (svc = scf_service_create(g_hndl)) == NULL ||
13829             (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13830             (pg = scf_pg_create(g_hndl)) == NULL ||
13831             (parent_prop = scf_property_create(g_hndl)) == NULL ||
13832             (prop = scf_property_create(g_hndl)) == NULL ||
13833             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13834             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13835             (tx = scf_transaction_create(g_hndl)) == NULL)
13836                 scfdie();
13837 
13838         if (cur_snap != NULL) {
13839                 semerr(emsg_cant_modify_snapshots);
13840                 goto fail;
13841         }
13842 
13843         if (cur_inst == NULL && cur_svc == NULL) {
13844                 semerr(emsg_entity_not_selected);
13845                 goto fail;
13846         }
13847 
13848         propname = strchr(pgname, '/');
13849         if (propname == NULL) {
13850                 semerr(gettext("Property names must contain a `/'.\n"));
13851                 goto fail;
13852         }
13853 
13854         *propname = '\0';
13855         ++propname;
13856 
13857         if (type != NULL) {
13858                 ty = string_to_type(type);
13859                 if (ty == SCF_TYPE_INVALID) {
13860                         semerr(gettext("Unknown type \"%s\".\n"), type);
13861                         goto fail;
13862                 }
13863         }
13864 
13865         if (cur_inst != NULL)
13866                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13867         else
13868                 ret = scf_service_get_pg(cur_svc, pgname, pg);
13869         if (ret != SCF_SUCCESS) {
13870                 switch (scf_error()) {
13871                 case SCF_ERROR_NOT_FOUND:
13872                         semerr(emsg_no_such_pg, pgname);
13873                         goto fail;
13874 
13875                 case SCF_ERROR_INVALID_ARGUMENT:
13876                         semerr(emsg_invalid_pg_name, pgname);
13877                         goto fail;
13878 
13879                 default:
13880                         scfdie();
13881                         break;
13882                 }
13883         }
13884 
13885         do {
13886                 if (scf_pg_update(pg) == -1)
13887                         scfdie();
13888                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13889                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13890                                 scfdie();
13891 
13892                         semerr(emsg_permission_denied);
13893                         goto fail;
13894                 }
13895 
13896                 ret = scf_pg_get_property(pg, propname, prop);
13897                 if (ret == SCF_SUCCESS) {
13898                         if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13899                                 scfdie();
13900 
13901                         if (type == NULL)
13902                                 ty = current_ty;
13903                         if (scf_transaction_property_change_type(tx, e,
13904                             propname, ty) == -1)
13905                                 scfdie();
13906 
13907                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13908                         /* Infer the type, if possible. */
13909                         if (type == NULL) {
13910                                 /*
13911                                  * First check if we're an instance and the
13912                                  * property is set on the service.
13913                                  */
13914                                 if (cur_inst != NULL &&
13915                                     scf_instance_get_parent(cur_inst,
13916                                     svc) == 0 &&
13917                                     scf_service_get_pg(cur_svc, pgname,
13918                                     parent_pg) == 0 &&
13919                                     scf_pg_get_property(parent_pg, propname,
13920                                     parent_prop) == 0 &&
13921                                     scf_property_type(parent_prop,
13922                                     &current_ty) == 0) {
13923                                         ty = current_ty;
13924 
13925                                 /* Then check for a type set in a template. */
13926                                 } else if (scf_tmpl_get_by_pg(pg, pgt,
13927                                     0) == 0 &&
13928                                     scf_tmpl_get_by_prop(pgt, propname, prt,
13929                                     0) == 0 &&
13930                                     scf_tmpl_prop_type(prt, &current_ty) == 0) {
13931                                         ty = current_ty;
13932 
13933                                 /* If type can't be inferred, fail. */
13934                                 } else {
13935                                         semerr(gettext("Type required for new "
13936                                             "properties.\n"));
13937                                         goto fail;
13938                                 }
13939                         }
13940                         if (scf_transaction_property_new(tx, e, propname,
13941                             ty) == -1)
13942                                 scfdie();
13943                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13944                         semerr(emsg_invalid_prop_name, propname);
13945                         goto fail;
13946                 } else {
13947                         scfdie();
13948                 }
13949 
13950                 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13951                         req_quotes = 1;
13952 
13953                 if (value != NULL) {
13954                         v = string_to_value(value, ty, 0);
13955 
13956                         if (v == NULL)
13957                                 goto fail;
13958 
13959                         ret = scf_entry_add_value(e, v);
13960                         assert(ret == SCF_SUCCESS);
13961                 } else {
13962                         assert(values != NULL);
13963 
13964                         walk = uu_list_walk_start((uu_list_t *)values,
13965                             UU_DEFAULT);
13966                         if (walk == NULL)
13967                                 uu_die(gettext("Could not walk list"));
13968 
13969                         for (sp = uu_list_walk_next(walk); sp != NULL;
13970                             sp = uu_list_walk_next(walk)) {
13971                                 v = string_to_value(sp->str, ty, req_quotes);
13972 
13973                                 if (v == NULL) {
13974                                         scf_entry_destroy_children(e);
13975                                         goto fail;
13976                                 }
13977 
13978                                 ret = scf_entry_add_value(e, v);
13979                                 assert(ret == SCF_SUCCESS);
13980                         }
13981                         uu_list_walk_end(walk);
13982                 }
13983                 result = scf_transaction_commit(tx);
13984 
13985                 scf_transaction_reset(tx);
13986                 scf_entry_destroy_children(e);
13987         } while (result == 0);
13988 
13989         if (result < 0) {
13990                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13991                         scfdie();
13992 
13993                 semerr(emsg_permission_denied);
13994                 goto fail;
13995         }
13996 
13997         ret = 0;
13998 
13999         private_refresh();
14000 
14001         goto cleanup;
14002 
14003 fail:
14004         ret = -1;
14005 
14006 cleanup:
14007         scf_transaction_destroy(tx);
14008         scf_entry_destroy(e);
14009         scf_service_destroy(svc);
14010         scf_pg_destroy(parent_pg);
14011         scf_pg_destroy(pg);
14012         scf_property_destroy(parent_prop);
14013         scf_property_destroy(prop);
14014         scf_tmpl_pg_destroy(pgt);
14015         scf_tmpl_prop_destroy(prt);
14016 
14017         return (ret);
14018 }
14019 
14020 void
14021 lscf_delprop(char *pgn)
14022 {
14023         char *slash, *pn;
14024         scf_propertygroup_t *pg;
14025         scf_transaction_t *tx;
14026         scf_transaction_entry_t *e;
14027         int ret;
14028 
14029 
14030         lscf_prep_hndl();
14031 
14032         if (cur_snap != NULL) {
14033                 semerr(emsg_cant_modify_snapshots);
14034                 return;
14035         }
14036 
14037         if (cur_inst == NULL && cur_svc == NULL) {
14038                 semerr(emsg_entity_not_selected);
14039                 return;
14040         }
14041 
14042         pg = scf_pg_create(g_hndl);
14043         if (pg == NULL)
14044                 scfdie();
14045 
14046         slash = strchr(pgn, '/');
14047         if (slash == NULL) {
14048                 pn = NULL;
14049         } else {
14050                 *slash = '\0';
14051                 pn = slash + 1;
14052         }
14053 
14054         if (cur_inst != NULL)
14055                 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14056         else
14057                 ret = scf_service_get_pg(cur_svc, pgn, pg);
14058         if (ret != SCF_SUCCESS) {
14059                 switch (scf_error()) {
14060                 case SCF_ERROR_NOT_FOUND:
14061                         semerr(emsg_no_such_pg, pgn);
14062                         break;
14063 
14064                 case SCF_ERROR_INVALID_ARGUMENT:
14065                         semerr(emsg_invalid_pg_name, pgn);
14066                         break;
14067 
14068                 default:
14069                         scfdie();
14070                 }
14071 
14072                 scf_pg_destroy(pg);
14073 
14074                 return;
14075         }
14076 
14077         if (pn == NULL) {
14078                 /* Try to delete the property group. */
14079                 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14080                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14081                                 scfdie();
14082 
14083                         semerr(emsg_permission_denied);
14084                 } else {
14085                         private_refresh();
14086                 }
14087 
14088                 scf_pg_destroy(pg);
14089                 return;
14090         }
14091 
14092         e = scf_entry_create(g_hndl);
14093         tx = scf_transaction_create(g_hndl);
14094 
14095         do {
14096                 if (scf_pg_update(pg) == -1)
14097                         scfdie();
14098                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14099                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14100                                 scfdie();
14101 
14102                         semerr(emsg_permission_denied);
14103                         break;
14104                 }
14105 
14106                 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14107                         if (scf_error() == SCF_ERROR_NOT_FOUND) {
14108                                 semerr(gettext("No such property %s/%s.\n"),
14109                                     pgn, pn);
14110                                 break;
14111                         } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14112                                 semerr(emsg_invalid_prop_name, pn);
14113                                 break;
14114                         } else {
14115                                 scfdie();
14116                         }
14117                 }
14118 
14119                 ret = scf_transaction_commit(tx);
14120 
14121                 if (ret == 0)
14122                         scf_transaction_reset(tx);
14123         } while (ret == 0);
14124 
14125         if (ret < 0) {
14126                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14127                         scfdie();
14128 
14129                 semerr(emsg_permission_denied);
14130         } else {
14131                 private_refresh();
14132         }
14133 
14134         scf_transaction_destroy(tx);
14135         scf_entry_destroy(e);
14136         scf_pg_destroy(pg);
14137 }
14138 
14139 /*
14140  * Property editing.
14141  */
14142 
14143 static int
14144 write_edit_script(FILE *strm)
14145 {
14146         char *fmribuf;
14147         ssize_t fmrilen;
14148 
14149         scf_propertygroup_t *pg;
14150         scf_property_t *prop;
14151         scf_value_t *val;
14152         scf_type_t ty;
14153         int ret, result = 0;
14154         scf_iter_t *iter, *piter, *viter;
14155         char *buf, *tybuf, *pname;
14156         const char *emsg_write_error;
14157 
14158 
14159         emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14160 
14161 
14162         /* select fmri */
14163         if (cur_inst != NULL) {
14164                 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14165                 if (fmrilen < 0)
14166                         scfdie();
14167                 fmribuf = safe_malloc(fmrilen + 1);
14168                 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14169                         scfdie();
14170         } else {
14171                 assert(cur_svc != NULL);
14172                 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14173                 if (fmrilen < 0)
14174                         scfdie();
14175                 fmribuf = safe_malloc(fmrilen + 1);
14176                 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14177                         scfdie();
14178         }
14179 
14180         if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14181                 warn(emsg_write_error, strerror(errno));
14182                 free(fmribuf);
14183                 return (-1);
14184         }
14185 
14186         free(fmribuf);
14187 
14188 
14189         if ((pg = scf_pg_create(g_hndl)) == NULL ||
14190             (prop = scf_property_create(g_hndl)) == NULL ||
14191             (val = scf_value_create(g_hndl)) == NULL ||
14192             (iter = scf_iter_create(g_hndl)) == NULL ||
14193             (piter = scf_iter_create(g_hndl)) == NULL ||
14194             (viter = scf_iter_create(g_hndl)) == NULL)
14195                 scfdie();
14196 
14197         buf = safe_malloc(max_scf_name_len + 1);
14198         tybuf = safe_malloc(max_scf_pg_type_len + 1);
14199         pname = safe_malloc(max_scf_name_len + 1);
14200 
14201         if (cur_inst != NULL)
14202                 ret = scf_iter_instance_pgs(iter, cur_inst);
14203         else
14204                 ret = scf_iter_service_pgs(iter, cur_svc);
14205         if (ret != SCF_SUCCESS)
14206                 scfdie();
14207 
14208         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14209                 int ret2;
14210 
14211                 /*
14212                  * # delprop pg
14213                  * # addpg pg type
14214                  */
14215                 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14216                         scfdie();
14217 
14218                 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14219                         scfdie();
14220 
14221                 if (fprintf(strm, "# Property group \"%s\"\n"
14222                     "# delprop %s\n"
14223                     "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14224                         warn(emsg_write_error, strerror(errno));
14225                         result = -1;
14226                         goto out;
14227                 }
14228 
14229                 /* # setprop pg/prop = (values) */
14230 
14231                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14232                         scfdie();
14233 
14234                 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14235                         int first = 1;
14236                         int ret3;
14237                         int multiple;
14238                         int is_str;
14239                         scf_type_t bty;
14240 
14241                         if (scf_property_get_name(prop, pname,
14242                             max_scf_name_len + 1) < 0)
14243                                 scfdie();
14244 
14245                         if (scf_property_type(prop, &ty) != 0)
14246                                 scfdie();
14247 
14248                         multiple = prop_has_multiple_values(prop, val);
14249 
14250                         if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14251                             pname, scf_type_to_string(ty), multiple ? "(" : "")
14252                             < 0) {
14253                                 warn(emsg_write_error, strerror(errno));
14254                                 result = -1;
14255                                 goto out;
14256                         }
14257 
14258                         (void) scf_type_base_type(ty, &bty);
14259                         is_str = (bty == SCF_TYPE_ASTRING);
14260 
14261                         if (scf_iter_property_values(viter, prop) !=
14262                             SCF_SUCCESS)
14263                                 scfdie();
14264 
14265                         while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14266                                 char *buf;
14267                                 ssize_t buflen;
14268 
14269                                 buflen = scf_value_get_as_string(val, NULL, 0);
14270                                 if (buflen < 0)
14271                                         scfdie();
14272 
14273                                 buf = safe_malloc(buflen + 1);
14274 
14275                                 if (scf_value_get_as_string(val, buf,
14276                                     buflen + 1) < 0)
14277                                         scfdie();
14278 
14279                                 if (first)
14280                                         first = 0;
14281                                 else {
14282                                         if (putc(' ', strm) != ' ') {
14283                                                 warn(emsg_write_error,
14284                                                     strerror(errno));
14285                                                 result = -1;
14286                                                 goto out;
14287                                         }
14288                                 }
14289 
14290                                 if ((is_str && multiple) ||
14291                                     strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14292                                         (void) putc('"', strm);
14293                                         (void) quote_and_print(buf, strm, 1);
14294                                         (void) putc('"', strm);
14295 
14296                                         if (ferror(strm)) {
14297                                                 warn(emsg_write_error,
14298                                                     strerror(errno));
14299                                                 result = -1;
14300                                                 goto out;
14301                                         }
14302                                 } else {
14303                                         if (fprintf(strm, "%s", buf) < 0) {
14304                                                 warn(emsg_write_error,
14305                                                     strerror(errno));
14306                                                 result = -1;
14307                                                 goto out;
14308                                         }
14309                                 }
14310 
14311                                 free(buf);
14312                         }
14313                         if (ret3 < 0 &&
14314                             scf_error() != SCF_ERROR_PERMISSION_DENIED)
14315                                 scfdie();
14316 
14317                         /* Write closing paren if mult-value property */
14318                         if ((multiple && putc(')', strm) == EOF) ||
14319 
14320                             /* Write final newline */
14321                             fputc('\n', strm) == EOF) {
14322                                 warn(emsg_write_error, strerror(errno));
14323                                 result = -1;
14324                                 goto out;
14325                         }
14326                 }
14327                 if (ret2 < 0)
14328                         scfdie();
14329 
14330                 if (fputc('\n', strm) == EOF) {
14331                         warn(emsg_write_error, strerror(errno));
14332                         result = -1;
14333                         goto out;
14334                 }
14335         }
14336         if (ret < 0)
14337                 scfdie();
14338 
14339 out:
14340         free(pname);
14341         free(tybuf);
14342         free(buf);
14343         scf_iter_destroy(viter);
14344         scf_iter_destroy(piter);
14345         scf_iter_destroy(iter);
14346         scf_value_destroy(val);
14347         scf_property_destroy(prop);
14348         scf_pg_destroy(pg);
14349 
14350         if (result == 0) {
14351                 if (fflush(strm) != 0) {
14352                         warn(emsg_write_error, strerror(errno));
14353                         return (-1);
14354                 }
14355         }
14356 
14357         return (result);
14358 }
14359 
14360 int
14361 lscf_editprop()
14362 {
14363         char *buf, *editor;
14364         size_t bufsz;
14365         int tmpfd;
14366         char tempname[] = TEMP_FILE_PATTERN;
14367 
14368         lscf_prep_hndl();
14369 
14370         if (cur_snap != NULL) {
14371                 semerr(emsg_cant_modify_snapshots);
14372                 return (-1);
14373         }
14374 
14375         if (cur_svc == NULL && cur_inst == NULL) {
14376                 semerr(emsg_entity_not_selected);
14377                 return (-1);
14378         }
14379 
14380         tmpfd = mkstemp(tempname);
14381         if (tmpfd == -1) {
14382                 semerr(gettext("Could not create temporary file.\n"));
14383                 return (-1);
14384         }
14385 
14386         (void) strcpy(tempfilename, tempname);
14387 
14388         tempfile = fdopen(tmpfd, "r+");
14389         if (tempfile == NULL) {
14390                 warn(gettext("Could not create temporary file.\n"));
14391                 if (close(tmpfd) == -1)
14392                         warn(gettext("Could not close temporary file: %s.\n"),
14393                             strerror(errno));
14394 
14395                 remove_tempfile();
14396 
14397                 return (-1);
14398         }
14399 
14400         if (write_edit_script(tempfile) == -1) {
14401                 remove_tempfile();
14402                 return (-1);
14403         }
14404 
14405         editor = getenv("EDITOR");
14406         if (editor == NULL)
14407                 editor = "vi";
14408 
14409         bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14410         buf = safe_malloc(bufsz);
14411 
14412         if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14413                 uu_die(gettext("Error creating editor command"));
14414 
14415         if (system(buf) == -1) {
14416                 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14417                     strerror(errno));
14418                 free(buf);
14419                 remove_tempfile();
14420                 return (-1);
14421         }
14422 
14423         free(buf);
14424 
14425         (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14426 
14427         remove_tempfile();
14428 
14429         return (0);
14430 }
14431 
14432 static void
14433 add_string(uu_list_t *strlist, const char *str)
14434 {
14435         string_list_t *elem;
14436         elem = safe_malloc(sizeof (*elem));
14437         uu_list_node_init(elem, &elem->node, string_pool);
14438         elem->str = safe_strdup(str);
14439         if (uu_list_append(strlist, elem) != 0)
14440                 uu_die(gettext("libuutil error: %s\n"),
14441                     uu_strerror(uu_error()));
14442 }
14443 
14444 static int
14445 remove_string(uu_list_t *strlist, const char *str)
14446 {
14447         uu_list_walk_t  *elems;
14448         string_list_t   *sp;
14449 
14450         /*
14451          * Find the element that needs to be removed.
14452          */
14453         elems = uu_list_walk_start(strlist, UU_DEFAULT);
14454         while ((sp = uu_list_walk_next(elems)) != NULL) {
14455                 if (strcmp(sp->str, str) == 0)
14456                         break;
14457         }
14458         uu_list_walk_end(elems);
14459 
14460         /*
14461          * Returning 1 here as the value was not found, this
14462          * might not be an error.  Leave it to the caller to
14463          * decide.
14464          */
14465         if (sp == NULL) {
14466                 return (1);
14467         }
14468 
14469         uu_list_remove(strlist, sp);
14470 
14471         free(sp->str);
14472         free(sp);
14473 
14474         return (0);
14475 }
14476 
14477 /*
14478  * Get all property values that don't match the given glob pattern,
14479  * if a pattern is specified.
14480  */
14481 static void
14482 get_prop_values(scf_property_t *prop, uu_list_t *values,
14483     const char *pattern)
14484 {
14485         scf_iter_t *iter;
14486         scf_value_t *val;
14487         int ret;
14488 
14489         if ((iter = scf_iter_create(g_hndl)) == NULL ||
14490             (val = scf_value_create(g_hndl)) == NULL)
14491                 scfdie();
14492 
14493         if (scf_iter_property_values(iter, prop) != 0)
14494                 scfdie();
14495 
14496         while ((ret = scf_iter_next_value(iter, val)) == 1) {
14497                 char *buf;
14498                 ssize_t vlen, szret;
14499 
14500                 vlen = scf_value_get_as_string(val, NULL, 0);
14501                 if (vlen < 0)
14502                         scfdie();
14503 
14504                 buf = safe_malloc(vlen + 1);
14505 
14506                 szret = scf_value_get_as_string(val, buf, vlen + 1);
14507                 if (szret < 0)
14508                         scfdie();
14509                 assert(szret <= vlen);
14510 
14511                 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14512                         add_string(values, buf);
14513 
14514                 free(buf);
14515         }
14516 
14517         if (ret == -1)
14518                 scfdie();
14519 
14520         scf_value_destroy(val);
14521         scf_iter_destroy(iter);
14522 }
14523 
14524 static int
14525 lscf_setpropvalue(const char *pgname, const char *type,
14526     const char *arg, int isadd, int isnotfoundok)
14527 {
14528         scf_type_t ty;
14529         scf_propertygroup_t *pg;
14530         scf_property_t *prop;
14531         int ret, result = 0;
14532         scf_transaction_t *tx;
14533         scf_transaction_entry_t *e;
14534         scf_value_t *v;
14535         string_list_t *sp;
14536         char *propname;
14537         uu_list_t *values;
14538         uu_list_walk_t *walk;
14539         void *cookie = NULL;
14540         char *pattern = NULL;
14541 
14542         lscf_prep_hndl();
14543 
14544         if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14545                 uu_die(gettext("Could not create property list: %s\n"),
14546                     uu_strerror(uu_error()));
14547 
14548         if (!isadd)
14549                 pattern = safe_strdup(arg);
14550 
14551         if ((e = scf_entry_create(g_hndl)) == NULL ||
14552             (pg = scf_pg_create(g_hndl)) == NULL ||
14553             (prop = scf_property_create(g_hndl)) == NULL ||
14554             (tx = scf_transaction_create(g_hndl)) == NULL)
14555                 scfdie();
14556 
14557         if (cur_snap != NULL) {
14558                 semerr(emsg_cant_modify_snapshots);
14559                 goto fail;
14560         }
14561 
14562         if (cur_inst == NULL && cur_svc == NULL) {
14563                 semerr(emsg_entity_not_selected);
14564                 goto fail;
14565         }
14566 
14567         propname = strchr(pgname, '/');
14568         if (propname == NULL) {
14569                 semerr(gettext("Property names must contain a `/'.\n"));
14570                 goto fail;
14571         }
14572 
14573         *propname = '\0';
14574         ++propname;
14575 
14576         if (type != NULL) {
14577                 ty = string_to_type(type);
14578                 if (ty == SCF_TYPE_INVALID) {
14579                         semerr(gettext("Unknown type \"%s\".\n"), type);
14580                         goto fail;
14581                 }
14582         }
14583 
14584         if (cur_inst != NULL)
14585                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14586         else
14587                 ret = scf_service_get_pg(cur_svc, pgname, pg);
14588         if (ret != 0) {
14589                 switch (scf_error()) {
14590                 case SCF_ERROR_NOT_FOUND:
14591                         if (isnotfoundok) {
14592                                 result = 0;
14593                         } else {
14594                                 semerr(emsg_no_such_pg, pgname);
14595                                 result = -1;
14596                         }
14597                         goto out;
14598 
14599                 case SCF_ERROR_INVALID_ARGUMENT:
14600                         semerr(emsg_invalid_pg_name, pgname);
14601                         goto fail;
14602 
14603                 default:
14604                         scfdie();
14605                 }
14606         }
14607 
14608         do {
14609                 if (scf_pg_update(pg) == -1)
14610                         scfdie();
14611                 if (scf_transaction_start(tx, pg) != 0) {
14612                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14613                                 scfdie();
14614 
14615                         semerr(emsg_permission_denied);
14616                         goto fail;
14617                 }
14618 
14619                 ret = scf_pg_get_property(pg, propname, prop);
14620                 if (ret == 0) {
14621                         scf_type_t ptype;
14622                         char *pat = pattern;
14623 
14624                         if (scf_property_type(prop, &ptype) != 0)
14625                                 scfdie();
14626 
14627                         if (isadd) {
14628                                 if (type != NULL && ptype != ty) {
14629                                         semerr(gettext("Property \"%s\" is not "
14630                                             "of type \"%s\".\n"), propname,
14631                                             type);
14632                                         goto fail;
14633                                 }
14634 
14635                                 pat = NULL;
14636                         } else {
14637                                 size_t len = strlen(pat);
14638                                 if (len > 0 && pat[len - 1] == '\"')
14639                                         pat[len - 1] = '\0';
14640                                 if (len > 0 && pat[0] == '\"')
14641                                         pat++;
14642                         }
14643 
14644                         ty = ptype;
14645 
14646                         get_prop_values(prop, values, pat);
14647 
14648                         if (isadd)
14649                                 add_string(values, arg);
14650 
14651                         if (scf_transaction_property_change(tx, e,
14652                             propname, ty) == -1)
14653                                 scfdie();
14654                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14655                         if (isadd) {
14656                                 if (type == NULL) {
14657                                         semerr(gettext("Type required "
14658                                             "for new properties.\n"));
14659                                         goto fail;
14660                                 }
14661 
14662                                 add_string(values, arg);
14663 
14664                                 if (scf_transaction_property_new(tx, e,
14665                                     propname, ty) == -1)
14666                                         scfdie();
14667                         } else if (isnotfoundok) {
14668                                 result = 0;
14669                                 goto out;
14670                         } else {
14671                                 semerr(gettext("No such property %s/%s.\n"),
14672                                     pgname, propname);
14673                                 result = -1;
14674                                 goto out;
14675                         }
14676                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14677                         semerr(emsg_invalid_prop_name, propname);
14678                         goto fail;
14679                 } else {
14680                         scfdie();
14681                 }
14682 
14683                 walk = uu_list_walk_start(values, UU_DEFAULT);
14684                 if (walk == NULL)
14685                         uu_die(gettext("Could not walk property list.\n"));
14686 
14687                 for (sp = uu_list_walk_next(walk); sp != NULL;
14688                     sp = uu_list_walk_next(walk)) {
14689                         v = string_to_value(sp->str, ty, 0);
14690 
14691                         if (v == NULL) {
14692                                 scf_entry_destroy_children(e);
14693                                 goto fail;
14694                         }
14695                         ret = scf_entry_add_value(e, v);
14696                         assert(ret == 0);
14697                 }
14698                 uu_list_walk_end(walk);
14699 
14700                 result = scf_transaction_commit(tx);
14701 
14702                 scf_transaction_reset(tx);
14703                 scf_entry_destroy_children(e);
14704         } while (result == 0);
14705 
14706         if (result < 0) {
14707                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14708                         scfdie();
14709 
14710                 semerr(emsg_permission_denied);
14711                 goto fail;
14712         }
14713 
14714         result = 0;
14715 
14716         private_refresh();
14717 
14718 out:
14719         scf_transaction_destroy(tx);
14720         scf_entry_destroy(e);
14721         scf_pg_destroy(pg);
14722         scf_property_destroy(prop);
14723         free(pattern);
14724 
14725         while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14726                 free(sp->str);
14727                 free(sp);
14728         }
14729 
14730         uu_list_destroy(values);
14731 
14732         return (result);
14733 
14734 fail:
14735         result = -1;
14736         goto out;
14737 }
14738 
14739 int
14740 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14741 {
14742         return (lscf_setpropvalue(pgname, type, value, 1, 0));
14743 }
14744 
14745 int
14746 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14747 {
14748         return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14749 }
14750 
14751 /*
14752  * Look for a standard start method, first in the instance (if any),
14753  * then the service.
14754  */
14755 static const char *
14756 start_method_name(int *in_instance)
14757 {
14758         scf_propertygroup_t *pg;
14759         char **p;
14760         int ret;
14761         scf_instance_t *inst = cur_inst;
14762 
14763         if ((pg = scf_pg_create(g_hndl)) == NULL)
14764                 scfdie();
14765 
14766 again:
14767         for (p = start_method_names; *p != NULL; p++) {
14768                 if (inst != NULL)
14769                         ret = scf_instance_get_pg(inst, *p, pg);
14770                 else
14771                         ret = scf_service_get_pg(cur_svc, *p, pg);
14772 
14773                 if (ret == 0) {
14774                         size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14775                         char *buf = safe_malloc(bufsz);
14776 
14777                         if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14778                                 free(buf);
14779                                 continue;
14780                         }
14781                         if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14782                                 free(buf);
14783                                 continue;
14784                         }
14785 
14786                         free(buf);
14787                         *in_instance = (inst != NULL);
14788                         scf_pg_destroy(pg);
14789                         return (*p);
14790                 }
14791 
14792                 if (scf_error() == SCF_ERROR_NOT_FOUND)
14793                         continue;
14794 
14795                 scfdie();
14796         }
14797 
14798         if (inst != NULL) {
14799                 inst = NULL;
14800                 goto again;
14801         }
14802 
14803         scf_pg_destroy(pg);
14804         return (NULL);
14805 }
14806 
14807 static int
14808 addpg(const char *name, const char *type)
14809 {
14810         scf_propertygroup_t *pg;
14811         int ret;
14812 
14813         pg = scf_pg_create(g_hndl);
14814         if (pg == NULL)
14815                 scfdie();
14816 
14817         if (cur_inst != NULL)
14818                 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14819         else
14820                 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14821 
14822         if (ret != 0) {
14823                 switch (scf_error()) {
14824                 case SCF_ERROR_EXISTS:
14825                         ret = 0;
14826                         break;
14827 
14828                 case SCF_ERROR_PERMISSION_DENIED:
14829                         semerr(emsg_permission_denied);
14830                         break;
14831 
14832                 default:
14833                         scfdie();
14834                 }
14835         }
14836 
14837         scf_pg_destroy(pg);
14838         return (ret);
14839 }
14840 
14841 int
14842 lscf_setenv(uu_list_t *args, int isunset)
14843 {
14844         int ret = 0;
14845         size_t i;
14846         int argc;
14847         char **argv = NULL;
14848         string_list_t *slp;
14849         char *pattern;
14850         char *prop;
14851         int do_service = 0;
14852         int do_instance = 0;
14853         const char *method = NULL;
14854         const char *name = NULL;
14855         const char *value = NULL;
14856         scf_instance_t *saved_cur_inst = cur_inst;
14857 
14858         lscf_prep_hndl();
14859 
14860         argc = uu_list_numnodes(args);
14861         if (argc < 1)
14862                 goto usage;
14863 
14864         argv = calloc(argc + 1, sizeof (char *));
14865         if (argv == NULL)
14866                 uu_die(gettext("Out of memory.\n"));
14867 
14868         for (slp = uu_list_first(args), i = 0;
14869             slp != NULL;
14870             slp = uu_list_next(args, slp), ++i)
14871                 argv[i] = slp->str;
14872 
14873         argv[i] = NULL;
14874 
14875         opterr = 0;
14876         optind = 0;
14877         for (;;) {
14878                 ret = getopt(argc, argv, "sim:");
14879                 if (ret == -1)
14880                         break;
14881 
14882                 switch (ret) {
14883                 case 's':
14884                         do_service = 1;
14885                         cur_inst = NULL;
14886                         break;
14887 
14888                 case 'i':
14889                         do_instance = 1;
14890                         break;
14891 
14892                 case 'm':
14893                         method = optarg;
14894                         break;
14895 
14896                 case '?':
14897                         goto usage;
14898 
14899                 default:
14900                         bad_error("getopt", ret);
14901                 }
14902         }
14903 
14904         argc -= optind;
14905         if ((do_service && do_instance) ||
14906             (isunset && argc != 1) ||
14907             (!isunset && argc != 2))
14908                 goto usage;
14909 
14910         name = argv[optind];
14911         if (!isunset)
14912                 value = argv[optind + 1];
14913 
14914         if (cur_snap != NULL) {
14915                 semerr(emsg_cant_modify_snapshots);
14916                 ret = -1;
14917                 goto out;
14918         }
14919 
14920         if (cur_inst == NULL && cur_svc == NULL) {
14921                 semerr(emsg_entity_not_selected);
14922                 ret = -1;
14923                 goto out;
14924         }
14925 
14926         if (do_instance && cur_inst == NULL) {
14927                 semerr(gettext("No instance is selected.\n"));
14928                 ret = -1;
14929                 goto out;
14930         }
14931 
14932         if (do_service && cur_svc == NULL) {
14933                 semerr(gettext("No service is selected.\n"));
14934                 ret = -1;
14935                 goto out;
14936         }
14937 
14938         if (method == NULL) {
14939                 if (do_instance || do_service) {
14940                         method = "method_context";
14941                         if (!isunset) {
14942                                 ret = addpg("method_context",
14943                                     SCF_GROUP_FRAMEWORK);
14944                                 if (ret != 0)
14945                                         goto out;
14946                         }
14947                 } else {
14948                         int in_instance;
14949                         method = start_method_name(&in_instance);
14950                         if (method == NULL) {
14951                                 semerr(gettext(
14952                                     "Couldn't find start method; please "
14953                                     "specify a method with '-m'.\n"));
14954                                 ret = -1;
14955                                 goto out;
14956                         }
14957                         if (!in_instance)
14958                                 cur_inst = NULL;
14959                 }
14960         } else {
14961                 scf_propertygroup_t *pg;
14962                 size_t bufsz;
14963                 char *buf;
14964                 int ret;
14965 
14966                 if ((pg = scf_pg_create(g_hndl)) == NULL)
14967                         scfdie();
14968 
14969                 if (cur_inst != NULL)
14970                         ret = scf_instance_get_pg(cur_inst, method, pg);
14971                 else
14972                         ret = scf_service_get_pg(cur_svc, method, pg);
14973 
14974                 if (ret != 0) {
14975                         scf_pg_destroy(pg);
14976                         switch (scf_error()) {
14977                         case SCF_ERROR_NOT_FOUND:
14978                                 semerr(gettext("Couldn't find the method "
14979                                     "\"%s\".\n"), method);
14980                                 goto out;
14981 
14982                         case SCF_ERROR_INVALID_ARGUMENT:
14983                                 semerr(gettext("Invalid method name \"%s\".\n"),
14984                                     method);
14985                                 goto out;
14986 
14987                         default:
14988                                 scfdie();
14989                         }
14990                 }
14991 
14992                 bufsz = strlen(SCF_GROUP_METHOD) + 1;
14993                 buf = safe_malloc(bufsz);
14994 
14995                 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14996                     strcmp(buf, SCF_GROUP_METHOD) != 0) {
14997                         semerr(gettext("Property group \"%s\" is not of type "
14998                             "\"method\".\n"), method);
14999                         ret = -1;
15000                         free(buf);
15001                         scf_pg_destroy(pg);
15002                         goto out;
15003                 }
15004 
15005                 free(buf);
15006                 scf_pg_destroy(pg);
15007         }
15008 
15009         prop = uu_msprintf("%s/environment", method);
15010         pattern = uu_msprintf("%s=*", name);
15011 
15012         if (prop == NULL || pattern == NULL)
15013                 uu_die(gettext("Out of memory.\n"));
15014 
15015         ret = lscf_delpropvalue(prop, pattern, !isunset);
15016 
15017         if (ret == 0 && !isunset) {
15018                 uu_free(pattern);
15019                 uu_free(prop);
15020                 prop = uu_msprintf("%s/environment", method);
15021                 pattern = uu_msprintf("%s=%s", name, value);
15022                 if (prop == NULL || pattern == NULL)
15023                         uu_die(gettext("Out of memory.\n"));
15024                 ret = lscf_addpropvalue(prop, "astring:", pattern);
15025         }
15026         uu_free(pattern);
15027         uu_free(prop);
15028 
15029 out:
15030         cur_inst = saved_cur_inst;
15031 
15032         free(argv);
15033         return (ret);
15034 usage:
15035         ret = -2;
15036         goto out;
15037 }
15038 
15039 /*
15040  * Snapshot commands
15041  */
15042 
15043 void
15044 lscf_listsnap()
15045 {
15046         scf_snapshot_t *snap;
15047         scf_iter_t *iter;
15048         char *nb;
15049         int r;
15050 
15051         lscf_prep_hndl();
15052 
15053         if (cur_inst == NULL) {
15054                 semerr(gettext("Instance not selected.\n"));
15055                 return;
15056         }
15057 
15058         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15059             (iter = scf_iter_create(g_hndl)) == NULL)
15060                 scfdie();
15061 
15062         if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15063                 scfdie();
15064 
15065         nb = safe_malloc(max_scf_name_len + 1);
15066 
15067         while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15068                 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15069                         scfdie();
15070 
15071                 (void) puts(nb);
15072         }
15073         if (r < 0)
15074                 scfdie();
15075 
15076         free(nb);
15077         scf_iter_destroy(iter);
15078         scf_snapshot_destroy(snap);
15079 }
15080 
15081 void
15082 lscf_selectsnap(const char *name)
15083 {
15084         scf_snapshot_t *snap;
15085         scf_snaplevel_t *level;
15086 
15087         lscf_prep_hndl();
15088 
15089         if (cur_inst == NULL) {
15090                 semerr(gettext("Instance not selected.\n"));
15091                 return;
15092         }
15093 
15094         if (cur_snap != NULL) {
15095                 if (name != NULL) {
15096                         char *cur_snap_name;
15097                         boolean_t nochange;
15098 
15099                         cur_snap_name = safe_malloc(max_scf_name_len + 1);
15100 
15101                         if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15102                             max_scf_name_len + 1) < 0)
15103                                 scfdie();
15104 
15105                         nochange = strcmp(name, cur_snap_name) == 0;
15106 
15107                         free(cur_snap_name);
15108 
15109                         if (nochange)
15110                                 return;
15111                 }
15112 
15113                 unselect_cursnap();
15114         }
15115 
15116         if (name == NULL)
15117                 return;
15118 
15119         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15120             (level = scf_snaplevel_create(g_hndl)) == NULL)
15121                 scfdie();
15122 
15123         if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15124             SCF_SUCCESS) {
15125                 switch (scf_error()) {
15126                 case SCF_ERROR_INVALID_ARGUMENT:
15127                         semerr(gettext("Invalid name \"%s\".\n"), name);
15128                         break;
15129 
15130                 case SCF_ERROR_NOT_FOUND:
15131                         semerr(gettext("No such snapshot \"%s\".\n"), name);
15132                         break;
15133 
15134                 default:
15135                         scfdie();
15136                 }
15137 
15138                 scf_snaplevel_destroy(level);
15139                 scf_snapshot_destroy(snap);
15140                 return;
15141         }
15142 
15143         /* Load the snaplevels into our list. */
15144         cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15145         if (cur_levels == NULL)
15146                 uu_die(gettext("Could not create list: %s\n"),
15147                     uu_strerror(uu_error()));
15148 
15149         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15150                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15151                         scfdie();
15152 
15153                 semerr(gettext("Snapshot has no snaplevels.\n"));
15154 
15155                 scf_snaplevel_destroy(level);
15156                 scf_snapshot_destroy(snap);
15157                 return;
15158         }
15159 
15160         cur_snap = snap;
15161 
15162         for (;;) {
15163                 cur_elt = safe_malloc(sizeof (*cur_elt));
15164                 uu_list_node_init(cur_elt, &cur_elt->list_node,
15165                     snaplevel_pool);
15166                 cur_elt->sl = level;
15167                 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15168                         uu_die(gettext("libuutil error: %s\n"),
15169                             uu_strerror(uu_error()));
15170 
15171                 level = scf_snaplevel_create(g_hndl);
15172                 if (level == NULL)
15173                         scfdie();
15174 
15175                 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15176                     level) != SCF_SUCCESS) {
15177                         if (scf_error() != SCF_ERROR_NOT_FOUND)
15178                                 scfdie();
15179 
15180                         scf_snaplevel_destroy(level);
15181                         break;
15182                 }
15183         }
15184 
15185         cur_elt = uu_list_last(cur_levels);
15186         cur_level = cur_elt->sl;
15187 }
15188 
15189 /*
15190  * Copies the properties & values in src to dst.  Assumes src won't change.
15191  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15192  * and 0 on success.
15193  *
15194  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15195  * property, if it is copied and has type boolean.  (See comment in
15196  * lscf_revert()).
15197  */
15198 static int
15199 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15200     uint8_t enabled)
15201 {
15202         scf_transaction_t *tx;
15203         scf_iter_t *iter, *viter;
15204         scf_property_t *prop;
15205         scf_value_t *v;
15206         char *nbuf;
15207         int r;
15208 
15209         tx = scf_transaction_create(g_hndl);
15210         if (tx == NULL)
15211                 scfdie();
15212 
15213         if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15214                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15215                         scfdie();
15216 
15217                 scf_transaction_destroy(tx);
15218 
15219                 return (-1);
15220         }
15221 
15222         if ((iter = scf_iter_create(g_hndl)) == NULL ||
15223             (prop = scf_property_create(g_hndl)) == NULL ||
15224             (viter = scf_iter_create(g_hndl)) == NULL)
15225                 scfdie();
15226 
15227         nbuf = safe_malloc(max_scf_name_len + 1);
15228 
15229         if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15230                 scfdie();
15231 
15232         for (;;) {
15233                 scf_transaction_entry_t *e;
15234                 scf_type_t ty;
15235 
15236                 r = scf_iter_next_property(iter, prop);
15237                 if (r == -1)
15238                         scfdie();
15239                 if (r == 0)
15240                         break;
15241 
15242                 e = scf_entry_create(g_hndl);
15243                 if (e == NULL)
15244                         scfdie();
15245 
15246                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15247                         scfdie();
15248 
15249                 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15250                         scfdie();
15251 
15252                 if (scf_transaction_property_new(tx, e, nbuf,
15253                     ty) != SCF_SUCCESS)
15254                         scfdie();
15255 
15256                 if ((enabled == 0 || enabled == 1) &&
15257                     strcmp(nbuf, scf_property_enabled) == 0 &&
15258                     ty == SCF_TYPE_BOOLEAN) {
15259                         v = scf_value_create(g_hndl);
15260                         if (v == NULL)
15261                                 scfdie();
15262 
15263                         scf_value_set_boolean(v, enabled);
15264 
15265                         if (scf_entry_add_value(e, v) != 0)
15266                                 scfdie();
15267                 } else {
15268                         if (scf_iter_property_values(viter, prop) != 0)
15269                                 scfdie();
15270 
15271                         for (;;) {
15272                                 v = scf_value_create(g_hndl);
15273                                 if (v == NULL)
15274                                         scfdie();
15275 
15276                                 r = scf_iter_next_value(viter, v);
15277                                 if (r == -1)
15278                                         scfdie();
15279                                 if (r == 0) {
15280                                         scf_value_destroy(v);
15281                                         break;
15282                                 }
15283 
15284                                 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15285                                         scfdie();
15286                         }
15287                 }
15288         }
15289 
15290         free(nbuf);
15291         scf_iter_destroy(viter);
15292         scf_property_destroy(prop);
15293         scf_iter_destroy(iter);
15294 
15295         r = scf_transaction_commit(tx);
15296         if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15297                 scfdie();
15298 
15299         scf_transaction_destroy_children(tx);
15300         scf_transaction_destroy(tx);
15301 
15302         switch (r) {
15303         case 1:         return (0);
15304         case 0:         return (-2);
15305         case -1:        return (-1);
15306 
15307         default:
15308                 abort();
15309         }
15310 
15311         /* NOTREACHED */
15312 }
15313 
15314 void
15315 lscf_revert(const char *snapname)
15316 {
15317         scf_snapshot_t *snap, *prev;
15318         scf_snaplevel_t *level, *nlevel;
15319         scf_iter_t *iter;
15320         scf_propertygroup_t *pg, *npg;
15321         scf_property_t *prop;
15322         scf_value_t *val;
15323         char *nbuf, *tbuf;
15324         uint8_t enabled;
15325 
15326         lscf_prep_hndl();
15327 
15328         if (cur_inst == NULL) {
15329                 semerr(gettext("Instance not selected.\n"));
15330                 return;
15331         }
15332 
15333         if (snapname != NULL) {
15334                 snap = scf_snapshot_create(g_hndl);
15335                 if (snap == NULL)
15336                         scfdie();
15337 
15338                 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15339                     SCF_SUCCESS) {
15340                         switch (scf_error()) {
15341                         case SCF_ERROR_INVALID_ARGUMENT:
15342                                 semerr(gettext("Invalid snapshot name "
15343                                     "\"%s\".\n"), snapname);
15344                                 break;
15345 
15346                         case SCF_ERROR_NOT_FOUND:
15347                                 semerr(gettext("No such snapshot.\n"));
15348                                 break;
15349 
15350                         default:
15351                                 scfdie();
15352                         }
15353 
15354                         scf_snapshot_destroy(snap);
15355                         return;
15356                 }
15357         } else {
15358                 if (cur_snap != NULL) {
15359                         snap = cur_snap;
15360                 } else {
15361                         semerr(gettext("No snapshot selected.\n"));
15362                         return;
15363                 }
15364         }
15365 
15366         if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15367             (level = scf_snaplevel_create(g_hndl)) == NULL ||
15368             (iter = scf_iter_create(g_hndl)) == NULL ||
15369             (pg = scf_pg_create(g_hndl)) == NULL ||
15370             (npg = scf_pg_create(g_hndl)) == NULL ||
15371             (prop = scf_property_create(g_hndl)) == NULL ||
15372             (val = scf_value_create(g_hndl)) == NULL)
15373                 scfdie();
15374 
15375         nbuf = safe_malloc(max_scf_name_len + 1);
15376         tbuf = safe_malloc(max_scf_pg_type_len + 1);
15377 
15378         /* Take the "previous" snapshot before we blow away the properties. */
15379         if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15380                 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15381                         scfdie();
15382         } else {
15383                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15384                         scfdie();
15385 
15386                 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15387                         scfdie();
15388         }
15389 
15390         /* Save general/enabled, since we're probably going to replace it. */
15391         enabled = 2;
15392         if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15393             scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15394             scf_property_get_value(prop, val) == 0)
15395                 (void) scf_value_get_boolean(val, &enabled);
15396 
15397         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15398                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15399                         scfdie();
15400 
15401                 goto out;
15402         }
15403 
15404         for (;;) {
15405                 boolean_t isinst;
15406                 uint32_t flags;
15407                 int r;
15408 
15409                 /* Clear the properties from the corresponding entity. */
15410                 isinst = snaplevel_is_instance(level);
15411 
15412                 if (!isinst)
15413                         r = scf_iter_service_pgs(iter, cur_svc);
15414                 else
15415                         r = scf_iter_instance_pgs(iter, cur_inst);
15416                 if (r != SCF_SUCCESS)
15417                         scfdie();
15418 
15419                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15420                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15421                                 scfdie();
15422 
15423                         /* Skip nonpersistent pgs. */
15424                         if (flags & SCF_PG_FLAG_NONPERSISTENT)
15425                                 continue;
15426 
15427                         if (scf_pg_delete(pg) != SCF_SUCCESS) {
15428                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15429                                         scfdie();
15430 
15431                                 semerr(emsg_permission_denied);
15432                                 goto out;
15433                         }
15434                 }
15435                 if (r == -1)
15436                         scfdie();
15437 
15438                 /* Copy the properties to the corresponding entity. */
15439                 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15440                         scfdie();
15441 
15442                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15443                         if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15444                                 scfdie();
15445 
15446                         if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15447                             0)
15448                                 scfdie();
15449 
15450                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15451                                 scfdie();
15452 
15453                         if (!isinst)
15454                                 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15455                                     flags, npg);
15456                         else
15457                                 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15458                                     flags, npg);
15459                         if (r != SCF_SUCCESS) {
15460                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15461                                         scfdie();
15462 
15463                                 semerr(emsg_permission_denied);
15464                                 goto out;
15465                         }
15466 
15467                         if ((enabled == 0 || enabled == 1) &&
15468                             strcmp(nbuf, scf_pg_general) == 0)
15469                                 r = pg_copy(pg, npg, enabled);
15470                         else
15471                                 r = pg_copy(pg, npg, 2);
15472 
15473                         switch (r) {
15474                         case 0:
15475                                 break;
15476 
15477                         case -1:
15478                                 semerr(emsg_permission_denied);
15479                                 goto out;
15480 
15481                         case -2:
15482                                 semerr(gettext(
15483                                     "Interrupted by another change.\n"));
15484                                 goto out;
15485 
15486                         default:
15487                                 abort();
15488                         }
15489                 }
15490                 if (r == -1)
15491                         scfdie();
15492 
15493                 /* Get next level. */
15494                 nlevel = scf_snaplevel_create(g_hndl);
15495                 if (nlevel == NULL)
15496                         scfdie();
15497 
15498                 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15499                     SCF_SUCCESS) {
15500                         if (scf_error() != SCF_ERROR_NOT_FOUND)
15501                                 scfdie();
15502 
15503                         scf_snaplevel_destroy(nlevel);
15504                         break;
15505                 }
15506 
15507                 scf_snaplevel_destroy(level);
15508                 level = nlevel;
15509         }
15510 
15511         if (snapname == NULL) {
15512                 lscf_selectsnap(NULL);
15513                 snap = NULL;            /* cur_snap has been destroyed */
15514         }
15515 
15516 out:
15517         free(tbuf);
15518         free(nbuf);
15519         scf_value_destroy(val);
15520         scf_property_destroy(prop);
15521         scf_pg_destroy(npg);
15522         scf_pg_destroy(pg);
15523         scf_iter_destroy(iter);
15524         scf_snaplevel_destroy(level);
15525         scf_snapshot_destroy(prev);
15526         if (snap != cur_snap)
15527                 scf_snapshot_destroy(snap);
15528 }
15529 
15530 void
15531 lscf_refresh(void)
15532 {
15533         ssize_t fmrilen;
15534         size_t bufsz;
15535         char *fmribuf;
15536         int r;
15537 
15538         lscf_prep_hndl();
15539 
15540         if (cur_inst == NULL) {
15541                 semerr(gettext("Instance not selected.\n"));
15542                 return;
15543         }
15544 
15545         bufsz = max_scf_fmri_len + 1;
15546         fmribuf = safe_malloc(bufsz);
15547         fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15548         if (fmrilen < 0) {
15549                 free(fmribuf);
15550                 if (scf_error() != SCF_ERROR_DELETED)
15551                         scfdie();
15552                 scf_instance_destroy(cur_inst);
15553                 cur_inst = NULL;
15554                 warn(emsg_deleted);
15555                 return;
15556         }
15557         assert(fmrilen < bufsz);
15558 
15559         r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15560         switch (r) {
15561         case 0:
15562                 break;
15563 
15564         case ECONNABORTED:
15565                 warn(gettext("Could not refresh %s "
15566                     "(repository connection broken).\n"), fmribuf);
15567                 break;
15568 
15569         case ECANCELED:
15570                 warn(emsg_deleted);
15571                 break;
15572 
15573         case EPERM:
15574                 warn(gettext("Could not refresh %s "
15575                     "(permission denied).\n"), fmribuf);
15576                 break;
15577 
15578         case ENOSPC:
15579                 warn(gettext("Could not refresh %s "
15580                     "(repository server out of resources).\n"),
15581                     fmribuf);
15582                 break;
15583 
15584         case EACCES:
15585         default:
15586                 bad_error("refresh_entity", scf_error());
15587         }
15588 
15589         free(fmribuf);
15590 }
15591 
15592 /*
15593  * describe [-v] [-t] [pg/prop]
15594  */
15595 int
15596 lscf_describe(uu_list_t *args, int hasargs)
15597 {
15598         int ret = 0;
15599         size_t i;
15600         int argc;
15601         char **argv = NULL;
15602         string_list_t *slp;
15603         int do_verbose = 0;
15604         int do_templates = 0;
15605         char *pattern = NULL;
15606 
15607         lscf_prep_hndl();
15608 
15609         if (hasargs != 0)  {
15610                 argc = uu_list_numnodes(args);
15611                 if (argc < 1)
15612                         goto usage;
15613 
15614                 argv = calloc(argc + 1, sizeof (char *));
15615                 if (argv == NULL)
15616                         uu_die(gettext("Out of memory.\n"));
15617 
15618                 for (slp = uu_list_first(args), i = 0;
15619                     slp != NULL;
15620                     slp = uu_list_next(args, slp), ++i)
15621                         argv[i] = slp->str;
15622 
15623                 argv[i] = NULL;
15624 
15625                 /*
15626                  * We start optind = 0 because our list of arguments
15627                  * starts at argv[0]
15628                  */
15629                 optind = 0;
15630                 opterr = 0;
15631                 for (;;) {
15632                         ret = getopt(argc, argv, "vt");
15633                         if (ret == -1)
15634                                 break;
15635 
15636                         switch (ret) {
15637                         case 'v':
15638                                 do_verbose = 1;
15639                                 break;
15640 
15641                         case 't':
15642                                 do_templates = 1;
15643                                 break;
15644 
15645                         case '?':
15646                                 goto usage;
15647 
15648                         default:
15649                                 bad_error("getopt", ret);
15650                         }
15651                 }
15652 
15653                 pattern = argv[optind];
15654         }
15655 
15656         if (cur_inst == NULL && cur_svc == NULL) {
15657                 semerr(emsg_entity_not_selected);
15658                 ret = -1;
15659                 goto out;
15660         }
15661 
15662         /*
15663          * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15664          * output if their last parameter is set to 2.  Less information is
15665          * produced if the parameter is set to 1.
15666          */
15667         if (pattern == NULL) {
15668                 if (do_verbose == 1)
15669                         list_entity_tmpl(2);
15670                 else
15671                         list_entity_tmpl(1);
15672         }
15673 
15674         if (do_templates == 0) {
15675                 if (do_verbose == 1)
15676                         listprop(pattern, 0, 2);
15677                 else
15678                         listprop(pattern, 0, 1);
15679         } else {
15680                 if (do_verbose == 1)
15681                         listtmpl(pattern, 2);
15682                 else
15683                         listtmpl(pattern, 1);
15684         }
15685 
15686         ret = 0;
15687 out:
15688         if (argv != NULL)
15689                 free(argv);
15690         return (ret);
15691 usage:
15692         ret = -2;
15693         goto out;
15694 }
15695 
15696 #define PARAM_ACTIVE    ((const char *) "active")
15697 #define PARAM_INACTIVE  ((const char *) "inactive")
15698 #define PARAM_SMTP_TO   ((const char *) "to")
15699 
15700 /*
15701  * tokenize()
15702  * Breaks down the string according to the tokens passed.
15703  * Caller is responsible for freeing array of pointers returned.
15704  * Returns NULL on failure
15705  */
15706 char **
15707 tokenize(char *str, const char *sep)
15708 {
15709         char *token, *lasts;
15710         char **buf;
15711         int n = 0;      /* number of elements */
15712         int size = 8;   /* size of the array (initial) */
15713 
15714         buf = safe_malloc(size * sizeof (char *));
15715 
15716         for (token = strtok_r(str, sep, &lasts); token != NULL;
15717             token = strtok_r(NULL, sep, &lasts), ++n) {
15718                 if (n + 1 >= size) {
15719                         size *= 2;
15720                         if ((buf = realloc(buf, size * sizeof (char *))) ==
15721                             NULL) {
15722                                 uu_die(gettext("Out of memory"));
15723                         }
15724                 }
15725                 buf[n] = token;
15726         }
15727         /* NULL terminate the pointer array */
15728         buf[n] = NULL;
15729 
15730         return (buf);
15731 }
15732 
15733 int32_t
15734 check_tokens(char **p)
15735 {
15736         int32_t smf = 0;
15737         int32_t fma = 0;
15738 
15739         while (*p) {
15740                 int32_t t = string_to_tset(*p);
15741 
15742                 if (t == 0) {
15743                         if (is_fma_token(*p) == 0)
15744                                 return (INVALID_TOKENS);
15745                         fma = 1; /* this token is an fma event */
15746                 } else {
15747                         smf |= t;
15748                 }
15749 
15750                 if (smf != 0 && fma == 1)
15751                         return (MIXED_TOKENS);
15752                 ++p;
15753         }
15754 
15755         if (smf > 0)
15756                 return (smf);
15757         else if (fma == 1)
15758                 return (FMA_TOKENS);
15759 
15760         return (INVALID_TOKENS);
15761 }
15762 
15763 static int
15764 get_selection_str(char *fmri, size_t sz)
15765 {
15766         if (g_hndl == NULL) {
15767                 semerr(emsg_entity_not_selected);
15768                 return (-1);
15769         } else if (cur_level != NULL) {
15770                 semerr(emsg_invalid_for_snapshot);
15771                 return (-1);
15772         } else {
15773                 lscf_get_selection_str(fmri, sz);
15774         }
15775 
15776         return (0);
15777 }
15778 
15779 void
15780 lscf_delnotify(const char *set, int global)
15781 {
15782         char *str = strdup(set);
15783         char **pgs;
15784         char **p;
15785         int32_t tset;
15786         char *fmri = NULL;
15787 
15788         if (str == NULL)
15789                 uu_die(gettext("Out of memory.\n"));
15790 
15791         pgs = tokenize(str, ",");
15792 
15793         if ((tset = check_tokens(pgs)) > 0) {
15794                 size_t sz = max_scf_fmri_len + 1;
15795 
15796                 fmri = safe_malloc(sz);
15797                 if (global) {
15798                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15799                 } else if (get_selection_str(fmri, sz) != 0) {
15800                         goto out;
15801                 }
15802 
15803                 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15804                     tset) != SCF_SUCCESS) {
15805                         uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15806                             scf_strerror(scf_error()));
15807                 }
15808         } else if (tset == FMA_TOKENS) {
15809                 if (global) {
15810                         semerr(gettext("Can't use option '-g' with FMA event "
15811                             "definitions\n"));
15812                         goto out;
15813                 }
15814 
15815                 for (p = pgs; *p; ++p) {
15816                         if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15817                             SCF_SUCCESS) {
15818                                 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15819                                     scf_strerror(scf_error()));
15820                                 goto out;
15821                         }
15822                 }
15823         } else if (tset == MIXED_TOKENS) {
15824                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15825                 goto out;
15826         } else {
15827                 uu_die(gettext("Invalid input.\n"));
15828         }
15829 
15830 out:
15831         free(fmri);
15832         free(pgs);
15833         free(str);
15834 }
15835 
15836 void
15837 lscf_listnotify(const char *set, int global)
15838 {
15839         char *str = safe_strdup(set);
15840         char **pgs;
15841         char **p;
15842         int32_t tset;
15843         nvlist_t *nvl;
15844         char *fmri = NULL;
15845 
15846         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15847                 uu_die(gettext("Out of memory.\n"));
15848 
15849         pgs = tokenize(str, ",");
15850 
15851         if ((tset = check_tokens(pgs)) > 0) {
15852                 size_t sz = max_scf_fmri_len + 1;
15853 
15854                 fmri = safe_malloc(sz);
15855                 if (global) {
15856                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15857                 } else if (get_selection_str(fmri, sz) != 0) {
15858                         goto out;
15859                 }
15860 
15861                 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15862                     SCF_SUCCESS) {
15863                         if (scf_error() != SCF_ERROR_NOT_FOUND &&
15864                             scf_error() != SCF_ERROR_DELETED)
15865                                 uu_warn(gettext(
15866                                     "Failed listnotify: %s\n"),
15867                                     scf_strerror(scf_error()));
15868                         goto out;
15869                 }
15870 
15871                 listnotify_print(nvl, NULL);
15872         } else if (tset == FMA_TOKENS) {
15873                 if (global) {
15874                         semerr(gettext("Can't use option '-g' with FMA event "
15875                             "definitions\n"));
15876                         goto out;
15877                 }
15878 
15879                 for (p = pgs; *p; ++p) {
15880                         if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15881                             SCF_SUCCESS) {
15882                                 /*
15883                                  * if the preferences have just been deleted
15884                                  * or does not exist, just skip.
15885                                  */
15886                                 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15887                                     scf_error() == SCF_ERROR_DELETED)
15888                                         continue;
15889                                 uu_warn(gettext(
15890                                     "Failed listnotify: %s\n"),
15891                                     scf_strerror(scf_error()));
15892                                 goto out;
15893                         }
15894                         listnotify_print(nvl, re_tag(*p));
15895                 }
15896         } else if (tset == MIXED_TOKENS) {
15897                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15898                 goto out;
15899         } else {
15900                 semerr(gettext("Invalid input.\n"));
15901         }
15902 
15903 out:
15904         nvlist_free(nvl);
15905         free(fmri);
15906         free(pgs);
15907         free(str);
15908 }
15909 
15910 static char *
15911 strip_quotes_and_blanks(char *s)
15912 {
15913         char *start = s;
15914         char *end = strrchr(s, '\"');
15915 
15916         if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15917                 start = s + 1;
15918                 while (isblank(*start))
15919                         start++;
15920                 while (isblank(*(end - 1)) && end > start) {
15921                         end--;
15922                 }
15923                 *end = '\0';
15924         }
15925 
15926         return (start);
15927 }
15928 
15929 static int
15930 set_active(nvlist_t *mech, const char *hier_part)
15931 {
15932         boolean_t b;
15933 
15934         if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15935                 b = B_TRUE;
15936         } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15937                 b = B_FALSE;
15938         } else {
15939                 return (-1);
15940         }
15941 
15942         if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15943                 uu_die(gettext("Out of memory.\n"));
15944 
15945         return (0);
15946 }
15947 
15948 static int
15949 add_snmp_params(nvlist_t *mech, char *hier_part)
15950 {
15951         return (set_active(mech, hier_part));
15952 }
15953 
15954 static int
15955 add_syslog_params(nvlist_t *mech, char *hier_part)
15956 {
15957         return (set_active(mech, hier_part));
15958 }
15959 
15960 /*
15961  * add_mailto_paramas()
15962  * parse the hier_part of mailto URI
15963  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15964  * or mailto:{[active]|inactive}
15965  */
15966 static int
15967 add_mailto_params(nvlist_t *mech, char *hier_part)
15968 {
15969         const char *tok = "?&";
15970         char *p;
15971         char *lasts;
15972         char *param;
15973         char *val;
15974 
15975         /*
15976          * If the notification parametes are in the form of
15977          *
15978          *   malito:{[active]|inactive}
15979          *
15980          * we set the property accordingly and return.
15981          * Otherwise, we make the notification type active and
15982          * process the hier_part.
15983          */
15984         if (set_active(mech, hier_part) == 0)
15985                 return (0);
15986         else if (set_active(mech, PARAM_ACTIVE) != 0)
15987                 return (-1);
15988 
15989         if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15990                 /*
15991                  * sanity check: we only get here if hier_part = "", but
15992                  * that's handled by set_active
15993                  */
15994                 uu_die("strtok_r");
15995         }
15996 
15997         if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15998                 uu_die(gettext("Out of memory.\n"));
15999 
16000         while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16001                 if ((param = strtok_r(p, "=", &val)) != NULL)
16002                         if (nvlist_add_string(mech, param, val) != 0)
16003                                 uu_die(gettext("Out of memory.\n"));
16004 
16005         return (0);
16006 }
16007 
16008 static int
16009 uri_split(char *uri, char **scheme, char **hier_part)
16010 {
16011         int r = -1;
16012 
16013         if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16014             *hier_part == NULL) {
16015                 semerr(gettext("'%s' is not an URI\n"), uri);
16016                 return (r);
16017         }
16018 
16019         if ((r = check_uri_scheme(*scheme)) < 0) {
16020                 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16021                 return (r);
16022         }
16023 
16024         return (r);
16025 }
16026 
16027 static int
16028 process_uri(nvlist_t *params, char *uri)
16029 {
16030         char *scheme;
16031         char *hier_part;
16032         nvlist_t *mech;
16033         int index;
16034         int r;
16035 
16036         if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16037                 return (-1);
16038 
16039         if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16040                 uu_die(gettext("Out of memory.\n"));
16041 
16042         switch (index) {
16043         case 0:
16044                 /* error messages displayed by called function */
16045                 r = add_mailto_params(mech, hier_part);
16046                 break;
16047 
16048         case 1:
16049                 if ((r = add_snmp_params(mech, hier_part)) != 0)
16050                         semerr(gettext("Not valid parameters: '%s'\n"),
16051                             hier_part);
16052                 break;
16053 
16054         case 2:
16055                 if ((r = add_syslog_params(mech, hier_part)) != 0)
16056                         semerr(gettext("Not valid parameters: '%s'\n"),
16057                             hier_part);
16058                 break;
16059 
16060         default:
16061                 r = -1;
16062         }
16063 
16064         if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16065             mech) != 0)
16066                 uu_die(gettext("Out of memory.\n"));
16067 
16068         nvlist_free(mech);
16069         return (r);
16070 }
16071 
16072 static int
16073 set_params(nvlist_t *params, char **p)
16074 {
16075         char *uri;
16076 
16077         if (p == NULL)
16078                 /* sanity check */
16079                 uu_die("set_params");
16080 
16081         while (*p) {
16082                 uri = strip_quotes_and_blanks(*p);
16083                 if (process_uri(params, uri) != 0)
16084                         return (-1);
16085 
16086                 ++p;
16087         }
16088 
16089         return (0);
16090 }
16091 
16092 static int
16093 setnotify(const char *e, char **p, int global)
16094 {
16095         char *str = safe_strdup(e);
16096         char **events;
16097         int32_t tset;
16098         int r = -1;
16099         nvlist_t *nvl, *params;
16100         char *fmri = NULL;
16101 
16102         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16103             nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16104             nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16105             SCF_NOTIFY_PARAMS_VERSION) != 0)
16106                 uu_die(gettext("Out of memory.\n"));
16107 
16108         events = tokenize(str, ",");
16109 
16110         if ((tset = check_tokens(events)) > 0) {
16111                 /* SMF state transitions parameters */
16112                 size_t sz = max_scf_fmri_len + 1;
16113 
16114                 fmri = safe_malloc(sz);
16115                 if (global) {
16116                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16117                 } else if (get_selection_str(fmri, sz) != 0) {
16118                         goto out;
16119                 }
16120 
16121                 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16122                     nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16123                         uu_die(gettext("Out of memory.\n"));
16124 
16125                 if ((r = set_params(params, p)) == 0) {
16126                         if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16127                             params) != 0)
16128                                 uu_die(gettext("Out of memory.\n"));
16129 
16130                         if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16131                             nvl) != SCF_SUCCESS) {
16132                                 r = -1;
16133                                 uu_warn(gettext(
16134                                     "Failed smf_notify_set_params(3SCF): %s\n"),
16135                                     scf_strerror(scf_error()));
16136                         }
16137                 }
16138         } else if (tset == FMA_TOKENS) {
16139                 /* FMA event parameters */
16140                 if (global) {
16141                         semerr(gettext("Can't use option '-g' with FMA event "
16142                             "definitions\n"));
16143                         goto out;
16144                 }
16145 
16146                 if ((r = set_params(params, p)) != 0)
16147                         goto out;
16148 
16149                 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16150                         uu_die(gettext("Out of memory.\n"));
16151 
16152                 while (*events) {
16153                         if (smf_notify_set_params(de_tag(*events), nvl) !=
16154                             SCF_SUCCESS)
16155                                 uu_warn(gettext(
16156                                     "Failed smf_notify_set_params(3SCF) for "
16157                                     "event %s: %s\n"), *events,
16158                                     scf_strerror(scf_error()));
16159                         events++;
16160                 }
16161         } else if (tset == MIXED_TOKENS) {
16162                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16163         } else {
16164                 /* Sanity check */
16165                 uu_die(gettext("Invalid input.\n"));
16166         }
16167 
16168 out:
16169         nvlist_free(nvl);
16170         nvlist_free(params);
16171         free(fmri);
16172         free(str);
16173 
16174         return (r);
16175 }
16176 
16177 int
16178 lscf_setnotify(uu_list_t *args)
16179 {
16180         int argc;
16181         char **argv = NULL;
16182         string_list_t *slp;
16183         int global;
16184         char *events;
16185         char **p;
16186         int i;
16187         int ret;
16188 
16189         if ((argc = uu_list_numnodes(args)) < 2)
16190                 goto usage;
16191 
16192         argv = calloc(argc + 1, sizeof (char *));
16193         if (argv == NULL)
16194                 uu_die(gettext("Out of memory.\n"));
16195 
16196         for (slp = uu_list_first(args), i = 0;
16197             slp != NULL;
16198             slp = uu_list_next(args, slp), ++i)
16199                 argv[i] = slp->str;
16200 
16201         argv[i] = NULL;
16202 
16203         if (strcmp(argv[0], "-g") == 0) {
16204                 global = 1;
16205                 events = argv[1];
16206                 p = argv + 2;
16207         } else {
16208                 global = 0;
16209                 events = argv[0];
16210                 p = argv + 1;
16211         }
16212 
16213         ret = setnotify(events, p, global);
16214 
16215 out:
16216         free(argv);
16217         return (ret);
16218 
16219 usage:
16220         ret = -2;
16221         goto out;
16222 }
16223 
16224 /*
16225  * Creates a list of instance name strings associated with a service. If
16226  * wohandcrafted flag is set, get only instances that have a last-import
16227  * snapshot, instances that were imported via svccfg.
16228  */
16229 static uu_list_t *
16230 create_instance_list(scf_service_t *svc, int wohandcrafted)
16231 {
16232         scf_snapshot_t  *snap = NULL;
16233         scf_instance_t  *inst;
16234         scf_iter_t      *inst_iter;
16235         uu_list_t       *instances;
16236         char            *instname;
16237         int             r;
16238 
16239         inst_iter = scf_iter_create(g_hndl);
16240         inst = scf_instance_create(g_hndl);
16241         if (inst_iter == NULL || inst == NULL) {
16242                 uu_warn(gettext("Could not create instance or iterator\n"));
16243                 scfdie();
16244         }
16245 
16246         if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16247                 return (instances);
16248 
16249         if (scf_iter_service_instances(inst_iter, svc) != 0) {
16250                 switch (scf_error()) {
16251                 case SCF_ERROR_CONNECTION_BROKEN:
16252                 case SCF_ERROR_DELETED:
16253                         uu_list_destroy(instances);
16254                         instances = NULL;
16255                         goto out;
16256 
16257                 case SCF_ERROR_HANDLE_MISMATCH:
16258                 case SCF_ERROR_NOT_BOUND:
16259                 case SCF_ERROR_NOT_SET:
16260                 default:
16261                         bad_error("scf_iter_service_instances", scf_error());
16262                 }
16263         }
16264 
16265         instname = safe_malloc(max_scf_name_len + 1);
16266         while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16267                 if (r == -1) {
16268                         (void) uu_warn(gettext("Unable to iterate through "
16269                             "instances to create instance list : %s\n"),
16270                             scf_strerror(scf_error()));
16271 
16272                         uu_list_destroy(instances);
16273                         instances = NULL;
16274                         goto out;
16275                 }
16276 
16277                 /*
16278                  * If the instance does not have a last-import snapshot
16279                  * then do not add it to the list as it is a hand-crafted
16280                  * instance that should not be managed.
16281                  */
16282                 if (wohandcrafted) {
16283                         if (snap == NULL &&
16284                             (snap = scf_snapshot_create(g_hndl)) == NULL) {
16285                                 uu_warn(gettext("Unable to create snapshot "
16286                                     "entity\n"));
16287                                 scfdie();
16288                         }
16289 
16290                         if (scf_instance_get_snapshot(inst,
16291                             snap_lastimport, snap) != 0) {
16292                                 switch (scf_error()) {
16293                                 case SCF_ERROR_NOT_FOUND :
16294                                 case SCF_ERROR_DELETED:
16295                                         continue;
16296 
16297                                 case SCF_ERROR_CONNECTION_BROKEN:
16298                                         uu_list_destroy(instances);
16299                                         instances = NULL;
16300                                         goto out;
16301 
16302                                 case SCF_ERROR_HANDLE_MISMATCH:
16303                                 case SCF_ERROR_NOT_BOUND:
16304                                 case SCF_ERROR_NOT_SET:
16305                                 default:
16306                                         bad_error("scf_iter_service_instances",
16307                                             scf_error());
16308                                 }
16309                         }
16310                 }
16311 
16312                 if (scf_instance_get_name(inst, instname,
16313                     max_scf_name_len + 1) < 0) {
16314                         switch (scf_error()) {
16315                         case SCF_ERROR_NOT_FOUND :
16316                                 continue;
16317 
16318                         case SCF_ERROR_CONNECTION_BROKEN:
16319                         case SCF_ERROR_DELETED:
16320                                 uu_list_destroy(instances);
16321                                 instances = NULL;
16322                                 goto out;
16323 
16324                         case SCF_ERROR_HANDLE_MISMATCH:
16325                         case SCF_ERROR_NOT_BOUND:
16326                         case SCF_ERROR_NOT_SET:
16327                         default:
16328                                 bad_error("scf_iter_service_instances",
16329                                     scf_error());
16330                         }
16331                 }
16332 
16333                 add_string(instances, instname);
16334         }
16335 
16336 out:
16337         if (snap)
16338                 scf_snapshot_destroy(snap);
16339 
16340         scf_instance_destroy(inst);
16341         scf_iter_destroy(inst_iter);
16342         free(instname);
16343         return (instances);
16344 }
16345 
16346 /*
16347  * disable an instance but wait for the instance to
16348  * move out of the running state.
16349  *
16350  * Returns 0 : if the instance did not disable
16351  * Returns non-zero : if the instance disabled.
16352  *
16353  */
16354 static int
16355 disable_instance(scf_instance_t *instance)
16356 {
16357         char    *fmribuf;
16358         int     enabled = 10000;
16359 
16360         if (inst_is_running(instance)) {
16361                 fmribuf = safe_malloc(max_scf_name_len + 1);
16362                 if (scf_instance_to_fmri(instance, fmribuf,
16363                     max_scf_name_len + 1) < 0) {
16364                         free(fmribuf);
16365                         return (0);
16366                 }
16367 
16368                 /*
16369                  * If the instance cannot be disabled then return
16370                  * failure to disable and let the caller decide
16371                  * if that is of importance.
16372                  */
16373                 if (smf_disable_instance(fmribuf, 0) != 0) {
16374                         free(fmribuf);
16375                         return (0);
16376                 }
16377 
16378                 while (enabled) {
16379                         if (!inst_is_running(instance))
16380                                 break;
16381 
16382                         (void) poll(NULL, 0, 5);
16383                         enabled = enabled - 5;
16384                 }
16385 
16386                 free(fmribuf);
16387         }
16388 
16389         return (enabled);
16390 }
16391 
16392 /*
16393  * Function to compare two service_manifest structures.
16394  */
16395 /* ARGSUSED2 */
16396 static int
16397 service_manifest_compare(const void *left, const void *right, void *unused)
16398 {
16399         service_manifest_t *l = (service_manifest_t *)left;
16400         service_manifest_t *r = (service_manifest_t *)right;
16401         int rc;
16402 
16403         rc = strcmp(l->servicename, r->servicename);
16404 
16405         return (rc);
16406 }
16407 
16408 /*
16409  * Look for the provided service in the service to manifest
16410  * tree.  If the service exists, and a manifest was provided
16411  * then add the manifest to that service.  If the service
16412  * does not exist, then add the service and manifest to the
16413  * list.
16414  *
16415  * If the manifest is NULL, return the element if found.  If
16416  * the service is not found return NULL.
16417  */
16418 service_manifest_t *
16419 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16420 {
16421         service_manifest_t      elem;
16422         service_manifest_t      *fnelem;
16423         uu_avl_index_t          marker;
16424 
16425         elem.servicename = svnbuf;
16426         fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16427 
16428         if (mfst) {
16429                 if (fnelem) {
16430                         add_string(fnelem->mfstlist, strdup(mfst));
16431                 } else {
16432                         fnelem = safe_malloc(sizeof (*fnelem));
16433                         fnelem->servicename = safe_strdup(svnbuf);
16434                         if ((fnelem->mfstlist =
16435                             uu_list_create(string_pool, NULL, 0)) == NULL)
16436                                 uu_die(gettext("Could not create property "
16437                                     "list: %s\n"), uu_strerror(uu_error()));
16438 
16439                         add_string(fnelem->mfstlist, safe_strdup(mfst));
16440 
16441                         uu_avl_insert(service_manifest_tree, fnelem, marker);
16442                 }
16443         }
16444 
16445         return (fnelem);
16446 }
16447 
16448 /*
16449  * Create the service to manifest avl tree.
16450  *
16451  * Walk each of the manifests currently installed in the supported
16452  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16453  * each of the manifests, inventory the services and add them to
16454  * the tree.
16455  *
16456  * Code that calls this function should make sure fileystem/minimal is online,
16457  * /var is available, since this function walks the /var/svc/manifest directory.
16458  */
16459 static void
16460 create_manifest_tree(void)
16461 {
16462         manifest_info_t **entry;
16463         manifest_info_t **manifests;
16464         uu_list_walk_t  *svcs;
16465         bundle_t        *b;
16466         entity_t        *mfsvc;
16467         char            *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16468         int             c, status;
16469 
16470         if (service_manifest_pool)
16471                 return;
16472 
16473         /*
16474          * Create the list pool for the service manifest list
16475          */
16476         service_manifest_pool = uu_avl_pool_create("service_manifest",
16477             sizeof (service_manifest_t),
16478             offsetof(service_manifest_t, svcmfst_node),
16479             service_manifest_compare, UU_DEFAULT);
16480         if (service_manifest_pool == NULL)
16481                 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16482                     uu_strerror(uu_error()));
16483 
16484         /*
16485          * Create the list
16486          */
16487         service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16488             UU_DEFAULT);
16489         if (service_manifest_tree == NULL)
16490                 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16491                     uu_strerror(uu_error()));
16492 
16493         /*
16494          * Walk the manifests adding the service(s) from each manifest.
16495          *
16496          * If a service already exists add the manifest to the manifest
16497          * list for that service.  This covers the case of a service that
16498          * is supported by multiple manifest files.
16499          */
16500         for (c = 0; dirs[c]; c++) {
16501                 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16502                 if (status < 0) {
16503                         uu_warn(gettext("file tree walk of %s encountered "
16504                             "error %s\n"), dirs[c], strerror(errno));
16505 
16506                         uu_avl_destroy(service_manifest_tree);
16507                         service_manifest_tree = NULL;
16508                         return;
16509                 }
16510 
16511                 /*
16512                  * If a manifest that was in the list is not found
16513                  * then skip and go to the next manifest file.
16514                  */
16515                 if (manifests != NULL) {
16516                         for (entry = manifests; *entry != NULL; entry++) {
16517                                 b = internal_bundle_new();
16518                                 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16519                                     SVCCFG_OP_IMPORT) != 0) {
16520                                         internal_bundle_free(b);
16521                                         continue;
16522                                 }
16523 
16524                                 svcs = uu_list_walk_start(b->sc_bundle_services,
16525                                     0);
16526                                 if (svcs == NULL) {
16527                                         internal_bundle_free(b);
16528                                         continue;
16529                                 }
16530 
16531                                 while ((mfsvc = uu_list_walk_next(svcs)) !=
16532                                     NULL) {
16533                                         /* Add manifest to service */
16534                                         (void) find_add_svc_mfst(mfsvc->sc_name,
16535                                             (*entry)->mi_path);
16536                                 }
16537 
16538                                 uu_list_walk_end(svcs);
16539                                 internal_bundle_free(b);
16540                         }
16541 
16542                         free_manifest_array(manifests);
16543                 }
16544         }
16545 }
16546 
16547 /*
16548  * Check the manifest history file to see
16549  * if the service was ever installed from
16550  * one of the supported directories.
16551  *
16552  * Return Values :
16553  *      -1 - if there's error reading manifest history file
16554  *       1 - if the service is not found
16555  *       0 - if the service is found
16556  */
16557 static int
16558 check_mfst_history(const char *svcname)
16559 {
16560         struct stat     st;
16561         caddr_t         mfsthist_start;
16562         char            *svnbuf;
16563         int             fd;
16564         int             r = 1;
16565 
16566         fd = open(MFSTHISTFILE, O_RDONLY);
16567         if (fd == -1) {
16568                 uu_warn(gettext("Unable to open the history file\n"));
16569                 return (-1);
16570         }
16571 
16572         if (fstat(fd, &st) == -1) {
16573                 uu_warn(gettext("Unable to stat the history file\n"));
16574                 return (-1);
16575         }
16576 
16577         mfsthist_start = mmap(0, st.st_size, PROT_READ,
16578             MAP_PRIVATE, fd, 0);
16579 
16580         (void) close(fd);
16581         if (mfsthist_start == MAP_FAILED ||
16582             *(mfsthist_start + st.st_size) != '\0') {
16583                 (void) munmap(mfsthist_start, st.st_size);
16584                 return (-1);
16585         }
16586 
16587         /*
16588          * The manifest history file is a space delimited list
16589          * of service and instance to manifest linkage.  Adding
16590          * a space to the end of the service name so to get only
16591          * the service that is being searched for.
16592          */
16593         svnbuf = uu_msprintf("%s ", svcname);
16594         if (svnbuf == NULL)
16595                 uu_die(gettext("Out of memory"));
16596 
16597         if (strstr(mfsthist_start, svnbuf) != NULL)
16598                 r = 0;
16599 
16600         (void) munmap(mfsthist_start, st.st_size);
16601         uu_free(svnbuf);
16602         return (r);
16603 }
16604 
16605 /*
16606  * Take down each of the instances in the service
16607  * and remove them, then delete the service.
16608  */
16609 static void
16610 teardown_service(scf_service_t *svc, const char *svnbuf)
16611 {
16612         scf_instance_t  *instance;
16613         scf_iter_t      *iter;
16614         int             r;
16615 
16616         safe_printf(gettext("Delete service %s as there are no "
16617             "supporting manifests\n"), svnbuf);
16618 
16619         instance = scf_instance_create(g_hndl);
16620         iter = scf_iter_create(g_hndl);
16621         if (iter == NULL || instance == NULL) {
16622                 uu_warn(gettext("Unable to create supporting entities to "
16623                     "teardown the service\n"));
16624                 uu_warn(gettext("scf error is : %s\n"),
16625                     scf_strerror(scf_error()));
16626                 scfdie();
16627         }
16628 
16629         if (scf_iter_service_instances(iter, svc) != 0) {
16630                 switch (scf_error()) {
16631                 case SCF_ERROR_CONNECTION_BROKEN:
16632                 case SCF_ERROR_DELETED:
16633                         goto out;
16634 
16635                 case SCF_ERROR_HANDLE_MISMATCH:
16636                 case SCF_ERROR_NOT_BOUND:
16637                 case SCF_ERROR_NOT_SET:
16638                 default:
16639                         bad_error("scf_iter_service_instances",
16640                             scf_error());
16641                 }
16642         }
16643 
16644         while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16645                 if (r == -1) {
16646                         uu_warn(gettext("Error - %s\n"),
16647                             scf_strerror(scf_error()));
16648                         goto out;
16649                 }
16650 
16651                 (void) disable_instance(instance);
16652         }
16653 
16654         /*
16655          * Delete the service... forcing the deletion in case
16656          * any of the instances did not disable.
16657          */
16658         (void) lscf_service_delete(svc, 1);
16659 out:
16660         scf_instance_destroy(instance);
16661         scf_iter_destroy(iter);
16662 }
16663 
16664 /*
16665  * Get the list of instances supported by the manifest
16666  * file.
16667  *
16668  * Return 0 if there are no instances.
16669  *
16670  * Return -1 if there are errors attempting to collect instances.
16671  *
16672  * Return the count of instances found if there are no errors.
16673  *
16674  */
16675 static int
16676 check_instance_support(char *mfstfile, const char *svcname,
16677     uu_list_t *instances)
16678 {
16679         uu_list_walk_t  *svcs, *insts;
16680         uu_list_t       *ilist;
16681         bundle_t        *b;
16682         entity_t        *mfsvc, *mfinst;
16683         const char      *svcn;
16684         int             rminstcnt = 0;
16685 
16686 
16687         b = internal_bundle_new();
16688 
16689         if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16690                 /*
16691                  * Unable to process the manifest file for
16692                  * instance support, so just return as
16693                  * don't want to remove instances that could
16694                  * not be accounted for that might exist here.
16695                  */
16696                 internal_bundle_free(b);
16697                 return (0);
16698         }
16699 
16700         svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16701         if (svcs == NULL) {
16702                 internal_bundle_free(b);
16703                 return (0);
16704         }
16705 
16706         svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16707             (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16708 
16709         while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16710                 if (strcmp(mfsvc->sc_name, svcn) == 0)
16711                         break;
16712         }
16713         uu_list_walk_end(svcs);
16714 
16715         if (mfsvc == NULL) {
16716                 internal_bundle_free(b);
16717                 return (-1);
16718         }
16719 
16720         ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16721         if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16722                 internal_bundle_free(b);
16723                 return (0);
16724         }
16725 
16726         while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16727                 /*
16728                  * Remove the instance from the instances list.
16729                  * The unaccounted for instances will be removed
16730                  * from the service once all manifests are
16731                  * processed.
16732                  */
16733                 (void) remove_string(instances,
16734                     mfinst->sc_name);
16735                 rminstcnt++;
16736         }
16737 
16738         uu_list_walk_end(insts);
16739         internal_bundle_free(b);
16740 
16741         return (rminstcnt);
16742 }
16743 
16744 /*
16745  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16746  * 'false' to indicate there's no manifest file(s) found for the service.
16747  */
16748 static void
16749 svc_add_no_support(scf_service_t *svc)
16750 {
16751         char    *pname;
16752 
16753         /* Add no support */
16754         cur_svc = svc;
16755         if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16756                 return;
16757 
16758         pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16759         if (pname == NULL)
16760                 uu_die(gettext("Out of memory.\n"));
16761 
16762         (void) lscf_addpropvalue(pname, "boolean:", "0");
16763 
16764         uu_free(pname);
16765         cur_svc = NULL;
16766 }
16767 
16768 /*
16769  * This function handles all upgrade scenarios for a service that doesn't have
16770  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16771  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16772  * manifest(s) mapping. Manifests under supported directories are inventoried
16773  * and a property is added for each file that delivers configuration to the
16774  * service.  A service that has no corresponding manifest files (deleted) are
16775  * removed from repository.
16776  *
16777  * Unsupported services:
16778  *
16779  * A service is considered unsupported if there is no corresponding manifest
16780  * in the supported directories for that service and the service isn't in the
16781  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16782  * services and instances that were delivered by Solaris before the introduction
16783  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16784  * the path to the manifest file that defined the service or instance.
16785  *
16786  * Another type of unsupported services is 'handcrafted' services,
16787  * programmatically created services or services created by dependent entries
16788  * in other manifests. A handcrafted service is identified by its lack of any
16789  * instance containing last-import snapshot which is created during svccfg
16790  * import.
16791  *
16792  * This function sets a flag for unsupported services by setting services'
16793  * SCF_PG_MANIFESTFILES/support property to false.
16794  */
16795 static void
16796 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16797 {
16798         service_manifest_t      *elem;
16799         uu_list_walk_t          *mfwalk;
16800         string_list_t           *mfile;
16801         uu_list_t               *instances;
16802         const char              *sname;
16803         char                    *pname;
16804         int                     r;
16805 
16806         /*
16807          * Since there's no guarantee manifests under /var are available during
16808          * early import, don't perform any upgrade during early import.
16809          */
16810         if (IGNORE_VAR)
16811                 return;
16812 
16813         if (service_manifest_tree == NULL) {
16814                 create_manifest_tree();
16815         }
16816 
16817         /*
16818          * Find service's supporting manifest(s) after
16819          * stripping off the svc:/ prefix that is part
16820          * of the fmri that is not used in the service
16821          * manifest bundle list.
16822          */
16823         sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16824             strlen(SCF_FMRI_SERVICE_PREFIX);
16825         elem = find_add_svc_mfst(sname, NULL);
16826         if (elem == NULL) {
16827 
16828                 /*
16829                  * A handcrafted service, one that has no instance containing
16830                  * last-import snapshot, should get unsupported flag.
16831                  */
16832                 instances = create_instance_list(svc, 1);
16833                 if (instances == NULL) {
16834                         uu_warn(gettext("Unable to create instance list %s\n"),
16835                             svcname);
16836                         return;
16837                 }
16838 
16839                 if (uu_list_numnodes(instances) == 0) {
16840                         svc_add_no_support(svc);
16841                         return;
16842                 }
16843 
16844                 /*
16845                  * If the service is in the history file, and its supporting
16846                  * manifests are not found, we can safely delete the service
16847                  * because its manifests are removed from the system.
16848                  *
16849                  * Services not found in the history file are not delivered by
16850                  * Solaris and/or delivered outside supported directories, set
16851                  * unsupported flag for these services.
16852                  */
16853                 r = check_mfst_history(svcname);
16854                 if (r == -1)
16855                         return;
16856 
16857                 if (r) {
16858                         /* Set unsupported flag for service  */
16859                         svc_add_no_support(svc);
16860                 } else {
16861                         /* Delete the service */
16862                         teardown_service(svc, svcname);
16863                 }
16864 
16865                 return;
16866         }
16867 
16868         /*
16869          * Walk through the list of manifests and add them
16870          * to the service.
16871          *
16872          * Create a manifestfiles pg and add the property.
16873          */
16874         mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16875         if (mfwalk == NULL)
16876                 return;
16877 
16878         cur_svc = svc;
16879         r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16880         if (r != 0) {
16881                 cur_svc = NULL;
16882                 return;
16883         }
16884 
16885         while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16886                 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16887                     mhash_filename_to_propname(mfile->str, 0));
16888                 if (pname == NULL)
16889                         uu_die(gettext("Out of memory.\n"));
16890 
16891                 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16892                 uu_free(pname);
16893         }
16894         uu_list_walk_end(mfwalk);
16895 
16896         cur_svc = NULL;
16897 }
16898 
16899 /*
16900  * Take a service and process the manifest file entires to see if
16901  * there is continued support for the service and instances.  If
16902  * not cleanup as appropriate.
16903  *
16904  * If a service does not have a manifest files entry flag it for
16905  * upgrade and return.
16906  *
16907  * For each manifestfiles property check if the manifest file is
16908  * under the supported /lib/svc/manifest or /var/svc/manifest path
16909  * and if not then return immediately as this service is not supported
16910  * by the cleanup mechanism and should be ignored.
16911  *
16912  * For each manifest file that is supported, check to see if the
16913  * file exists.  If not then remove the manifest file property
16914  * from the service and the smf/manifest hash table.  If the manifest
16915  * file exists then verify that it supports the instances that are
16916  * part of the service.
16917  *
16918  * Once all manifest files have been accounted for remove any instances
16919  * that are no longer supported in the service.
16920  *
16921  * Return values :
16922  * 0 - Successfully processed the service
16923  * non-zero - failed to process the service
16924  *
16925  * On most errors, will just return to wait and get the next service,
16926  * unless in case of unable to create the needed structures which is
16927  * most likely a fatal error that is not going to be recoverable.
16928  */
16929 int
16930 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16931 {
16932         struct mpg_mfile        *mpntov;
16933         struct mpg_mfile        **mpvarry = NULL;
16934         scf_service_t           *svc;
16935         scf_propertygroup_t     *mpg;
16936         scf_property_t          *mp;
16937         scf_value_t             *mv;
16938         scf_iter_t              *mi;
16939         scf_instance_t          *instance;
16940         uu_list_walk_t          *insts;
16941         uu_list_t               *instances = NULL;
16942         boolean_t               activity = (boolean_t)act;
16943         char                    *mpnbuf;
16944         char                    *mpvbuf;
16945         char                    *pgpropbuf;
16946         int                     mfstcnt, rminstct, instct, mfstmax;
16947         int                     index;
16948         int                     r = 0;
16949 
16950         assert(g_hndl != NULL);
16951         assert(wip->svc != NULL);
16952         assert(wip->fmri != NULL);
16953 
16954         svc = wip->svc;
16955 
16956         mpg = scf_pg_create(g_hndl);
16957         mp = scf_property_create(g_hndl);
16958         mi = scf_iter_create(g_hndl);
16959         mv = scf_value_create(g_hndl);
16960         instance = scf_instance_create(g_hndl);
16961 
16962         if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16963             instance == NULL) {
16964                 uu_warn(gettext("Unable to create the supporting entities\n"));
16965                 uu_warn(gettext("scf error is : %s\n"),
16966                     scf_strerror(scf_error()));
16967                 scfdie();
16968         }
16969 
16970         /*
16971          * Get the manifestfiles property group to be parsed for
16972          * files existence.
16973          */
16974         if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16975                 switch (scf_error()) {
16976                 case SCF_ERROR_NOT_FOUND:
16977                         upgrade_svc_mfst_connection(svc, wip->fmri);
16978                         break;
16979                 case SCF_ERROR_DELETED:
16980                 case SCF_ERROR_CONNECTION_BROKEN:
16981                         goto out;
16982 
16983                 case SCF_ERROR_HANDLE_MISMATCH:
16984                 case SCF_ERROR_NOT_BOUND:
16985                 case SCF_ERROR_NOT_SET:
16986                 default:
16987                         bad_error("scf_iter_pg_properties",
16988                             scf_error());
16989                 }
16990 
16991                 goto out;
16992         }
16993 
16994         /*
16995          * Iterate through each of the manifestfiles properties
16996          * to determine what manifestfiles are available.
16997          *
16998          * If a manifest file is supported then increment the
16999          * count and therefore the service is safe.
17000          */
17001         if (scf_iter_pg_properties(mi, mpg) != 0) {
17002                 switch (scf_error()) {
17003                 case SCF_ERROR_DELETED:
17004                 case SCF_ERROR_CONNECTION_BROKEN:
17005                         goto out;
17006 
17007                 case SCF_ERROR_HANDLE_MISMATCH:
17008                 case SCF_ERROR_NOT_BOUND:
17009                 case SCF_ERROR_NOT_SET:
17010                 default:
17011                         bad_error("scf_iter_pg_properties",
17012                             scf_error());
17013                 }
17014         }
17015 
17016         mfstcnt = 0;
17017         mfstmax = MFSTFILE_MAX;
17018         mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17019         while ((r = scf_iter_next_property(mi, mp)) != 0) {
17020                 if (r == -1)
17021                         bad_error(gettext("Unable to iterate through "
17022                             "manifestfiles properties : %s"),
17023                             scf_error());
17024 
17025                 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17026                 mpnbuf = safe_malloc(max_scf_name_len + 1);
17027                 mpvbuf = safe_malloc(max_scf_value_len + 1);
17028                 mpntov->mpg = mpnbuf;
17029                 mpntov->mfile = mpvbuf;
17030                 mpntov->access = 1;
17031                 if (scf_property_get_name(mp, mpnbuf,
17032                     max_scf_name_len + 1) < 0) {
17033                         uu_warn(gettext("Unable to get manifest file "
17034                             "property : %s\n"),
17035                             scf_strerror(scf_error()));
17036 
17037                         switch (scf_error()) {
17038                         case SCF_ERROR_DELETED:
17039                         case SCF_ERROR_CONNECTION_BROKEN:
17040                                 r = scferror2errno(scf_error());
17041                                 goto out_free;
17042 
17043                         case SCF_ERROR_HANDLE_MISMATCH:
17044                         case SCF_ERROR_NOT_BOUND:
17045                         case SCF_ERROR_NOT_SET:
17046                         default:
17047                                 bad_error("scf_iter_pg_properties",
17048                                     scf_error());
17049                         }
17050                 }
17051 
17052                 /*
17053                  * The support property is a boolean value that indicates
17054                  * if the service is supported for manifest file deletion.
17055                  * Currently at this time there is no code that sets this
17056                  * value to true.  So while we could just let this be caught
17057                  * by the support check below, in the future this by be set
17058                  * to true and require processing.  So for that, go ahead
17059                  * and check here, and just return if false.  Otherwise,
17060                  * fall through expecting that other support checks will
17061                  * handle the entries.
17062                  */
17063                 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17064                         uint8_t support;
17065 
17066                         if (scf_property_get_value(mp, mv) != 0 ||
17067                             scf_value_get_boolean(mv, &support) != 0) {
17068                                 uu_warn(gettext("Unable to get the manifest "
17069                                     "support value: %s\n"),
17070                                     scf_strerror(scf_error()));
17071 
17072                                 switch (scf_error()) {
17073                                 case SCF_ERROR_DELETED:
17074                                 case SCF_ERROR_CONNECTION_BROKEN:
17075                                         r = scferror2errno(scf_error());
17076                                         goto out_free;
17077 
17078                                 case SCF_ERROR_HANDLE_MISMATCH:
17079                                 case SCF_ERROR_NOT_BOUND:
17080                                 case SCF_ERROR_NOT_SET:
17081                                 default:
17082                                         bad_error("scf_iter_pg_properties",
17083                                             scf_error());
17084                                 }
17085                         }
17086 
17087                         if (support == B_FALSE)
17088                                 goto out_free;
17089                 }
17090 
17091                 /*
17092                  * Anything with a manifest outside of the supported
17093                  * directories, immediately bail out because that makes
17094                  * this service non-supported.  We don't even want
17095                  * to do instance processing in this case because the
17096                  * instances could be part of the non-supported manifest.
17097                  */
17098                 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17099                         /*
17100                          * Manifest is not in /lib/svc, so we need to
17101                          * consider the /var/svc case.
17102                          */
17103                         if (strncmp(mpnbuf, VARSVC_PR,
17104                             strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17105                                 /*
17106                                  * Either the manifest is not in /var/svc or
17107                                  * /var is not yet mounted.  We ignore the
17108                                  * manifest either because it is not in a
17109                                  * standard location or because we cannot
17110                                  * currently access the manifest.
17111                                  */
17112                                 goto out_free;
17113                         }
17114                 }
17115 
17116                 /*
17117                  * Get the value to of the manifest file for this entry
17118                  * for access verification and instance support
17119                  * verification if it still exists.
17120                  *
17121                  * During Early Manifest Import if the manifest is in
17122                  * /var/svc then it may not yet be available for checking
17123                  * so we must determine if /var/svc is available.  If not
17124                  * then defer until Late Manifest Import to cleanup.
17125                  */
17126                 if (scf_property_get_value(mp, mv) != 0) {
17127                         uu_warn(gettext("Unable to get the manifest file "
17128                             "value: %s\n"),
17129                             scf_strerror(scf_error()));
17130 
17131                         switch (scf_error()) {
17132                         case SCF_ERROR_DELETED:
17133                         case SCF_ERROR_CONNECTION_BROKEN:
17134                                 r = scferror2errno(scf_error());
17135                                 goto out_free;
17136 
17137                         case SCF_ERROR_HANDLE_MISMATCH:
17138                         case SCF_ERROR_NOT_BOUND:
17139                         case SCF_ERROR_NOT_SET:
17140                         default:
17141                                 bad_error("scf_property_get_value",
17142                                     scf_error());
17143                         }
17144                 }
17145 
17146                 if (scf_value_get_astring(mv, mpvbuf,
17147                     max_scf_value_len + 1) < 0) {
17148                         uu_warn(gettext("Unable to get the manifest "
17149                             "file : %s\n"),
17150                             scf_strerror(scf_error()));
17151 
17152                         switch (scf_error()) {
17153                         case SCF_ERROR_DELETED:
17154                         case SCF_ERROR_CONNECTION_BROKEN:
17155                                 r = scferror2errno(scf_error());
17156                                 goto out_free;
17157 
17158                         case SCF_ERROR_HANDLE_MISMATCH:
17159                         case SCF_ERROR_NOT_BOUND:
17160                         case SCF_ERROR_NOT_SET:
17161                         default:
17162                                 bad_error("scf_value_get_astring",
17163                                     scf_error());
17164                         }
17165                 }
17166 
17167                 mpvarry[mfstcnt] = mpntov;
17168                 mfstcnt++;
17169 
17170                 /*
17171                  * Check for the need to reallocate array
17172                  */
17173                 if (mfstcnt >= (mfstmax - 1)) {
17174                         struct mpg_mfile **newmpvarry;
17175 
17176                         mfstmax = mfstmax * 2;
17177                         newmpvarry = realloc(mpvarry,
17178                             sizeof (struct mpg_mfile *) * mfstmax);
17179 
17180                         if (newmpvarry == NULL)
17181                                 goto out_free;
17182 
17183                         mpvarry = newmpvarry;
17184                 }
17185 
17186                 mpvarry[mfstcnt] = NULL;
17187         }
17188 
17189         for (index = 0; mpvarry[index]; index++) {
17190                 mpntov = mpvarry[index];
17191 
17192                 /*
17193                  * Check to see if the manifestfile is accessable, if so hand
17194                  * this service and manifestfile off to be processed for
17195                  * instance support.
17196                  */
17197                 mpnbuf = mpntov->mpg;
17198                 mpvbuf = mpntov->mfile;
17199                 if (access(mpvbuf, F_OK) != 0) {
17200                         mpntov->access = 0;
17201                         activity++;
17202                         mfstcnt--;
17203                         /* Remove the entry from the service */
17204                         cur_svc = svc;
17205                         pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17206                             mpnbuf);
17207                         if (pgpropbuf == NULL)
17208                                 uu_die(gettext("Out of memory.\n"));
17209 
17210                         lscf_delprop(pgpropbuf);
17211                         cur_svc = NULL;
17212 
17213                         uu_free(pgpropbuf);
17214                 }
17215         }
17216 
17217         /*
17218          * If mfstcnt is 0, none of the manifests that supported the service
17219          * existed so remove the service.
17220          */
17221         if (mfstcnt == 0) {
17222                 teardown_service(svc, wip->fmri);
17223 
17224                 goto out_free;
17225         }
17226 
17227         if (activity) {
17228                 int     nosvcsupport = 0;
17229 
17230                 /*
17231                  * If the list of service instances is NULL then
17232                  * create the list.
17233                  */
17234                 instances = create_instance_list(svc, 1);
17235                 if (instances == NULL) {
17236                         uu_warn(gettext("Unable to create instance list %s\n"),
17237                             wip->fmri);
17238                         goto out_free;
17239                 }
17240 
17241                 rminstct = uu_list_numnodes(instances);
17242                 instct = rminstct;
17243 
17244                 for (index = 0; mpvarry[index]; index++) {
17245                         mpntov = mpvarry[index];
17246                         if (mpntov->access == 0)
17247                                 continue;
17248 
17249                         mpnbuf = mpntov->mpg;
17250                         mpvbuf = mpntov->mfile;
17251                         r = check_instance_support(mpvbuf, wip->fmri,
17252                             instances);
17253                         if (r == -1) {
17254                                 nosvcsupport++;
17255                         } else {
17256                                 rminstct -= r;
17257                         }
17258                 }
17259 
17260                 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17261                         teardown_service(svc, wip->fmri);
17262 
17263                         goto out_free;
17264                 }
17265         }
17266 
17267         /*
17268          * If there are instances left on the instance list, then
17269          * we must remove them.
17270          */
17271         if (instances != NULL && uu_list_numnodes(instances)) {
17272                 string_list_t *sp;
17273 
17274                 insts = uu_list_walk_start(instances, 0);
17275                 while ((sp = uu_list_walk_next(insts)) != NULL) {
17276                         /*
17277                          * Remove the instance from the instances list.
17278                          */
17279                         safe_printf(gettext("Delete instance %s from "
17280                             "service %s\n"), sp->str, wip->fmri);
17281                         if (scf_service_get_instance(svc, sp->str,
17282                             instance) != SCF_SUCCESS) {
17283                                 (void) uu_warn("scf_error - %s\n",
17284                                     scf_strerror(scf_error()));
17285 
17286                                 continue;
17287                         }
17288 
17289                         (void) disable_instance(instance);
17290 
17291                         (void) lscf_instance_delete(instance, 1);
17292                 }
17293                 scf_instance_destroy(instance);
17294                 uu_list_walk_end(insts);
17295         }
17296 
17297 out_free:
17298         if (mpvarry) {
17299                 struct mpg_mfile *fmpntov;
17300 
17301                 for (index = 0; mpvarry[index]; index++) {
17302                         fmpntov  = mpvarry[index];
17303                         if (fmpntov->mpg == mpnbuf)
17304                                 mpnbuf = NULL;
17305                         free(fmpntov->mpg);
17306 
17307                         if (fmpntov->mfile == mpvbuf)
17308                                 mpvbuf = NULL;
17309                         free(fmpntov->mfile);
17310 
17311                         if (fmpntov == mpntov)
17312                                 mpntov = NULL;
17313                         free(fmpntov);
17314                 }
17315                 if (mpnbuf)
17316                         free(mpnbuf);
17317                 if (mpvbuf)
17318                         free(mpvbuf);
17319                 if (mpntov)
17320                         free(mpntov);
17321 
17322                 free(mpvarry);
17323         }
17324 out:
17325         scf_pg_destroy(mpg);
17326         scf_property_destroy(mp);
17327         scf_iter_destroy(mi);
17328         scf_value_destroy(mv);
17329 
17330         return (0);
17331 }
17332 
17333 /*
17334  * Take the service and search for the manifestfiles property
17335  * in each of the property groups.  If the manifest file
17336  * associated with the property does not exist then remove
17337  * the property group.
17338  */
17339 int
17340 lscf_hash_cleanup()
17341 {
17342         scf_service_t           *svc;
17343         scf_scope_t             *scope;
17344         scf_propertygroup_t     *pg;
17345         scf_property_t          *prop;
17346         scf_value_t             *val;
17347         scf_iter_t              *iter;
17348         char                    *pgname = NULL;
17349         char                    *mfile = NULL;
17350         int                     r;
17351 
17352         svc = scf_service_create(g_hndl);
17353         scope = scf_scope_create(g_hndl);
17354         pg = scf_pg_create(g_hndl);
17355         prop = scf_property_create(g_hndl);
17356         val = scf_value_create(g_hndl);
17357         iter = scf_iter_create(g_hndl);
17358         if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17359             svc == NULL || scope == NULL) {
17360                 uu_warn(gettext("Unable to create a property group, or "
17361                     "property\n"));
17362                 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17363                     "pg is not NULL");
17364                 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17365                     "prop is not NULL");
17366                 uu_warn("%s\n", val == NULL ? "val is NULL" :
17367                     "val is not NULL");
17368                 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17369                     "iter is not NULL");
17370                 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17371                     "svc is not NULL");
17372                 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17373                     "scope is not NULL");
17374                 uu_warn(gettext("scf error is : %s\n"),
17375                     scf_strerror(scf_error()));
17376                 scfdie();
17377         }
17378 
17379         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17380                 switch (scf_error()) {
17381                 case SCF_ERROR_CONNECTION_BROKEN:
17382                 case SCF_ERROR_NOT_FOUND:
17383                         goto out;
17384 
17385                 case SCF_ERROR_HANDLE_MISMATCH:
17386                 case SCF_ERROR_NOT_BOUND:
17387                 case SCF_ERROR_INVALID_ARGUMENT:
17388                 default:
17389                         bad_error("scf_handle_get_scope", scf_error());
17390                 }
17391         }
17392 
17393         if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17394                 uu_warn(gettext("Unable to process the hash service, %s\n"),
17395                     HASH_SVC);
17396                 goto out;
17397         }
17398 
17399         pgname = safe_malloc(max_scf_name_len + 1);
17400         mfile = safe_malloc(max_scf_value_len + 1);
17401 
17402         if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17403                 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17404                     scf_strerror(scf_error()));
17405                 goto out;
17406         }
17407 
17408         while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17409                 if (r == -1)
17410                         goto out;
17411 
17412                 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17413                         switch (scf_error()) {
17414                         case SCF_ERROR_DELETED:
17415                                 return (ENODEV);
17416 
17417                         case SCF_ERROR_CONNECTION_BROKEN:
17418                                 return (ECONNABORTED);
17419 
17420                         case SCF_ERROR_NOT_SET:
17421                         case SCF_ERROR_NOT_BOUND:
17422                         default:
17423                                 bad_error("scf_pg_get_name", scf_error());
17424                         }
17425                 }
17426                 if (IGNORE_VAR) {
17427                         if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17428                                 continue;
17429                 }
17430 
17431                 /*
17432                  * If unable to get the property continue as this is an
17433                  * entry that has no location to check against.
17434                  */
17435                 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17436                         continue;
17437                 }
17438 
17439                 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17440                         uu_warn(gettext("Unable to get value from %s\n"),
17441                             pgname);
17442 
17443                         switch (scf_error()) {
17444                         case SCF_ERROR_DELETED:
17445                         case SCF_ERROR_CONSTRAINT_VIOLATED:
17446                         case SCF_ERROR_NOT_FOUND:
17447                         case SCF_ERROR_NOT_SET:
17448                                 continue;
17449 
17450                         case SCF_ERROR_CONNECTION_BROKEN:
17451                                 r = scferror2errno(scf_error());
17452                                 goto out;
17453 
17454                         case SCF_ERROR_HANDLE_MISMATCH:
17455                         case SCF_ERROR_NOT_BOUND:
17456                         default:
17457                                 bad_error("scf_property_get_value",
17458                                     scf_error());
17459                         }
17460                 }
17461 
17462                 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17463                     == -1) {
17464                         uu_warn(gettext("Unable to get astring from %s : %s\n"),
17465                             pgname, scf_strerror(scf_error()));
17466 
17467                         switch (scf_error()) {
17468                         case SCF_ERROR_NOT_SET:
17469                         case SCF_ERROR_TYPE_MISMATCH:
17470                                 continue;
17471 
17472                         default:
17473                                 bad_error("scf_value_get_astring", scf_error());
17474                         }
17475                 }
17476 
17477                 if (access(mfile, F_OK) == 0)
17478                         continue;
17479 
17480                 (void) scf_pg_delete(pg);
17481         }
17482 
17483 out:
17484         scf_scope_destroy(scope);
17485         scf_service_destroy(svc);
17486         scf_pg_destroy(pg);
17487         scf_property_destroy(prop);
17488         scf_value_destroy(val);
17489         scf_iter_destroy(iter);
17490         free(pgname);
17491         free(mfile);
17492 
17493         return (0);
17494 }
17495 
17496 #ifndef NATIVE_BUILD
17497 /* ARGSUSED */
17498 CPL_MATCH_FN(complete_select)
17499 {
17500         const char *arg0, *arg1, *arg1end;
17501         int word_start, err = 0, r;
17502         size_t len;
17503         char *buf;
17504 
17505         lscf_prep_hndl();
17506 
17507         arg0 = line + strspn(line, " \t");
17508         assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17509 
17510         arg1 = arg0 + sizeof ("select") - 1;
17511         arg1 += strspn(arg1, " \t");
17512         word_start = arg1 - line;
17513 
17514         arg1end = arg1 + strcspn(arg1, " \t");
17515         if (arg1end < line + word_end)
17516                 return (0);
17517 
17518         len = line + word_end - arg1;
17519 
17520         buf = safe_malloc(max_scf_name_len + 1);
17521 
17522         if (cur_snap != NULL) {
17523                 return (0);
17524         } else if (cur_inst != NULL) {
17525                 return (0);
17526         } else if (cur_svc != NULL) {
17527                 scf_instance_t *inst;
17528                 scf_iter_t *iter;
17529 
17530                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17531                     (iter = scf_iter_create(g_hndl)) == NULL)
17532                         scfdie();
17533 
17534                 if (scf_iter_service_instances(iter, cur_svc) != 0)
17535                         scfdie();
17536 
17537                 for (;;) {
17538                         r = scf_iter_next_instance(iter, inst);
17539                         if (r == 0)
17540                                 break;
17541                         if (r != 1)
17542                                 scfdie();
17543 
17544                         if (scf_instance_get_name(inst, buf,
17545                             max_scf_name_len + 1) < 0)
17546                                 scfdie();
17547 
17548                         if (strncmp(buf, arg1, len) == 0) {
17549                                 err = cpl_add_completion(cpl, line, word_start,
17550                                     word_end, buf + len, "", " ");
17551                                 if (err != 0)
17552                                         break;
17553                         }
17554                 }
17555 
17556                 scf_iter_destroy(iter);
17557                 scf_instance_destroy(inst);
17558 
17559                 return (err);
17560         } else {
17561                 scf_service_t *svc;
17562                 scf_iter_t *iter;
17563 
17564                 assert(cur_scope != NULL);
17565 
17566                 if ((svc = scf_service_create(g_hndl)) == NULL ||
17567                     (iter = scf_iter_create(g_hndl)) == NULL)
17568                         scfdie();
17569 
17570                 if (scf_iter_scope_services(iter, cur_scope) != 0)
17571                         scfdie();
17572 
17573                 for (;;) {
17574                         r = scf_iter_next_service(iter, svc);
17575                         if (r == 0)
17576                                 break;
17577                         if (r != 1)
17578                                 scfdie();
17579 
17580                         if (scf_service_get_name(svc, buf,
17581                             max_scf_name_len + 1) < 0)
17582                                 scfdie();
17583 
17584                         if (strncmp(buf, arg1, len) == 0) {
17585                                 err = cpl_add_completion(cpl, line, word_start,
17586                                     word_end, buf + len, "", " ");
17587                                 if (err != 0)
17588                                         break;
17589                         }
17590                 }
17591 
17592                 scf_iter_destroy(iter);
17593                 scf_service_destroy(svc);
17594 
17595                 return (err);
17596         }
17597 }
17598 
17599 /* ARGSUSED */
17600 CPL_MATCH_FN(complete_command)
17601 {
17602         uint32_t scope = 0;
17603 
17604         if (cur_snap != NULL)
17605                 scope = CS_SNAP;
17606         else if (cur_inst != NULL)
17607                 scope = CS_INST;
17608         else if (cur_svc != NULL)
17609                 scope = CS_SVC;
17610         else
17611                 scope = CS_SCOPE;
17612 
17613         return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17614 }
17615 #endif  /* NATIVE_BUILD */