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