1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2015 Joyent, Inc.
  25  * Copyright 2012 Milan Jurik. All rights reserved.
  26  * Copyright 2017 RackTop Systems.
  27  */
  28 
  29 
  30 #include <alloca.h>
  31 #include <assert.h>
  32 #include <ctype.h>
  33 #include <door.h>
  34 #include <errno.h>
  35 #include <fcntl.h>
  36 #include <fnmatch.h>
  37 #include <inttypes.h>
  38 #include <libintl.h>
  39 #include <libnvpair.h>
  40 #include <libscf.h>
  41 #include <libscf_priv.h>
  42 #include <libtecla.h>
  43 #include <libuutil.h>
  44 #include <limits.h>
  45 #include <locale.h>
  46 #include <stdarg.h>
  47 #include <string.h>
  48 #include <strings.h>
  49 #include <time.h>
  50 #include <unistd.h>
  51 #include <wait.h>
  52 #include <poll.h>
  53 
  54 #include <libxml/tree.h>
  55 
  56 #include <sys/param.h>
  57 
  58 #include <sys/stat.h>
  59 #include <sys/mman.h>
  60 
  61 #include "svccfg.h"
  62 #include "notify_params.h"
  63 #include "manifest_hash.h"
  64 #include "manifest_find.h"
  65 
  66 /* The colon namespaces in each entity (each followed by a newline). */
  67 #define COLON_NAMESPACES        ":properties\n"
  68 
  69 #define TEMP_FILE_PATTERN       "/tmp/svccfg-XXXXXX"
  70 
  71 /* These are characters which the lexer requires to be in double-quotes. */
  72 #define CHARS_TO_QUOTE          " \t\n\\>=\"()"
  73 
  74 #define HASH_SIZE               16
  75 #define HASH_PG_TYPE            "framework"
  76 #define HASH_PG_FLAGS           0
  77 #define HASH_PROP               "md5sum"
  78 
  79 /*
  80  * Indentation used in the output of the describe subcommand.
  81  */
  82 #define TMPL_VALUE_INDENT       "  "
  83 #define TMPL_INDENT             "    "
  84 #define TMPL_INDENT_2X          "        "
  85 #define TMPL_CHOICE_INDENT      "      "
  86 
  87 /*
  88  * Directory locations for manifests
  89  */
  90 #define VARSVC_DIR              "/var/svc/manifest"
  91 #define LIBSVC_DIR              "/lib/svc/manifest"
  92 #define VARSVC_PR               "var_svc_manifest"
  93 #define LIBSVC_PR               "lib_svc_manifest"
  94 #define MFSTFILEPR              "manifestfile"
  95 
  96 #define SUPPORTPROP             "support"
  97 
  98 #define MFSTHISTFILE            "/lib/svc/share/mfsthistory"
  99 
 100 #define MFSTFILE_MAX            16
 101 
 102 /*
 103  * These are the classes of elements which may appear as children of service
 104  * or instance elements in XML manifests.
 105  */
 106 struct entity_elts {
 107         xmlNodePtr      create_default_instance;
 108         xmlNodePtr      single_instance;
 109         xmlNodePtr      restarter;
 110         xmlNodePtr      dependencies;
 111         xmlNodePtr      dependents;
 112         xmlNodePtr      method_context;
 113         xmlNodePtr      exec_methods;
 114         xmlNodePtr      notify_params;
 115         xmlNodePtr      property_groups;
 116         xmlNodePtr      instances;
 117         xmlNodePtr      stability;
 118         xmlNodePtr      template;
 119 };
 120 
 121 /*
 122  * Likewise for property_group elements.
 123  */
 124 struct pg_elts {
 125         xmlNodePtr      stability;
 126         xmlNodePtr      propvals;
 127         xmlNodePtr      properties;
 128 };
 129 
 130 /*
 131  * Likewise for template elements.
 132  */
 133 struct template_elts {
 134         xmlNodePtr      common_name;
 135         xmlNodePtr      description;
 136         xmlNodePtr      documentation;
 137 };
 138 
 139 /*
 140  * Likewise for type (for notification parameters) elements.
 141  */
 142 struct params_elts {
 143         xmlNodePtr      paramval;
 144         xmlNodePtr      parameter;
 145 };
 146 
 147 /*
 148  * This structure is for snaplevel lists.  They are convenient because libscf
 149  * only allows traversing snaplevels in one direction.
 150  */
 151 struct snaplevel {
 152         uu_list_node_t  list_node;
 153         scf_snaplevel_t *sl;
 154 };
 155 
 156 /*
 157  * This is used for communication between lscf_service_export and
 158  * export_callback.
 159  */
 160 struct export_args {
 161         const char      *filename;
 162         int             flags;
 163 };
 164 
 165 /*
 166  * The service_manifest structure is used by the upgrade process
 167  * to create a list of service to manifest linkages from the manifests
 168  * in a set of given directories.
 169  */
 170 typedef struct service_manifest {
 171         const char      *servicename;
 172         uu_list_t       *mfstlist;
 173         size_t  mfstlist_sz;
 174 
 175         uu_avl_node_t   svcmfst_node;
 176 } service_manifest_t;
 177 
 178 /*
 179  * Structure to track the manifest file property group
 180  * and the manifest file associated with that property
 181  * group.  Also, a flag to keep the access once it has
 182  * been checked.
 183  */
 184 struct mpg_mfile {
 185         char    *mpg;
 186         char    *mfile;
 187         int     access;
 188 };
 189 
 190 const char * const scf_pg_general = SCF_PG_GENERAL;
 191 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
 192 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
 193 const char * const scf_property_external = "external";
 194 
 195 const char * const snap_initial = "initial";
 196 const char * const snap_lastimport = "last-import";
 197 const char * const snap_previous = "previous";
 198 const char * const snap_running = "running";
 199 
 200 scf_handle_t *g_hndl = NULL;    /* only valid after lscf_prep_hndl() */
 201 
 202 ssize_t max_scf_fmri_len;
 203 ssize_t max_scf_name_len;
 204 ssize_t max_scf_pg_type_len;
 205 ssize_t max_scf_value_len;
 206 static size_t max_scf_len;
 207 
 208 static scf_scope_t *cur_scope;
 209 static scf_service_t *cur_svc = NULL;
 210 static scf_instance_t *cur_inst = NULL;
 211 static scf_snapshot_t *cur_snap = NULL;
 212 static scf_snaplevel_t *cur_level = NULL;
 213 
 214 static uu_list_pool_t *snaplevel_pool;
 215 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
 216 static uu_list_t *cur_levels;
 217 static struct snaplevel *cur_elt;               /* cur_elt->sl == cur_level */
 218 
 219 static FILE *tempfile = NULL;
 220 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
 221 
 222 static const char *emsg_entity_not_selected;
 223 static const char *emsg_permission_denied;
 224 static const char *emsg_create_xml;
 225 static const char *emsg_cant_modify_snapshots;
 226 static const char *emsg_invalid_for_snapshot;
 227 static const char *emsg_read_only;
 228 static const char *emsg_deleted;
 229 static const char *emsg_invalid_pg_name;
 230 static const char *emsg_invalid_prop_name;
 231 static const char *emsg_no_such_pg;
 232 static const char *emsg_fmri_invalid_pg_name;
 233 static const char *emsg_fmri_invalid_pg_name_type;
 234 static const char *emsg_pg_added;
 235 static const char *emsg_pg_changed;
 236 static const char *emsg_pg_deleted;
 237 static const char *emsg_pg_mod_perm;
 238 static const char *emsg_pg_add_perm;
 239 static const char *emsg_pg_del_perm;
 240 static const char *emsg_snap_perm;
 241 static const char *emsg_dpt_dangling;
 242 static const char *emsg_dpt_no_dep;
 243 
 244 static int li_only = 0;
 245 static int no_refresh = 0;
 246 
 247 /* how long in ns we should wait between checks for a pg */
 248 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
 249 
 250 /* import globals, to minimize allocations */
 251 static scf_scope_t *imp_scope = NULL;
 252 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
 253 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
 254 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
 255 static scf_snapshot_t *imp_rsnap = NULL;
 256 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
 257 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
 258 static scf_property_t *imp_prop = NULL;
 259 static scf_iter_t *imp_iter = NULL;
 260 static scf_iter_t *imp_rpg_iter = NULL;
 261 static scf_iter_t *imp_up_iter = NULL;
 262 static scf_transaction_t *imp_tx = NULL;        /* always reset this */
 263 static char *imp_str = NULL;
 264 static size_t imp_str_sz;
 265 static char *imp_tsname = NULL;
 266 static char *imp_fe1 = NULL;            /* for fmri_equal() */
 267 static char *imp_fe2 = NULL;
 268 static uu_list_t *imp_deleted_dpts = NULL;      /* pgroup_t's to refresh */
 269 
 270 /* upgrade_dependents() globals */
 271 static scf_instance_t *ud_inst = NULL;
 272 static scf_snaplevel_t *ud_snpl = NULL;
 273 static scf_propertygroup_t *ud_pg = NULL;
 274 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
 275 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
 276 static int ud_run_dpts_pg_set = 0;
 277 static scf_property_t *ud_prop = NULL;
 278 static scf_property_t *ud_dpt_prop = NULL;
 279 static scf_value_t *ud_val = NULL;
 280 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
 281 static scf_transaction_t *ud_tx = NULL;
 282 static char *ud_ctarg = NULL;
 283 static char *ud_oldtarg = NULL;
 284 static char *ud_name = NULL;
 285 
 286 /* export globals */
 287 static scf_instance_t *exp_inst;
 288 static scf_propertygroup_t *exp_pg;
 289 static scf_property_t *exp_prop;
 290 static scf_value_t *exp_val;
 291 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
 292 static char *exp_str;
 293 static size_t exp_str_sz;
 294 
 295 /* cleanup globals */
 296 static uu_avl_pool_t *service_manifest_pool = NULL;
 297 static uu_avl_t *service_manifest_tree = NULL;
 298 
 299 static void scfdie_lineno(int lineno) __NORETURN;
 300 
 301 static char *start_method_names[] = {
 302         "start",
 303         "inetd_start",
 304         NULL
 305 };
 306 
 307 static struct uri_scheme {
 308         const char *scheme;
 309         const char *protocol;
 310 } uri_scheme[] = {
 311         { "mailto", "smtp" },
 312         { "snmp", "snmp" },
 313         { "syslog", "syslog" },
 314         { NULL, NULL }
 315 };
 316 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
 317     sizeof (struct uri_scheme)) - 1)
 318 
 319 static int
 320 check_uri_scheme(const char *scheme)
 321 {
 322         int i;
 323 
 324         for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
 325                 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
 326                         return (i);
 327         }
 328 
 329         return (-1);
 330 }
 331 
 332 static int
 333 check_uri_protocol(const char *p)
 334 {
 335         int i;
 336 
 337         for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
 338                 if (strcmp(p, uri_scheme[i].protocol) == 0)
 339                         return (i);
 340         }
 341 
 342         return (-1);
 343 }
 344 
 345 /*
 346  * For unexpected libscf errors.
 347  */
 348 #ifdef NDEBUG
 349 
 350 static void scfdie(void) __NORETURN;
 351 
 352 static void
 353 scfdie(void)
 354 {
 355         scf_error_t err = scf_error();
 356 
 357         if (err == SCF_ERROR_CONNECTION_BROKEN)
 358                 uu_die(gettext("Repository connection broken.  Exiting.\n"));
 359 
 360         uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
 361             scf_strerror(err));
 362 }
 363 
 364 #else
 365 
 366 #define scfdie()        scfdie_lineno(__LINE__)
 367 
 368 static void
 369 scfdie_lineno(int lineno)
 370 {
 371         scf_error_t err = scf_error();
 372 
 373         if (err == SCF_ERROR_CONNECTION_BROKEN)
 374                 uu_die(gettext("Repository connection broken.  Exiting.\n"));
 375 
 376         uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
 377             ": %s.\n"), lineno, scf_strerror(err));
 378 }
 379 
 380 #endif
 381 
 382 static void
 383 scfwarn(void)
 384 {
 385         warn(gettext("Unexpected libscf error: %s.\n"),
 386             scf_strerror(scf_error()));
 387 }
 388 
 389 /*
 390  * Clear a field of a structure.
 391  */
 392 static int
 393 clear_int(void *a, void *b)
 394 {
 395         /* LINTED */
 396         *(int *)((char *)a + (size_t)b) = 0;
 397 
 398         return (UU_WALK_NEXT);
 399 }
 400 
 401 static int
 402 scferror2errno(scf_error_t err)
 403 {
 404         switch (err) {
 405         case SCF_ERROR_BACKEND_ACCESS:
 406                 return (EACCES);
 407 
 408         case SCF_ERROR_BACKEND_READONLY:
 409                 return (EROFS);
 410 
 411         case SCF_ERROR_CONNECTION_BROKEN:
 412                 return (ECONNABORTED);
 413 
 414         case SCF_ERROR_CONSTRAINT_VIOLATED:
 415         case SCF_ERROR_INVALID_ARGUMENT:
 416                 return (EINVAL);
 417 
 418         case SCF_ERROR_DELETED:
 419                 return (ECANCELED);
 420 
 421         case SCF_ERROR_EXISTS:
 422                 return (EEXIST);
 423 
 424         case SCF_ERROR_NO_MEMORY:
 425                 return (ENOMEM);
 426 
 427         case SCF_ERROR_NO_RESOURCES:
 428                 return (ENOSPC);
 429 
 430         case SCF_ERROR_NOT_FOUND:
 431                 return (ENOENT);
 432 
 433         case SCF_ERROR_PERMISSION_DENIED:
 434                 return (EPERM);
 435 
 436         default:
 437 #ifndef NDEBUG
 438                 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
 439                     __FILE__, __LINE__, err);
 440 #else
 441                 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
 442 #endif
 443                 abort();
 444                 /* NOTREACHED */
 445         }
 446 }
 447 
 448 static int
 449 entity_get_pg(void *ent, int issvc, const char *name,
 450     scf_propertygroup_t *pg)
 451 {
 452         if (issvc)
 453                 return (scf_service_get_pg(ent, name, pg));
 454         else
 455                 return (scf_instance_get_pg(ent, name, pg));
 456 }
 457 
 458 static void
 459 entity_destroy(void *ent, int issvc)
 460 {
 461         if (issvc)
 462                 scf_service_destroy(ent);
 463         else
 464                 scf_instance_destroy(ent);
 465 }
 466 
 467 static int
 468 get_pg(const char *pg_name, scf_propertygroup_t *pg)
 469 {
 470         int ret;
 471 
 472         if (cur_level != NULL)
 473                 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
 474         else if (cur_inst != NULL)
 475                 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
 476         else
 477                 ret = scf_service_get_pg(cur_svc, pg_name, pg);
 478 
 479         return (ret);
 480 }
 481 
 482 /*
 483  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
 484  * snaplevel.  Otherwise find the instance snaplevel.
 485  *
 486  * Returns
 487  *   0 - success
 488  *   ECONNABORTED - repository connection broken
 489  *   ECANCELED - instance containing snap was deleted
 490  *   ENOENT - snap has no snaplevels
 491  *          - requested snaplevel not found
 492  */
 493 static int
 494 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
 495 {
 496         if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
 497                 switch (scf_error()) {
 498                 case SCF_ERROR_CONNECTION_BROKEN:
 499                 case SCF_ERROR_DELETED:
 500                 case SCF_ERROR_NOT_FOUND:
 501                         return (scferror2errno(scf_error()));
 502 
 503                 case SCF_ERROR_HANDLE_MISMATCH:
 504                 case SCF_ERROR_NOT_BOUND:
 505                 case SCF_ERROR_NOT_SET:
 506                 default:
 507                         bad_error("scf_snapshot_get_base_snaplevel",
 508                             scf_error());
 509                 }
 510         }
 511 
 512         for (;;) {
 513                 ssize_t ssz;
 514 
 515                 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
 516                 if (ssz >= 0) {
 517                         if (!get_svc)
 518                                 return (0);
 519                 } else {
 520                         switch (scf_error()) {
 521                         case SCF_ERROR_CONSTRAINT_VIOLATED:
 522                                 if (get_svc)
 523                                         return (0);
 524                                 break;
 525 
 526                         case SCF_ERROR_DELETED:
 527                         case SCF_ERROR_CONNECTION_BROKEN:
 528                                 return (scferror2errno(scf_error()));
 529 
 530                         case SCF_ERROR_NOT_SET:
 531                         case SCF_ERROR_NOT_BOUND:
 532                         default:
 533                                 bad_error("scf_snaplevel_get_instance_name",
 534                                     scf_error());
 535                         }
 536                 }
 537 
 538                 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
 539                         switch (scf_error()) {
 540                         case SCF_ERROR_NOT_FOUND:
 541                         case SCF_ERROR_CONNECTION_BROKEN:
 542                         case SCF_ERROR_DELETED:
 543                                 return (scferror2errno(scf_error()));
 544 
 545                         case SCF_ERROR_HANDLE_MISMATCH:
 546                         case SCF_ERROR_NOT_BOUND:
 547                         case SCF_ERROR_NOT_SET:
 548                         case SCF_ERROR_INVALID_ARGUMENT:
 549                         default:
 550                                 bad_error("scf_snaplevel_get_next_snaplevel",
 551                                     scf_error());
 552                         }
 553                 }
 554         }
 555 }
 556 
 557 /*
 558  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
 559  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
 560  * the property group named name in it.  If it doesn't have a running
 561  * snapshot, set pg to the instance's current property group named name.
 562  *
 563  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
 564  * its instances.  If one has a running snapshot with a service snaplevel, set
 565  * pg to the property group named name in it.  If no such snaplevel could be
 566  * found, set pg to the service's current property group named name.
 567  *
 568  * iter, inst, snap, and snpl are required scratch objects.
 569  *
 570  * Returns
 571  *   0 - success
 572  *   ECONNABORTED - repository connection broken
 573  *   ECANCELED - ent was deleted
 574  *   ENOENT - no such property group
 575  *   EINVAL - name is an invalid property group name
 576  *   EBADF - found running snapshot is missing a snaplevel
 577  */
 578 static int
 579 entity_get_running_pg(void *ent, int issvc, const char *name,
 580     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
 581     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
 582 {
 583         int r;
 584 
 585         if (issvc) {
 586                 /* Search for an instance with a running snapshot. */
 587                 if (scf_iter_service_instances(iter, ent) != 0) {
 588                         switch (scf_error()) {
 589                         case SCF_ERROR_DELETED:
 590                         case SCF_ERROR_CONNECTION_BROKEN:
 591                                 return (scferror2errno(scf_error()));
 592 
 593                         case SCF_ERROR_NOT_SET:
 594                         case SCF_ERROR_NOT_BOUND:
 595                         case SCF_ERROR_HANDLE_MISMATCH:
 596                         default:
 597                                 bad_error("scf_iter_service_instances",
 598                                     scf_error());
 599                         }
 600                 }
 601 
 602                 for (;;) {
 603                         r = scf_iter_next_instance(iter, inst);
 604                         if (r == 0) {
 605                                 if (scf_service_get_pg(ent, name, pg) == 0)
 606                                         return (0);
 607 
 608                                 switch (scf_error()) {
 609                                 case SCF_ERROR_DELETED:
 610                                 case SCF_ERROR_NOT_FOUND:
 611                                 case SCF_ERROR_INVALID_ARGUMENT:
 612                                 case SCF_ERROR_CONNECTION_BROKEN:
 613                                         return (scferror2errno(scf_error()));
 614 
 615                                 case SCF_ERROR_NOT_BOUND:
 616                                 case SCF_ERROR_HANDLE_MISMATCH:
 617                                 case SCF_ERROR_NOT_SET:
 618                                 default:
 619                                         bad_error("scf_service_get_pg",
 620                                             scf_error());
 621                                 }
 622                         }
 623                         if (r != 1) {
 624                                 switch (scf_error()) {
 625                                 case SCF_ERROR_DELETED:
 626                                 case SCF_ERROR_CONNECTION_BROKEN:
 627                                         return (scferror2errno(scf_error()));
 628 
 629                                 case SCF_ERROR_INVALID_ARGUMENT:
 630                                 case SCF_ERROR_NOT_SET:
 631                                 case SCF_ERROR_NOT_BOUND:
 632                                 case SCF_ERROR_HANDLE_MISMATCH:
 633                                 default:
 634                                         bad_error("scf_iter_next_instance",
 635                                             scf_error());
 636                                 }
 637                         }
 638 
 639                         if (scf_instance_get_snapshot(inst, snap_running,
 640                             snap) == 0)
 641                                 break;
 642 
 643                         switch (scf_error()) {
 644                         case SCF_ERROR_NOT_FOUND:
 645                         case SCF_ERROR_DELETED:
 646                                 continue;
 647 
 648                         case SCF_ERROR_CONNECTION_BROKEN:
 649                                 return (ECONNABORTED);
 650 
 651                         case SCF_ERROR_HANDLE_MISMATCH:
 652                         case SCF_ERROR_INVALID_ARGUMENT:
 653                         case SCF_ERROR_NOT_SET:
 654                         case SCF_ERROR_NOT_BOUND:
 655                         default:
 656                                 bad_error("scf_instance_get_snapshot",
 657                                     scf_error());
 658                         }
 659                 }
 660         } else {
 661                 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
 662                         switch (scf_error()) {
 663                         case SCF_ERROR_NOT_FOUND:
 664                                 break;
 665 
 666                         case SCF_ERROR_DELETED:
 667                         case SCF_ERROR_CONNECTION_BROKEN:
 668                                 return (scferror2errno(scf_error()));
 669 
 670                         case SCF_ERROR_NOT_BOUND:
 671                         case SCF_ERROR_HANDLE_MISMATCH:
 672                         case SCF_ERROR_INVALID_ARGUMENT:
 673                         case SCF_ERROR_NOT_SET:
 674                         default:
 675                                 bad_error("scf_instance_get_snapshot",
 676                                     scf_error());
 677                         }
 678 
 679                         if (scf_instance_get_pg(ent, name, pg) == 0)
 680                                 return (0);
 681 
 682                         switch (scf_error()) {
 683                         case SCF_ERROR_DELETED:
 684                         case SCF_ERROR_NOT_FOUND:
 685                         case SCF_ERROR_INVALID_ARGUMENT:
 686                         case SCF_ERROR_CONNECTION_BROKEN:
 687                                 return (scferror2errno(scf_error()));
 688 
 689                         case SCF_ERROR_NOT_BOUND:
 690                         case SCF_ERROR_HANDLE_MISMATCH:
 691                         case SCF_ERROR_NOT_SET:
 692                         default:
 693                                 bad_error("scf_instance_get_pg", scf_error());
 694                         }
 695                 }
 696         }
 697 
 698         r = get_snaplevel(snap, issvc, snpl);
 699         switch (r) {
 700         case 0:
 701                 break;
 702 
 703         case ECONNABORTED:
 704         case ECANCELED:
 705                 return (r);
 706 
 707         case ENOENT:
 708                 return (EBADF);
 709 
 710         default:
 711                 bad_error("get_snaplevel", r);
 712         }
 713 
 714         if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
 715                 return (0);
 716 
 717         switch (scf_error()) {
 718         case SCF_ERROR_DELETED:
 719         case SCF_ERROR_INVALID_ARGUMENT:
 720         case SCF_ERROR_CONNECTION_BROKEN:
 721         case SCF_ERROR_NOT_FOUND:
 722                 return (scferror2errno(scf_error()));
 723 
 724         case SCF_ERROR_NOT_BOUND:
 725         case SCF_ERROR_HANDLE_MISMATCH:
 726         case SCF_ERROR_NOT_SET:
 727         default:
 728                 bad_error("scf_snaplevel_get_pg", scf_error());
 729                 /* NOTREACHED */
 730         }
 731 }
 732 
 733 /*
 734  * To be registered with atexit().
 735  */
 736 static void
 737 remove_tempfile(void)
 738 {
 739         int ret;
 740 
 741         if (tempfile != NULL) {
 742                 if (fclose(tempfile) == EOF)
 743                         (void) warn(gettext("Could not close temporary file"));
 744                 tempfile = NULL;
 745         }
 746 
 747         if (tempfilename[0] != '\0') {
 748                 do {
 749                         ret = remove(tempfilename);
 750                 } while (ret == -1 && errno == EINTR);
 751                 if (ret == -1)
 752                         warn(gettext("Could not remove temporary file"));
 753                 tempfilename[0] = '\0';
 754         }
 755 }
 756 
 757 /*
 758  * Launch private svc.configd(1M) for manipulating alternate repositories.
 759  */
 760 static void
 761 start_private_repository(engine_state_t *est)
 762 {
 763         int fd, stat;
 764         struct door_info info;
 765         pid_t pid;
 766 
 767         /*
 768          * 1.  Create a temporary file for the door.
 769          */
 770         if (est->sc_repo_doorname != NULL)
 771                 free((void *)est->sc_repo_doorname);
 772 
 773         est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
 774         if (est->sc_repo_doorname == NULL)
 775                 uu_die(gettext("Could not acquire temporary filename"));
 776 
 777         fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
 778         if (fd < 0)
 779                 uu_die(gettext("Could not create temporary file for "
 780                     "repository server"));
 781 
 782         (void) close(fd);
 783 
 784         /*
 785          * 2.  Launch a configd with that door, using the specified
 786          * repository.
 787          */
 788         if ((est->sc_repo_pid = fork()) == 0) {
 789                 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
 790                     "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
 791                     NULL);
 792                 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
 793         } else if (est->sc_repo_pid == -1)
 794                 uu_die(gettext("Attempt to fork failed"));
 795 
 796         do {
 797                 pid = waitpid(est->sc_repo_pid, &stat, 0);
 798         } while (pid == -1 && errno == EINTR);
 799 
 800         if (pid == -1)
 801                 uu_die(gettext("Could not waitpid() for repository server"));
 802 
 803         if (!WIFEXITED(stat)) {
 804                 uu_die(gettext("Repository server failed (status %d).\n"),
 805                     stat);
 806         } else if (WEXITSTATUS(stat) != 0) {
 807                 uu_die(gettext("Repository server failed (exit %d).\n"),
 808                     WEXITSTATUS(stat));
 809         }
 810 
 811         /*
 812          * See if it was successful by checking if the door is a door.
 813          */
 814 
 815         fd = open(est->sc_repo_doorname, O_RDWR);
 816         if (fd < 0)
 817                 uu_die(gettext("Could not open door \"%s\""),
 818                     est->sc_repo_doorname);
 819 
 820         if (door_info(fd, &info) < 0)
 821                 uu_die(gettext("Unexpected door_info() error"));
 822 
 823         if (close(fd) == -1)
 824                 warn(gettext("Could not close repository door"),
 825                     strerror(errno));
 826 
 827         est->sc_repo_pid = info.di_target;
 828 }
 829 
 830 void
 831 lscf_cleanup(void)
 832 {
 833         /*
 834          * In the case where we've launched a private svc.configd(1M)
 835          * instance, we must terminate our child and remove the temporary
 836          * rendezvous point.
 837          */
 838         if (est->sc_repo_pid > 0) {
 839                 (void) kill(est->sc_repo_pid, SIGTERM);
 840                 (void) waitpid(est->sc_repo_pid, NULL, 0);
 841                 (void) unlink(est->sc_repo_doorname);
 842 
 843                 est->sc_repo_pid = 0;
 844         }
 845 }
 846 
 847 void
 848 unselect_cursnap(void)
 849 {
 850         void *cookie;
 851 
 852         cur_level = NULL;
 853 
 854         cookie = NULL;
 855         while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
 856                 scf_snaplevel_destroy(cur_elt->sl);
 857                 free(cur_elt);
 858         }
 859 
 860         scf_snapshot_destroy(cur_snap);
 861         cur_snap = NULL;
 862 }
 863 
 864 void
 865 lscf_prep_hndl(void)
 866 {
 867         if (g_hndl != NULL)
 868                 return;
 869 
 870         g_hndl = scf_handle_create(SCF_VERSION);
 871         if (g_hndl == NULL)
 872                 scfdie();
 873 
 874         if (est->sc_repo_filename != NULL)
 875                 start_private_repository(est);
 876 
 877         if (est->sc_repo_doorname != NULL) {
 878                 scf_value_t *repo_value;
 879                 int ret;
 880 
 881                 repo_value = scf_value_create(g_hndl);
 882                 if (repo_value == NULL)
 883                         scfdie();
 884 
 885                 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
 886                 assert(ret == SCF_SUCCESS);
 887 
 888                 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
 889                     SCF_SUCCESS)
 890                         scfdie();
 891 
 892                 scf_value_destroy(repo_value);
 893         }
 894 
 895         if (scf_handle_bind(g_hndl) != 0)
 896                 uu_die(gettext("Could not connect to repository server: %s.\n"),
 897                     scf_strerror(scf_error()));
 898 
 899         cur_scope = scf_scope_create(g_hndl);
 900         if (cur_scope == NULL)
 901                 scfdie();
 902 
 903         if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
 904                 scfdie();
 905 }
 906 
 907 static void
 908 repository_teardown(void)
 909 {
 910         if (g_hndl != NULL) {
 911                 if (cur_snap != NULL)
 912                         unselect_cursnap();
 913                 scf_instance_destroy(cur_inst);
 914                 scf_service_destroy(cur_svc);
 915                 scf_scope_destroy(cur_scope);
 916                 scf_handle_destroy(g_hndl);
 917                 cur_inst = NULL;
 918                 cur_svc = NULL;
 919                 cur_scope = NULL;
 920                 g_hndl = NULL;
 921                 lscf_cleanup();
 922         }
 923 }
 924 
 925 void
 926 lscf_set_repository(const char *repfile, int force)
 927 {
 928         repository_teardown();
 929 
 930         if (est->sc_repo_filename != NULL) {
 931                 free((void *)est->sc_repo_filename);
 932                 est->sc_repo_filename = NULL;
 933         }
 934 
 935         if ((force == 0) && (access(repfile, R_OK) != 0)) {
 936                 /*
 937                  * Repository file does not exist
 938                  * or has no read permission.
 939                  */
 940                 warn(gettext("Cannot access \"%s\": %s\n"),
 941                     repfile, strerror(errno));
 942         } else {
 943                 est->sc_repo_filename = safe_strdup(repfile);
 944         }
 945 
 946         lscf_prep_hndl();
 947 }
 948 
 949 void
 950 lscf_init()
 951 {
 952         if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
 953             (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
 954             (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
 955             0 ||
 956             (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
 957                 scfdie();
 958 
 959         max_scf_len = max_scf_fmri_len;
 960         if (max_scf_name_len > max_scf_len)
 961                 max_scf_len = max_scf_name_len;
 962         if (max_scf_pg_type_len > max_scf_len)
 963                 max_scf_len = max_scf_pg_type_len;
 964         /*
 965          * When a value of type opaque is represented as a string, the
 966          * string contains 2 characters for every byte of data.  That is
 967          * because the string contains the hex representation of the opaque
 968          * value.
 969          */
 970         if (2 * max_scf_value_len > max_scf_len)
 971                 max_scf_len = 2 * max_scf_value_len;
 972 
 973         if (atexit(remove_tempfile) != 0)
 974                 uu_die(gettext("Could not register atexit() function"));
 975 
 976         emsg_entity_not_selected = gettext("An entity is not selected.\n");
 977         emsg_permission_denied = gettext("Permission denied.\n");
 978         emsg_create_xml = gettext("Could not create XML node.\n");
 979         emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
 980         emsg_invalid_for_snapshot =
 981             gettext("Invalid operation on a snapshot.\n");
 982         emsg_read_only = gettext("Backend read-only.\n");
 983         emsg_deleted = gettext("Current selection has been deleted.\n");
 984         emsg_invalid_pg_name =
 985             gettext("Invalid property group name \"%s\".\n");
 986         emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
 987         emsg_no_such_pg = gettext("No such property group \"%s\".\n");
 988         emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
 989             "with invalid name \"%s\".\n");
 990         emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
 991             "group with invalid name \"%s\" or type \"%s\".\n");
 992         emsg_pg_added = gettext("%s changed unexpectedly "
 993             "(property group \"%s\" added).\n");
 994         emsg_pg_changed = gettext("%s changed unexpectedly "
 995             "(property group \"%s\" changed).\n");
 996         emsg_pg_deleted = gettext("%s changed unexpectedly "
 997             "(property group \"%s\" or an ancestor was deleted).\n");
 998         emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
 999             "in %s (permission denied).\n");
1000         emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1001             "in %s (permission denied).\n");
1002         emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1003             "in %s (permission denied).\n");
1004         emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1005             "(permission denied).\n");
1006         emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1007             "new dependent \"%s\" because it already exists).  Warning: The "
1008             "current dependent's target (%s) does not exist.\n");
1009         emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1010             "dependent \"%s\" because it already exists).  Warning: The "
1011             "current dependent's target (%s) does not have a dependency named "
1012             "\"%s\" as expected.\n");
1013 
1014         string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1015             offsetof(string_list_t, node), NULL, 0);
1016         snaplevel_pool = uu_list_pool_create("snaplevels",
1017             sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1018             NULL, 0);
1019 }
1020 
1021 
1022 static const char *
1023 prop_to_typestr(const scf_property_t *prop)
1024 {
1025         scf_type_t ty;
1026 
1027         if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1028                 scfdie();
1029 
1030         return (scf_type_to_string(ty));
1031 }
1032 
1033 static scf_type_t
1034 string_to_type(const char *type)
1035 {
1036         size_t len = strlen(type);
1037         char *buf;
1038 
1039         if (len == 0 || type[len - 1] != ':')
1040                 return (SCF_TYPE_INVALID);
1041 
1042         buf = (char *)alloca(len + 1);
1043         (void) strlcpy(buf, type, len + 1);
1044         buf[len - 1] = 0;
1045 
1046         return (scf_string_to_type(buf));
1047 }
1048 
1049 static scf_value_t *
1050 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1051 {
1052         scf_value_t *v;
1053         char *dup, *nstr;
1054         size_t len;
1055 
1056         v = scf_value_create(g_hndl);
1057         if (v == NULL)
1058                 scfdie();
1059 
1060         len = strlen(str);
1061         if (require_quotes &&
1062             (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1063                 semerr(gettext("Multiple string values or string values "
1064                     "with spaces must be quoted with '\"'.\n"));
1065                 scf_value_destroy(v);
1066                 return (NULL);
1067         }
1068 
1069         nstr = dup = safe_strdup(str);
1070         if (dup[0] == '\"') {
1071                 /*
1072                  * Strip out the first and the last quote.
1073                  */
1074                 dup[len - 1] = '\0';
1075                 nstr = dup + 1;
1076         }
1077 
1078         if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1079                 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1080                 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1081                     scf_type_to_string(ty), nstr);
1082                 scf_value_destroy(v);
1083                 v = NULL;
1084         }
1085         free(dup);
1086         return (v);
1087 }
1088 
1089 /*
1090  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1091  * Optionally append a comment prefix ('#') to newlines ('\n').
1092  */
1093 static int
1094 quote_and_print(const char *str, FILE *strm, int commentnl)
1095 {
1096         const char *cp;
1097 
1098         for (cp = str; *cp != '\0'; ++cp) {
1099                 if (*cp == '"' || *cp == '\\')
1100                         (void) putc('\\', strm);
1101 
1102                 (void) putc(*cp, strm);
1103 
1104                 if (commentnl && *cp == '\n') {
1105                         (void) putc('#', strm);
1106                 }
1107         }
1108 
1109         return (ferror(strm));
1110 }
1111 
1112 /*
1113  * These wrappers around lowlevel functions provide consistent error checking
1114  * and warnings.
1115  */
1116 static int
1117 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1118 {
1119         if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1120                 return (0);
1121 
1122         if (scf_error() != SCF_ERROR_NOT_FOUND)
1123                 scfdie();
1124 
1125         if (g_verbose) {
1126                 ssize_t len;
1127                 char *fmri;
1128 
1129                 len = scf_pg_to_fmri(pg, NULL, 0);
1130                 if (len < 0)
1131                         scfdie();
1132 
1133                 fmri = safe_malloc(len + 1);
1134 
1135                 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1136                         scfdie();
1137 
1138                 warn(gettext("Expected property %s of property group %s is "
1139                     "missing.\n"), propname, fmri);
1140 
1141                 free(fmri);
1142         }
1143 
1144         return (-1);
1145 }
1146 
1147 static int
1148 prop_check_type(scf_property_t *prop, scf_type_t ty)
1149 {
1150         scf_type_t pty;
1151 
1152         if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1153                 scfdie();
1154 
1155         if (ty == pty)
1156                 return (0);
1157 
1158         if (g_verbose) {
1159                 ssize_t len;
1160                 char *fmri;
1161                 const char *tystr;
1162 
1163                 len = scf_property_to_fmri(prop, NULL, 0);
1164                 if (len < 0)
1165                         scfdie();
1166 
1167                 fmri = safe_malloc(len + 1);
1168 
1169                 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1170                         scfdie();
1171 
1172                 tystr = scf_type_to_string(ty);
1173                 if (tystr == NULL)
1174                         tystr = "?";
1175 
1176                 warn(gettext("Property %s is not of expected type %s.\n"),
1177                     fmri, tystr);
1178 
1179                 free(fmri);
1180         }
1181 
1182         return (-1);
1183 }
1184 
1185 static int
1186 prop_get_val(scf_property_t *prop, scf_value_t *val)
1187 {
1188         scf_error_t err;
1189 
1190         if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1191                 return (0);
1192 
1193         err = scf_error();
1194 
1195         if (err != SCF_ERROR_NOT_FOUND &&
1196             err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1197             err != SCF_ERROR_PERMISSION_DENIED)
1198                 scfdie();
1199 
1200         if (g_verbose) {
1201                 ssize_t len;
1202                 char *fmri, *emsg;
1203 
1204                 len = scf_property_to_fmri(prop, NULL, 0);
1205                 if (len < 0)
1206                         scfdie();
1207 
1208                 fmri = safe_malloc(len + 1);
1209 
1210                 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1211                         scfdie();
1212 
1213                 if (err == SCF_ERROR_NOT_FOUND)
1214                         emsg = gettext("Property %s has no values; expected "
1215                             "one.\n");
1216                 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1217                         emsg = gettext("Property %s has multiple values; "
1218                             "expected one.\n");
1219                 else
1220                         emsg = gettext("No permission to read property %s.\n");
1221 
1222                 warn(emsg, fmri);
1223 
1224                 free(fmri);
1225         }
1226 
1227         return (-1);
1228 }
1229 
1230 
1231 static boolean_t
1232 snaplevel_is_instance(const scf_snaplevel_t *level)
1233 {
1234         if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1235                 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1236                         scfdie();
1237                 return (0);
1238         } else {
1239                 return (1);
1240         }
1241 }
1242 
1243 /*
1244  * Decode FMRI into a service or instance, and put the result in *ep.  If
1245  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1246  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1247  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1248  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1249  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1250  * whether *ep is a service.
1251  */
1252 static scf_error_t
1253 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1254 {
1255         char *fmri_copy;
1256         const char *sstr, *istr, *pgstr;
1257         scf_service_t *svc;
1258         scf_instance_t *inst;
1259 
1260         fmri_copy = strdup(fmri);
1261         if (fmri_copy == NULL)
1262                 return (SCF_ERROR_NO_MEMORY);
1263 
1264         if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1265             SCF_SUCCESS) {
1266                 free(fmri_copy);
1267                 return (SCF_ERROR_INVALID_ARGUMENT);
1268         }
1269 
1270         free(fmri_copy);
1271 
1272         if (sstr == NULL || pgstr != NULL)
1273                 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1274 
1275         if (istr == NULL) {
1276                 svc = scf_service_create(h);
1277                 if (svc == NULL)
1278                         return (SCF_ERROR_NO_MEMORY);
1279 
1280                 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1281                     SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1282                         if (scf_error() != SCF_ERROR_NOT_FOUND)
1283                                 scfdie();
1284 
1285                         return (SCF_ERROR_NOT_FOUND);
1286                 }
1287 
1288                 *ep = svc;
1289                 *isservice = 1;
1290         } else {
1291                 inst = scf_instance_create(h);
1292                 if (inst == NULL)
1293                         return (SCF_ERROR_NO_MEMORY);
1294 
1295                 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1296                     NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1297                         if (scf_error() != SCF_ERROR_NOT_FOUND)
1298                                 scfdie();
1299 
1300                         return (SCF_ERROR_NOT_FOUND);
1301                 }
1302 
1303                 *ep = inst;
1304                 *isservice = 0;
1305         }
1306 
1307         return (SCF_ERROR_NONE);
1308 }
1309 
1310 /*
1311  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1312  * *ep, and set or clear *isservicep if it is a service or an instance.
1313  * Returns
1314  *   SCF_ERROR_NONE - success
1315  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1316  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1317  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1318  *   SCF_ERROR_NOT_FOUND - no such scope
1319  *   SCF_ERROR_PERMISSION_DENIED
1320  *   SCF_ERROR_BACKEND_READONLY
1321  *   SCF_ERROR_BACKEND_ACCESS
1322  */
1323 static scf_error_t
1324 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1325 {
1326         char *fmri_copy;
1327         const char *scstr, *sstr, *istr, *pgstr;
1328         scf_scope_t *scope = NULL;
1329         scf_service_t *svc = NULL;
1330         scf_instance_t *inst = NULL;
1331         scf_error_t scfe;
1332 
1333         fmri_copy = safe_strdup(fmri);
1334 
1335         if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1336             0) {
1337                 free(fmri_copy);
1338                 return (SCF_ERROR_INVALID_ARGUMENT);
1339         }
1340 
1341         if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1342                 free(fmri_copy);
1343                 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1344         }
1345 
1346         *ep = NULL;
1347 
1348         if ((scope = scf_scope_create(h)) == NULL ||
1349             (svc = scf_service_create(h)) == NULL ||
1350             (inst = scf_instance_create(h)) == NULL) {
1351                 scfe = SCF_ERROR_NO_MEMORY;
1352                 goto out;
1353         }
1354 
1355 get_scope:
1356         if (scf_handle_get_scope(h, scstr, scope) != 0) {
1357                 switch (scf_error()) {
1358                 case SCF_ERROR_CONNECTION_BROKEN:
1359                         scfdie();
1360                         /* NOTREACHED */
1361 
1362                 case SCF_ERROR_NOT_FOUND:
1363                         scfe = SCF_ERROR_NOT_FOUND;
1364                         goto out;
1365 
1366                 case SCF_ERROR_HANDLE_MISMATCH:
1367                 case SCF_ERROR_NOT_BOUND:
1368                 case SCF_ERROR_INVALID_ARGUMENT:
1369                 default:
1370                         bad_error("scf_handle_get_scope", scf_error());
1371                 }
1372         }
1373 
1374 get_svc:
1375         if (scf_scope_get_service(scope, sstr, svc) != 0) {
1376                 switch (scf_error()) {
1377                 case SCF_ERROR_CONNECTION_BROKEN:
1378                         scfdie();
1379                         /* NOTREACHED */
1380 
1381                 case SCF_ERROR_DELETED:
1382                         goto get_scope;
1383 
1384                 case SCF_ERROR_NOT_FOUND:
1385                         break;
1386 
1387                 case SCF_ERROR_HANDLE_MISMATCH:
1388                 case SCF_ERROR_INVALID_ARGUMENT:
1389                 case SCF_ERROR_NOT_BOUND:
1390                 case SCF_ERROR_NOT_SET:
1391                 default:
1392                         bad_error("scf_scope_get_service", scf_error());
1393                 }
1394 
1395                 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1396                         switch (scf_error()) {
1397                         case SCF_ERROR_CONNECTION_BROKEN:
1398                                 scfdie();
1399                                 /* NOTREACHED */
1400 
1401                         case SCF_ERROR_DELETED:
1402                                 goto get_scope;
1403 
1404                         case SCF_ERROR_PERMISSION_DENIED:
1405                         case SCF_ERROR_BACKEND_READONLY:
1406                         case SCF_ERROR_BACKEND_ACCESS:
1407                                 scfe = scf_error();
1408                                 goto out;
1409 
1410                         case SCF_ERROR_HANDLE_MISMATCH:
1411                         case SCF_ERROR_INVALID_ARGUMENT:
1412                         case SCF_ERROR_NOT_BOUND:
1413                         case SCF_ERROR_NOT_SET:
1414                         default:
1415                                 bad_error("scf_scope_get_service", scf_error());
1416                         }
1417                 }
1418         }
1419 
1420         if (istr == NULL) {
1421                 scfe = SCF_ERROR_NONE;
1422                 *ep = svc;
1423                 *isservicep = 1;
1424                 goto out;
1425         }
1426 
1427 get_inst:
1428         if (scf_service_get_instance(svc, istr, inst) != 0) {
1429                 switch (scf_error()) {
1430                 case SCF_ERROR_CONNECTION_BROKEN:
1431                         scfdie();
1432                         /* NOTREACHED */
1433 
1434                 case SCF_ERROR_DELETED:
1435                         goto get_svc;
1436 
1437                 case SCF_ERROR_NOT_FOUND:
1438                         break;
1439 
1440                 case SCF_ERROR_HANDLE_MISMATCH:
1441                 case SCF_ERROR_INVALID_ARGUMENT:
1442                 case SCF_ERROR_NOT_BOUND:
1443                 case SCF_ERROR_NOT_SET:
1444                 default:
1445                         bad_error("scf_service_get_instance", scf_error());
1446                 }
1447 
1448                 if (scf_service_add_instance(svc, istr, inst) != 0) {
1449                         switch (scf_error()) {
1450                         case SCF_ERROR_CONNECTION_BROKEN:
1451                                 scfdie();
1452                                 /* NOTREACHED */
1453 
1454                         case SCF_ERROR_DELETED:
1455                                 goto get_svc;
1456 
1457                         case SCF_ERROR_PERMISSION_DENIED:
1458                         case SCF_ERROR_BACKEND_READONLY:
1459                         case SCF_ERROR_BACKEND_ACCESS:
1460                                 scfe = scf_error();
1461                                 goto out;
1462 
1463                         case SCF_ERROR_HANDLE_MISMATCH:
1464                         case SCF_ERROR_INVALID_ARGUMENT:
1465                         case SCF_ERROR_NOT_BOUND:
1466                         case SCF_ERROR_NOT_SET:
1467                         default:
1468                                 bad_error("scf_service_add_instance",
1469                                     scf_error());
1470                         }
1471                 }
1472         }
1473 
1474         scfe = SCF_ERROR_NONE;
1475         *ep = inst;
1476         *isservicep = 0;
1477 
1478 out:
1479         if (*ep != inst)
1480                 scf_instance_destroy(inst);
1481         if (*ep != svc)
1482                 scf_service_destroy(svc);
1483         scf_scope_destroy(scope);
1484         free(fmri_copy);
1485         return (scfe);
1486 }
1487 
1488 /*
1489  * Create or update a snapshot of inst.  snap is a required scratch object.
1490  *
1491  * Returns
1492  *   0 - success
1493  *   ECONNABORTED - repository connection broken
1494  *   EPERM - permission denied
1495  *   ENOSPC - configd is out of resources
1496  *   ECANCELED - inst was deleted
1497  *   -1 - unknown libscf error (message printed)
1498  */
1499 static int
1500 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1501 {
1502 again:
1503         if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1504                 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1505                         switch (scf_error()) {
1506                         case SCF_ERROR_CONNECTION_BROKEN:
1507                         case SCF_ERROR_PERMISSION_DENIED:
1508                         case SCF_ERROR_NO_RESOURCES:
1509                                 return (scferror2errno(scf_error()));
1510 
1511                         case SCF_ERROR_NOT_SET:
1512                         case SCF_ERROR_INVALID_ARGUMENT:
1513                         default:
1514                                 bad_error("_scf_snapshot_take_attach",
1515                                     scf_error());
1516                         }
1517                 }
1518         } else {
1519                 switch (scf_error()) {
1520                 case SCF_ERROR_NOT_FOUND:
1521                         break;
1522 
1523                 case SCF_ERROR_DELETED:
1524                 case SCF_ERROR_CONNECTION_BROKEN:
1525                         return (scferror2errno(scf_error()));
1526 
1527                 case SCF_ERROR_HANDLE_MISMATCH:
1528                 case SCF_ERROR_NOT_BOUND:
1529                 case SCF_ERROR_INVALID_ARGUMENT:
1530                 case SCF_ERROR_NOT_SET:
1531                 default:
1532                         bad_error("scf_instance_get_snapshot", scf_error());
1533                 }
1534 
1535                 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1536                         switch (scf_error()) {
1537                         case SCF_ERROR_EXISTS:
1538                                 goto again;
1539 
1540                         case SCF_ERROR_CONNECTION_BROKEN:
1541                         case SCF_ERROR_NO_RESOURCES:
1542                         case SCF_ERROR_PERMISSION_DENIED:
1543                                 return (scferror2errno(scf_error()));
1544 
1545                         default:
1546                                 scfwarn();
1547                                 return (-1);
1548 
1549                         case SCF_ERROR_NOT_SET:
1550                         case SCF_ERROR_INTERNAL:
1551                         case SCF_ERROR_INVALID_ARGUMENT:
1552                         case SCF_ERROR_HANDLE_MISMATCH:
1553                                 bad_error("_scf_snapshot_take_new",
1554                                     scf_error());
1555                         }
1556                 }
1557         }
1558 
1559         return (0);
1560 }
1561 
1562 static int
1563 refresh_running_snapshot(void *entity)
1564 {
1565         scf_snapshot_t *snap;
1566         int r;
1567 
1568         if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1569                 scfdie();
1570         r = take_snap(entity, snap_running, snap);
1571         scf_snapshot_destroy(snap);
1572 
1573         return (r);
1574 }
1575 
1576 /*
1577  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1578  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1579  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1580  * for scratch space.  Returns
1581  *   0 - success
1582  *   ECONNABORTED - repository connection broken
1583  *   ECANCELED - entity was deleted
1584  *   EACCES - backend denied access
1585  *   EPERM - permission denied
1586  *   ENOSPC - repository server out of resources
1587  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1588  */
1589 static int
1590 refresh_entity(int isservice, void *entity, const char *fmri,
1591     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1592 {
1593         scf_error_t scfe;
1594         int r;
1595 
1596         if (!isservice) {
1597                 /*
1598                  * Let restarter handles refreshing and making new running
1599                  * snapshot only if operating on a live repository and not
1600                  * running in early import.
1601                  */
1602                 if (est->sc_repo_filename == NULL &&
1603                     est->sc_repo_doorname == NULL &&
1604                     est->sc_in_emi == 0) {
1605                         if (_smf_refresh_instance_i(entity) == 0) {
1606                                 if (g_verbose)
1607                                         warn(gettext("Refreshed %s.\n"), fmri);
1608                                 return (0);
1609                         }
1610 
1611                         switch (scf_error()) {
1612                         case SCF_ERROR_BACKEND_ACCESS:
1613                                 return (EACCES);
1614 
1615                         case SCF_ERROR_PERMISSION_DENIED:
1616                                 return (EPERM);
1617 
1618                         default:
1619                                 return (-1);
1620                         }
1621                 } else {
1622                         r = refresh_running_snapshot(entity);
1623                         switch (r) {
1624                         case 0:
1625                                 break;
1626 
1627                         case ECONNABORTED:
1628                         case ECANCELED:
1629                         case EPERM:
1630                         case ENOSPC:
1631                                 break;
1632 
1633                         default:
1634                                 bad_error("refresh_running_snapshot",
1635                                     scf_error());
1636                         }
1637 
1638                         return (r);
1639                 }
1640         }
1641 
1642         if (scf_iter_service_instances(iter, entity) != 0) {
1643                 switch (scf_error()) {
1644                 case SCF_ERROR_CONNECTION_BROKEN:
1645                         return (ECONNABORTED);
1646 
1647                 case SCF_ERROR_DELETED:
1648                         return (ECANCELED);
1649 
1650                 case SCF_ERROR_HANDLE_MISMATCH:
1651                 case SCF_ERROR_NOT_BOUND:
1652                 case SCF_ERROR_NOT_SET:
1653                 default:
1654                         bad_error("scf_iter_service_instances", scf_error());
1655                 }
1656         }
1657 
1658         for (;;) {
1659                 r = scf_iter_next_instance(iter, inst);
1660                 if (r == 0)
1661                         break;
1662                 if (r != 1) {
1663                         switch (scf_error()) {
1664                         case SCF_ERROR_CONNECTION_BROKEN:
1665                                 return (ECONNABORTED);
1666 
1667                         case SCF_ERROR_DELETED:
1668                                 return (ECANCELED);
1669 
1670                         case SCF_ERROR_HANDLE_MISMATCH:
1671                         case SCF_ERROR_NOT_BOUND:
1672                         case SCF_ERROR_NOT_SET:
1673                         case SCF_ERROR_INVALID_ARGUMENT:
1674                         default:
1675                                 bad_error("scf_iter_next_instance",
1676                                     scf_error());
1677                         }
1678                 }
1679 
1680                 /*
1681                  * Similarly, just take a new running snapshot if operating on
1682                  * a non-live repository or running during early import.
1683                  */
1684                 if (est->sc_repo_filename != NULL ||
1685                     est->sc_repo_doorname != NULL ||
1686                     est->sc_in_emi == 1) {
1687                         r = refresh_running_snapshot(inst);
1688                         switch (r) {
1689                         case 0:
1690                                 continue;
1691 
1692                         case ECONNABORTED:
1693                         case ECANCELED:
1694                         case EPERM:
1695                         case ENOSPC:
1696                                 break;
1697                         default:
1698                                 bad_error("refresh_running_snapshot",
1699                                     scf_error());
1700                         }
1701 
1702                         return (r);
1703 
1704                 }
1705 
1706                 if (_smf_refresh_instance_i(inst) == 0) {
1707                         if (g_verbose) {
1708                                 if (scf_instance_get_name(inst, name_buf,
1709                                     max_scf_name_len + 1) < 0)
1710                                         (void) strcpy(name_buf, "?");
1711 
1712                                 warn(gettext("Refreshed %s:%s.\n"),
1713                                     fmri, name_buf);
1714                         }
1715                 } else {
1716                         if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1717                             g_verbose) {
1718                                 scfe = scf_error();
1719 
1720                                 if (scf_instance_to_fmri(inst, name_buf,
1721                                     max_scf_name_len + 1) < 0)
1722                                         (void) strcpy(name_buf, "?");
1723 
1724                                 warn(gettext(
1725                                     "Refresh of %s:%s failed: %s.\n"), fmri,
1726                                     name_buf, scf_strerror(scfe));
1727                         }
1728                 }
1729         }
1730 
1731         return (0);
1732 }
1733 
1734 static void
1735 private_refresh(void)
1736 {
1737         scf_instance_t *pinst = NULL;
1738         scf_iter_t *piter = NULL;
1739         ssize_t fmrilen;
1740         size_t bufsz;
1741         char *fmribuf;
1742         void *ent;
1743         int issvc;
1744         int r;
1745 
1746         if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1747                 return;
1748 
1749         assert(cur_svc != NULL);
1750 
1751         bufsz = max_scf_fmri_len + 1;
1752         fmribuf = safe_malloc(bufsz);
1753         if (cur_inst) {
1754                 issvc = 0;
1755                 ent = cur_inst;
1756                 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1757         } else {
1758                 issvc = 1;
1759                 ent = cur_svc;
1760                 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1761                 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1762                         scfdie();
1763 
1764                 if ((piter = scf_iter_create(g_hndl)) == NULL)
1765                         scfdie();
1766         }
1767         if (fmrilen < 0) {
1768                 free(fmribuf);
1769                 if (scf_error() != SCF_ERROR_DELETED)
1770                         scfdie();
1771 
1772                 warn(emsg_deleted);
1773                 return;
1774         }
1775         assert(fmrilen < bufsz);
1776 
1777         r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1778         switch (r) {
1779         case 0:
1780                 break;
1781 
1782         case ECONNABORTED:
1783                 warn(gettext("Could not refresh %s "
1784                     "(repository connection broken).\n"), fmribuf);
1785                 break;
1786 
1787         case ECANCELED:
1788                 warn(emsg_deleted);
1789                 break;
1790 
1791         case EPERM:
1792                 warn(gettext("Could not refresh %s "
1793                     "(permission denied).\n"), fmribuf);
1794                 break;
1795 
1796         case ENOSPC:
1797                 warn(gettext("Could not refresh %s "
1798                     "(repository server out of resources).\n"),
1799                     fmribuf);
1800                 break;
1801 
1802         case EACCES:
1803         default:
1804                 bad_error("refresh_entity", scf_error());
1805         }
1806 
1807         if (issvc) {
1808                 scf_instance_destroy(pinst);
1809                 scf_iter_destroy(piter);
1810         }
1811 
1812         free(fmribuf);
1813 }
1814 
1815 
1816 static int
1817 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1818 {
1819         cbp->sc_err = scferror2errno(err);
1820         return (UU_WALK_ERROR);
1821 }
1822 
1823 static int
1824 stash_scferror(scf_callback_t *cbp)
1825 {
1826         return (stash_scferror_err(cbp, scf_error()));
1827 }
1828 
1829 static int select_inst(const char *);
1830 static int select_svc(const char *);
1831 
1832 /*
1833  * Take a property that does not have a type and check to see if a type
1834  * exists or can be gleened from the current data.  Set the type.
1835  *
1836  * Check the current level (instance) and then check the higher level
1837  * (service).  This could be the case for adding a new property to
1838  * the instance that's going to "override" a service level property.
1839  *
1840  * For a property :
1841  * 1. Take the type from an existing property
1842  * 2. Take the type from a template entry
1843  *
1844  * If the type can not be found, then leave the type as is, and let the import
1845  * report the problem of the missing type.
1846  */
1847 static int
1848 find_current_prop_type(void *p, void *g)
1849 {
1850         property_t *prop = p;
1851         scf_callback_t *lcb = g;
1852         pgroup_t *pg = NULL;
1853 
1854         const char *fmri = NULL;
1855         char *lfmri = NULL;
1856         char *cur_selection = NULL;
1857 
1858         scf_propertygroup_t *sc_pg = NULL;
1859         scf_property_t *sc_prop = NULL;
1860         scf_pg_tmpl_t *t_pg = NULL;
1861         scf_prop_tmpl_t *t_prop = NULL;
1862         scf_type_t prop_type;
1863 
1864         value_t *vp;
1865         int issvc = lcb->sc_service;
1866         int r = UU_WALK_ERROR;
1867 
1868         if (prop->sc_value_type != SCF_TYPE_INVALID)
1869                 return (UU_WALK_NEXT);
1870 
1871         t_prop = scf_tmpl_prop_create(g_hndl);
1872         sc_prop = scf_property_create(g_hndl);
1873         if (sc_prop == NULL || t_prop == NULL) {
1874                 warn(gettext("Unable to create the property to attempt and "
1875                     "find a missing type.\n"));
1876 
1877                 scf_property_destroy(sc_prop);
1878                 scf_tmpl_prop_destroy(t_prop);
1879 
1880                 return (UU_WALK_ERROR);
1881         }
1882 
1883         if (lcb->sc_flags == 1) {
1884                 pg = lcb->sc_parent;
1885                 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1886                 fmri = pg->sc_parent->sc_fmri;
1887 retry_pg:
1888                 if (cur_svc && cur_selection == NULL) {
1889                         cur_selection = safe_malloc(max_scf_fmri_len + 1);
1890                         lscf_get_selection_str(cur_selection,
1891                             max_scf_fmri_len + 1);
1892 
1893                         if (strcmp(cur_selection, fmri) != 0) {
1894                                 lscf_select(fmri);
1895                         } else {
1896                                 free(cur_selection);
1897                                 cur_selection = NULL;
1898                         }
1899                 } else {
1900                         lscf_select(fmri);
1901                 }
1902 
1903                 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1904                         warn(gettext("Unable to create property group to "
1905                             "find a missing property type.\n"));
1906 
1907                         goto out;
1908                 }
1909 
1910                 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1911                         /*
1912                          * If this is the sc_pg from the parent
1913                          * let the caller clean up the sc_pg,
1914                          * and just throw it away in this case.
1915                          */
1916                         if (sc_pg != lcb->sc_parent)
1917                                 scf_pg_destroy(sc_pg);
1918 
1919                         sc_pg = NULL;
1920                         if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1921                                 warn(gettext("Unable to create template "
1922                                     "property group to find a property "
1923                                     "type.\n"));
1924 
1925                                 goto out;
1926                         }
1927 
1928                         if (scf_tmpl_get_by_pg_name(fmri, NULL,
1929                             pg->sc_pgroup_name, NULL, t_pg,
1930                             SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1931                                 /*
1932                                  * if instance get service and jump back
1933                                  */
1934                                 scf_tmpl_pg_destroy(t_pg);
1935                                 t_pg = NULL;
1936                                 if (issvc == 0) {
1937                                         entity_t *e = pg->sc_parent->sc_parent;
1938 
1939                                         fmri = e->sc_fmri;
1940                                         issvc = 1;
1941                                         goto retry_pg;
1942                                 } else {
1943                                         goto out;
1944                                 }
1945                         }
1946                 }
1947         } else {
1948                 sc_pg = lcb->sc_parent;
1949         }
1950 
1951         /*
1952          * Attempt to get the type from an existing property.  If the property
1953          * cannot be found then attempt to get the type from a template entry
1954          * for the property.
1955          *
1956          * Finally, if at the instance level look at the service level.
1957          */
1958         if (sc_pg != NULL &&
1959             pg_get_prop(sc_pg, prop->sc_property_name,
1960             sc_prop) == SCF_SUCCESS &&
1961             scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1962                 prop->sc_value_type = prop_type;
1963 
1964                 /*
1965                  * Found a type, update the value types and validate
1966                  * the actual value against this type.
1967                  */
1968                 for (vp = uu_list_first(prop->sc_property_values);
1969                     vp != NULL;
1970                     vp = uu_list_next(prop->sc_property_values, vp)) {
1971                         vp->sc_type = prop->sc_value_type;
1972                         lxml_store_value(vp, 0, NULL);
1973                 }
1974 
1975                 r = UU_WALK_NEXT;
1976                 goto out;
1977         }
1978 
1979         /*
1980          * If we get here with t_pg set to NULL then we had to have
1981          * gotten an sc_pg but that sc_pg did not have the property
1982          * we are looking for.   So if the t_pg is not null look up
1983          * the template entry for the property.
1984          *
1985          * If the t_pg is null then need to attempt to get a matching
1986          * template entry for the sc_pg, and see if there is a property
1987          * entry for that template entry.
1988          */
1989 do_tmpl :
1990         if (t_pg != NULL &&
1991             scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1992             t_prop, 0) == SCF_SUCCESS) {
1993                 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1994                         prop->sc_value_type = prop_type;
1995 
1996                         /*
1997                          * Found a type, update the value types and validate
1998                          * the actual value against this type.
1999                          */
2000                         for (vp = uu_list_first(prop->sc_property_values);
2001                             vp != NULL;
2002                             vp = uu_list_next(prop->sc_property_values, vp)) {
2003                                 vp->sc_type = prop->sc_value_type;
2004                                 lxml_store_value(vp, 0, NULL);
2005                         }
2006 
2007                         r = UU_WALK_NEXT;
2008                         goto out;
2009                 }
2010         } else {
2011                 if (t_pg == NULL && sc_pg) {
2012                         if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2013                                 warn(gettext("Unable to create template "
2014                                     "property group to find a property "
2015                                     "type.\n"));
2016 
2017                                 goto out;
2018                         }
2019 
2020                         if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2021                                 scf_tmpl_pg_destroy(t_pg);
2022                                 t_pg = NULL;
2023                         } else {
2024                                 goto do_tmpl;
2025                         }
2026                 }
2027         }
2028 
2029         if (issvc == 0) {
2030                 scf_instance_t *i;
2031                 scf_service_t *s;
2032 
2033                 issvc = 1;
2034                 if (lcb->sc_flags == 1) {
2035                         entity_t *e = pg->sc_parent->sc_parent;
2036 
2037                         fmri = e->sc_fmri;
2038                         goto retry_pg;
2039                 }
2040 
2041                 /*
2042                  * because lcb->sc_flags was not set then this means
2043                  * the pg was not used and can be used here.
2044                  */
2045                 if ((pg = internal_pgroup_new()) == NULL) {
2046                         warn(gettext("Could not create internal property group "
2047                             "to find a missing type."));
2048 
2049                         goto out;
2050                 }
2051 
2052                 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2053                 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2054                     max_scf_name_len + 1) < 0)
2055                                 goto out;
2056 
2057                 i = scf_instance_create(g_hndl);
2058                 s = scf_service_create(g_hndl);
2059                 if (i == NULL || s == NULL ||
2060                     scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2061                         warn(gettext("Could not get a service for the instance "
2062                             "to find a missing type."));
2063 
2064                         goto out;
2065                 }
2066 
2067                 /*
2068                  * Check to see truly at the instance level.
2069                  */
2070                 lfmri = safe_malloc(max_scf_fmri_len + 1);
2071                 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2072                     scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2073                         goto out;
2074                 else
2075                         fmri = (const char *)lfmri;
2076 
2077                 goto retry_pg;
2078         }
2079 
2080 out :
2081         if (sc_pg != lcb->sc_parent) {
2082                 scf_pg_destroy(sc_pg);
2083         }
2084 
2085         /*
2086          * If this is true then the pg was allocated
2087          * here, and the name was set so need to free
2088          * the name and the pg.
2089          */
2090         if (pg != NULL && pg != lcb->sc_parent) {
2091                 free((char *)pg->sc_pgroup_name);
2092                 internal_pgroup_free(pg);
2093         }
2094 
2095         if (cur_selection) {
2096                 lscf_select(cur_selection);
2097                 free(cur_selection);
2098         }
2099 
2100         scf_tmpl_pg_destroy(t_pg);
2101         scf_tmpl_prop_destroy(t_prop);
2102         scf_property_destroy(sc_prop);
2103 
2104         if (r != UU_WALK_NEXT)
2105                 warn(gettext("Could not find property type for \"%s\" "
2106                     "from \"%s\"\n"), prop->sc_property_name,
2107                     fmri != NULL ? fmri : lcb->sc_source_fmri);
2108 
2109         free(lfmri);
2110 
2111         return (r);
2112 }
2113 
2114 /*
2115  * Take a property group that does not have a type and check to see if a type
2116  * exists or can be gleened from the current data.  Set the type.
2117  *
2118  * Check the current level (instance) and then check the higher level
2119  * (service).  This could be the case for adding a new property to
2120  * the instance that's going to "override" a service level property.
2121  *
2122  * For a property group
2123  * 1. Take the type from an existing property group
2124  * 2. Take the type from a template entry
2125  *
2126  * If the type can not be found, then leave the type as is, and let the import
2127  * report the problem of the missing type.
2128  */
2129 static int
2130 find_current_pg_type(void *p, void *sori)
2131 {
2132         entity_t *si = sori;
2133         pgroup_t *pg = p;
2134 
2135         const char *ofmri, *fmri;
2136         char *cur_selection = NULL;
2137         char *pg_type = NULL;
2138 
2139         scf_propertygroup_t *sc_pg = NULL;
2140         scf_pg_tmpl_t *t_pg = NULL;
2141 
2142         int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2143         int r = UU_WALK_ERROR;
2144 
2145         ofmri = fmri = si->sc_fmri;
2146         if (pg->sc_pgroup_type != NULL) {
2147                 r = UU_WALK_NEXT;
2148 
2149                 goto out;
2150         }
2151 
2152         sc_pg = scf_pg_create(g_hndl);
2153         if (sc_pg == NULL) {
2154                 warn(gettext("Unable to create property group to attempt "
2155                     "and find a missing type.\n"));
2156 
2157                 return (UU_WALK_ERROR);
2158         }
2159 
2160         /*
2161          * Using get_pg() requires that the cur_svc/cur_inst be
2162          * via lscf_select.  Need to preserve the current selection
2163          * if going to use lscf_select() to set up the cur_svc/cur_inst
2164          */
2165         if (cur_svc) {
2166                 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2167                 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2168         }
2169 
2170         /*
2171          * If the property group exists get the type, and set
2172          * the pgroup_t type of that type.
2173          *
2174          * If not the check for a template pg_pattern entry
2175          * and take the type from that.
2176          */
2177 retry_svc:
2178         lscf_select(fmri);
2179 
2180         if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2181                 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2182                 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2183                     max_scf_pg_type_len + 1) != -1) {
2184                         pg->sc_pgroup_type = pg_type;
2185 
2186                         r = UU_WALK_NEXT;
2187                         goto out;
2188                 } else {
2189                         free(pg_type);
2190                 }
2191         } else {
2192                 if ((t_pg == NULL) &&
2193                     (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2194                         goto out;
2195 
2196                 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2197                     NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2198                     scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2199                         pg->sc_pgroup_type = pg_type;
2200 
2201                         r = UU_WALK_NEXT;
2202                         goto out;
2203                 }
2204         }
2205 
2206         /*
2207          * If type is not found at the instance level then attempt to
2208          * find the type at the service level.
2209          */
2210         if (!issvc) {
2211                 si = si->sc_parent;
2212                 fmri = si->sc_fmri;
2213                 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2214                 goto retry_svc;
2215         }
2216 
2217 out :
2218         if (cur_selection) {
2219                 lscf_select(cur_selection);
2220                 free(cur_selection);
2221         }
2222 
2223         /*
2224          * Now walk the properties of the property group to make sure that
2225          * all properties have the correct type and values are valid for
2226          * those types.
2227          */
2228         if (r == UU_WALK_NEXT) {
2229                 scf_callback_t cb;
2230 
2231                 cb.sc_service = issvc;
2232                 cb.sc_source_fmri = ofmri;
2233                 if (sc_pg != NULL) {
2234                         cb.sc_parent = sc_pg;
2235                         cb.sc_flags = 0;
2236                 } else {
2237                         cb.sc_parent = pg;
2238                         cb.sc_flags = 1;
2239                 }
2240 
2241                 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2242                     &cb, UU_DEFAULT) != 0) {
2243                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2244                                 bad_error("uu_list_walk", uu_error());
2245 
2246                         r = UU_WALK_ERROR;
2247                 }
2248         } else {
2249                 warn(gettext("Could not find property group type for "
2250                     "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2251         }
2252 
2253         scf_tmpl_pg_destroy(t_pg);
2254         scf_pg_destroy(sc_pg);
2255 
2256         return (r);
2257 }
2258 
2259 /*
2260  * Import.  These functions import a bundle into the repository.
2261  */
2262 
2263 /*
2264  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2265  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2266  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2267  * lcbdata->sc_err to
2268  *   ENOMEM - out of memory
2269  *   ECONNABORTED - repository connection broken
2270  *   ECANCELED - sc_trans's property group was deleted
2271  *   EINVAL - p's name is invalid (error printed)
2272  *          - p has an invalid value (error printed)
2273  */
2274 static int
2275 lscf_property_import(void *v, void *pvt)
2276 {
2277         property_t *p = v;
2278         scf_callback_t *lcbdata = pvt;
2279         value_t *vp;
2280         scf_transaction_t *trans = lcbdata->sc_trans;
2281         scf_transaction_entry_t *entr;
2282         scf_value_t *val;
2283         scf_type_t tp;
2284 
2285         if ((lcbdata->sc_flags & SCI_NOENABLED ||
2286             lcbdata->sc_flags & SCI_DELAYENABLE) &&
2287             strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2288                 lcbdata->sc_enable = p;
2289                 return (UU_WALK_NEXT);
2290         }
2291 
2292         entr = scf_entry_create(lcbdata->sc_handle);
2293         if (entr == NULL) {
2294                 switch (scf_error()) {
2295                 case SCF_ERROR_NO_MEMORY:
2296                         return (stash_scferror(lcbdata));
2297 
2298                 case SCF_ERROR_INVALID_ARGUMENT:
2299                 default:
2300                         bad_error("scf_entry_create", scf_error());
2301                 }
2302         }
2303 
2304         tp = p->sc_value_type;
2305 
2306         if (scf_transaction_property_new(trans, entr,
2307             p->sc_property_name, tp) != 0) {
2308                 switch (scf_error()) {
2309                 case SCF_ERROR_INVALID_ARGUMENT:
2310                         semerr(emsg_invalid_prop_name, p->sc_property_name);
2311                         scf_entry_destroy(entr);
2312                         return (stash_scferror(lcbdata));
2313 
2314                 case SCF_ERROR_EXISTS:
2315                         break;
2316 
2317                 case SCF_ERROR_DELETED:
2318                 case SCF_ERROR_CONNECTION_BROKEN:
2319                         scf_entry_destroy(entr);
2320                         return (stash_scferror(lcbdata));
2321 
2322                 case SCF_ERROR_NOT_BOUND:
2323                 case SCF_ERROR_HANDLE_MISMATCH:
2324                 case SCF_ERROR_NOT_SET:
2325                 default:
2326                         bad_error("scf_transaction_property_new", scf_error());
2327                 }
2328 
2329                 if (scf_transaction_property_change_type(trans, entr,
2330                     p->sc_property_name, tp) != 0) {
2331                         switch (scf_error()) {
2332                         case SCF_ERROR_DELETED:
2333                         case SCF_ERROR_CONNECTION_BROKEN:
2334                                 scf_entry_destroy(entr);
2335                                 return (stash_scferror(lcbdata));
2336 
2337                         case SCF_ERROR_INVALID_ARGUMENT:
2338                                 semerr(emsg_invalid_prop_name,
2339                                     p->sc_property_name);
2340                                 scf_entry_destroy(entr);
2341                                 return (stash_scferror(lcbdata));
2342 
2343                         case SCF_ERROR_NOT_FOUND:
2344                         case SCF_ERROR_NOT_SET:
2345                         case SCF_ERROR_HANDLE_MISMATCH:
2346                         case SCF_ERROR_NOT_BOUND:
2347                         default:
2348                                 bad_error(
2349                                     "scf_transaction_property_change_type",
2350                                     scf_error());
2351                         }
2352                 }
2353         }
2354 
2355         for (vp = uu_list_first(p->sc_property_values);
2356             vp != NULL;
2357             vp = uu_list_next(p->sc_property_values, vp)) {
2358                 val = scf_value_create(g_hndl);
2359                 if (val == NULL) {
2360                         switch (scf_error()) {
2361                         case SCF_ERROR_NO_MEMORY:
2362                                 return (stash_scferror(lcbdata));
2363 
2364                         case SCF_ERROR_INVALID_ARGUMENT:
2365                         default:
2366                                 bad_error("scf_value_create", scf_error());
2367                         }
2368                 }
2369 
2370                 switch (tp) {
2371                 case SCF_TYPE_BOOLEAN:
2372                         scf_value_set_boolean(val, vp->sc_u.sc_count);
2373                         break;
2374                 case SCF_TYPE_COUNT:
2375                         scf_value_set_count(val, vp->sc_u.sc_count);
2376                         break;
2377                 case SCF_TYPE_INTEGER:
2378                         scf_value_set_integer(val, vp->sc_u.sc_integer);
2379                         break;
2380                 default:
2381                         assert(vp->sc_u.sc_string != NULL);
2382                         if (scf_value_set_from_string(val, tp,
2383                             vp->sc_u.sc_string) != 0) {
2384                                 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2385                                         bad_error("scf_value_set_from_string",
2386                                             scf_error());
2387 
2388                                 warn(gettext("Value \"%s\" is not a valid "
2389                                     "%s.\n"), vp->sc_u.sc_string,
2390                                     scf_type_to_string(tp));
2391                                 scf_value_destroy(val);
2392                                 return (stash_scferror(lcbdata));
2393                         }
2394                         break;
2395                 }
2396 
2397                 if (scf_entry_add_value(entr, val) != 0)
2398                         bad_error("scf_entry_add_value", scf_error());
2399         }
2400 
2401         return (UU_WALK_NEXT);
2402 }
2403 
2404 /*
2405  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2406  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2407  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2408  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2409  * lcbdata->sc_err to
2410  *   ECONNABORTED - repository connection broken
2411  *   ENOMEM - out of memory
2412  *   ENOSPC - svc.configd is out of resources
2413  *   ECANCELED - sc_parent was deleted
2414  *   EPERM - could not create property group (permission denied) (error printed)
2415  *         - could not modify property group (permission denied) (error printed)
2416  *         - could not delete property group (permission denied) (error printed)
2417  *   EROFS - could not create property group (repository is read-only)
2418  *         - could not delete property group (repository is read-only)
2419  *   EACCES - could not create property group (backend access denied)
2420  *          - could not delete property group (backend access denied)
2421  *   EEXIST - could not create property group (already exists)
2422  *   EINVAL - invalid property group name (error printed)
2423  *          - invalid property name (error printed)
2424  *          - invalid value (error printed)
2425  *   EBUSY - new property group deleted (error printed)
2426  *         - new property group changed (error printed)
2427  *         - property group added (error printed)
2428  *         - property group deleted (error printed)
2429  */
2430 static int
2431 entity_pgroup_import(void *v, void *pvt)
2432 {
2433         pgroup_t *p = v;
2434         scf_callback_t cbdata;
2435         scf_callback_t *lcbdata = pvt;
2436         void *ent = lcbdata->sc_parent;
2437         int issvc = lcbdata->sc_service;
2438         int r;
2439 
2440         const char * const pg_changed = gettext("%s changed unexpectedly "
2441             "(new property group \"%s\" changed).\n");
2442 
2443         /* Never import deleted property groups. */
2444         if (p->sc_pgroup_delete) {
2445                 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2446                     entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2447                         goto delete_pg;
2448                 }
2449                 return (UU_WALK_NEXT);
2450         }
2451 
2452         if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2453             strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2454                 lcbdata->sc_general = p;
2455                 return (UU_WALK_NEXT);
2456         }
2457 
2458 add_pg:
2459         if (issvc)
2460                 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2461                     p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2462         else
2463                 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2464                     p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2465         if (r != 0) {
2466                 switch (scf_error()) {
2467                 case SCF_ERROR_DELETED:
2468                 case SCF_ERROR_CONNECTION_BROKEN:
2469                 case SCF_ERROR_BACKEND_READONLY:
2470                 case SCF_ERROR_BACKEND_ACCESS:
2471                 case SCF_ERROR_NO_RESOURCES:
2472                         return (stash_scferror(lcbdata));
2473 
2474                 case SCF_ERROR_EXISTS:
2475                         if (lcbdata->sc_flags & SCI_FORCE)
2476                                 break;
2477                         return (stash_scferror(lcbdata));
2478 
2479                 case SCF_ERROR_INVALID_ARGUMENT:
2480                         warn(emsg_fmri_invalid_pg_name_type,
2481                             lcbdata->sc_source_fmri,
2482                             p->sc_pgroup_name, p->sc_pgroup_type);
2483                         return (stash_scferror(lcbdata));
2484 
2485                 case SCF_ERROR_PERMISSION_DENIED:
2486                         warn(emsg_pg_add_perm, p->sc_pgroup_name,
2487                             lcbdata->sc_target_fmri);
2488                         return (stash_scferror(lcbdata));
2489 
2490                 case SCF_ERROR_NOT_BOUND:
2491                 case SCF_ERROR_HANDLE_MISMATCH:
2492                 case SCF_ERROR_NOT_SET:
2493                 default:
2494                         bad_error("scf_service_add_pg", scf_error());
2495                 }
2496 
2497                 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2498                         switch (scf_error()) {
2499                         case SCF_ERROR_CONNECTION_BROKEN:
2500                         case SCF_ERROR_DELETED:
2501                                 return (stash_scferror(lcbdata));
2502 
2503                         case SCF_ERROR_INVALID_ARGUMENT:
2504                                 warn(emsg_fmri_invalid_pg_name,
2505                                     lcbdata->sc_source_fmri,
2506                                     p->sc_pgroup_name);
2507                                 return (stash_scferror(lcbdata));
2508 
2509                         case SCF_ERROR_NOT_FOUND:
2510                                 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2511                                     p->sc_pgroup_name);
2512                                 lcbdata->sc_err = EBUSY;
2513                                 return (UU_WALK_ERROR);
2514 
2515                         case SCF_ERROR_NOT_BOUND:
2516                         case SCF_ERROR_HANDLE_MISMATCH:
2517                         case SCF_ERROR_NOT_SET:
2518                         default:
2519                                 bad_error("entity_get_pg", scf_error());
2520                         }
2521                 }
2522 
2523                 if (lcbdata->sc_flags & SCI_KEEP)
2524                         goto props;
2525 
2526 delete_pg:
2527                 if (scf_pg_delete(imp_pg) != 0) {
2528                         switch (scf_error()) {
2529                         case SCF_ERROR_DELETED:
2530                                 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2531                                     p->sc_pgroup_name);
2532                                 lcbdata->sc_err = EBUSY;
2533                                 return (UU_WALK_ERROR);
2534 
2535                         case SCF_ERROR_PERMISSION_DENIED:
2536                                 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2537                                     lcbdata->sc_target_fmri);
2538                                 return (stash_scferror(lcbdata));
2539 
2540                         case SCF_ERROR_BACKEND_READONLY:
2541                         case SCF_ERROR_BACKEND_ACCESS:
2542                         case SCF_ERROR_CONNECTION_BROKEN:
2543                                 return (stash_scferror(lcbdata));
2544 
2545                         case SCF_ERROR_NOT_SET:
2546                         default:
2547                                 bad_error("scf_pg_delete", scf_error());
2548                         }
2549                 }
2550 
2551                 if (p->sc_pgroup_delete)
2552                         return (UU_WALK_NEXT);
2553 
2554                 goto add_pg;
2555         }
2556 
2557 props:
2558 
2559         /*
2560          * Add properties to property group, if any.
2561          */
2562         cbdata.sc_handle = lcbdata->sc_handle;
2563         cbdata.sc_parent = imp_pg;
2564         cbdata.sc_flags = lcbdata->sc_flags;
2565         cbdata.sc_trans = imp_tx;
2566         cbdata.sc_enable = NULL;
2567 
2568         if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2569                 switch (scf_error()) {
2570                 case SCF_ERROR_BACKEND_ACCESS:
2571                 case SCF_ERROR_BACKEND_READONLY:
2572                 case SCF_ERROR_CONNECTION_BROKEN:
2573                         return (stash_scferror(lcbdata));
2574 
2575                 case SCF_ERROR_DELETED:
2576                         warn(pg_changed, lcbdata->sc_target_fmri,
2577                             p->sc_pgroup_name);
2578                         lcbdata->sc_err = EBUSY;
2579                         return (UU_WALK_ERROR);
2580 
2581                 case SCF_ERROR_PERMISSION_DENIED:
2582                         warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2583                             lcbdata->sc_target_fmri);
2584                         return (stash_scferror(lcbdata));
2585 
2586                 case SCF_ERROR_NOT_BOUND:
2587                 case SCF_ERROR_NOT_SET:
2588                 case SCF_ERROR_IN_USE:
2589                 case SCF_ERROR_HANDLE_MISMATCH:
2590                 default:
2591                         bad_error("scf_transaction_start", scf_error());
2592                 }
2593         }
2594 
2595         if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2596             UU_DEFAULT) != 0) {
2597                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2598                         bad_error("uu_list_walk", uu_error());
2599                 scf_transaction_reset(imp_tx);
2600 
2601                 lcbdata->sc_err = cbdata.sc_err;
2602                 if (cbdata.sc_err == ECANCELED) {
2603                         warn(pg_changed, lcbdata->sc_target_fmri,
2604                             p->sc_pgroup_name);
2605                         lcbdata->sc_err = EBUSY;
2606                 }
2607                 return (UU_WALK_ERROR);
2608         }
2609 
2610         if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2611                 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2612 
2613                 /*
2614                  * take the snapshot running snapshot then
2615                  * import the stored general/enable property
2616                  */
2617                 r = take_snap(ent, snap_running, imp_rsnap);
2618                 switch (r) {
2619                 case 0:
2620                         break;
2621 
2622                 case ECONNABORTED:
2623                         warn(gettext("Could not take %s snapshot on import "
2624                             "(repository connection broken).\n"),
2625                             snap_running);
2626                         lcbdata->sc_err = r;
2627                         return (UU_WALK_ERROR);
2628                 case ECANCELED:
2629                         warn(emsg_deleted);
2630                         lcbdata->sc_err = r;
2631                         return (UU_WALK_ERROR);
2632 
2633                 case EPERM:
2634                         warn(gettext("Could not take %s snapshot "
2635                             "(permission denied).\n"), snap_running);
2636                         lcbdata->sc_err = r;
2637                         return (UU_WALK_ERROR);
2638 
2639                 case ENOSPC:
2640                         warn(gettext("Could not take %s snapshot"
2641                             "(repository server out of resources).\n"),
2642                             snap_running);
2643                         lcbdata->sc_err = r;
2644                         return (UU_WALK_ERROR);
2645 
2646                 default:
2647                         bad_error("take_snap", r);
2648                 }
2649 
2650                 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2651                 if (r != UU_WALK_NEXT) {
2652                         if (r != UU_WALK_ERROR)
2653                                 bad_error("lscf_property_import", r);
2654                         return (EINVAL);
2655                 }
2656         }
2657 
2658         r = scf_transaction_commit(imp_tx);
2659         switch (r) {
2660         case 1:
2661                 r = UU_WALK_NEXT;
2662                 break;
2663 
2664         case 0:
2665                 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2666                 lcbdata->sc_err = EBUSY;
2667                 r = UU_WALK_ERROR;
2668                 break;
2669 
2670         case -1:
2671                 switch (scf_error()) {
2672                 case SCF_ERROR_BACKEND_READONLY:
2673                 case SCF_ERROR_BACKEND_ACCESS:
2674                 case SCF_ERROR_CONNECTION_BROKEN:
2675                 case SCF_ERROR_NO_RESOURCES:
2676                         r = stash_scferror(lcbdata);
2677                         break;
2678 
2679                 case SCF_ERROR_DELETED:
2680                         warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2681                             p->sc_pgroup_name);
2682                         lcbdata->sc_err = EBUSY;
2683                         r = UU_WALK_ERROR;
2684                         break;
2685 
2686                 case SCF_ERROR_PERMISSION_DENIED:
2687                         warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2688                             lcbdata->sc_target_fmri);
2689                         r = stash_scferror(lcbdata);
2690                         break;
2691 
2692                 case SCF_ERROR_NOT_SET:
2693                 case SCF_ERROR_INVALID_ARGUMENT:
2694                 case SCF_ERROR_NOT_BOUND:
2695                 default:
2696                         bad_error("scf_transaction_commit", scf_error());
2697                 }
2698                 break;
2699 
2700         default:
2701                 bad_error("scf_transaction_commit", r);
2702         }
2703 
2704         scf_transaction_destroy_children(imp_tx);
2705 
2706         return (r);
2707 }
2708 
2709 /*
2710  * Returns
2711  *   0 - success
2712  *   ECONNABORTED - repository connection broken
2713  *   ENOMEM - out of memory
2714  *   ENOSPC - svc.configd is out of resources
2715  *   ECANCELED - inst was deleted
2716  *   EPERM - could not create property group (permission denied) (error printed)
2717  *         - could not modify property group (permission denied) (error printed)
2718  *   EROFS - could not create property group (repository is read-only)
2719  *   EACCES - could not create property group (backend access denied)
2720  *   EEXIST - could not create property group (already exists)
2721  *   EINVAL - invalid property group name (error printed)
2722  *          - invalid property name (error printed)
2723  *          - invalid value (error printed)
2724  *   EBUSY - new property group changed (error printed)
2725  */
2726 static int
2727 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2728     const entity_t *isvc, int flags)
2729 {
2730         scf_callback_t cbdata;
2731 
2732         cbdata.sc_handle = scf_service_handle(svc);
2733         cbdata.sc_parent = svc;
2734         cbdata.sc_service = 1;
2735         cbdata.sc_general = 0;
2736         cbdata.sc_enable = 0;
2737         cbdata.sc_flags = flags;
2738         cbdata.sc_source_fmri = isvc->sc_fmri;
2739         cbdata.sc_target_fmri = target_fmri;
2740 
2741         /*
2742          * If the op is set, then add the flag to the callback
2743          * flags for later use.
2744          */
2745         if (isvc->sc_op != SVCCFG_OP_NONE) {
2746                 switch (isvc->sc_op) {
2747                 case SVCCFG_OP_IMPORT :
2748                         cbdata.sc_flags |= SCI_OP_IMPORT;
2749                         break;
2750                 case SVCCFG_OP_APPLY :
2751                         cbdata.sc_flags |= SCI_OP_APPLY;
2752                         break;
2753                 case SVCCFG_OP_RESTORE :
2754                         cbdata.sc_flags |= SCI_OP_RESTORE;
2755                         break;
2756                 default :
2757                         uu_die(gettext("lscf_import_service_pgs : "
2758                             "Unknown op stored in the service entity\n"));
2759 
2760                 }
2761         }
2762 
2763         if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2764             UU_DEFAULT) != 0) {
2765                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2766                         bad_error("uu_list_walk", uu_error());
2767 
2768                 return (cbdata.sc_err);
2769         }
2770 
2771         return (0);
2772 }
2773 
2774 /*
2775  * Returns
2776  *   0 - success
2777  *   ECONNABORTED - repository connection broken
2778  *   ENOMEM - out of memory
2779  *   ENOSPC - svc.configd is out of resources
2780  *   ECANCELED - inst was deleted
2781  *   EPERM - could not create property group (permission denied) (error printed)
2782  *         - could not modify property group (permission denied) (error printed)
2783  *   EROFS - could not create property group (repository is read-only)
2784  *   EACCES - could not create property group (backend access denied)
2785  *   EEXIST - could not create property group (already exists)
2786  *   EINVAL - invalid property group name (error printed)
2787  *          - invalid property name (error printed)
2788  *          - invalid value (error printed)
2789  *   EBUSY - new property group changed (error printed)
2790  */
2791 static int
2792 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2793     const entity_t *iinst, int flags)
2794 {
2795         scf_callback_t cbdata;
2796 
2797         cbdata.sc_handle = scf_instance_handle(inst);
2798         cbdata.sc_parent = inst;
2799         cbdata.sc_service = 0;
2800         cbdata.sc_general = NULL;
2801         cbdata.sc_enable = NULL;
2802         cbdata.sc_flags = flags;
2803         cbdata.sc_source_fmri = iinst->sc_fmri;
2804         cbdata.sc_target_fmri = target_fmri;
2805 
2806         /*
2807          * If the op is set, then add the flag to the callback
2808          * flags for later use.
2809          */
2810         if (iinst->sc_op != SVCCFG_OP_NONE) {
2811                 switch (iinst->sc_op) {
2812                 case SVCCFG_OP_IMPORT :
2813                         cbdata.sc_flags |= SCI_OP_IMPORT;
2814                         break;
2815                 case SVCCFG_OP_APPLY :
2816                         cbdata.sc_flags |= SCI_OP_APPLY;
2817                         break;
2818                 case SVCCFG_OP_RESTORE :
2819                         cbdata.sc_flags |= SCI_OP_RESTORE;
2820                         break;
2821                 default :
2822                         uu_die(gettext("lscf_import_instance_pgs : "
2823                             "Unknown op stored in the instance entity\n"));
2824                 }
2825         }
2826 
2827         if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2828             UU_DEFAULT) != 0) {
2829                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2830                         bad_error("uu_list_walk", uu_error());
2831 
2832                 return (cbdata.sc_err);
2833         }
2834 
2835         if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2836                 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2837                 /*
2838                  * If importing with the SCI_NOENABLED flag then
2839                  * skip the delay, but if not then add the delay
2840                  * of the enable property.
2841                  */
2842                 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2843                         cbdata.sc_flags |= SCI_DELAYENABLE;
2844                 }
2845 
2846                 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2847                     != UU_WALK_NEXT)
2848                         return (cbdata.sc_err);
2849         }
2850 
2851         return (0);
2852 }
2853 
2854 /*
2855  * Report the reasons why we can't upgrade pg2 to pg1.
2856  */
2857 static void
2858 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2859     int new)
2860 {
2861         property_t *p1, *p2;
2862 
2863         assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2864 
2865         if (!pg_attrs_equal(pg1, pg2, fmri, new))
2866                 return;
2867 
2868         for (p1 = uu_list_first(pg1->sc_pgroup_props);
2869             p1 != NULL;
2870             p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2871                 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2872                 if (p2 != NULL) {
2873                         (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2874                             new);
2875                         continue;
2876                 }
2877 
2878                 if (new)
2879                         warn(gettext("Conflict upgrading %s (new property "
2880                             "group \"%s\" is missing property \"%s\").\n"),
2881                             fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2882                 else
2883                         warn(gettext("Conflict upgrading %s (property "
2884                             "\"%s/%s\" is missing).\n"), fmri,
2885                             pg1->sc_pgroup_name, p1->sc_property_name);
2886         }
2887 
2888         /*
2889          * Since pg1 should be from the manifest, any properties in pg2 which
2890          * aren't in pg1 shouldn't be reported as conflicts.
2891          */
2892 }
2893 
2894 /*
2895  * Add transaction entries to tx which will upgrade cur's pg according to old
2896  * & new.
2897  *
2898  * Returns
2899  *   0 - success
2900  *   EINVAL - new has a property with an invalid name or value (message emitted)
2901  *   ENOMEM - out of memory
2902  */
2903 static int
2904 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2905     pgroup_t *cur, int speak, const char *fmri)
2906 {
2907         property_t *p, *new_p, *cur_p;
2908         scf_transaction_entry_t *e;
2909         int r;
2910         int is_general;
2911         int is_protected;
2912 
2913         if (uu_list_walk(new->sc_pgroup_props, clear_int,
2914             (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2915                 bad_error("uu_list_walk", uu_error());
2916 
2917         is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2918 
2919         for (p = uu_list_first(old->sc_pgroup_props);
2920             p != NULL;
2921             p = uu_list_next(old->sc_pgroup_props, p)) {
2922                 /* p is a property in the old property group. */
2923 
2924                 /* Protect live properties. */
2925                 is_protected = 0;
2926                 if (is_general) {
2927                         if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2928                             0 ||
2929                             strcmp(p->sc_property_name,
2930                             SCF_PROPERTY_RESTARTER) == 0)
2931                                 is_protected = 1;
2932                 }
2933 
2934                 /* Look for the same property in the new properties. */
2935                 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2936                 if (new_p != NULL) {
2937                         new_p->sc_seen = 1;
2938 
2939                         /*
2940                          * If the new property is the same as the old, don't do
2941                          * anything (leave any user customizations).
2942                          */
2943                         if (prop_equal(p, new_p, NULL, NULL, 0))
2944                                 continue;
2945 
2946                         if (new_p->sc_property_override)
2947                                 goto upgrade;
2948                 }
2949 
2950                 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2951                 if (cur_p == NULL) {
2952                         /*
2953                          * p has been deleted from the repository.  If we were
2954                          * going to delete it anyway, do nothing.  Otherwise
2955                          * report a conflict.
2956                          */
2957                         if (new_p == NULL)
2958                                 continue;
2959 
2960                         if (is_protected)
2961                                 continue;
2962 
2963                         warn(gettext("Conflict upgrading %s "
2964                             "(property \"%s/%s\" is missing).\n"), fmri,
2965                             old->sc_pgroup_name, p->sc_property_name);
2966                         continue;
2967                 }
2968 
2969                 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2970                         /*
2971                          * Conflict.  Don't warn if the property is already the
2972                          * way we want it, though.
2973                          */
2974                         if (is_protected)
2975                                 continue;
2976 
2977                         if (new_p == NULL)
2978                                 (void) prop_equal(p, cur_p, fmri,
2979                                     old->sc_pgroup_name, 0);
2980                         else
2981                                 (void) prop_equal(cur_p, new_p, fmri,
2982                                     old->sc_pgroup_name, 0);
2983                         continue;
2984                 }
2985 
2986                 if (is_protected) {
2987                         if (speak)
2988                                 warn(gettext("%s: Refusing to upgrade "
2989                                     "\"%s/%s\" (live property).\n"), fmri,
2990                                     old->sc_pgroup_name, p->sc_property_name);
2991                         continue;
2992                 }
2993 
2994 upgrade:
2995                 /* p hasn't been customized in the repository.  Upgrade it. */
2996                 if (new_p == NULL) {
2997                         /* p was deleted.  Delete from cur if unchanged. */
2998                         if (speak)
2999                                 warn(gettext(
3000                                     "%s: Deleting property \"%s/%s\".\n"),
3001                                     fmri, old->sc_pgroup_name,
3002                                     p->sc_property_name);
3003 
3004                         e = scf_entry_create(g_hndl);
3005                         if (e == NULL)
3006                                 return (ENOMEM);
3007 
3008                         if (scf_transaction_property_delete(tx, e,
3009                             p->sc_property_name) != 0) {
3010                                 switch (scf_error()) {
3011                                 case SCF_ERROR_DELETED:
3012                                         scf_entry_destroy(e);
3013                                         return (ECANCELED);
3014 
3015                                 case SCF_ERROR_CONNECTION_BROKEN:
3016                                         scf_entry_destroy(e);
3017                                         return (ECONNABORTED);
3018 
3019                                 case SCF_ERROR_NOT_FOUND:
3020                                         /*
3021                                          * This can happen if cur is from the
3022                                          * running snapshot (and it differs
3023                                          * from the live properties).
3024                                          */
3025                                         scf_entry_destroy(e);
3026                                         break;
3027 
3028                                 case SCF_ERROR_HANDLE_MISMATCH:
3029                                 case SCF_ERROR_NOT_BOUND:
3030                                 case SCF_ERROR_NOT_SET:
3031                                 case SCF_ERROR_INVALID_ARGUMENT:
3032                                 default:
3033                                         bad_error(
3034                                             "scf_transaction_property_delete",
3035                                             scf_error());
3036                                 }
3037                         }
3038                 } else {
3039                         scf_callback_t ctx;
3040 
3041                         if (speak)
3042                                 warn(gettext(
3043                                     "%s: Upgrading property \"%s/%s\".\n"),
3044                                     fmri, old->sc_pgroup_name,
3045                                     p->sc_property_name);
3046 
3047                         ctx.sc_handle = g_hndl;
3048                         ctx.sc_trans = tx;
3049                         ctx.sc_flags = 0;
3050 
3051                         r = lscf_property_import(new_p, &ctx);
3052                         if (r != UU_WALK_NEXT) {
3053                                 if (r != UU_WALK_ERROR)
3054                                         bad_error("lscf_property_import", r);
3055                                 return (EINVAL);
3056                         }
3057                 }
3058         }
3059 
3060         /* Go over the properties which were added. */
3061         for (new_p = uu_list_first(new->sc_pgroup_props);
3062             new_p != NULL;
3063             new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3064                 if (new_p->sc_seen)
3065                         continue;
3066 
3067                 /* This is a new property. */
3068                 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3069                 if (cur_p == NULL) {
3070                         scf_callback_t ctx;
3071 
3072                         ctx.sc_handle = g_hndl;
3073                         ctx.sc_trans = tx;
3074                         ctx.sc_flags = 0;
3075 
3076                         r = lscf_property_import(new_p, &ctx);
3077                         if (r != UU_WALK_NEXT) {
3078                                 if (r != UU_WALK_ERROR)
3079                                         bad_error("lscf_property_import", r);
3080                                 return (EINVAL);
3081                         }
3082                         continue;
3083                 }
3084 
3085                 /*
3086                  * Report a conflict if the new property differs from the
3087                  * current one.  Unless it's general/enabled, since that's
3088                  * never in the last-import snapshot.
3089                  */
3090                 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3091                     0 &&
3092                     strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3093                         continue;
3094 
3095                 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3096         }
3097 
3098         return (0);
3099 }
3100 
3101 /*
3102  * Upgrade pg according to old & new.
3103  *
3104  * Returns
3105  *   0 - success
3106  *   ECONNABORTED - repository connection broken
3107  *   ENOMEM - out of memory
3108  *   ENOSPC - svc.configd is out of resources
3109  *   ECANCELED - pg was deleted
3110  *   EPERM - couldn't modify pg (permission denied)
3111  *   EROFS - couldn't modify pg (backend read-only)
3112  *   EACCES - couldn't modify pg (backend access denied)
3113  *   EINVAL - new has a property with invalid name or value (error printed)
3114  *   EBUSY - pg changed unexpectedly
3115  */
3116 static int
3117 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3118     pgroup_t *new, int speak, const char *fmri)
3119 {
3120         int r;
3121 
3122         if (scf_transaction_start(imp_tx, pg) != 0) {
3123                 switch (scf_error()) {
3124                 case SCF_ERROR_CONNECTION_BROKEN:
3125                 case SCF_ERROR_DELETED:
3126                 case SCF_ERROR_PERMISSION_DENIED:
3127                 case SCF_ERROR_BACKEND_READONLY:
3128                 case SCF_ERROR_BACKEND_ACCESS:
3129                         return (scferror2errno(scf_error()));
3130 
3131                 case SCF_ERROR_HANDLE_MISMATCH:
3132                 case SCF_ERROR_IN_USE:
3133                 case SCF_ERROR_NOT_BOUND:
3134                 case SCF_ERROR_NOT_SET:
3135                 default:
3136                         bad_error("scf_transaction_start", scf_error());
3137                 }
3138         }
3139 
3140         r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3141         switch (r) {
3142         case 0:
3143                 break;
3144 
3145         case EINVAL:
3146         case ENOMEM:
3147                 scf_transaction_destroy_children(imp_tx);
3148                 return (r);
3149 
3150         default:
3151                 bad_error("add_upgrade_entries", r);
3152         }
3153 
3154         r = scf_transaction_commit(imp_tx);
3155 
3156         scf_transaction_destroy_children(imp_tx);
3157 
3158         switch (r) {
3159         case 1:
3160                 break;
3161 
3162         case 0:
3163                 return (EBUSY);
3164 
3165         case -1:
3166                 switch (scf_error()) {
3167                 case SCF_ERROR_CONNECTION_BROKEN:
3168                 case SCF_ERROR_NO_RESOURCES:
3169                 case SCF_ERROR_PERMISSION_DENIED:
3170                 case SCF_ERROR_BACKEND_READONLY:
3171                 case SCF_ERROR_BACKEND_ACCESS:
3172                 case SCF_ERROR_DELETED:
3173                         return (scferror2errno(scf_error()));
3174 
3175                 case SCF_ERROR_NOT_BOUND:
3176                 case SCF_ERROR_INVALID_ARGUMENT:
3177                 case SCF_ERROR_NOT_SET:
3178                 default:
3179                         bad_error("scf_transaction_commit", scf_error());
3180                 }
3181 
3182         default:
3183                 bad_error("scf_transaction_commit", r);
3184         }
3185 
3186         return (0);
3187 }
3188 
3189 /*
3190  * Compares two entity FMRIs.  Returns
3191  *
3192  *   1 - equal
3193  *   0 - not equal
3194  *   -1 - f1 is invalid or not an entity
3195  *   -2 - f2 is invalid or not an entity
3196  */
3197 static int
3198 fmri_equal(const char *f1, const char *f2)
3199 {
3200         int r;
3201         const char *s1, *i1, *pg1;
3202         const char *s2, *i2, *pg2;
3203 
3204         if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3205                 return (-1);
3206         if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3207                 return (-1);
3208 
3209         if (s1 == NULL || pg1 != NULL)
3210                 return (-1);
3211 
3212         if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3213                 return (-2);
3214         if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3215                 return (-2);
3216 
3217         if (s2 == NULL || pg2 != NULL)
3218                 return (-2);
3219 
3220         r = strcmp(s1, s2);
3221         if (r != 0)
3222                 return (0);
3223 
3224         if (i1 == NULL && i2 == NULL)
3225                 return (1);
3226 
3227         if (i1 == NULL || i2 == NULL)
3228                 return (0);
3229 
3230         return (strcmp(i1, i2) == 0);
3231 }
3232 
3233 /*
3234  * Import a dependent by creating a dependency property group in the dependent
3235  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3236  * dependents pg, and add an entry to create a new property for this
3237  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3238  *
3239  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3240  * lcbdata->sc_err to
3241  *   ECONNABORTED - repository connection broken
3242  *   ENOMEM - out of memory
3243  *   ENOSPC - configd is out of resources
3244  *   EINVAL - target is invalid (error printed)
3245  *          - target is not an entity (error printed)
3246  *          - dependent has invalid name (error printed)
3247  *          - invalid property name (error printed)
3248  *          - invalid value (error printed)
3249  *          - scope of target does not exist (error printed)
3250  *   EPERM - couldn't create target (permission denied) (error printed)
3251  *         - couldn't create dependency pg (permission denied) (error printed)
3252  *         - couldn't modify dependency pg (permission denied) (error printed)
3253  *   EROFS - couldn't create target (repository read-only)
3254  *         - couldn't create dependency pg (repository read-only)
3255  *   EACCES - couldn't create target (backend access denied)
3256  *          - couldn't create dependency pg (backend access denied)
3257  *   ECANCELED - sc_trans's pg was deleted
3258  *   EALREADY - property for dependent already exists in sc_trans's pg
3259  *   EEXIST - dependency pg already exists in target (error printed)
3260  *   EBUSY - target deleted (error printed)
3261  *         - property group changed during import (error printed)
3262  */
3263 static int
3264 lscf_dependent_import(void *a1, void *pvt)
3265 {
3266         pgroup_t *pgrp = a1;
3267         scf_callback_t *lcbdata = pvt;
3268 
3269         int isservice;
3270         int ret;
3271         scf_transaction_entry_t *e;
3272         scf_value_t *val;
3273         scf_callback_t dependent_cbdata;
3274         scf_error_t scfe;
3275 
3276         /*
3277          * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3278          * it's invalid, we fail before modifying the repository.
3279          */
3280         scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3281             &dependent_cbdata.sc_parent, &isservice);
3282         switch (scfe) {
3283         case SCF_ERROR_NONE:
3284                 break;
3285 
3286         case SCF_ERROR_NO_MEMORY:
3287                 return (stash_scferror_err(lcbdata, scfe));
3288 
3289         case SCF_ERROR_INVALID_ARGUMENT:
3290                 semerr(gettext("The FMRI for the \"%s\" dependent is "
3291                     "invalid.\n"), pgrp->sc_pgroup_name);
3292                 return (stash_scferror_err(lcbdata, scfe));
3293 
3294         case SCF_ERROR_CONSTRAINT_VIOLATED:
3295                 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3296                     "specifies neither a service nor an instance.\n"),
3297                     pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3298                 return (stash_scferror_err(lcbdata, scfe));
3299 
3300         case SCF_ERROR_NOT_FOUND:
3301                 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3302                     &dependent_cbdata.sc_parent, &isservice);
3303                 switch (scfe) {
3304                 case SCF_ERROR_NONE:
3305                         break;
3306 
3307                 case SCF_ERROR_NO_MEMORY:
3308                 case SCF_ERROR_BACKEND_READONLY:
3309                 case SCF_ERROR_BACKEND_ACCESS:
3310                         return (stash_scferror_err(lcbdata, scfe));
3311 
3312                 case SCF_ERROR_NOT_FOUND:
3313                         semerr(gettext("The scope in FMRI \"%s\" for the "
3314                             "\"%s\" dependent does not exist.\n"),
3315                             pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3316                         lcbdata->sc_err = EINVAL;
3317                         return (UU_WALK_ERROR);
3318 
3319                 case SCF_ERROR_PERMISSION_DENIED:
3320                         warn(gettext(
3321                             "Could not create %s (permission denied).\n"),
3322                             pgrp->sc_pgroup_fmri);
3323                         return (stash_scferror_err(lcbdata, scfe));
3324 
3325                 case SCF_ERROR_INVALID_ARGUMENT:
3326                 case SCF_ERROR_CONSTRAINT_VIOLATED:
3327                 default:
3328                         bad_error("create_entity", scfe);
3329                 }
3330                 break;
3331 
3332         default:
3333                 bad_error("fmri_to_entity", scfe);
3334         }
3335 
3336         if (lcbdata->sc_trans != NULL) {
3337                 e = scf_entry_create(lcbdata->sc_handle);
3338                 if (e == NULL) {
3339                         if (scf_error() != SCF_ERROR_NO_MEMORY)
3340                                 bad_error("scf_entry_create", scf_error());
3341 
3342                         entity_destroy(dependent_cbdata.sc_parent, isservice);
3343                         return (stash_scferror(lcbdata));
3344                 }
3345 
3346                 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3347                     pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3348                         switch (scf_error()) {
3349                         case SCF_ERROR_INVALID_ARGUMENT:
3350                                 warn(gettext("Dependent of %s has invalid name "
3351                                     "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3352                                     pgrp->sc_pgroup_name);
3353                                 /* FALLTHROUGH */
3354 
3355                         case SCF_ERROR_DELETED:
3356                         case SCF_ERROR_CONNECTION_BROKEN:
3357                                 scf_entry_destroy(e);
3358                                 entity_destroy(dependent_cbdata.sc_parent,
3359                                     isservice);
3360                                 return (stash_scferror(lcbdata));
3361 
3362                         case SCF_ERROR_EXISTS:
3363                                 scf_entry_destroy(e);
3364                                 entity_destroy(dependent_cbdata.sc_parent,
3365                                     isservice);
3366                                 lcbdata->sc_err = EALREADY;
3367                                 return (UU_WALK_ERROR);
3368 
3369                         case SCF_ERROR_NOT_BOUND:
3370                         case SCF_ERROR_HANDLE_MISMATCH:
3371                         case SCF_ERROR_NOT_SET:
3372                         default:
3373                                 bad_error("scf_transaction_property_new",
3374                                     scf_error());
3375                         }
3376                 }
3377 
3378                 val = scf_value_create(lcbdata->sc_handle);
3379                 if (val == NULL) {
3380                         if (scf_error() != SCF_ERROR_NO_MEMORY)
3381                                 bad_error("scf_value_create", scf_error());
3382 
3383                         entity_destroy(dependent_cbdata.sc_parent, isservice);
3384                         return (stash_scferror(lcbdata));
3385                 }
3386 
3387                 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3388                     pgrp->sc_pgroup_fmri) != 0)
3389                         /* invalid should have been caught above */
3390                         bad_error("scf_value_set_from_string", scf_error());
3391 
3392                 if (scf_entry_add_value(e, val) != 0)
3393                         bad_error("scf_entry_add_value", scf_error());
3394         }
3395 
3396         /* Add the property group to the target entity. */
3397 
3398         dependent_cbdata.sc_handle = lcbdata->sc_handle;
3399         dependent_cbdata.sc_flags = lcbdata->sc_flags;
3400         dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3401         dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3402 
3403         ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3404 
3405         entity_destroy(dependent_cbdata.sc_parent, isservice);
3406 
3407         if (ret == UU_WALK_NEXT)
3408                 return (ret);
3409 
3410         if (ret != UU_WALK_ERROR)
3411                 bad_error("entity_pgroup_import", ret);
3412 
3413         switch (dependent_cbdata.sc_err) {
3414         case ECANCELED:
3415                 warn(gettext("%s deleted unexpectedly.\n"),
3416                     pgrp->sc_pgroup_fmri);
3417                 lcbdata->sc_err = EBUSY;
3418                 break;
3419 
3420         case EEXIST:
3421                 warn(gettext("Could not create \"%s\" dependency in %s "
3422                     "(already exists).\n"), pgrp->sc_pgroup_name,
3423                     pgrp->sc_pgroup_fmri);
3424                 /* FALLTHROUGH */
3425 
3426         default:
3427                 lcbdata->sc_err = dependent_cbdata.sc_err;
3428         }
3429 
3430         return (UU_WALK_ERROR);
3431 }
3432 
3433 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3434     const scf_snaplevel_t *, scf_transaction_t *);
3435 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3436     const pgroup_t *);
3437 
3438 /*
3439  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3440  * the current dependent targets from running (the snaplevel of a running
3441  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3442  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3443  * dependent targets and dependency properties from li_dpts_pg (the
3444  * "dependents" property group in snpl) and snpl (the snaplevel which
3445  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3446  * snpl doesn't have a "dependents" property group, and any dependents in ient
3447  * are new.
3448  *
3449  * Returns
3450  *   0 - success
3451  *   ECONNABORTED - repository connection broken
3452  *   ENOMEM - out of memory
3453  *   ENOSPC - configd is out of resources
3454  *   ECANCELED - ent was deleted
3455  *   ENODEV - the entity containing li_dpts_pg was deleted
3456  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3457  *         - couldn't upgrade dependent (permission denied) (error printed)
3458  *         - couldn't create dependent (permission denied) (error printed)
3459  *   EROFS - could not modify dependents pg (repository read-only)
3460  *         - couldn't upgrade dependent (repository read-only)
3461  *         - couldn't create dependent (repository read-only)
3462  *   EACCES - could not modify dependents pg (backend access denied)
3463  *          - could not upgrade dependent (backend access denied)
3464  *          - could not create dependent (backend access denied)
3465  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3466  *         - dependent target deleted (error printed)
3467  *         - dependent pg changed (error printed)
3468  *   EINVAL - new dependent is invalid (error printed)
3469  *   EBADF - snpl is corrupt (error printed)
3470  *         - snpl has corrupt pg (error printed)
3471  *         - dependency pg in target is corrupt (error printed)
3472  *         - target has corrupt snapshot (error printed)
3473  *   EEXIST - dependency pg already existed in target service (error printed)
3474  */
3475 static int
3476 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3477     const scf_snaplevel_t *snpl, const entity_t *ient,
3478     const scf_snaplevel_t *running, void *ent)
3479 {
3480         pgroup_t *new_dpt_pgroup;
3481         scf_callback_t cbdata;
3482         int r, unseen, tx_started = 0;
3483         int have_cur_depts;
3484 
3485         const char * const dependents = "dependents";
3486 
3487         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3488 
3489         if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3490                 /* Nothing to do. */
3491                 return (0);
3492 
3493         /* Fetch the current version of the "dependents" property group. */
3494         have_cur_depts = 1;
3495         if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3496                 switch (scf_error()) {
3497                 case SCF_ERROR_NOT_FOUND:
3498                         break;
3499 
3500                 case SCF_ERROR_DELETED:
3501                 case SCF_ERROR_CONNECTION_BROKEN:
3502                         return (scferror2errno(scf_error()));
3503 
3504                 case SCF_ERROR_NOT_SET:
3505                 case SCF_ERROR_INVALID_ARGUMENT:
3506                 case SCF_ERROR_HANDLE_MISMATCH:
3507                 case SCF_ERROR_NOT_BOUND:
3508                 default:
3509                         bad_error("entity_get_pg", scf_error());
3510                 }
3511 
3512                 have_cur_depts = 0;
3513         }
3514 
3515         /* Fetch the running version of the "dependents" property group. */
3516         ud_run_dpts_pg_set = 0;
3517         if (running != NULL)
3518                 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3519         else
3520                 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3521         if (r == 0) {
3522                 ud_run_dpts_pg_set = 1;
3523         } else {
3524                 switch (scf_error()) {
3525                 case SCF_ERROR_NOT_FOUND:
3526                         break;
3527 
3528                 case SCF_ERROR_DELETED:
3529                 case SCF_ERROR_CONNECTION_BROKEN:
3530                         return (scferror2errno(scf_error()));
3531 
3532                 case SCF_ERROR_NOT_SET:
3533                 case SCF_ERROR_INVALID_ARGUMENT:
3534                 case SCF_ERROR_HANDLE_MISMATCH:
3535                 case SCF_ERROR_NOT_BOUND:
3536                 default:
3537                         bad_error(running ? "scf_snaplevel_get_pg" :
3538                             "entity_get_pg", scf_error());
3539                 }
3540         }
3541 
3542         /*
3543          * Clear the seen fields of the dependents, so we can tell which ones
3544          * are new.
3545          */
3546         if (uu_list_walk(ient->sc_dependents, clear_int,
3547             (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3548                 bad_error("uu_list_walk", uu_error());
3549 
3550         if (li_dpts_pg != NULL) {
3551                 /*
3552                  * Each property in li_dpts_pg represents a dependent tag in
3553                  * the old manifest.  For each, call upgrade_dependent(),
3554                  * which will change ud_cur_depts_pg or dependencies in other
3555                  * services as appropriate.  Note (a) that changes to
3556                  * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3557                  * made en masse, and (b) it's ok if the entity doesn't have
3558                  * a current version of the "dependents" property group,
3559                  * because we'll just consider all dependents as customized
3560                  * (by being deleted).
3561                  */
3562 
3563                 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3564                         switch (scf_error()) {
3565                         case SCF_ERROR_DELETED:
3566                                 return (ENODEV);
3567 
3568                         case SCF_ERROR_CONNECTION_BROKEN:
3569                                 return (ECONNABORTED);
3570 
3571                         case SCF_ERROR_HANDLE_MISMATCH:
3572                         case SCF_ERROR_NOT_BOUND:
3573                         case SCF_ERROR_NOT_SET:
3574                         default:
3575                                 bad_error("scf_iter_pg_properties",
3576                                     scf_error());
3577                         }
3578                 }
3579 
3580                 if (have_cur_depts &&
3581                     scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3582                         switch (scf_error()) {
3583                         case SCF_ERROR_BACKEND_ACCESS:
3584                         case SCF_ERROR_BACKEND_READONLY:
3585                         case SCF_ERROR_CONNECTION_BROKEN:
3586                                 return (scferror2errno(scf_error()));
3587 
3588                         case SCF_ERROR_DELETED:
3589                                 warn(emsg_pg_deleted, ient->sc_fmri,
3590                                     dependents);
3591                                 return (EBUSY);
3592 
3593                         case SCF_ERROR_PERMISSION_DENIED:
3594                                 warn(emsg_pg_mod_perm, dependents,
3595                                     ient->sc_fmri);
3596                                 return (scferror2errno(scf_error()));
3597 
3598                         case SCF_ERROR_HANDLE_MISMATCH:
3599                         case SCF_ERROR_IN_USE:
3600                         case SCF_ERROR_NOT_BOUND:
3601                         case SCF_ERROR_NOT_SET:
3602                         default:
3603                                 bad_error("scf_transaction_start", scf_error());
3604                         }
3605                 }
3606                 tx_started = have_cur_depts;
3607 
3608                 for (;;) {
3609                         r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3610                         if (r == 0)
3611                                 break;
3612                         if (r == 1) {
3613                                 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3614                                     tx_started ? ud_tx : NULL);
3615                                 switch (r) {
3616                                 case 0:
3617                                         continue;
3618 
3619                                 case ECONNABORTED:
3620                                 case ENOMEM:
3621                                 case ENOSPC:
3622                                 case EBADF:
3623                                 case EBUSY:
3624                                 case EINVAL:
3625                                 case EPERM:
3626                                 case EROFS:
3627                                 case EACCES:
3628                                 case EEXIST:
3629                                         break;
3630 
3631                                 case ECANCELED:
3632                                         r = ENODEV;
3633                                         break;
3634 
3635                                 default:
3636                                         bad_error("upgrade_dependent", r);
3637                                 }
3638 
3639                                 if (tx_started)
3640                                         scf_transaction_destroy_children(ud_tx);
3641                                 return (r);
3642                         }
3643                         if (r != -1)
3644                                 bad_error("scf_iter_next_property", r);
3645 
3646                         switch (scf_error()) {
3647                         case SCF_ERROR_DELETED:
3648                                 r = ENODEV;
3649                                 break;
3650 
3651                         case SCF_ERROR_CONNECTION_BROKEN:
3652                                 r = ECONNABORTED;
3653                                 break;
3654 
3655                         case SCF_ERROR_NOT_SET:
3656                         case SCF_ERROR_INVALID_ARGUMENT:
3657                         case SCF_ERROR_NOT_BOUND:
3658                         case SCF_ERROR_HANDLE_MISMATCH:
3659                         default:
3660                                 bad_error("scf_iter_next_property",
3661                                     scf_error());
3662                         }
3663 
3664                         if (tx_started)
3665                                 scf_transaction_destroy_children(ud_tx);
3666                         return (r);
3667                 }
3668         }
3669 
3670         /* import unseen dependents */
3671         unseen = 0;
3672         for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3673             new_dpt_pgroup != NULL;
3674             new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3675             new_dpt_pgroup)) {
3676                 if (!new_dpt_pgroup->sc_pgroup_seen) {
3677                         unseen = 1;
3678                         break;
3679                 }
3680         }
3681 
3682         /* If there are none, exit early. */
3683         if (unseen == 0)
3684                 goto commit;
3685 
3686         /* Set up for lscf_dependent_import() */
3687         cbdata.sc_handle = g_hndl;
3688         cbdata.sc_parent = ent;
3689         cbdata.sc_service = issvc;
3690         cbdata.sc_flags = 0;
3691 
3692         if (!have_cur_depts) {
3693                 /*
3694                  * We have new dependents to import, so we need a "dependents"
3695                  * property group.
3696                  */
3697                 if (issvc)
3698                         r = scf_service_add_pg(ent, dependents,
3699                             SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3700                 else
3701                         r = scf_instance_add_pg(ent, dependents,
3702                             SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3703                 if (r != 0) {
3704                         switch (scf_error()) {
3705                         case SCF_ERROR_DELETED:
3706                         case SCF_ERROR_CONNECTION_BROKEN:
3707                         case SCF_ERROR_BACKEND_READONLY:
3708                         case SCF_ERROR_BACKEND_ACCESS:
3709                         case SCF_ERROR_NO_RESOURCES:
3710                                 return (scferror2errno(scf_error()));
3711 
3712                         case SCF_ERROR_EXISTS:
3713                                 warn(emsg_pg_added, ient->sc_fmri, dependents);
3714                                 return (EBUSY);
3715 
3716                         case SCF_ERROR_PERMISSION_DENIED:
3717                                 warn(emsg_pg_add_perm, dependents,
3718                                     ient->sc_fmri);
3719                                 return (scferror2errno(scf_error()));
3720 
3721                         case SCF_ERROR_NOT_BOUND:
3722                         case SCF_ERROR_HANDLE_MISMATCH:
3723                         case SCF_ERROR_INVALID_ARGUMENT:
3724                         case SCF_ERROR_NOT_SET:
3725                         default:
3726                                 bad_error("scf_service_add_pg", scf_error());
3727                         }
3728                 }
3729         }
3730 
3731         cbdata.sc_trans = ud_tx;
3732 
3733         if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3734                 switch (scf_error()) {
3735                 case SCF_ERROR_CONNECTION_BROKEN:
3736                 case SCF_ERROR_BACKEND_ACCESS:
3737                 case SCF_ERROR_BACKEND_READONLY:
3738                         return (scferror2errno(scf_error()));
3739 
3740                 case SCF_ERROR_DELETED:
3741                         warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3742                         return (EBUSY);
3743 
3744                 case SCF_ERROR_PERMISSION_DENIED:
3745                         warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3746                         return (scferror2errno(scf_error()));
3747 
3748                 case SCF_ERROR_HANDLE_MISMATCH:
3749                 case SCF_ERROR_IN_USE:
3750                 case SCF_ERROR_NOT_BOUND:
3751                 case SCF_ERROR_NOT_SET:
3752                 default:
3753                         bad_error("scf_transaction_start", scf_error());
3754                 }
3755         }
3756         tx_started = 1;
3757 
3758         for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3759             new_dpt_pgroup != NULL;
3760             new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3761             new_dpt_pgroup)) {
3762                 if (new_dpt_pgroup->sc_pgroup_seen)
3763                         continue;
3764 
3765                 if (ud_run_dpts_pg_set) {
3766                         /*
3767                          * If the dependent is already there, then we have
3768                          * a conflict.
3769                          */
3770                         if (scf_pg_get_property(ud_run_dpts_pg,
3771                             new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3772                                 r = handle_dependent_conflict(ient, ud_prop,
3773                                     new_dpt_pgroup);
3774                                 switch (r) {
3775                                 case 0:
3776                                         continue;
3777 
3778                                 case ECONNABORTED:
3779                                 case ENOMEM:
3780                                 case EBUSY:
3781                                 case EBADF:
3782                                 case EINVAL:
3783                                         scf_transaction_destroy_children(ud_tx);
3784                                         return (r);
3785 
3786                                 default:
3787                                         bad_error("handle_dependent_conflict",
3788                                             r);
3789                                 }
3790                         } else {
3791                                 switch (scf_error()) {
3792                                 case SCF_ERROR_NOT_FOUND:
3793                                         break;
3794 
3795                                 case SCF_ERROR_INVALID_ARGUMENT:
3796                                         warn(emsg_fmri_invalid_pg_name,
3797                                             ient->sc_fmri,
3798                                             new_dpt_pgroup->sc_pgroup_name);
3799                                         scf_transaction_destroy_children(ud_tx);
3800                                         return (EINVAL);
3801 
3802                                 case SCF_ERROR_DELETED:
3803                                         warn(emsg_pg_deleted, ient->sc_fmri,
3804                                             new_dpt_pgroup->sc_pgroup_name);
3805                                         scf_transaction_destroy_children(ud_tx);
3806                                         return (EBUSY);
3807 
3808                                 case SCF_ERROR_CONNECTION_BROKEN:
3809                                         scf_transaction_destroy_children(ud_tx);
3810                                         return (ECONNABORTED);
3811 
3812                                 case SCF_ERROR_NOT_BOUND:
3813                                 case SCF_ERROR_HANDLE_MISMATCH:
3814                                 case SCF_ERROR_NOT_SET:
3815                                 default:
3816                                         bad_error("scf_pg_get_property",
3817                                             scf_error());
3818                                 }
3819                         }
3820                 }
3821 
3822                 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3823                 if (r != UU_WALK_NEXT) {
3824                         if (r != UU_WALK_ERROR)
3825                                 bad_error("lscf_dependent_import", r);
3826 
3827                         if (cbdata.sc_err == EALREADY) {
3828                                 /* Collisions were handled preemptively. */
3829                                 bad_error("lscf_dependent_import",
3830                                     cbdata.sc_err);
3831                         }
3832 
3833                         scf_transaction_destroy_children(ud_tx);
3834                         return (cbdata.sc_err);
3835                 }
3836         }
3837 
3838 commit:
3839         if (!tx_started)
3840                 return (0);
3841 
3842         r = scf_transaction_commit(ud_tx);
3843 
3844         scf_transaction_destroy_children(ud_tx);
3845 
3846         switch (r) {
3847         case 1:
3848                 return (0);
3849 
3850         case 0:
3851                 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3852                 return (EBUSY);
3853 
3854         case -1:
3855                 break;
3856 
3857         default:
3858                 bad_error("scf_transaction_commit", r);
3859         }
3860 
3861         switch (scf_error()) {
3862         case SCF_ERROR_CONNECTION_BROKEN:
3863         case SCF_ERROR_BACKEND_READONLY:
3864         case SCF_ERROR_BACKEND_ACCESS:
3865         case SCF_ERROR_NO_RESOURCES:
3866                 return (scferror2errno(scf_error()));
3867 
3868         case SCF_ERROR_DELETED:
3869                 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3870                 return (EBUSY);
3871 
3872         case SCF_ERROR_PERMISSION_DENIED:
3873                 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3874                 return (scferror2errno(scf_error()));
3875 
3876         case SCF_ERROR_NOT_BOUND:
3877         case SCF_ERROR_INVALID_ARGUMENT:
3878         case SCF_ERROR_NOT_SET:
3879         default:
3880                 bad_error("scf_transaction_destroy", scf_error());
3881                 /* NOTREACHED */
3882         }
3883 }
3884 
3885 /*
3886  * Used to add the manifests to the list of currently supported manifests.
3887  * We can modify the existing manifest list removing entries if the files
3888  * don't exist.
3889  *
3890  * Get the old list and the new file name
3891  * If the new file name is in the list return
3892  * If not then add the file to the list.
3893  * As we process the list check to see if the files in the old list exist
3894  *      if not then remove the file from the list.
3895  * Commit the list of manifest file names.
3896  *
3897  */
3898 static int
3899 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3900     const scf_snaplevel_t *running, void *ent)
3901 {
3902         scf_propertygroup_t *ud_mfsts_pg = NULL;
3903         scf_property_t *ud_prop = NULL;
3904         scf_iter_t *ud_prop_iter;
3905         scf_value_t *fname_value;
3906         scf_callback_t cbdata;
3907         pgroup_t *mfst_pgroup;
3908         property_t *mfst_prop;
3909         property_t *old_prop;
3910         char *pname;
3911         char *fval;
3912         char *old_pname;
3913         char *old_fval;
3914         int no_upgrade_pg;
3915         int mfst_seen;
3916         int r;
3917 
3918         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3919 
3920         /*
3921          * This should always be the service base on the code
3922          * path, and the fact that the manifests pg is a service
3923          * level property group only.
3924          */
3925         ud_mfsts_pg = scf_pg_create(g_hndl);
3926         ud_prop = scf_property_create(g_hndl);
3927         ud_prop_iter = scf_iter_create(g_hndl);
3928         fname_value = scf_value_create(g_hndl);
3929 
3930         /* Fetch the "manifests" property group */
3931         no_upgrade_pg = 0;
3932         r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3933             ud_mfsts_pg);
3934         if (r != 0) {
3935                 switch (scf_error()) {
3936                 case SCF_ERROR_NOT_FOUND:
3937                         no_upgrade_pg = 1;
3938                         break;
3939 
3940                 case SCF_ERROR_DELETED:
3941                 case SCF_ERROR_CONNECTION_BROKEN:
3942                         return (scferror2errno(scf_error()));
3943 
3944                 case SCF_ERROR_NOT_SET:
3945                 case SCF_ERROR_INVALID_ARGUMENT:
3946                 case SCF_ERROR_HANDLE_MISMATCH:
3947                 case SCF_ERROR_NOT_BOUND:
3948                 default:
3949                         bad_error(running ? "scf_snaplevel_get_pg" :
3950                             "entity_get_pg", scf_error());
3951                 }
3952         }
3953 
3954         if (no_upgrade_pg) {
3955                 cbdata.sc_handle = g_hndl;
3956                 cbdata.sc_parent = ent;
3957                 cbdata.sc_service = issvc;
3958                 cbdata.sc_flags = SCI_FORCE;
3959                 cbdata.sc_source_fmri = ient->sc_fmri;
3960                 cbdata.sc_target_fmri = ient->sc_fmri;
3961 
3962                 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3963                         return (cbdata.sc_err);
3964 
3965                 return (0);
3966         }
3967 
3968         /* Fetch the new manifests property group */
3969         mfst_pgroup = internal_pgroup_find_or_create(ient,
3970             SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3971         assert(mfst_pgroup != NULL);
3972 
3973         if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3974             SCF_SUCCESS)
3975                 return (-1);
3976 
3977         if ((pname = malloc(MAXPATHLEN)) == NULL)
3978                 return (ENOMEM);
3979         if ((fval = malloc(MAXPATHLEN)) == NULL) {
3980                 free(pname);
3981                 return (ENOMEM);
3982         }
3983 
3984         while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3985                 mfst_seen = 0;
3986                 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3987                         continue;
3988 
3989                 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3990                     mfst_prop != NULL;
3991                     mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3992                     mfst_prop)) {
3993                         if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3994                                 mfst_seen = 1;
3995                         }
3996                 }
3997 
3998                 /*
3999                  * If the manifest is not seen then add it to the new mfst
4000                  * property list to get proccessed into the repo.
4001                  */
4002                 if (mfst_seen == 0) {
4003                         /*
4004                          * If we cannot get the value then there is no
4005                          * reason to attempt to attach the value to
4006                          * the property group
4007                          */
4008                         if (prop_get_val(ud_prop, fname_value) == 0 &&
4009                             scf_value_get_astring(fname_value, fval,
4010                             MAXPATHLEN) != -1)  {
4011                                 old_pname = safe_strdup(pname);
4012                                 old_fval = safe_strdup(fval);
4013                                 old_prop = internal_property_create(old_pname,
4014                                     SCF_TYPE_ASTRING, 1, old_fval);
4015 
4016                                 /*
4017                                  * Already checked to see if the property exists
4018                                  * in the group, and it does not.
4019                                  */
4020                                 (void) internal_attach_property(mfst_pgroup,
4021                                     old_prop);
4022                         }
4023                 }
4024         }
4025         free(pname);
4026         free(fval);
4027 
4028         cbdata.sc_handle = g_hndl;
4029         cbdata.sc_parent = ent;
4030         cbdata.sc_service = issvc;
4031         cbdata.sc_flags = SCI_FORCE;
4032         cbdata.sc_source_fmri = ient->sc_fmri;
4033         cbdata.sc_target_fmri = ient->sc_fmri;
4034 
4035         if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4036                 return (cbdata.sc_err);
4037 
4038         return (r);
4039 }
4040 
4041 /*
4042  * prop is taken to be a property in the "dependents" property group of snpl,
4043  * which is taken to be the snaplevel of a last-import snapshot corresponding
4044  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4045  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4046  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4047  * of the entity ient represents (possibly in the running snapshot).  If it
4048  * needs to be changed, an entry will be added to tx, if not NULL.
4049  *
4050  * Returns
4051  *   0 - success
4052  *   ECONNABORTED - repository connection broken
4053  *   ENOMEM - out of memory
4054  *   ENOSPC - configd was out of resources
4055  *   ECANCELED - snpl's entity was deleted
4056  *   EINVAL - dependent target is invalid (error printed)
4057  *          - dependent is invalid (error printed)
4058  *   EBADF - snpl is corrupt (error printed)
4059  *         - snpl has corrupt pg (error printed)
4060  *         - dependency pg in target is corrupt (error printed)
4061  *         - running snapshot in dependent is missing snaplevel (error printed)
4062  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4063  *         - couldn't create dependent (permission denied) (error printed)
4064  *         - couldn't modify dependent pg (permission denied) (error printed)
4065  *   EROFS - couldn't delete dependency pg (repository read-only)
4066  *         - couldn't create dependent (repository read-only)
4067  *   EACCES - couldn't delete dependency pg (backend access denied)
4068  *          - couldn't create dependent (backend access denied)
4069  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4070  *         - tx's pg was deleted (error printed)
4071  *         - dependent pg was changed or deleted (error printed)
4072  *   EEXIST - dependency pg already exists in new target (error printed)
4073  */
4074 static int
4075 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4076     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4077 {
4078         pgroup_t pgrp;
4079         scf_type_t ty;
4080         pgroup_t *new_dpt_pgroup;
4081         pgroup_t *old_dpt_pgroup = NULL;
4082         pgroup_t *current_pg;
4083         pgroup_t *dpt;
4084         scf_callback_t cbdata;
4085         int tissvc;
4086         void *target_ent;
4087         scf_error_t serr;
4088         int r;
4089         scf_transaction_entry_t *ent;
4090 
4091         const char * const cf_inval = gettext("Conflict upgrading %s "
4092             "(dependent \"%s\" has invalid dependents property).\n");
4093         const char * const cf_missing = gettext("Conflict upgrading %s "
4094             "(dependent \"%s\" is missing).\n");
4095         const char * const cf_newdpg = gettext("Conflict upgrading %s "
4096             "(dependent \"%s\" has new dependency property group).\n");
4097         const char * const cf_newtarg = gettext("Conflict upgrading %s "
4098             "(dependent \"%s\" has new target).\n");
4099         const char * const li_corrupt =
4100             gettext("%s: \"last-import\" snapshot is corrupt.\n");
4101         const char * const upgrading =
4102             gettext("%s: Upgrading dependent \"%s\".\n");
4103         const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4104             "corrupt (missing snaplevel).\n");
4105 
4106         if (scf_property_type(prop, &ty) != 0) {
4107                 switch (scf_error()) {
4108                 case SCF_ERROR_DELETED:
4109                 case SCF_ERROR_CONNECTION_BROKEN:
4110                         return (scferror2errno(scf_error()));
4111 
4112                 case SCF_ERROR_NOT_BOUND:
4113                 case SCF_ERROR_NOT_SET:
4114                 default:
4115                         bad_error("scf_property_type", scf_error());
4116                 }
4117         }
4118 
4119         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4120                 warn(li_corrupt, ient->sc_fmri);
4121                 return (EBADF);
4122         }
4123 
4124         /*
4125          * prop represents a dependent in the old manifest.  It is named after
4126          * the dependent.
4127          */
4128         if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4129                 switch (scf_error()) {
4130                 case SCF_ERROR_DELETED:
4131                 case SCF_ERROR_CONNECTION_BROKEN:
4132                         return (scferror2errno(scf_error()));
4133 
4134                 case SCF_ERROR_NOT_BOUND:
4135                 case SCF_ERROR_NOT_SET:
4136                 default:
4137                         bad_error("scf_property_get_name", scf_error());
4138                 }
4139         }
4140 
4141         /* See if it's in the new manifest. */
4142         pgrp.sc_pgroup_name = ud_name;
4143         new_dpt_pgroup =
4144             uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4145 
4146         /* If it's not, delete it... if it hasn't been customized. */
4147         if (new_dpt_pgroup == NULL) {
4148                 if (!ud_run_dpts_pg_set)
4149                         return (0);
4150 
4151                 if (scf_property_get_value(prop, ud_val) != 0) {
4152                         switch (scf_error()) {
4153                         case SCF_ERROR_NOT_FOUND:
4154                         case SCF_ERROR_CONSTRAINT_VIOLATED:
4155                                 warn(li_corrupt, ient->sc_fmri);
4156                                 return (EBADF);
4157 
4158                         case SCF_ERROR_DELETED:
4159                         case SCF_ERROR_CONNECTION_BROKEN:
4160                                 return (scferror2errno(scf_error()));
4161 
4162                         case SCF_ERROR_HANDLE_MISMATCH:
4163                         case SCF_ERROR_NOT_BOUND:
4164                         case SCF_ERROR_NOT_SET:
4165                         case SCF_ERROR_PERMISSION_DENIED:
4166                         default:
4167                                 bad_error("scf_property_get_value",
4168                                     scf_error());
4169                         }
4170                 }
4171 
4172                 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4173                     max_scf_value_len + 1) < 0)
4174                         bad_error("scf_value_get_as_string", scf_error());
4175 
4176                 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4177                     0) {
4178                         switch (scf_error()) {
4179                         case SCF_ERROR_NOT_FOUND:
4180                                 return (0);
4181 
4182                         case SCF_ERROR_CONNECTION_BROKEN:
4183                                 return (scferror2errno(scf_error()));
4184 
4185                         case SCF_ERROR_DELETED:
4186                                 warn(emsg_pg_deleted, ient->sc_fmri,
4187                                     "dependents");
4188                                 return (EBUSY);
4189 
4190                         case SCF_ERROR_INVALID_ARGUMENT:
4191                         case SCF_ERROR_NOT_BOUND:
4192                         case SCF_ERROR_HANDLE_MISMATCH:
4193                         case SCF_ERROR_NOT_SET:
4194                         default:
4195                                 bad_error("scf_pg_get_property", scf_error());
4196                         }
4197                 }
4198                 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4199                         switch (scf_error()) {
4200                         case SCF_ERROR_NOT_FOUND:
4201                         case SCF_ERROR_CONSTRAINT_VIOLATED:
4202                                 warn(cf_inval, ient->sc_fmri, ud_name);
4203                                 return (0);
4204 
4205                         case SCF_ERROR_DELETED:
4206                         case SCF_ERROR_CONNECTION_BROKEN:
4207                                 return (scferror2errno(scf_error()));
4208 
4209                         case SCF_ERROR_HANDLE_MISMATCH:
4210                         case SCF_ERROR_NOT_BOUND:
4211                         case SCF_ERROR_NOT_SET:
4212                         case SCF_ERROR_PERMISSION_DENIED:
4213                         default:
4214                                 bad_error("scf_property_get_value",
4215                                     scf_error());
4216                         }
4217                 }
4218 
4219                 ty = scf_value_type(ud_val);
4220                 assert(ty != SCF_TYPE_INVALID);
4221                 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4222                         warn(cf_inval, ient->sc_fmri, ud_name);
4223                         return (0);
4224                 }
4225 
4226                 if (scf_value_get_as_string(ud_val, ud_ctarg,
4227                     max_scf_value_len + 1) < 0)
4228                         bad_error("scf_value_get_as_string", scf_error());
4229 
4230                 r = fmri_equal(ud_ctarg, ud_oldtarg);
4231                 switch (r) {
4232                 case 1:
4233                         break;
4234 
4235                 case 0:
4236                 case -1:        /* warn? */
4237                         warn(cf_newtarg, ient->sc_fmri, ud_name);
4238                         return (0);
4239 
4240                 case -2:
4241                         warn(li_corrupt, ient->sc_fmri);
4242                         return (EBADF);
4243 
4244                 default:
4245                         bad_error("fmri_equal", r);
4246                 }
4247 
4248                 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4249                         switch (scf_error()) {
4250                         case SCF_ERROR_NOT_FOUND:
4251                                 warn(li_corrupt, ient->sc_fmri);
4252                                 return (EBADF);
4253 
4254                         case SCF_ERROR_DELETED:
4255                         case SCF_ERROR_CONNECTION_BROKEN:
4256                                 return (scferror2errno(scf_error()));
4257 
4258                         case SCF_ERROR_NOT_BOUND:
4259                         case SCF_ERROR_HANDLE_MISMATCH:
4260                         case SCF_ERROR_INVALID_ARGUMENT:
4261                         case SCF_ERROR_NOT_SET:
4262                         default:
4263                                 bad_error("scf_snaplevel_get_pg", scf_error());
4264                         }
4265                 }
4266 
4267                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4268                     snap_lastimport);
4269                 switch (r) {
4270                 case 0:
4271                         break;
4272 
4273                 case ECANCELED:
4274                 case ECONNABORTED:
4275                 case ENOMEM:
4276                 case EBADF:
4277                         return (r);
4278 
4279                 case EACCES:
4280                 default:
4281                         bad_error("load_pg", r);
4282                 }
4283 
4284                 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4285                 switch (serr) {
4286                 case SCF_ERROR_NONE:
4287                         break;
4288 
4289                 case SCF_ERROR_NO_MEMORY:
4290                         internal_pgroup_free(old_dpt_pgroup);
4291                         return (ENOMEM);
4292 
4293                 case SCF_ERROR_NOT_FOUND:
4294                         internal_pgroup_free(old_dpt_pgroup);
4295                         goto delprop;
4296 
4297                 case SCF_ERROR_CONSTRAINT_VIOLATED:     /* caught above */
4298                 case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
4299                 default:
4300                         bad_error("fmri_to_entity", serr);
4301                 }
4302 
4303                 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4304                     ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4305                 switch (r) {
4306                 case 0:
4307                         break;
4308 
4309                 case ECONNABORTED:
4310                         internal_pgroup_free(old_dpt_pgroup);
4311                         return (r);
4312 
4313                 case ECANCELED:
4314                 case ENOENT:
4315                         internal_pgroup_free(old_dpt_pgroup);
4316                         goto delprop;
4317 
4318                 case EBADF:
4319                         warn(r_no_lvl, ud_ctarg);
4320                         internal_pgroup_free(old_dpt_pgroup);
4321                         return (r);
4322 
4323                 case EINVAL:
4324                 default:
4325                         bad_error("entity_get_running_pg", r);
4326                 }
4327 
4328                 /* load it */
4329                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4330                 switch (r) {
4331                 case 0:
4332                         break;
4333 
4334                 case ECANCELED:
4335                         internal_pgroup_free(old_dpt_pgroup);
4336                         goto delprop;
4337 
4338                 case ECONNABORTED:
4339                 case ENOMEM:
4340                 case EBADF:
4341                         internal_pgroup_free(old_dpt_pgroup);
4342                         return (r);
4343 
4344                 case EACCES:
4345                 default:
4346                         bad_error("load_pg", r);
4347                 }
4348 
4349                 /* compare property groups */
4350                 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4351                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4352                         internal_pgroup_free(old_dpt_pgroup);
4353                         internal_pgroup_free(current_pg);
4354                         return (0);
4355                 }
4356 
4357                 internal_pgroup_free(old_dpt_pgroup);
4358                 internal_pgroup_free(current_pg);
4359 
4360                 if (g_verbose)
4361                         warn(gettext("%s: Deleting dependent \"%s\".\n"),
4362                             ient->sc_fmri, ud_name);
4363 
4364                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4365                         switch (scf_error()) {
4366                         case SCF_ERROR_NOT_FOUND:
4367                         case SCF_ERROR_DELETED:
4368                                 internal_pgroup_free(old_dpt_pgroup);
4369                                 goto delprop;
4370 
4371                         case SCF_ERROR_CONNECTION_BROKEN:
4372                                 internal_pgroup_free(old_dpt_pgroup);
4373                                 return (ECONNABORTED);
4374 
4375                         case SCF_ERROR_NOT_SET:
4376                         case SCF_ERROR_INVALID_ARGUMENT:
4377                         case SCF_ERROR_HANDLE_MISMATCH:
4378                         case SCF_ERROR_NOT_BOUND:
4379                         default:
4380                                 bad_error("entity_get_pg", scf_error());
4381                         }
4382                 }
4383 
4384                 if (scf_pg_delete(ud_pg) != 0) {
4385                         switch (scf_error()) {
4386                         case SCF_ERROR_DELETED:
4387                                 break;
4388 
4389                         case SCF_ERROR_CONNECTION_BROKEN:
4390                         case SCF_ERROR_BACKEND_READONLY:
4391                         case SCF_ERROR_BACKEND_ACCESS:
4392                                 return (scferror2errno(scf_error()));
4393 
4394                         case SCF_ERROR_PERMISSION_DENIED:
4395                                 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4396                                 return (scferror2errno(scf_error()));
4397 
4398                         case SCF_ERROR_NOT_SET:
4399                         default:
4400                                 bad_error("scf_pg_delete", scf_error());
4401                         }
4402                 }
4403 
4404                 /*
4405                  * This service was changed, so it must be refreshed.  But
4406                  * since it's not mentioned in the new manifest, we have to
4407                  * record its FMRI here for use later.  We record the name
4408                  * & the entity (via sc_parent) in case we need to print error
4409                  * messages during the refresh.
4410                  */
4411                 dpt = internal_pgroup_new();
4412                 if (dpt == NULL)
4413                         return (ENOMEM);
4414                 dpt->sc_pgroup_name = strdup(ud_name);
4415                 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4416                 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4417                         return (ENOMEM);
4418                 dpt->sc_parent = (entity_t *)ient;
4419                 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4420                         uu_die(gettext("libuutil error: %s\n"),
4421                             uu_strerror(uu_error()));
4422 
4423 delprop:
4424                 if (tx == NULL)
4425                         return (0);
4426 
4427                 ent = scf_entry_create(g_hndl);
4428                 if (ent == NULL)
4429                         return (ENOMEM);
4430 
4431                 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4432                         scf_entry_destroy(ent);
4433                         switch (scf_error()) {
4434                         case SCF_ERROR_DELETED:
4435                                 warn(emsg_pg_deleted, ient->sc_fmri,
4436                                     "dependents");
4437                                 return (EBUSY);
4438 
4439                         case SCF_ERROR_CONNECTION_BROKEN:
4440                                 return (scferror2errno(scf_error()));
4441 
4442                         case SCF_ERROR_NOT_FOUND:
4443                                 break;
4444 
4445                         case SCF_ERROR_HANDLE_MISMATCH:
4446                         case SCF_ERROR_NOT_BOUND:
4447                         case SCF_ERROR_INVALID_ARGUMENT:
4448                         case SCF_ERROR_NOT_SET:
4449                         default:
4450                                 bad_error("scf_transaction_property_delete",
4451                                     scf_error());
4452                         }
4453                 }
4454 
4455                 return (0);
4456         }
4457 
4458         new_dpt_pgroup->sc_pgroup_seen = 1;
4459 
4460         /*
4461          * Decide whether the dependent has changed in the manifest.
4462          */
4463         /* Compare the target. */
4464         if (scf_property_get_value(prop, ud_val) != 0) {
4465                 switch (scf_error()) {
4466                 case SCF_ERROR_NOT_FOUND:
4467                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4468                         warn(li_corrupt, ient->sc_fmri);
4469                         return (EBADF);
4470 
4471                 case SCF_ERROR_DELETED:
4472                 case SCF_ERROR_CONNECTION_BROKEN:
4473                         return (scferror2errno(scf_error()));
4474 
4475                 case SCF_ERROR_HANDLE_MISMATCH:
4476                 case SCF_ERROR_NOT_BOUND:
4477                 case SCF_ERROR_NOT_SET:
4478                 case SCF_ERROR_PERMISSION_DENIED:
4479                 default:
4480                         bad_error("scf_property_get_value", scf_error());
4481                 }
4482         }
4483 
4484         if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4485             0)
4486                 bad_error("scf_value_get_as_string", scf_error());
4487 
4488         /*
4489          * If the fmri's are not equal then the old fmri will need to
4490          * be refreshed to ensure that the changes are properly updated
4491          * in that service.
4492          */
4493         r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4494         switch (r) {
4495         case 0:
4496                 dpt = internal_pgroup_new();
4497                 if (dpt == NULL)
4498                         return (ENOMEM);
4499                 dpt->sc_pgroup_name = strdup(ud_name);
4500                 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4501                 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4502                         return (ENOMEM);
4503                 dpt->sc_parent = (entity_t *)ient;
4504                 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4505                         uu_die(gettext("libuutil error: %s\n"),
4506                             uu_strerror(uu_error()));
4507                 break;
4508 
4509         case 1:
4510                 /* Compare the dependency pgs. */
4511                 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4512                         switch (scf_error()) {
4513                         case SCF_ERROR_NOT_FOUND:
4514                                 warn(li_corrupt, ient->sc_fmri);
4515                                 return (EBADF);
4516 
4517                         case SCF_ERROR_DELETED:
4518                         case SCF_ERROR_CONNECTION_BROKEN:
4519                                 return (scferror2errno(scf_error()));
4520 
4521                         case SCF_ERROR_NOT_BOUND:
4522                         case SCF_ERROR_HANDLE_MISMATCH:
4523                         case SCF_ERROR_INVALID_ARGUMENT:
4524                         case SCF_ERROR_NOT_SET:
4525                         default:
4526                                 bad_error("scf_snaplevel_get_pg", scf_error());
4527                         }
4528                 }
4529 
4530                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4531                     snap_lastimport);
4532                 switch (r) {
4533                 case 0:
4534                         break;
4535 
4536                 case ECANCELED:
4537                 case ECONNABORTED:
4538                 case ENOMEM:
4539                 case EBADF:
4540                         return (r);
4541 
4542                 case EACCES:
4543                 default:
4544                         bad_error("load_pg", r);
4545                 }
4546 
4547                 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4548                         /* no change, leave customizations */
4549                         internal_pgroup_free(old_dpt_pgroup);
4550                         return (0);
4551                 }
4552                 break;
4553 
4554         case -1:
4555                 warn(li_corrupt, ient->sc_fmri);
4556                 return (EBADF);
4557 
4558         case -2:
4559                 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4560                     ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4561                 return (EINVAL);
4562 
4563         default:
4564                 bad_error("fmri_equal", r);
4565         }
4566 
4567         /*
4568          * The dependent has changed in the manifest.  Upgrade the current
4569          * properties if they haven't been customized.
4570          */
4571 
4572         /*
4573          * If new_dpt_pgroup->sc_override, then act as though the property
4574          * group hasn't been customized.
4575          */
4576         if (new_dpt_pgroup->sc_pgroup_override) {
4577                 (void) strcpy(ud_ctarg, ud_oldtarg);
4578                 goto nocust;
4579         }
4580 
4581         if (!ud_run_dpts_pg_set) {
4582                 warn(cf_missing, ient->sc_fmri, ud_name);
4583                 r = 0;
4584                 goto out;
4585         } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4586                 switch (scf_error()) {
4587                 case SCF_ERROR_NOT_FOUND:
4588                         warn(cf_missing, ient->sc_fmri, ud_name);
4589                         r = 0;
4590                         goto out;
4591 
4592                 case SCF_ERROR_CONNECTION_BROKEN:
4593                         r = scferror2errno(scf_error());
4594                         goto out;
4595 
4596                 case SCF_ERROR_DELETED:
4597                         warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4598                         r = EBUSY;
4599                         goto out;
4600 
4601                 case SCF_ERROR_INVALID_ARGUMENT:
4602                 case SCF_ERROR_NOT_BOUND:
4603                 case SCF_ERROR_HANDLE_MISMATCH:
4604                 case SCF_ERROR_NOT_SET:
4605                 default:
4606                         bad_error("scf_pg_get_property", scf_error());
4607                 }
4608         }
4609 
4610         if (scf_property_get_value(ud_prop, ud_val) != 0) {
4611                 switch (scf_error()) {
4612                 case SCF_ERROR_NOT_FOUND:
4613                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4614                         warn(cf_inval, ient->sc_fmri, ud_name);
4615                         r = 0;
4616                         goto out;
4617 
4618                 case SCF_ERROR_DELETED:
4619                 case SCF_ERROR_CONNECTION_BROKEN:
4620                         r = scferror2errno(scf_error());
4621                         goto out;
4622 
4623                 case SCF_ERROR_HANDLE_MISMATCH:
4624                 case SCF_ERROR_NOT_BOUND:
4625                 case SCF_ERROR_NOT_SET:
4626                 case SCF_ERROR_PERMISSION_DENIED:
4627                 default:
4628                         bad_error("scf_property_get_value", scf_error());
4629                 }
4630         }
4631 
4632         ty = scf_value_type(ud_val);
4633         assert(ty != SCF_TYPE_INVALID);
4634         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4635                 warn(cf_inval, ient->sc_fmri, ud_name);
4636                 r = 0;
4637                 goto out;
4638         }
4639         if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4640             0)
4641                 bad_error("scf_value_get_as_string", scf_error());
4642 
4643         r = fmri_equal(ud_ctarg, ud_oldtarg);
4644         if (r == -1) {
4645                 warn(cf_inval, ient->sc_fmri, ud_name);
4646                 r = 0;
4647                 goto out;
4648         } else if (r == -2) {
4649                 warn(li_corrupt, ient->sc_fmri);
4650                 r = EBADF;
4651                 goto out;
4652         } else if (r == 0) {
4653                 /*
4654                  * Target has been changed.  Only abort now if it's been
4655                  * changed to something other than what's in the manifest.
4656                  */
4657                 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4658                 if (r == -1) {
4659                         warn(cf_inval, ient->sc_fmri, ud_name);
4660                         r = 0;
4661                         goto out;
4662                 } else if (r == 0) {
4663                         warn(cf_newtarg, ient->sc_fmri, ud_name);
4664                         r = 0;
4665                         goto out;
4666                 } else if (r != 1) {
4667                         /* invalid sc_pgroup_fmri caught above */
4668                         bad_error("fmri_equal", r);
4669                 }
4670 
4671                 /*
4672                  * Fetch the current dependency pg.  If it's what the manifest
4673                  * says, then no problem.
4674                  */
4675                 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4676                 switch (serr) {
4677                 case SCF_ERROR_NONE:
4678                         break;
4679 
4680                 case SCF_ERROR_NOT_FOUND:
4681                         warn(cf_missing, ient->sc_fmri, ud_name);
4682                         r = 0;
4683                         goto out;
4684 
4685                 case SCF_ERROR_NO_MEMORY:
4686                         r = ENOMEM;
4687                         goto out;
4688 
4689                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4690                 case SCF_ERROR_INVALID_ARGUMENT:
4691                 default:
4692                         bad_error("fmri_to_entity", serr);
4693                 }
4694 
4695                 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4696                     ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4697                 switch (r) {
4698                 case 0:
4699                         break;
4700 
4701                 case ECONNABORTED:
4702                         goto out;
4703 
4704                 case ECANCELED:
4705                 case ENOENT:
4706                         warn(cf_missing, ient->sc_fmri, ud_name);
4707                         r = 0;
4708                         goto out;
4709 
4710                 case EBADF:
4711                         warn(r_no_lvl, ud_ctarg);
4712                         goto out;
4713 
4714                 case EINVAL:
4715                 default:
4716                         bad_error("entity_get_running_pg", r);
4717                 }
4718 
4719                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4720                 switch (r) {
4721                 case 0:
4722                         break;
4723 
4724                 case ECANCELED:
4725                         warn(cf_missing, ient->sc_fmri, ud_name);
4726                         r = 0;
4727                         goto out;
4728 
4729                 case ECONNABORTED:
4730                 case ENOMEM:
4731                 case EBADF:
4732                         goto out;
4733 
4734                 case EACCES:
4735                 default:
4736                         bad_error("load_pg", r);
4737                 }
4738 
4739                 if (!pg_equal(current_pg, new_dpt_pgroup))
4740                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4741                 internal_pgroup_free(current_pg);
4742                 r = 0;
4743                 goto out;
4744         } else if (r != 1) {
4745                 bad_error("fmri_equal", r);
4746         }
4747 
4748 nocust:
4749         /*
4750          * Target has not been customized.  Check the dependency property
4751          * group.
4752          */
4753 
4754         if (old_dpt_pgroup == NULL) {
4755                 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4756                     ud_pg) != 0) {
4757                         switch (scf_error()) {
4758                         case SCF_ERROR_NOT_FOUND:
4759                                 warn(li_corrupt, ient->sc_fmri);
4760                                 return (EBADF);
4761 
4762                         case SCF_ERROR_DELETED:
4763                         case SCF_ERROR_CONNECTION_BROKEN:
4764                                 return (scferror2errno(scf_error()));
4765 
4766                         case SCF_ERROR_NOT_BOUND:
4767                         case SCF_ERROR_HANDLE_MISMATCH:
4768                         case SCF_ERROR_INVALID_ARGUMENT:
4769                         case SCF_ERROR_NOT_SET:
4770                         default:
4771                                 bad_error("scf_snaplevel_get_pg", scf_error());
4772                         }
4773                 }
4774 
4775                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4776                     snap_lastimport);
4777                 switch (r) {
4778                 case 0:
4779                         break;
4780 
4781                 case ECANCELED:
4782                 case ECONNABORTED:
4783                 case ENOMEM:
4784                 case EBADF:
4785                         return (r);
4786 
4787                 case EACCES:
4788                 default:
4789                         bad_error("load_pg", r);
4790                 }
4791         }
4792         serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4793         switch (serr) {
4794         case SCF_ERROR_NONE:
4795                 break;
4796 
4797         case SCF_ERROR_NOT_FOUND:
4798                 warn(cf_missing, ient->sc_fmri, ud_name);
4799                 r = 0;
4800                 goto out;
4801 
4802         case SCF_ERROR_NO_MEMORY:
4803                 r = ENOMEM;
4804                 goto out;
4805 
4806         case SCF_ERROR_CONSTRAINT_VIOLATED:
4807         case SCF_ERROR_INVALID_ARGUMENT:
4808         default:
4809                 bad_error("fmri_to_entity", serr);
4810         }
4811 
4812         r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4813             ud_iter2, ud_inst, imp_snap, ud_snpl);
4814         switch (r) {
4815         case 0:
4816                 break;
4817 
4818         case ECONNABORTED:
4819                 goto out;
4820 
4821         case ECANCELED:
4822         case ENOENT:
4823                 warn(cf_missing, ient->sc_fmri, ud_name);
4824                 r = 0;
4825                 goto out;
4826 
4827         case EBADF:
4828                 warn(r_no_lvl, ud_ctarg);
4829                 goto out;
4830 
4831         case EINVAL:
4832         default:
4833                 bad_error("entity_get_running_pg", r);
4834         }
4835 
4836         r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4837         switch (r) {
4838         case 0:
4839                 break;
4840 
4841         case ECANCELED:
4842                 warn(cf_missing, ient->sc_fmri, ud_name);
4843                 goto out;
4844 
4845         case ECONNABORTED:
4846         case ENOMEM:
4847         case EBADF:
4848                 goto out;
4849 
4850         case EACCES:
4851         default:
4852                 bad_error("load_pg", r);
4853         }
4854 
4855         if (!pg_equal(current_pg, old_dpt_pgroup)) {
4856                 if (!pg_equal(current_pg, new_dpt_pgroup))
4857                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4858                 internal_pgroup_free(current_pg);
4859                 r = 0;
4860                 goto out;
4861         }
4862 
4863         /* Uncustomized.  Upgrade. */
4864 
4865         r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4866         switch (r) {
4867         case 1:
4868                 if (pg_equal(current_pg, new_dpt_pgroup)) {
4869                         /* Already upgraded. */
4870                         internal_pgroup_free(current_pg);
4871                         r = 0;
4872                         goto out;
4873                 }
4874 
4875                 internal_pgroup_free(current_pg);
4876 
4877                 /* upgrade current_pg */
4878                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4879                         switch (scf_error()) {
4880                         case SCF_ERROR_CONNECTION_BROKEN:
4881                                 r = scferror2errno(scf_error());
4882                                 goto out;
4883 
4884                         case SCF_ERROR_DELETED:
4885                                 warn(cf_missing, ient->sc_fmri, ud_name);
4886                                 r = 0;
4887                                 goto out;
4888 
4889                         case SCF_ERROR_NOT_FOUND:
4890                                 break;
4891 
4892                         case SCF_ERROR_INVALID_ARGUMENT:
4893                         case SCF_ERROR_NOT_BOUND:
4894                         case SCF_ERROR_NOT_SET:
4895                         case SCF_ERROR_HANDLE_MISMATCH:
4896                         default:
4897                                 bad_error("entity_get_pg", scf_error());
4898                         }
4899 
4900                         if (tissvc)
4901                                 r = scf_service_add_pg(target_ent, ud_name,
4902                                     SCF_GROUP_DEPENDENCY, 0, ud_pg);
4903                         else
4904                                 r = scf_instance_add_pg(target_ent, ud_name,
4905                                     SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906                         if (r != 0) {
4907                                 switch (scf_error()) {
4908                                 case SCF_ERROR_CONNECTION_BROKEN:
4909                                 case SCF_ERROR_NO_RESOURCES:
4910                                 case SCF_ERROR_BACKEND_READONLY:
4911                                 case SCF_ERROR_BACKEND_ACCESS:
4912                                         r = scferror2errno(scf_error());
4913                                         goto out;
4914 
4915                                 case SCF_ERROR_DELETED:
4916                                         warn(cf_missing, ient->sc_fmri,
4917                                             ud_name);
4918                                         r = 0;
4919                                         goto out;
4920 
4921                                 case SCF_ERROR_PERMISSION_DENIED:
4922                                         warn(emsg_pg_deleted, ud_ctarg,
4923                                             ud_name);
4924                                         r = EPERM;
4925                                         goto out;
4926 
4927                                 case SCF_ERROR_EXISTS:
4928                                         warn(emsg_pg_added, ud_ctarg, ud_name);
4929                                         r = EBUSY;
4930                                         goto out;
4931 
4932                                 case SCF_ERROR_NOT_BOUND:
4933                                 case SCF_ERROR_HANDLE_MISMATCH:
4934                                 case SCF_ERROR_INVALID_ARGUMENT:
4935                                 case SCF_ERROR_NOT_SET:
4936                                 default:
4937                                         bad_error("entity_add_pg", scf_error());
4938                                 }
4939                         }
4940                 }
4941 
4942                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4943                 switch (r) {
4944                 case 0:
4945                         break;
4946 
4947                 case ECANCELED:
4948                         warn(cf_missing, ient->sc_fmri, ud_name);
4949                         goto out;
4950 
4951                 case ECONNABORTED:
4952                 case ENOMEM:
4953                 case EBADF:
4954                         goto out;
4955 
4956                 case EACCES:
4957                 default:
4958                         bad_error("load_pg", r);
4959                 }
4960 
4961                 if (g_verbose)
4962                         warn(upgrading, ient->sc_fmri, ud_name);
4963 
4964                 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4965                     new_dpt_pgroup, 0, ient->sc_fmri);
4966                 switch (r) {
4967                 case 0:
4968                         break;
4969 
4970                 case ECANCELED:
4971                         warn(emsg_pg_deleted, ud_ctarg, ud_name);
4972                         r = EBUSY;
4973                         goto out;
4974 
4975                 case EPERM:
4976                         warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4977                         goto out;
4978 
4979                 case EBUSY:
4980                         warn(emsg_pg_changed, ud_ctarg, ud_name);
4981                         goto out;
4982 
4983                 case ECONNABORTED:
4984                 case ENOMEM:
4985                 case ENOSPC:
4986                 case EROFS:
4987                 case EACCES:
4988                 case EINVAL:
4989                         goto out;
4990 
4991                 default:
4992                         bad_error("upgrade_pg", r);
4993                 }
4994                 break;
4995 
4996         case 0: {
4997                 scf_transaction_entry_t *ent;
4998                 scf_value_t *val;
4999 
5000                 internal_pgroup_free(current_pg);
5001 
5002                 /* delete old pg */
5003                 if (g_verbose)
5004                         warn(upgrading, ient->sc_fmri, ud_name);
5005 
5006                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5007                         switch (scf_error()) {
5008                         case SCF_ERROR_CONNECTION_BROKEN:
5009                                 r = scferror2errno(scf_error());
5010                                 goto out;
5011 
5012                         case SCF_ERROR_DELETED:
5013                                 warn(cf_missing, ient->sc_fmri, ud_name);
5014                                 r = 0;
5015                                 goto out;
5016 
5017                         case SCF_ERROR_NOT_FOUND:
5018                                 break;
5019 
5020                         case SCF_ERROR_INVALID_ARGUMENT:
5021                         case SCF_ERROR_NOT_BOUND:
5022                         case SCF_ERROR_NOT_SET:
5023                         case SCF_ERROR_HANDLE_MISMATCH:
5024                         default:
5025                                 bad_error("entity_get_pg", scf_error());
5026                         }
5027                 } else if (scf_pg_delete(ud_pg) != 0) {
5028                         switch (scf_error()) {
5029                         case SCF_ERROR_DELETED:
5030                                 break;
5031 
5032                         case SCF_ERROR_CONNECTION_BROKEN:
5033                         case SCF_ERROR_BACKEND_READONLY:
5034                         case SCF_ERROR_BACKEND_ACCESS:
5035                                 r = scferror2errno(scf_error());
5036                                 goto out;
5037 
5038                         case SCF_ERROR_PERMISSION_DENIED:
5039                                 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5040                                 r = scferror2errno(scf_error());
5041                                 goto out;
5042 
5043                         case SCF_ERROR_NOT_SET:
5044                         default:
5045                                 bad_error("scf_pg_delete", scf_error());
5046                         }
5047                 }
5048 
5049                 /* import new one */
5050                 cbdata.sc_handle = g_hndl;
5051                 cbdata.sc_trans = NULL;         /* handled below */
5052                 cbdata.sc_flags = 0;
5053 
5054                 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5055                 if (r != UU_WALK_NEXT) {
5056                         if (r != UU_WALK_ERROR)
5057                                 bad_error("lscf_dependent_import", r);
5058 
5059                         r = cbdata.sc_err;
5060                         goto out;
5061                 }
5062 
5063                 if (tx == NULL)
5064                         break;
5065 
5066                 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5067                     (val = scf_value_create(g_hndl)) == NULL) {
5068                         if (scf_error() == SCF_ERROR_NO_MEMORY)
5069                                 return (ENOMEM);
5070 
5071                         bad_error("scf_entry_create", scf_error());
5072                 }
5073 
5074                 if (scf_transaction_property_change_type(tx, ent, ud_name,
5075                     SCF_TYPE_FMRI) != 0) {
5076                         switch (scf_error()) {
5077                         case SCF_ERROR_CONNECTION_BROKEN:
5078                                 r = scferror2errno(scf_error());
5079                                 goto out;
5080 
5081                         case SCF_ERROR_DELETED:
5082                                 warn(emsg_pg_deleted, ient->sc_fmri,
5083                                     "dependents");
5084                                 r = EBUSY;
5085                                 goto out;
5086 
5087                         case SCF_ERROR_NOT_FOUND:
5088                                 break;
5089 
5090                         case SCF_ERROR_NOT_BOUND:
5091                         case SCF_ERROR_HANDLE_MISMATCH:
5092                         case SCF_ERROR_INVALID_ARGUMENT:
5093                         case SCF_ERROR_NOT_SET:
5094                         default:
5095                                 bad_error("scf_transaction_property_"
5096                                     "change_type", scf_error());
5097                         }
5098 
5099                         if (scf_transaction_property_new(tx, ent, ud_name,
5100                             SCF_TYPE_FMRI) != 0) {
5101                                 switch (scf_error()) {
5102                                 case SCF_ERROR_CONNECTION_BROKEN:
5103                                         r = scferror2errno(scf_error());
5104                                         goto out;
5105 
5106                                 case SCF_ERROR_DELETED:
5107                                         warn(emsg_pg_deleted, ient->sc_fmri,
5108                                             "dependents");
5109                                         r = EBUSY;
5110                                         goto out;
5111 
5112                                 case SCF_ERROR_EXISTS:
5113                                         warn(emsg_pg_changed, ient->sc_fmri,
5114                                             "dependents");
5115                                         r = EBUSY;
5116                                         goto out;
5117 
5118                                 case SCF_ERROR_INVALID_ARGUMENT:
5119                                 case SCF_ERROR_HANDLE_MISMATCH:
5120                                 case SCF_ERROR_NOT_BOUND:
5121                                 case SCF_ERROR_NOT_SET:
5122                                 default:
5123                                         bad_error("scf_transaction_property_"
5124                                             "new", scf_error());
5125                                 }
5126                         }
5127                 }
5128 
5129                 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5130                     new_dpt_pgroup->sc_pgroup_fmri) != 0)
5131                         /* invalid sc_pgroup_fmri caught above */
5132                         bad_error("scf_value_set_from_string",
5133                             scf_error());
5134 
5135                 if (scf_entry_add_value(ent, val) != 0)
5136                         bad_error("scf_entry_add_value", scf_error());
5137                 break;
5138         }
5139 
5140         case -2:
5141                 warn(li_corrupt, ient->sc_fmri);
5142                 internal_pgroup_free(current_pg);
5143                 r = EBADF;
5144                 goto out;
5145 
5146         case -1:
5147         default:
5148                 /* invalid sc_pgroup_fmri caught above */
5149                 bad_error("fmri_equal", r);
5150         }
5151 
5152         r = 0;
5153 
5154 out:
5155         if (old_dpt_pgroup != NULL)
5156                 internal_pgroup_free(old_dpt_pgroup);
5157 
5158         return (r);
5159 }
5160 
5161 /*
5162  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5163  * would import it, except it seems to exist in the service anyway.  Compare
5164  * the existent dependent with the one we would import, and report any
5165  * differences (if there are none, be silent).  prop is the property which
5166  * represents the existent dependent (in the dependents property group) in the
5167  * entity corresponding to ient.
5168  *
5169  * Returns
5170  *   0 - success (Sort of.  At least, we can continue importing.)
5171  *   ECONNABORTED - repository connection broken
5172  *   EBUSY - ancestor of prop was deleted (error printed)
5173  *   ENOMEM - out of memory
5174  *   EBADF - corrupt property group (error printed)
5175  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5176  */
5177 static int
5178 handle_dependent_conflict(const entity_t * const ient,
5179     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5180 {
5181         int r;
5182         scf_type_t ty;
5183         scf_error_t scfe;
5184         void *tptr;
5185         int tissvc;
5186         pgroup_t *pgroup;
5187 
5188         if (scf_property_get_value(prop, ud_val) != 0) {
5189                 switch (scf_error()) {
5190                 case SCF_ERROR_CONNECTION_BROKEN:
5191                         return (scferror2errno(scf_error()));
5192 
5193                 case SCF_ERROR_DELETED:
5194                         warn(emsg_pg_deleted, ient->sc_fmri,
5195                             new_dpt_pgroup->sc_pgroup_name);
5196                         return (EBUSY);
5197 
5198                 case SCF_ERROR_CONSTRAINT_VIOLATED:
5199                 case SCF_ERROR_NOT_FOUND:
5200                         warn(gettext("Conflict upgrading %s (not importing "
5201                             "dependent \"%s\" because it already exists.)  "
5202                             "Warning: The \"%s/%2$s\" property has more or "
5203                             "fewer than one value)).\n"), ient->sc_fmri,
5204                             new_dpt_pgroup->sc_pgroup_name, "dependents");
5205                         return (0);
5206 
5207                 case SCF_ERROR_HANDLE_MISMATCH:
5208                 case SCF_ERROR_NOT_BOUND:
5209                 case SCF_ERROR_NOT_SET:
5210                 case SCF_ERROR_PERMISSION_DENIED:
5211                 default:
5212                         bad_error("scf_property_get_value",
5213                             scf_error());
5214                 }
5215         }
5216 
5217         ty = scf_value_type(ud_val);
5218         assert(ty != SCF_TYPE_INVALID);
5219         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5220                 warn(gettext("Conflict upgrading %s (not importing dependent "
5221                     "\"%s\" because it already exists).  Warning: The "
5222                     "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5223                     ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5224                     scf_type_to_string(ty), "dependents");
5225                 return (0);
5226         }
5227 
5228         if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5229             0)
5230                 bad_error("scf_value_get_as_string", scf_error());
5231 
5232         r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5233         switch (r) {
5234         case 0:
5235                 warn(gettext("Conflict upgrading %s (not importing dependent "
5236                     "\"%s\" (target \"%s\") because it already exists with "
5237                     "target \"%s\").\n"), ient->sc_fmri,
5238                     new_dpt_pgroup->sc_pgroup_name,
5239                     new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5240                 return (0);
5241 
5242         case 1:
5243                 break;
5244 
5245         case -1:
5246                 warn(gettext("Conflict upgrading %s (not importing dependent "
5247                     "\"%s\" because it already exists).  Warning: The current "
5248                     "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5249                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5250                 return (0);
5251 
5252         case -2:
5253                 warn(gettext("Dependent \"%s\" of %s has invalid target "
5254                     "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5255                     new_dpt_pgroup->sc_pgroup_fmri);
5256                 return (EINVAL);
5257 
5258         default:
5259                 bad_error("fmri_equal", r);
5260         }
5261 
5262         /* compare dependency pgs in target */
5263         scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5264         switch (scfe) {
5265         case SCF_ERROR_NONE:
5266                 break;
5267 
5268         case SCF_ERROR_NO_MEMORY:
5269                 return (ENOMEM);
5270 
5271         case SCF_ERROR_NOT_FOUND:
5272                 warn(emsg_dpt_dangling, ient->sc_fmri,
5273                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5274                 return (0);
5275 
5276         case SCF_ERROR_CONSTRAINT_VIOLATED:
5277         case SCF_ERROR_INVALID_ARGUMENT:
5278         default:
5279                 bad_error("fmri_to_entity", scfe);
5280         }
5281 
5282         r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5283             ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5284         switch (r) {
5285         case 0:
5286                 break;
5287 
5288         case ECONNABORTED:
5289                 return (r);
5290 
5291         case ECANCELED:
5292                 warn(emsg_dpt_dangling, ient->sc_fmri,
5293                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5294                 return (0);
5295 
5296         case EBADF:
5297                 if (tissvc)
5298                         warn(gettext("%s has an instance with a \"%s\" "
5299                             "snapshot which is missing a snaplevel.\n"),
5300                             ud_ctarg, "running");
5301                 else
5302                         warn(gettext("%s has a \"%s\" snapshot which is "
5303                             "missing a snaplevel.\n"), ud_ctarg, "running");
5304                 /* FALLTHROUGH */
5305 
5306         case ENOENT:
5307                 warn(emsg_dpt_no_dep, ient->sc_fmri,
5308                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5309                     new_dpt_pgroup->sc_pgroup_name);
5310                 return (0);
5311 
5312         case EINVAL:
5313         default:
5314                 bad_error("entity_get_running_pg", r);
5315         }
5316 
5317         pgroup = internal_pgroup_new();
5318         if (pgroup == NULL)
5319                 return (ENOMEM);
5320 
5321         r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5322         switch (r) {
5323         case 0:
5324                 break;
5325 
5326         case ECONNABORTED:
5327         case EBADF:
5328         case ENOMEM:
5329                 internal_pgroup_free(pgroup);
5330                 return (r);
5331 
5332         case ECANCELED:
5333                 warn(emsg_dpt_no_dep, ient->sc_fmri,
5334                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5335                     new_dpt_pgroup->sc_pgroup_name);
5336                 internal_pgroup_free(pgroup);
5337                 return (0);
5338 
5339         case EACCES:
5340         default:
5341                 bad_error("load_pg", r);
5342         }
5343 
5344         /* report differences */
5345         report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5346         internal_pgroup_free(pgroup);
5347         return (0);
5348 }
5349 
5350 /*
5351  * lipg is a property group in the last-import snapshot of ent, which is an
5352  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5353  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5354  * in ents's property groups, compare and upgrade ent appropriately.
5355  *
5356  * Returns
5357  *   0 - success
5358  *   ECONNABORTED - repository connection broken
5359  *   ENOMEM - out of memory
5360  *   ENOSPC - configd is out of resources
5361  *   EINVAL - ient has invalid dependent (error printed)
5362  *          - ient has invalid pgroup_t (error printed)
5363  *   ECANCELED - ent has been deleted
5364  *   ENODEV - entity containing lipg has been deleted
5365  *          - entity containing running has been deleted
5366  *   EPERM - could not delete pg (permission denied) (error printed)
5367  *         - couldn't upgrade dependents (permission denied) (error printed)
5368  *         - couldn't import pg (permission denied) (error printed)
5369  *         - couldn't upgrade pg (permission denied) (error printed)
5370  *   EROFS - could not delete pg (repository read-only)
5371  *         - couldn't upgrade dependents (repository read-only)
5372  *         - couldn't import pg (repository read-only)
5373  *         - couldn't upgrade pg (repository read-only)
5374  *   EACCES - could not delete pg (backend access denied)
5375  *          - couldn't upgrade dependents (backend access denied)
5376  *          - couldn't import pg (backend access denied)
5377  *          - couldn't upgrade pg (backend access denied)
5378  *          - couldn't read property (backend access denied)
5379  *   EBUSY - property group was added (error printed)
5380  *         - property group was deleted (error printed)
5381  *         - property group changed (error printed)
5382  *         - "dependents" pg was added, changed, or deleted (error printed)
5383  *         - dependent target deleted (error printed)
5384  *         - dependent pg changed (error printed)
5385  *   EBADF - imp_snpl is corrupt (error printed)
5386  *         - ent has bad pg (error printed)
5387  *   EEXIST - dependent collision in target service (error printed)
5388  */
5389 static int
5390 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5391     const scf_snaplevel_t *running)
5392 {
5393         int r;
5394         pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5395         scf_callback_t cbdata;
5396 
5397         const char * const cf_pg_missing =
5398             gettext("Conflict upgrading %s (property group %s is missing)\n");
5399         const char * const deleting =
5400             gettext("%s: Deleting property group \"%s\".\n");
5401 
5402         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5403 
5404         /* Skip dependent property groups. */
5405         if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5406                 switch (scf_error()) {
5407                 case SCF_ERROR_DELETED:
5408                         return (ENODEV);
5409 
5410                 case SCF_ERROR_CONNECTION_BROKEN:
5411                         return (ECONNABORTED);
5412 
5413                 case SCF_ERROR_NOT_SET:
5414                 case SCF_ERROR_NOT_BOUND:
5415                 default:
5416                         bad_error("scf_pg_get_type", scf_error());
5417                 }
5418         }
5419 
5420         if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5421                 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5422                         return (0);
5423 
5424                 switch (scf_error()) {
5425                 case SCF_ERROR_NOT_FOUND:
5426                         break;
5427 
5428                 case SCF_ERROR_CONNECTION_BROKEN:
5429                         return (ECONNABORTED);
5430 
5431                 case SCF_ERROR_DELETED:
5432                         return (ENODEV);
5433 
5434                 case SCF_ERROR_INVALID_ARGUMENT:
5435                 case SCF_ERROR_NOT_BOUND:
5436                 case SCF_ERROR_HANDLE_MISMATCH:
5437                 case SCF_ERROR_NOT_SET:
5438                 default:
5439                         bad_error("scf_pg_get_property", scf_error());
5440                 }
5441         }
5442 
5443         /* lookup pg in new properties */
5444         if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5445                 switch (scf_error()) {
5446                 case SCF_ERROR_DELETED:
5447                         return (ENODEV);
5448 
5449                 case SCF_ERROR_CONNECTION_BROKEN:
5450                         return (ECONNABORTED);
5451 
5452                 case SCF_ERROR_NOT_SET:
5453                 case SCF_ERROR_NOT_BOUND:
5454                 default:
5455                         bad_error("scf_pg_get_name", scf_error());
5456                 }
5457         }
5458 
5459         pgrp.sc_pgroup_name = imp_str;
5460         mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5461 
5462         if (mpg != NULL)
5463                 mpg->sc_pgroup_seen = 1;
5464 
5465         /* Special handling for dependents */
5466         if (strcmp(imp_str, "dependents") == 0)
5467                 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5468 
5469         if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5470                 return (upgrade_manifestfiles(NULL, ient, running, ent));
5471 
5472         if (mpg == NULL || mpg->sc_pgroup_delete) {
5473                 /* property group was deleted from manifest */
5474                 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5475                         switch (scf_error()) {
5476                         case SCF_ERROR_NOT_FOUND:
5477                                 return (0);
5478 
5479                         case SCF_ERROR_DELETED:
5480                         case SCF_ERROR_CONNECTION_BROKEN:
5481                                 return (scferror2errno(scf_error()));
5482 
5483                         case SCF_ERROR_INVALID_ARGUMENT:
5484                         case SCF_ERROR_HANDLE_MISMATCH:
5485                         case SCF_ERROR_NOT_BOUND:
5486                         case SCF_ERROR_NOT_SET:
5487                         default:
5488                                 bad_error("entity_get_pg", scf_error());
5489                         }
5490                 }
5491 
5492                 if (mpg != NULL && mpg->sc_pgroup_delete) {
5493                         if (g_verbose)
5494                                 warn(deleting, ient->sc_fmri, imp_str);
5495                         if (scf_pg_delete(imp_pg2) == 0)
5496                                 return (0);
5497 
5498                         switch (scf_error()) {
5499                         case SCF_ERROR_DELETED:
5500                                 return (0);
5501 
5502                         case SCF_ERROR_CONNECTION_BROKEN:
5503                         case SCF_ERROR_BACKEND_READONLY:
5504                         case SCF_ERROR_BACKEND_ACCESS:
5505                                 return (scferror2errno(scf_error()));
5506 
5507                         case SCF_ERROR_PERMISSION_DENIED:
5508                                 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5509                                 return (scferror2errno(scf_error()));
5510 
5511                         case SCF_ERROR_NOT_SET:
5512                         default:
5513                                 bad_error("scf_pg_delete", scf_error());
5514                         }
5515                 }
5516 
5517                 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5518                 switch (r) {
5519                 case 0:
5520                         break;
5521 
5522                 case ECANCELED:
5523                         return (ENODEV);
5524 
5525                 case ECONNABORTED:
5526                 case ENOMEM:
5527                 case EBADF:
5528                 case EACCES:
5529                         return (r);
5530 
5531                 default:
5532                         bad_error("load_pg", r);
5533                 }
5534 
5535                 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5536                 switch (r) {
5537                 case 0:
5538                         break;
5539 
5540                 case ECANCELED:
5541                 case ECONNABORTED:
5542                 case ENOMEM:
5543                 case EBADF:
5544                 case EACCES:
5545                         internal_pgroup_free(lipg_i);
5546                         return (r);
5547 
5548                 default:
5549                         bad_error("load_pg", r);
5550                 }
5551 
5552                 if (pg_equal(lipg_i, curpg_i)) {
5553                         if (g_verbose)
5554                                 warn(deleting, ient->sc_fmri, imp_str);
5555                         if (scf_pg_delete(imp_pg2) != 0) {
5556                                 switch (scf_error()) {
5557                                 case SCF_ERROR_DELETED:
5558                                         break;
5559 
5560                                 case SCF_ERROR_CONNECTION_BROKEN:
5561                                         internal_pgroup_free(lipg_i);
5562                                         internal_pgroup_free(curpg_i);
5563                                         return (ECONNABORTED);
5564 
5565                                 case SCF_ERROR_NOT_SET:
5566                                 case SCF_ERROR_NOT_BOUND:
5567                                 default:
5568                                         bad_error("scf_pg_delete", scf_error());
5569                                 }
5570                         }
5571                 } else {
5572                         report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5573                 }
5574 
5575                 internal_pgroup_free(lipg_i);
5576                 internal_pgroup_free(curpg_i);
5577 
5578                 return (0);
5579         }
5580 
5581         /*
5582          * Only dependent pgs can have override set, and we skipped those
5583          * above.
5584          */
5585         assert(!mpg->sc_pgroup_override);
5586 
5587         /* compare */
5588         r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5589         switch (r) {
5590         case 0:
5591                 break;
5592 
5593         case ECANCELED:
5594                 return (ENODEV);
5595 
5596         case ECONNABORTED:
5597         case EBADF:
5598         case ENOMEM:
5599         case EACCES:
5600                 return (r);
5601 
5602         default:
5603                 bad_error("load_pg", r);
5604         }
5605 
5606         if (pg_equal(mpg, lipg_i)) {
5607                 /* The manifest pg has not changed.  Move on. */
5608                 r = 0;
5609                 goto out;
5610         }
5611 
5612         /* upgrade current properties according to lipg & mpg */
5613         if (running != NULL)
5614                 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5615         else
5616                 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5617         if (r != 0) {
5618                 switch (scf_error()) {
5619                 case SCF_ERROR_CONNECTION_BROKEN:
5620                         r = scferror2errno(scf_error());
5621                         goto out;
5622 
5623                 case SCF_ERROR_DELETED:
5624                         if (running != NULL)
5625                                 r = ENODEV;
5626                         else
5627                                 r = ECANCELED;
5628                         goto out;
5629 
5630                 case SCF_ERROR_NOT_FOUND:
5631                         break;
5632 
5633                 case SCF_ERROR_INVALID_ARGUMENT:
5634                 case SCF_ERROR_HANDLE_MISMATCH:
5635                 case SCF_ERROR_NOT_BOUND:
5636                 case SCF_ERROR_NOT_SET:
5637                 default:
5638                         bad_error("entity_get_pg", scf_error());
5639                 }
5640 
5641                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5642 
5643                 r = 0;
5644                 goto out;
5645         }
5646 
5647         r = load_pg_attrs(imp_pg2, &curpg_i);
5648         switch (r) {
5649         case 0:
5650                 break;
5651 
5652         case ECANCELED:
5653                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5654                 r = 0;
5655                 goto out;
5656 
5657         case ECONNABORTED:
5658         case ENOMEM:
5659                 goto out;
5660 
5661         default:
5662                 bad_error("load_pg_attrs", r);
5663         }
5664 
5665         if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5666                 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5667                 internal_pgroup_free(curpg_i);
5668                 r = 0;
5669                 goto out;
5670         }
5671 
5672         internal_pgroup_free(curpg_i);
5673 
5674         r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5675         switch (r) {
5676         case 0:
5677                 break;
5678 
5679         case ECANCELED:
5680                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5681                 r = 0;
5682                 goto out;
5683 
5684         case ECONNABORTED:
5685         case EBADF:
5686         case ENOMEM:
5687         case EACCES:
5688                 goto out;
5689 
5690         default:
5691                 bad_error("load_pg", r);
5692         }
5693 
5694         if (pg_equal(lipg_i, curpg_i) &&
5695             !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5696                 int do_delete = 1;
5697 
5698                 if (g_verbose)
5699                         warn(gettext("%s: Upgrading property group \"%s\".\n"),
5700                             ient->sc_fmri, mpg->sc_pgroup_name);
5701 
5702                 internal_pgroup_free(curpg_i);
5703 
5704                 if (running != NULL &&
5705                     entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5706                         switch (scf_error()) {
5707                         case SCF_ERROR_DELETED:
5708                                 r = ECANCELED;
5709                                 goto out;
5710 
5711                         case SCF_ERROR_NOT_FOUND:
5712                                 do_delete = 0;
5713                                 break;
5714 
5715                         case SCF_ERROR_CONNECTION_BROKEN:
5716                                 r = scferror2errno(scf_error());
5717                                 goto out;
5718 
5719                         case SCF_ERROR_HANDLE_MISMATCH:
5720                         case SCF_ERROR_INVALID_ARGUMENT:
5721                         case SCF_ERROR_NOT_SET:
5722                         case SCF_ERROR_NOT_BOUND:
5723                         default:
5724                                 bad_error("entity_get_pg", scf_error());
5725                         }
5726                 }
5727 
5728                 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5729                         switch (scf_error()) {
5730                         case SCF_ERROR_DELETED:
5731                                 break;
5732 
5733                         case SCF_ERROR_CONNECTION_BROKEN:
5734                         case SCF_ERROR_BACKEND_READONLY:
5735                         case SCF_ERROR_BACKEND_ACCESS:
5736                                 r = scferror2errno(scf_error());
5737                                 goto out;
5738 
5739                         case SCF_ERROR_PERMISSION_DENIED:
5740                                 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5741                                     ient->sc_fmri);
5742                                 r = scferror2errno(scf_error());
5743                                 goto out;
5744 
5745                         case SCF_ERROR_NOT_SET:
5746                         case SCF_ERROR_NOT_BOUND:
5747                         default:
5748                                 bad_error("scf_pg_delete", scf_error());
5749                         }
5750                 }
5751 
5752                 cbdata.sc_handle = g_hndl;
5753                 cbdata.sc_parent = ent;
5754                 cbdata.sc_service = issvc;
5755                 cbdata.sc_flags = 0;
5756                 cbdata.sc_source_fmri = ient->sc_fmri;
5757                 cbdata.sc_target_fmri = ient->sc_fmri;
5758 
5759                 r = entity_pgroup_import(mpg, &cbdata);
5760                 switch (r) {
5761                 case UU_WALK_NEXT:
5762                         r = 0;
5763                         goto out;
5764 
5765                 case UU_WALK_ERROR:
5766                         if (cbdata.sc_err == EEXIST) {
5767                                 warn(emsg_pg_added, ient->sc_fmri,
5768                                     mpg->sc_pgroup_name);
5769                                 r = EBUSY;
5770                         } else {
5771                                 r = cbdata.sc_err;
5772                         }
5773                         goto out;
5774 
5775                 default:
5776                         bad_error("entity_pgroup_import", r);
5777                 }
5778         }
5779 
5780         if (running != NULL &&
5781             entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5782                 switch (scf_error()) {
5783                 case SCF_ERROR_CONNECTION_BROKEN:
5784                 case SCF_ERROR_DELETED:
5785                         r = scferror2errno(scf_error());
5786                         goto out;
5787 
5788                 case SCF_ERROR_NOT_FOUND:
5789                         break;
5790 
5791                 case SCF_ERROR_HANDLE_MISMATCH:
5792                 case SCF_ERROR_INVALID_ARGUMENT:
5793                 case SCF_ERROR_NOT_SET:
5794                 case SCF_ERROR_NOT_BOUND:
5795                 default:
5796                         bad_error("entity_get_pg", scf_error());
5797                 }
5798 
5799                 cbdata.sc_handle = g_hndl;
5800                 cbdata.sc_parent = ent;
5801                 cbdata.sc_service = issvc;
5802                 cbdata.sc_flags = SCI_FORCE;
5803                 cbdata.sc_source_fmri = ient->sc_fmri;
5804                 cbdata.sc_target_fmri = ient->sc_fmri;
5805 
5806                 r = entity_pgroup_import(mpg, &cbdata);
5807                 switch (r) {
5808                 case UU_WALK_NEXT:
5809                         r = 0;
5810                         goto out;
5811 
5812                 case UU_WALK_ERROR:
5813                         if (cbdata.sc_err == EEXIST) {
5814                                 warn(emsg_pg_added, ient->sc_fmri,
5815                                     mpg->sc_pgroup_name);
5816                                 r = EBUSY;
5817                         } else {
5818                                 r = cbdata.sc_err;
5819                         }
5820                         goto out;
5821 
5822                 default:
5823                         bad_error("entity_pgroup_import", r);
5824                 }
5825         }
5826 
5827         r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5828         internal_pgroup_free(curpg_i);
5829         switch (r) {
5830         case 0:
5831                 ient->sc_import_state = IMPORT_PROP_BEGUN;
5832                 break;
5833 
5834         case ECANCELED:
5835                 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5836                 r = EBUSY;
5837                 break;
5838 
5839         case EPERM:
5840                 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5841                 break;
5842 
5843         case EBUSY:
5844                 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5845                 break;
5846 
5847         case ECONNABORTED:
5848         case ENOMEM:
5849         case ENOSPC:
5850         case EROFS:
5851         case EACCES:
5852         case EINVAL:
5853                 break;
5854 
5855         default:
5856                 bad_error("upgrade_pg", r);
5857         }
5858 
5859 out:
5860         internal_pgroup_free(lipg_i);
5861         return (r);
5862 }
5863 
5864 /*
5865  * Upgrade the properties of ent according to snpl & ient.
5866  *
5867  * Returns
5868  *   0 - success
5869  *   ECONNABORTED - repository connection broken
5870  *   ENOMEM - out of memory
5871  *   ENOSPC - configd is out of resources
5872  *   ECANCELED - ent was deleted
5873  *   ENODEV - entity containing snpl was deleted
5874  *          - entity containing running was deleted
5875  *   EBADF - imp_snpl is corrupt (error printed)
5876  *         - ent has corrupt pg (error printed)
5877  *         - dependent has corrupt pg (error printed)
5878  *         - dependent target has a corrupt snapshot (error printed)
5879  *   EBUSY - pg was added, changed, or deleted (error printed)
5880  *         - dependent target was deleted (error printed)
5881  *         - dependent pg changed (error printed)
5882  *   EINVAL - invalid property group name (error printed)
5883  *          - invalid property name (error printed)
5884  *          - invalid value (error printed)
5885  *          - ient has invalid pgroup or dependent (error printed)
5886  *   EPERM - could not create property group (permission denied) (error printed)
5887  *         - could not modify property group (permission denied) (error printed)
5888  *         - couldn't delete, upgrade, or import pg or dependent (error printed)
5889  *   EROFS - could not create property group (repository read-only)
5890  *         - couldn't delete, upgrade, or import pg or dependent
5891  *   EACCES - could not create property group (backend access denied)
5892  *          - couldn't delete, upgrade, or import pg or dependent
5893  *   EEXIST - dependent collision in target service (error printed)
5894  */
5895 static int
5896 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5897     entity_t *ient)
5898 {
5899         pgroup_t *pg, *rpg;
5900         int r;
5901         uu_list_t *pgs = ient->sc_pgroups;
5902 
5903         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5904 
5905         /* clear sc_sceen for pgs */
5906         if (uu_list_walk(pgs, clear_int,
5907             (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5908                 bad_error("uu_list_walk", uu_error());
5909 
5910         if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5911                 switch (scf_error()) {
5912                 case SCF_ERROR_DELETED:
5913                         return (ENODEV);
5914 
5915                 case SCF_ERROR_CONNECTION_BROKEN:
5916                         return (ECONNABORTED);
5917 
5918                 case SCF_ERROR_NOT_SET:
5919                 case SCF_ERROR_NOT_BOUND:
5920                 case SCF_ERROR_HANDLE_MISMATCH:
5921                 default:
5922                         bad_error("scf_iter_snaplevel_pgs", scf_error());
5923                 }
5924         }
5925 
5926         for (;;) {
5927                 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5928                 if (r == 0)
5929                         break;
5930                 if (r == 1) {
5931                         r = process_old_pg(imp_pg, ient, ent, running);
5932                         switch (r) {
5933                         case 0:
5934                                 break;
5935 
5936                         case ECONNABORTED:
5937                         case ENOMEM:
5938                         case ENOSPC:
5939                         case ECANCELED:
5940                         case ENODEV:
5941                         case EPERM:
5942                         case EROFS:
5943                         case EACCES:
5944                         case EBADF:
5945                         case EBUSY:
5946                         case EINVAL:
5947                         case EEXIST:
5948                                 return (r);
5949 
5950                         default:
5951                                 bad_error("process_old_pg", r);
5952                         }
5953                         continue;
5954                 }
5955                 if (r != -1)
5956                         bad_error("scf_iter_next_pg", r);
5957 
5958                 switch (scf_error()) {
5959                 case SCF_ERROR_DELETED:
5960                         return (ENODEV);
5961 
5962                 case SCF_ERROR_CONNECTION_BROKEN:
5963                         return (ECONNABORTED);
5964 
5965                 case SCF_ERROR_HANDLE_MISMATCH:
5966                 case SCF_ERROR_NOT_BOUND:
5967                 case SCF_ERROR_NOT_SET:
5968                 case SCF_ERROR_INVALID_ARGUMENT:
5969                 default:
5970                         bad_error("scf_iter_next_pg", scf_error());
5971                 }
5972         }
5973 
5974         for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5975                 if (pg->sc_pgroup_seen)
5976                         continue;
5977 
5978                 /* pg is new */
5979 
5980                 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5981                         r = upgrade_dependents(NULL, imp_snpl, ient, running,
5982                             ent);
5983                         switch (r) {
5984                         case 0:
5985                                 break;
5986 
5987                         case ECONNABORTED:
5988                         case ENOMEM:
5989                         case ENOSPC:
5990                         case ECANCELED:
5991                         case ENODEV:
5992                         case EBADF:
5993                         case EBUSY:
5994                         case EINVAL:
5995                         case EPERM:
5996                         case EROFS:
5997                         case EACCES:
5998                         case EEXIST:
5999                                 return (r);
6000 
6001                         default:
6002                                 bad_error("upgrade_dependents", r);
6003                         }
6004                         continue;
6005                 }
6006 
6007                 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6008                         r = upgrade_manifestfiles(pg, ient, running, ent);
6009                         switch (r) {
6010                         case 0:
6011                                 break;
6012 
6013                         case ECONNABORTED:
6014                         case ENOMEM:
6015                         case ENOSPC:
6016                         case ECANCELED:
6017                         case ENODEV:
6018                         case EBADF:
6019                         case EBUSY:
6020                         case EINVAL:
6021                         case EPERM:
6022                         case EROFS:
6023                         case EACCES:
6024                         case EEXIST:
6025                                 return (r);
6026 
6027                         default:
6028                                 bad_error("upgrade_manifestfiles", r);
6029                         }
6030                         continue;
6031                 }
6032 
6033                 if (running != NULL) {
6034                         r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6035                             imp_pg);
6036                 } else {
6037                         r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6038                             imp_pg);
6039                 }
6040                 if (r != 0) {
6041                         scf_callback_t cbdata;
6042 
6043                         switch (scf_error()) {
6044                         case SCF_ERROR_NOT_FOUND:
6045                                 break;
6046 
6047                         case SCF_ERROR_CONNECTION_BROKEN:
6048                                 return (scferror2errno(scf_error()));
6049 
6050                         case SCF_ERROR_DELETED:
6051                                 if (running != NULL)
6052                                         return (ENODEV);
6053                                 else
6054                                         return (scferror2errno(scf_error()));
6055 
6056                         case SCF_ERROR_INVALID_ARGUMENT:
6057                                 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6058                                     pg->sc_pgroup_name);
6059                                 return (EINVAL);
6060 
6061                         case SCF_ERROR_NOT_SET:
6062                         case SCF_ERROR_HANDLE_MISMATCH:
6063                         case SCF_ERROR_NOT_BOUND:
6064                         default:
6065                                 bad_error("entity_get_pg", scf_error());
6066                         }
6067 
6068                         /* User doesn't have pg, so import it. */
6069 
6070                         cbdata.sc_handle = g_hndl;
6071                         cbdata.sc_parent = ent;
6072                         cbdata.sc_service = issvc;
6073                         cbdata.sc_flags = SCI_FORCE;
6074                         cbdata.sc_source_fmri = ient->sc_fmri;
6075                         cbdata.sc_target_fmri = ient->sc_fmri;
6076 
6077                         r = entity_pgroup_import(pg, &cbdata);
6078                         switch (r) {
6079                         case UU_WALK_NEXT:
6080                                 ient->sc_import_state = IMPORT_PROP_BEGUN;
6081                                 continue;
6082 
6083                         case UU_WALK_ERROR:
6084                                 if (cbdata.sc_err == EEXIST) {
6085                                         warn(emsg_pg_added, ient->sc_fmri,
6086                                             pg->sc_pgroup_name);
6087                                         return (EBUSY);
6088                                 }
6089                                 return (cbdata.sc_err);
6090 
6091                         default:
6092                                 bad_error("entity_pgroup_import", r);
6093                         }
6094                 }
6095 
6096                 /* report differences between pg & current */
6097                 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6098                 switch (r) {
6099                 case 0:
6100                         break;
6101 
6102                 case ECANCELED:
6103                         warn(emsg_pg_deleted, ient->sc_fmri,
6104                             pg->sc_pgroup_name);
6105                         return (EBUSY);
6106 
6107                 case ECONNABORTED:
6108                 case EBADF:
6109                 case ENOMEM:
6110                 case EACCES:
6111                         return (r);
6112 
6113                 default:
6114                         bad_error("load_pg", r);
6115                 }
6116                 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6117                 internal_pgroup_free(rpg);
6118                 rpg = NULL;
6119         }
6120 
6121         return (0);
6122 }
6123 
6124 /*
6125  * Import an instance.  If it doesn't exist, create it.  If it has
6126  * a last-import snapshot, upgrade its properties.  Finish by updating its
6127  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6128  * could have been created for a dependent tag in another manifest.  Import the
6129  * new properties.  If there's a conflict, don't override, like now?
6130  *
6131  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6132  * lcbdata->sc_err to
6133  *   ECONNABORTED - repository connection broken
6134  *   ENOMEM - out of memory
6135  *   ENOSPC - svc.configd is out of resources
6136  *   EEXIST - dependency collision in dependent service (error printed)
6137  *   EPERM - couldn't create temporary instance (permission denied)
6138  *         - couldn't import into temporary instance (permission denied)
6139  *         - couldn't take snapshot (permission denied)
6140  *         - couldn't upgrade properties (permission denied)
6141  *         - couldn't import properties (permission denied)
6142  *         - couldn't import dependents (permission denied)
6143  *   EROFS - couldn't create temporary instance (repository read-only)
6144  *         - couldn't import into temporary instance (repository read-only)
6145  *         - couldn't upgrade properties (repository read-only)
6146  *         - couldn't import properties (repository read-only)
6147  *         - couldn't import dependents (repository read-only)
6148  *   EACCES - couldn't create temporary instance (backend access denied)
6149  *          - couldn't import into temporary instance (backend access denied)
6150  *          - couldn't upgrade properties (backend access denied)
6151  *          - couldn't import properties (backend access denied)
6152  *          - couldn't import dependents (backend access denied)
6153  *   EINVAL - invalid instance name (error printed)
6154  *          - invalid pgroup_t's (error printed)
6155  *          - invalid dependents (error printed)
6156  *   EBUSY - temporary service deleted (error printed)
6157  *         - temporary instance deleted (error printed)
6158  *         - temporary instance changed (error printed)
6159  *         - temporary instance already exists (error printed)
6160  *         - instance deleted (error printed)
6161  *   EBADF - instance has corrupt last-import snapshot (error printed)
6162  *         - instance is corrupt (error printed)
6163  *         - dependent has corrupt pg (error printed)
6164  *         - dependent target has a corrupt snapshot (error printed)
6165  *   -1 - unknown libscf error (error printed)
6166  */
6167 static int
6168 lscf_instance_import(void *v, void *pvt)
6169 {
6170         entity_t *inst = v;
6171         scf_callback_t ctx;
6172         scf_callback_t *lcbdata = pvt;
6173         scf_service_t *rsvc = lcbdata->sc_parent;
6174         int r;
6175         scf_snaplevel_t *running;
6176         int flags = lcbdata->sc_flags;
6177 
6178         const char * const emsg_tdel =
6179             gettext("Temporary instance svc:/%s:%s was deleted.\n");
6180         const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6181             "changed unexpectedly.\n");
6182         const char * const emsg_del = gettext("%s changed unexpectedly "
6183             "(instance \"%s\" was deleted.)\n");
6184         const char * const emsg_badsnap = gettext(
6185             "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6186 
6187         /*
6188          * prepare last-import snapshot:
6189          * create temporary instance (service was precreated)
6190          * populate with properties from bundle
6191          * take snapshot
6192          */
6193         if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6194                 switch (scf_error()) {
6195                 case SCF_ERROR_CONNECTION_BROKEN:
6196                 case SCF_ERROR_NO_RESOURCES:
6197                 case SCF_ERROR_BACKEND_READONLY:
6198                 case SCF_ERROR_BACKEND_ACCESS:
6199                         return (stash_scferror(lcbdata));
6200 
6201                 case SCF_ERROR_EXISTS:
6202                         warn(gettext("Temporary service svc:/%s "
6203                             "changed unexpectedly (instance \"%s\" added).\n"),
6204                             imp_tsname, inst->sc_name);
6205                         lcbdata->sc_err = EBUSY;
6206                         return (UU_WALK_ERROR);
6207 
6208                 case SCF_ERROR_DELETED:
6209                         warn(gettext("Temporary service svc:/%s "
6210                             "was deleted unexpectedly.\n"), imp_tsname);
6211                         lcbdata->sc_err = EBUSY;
6212                         return (UU_WALK_ERROR);
6213 
6214                 case SCF_ERROR_INVALID_ARGUMENT:
6215                         warn(gettext("Invalid instance name \"%s\".\n"),
6216                             inst->sc_name);
6217                         return (stash_scferror(lcbdata));
6218 
6219                 case SCF_ERROR_PERMISSION_DENIED:
6220                         warn(gettext("Could not create temporary instance "
6221                             "\"%s\" in svc:/%s (permission denied).\n"),
6222                             inst->sc_name, imp_tsname);
6223                         return (stash_scferror(lcbdata));
6224 
6225                 case SCF_ERROR_HANDLE_MISMATCH:
6226                 case SCF_ERROR_NOT_BOUND:
6227                 case SCF_ERROR_NOT_SET:
6228                 default:
6229                         bad_error("scf_service_add_instance", scf_error());
6230                 }
6231         }
6232 
6233         r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6234             inst->sc_name);
6235         if (r < 0)
6236                 bad_error("snprintf", errno);
6237 
6238         r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6239             lcbdata->sc_flags | SCI_NOENABLED);
6240         switch (r) {
6241         case 0:
6242                 break;
6243 
6244         case ECANCELED:
6245                 warn(emsg_tdel, imp_tsname, inst->sc_name);
6246                 lcbdata->sc_err = EBUSY;
6247                 r = UU_WALK_ERROR;
6248                 goto deltemp;
6249 
6250         case EEXIST:
6251                 warn(emsg_tchg, imp_tsname, inst->sc_name);
6252                 lcbdata->sc_err = EBUSY;
6253                 r = UU_WALK_ERROR;
6254                 goto deltemp;
6255 
6256         case ECONNABORTED:
6257                 goto connaborted;
6258 
6259         case ENOMEM:
6260         case ENOSPC:
6261         case EPERM:
6262         case EROFS:
6263         case EACCES:
6264         case EINVAL:
6265         case EBUSY:
6266                 lcbdata->sc_err = r;
6267                 r = UU_WALK_ERROR;
6268                 goto deltemp;
6269 
6270         default:
6271                 bad_error("lscf_import_instance_pgs", r);
6272         }
6273 
6274         r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6275             inst->sc_name);
6276         if (r < 0)
6277                 bad_error("snprintf", errno);
6278 
6279         ctx.sc_handle = lcbdata->sc_handle;
6280         ctx.sc_parent = imp_tinst;
6281         ctx.sc_service = 0;
6282         ctx.sc_source_fmri = inst->sc_fmri;
6283         ctx.sc_target_fmri = imp_str;
6284         if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6285             UU_DEFAULT) != 0) {
6286                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6287                         bad_error("uu_list_walk", uu_error());
6288 
6289                 switch (ctx.sc_err) {
6290                 case ECONNABORTED:
6291                         goto connaborted;
6292 
6293                 case ECANCELED:
6294                         warn(emsg_tdel, imp_tsname, inst->sc_name);
6295                         lcbdata->sc_err = EBUSY;
6296                         break;
6297 
6298                 case EEXIST:
6299                         warn(emsg_tchg, imp_tsname, inst->sc_name);
6300                         lcbdata->sc_err = EBUSY;
6301                         break;
6302 
6303                 default:
6304                         lcbdata->sc_err = ctx.sc_err;
6305                 }
6306                 r = UU_WALK_ERROR;
6307                 goto deltemp;
6308         }
6309 
6310         if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6311             inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6312                 switch (scf_error()) {
6313                 case SCF_ERROR_CONNECTION_BROKEN:
6314                         goto connaborted;
6315 
6316                 case SCF_ERROR_NO_RESOURCES:
6317                         r = stash_scferror(lcbdata);
6318                         goto deltemp;
6319 
6320                 case SCF_ERROR_EXISTS:
6321                         warn(emsg_tchg, imp_tsname, inst->sc_name);
6322                         lcbdata->sc_err = EBUSY;
6323                         r = UU_WALK_ERROR;
6324                         goto deltemp;
6325 
6326                 case SCF_ERROR_PERMISSION_DENIED:
6327                         warn(gettext("Could not take \"%s\" snapshot of %s "
6328                             "(permission denied).\n"), snap_lastimport,
6329                             imp_str);
6330                         r = stash_scferror(lcbdata);
6331                         goto deltemp;
6332 
6333                 default:
6334                         scfwarn();
6335                         lcbdata->sc_err = -1;
6336                         r = UU_WALK_ERROR;
6337                         goto deltemp;
6338 
6339                 case SCF_ERROR_HANDLE_MISMATCH:
6340                 case SCF_ERROR_INVALID_ARGUMENT:
6341                 case SCF_ERROR_NOT_SET:
6342                         bad_error("_scf_snapshot_take_new_named", scf_error());
6343                 }
6344         }
6345 
6346         if (lcbdata->sc_flags & SCI_FRESH)
6347                 goto fresh;
6348 
6349         if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6350                 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6351                     imp_lisnap) != 0) {
6352                         switch (scf_error()) {
6353                         case SCF_ERROR_DELETED:
6354                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6355                                     inst->sc_name);
6356                                 lcbdata->sc_err = EBUSY;
6357                                 r = UU_WALK_ERROR;
6358                                 goto deltemp;
6359 
6360                         case SCF_ERROR_NOT_FOUND:
6361                                 flags |= SCI_FORCE;
6362                                 goto nosnap;
6363 
6364                         case SCF_ERROR_CONNECTION_BROKEN:
6365                                 goto connaborted;
6366 
6367                         case SCF_ERROR_INVALID_ARGUMENT:
6368                         case SCF_ERROR_HANDLE_MISMATCH:
6369                         case SCF_ERROR_NOT_BOUND:
6370                         case SCF_ERROR_NOT_SET:
6371                         default:
6372                                 bad_error("scf_instance_get_snapshot",
6373                                     scf_error());
6374                         }
6375                 }
6376 
6377                 /* upgrade */
6378 
6379                 /*
6380                  * compare new properties with last-import properties
6381                  * upgrade current properties
6382                  */
6383                 /* clear sc_sceen for pgs */
6384                 if (uu_list_walk(inst->sc_pgroups, clear_int,
6385                     (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6386                     0)
6387                         bad_error("uu_list_walk", uu_error());
6388 
6389                 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6390                 switch (r) {
6391                 case 0:
6392                         break;
6393 
6394                 case ECONNABORTED:
6395                         goto connaborted;
6396 
6397                 case ECANCELED:
6398                         warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6399                         lcbdata->sc_err = EBUSY;
6400                         r = UU_WALK_ERROR;
6401                         goto deltemp;
6402 
6403                 case ENOENT:
6404                         warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6405                         lcbdata->sc_err = EBADF;
6406                         r = UU_WALK_ERROR;
6407                         goto deltemp;
6408 
6409                 default:
6410                         bad_error("get_snaplevel", r);
6411                 }
6412 
6413                 if (scf_instance_get_snapshot(imp_inst, snap_running,
6414                     imp_rsnap) != 0) {
6415                         switch (scf_error()) {
6416                         case SCF_ERROR_DELETED:
6417                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6418                                     inst->sc_name);
6419                                 lcbdata->sc_err = EBUSY;
6420                                 r = UU_WALK_ERROR;
6421                                 goto deltemp;
6422 
6423                         case SCF_ERROR_NOT_FOUND:
6424                                 break;
6425 
6426                         case SCF_ERROR_CONNECTION_BROKEN:
6427                                 goto connaborted;
6428 
6429                         case SCF_ERROR_INVALID_ARGUMENT:
6430                         case SCF_ERROR_HANDLE_MISMATCH:
6431                         case SCF_ERROR_NOT_BOUND:
6432                         case SCF_ERROR_NOT_SET:
6433                         default:
6434                                 bad_error("scf_instance_get_snapshot",
6435                                     scf_error());
6436                         }
6437 
6438                         running = NULL;
6439                 } else {
6440                         r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6441                         switch (r) {
6442                         case 0:
6443                                 running = imp_rsnpl;
6444                                 break;
6445 
6446                         case ECONNABORTED:
6447                                 goto connaborted;
6448 
6449                         case ECANCELED:
6450                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6451                                     inst->sc_name);
6452                                 lcbdata->sc_err = EBUSY;
6453                                 r = UU_WALK_ERROR;
6454                                 goto deltemp;
6455 
6456                         case ENOENT:
6457                                 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6458                                 lcbdata->sc_err = EBADF;
6459                                 r = UU_WALK_ERROR;
6460                                 goto deltemp;
6461 
6462                         default:
6463                                 bad_error("get_snaplevel", r);
6464                         }
6465                 }
6466 
6467                 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6468                 switch (r) {
6469                 case 0:
6470                         break;
6471 
6472                 case ECANCELED:
6473                 case ENODEV:
6474                         warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6475                         lcbdata->sc_err = EBUSY;
6476                         r = UU_WALK_ERROR;
6477                         goto deltemp;
6478 
6479                 case ECONNABORTED:
6480                         goto connaborted;
6481 
6482                 case ENOMEM:
6483                 case ENOSPC:
6484                 case EBADF:
6485                 case EBUSY:
6486                 case EINVAL:
6487                 case EPERM:
6488                 case EROFS:
6489                 case EACCES:
6490                 case EEXIST:
6491                         lcbdata->sc_err = r;
6492                         r = UU_WALK_ERROR;
6493                         goto deltemp;
6494 
6495                 default:
6496                         bad_error("upgrade_props", r);
6497                 }
6498 
6499                 inst->sc_import_state = IMPORT_PROP_DONE;
6500         } else {
6501                 switch (scf_error()) {
6502                 case SCF_ERROR_CONNECTION_BROKEN:
6503                         goto connaborted;
6504 
6505                 case SCF_ERROR_NOT_FOUND:
6506                         break;
6507 
6508                 case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
6509                 case SCF_ERROR_HANDLE_MISMATCH:
6510                 case SCF_ERROR_NOT_BOUND:
6511                 case SCF_ERROR_NOT_SET:
6512                 default:
6513                         bad_error("scf_service_get_instance", scf_error());
6514                 }
6515 
6516 fresh:
6517                 /* create instance */
6518                 if (scf_service_add_instance(rsvc, inst->sc_name,
6519                     imp_inst) != 0) {
6520                         switch (scf_error()) {
6521                         case SCF_ERROR_CONNECTION_BROKEN:
6522                                 goto connaborted;
6523 
6524                         case SCF_ERROR_NO_RESOURCES:
6525                         case SCF_ERROR_BACKEND_READONLY:
6526                         case SCF_ERROR_BACKEND_ACCESS:
6527                                 r = stash_scferror(lcbdata);
6528                                 goto deltemp;
6529 
6530                         case SCF_ERROR_EXISTS:
6531                                 warn(gettext("%s changed unexpectedly "
6532                                     "(instance \"%s\" added).\n"),
6533                                     inst->sc_parent->sc_fmri, inst->sc_name);
6534                                 lcbdata->sc_err = EBUSY;
6535                                 r = UU_WALK_ERROR;
6536                                 goto deltemp;
6537 
6538                         case SCF_ERROR_PERMISSION_DENIED:
6539                                 warn(gettext("Could not create \"%s\" instance "
6540                                     "in %s (permission denied).\n"),
6541                                     inst->sc_name, inst->sc_parent->sc_fmri);
6542                                 r = stash_scferror(lcbdata);
6543                                 goto deltemp;
6544 
6545                         case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6546                         case SCF_ERROR_HANDLE_MISMATCH:
6547                         case SCF_ERROR_NOT_BOUND:
6548                         case SCF_ERROR_NOT_SET:
6549                         default:
6550                                 bad_error("scf_service_add_instance",
6551                                     scf_error());
6552                         }
6553                 }
6554 
6555 nosnap:
6556                 /*
6557                  * Create a last-import snapshot to serve as an attachment
6558                  * point for the real one from the temporary instance.  Since
6559                  * the contents is irrelevant, take it now, while the instance
6560                  * is empty, to minimize svc.configd's work.
6561                  */
6562                 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6563                     imp_lisnap) != 0) {
6564                         switch (scf_error()) {
6565                         case SCF_ERROR_CONNECTION_BROKEN:
6566                                 goto connaborted;
6567 
6568                         case SCF_ERROR_NO_RESOURCES:
6569                                 r = stash_scferror(lcbdata);
6570                                 goto deltemp;
6571 
6572                         case SCF_ERROR_EXISTS:
6573                                 warn(gettext("%s changed unexpectedly "
6574                                     "(snapshot \"%s\" added).\n"),
6575                                     inst->sc_fmri, snap_lastimport);
6576                                 lcbdata->sc_err = EBUSY;
6577                                 r = UU_WALK_ERROR;
6578                                 goto deltemp;
6579 
6580                         case SCF_ERROR_PERMISSION_DENIED:
6581                                 warn(gettext("Could not take \"%s\" snapshot "
6582                                     "of %s (permission denied).\n"),
6583                                     snap_lastimport, inst->sc_fmri);
6584                                 r = stash_scferror(lcbdata);
6585                                 goto deltemp;
6586 
6587                         default:
6588                                 scfwarn();
6589                                 lcbdata->sc_err = -1;
6590                                 r = UU_WALK_ERROR;
6591                                 goto deltemp;
6592 
6593                         case SCF_ERROR_NOT_SET:
6594                         case SCF_ERROR_INTERNAL:
6595                         case SCF_ERROR_INVALID_ARGUMENT:
6596                         case SCF_ERROR_HANDLE_MISMATCH:
6597                                 bad_error("_scf_snapshot_take_new",
6598                                     scf_error());
6599                         }
6600                 }
6601 
6602                 if (li_only)
6603                         goto lionly;
6604 
6605                 inst->sc_import_state = IMPORT_PROP_BEGUN;
6606 
6607                 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6608                     flags);
6609                 switch (r) {
6610                 case 0:
6611                         break;
6612 
6613                 case ECONNABORTED:
6614                         goto connaborted;
6615 
6616                 case ECANCELED:
6617                         warn(gettext("%s changed unexpectedly "
6618                             "(instance \"%s\" deleted).\n"),
6619                             inst->sc_parent->sc_fmri, inst->sc_name);
6620                         lcbdata->sc_err = EBUSY;
6621                         r = UU_WALK_ERROR;
6622                         goto deltemp;
6623 
6624                 case EEXIST:
6625                         warn(gettext("%s changed unexpectedly "
6626                             "(property group added).\n"), inst->sc_fmri);
6627                         lcbdata->sc_err = EBUSY;
6628                         r = UU_WALK_ERROR;
6629                         goto deltemp;
6630 
6631                 default:
6632                         lcbdata->sc_err = r;
6633                         r = UU_WALK_ERROR;
6634                         goto deltemp;
6635 
6636                 case EINVAL:    /* caught above */
6637                         bad_error("lscf_import_instance_pgs", r);
6638                 }
6639 
6640                 ctx.sc_parent = imp_inst;
6641                 ctx.sc_service = 0;
6642                 ctx.sc_trans = NULL;
6643                 ctx.sc_flags = 0;
6644                 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6645                     &ctx, UU_DEFAULT) != 0) {
6646                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6647                                 bad_error("uu_list_walk", uu_error());
6648 
6649                         if (ctx.sc_err == ECONNABORTED)
6650                                 goto connaborted;
6651                         lcbdata->sc_err = ctx.sc_err;
6652                         r = UU_WALK_ERROR;
6653                         goto deltemp;
6654                 }
6655 
6656                 inst->sc_import_state = IMPORT_PROP_DONE;
6657 
6658                 if (g_verbose)
6659                         warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6660                             snap_initial, inst->sc_fmri);
6661                 r = take_snap(imp_inst, snap_initial, imp_snap);
6662                 switch (r) {
6663                 case 0:
6664                         break;
6665 
6666                 case ECONNABORTED:
6667                         goto connaborted;
6668 
6669                 case ENOSPC:
6670                 case -1:
6671                         lcbdata->sc_err = r;
6672                         r = UU_WALK_ERROR;
6673                         goto deltemp;
6674 
6675                 case ECANCELED:
6676                         warn(gettext("%s changed unexpectedly "
6677                             "(instance %s deleted).\n"),
6678                             inst->sc_parent->sc_fmri, inst->sc_name);
6679                         lcbdata->sc_err = r;
6680                         r = UU_WALK_ERROR;
6681                         goto deltemp;
6682 
6683                 case EPERM:
6684                         warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6685                         lcbdata->sc_err = r;
6686                         r = UU_WALK_ERROR;
6687                         goto deltemp;
6688 
6689                 default:
6690                         bad_error("take_snap", r);
6691                 }
6692         }
6693 
6694 lionly:
6695         if (lcbdata->sc_flags & SCI_NOSNAP)
6696                 goto deltemp;
6697 
6698         /* transfer snapshot from temporary instance */
6699         if (g_verbose)
6700                 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6701                     snap_lastimport, inst->sc_fmri);
6702         if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6703                 switch (scf_error()) {
6704                 case SCF_ERROR_CONNECTION_BROKEN:
6705                         goto connaborted;
6706 
6707                 case SCF_ERROR_NO_RESOURCES:
6708                         r = stash_scferror(lcbdata);
6709                         goto deltemp;
6710 
6711                 case SCF_ERROR_PERMISSION_DENIED:
6712                         warn(gettext("Could not take \"%s\" snapshot for %s "
6713                             "(permission denied).\n"), snap_lastimport,
6714                             inst->sc_fmri);
6715                         r = stash_scferror(lcbdata);
6716                         goto deltemp;
6717 
6718                 case SCF_ERROR_NOT_SET:
6719                 case SCF_ERROR_HANDLE_MISMATCH:
6720                 default:
6721                         bad_error("_scf_snapshot_attach", scf_error());
6722                 }
6723         }
6724 
6725         inst->sc_import_state = IMPORT_COMPLETE;
6726 
6727         r = UU_WALK_NEXT;
6728 
6729 deltemp:
6730         /* delete temporary instance */
6731         if (scf_instance_delete(imp_tinst) != 0) {
6732                 switch (scf_error()) {
6733                 case SCF_ERROR_DELETED:
6734                         break;
6735 
6736                 case SCF_ERROR_CONNECTION_BROKEN:
6737                         goto connaborted;
6738 
6739                 case SCF_ERROR_NOT_SET:
6740                 case SCF_ERROR_NOT_BOUND:
6741                 default:
6742                         bad_error("scf_instance_delete", scf_error());
6743                 }
6744         }
6745 
6746         return (r);
6747 
6748 connaborted:
6749         warn(gettext("Could not delete svc:/%s:%s "
6750             "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6751         lcbdata->sc_err = ECONNABORTED;
6752         return (UU_WALK_ERROR);
6753 }
6754 
6755 /*
6756  * When an instance is imported we end up telling configd about it. Once we tell
6757  * configd about these changes, startd eventually notices. If this is a new
6758  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6759  * property group. However, many of the other tools expect that this property
6760  * group exists and has certain values.
6761  *
6762  * These values are added asynchronously by startd. We should not return from
6763  * this routine until we can verify that the property group we need is there.
6764  *
6765  * Before we go ahead and verify this, we have to ask ourselves an important
6766  * question: Is the early manifest service currently running?  Because if it is
6767  * running and it has invoked us, then the service will never get a restarter
6768  * property because svc.startd is blocked on EMI finishing before it lets itself
6769  * fully connect to svc.configd. Of course, this means that this race condition
6770  * is in fact impossible to 100% eliminate.
6771  *
6772  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6773  * the state of the EMI instance. If it is online it bails out and makes sure
6774  * that it doesn't run again. In this case, we're going to do something similar,
6775  * only if the state is online, then we're going to actually verify. EMI always
6776  * has to be present, but it can be explicitly disabled to reduce the amount of
6777  * damage it can cause. If EMI has been disabled then we no longer have to worry
6778  * about the implicit race condition and can go ahead and check things. If EMI
6779  * is in some state that isn't online or disabled and isn't runinng, then we
6780  * assume that things are rather bad and we're not going to get in your way,
6781  * even if the rest of SMF does.
6782  *
6783  * Returns 0 on success or returns an errno.
6784  */
6785 #ifndef NATIVE_BUILD
6786 static int
6787 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6788 {
6789         int ret, err;
6790         struct timespec ts;
6791         char *emi_state;
6792 
6793         /*
6794          * smf_get_state does not distinguish between its different failure
6795          * modes: memory allocation failures, SMF internal failures, and a lack
6796          * of EMI entirely because it's been removed. In these cases, we're
6797          * going to be conservative and opt to say that if we don't know, better
6798          * to not block import or falsely warn to the user.
6799          */
6800         if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6801                 return (0);
6802         }
6803 
6804         /*
6805          * As per the block comment for this function check the state of EMI
6806          */
6807         if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6808             strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6809                 warn(gettext("Not validating instance %s:%s because EMI's "
6810                     "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6811                 free(emi_state);
6812                 return (0);
6813         }
6814 
6815         free(emi_state);
6816 
6817         /*
6818          * First we have to get the property.
6819          */
6820         if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6821                 ret = scf_error();
6822                 warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6823                 return (ret);
6824         }
6825 
6826         /*
6827          * We should always be able to get the instance. It should already
6828          * exist because we just created it or got it. There probably is a
6829          * slim chance that someone may have come in and deleted it though from
6830          * under us.
6831          */
6832         if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6833             != 0) {
6834                 ret = scf_error();
6835                 warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6836                 switch (ret) {
6837                 case SCF_ERROR_DELETED:
6838                         err = ENODEV;
6839                         break;
6840                 case SCF_ERROR_CONNECTION_BROKEN:
6841                         warn(gettext("Lost repository connection\n"));
6842                         err = ECONNABORTED;
6843                         break;
6844                 case SCF_ERROR_NOT_FOUND:
6845                         warn(gettext("Instance \"%s\" disappeared out from "
6846                             "under us.\n"), inst->sc_name);
6847                         err = ENOENT;
6848                         break;
6849                 default:
6850                         bad_error("scf_service_get_instance", ret);
6851                 }
6852 
6853                 return (err);
6854         }
6855 
6856         /*
6857          * An astute observer may want to use _scf_wait_pg which would notify us
6858          * of a property group change, unfortunately that does not work if the
6859          * property group in question does not exist. So instead we have to
6860          * manually poll and ask smf the best way to get to it.
6861          */
6862         while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6863             != SCF_SUCCESS) {
6864                 ret = scf_error();
6865                 if (ret != SCF_ERROR_NOT_FOUND) {
6866                         warn(gettext("Failed to get restarter property "
6867                             "group for instance: %s\n"), inst->sc_name);
6868                         switch (ret) {
6869                         case SCF_ERROR_DELETED:
6870                                 err = ENODEV;
6871                                 break;
6872                         case SCF_ERROR_CONNECTION_BROKEN:
6873                                 warn(gettext("Lost repository connection\n"));
6874                                 err = ECONNABORTED;
6875                                 break;
6876                         default:
6877                                 bad_error("scf_service_get_instance", ret);
6878                         }
6879 
6880                         return (err);
6881                 }
6882 
6883                 ts.tv_sec = pg_timeout / NANOSEC;
6884                 ts.tv_nsec = pg_timeout % NANOSEC;
6885 
6886                 (void) nanosleep(&ts, NULL);
6887         }
6888 
6889         /*
6890          * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6891          * So in addition to the property group being present, we need to wait
6892          * for the property to be there in some form.
6893          *
6894          * Note that a property group is a frozen snapshot in time. To properly
6895          * get beyond this, you have to refresh the property group each time.
6896          */
6897         while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6898             imp_prop)) != 0) {
6899 
6900                 ret = scf_error();
6901                 if (ret != SCF_ERROR_NOT_FOUND) {
6902                         warn(gettext("Failed to get property %s from the "
6903                             "restarter property group of instance %s\n"),
6904                             SCF_PROPERTY_STATE, inst->sc_name);
6905                         switch (ret) {
6906                         case SCF_ERROR_CONNECTION_BROKEN:
6907                                 warn(gettext("Lost repository connection\n"));
6908                                 err = ECONNABORTED;
6909                                 break;
6910                         case SCF_ERROR_DELETED:
6911                                 err = ENODEV;
6912                                 break;
6913                         default:
6914                                 bad_error("scf_pg_get_property", ret);
6915                         }
6916 
6917                         return (err);
6918                 }
6919 
6920                 ts.tv_sec = pg_timeout / NANOSEC;
6921                 ts.tv_nsec = pg_timeout % NANOSEC;
6922 
6923                 (void) nanosleep(&ts, NULL);
6924 
6925                 ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6926                 if (ret != SCF_SUCCESS) {
6927                         warn(gettext("Failed to get restarter property "
6928                             "group for instance: %s\n"), inst->sc_name);
6929                         switch (ret) {
6930                         case SCF_ERROR_DELETED:
6931                                 err = ENODEV;
6932                                 break;
6933                         case SCF_ERROR_CONNECTION_BROKEN:
6934                                 warn(gettext("Lost repository connection\n"));
6935                                 err = ECONNABORTED;
6936                                 break;
6937                         default:
6938                                 bad_error("scf_service_get_instance", ret);
6939                         }
6940 
6941                         return (err);
6942                 }
6943         }
6944 
6945         /*
6946          * We don't have to free the property groups or other values that we got
6947          * because we stored them in global variables that are allocated and
6948          * freed by the routines that call into these functions. Unless of
6949          * course the rest of the code here that we are basing this on is
6950          * mistaken.
6951          */
6952         return (0);
6953 }
6954 #endif
6955 
6956 /*
6957  * If the service is missing, create it, import its properties, and import the
6958  * instances.  Since the service is brand new, it should be empty, and if we
6959  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6960  *
6961  * If the service exists, we want to upgrade its properties and import the
6962  * instances.  Upgrade requires a last-import snapshot, though, which are
6963  * children of instances, so first we'll have to go through the instances
6964  * looking for a last-import snapshot.  If we don't find one then we'll just
6965  * override-import the service properties (but don't delete existing
6966  * properties: another service might have declared us as a dependent).  Before
6967  * we change anything, though, we want to take the previous snapshots.  We
6968  * also give lscf_instance_import() a leg up on taking last-import snapshots
6969  * by importing the manifest's service properties into a temporary service.
6970  *
6971  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6972  * sets lcbdata->sc_err to
6973  *   ECONNABORTED - repository connection broken
6974  *   ENOMEM - out of memory
6975  *   ENOSPC - svc.configd is out of resources
6976  *   EPERM - couldn't create temporary service (error printed)
6977  *         - couldn't import into temp service (error printed)
6978  *         - couldn't create service (error printed)
6979  *         - couldn't import dependent (error printed)
6980  *         - couldn't take snapshot (error printed)
6981  *         - couldn't create instance (error printed)
6982  *         - couldn't create, modify, or delete pg (error printed)
6983  *         - couldn't create, modify, or delete dependent (error printed)
6984  *         - couldn't import instance (error printed)
6985  *   EROFS - couldn't create temporary service (repository read-only)
6986  *         - couldn't import into temporary service (repository read-only)
6987  *         - couldn't create service (repository read-only)
6988  *         - couldn't import dependent (repository read-only)
6989  *         - couldn't create instance (repository read-only)
6990  *         - couldn't create, modify, or delete pg or dependent
6991  *         - couldn't import instance (repository read-only)
6992  *   EACCES - couldn't create temporary service (backend access denied)
6993  *          - couldn't import into temporary service (backend access denied)
6994  *          - couldn't create service (backend access denied)
6995  *          - couldn't import dependent (backend access denied)
6996  *          - couldn't create instance (backend access denied)
6997  *          - couldn't create, modify, or delete pg or dependent
6998  *          - couldn't import instance (backend access denied)
6999  *   EINVAL - service name is invalid (error printed)
7000  *          - service name is too long (error printed)
7001  *          - s has invalid pgroup (error printed)
7002  *          - s has invalid dependent (error printed)
7003  *          - instance name is invalid (error printed)
7004  *          - instance entity_t is invalid (error printed)
7005  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7006  *          - couldn't import dependent (dependency pg already exists) (printed)
7007  *          - dependency collision in dependent service (error printed)
7008  *   EBUSY - temporary service deleted (error printed)
7009  *         - property group added to temporary service (error printed)
7010  *         - new property group changed or was deleted (error printed)
7011  *         - service was added unexpectedly (error printed)
7012  *         - service was deleted unexpectedly (error printed)
7013  *         - property group added to new service (error printed)
7014  *         - instance added unexpectedly (error printed)
7015  *         - instance deleted unexpectedly (error printed)
7016  *         - dependent service deleted unexpectedly (error printed)
7017  *         - pg was added, changed, or deleted (error printed)
7018  *         - dependent pg changed (error printed)
7019  *         - temporary instance added, changed, or deleted (error printed)
7020  *   EBADF - a last-import snapshot is corrupt (error printed)
7021  *         - the service is corrupt (error printed)
7022  *         - a dependent is corrupt (error printed)
7023  *         - an instance is corrupt (error printed)
7024  *         - an instance has a corrupt last-import snapshot (error printed)
7025  *         - dependent target has a corrupt snapshot (error printed)
7026  *   -1 - unknown libscf error (error printed)
7027  */
7028 static int
7029 lscf_service_import(void *v, void *pvt)
7030 {
7031         entity_t *s = v;
7032         scf_callback_t cbdata;
7033         scf_callback_t *lcbdata = pvt;
7034         scf_scope_t *scope = lcbdata->sc_parent;
7035         entity_t *inst, linst;
7036         int r;
7037         int fresh = 0;
7038         scf_snaplevel_t *running;
7039         int have_ge = 0;
7040         boolean_t retried = B_FALSE;
7041 
7042         const char * const ts_deleted = gettext("Temporary service svc:/%s "
7043             "was deleted unexpectedly.\n");
7044         const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7045             "changed unexpectedly (property group added).\n");
7046         const char * const s_deleted =
7047             gettext("%s was deleted unexpectedly.\n");
7048         const char * const i_deleted =
7049             gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7050         const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7051             "is corrupt (missing service snaplevel).\n");
7052         const char * const s_mfile_upd =
7053             gettext("Unable to update the manifest file connection "
7054             "for %s\n");
7055 
7056         li_only = 0;
7057         /* Validate the service name */
7058         if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7059                 switch (scf_error()) {
7060                 case SCF_ERROR_CONNECTION_BROKEN:
7061                         return (stash_scferror(lcbdata));
7062 
7063                 case SCF_ERROR_INVALID_ARGUMENT:
7064                         warn(gettext("\"%s\" is an invalid service name.  "
7065                             "Cannot import.\n"), s->sc_name);
7066                         return (stash_scferror(lcbdata));
7067 
7068                 case SCF_ERROR_NOT_FOUND:
7069                         break;
7070 
7071                 case SCF_ERROR_HANDLE_MISMATCH:
7072                 case SCF_ERROR_NOT_BOUND:
7073                 case SCF_ERROR_NOT_SET:
7074                 default:
7075                         bad_error("scf_scope_get_service", scf_error());
7076                 }
7077         }
7078 
7079         /* create temporary service */
7080         /*
7081          * the size of the buffer was reduced to max_scf_name_len to prevent
7082          * hitting bug 6681151.  After the bug fix, the size of the buffer
7083          * should be restored to its original value (max_scf_name_len +1)
7084          */
7085         r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7086         if (r < 0)
7087                 bad_error("snprintf", errno);
7088         if (r > max_scf_name_len) {
7089                 warn(gettext(
7090                     "Service name \"%s\" is too long.  Cannot import.\n"),
7091                     s->sc_name);
7092                 lcbdata->sc_err = EINVAL;
7093                 return (UU_WALK_ERROR);
7094         }
7095 
7096 retry:
7097         if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7098                 switch (scf_error()) {
7099                 case SCF_ERROR_CONNECTION_BROKEN:
7100                 case SCF_ERROR_NO_RESOURCES:
7101                 case SCF_ERROR_BACKEND_READONLY:
7102                 case SCF_ERROR_BACKEND_ACCESS:
7103                         return (stash_scferror(lcbdata));
7104 
7105                 case SCF_ERROR_EXISTS:
7106                         if (!retried) {
7107                                 lscf_delete(imp_tsname, 0);
7108                                 retried = B_TRUE;
7109                                 goto retry;
7110                         }
7111                         warn(gettext(
7112                             "Temporary service \"%s\" must be deleted before "
7113                             "this manifest can be imported.\n"), imp_tsname);
7114                         return (stash_scferror(lcbdata));
7115 
7116                 case SCF_ERROR_PERMISSION_DENIED:
7117                         warn(gettext("Could not create temporary service "
7118                             "\"%s\" (permission denied).\n"), imp_tsname);
7119                         return (stash_scferror(lcbdata));
7120 
7121                 case SCF_ERROR_INVALID_ARGUMENT:
7122                 case SCF_ERROR_HANDLE_MISMATCH:
7123                 case SCF_ERROR_NOT_BOUND:
7124                 case SCF_ERROR_NOT_SET:
7125                 default:
7126                         bad_error("scf_scope_add_service", scf_error());
7127                 }
7128         }
7129 
7130         r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7131         if (r < 0)
7132                 bad_error("snprintf", errno);
7133 
7134         cbdata.sc_handle = lcbdata->sc_handle;
7135         cbdata.sc_parent = imp_tsvc;
7136         cbdata.sc_service = 1;
7137         cbdata.sc_source_fmri = s->sc_fmri;
7138         cbdata.sc_target_fmri = imp_str;
7139         cbdata.sc_flags = 0;
7140 
7141         if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7142             UU_DEFAULT) != 0) {
7143                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7144                         bad_error("uu_list_walk", uu_error());
7145 
7146                 lcbdata->sc_err = cbdata.sc_err;
7147                 switch (cbdata.sc_err) {
7148                 case ECONNABORTED:
7149                         goto connaborted;
7150 
7151                 case ECANCELED:
7152                         warn(ts_deleted, imp_tsname);
7153                         lcbdata->sc_err = EBUSY;
7154                         return (UU_WALK_ERROR);
7155 
7156                 case EEXIST:
7157                         warn(ts_pg_added, imp_tsname);
7158                         lcbdata->sc_err = EBUSY;
7159                         return (UU_WALK_ERROR);
7160                 }
7161 
7162                 r = UU_WALK_ERROR;
7163                 goto deltemp;
7164         }
7165 
7166         if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7167             UU_DEFAULT) != 0) {
7168                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7169                         bad_error("uu_list_walk", uu_error());
7170 
7171                 lcbdata->sc_err = cbdata.sc_err;
7172                 switch (cbdata.sc_err) {
7173                 case ECONNABORTED:
7174                         goto connaborted;
7175 
7176                 case ECANCELED:
7177                         warn(ts_deleted, imp_tsname);
7178                         lcbdata->sc_err = EBUSY;
7179                         return (UU_WALK_ERROR);
7180 
7181                 case EEXIST:
7182                         warn(ts_pg_added, imp_tsname);
7183                         lcbdata->sc_err = EBUSY;
7184                         return (UU_WALK_ERROR);
7185                 }
7186 
7187                 r = UU_WALK_ERROR;
7188                 goto deltemp;
7189         }
7190 
7191         if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7192                 switch (scf_error()) {
7193                 case SCF_ERROR_NOT_FOUND:
7194                         break;
7195 
7196                 case SCF_ERROR_CONNECTION_BROKEN:
7197                         goto connaborted;
7198 
7199                 case SCF_ERROR_INVALID_ARGUMENT:
7200                 case SCF_ERROR_HANDLE_MISMATCH:
7201                 case SCF_ERROR_NOT_BOUND:
7202                 case SCF_ERROR_NOT_SET:
7203                 default:
7204                         bad_error("scf_scope_get_service", scf_error());
7205                 }
7206 
7207                 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7208                         switch (scf_error()) {
7209                         case SCF_ERROR_CONNECTION_BROKEN:
7210                                 goto connaborted;
7211 
7212                         case SCF_ERROR_NO_RESOURCES:
7213                         case SCF_ERROR_BACKEND_READONLY:
7214                         case SCF_ERROR_BACKEND_ACCESS:
7215                                 r = stash_scferror(lcbdata);
7216                                 goto deltemp;
7217 
7218                         case SCF_ERROR_EXISTS:
7219                                 warn(gettext("Scope \"%s\" changed unexpectedly"
7220                                     " (service \"%s\" added).\n"),
7221                                     SCF_SCOPE_LOCAL, s->sc_name);
7222                                 lcbdata->sc_err = EBUSY;
7223                                 goto deltemp;
7224 
7225                         case SCF_ERROR_PERMISSION_DENIED:
7226                                 warn(gettext("Could not create service \"%s\" "
7227                                     "(permission denied).\n"), s->sc_name);
7228                                 goto deltemp;
7229 
7230                         case SCF_ERROR_INVALID_ARGUMENT:
7231                         case SCF_ERROR_HANDLE_MISMATCH:
7232                         case SCF_ERROR_NOT_BOUND:
7233                         case SCF_ERROR_NOT_SET:
7234                         default:
7235                                 bad_error("scf_scope_add_service", scf_error());
7236                         }
7237                 }
7238 
7239                 s->sc_import_state = IMPORT_PROP_BEGUN;
7240 
7241                 /* import service properties */
7242                 cbdata.sc_handle = lcbdata->sc_handle;
7243                 cbdata.sc_parent = imp_svc;
7244                 cbdata.sc_service = 1;
7245                 cbdata.sc_flags = lcbdata->sc_flags;
7246                 cbdata.sc_source_fmri = s->sc_fmri;
7247                 cbdata.sc_target_fmri = s->sc_fmri;
7248 
7249                 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7250                     &cbdata, UU_DEFAULT) != 0) {
7251                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7252                                 bad_error("uu_list_walk", uu_error());
7253 
7254                         lcbdata->sc_err = cbdata.sc_err;
7255                         switch (cbdata.sc_err) {
7256                         case ECONNABORTED:
7257                                 goto connaborted;
7258 
7259                         case ECANCELED:
7260                                 warn(s_deleted, s->sc_fmri);
7261                                 lcbdata->sc_err = EBUSY;
7262                                 return (UU_WALK_ERROR);
7263 
7264                         case EEXIST:
7265                                 warn(gettext("%s changed unexpectedly "
7266                                     "(property group added).\n"), s->sc_fmri);
7267                                 lcbdata->sc_err = EBUSY;
7268                                 return (UU_WALK_ERROR);
7269 
7270                         case EINVAL:
7271                                 /* caught above */
7272                                 bad_error("entity_pgroup_import",
7273                                     cbdata.sc_err);
7274                         }
7275 
7276                         r = UU_WALK_ERROR;
7277                         goto deltemp;
7278                 }
7279 
7280                 cbdata.sc_trans = NULL;
7281                 cbdata.sc_flags = 0;
7282                 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7283                     &cbdata, UU_DEFAULT) != 0) {
7284                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7285                                 bad_error("uu_list_walk", uu_error());
7286 
7287                         lcbdata->sc_err = cbdata.sc_err;
7288                         if (cbdata.sc_err == ECONNABORTED)
7289                                 goto connaborted;
7290                         r = UU_WALK_ERROR;
7291                         goto deltemp;
7292                 }
7293 
7294                 s->sc_import_state = IMPORT_PROP_DONE;
7295 
7296                 /*
7297                  * This is a new service, so we can't take previous snapshots
7298                  * or upgrade service properties.
7299                  */
7300                 fresh = 1;
7301                 goto instances;
7302         }
7303 
7304         /* Clear sc_seen for the instances. */
7305         if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7306             (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7307                 bad_error("uu_list_walk", uu_error());
7308 
7309         /*
7310          * Take previous snapshots for all instances.  Even for ones not
7311          * mentioned in the bundle, since we might change their service
7312          * properties.
7313          */
7314         if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7315                 switch (scf_error()) {
7316                 case SCF_ERROR_CONNECTION_BROKEN:
7317                         goto connaborted;
7318 
7319                 case SCF_ERROR_DELETED:
7320                         warn(s_deleted, s->sc_fmri);
7321                         lcbdata->sc_err = EBUSY;
7322                         r = UU_WALK_ERROR;
7323                         goto deltemp;
7324 
7325                 case SCF_ERROR_HANDLE_MISMATCH:
7326                 case SCF_ERROR_NOT_BOUND:
7327                 case SCF_ERROR_NOT_SET:
7328                 default:
7329                         bad_error("scf_iter_service_instances", scf_error());
7330                 }
7331         }
7332 
7333         for (;;) {
7334                 r = scf_iter_next_instance(imp_iter, imp_inst);
7335                 if (r == 0)
7336                         break;
7337                 if (r != 1) {
7338                         switch (scf_error()) {
7339                         case SCF_ERROR_DELETED:
7340                                 warn(s_deleted, s->sc_fmri);
7341                                 lcbdata->sc_err = EBUSY;
7342                                 r = UU_WALK_ERROR;
7343                                 goto deltemp;
7344 
7345                         case SCF_ERROR_CONNECTION_BROKEN:
7346                                 goto connaborted;
7347 
7348                         case SCF_ERROR_NOT_BOUND:
7349                         case SCF_ERROR_HANDLE_MISMATCH:
7350                         case SCF_ERROR_INVALID_ARGUMENT:
7351                         case SCF_ERROR_NOT_SET:
7352                         default:
7353                                 bad_error("scf_iter_next_instance",
7354                                     scf_error());
7355                         }
7356                 }
7357 
7358                 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7359                         switch (scf_error()) {
7360                         case SCF_ERROR_DELETED:
7361                                 continue;
7362 
7363                         case SCF_ERROR_CONNECTION_BROKEN:
7364                                 goto connaborted;
7365 
7366                         case SCF_ERROR_NOT_SET:
7367                         case SCF_ERROR_NOT_BOUND:
7368                         default:
7369                                 bad_error("scf_instance_get_name", scf_error());
7370                         }
7371                 }
7372 
7373                 if (g_verbose)
7374                         warn(gettext(
7375                             "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7376                             snap_previous, s->sc_name, imp_str);
7377 
7378                 r = take_snap(imp_inst, snap_previous, imp_snap);
7379                 switch (r) {
7380                 case 0:
7381                         break;
7382 
7383                 case ECANCELED:
7384                         continue;
7385 
7386                 case ECONNABORTED:
7387                         goto connaborted;
7388 
7389                 case EPERM:
7390                         warn(gettext("Could not take \"%s\" snapshot of "
7391                             "svc:/%s:%s (permission denied).\n"),
7392                             snap_previous, s->sc_name, imp_str);
7393                         lcbdata->sc_err = r;
7394                         return (UU_WALK_ERROR);
7395 
7396                 case ENOSPC:
7397                 case -1:
7398                         lcbdata->sc_err = r;
7399                         r = UU_WALK_ERROR;
7400                         goto deltemp;
7401 
7402                 default:
7403                         bad_error("take_snap", r);
7404                 }
7405 
7406                 linst.sc_name = imp_str;
7407                 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7408                     &linst, NULL, NULL);
7409                 if (inst != NULL) {
7410                         inst->sc_import_state = IMPORT_PREVIOUS;
7411                         inst->sc_seen = 1;
7412                 }
7413         }
7414 
7415         /*
7416          * Create the new instances and take previous snapshots of
7417          * them.  This is not necessary, but it maximizes data preservation.
7418          */
7419         for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7420             inst != NULL;
7421             inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7422             inst)) {
7423                 if (inst->sc_seen)
7424                         continue;
7425 
7426                 if (scf_service_add_instance(imp_svc, inst->sc_name,
7427                     imp_inst) != 0) {
7428                         switch (scf_error()) {
7429                         case SCF_ERROR_CONNECTION_BROKEN:
7430                                 goto connaborted;
7431 
7432                         case SCF_ERROR_BACKEND_READONLY:
7433                         case SCF_ERROR_BACKEND_ACCESS:
7434                         case SCF_ERROR_NO_RESOURCES:
7435                                 r = stash_scferror(lcbdata);
7436                                 goto deltemp;
7437 
7438                         case SCF_ERROR_EXISTS:
7439                                 warn(gettext("%s changed unexpectedly "
7440                                     "(instance \"%s\" added).\n"), s->sc_fmri,
7441                                     inst->sc_name);
7442                                 lcbdata->sc_err = EBUSY;
7443                                 r = UU_WALK_ERROR;
7444                                 goto deltemp;
7445 
7446                         case SCF_ERROR_INVALID_ARGUMENT:
7447                                 warn(gettext("Service \"%s\" has instance with "
7448                                     "invalid name \"%s\".\n"), s->sc_name,
7449                                     inst->sc_name);
7450                                 r = stash_scferror(lcbdata);
7451                                 goto deltemp;
7452 
7453                         case SCF_ERROR_PERMISSION_DENIED:
7454                                 warn(gettext("Could not create instance \"%s\" "
7455                                     "in %s (permission denied).\n"),
7456                                     inst->sc_name, s->sc_fmri);
7457                                 r = stash_scferror(lcbdata);
7458                                 goto deltemp;
7459 
7460                         case SCF_ERROR_HANDLE_MISMATCH:
7461                         case SCF_ERROR_NOT_BOUND:
7462                         case SCF_ERROR_NOT_SET:
7463                         default:
7464                                 bad_error("scf_service_add_instance",
7465                                     scf_error());
7466                         }
7467                 }
7468 
7469                 if (g_verbose)
7470                         warn(gettext("Taking \"%s\" snapshot for "
7471                             "new service %s.\n"), snap_previous, inst->sc_fmri);
7472                 r = take_snap(imp_inst, snap_previous, imp_snap);
7473                 switch (r) {
7474                 case 0:
7475                         break;
7476 
7477                 case ECANCELED:
7478                         warn(i_deleted, s->sc_fmri, inst->sc_name);
7479                         lcbdata->sc_err = EBUSY;
7480                         r = UU_WALK_ERROR;
7481                         goto deltemp;
7482 
7483                 case ECONNABORTED:
7484                         goto connaborted;
7485 
7486                 case EPERM:
7487                         warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7488                         lcbdata->sc_err = r;
7489                         r = UU_WALK_ERROR;
7490                         goto deltemp;
7491 
7492                 case ENOSPC:
7493                 case -1:
7494                         r = UU_WALK_ERROR;
7495                         goto deltemp;
7496 
7497                 default:
7498                         bad_error("take_snap", r);
7499                 }
7500         }
7501 
7502         s->sc_import_state = IMPORT_PREVIOUS;
7503 
7504         /*
7505          * Upgrade service properties, if we can find a last-import snapshot.
7506          * Any will do because we don't support different service properties
7507          * in different manifests, so all snaplevels of the service in all of
7508          * the last-import snapshots of the instances should be the same.
7509          */
7510         if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7511                 switch (scf_error()) {
7512                 case SCF_ERROR_CONNECTION_BROKEN:
7513                         goto connaborted;
7514 
7515                 case SCF_ERROR_DELETED:
7516                         warn(s_deleted, s->sc_fmri);
7517                         lcbdata->sc_err = EBUSY;
7518                         r = UU_WALK_ERROR;
7519                         goto deltemp;
7520 
7521                 case SCF_ERROR_HANDLE_MISMATCH:
7522                 case SCF_ERROR_NOT_BOUND:
7523                 case SCF_ERROR_NOT_SET:
7524                 default:
7525                         bad_error("scf_iter_service_instances", scf_error());
7526                 }
7527         }
7528 
7529         for (;;) {
7530                 r = scf_iter_next_instance(imp_iter, imp_inst);
7531                 if (r == -1) {
7532                         switch (scf_error()) {
7533                         case SCF_ERROR_DELETED:
7534                                 warn(s_deleted, s->sc_fmri);
7535                                 lcbdata->sc_err = EBUSY;
7536                                 r = UU_WALK_ERROR;
7537                                 goto deltemp;
7538 
7539                         case SCF_ERROR_CONNECTION_BROKEN:
7540                                 goto connaborted;
7541 
7542                         case SCF_ERROR_NOT_BOUND:
7543                         case SCF_ERROR_HANDLE_MISMATCH:
7544                         case SCF_ERROR_INVALID_ARGUMENT:
7545                         case SCF_ERROR_NOT_SET:
7546                         default:
7547                                 bad_error("scf_iter_next_instance",
7548                                     scf_error());
7549                         }
7550                 }
7551 
7552                 if (r == 0) {
7553                         /*
7554                          * Didn't find any last-import snapshots.  Override-
7555                          * import the properties.  Unless one of the instances
7556                          * has a general/enabled property, in which case we're
7557                          * probably running a last-import-capable svccfg for
7558                          * the first time, and we should only take the
7559                          * last-import snapshot.
7560                          */
7561                         if (have_ge) {
7562                                 pgroup_t *mfpg;
7563                                 scf_callback_t mfcbdata;
7564 
7565                                 li_only = 1;
7566                                 no_refresh = 1;
7567                                 /*
7568                                  * Need to go ahead and import the manifestfiles
7569                                  * pg if it exists. If the last-import snapshot
7570                                  * upgrade code is ever removed this code can
7571                                  * be removed as well.
7572                                  */
7573                                 mfpg = internal_pgroup_find(s,
7574                                     SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7575 
7576                                 if (mfpg) {
7577                                         mfcbdata.sc_handle = g_hndl;
7578                                         mfcbdata.sc_parent = imp_svc;
7579                                         mfcbdata.sc_service = 1;
7580                                         mfcbdata.sc_flags = SCI_FORCE;
7581                                         mfcbdata.sc_source_fmri = s->sc_fmri;
7582                                         mfcbdata.sc_target_fmri = s->sc_fmri;
7583                                         if (entity_pgroup_import(mfpg,
7584                                             &mfcbdata) != UU_WALK_NEXT) {
7585                                                 warn(s_mfile_upd, s->sc_fmri);
7586                                                 r = UU_WALK_ERROR;
7587                                                 goto deltemp;
7588                                         }
7589                                 }
7590                                 break;
7591                         }
7592 
7593                         s->sc_import_state = IMPORT_PROP_BEGUN;
7594 
7595                         cbdata.sc_handle = g_hndl;
7596                         cbdata.sc_parent = imp_svc;
7597                         cbdata.sc_service = 1;
7598                         cbdata.sc_flags = SCI_FORCE;
7599                         cbdata.sc_source_fmri = s->sc_fmri;
7600                         cbdata.sc_target_fmri = s->sc_fmri;
7601                         if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7602                             &cbdata, UU_DEFAULT) != 0) {
7603                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7604                                         bad_error("uu_list_walk", uu_error());
7605                                 lcbdata->sc_err = cbdata.sc_err;
7606                                 switch (cbdata.sc_err) {
7607                                 case ECONNABORTED:
7608                                         goto connaborted;
7609 
7610                                 case ECANCELED:
7611                                         warn(s_deleted, s->sc_fmri);
7612                                         lcbdata->sc_err = EBUSY;
7613                                         break;
7614 
7615                                 case EINVAL:    /* caught above */
7616                                 case EEXIST:
7617                                         bad_error("entity_pgroup_import",
7618                                             cbdata.sc_err);
7619                                 }
7620 
7621                                 r = UU_WALK_ERROR;
7622                                 goto deltemp;
7623                         }
7624 
7625                         cbdata.sc_trans = NULL;
7626                         cbdata.sc_flags = 0;
7627                         if (uu_list_walk(s->sc_dependents,
7628                             lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7629                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7630                                         bad_error("uu_list_walk", uu_error());
7631                                 lcbdata->sc_err = cbdata.sc_err;
7632                                 if (cbdata.sc_err == ECONNABORTED)
7633                                         goto connaborted;
7634                                 r = UU_WALK_ERROR;
7635                                 goto deltemp;
7636                         }
7637                         break;
7638                 }
7639 
7640                 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7641                     imp_snap) != 0) {
7642                         switch (scf_error()) {
7643                         case SCF_ERROR_DELETED:
7644                                 continue;
7645 
7646                         case SCF_ERROR_NOT_FOUND:
7647                                 break;
7648 
7649                         case SCF_ERROR_CONNECTION_BROKEN:
7650                                 goto connaborted;
7651 
7652                         case SCF_ERROR_HANDLE_MISMATCH:
7653                         case SCF_ERROR_NOT_BOUND:
7654                         case SCF_ERROR_INVALID_ARGUMENT:
7655                         case SCF_ERROR_NOT_SET:
7656                         default:
7657                                 bad_error("scf_instance_get_snapshot",
7658                                     scf_error());
7659                         }
7660 
7661                         if (have_ge)
7662                                 continue;
7663 
7664                         /*
7665                          * Check for a general/enabled property.  This is how
7666                          * we tell whether to import if there turn out to be
7667                          * no last-import snapshots.
7668                          */
7669                         if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7670                             imp_pg) == 0) {
7671                                 if (scf_pg_get_property(imp_pg,
7672                                     SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7673                                         have_ge = 1;
7674                                 } else {
7675                                         switch (scf_error()) {
7676                                         case SCF_ERROR_DELETED:
7677                                         case SCF_ERROR_NOT_FOUND:
7678                                                 continue;
7679 
7680                                         case SCF_ERROR_INVALID_ARGUMENT:
7681                                         case SCF_ERROR_HANDLE_MISMATCH:
7682                                         case SCF_ERROR_CONNECTION_BROKEN:
7683                                         case SCF_ERROR_NOT_BOUND:
7684                                         case SCF_ERROR_NOT_SET:
7685                                         default:
7686                                                 bad_error("scf_pg_get_property",
7687                                                     scf_error());
7688                                         }
7689                                 }
7690                         } else {
7691                                 switch (scf_error()) {
7692                                 case SCF_ERROR_DELETED:
7693                                 case SCF_ERROR_NOT_FOUND:
7694                                         continue;
7695 
7696                                 case SCF_ERROR_CONNECTION_BROKEN:
7697                                         goto connaborted;
7698 
7699                                 case SCF_ERROR_NOT_BOUND:
7700                                 case SCF_ERROR_NOT_SET:
7701                                 case SCF_ERROR_INVALID_ARGUMENT:
7702                                 case SCF_ERROR_HANDLE_MISMATCH:
7703                                 default:
7704                                         bad_error("scf_instance_get_pg",
7705                                             scf_error());
7706                                 }
7707                         }
7708                         continue;
7709                 }
7710 
7711                 /* find service snaplevel */
7712                 r = get_snaplevel(imp_snap, 1, imp_snpl);
7713                 switch (r) {
7714                 case 0:
7715                         break;
7716 
7717                 case ECONNABORTED:
7718                         goto connaborted;
7719 
7720                 case ECANCELED:
7721                         continue;
7722 
7723                 case ENOENT:
7724                         if (scf_instance_get_name(imp_inst, imp_str,
7725                             imp_str_sz) < 0)
7726                                 (void) strcpy(imp_str, "?");
7727                         warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7728                         lcbdata->sc_err = EBADF;
7729                         r = UU_WALK_ERROR;
7730                         goto deltemp;
7731 
7732                 default:
7733                         bad_error("get_snaplevel", r);
7734                 }
7735 
7736                 if (scf_instance_get_snapshot(imp_inst, snap_running,
7737                     imp_rsnap) != 0) {
7738                         switch (scf_error()) {
7739                         case SCF_ERROR_DELETED:
7740                                 continue;
7741 
7742                         case SCF_ERROR_NOT_FOUND:
7743                                 break;
7744 
7745                         case SCF_ERROR_CONNECTION_BROKEN:
7746                                 goto connaborted;
7747 
7748                         case SCF_ERROR_INVALID_ARGUMENT:
7749                         case SCF_ERROR_HANDLE_MISMATCH:
7750                         case SCF_ERROR_NOT_BOUND:
7751                         case SCF_ERROR_NOT_SET:
7752                         default:
7753                                 bad_error("scf_instance_get_snapshot",
7754                                     scf_error());
7755                         }
7756                         running = NULL;
7757                 } else {
7758                         r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7759                         switch (r) {
7760                         case 0:
7761                                 running = imp_rsnpl;
7762                                 break;
7763 
7764                         case ECONNABORTED:
7765                                 goto connaborted;
7766 
7767                         case ECANCELED:
7768                                 continue;
7769 
7770                         case ENOENT:
7771                                 if (scf_instance_get_name(imp_inst, imp_str,
7772                                     imp_str_sz) < 0)
7773                                         (void) strcpy(imp_str, "?");
7774                                 warn(badsnap, snap_running, s->sc_name,
7775                                     imp_str);
7776                                 lcbdata->sc_err = EBADF;
7777                                 r = UU_WALK_ERROR;
7778                                 goto deltemp;
7779 
7780                         default:
7781                                 bad_error("get_snaplevel", r);
7782                         }
7783                 }
7784 
7785                 if (g_verbose) {
7786                         if (scf_instance_get_name(imp_inst, imp_str,
7787                             imp_str_sz) < 0)
7788                                 (void) strcpy(imp_str, "?");
7789                         warn(gettext("Upgrading properties of %s according to "
7790                             "instance \"%s\".\n"), s->sc_fmri, imp_str);
7791                 }
7792 
7793                 /* upgrade service properties */
7794                 r = upgrade_props(imp_svc, running, imp_snpl, s);
7795                 if (r == 0)
7796                         break;
7797 
7798                 switch (r) {
7799                 case ECONNABORTED:
7800                         goto connaborted;
7801 
7802                 case ECANCELED:
7803                         warn(s_deleted, s->sc_fmri);
7804                         lcbdata->sc_err = EBUSY;
7805                         break;
7806 
7807                 case ENODEV:
7808                         if (scf_instance_get_name(imp_inst, imp_str,
7809                             imp_str_sz) < 0)
7810                                 (void) strcpy(imp_str, "?");
7811                         warn(i_deleted, s->sc_fmri, imp_str);
7812                         lcbdata->sc_err = EBUSY;
7813                         break;
7814 
7815                 default:
7816                         lcbdata->sc_err = r;
7817                 }
7818 
7819                 r = UU_WALK_ERROR;
7820                 goto deltemp;
7821         }
7822 
7823         s->sc_import_state = IMPORT_PROP_DONE;
7824 
7825 instances:
7826         /* import instances */
7827         cbdata.sc_handle = lcbdata->sc_handle;
7828         cbdata.sc_parent = imp_svc;
7829         cbdata.sc_service = 1;
7830         cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7831         cbdata.sc_general = NULL;
7832 
7833         if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7834             lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7835                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7836                         bad_error("uu_list_walk", uu_error());
7837 
7838                 lcbdata->sc_err = cbdata.sc_err;
7839                 if (cbdata.sc_err == ECONNABORTED)
7840                         goto connaborted;
7841                 r = UU_WALK_ERROR;
7842                 goto deltemp;
7843         }
7844 
7845         s->sc_import_state = IMPORT_COMPLETE;
7846         r = UU_WALK_NEXT;
7847 
7848 deltemp:
7849         /* delete temporary service */
7850         if (scf_service_delete(imp_tsvc) != 0) {
7851                 switch (scf_error()) {
7852                 case SCF_ERROR_DELETED:
7853                         break;
7854 
7855                 case SCF_ERROR_CONNECTION_BROKEN:
7856                         goto connaborted;
7857 
7858                 case SCF_ERROR_EXISTS:
7859                         warn(gettext(
7860                             "Could not delete svc:/%s (instances exist).\n"),
7861                             imp_tsname);
7862                         break;
7863 
7864                 case SCF_ERROR_NOT_SET:
7865                 case SCF_ERROR_NOT_BOUND:
7866                 default:
7867                         bad_error("scf_service_delete", scf_error());
7868                 }
7869         }
7870 
7871         return (r);
7872 
7873 connaborted:
7874         warn(gettext("Could not delete svc:/%s "
7875             "(repository connection broken).\n"), imp_tsname);
7876         lcbdata->sc_err = ECONNABORTED;
7877         return (UU_WALK_ERROR);
7878 }
7879 
7880 static const char *
7881 import_progress(int st)
7882 {
7883         switch (st) {
7884         case 0:
7885                 return (gettext("not reached."));
7886 
7887         case IMPORT_PREVIOUS:
7888                 return (gettext("previous snapshot taken."));
7889 
7890         case IMPORT_PROP_BEGUN:
7891                 return (gettext("some properties imported."));
7892 
7893         case IMPORT_PROP_DONE:
7894                 return (gettext("properties imported."));
7895 
7896         case IMPORT_COMPLETE:
7897                 return (gettext("imported."));
7898 
7899         case IMPORT_REFRESHED:
7900                 return (gettext("refresh requested."));
7901 
7902         default:
7903 #ifndef NDEBUG
7904                 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7905                     __FILE__, __LINE__, st);
7906 #endif
7907                 abort();
7908                 /* NOTREACHED */
7909         }
7910 }
7911 
7912 /*
7913  * Returns
7914  *   0 - success
7915  *     - fmri wasn't found (error printed)
7916  *     - entity was deleted (error printed)
7917  *     - backend denied access (error printed)
7918  *   ENOMEM - out of memory (error printed)
7919  *   ECONNABORTED - repository connection broken (error printed)
7920  *   EPERM - permission denied (error printed)
7921  *   -1 - unknown libscf error (error printed)
7922  */
7923 static int
7924 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7925 {
7926         scf_error_t serr;
7927         void *ent;
7928         int issvc;
7929         int r;
7930 
7931         const char *deleted = gettext("Could not refresh %s (deleted).\n");
7932         const char *dpt_deleted = gettext("Could not refresh %s "
7933             "(dependent \"%s\" of %s) (deleted).\n");
7934 
7935         serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7936         switch (serr) {
7937         case SCF_ERROR_NONE:
7938                 break;
7939 
7940         case SCF_ERROR_NO_MEMORY:
7941                 if (name == NULL)
7942                         warn(gettext("Could not refresh %s (out of memory).\n"),
7943                             fmri);
7944                 else
7945                         warn(gettext("Could not refresh %s "
7946                             "(dependent \"%s\" of %s) (out of memory).\n"),
7947                             fmri, name, d_fmri);
7948                 return (ENOMEM);
7949 
7950         case SCF_ERROR_NOT_FOUND:
7951                 if (name == NULL)
7952                         warn(deleted, fmri);
7953                 else
7954                         warn(dpt_deleted, fmri, name, d_fmri);
7955                 return (0);
7956 
7957         case SCF_ERROR_INVALID_ARGUMENT:
7958         case SCF_ERROR_CONSTRAINT_VIOLATED:
7959         default:
7960                 bad_error("fmri_to_entity", serr);
7961         }
7962 
7963         r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7964         switch (r) {
7965         case 0:
7966                 break;
7967 
7968         case ECONNABORTED:
7969                 if (name != NULL)
7970                         warn(gettext("Could not refresh %s "
7971                             "(dependent \"%s\" of %s) "
7972                             "(repository connection broken).\n"), fmri, name,
7973                             d_fmri);
7974                 return (r);
7975 
7976         case ECANCELED:
7977                 if (name == NULL)
7978                         warn(deleted, fmri);
7979                 else
7980                         warn(dpt_deleted, fmri, name, d_fmri);
7981                 return (0);
7982 
7983         case EACCES:
7984                 if (!g_verbose)
7985                         return (0);
7986                 if (name == NULL)
7987                         warn(gettext("Could not refresh %s "
7988                             "(backend access denied).\n"), fmri);
7989                 else
7990                         warn(gettext("Could not refresh %s "
7991                             "(dependent \"%s\" of %s) "
7992                             "(backend access denied).\n"), fmri, name, d_fmri);
7993                 return (0);
7994 
7995         case EPERM:
7996                 if (name == NULL)
7997                         warn(gettext("Could not refresh %s "
7998                             "(permission denied).\n"), fmri);
7999                 else
8000                         warn(gettext("Could not refresh %s "
8001                             "(dependent \"%s\" of %s) "
8002                             "(permission denied).\n"), fmri, name, d_fmri);
8003                 return (r);
8004 
8005         case ENOSPC:
8006                 if (name == NULL)
8007                         warn(gettext("Could not refresh %s "
8008                             "(repository server out of resources).\n"),
8009                             fmri);
8010                 else
8011                         warn(gettext("Could not refresh %s "
8012                             "(dependent \"%s\" of %s) "
8013                             "(repository server out of resources).\n"),
8014                             fmri, name, d_fmri);
8015                 return (r);
8016 
8017         case -1:
8018                 scfwarn();
8019                 return (r);
8020 
8021         default:
8022                 bad_error("refresh_entity", r);
8023         }
8024 
8025         if (issvc)
8026                 scf_service_destroy(ent);
8027         else
8028                 scf_instance_destroy(ent);
8029 
8030         return (0);
8031 }
8032 
8033 static int
8034 alloc_imp_globals()
8035 {
8036         int r;
8037 
8038         const char * const emsg_nomem = gettext("Out of memory.\n");
8039         const char * const emsg_nores =
8040             gettext("svc.configd is out of resources.\n");
8041 
8042         imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8043             max_scf_name_len : max_scf_fmri_len) + 1;
8044 
8045         if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8046             (imp_svc = scf_service_create(g_hndl)) == NULL ||
8047             (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8048             (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8049             (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8050             (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8051             (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8052             (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8053             (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8054             (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8055             (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8056             (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8057             (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8058             (imp_prop = scf_property_create(g_hndl)) == NULL ||
8059             (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8060             (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8061             (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8062             (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8063             (imp_str = malloc(imp_str_sz)) == NULL ||
8064             (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8065             (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8066             (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8067             (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8068             (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8069             (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8070             (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8071             (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8072             (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8073             (ud_prop = scf_property_create(g_hndl)) == NULL ||
8074             (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8075             (ud_val = scf_value_create(g_hndl)) == NULL ||
8076             (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8077             (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8078             (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8079             (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8080             (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8081             (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8082                 if (scf_error() == SCF_ERROR_NO_RESOURCES)
8083                         warn(emsg_nores);
8084                 else
8085                         warn(emsg_nomem);
8086 
8087                 return (-1);
8088         }
8089 
8090         r = load_init();
8091         switch (r) {
8092         case 0:
8093                 break;
8094 
8095         case ENOMEM:
8096                 warn(emsg_nomem);
8097                 return (-1);
8098 
8099         default:
8100                 bad_error("load_init", r);
8101         }
8102 
8103         return (0);
8104 }
8105 
8106 static void
8107 free_imp_globals()
8108 {
8109         pgroup_t *old_dpt;
8110         void *cookie;
8111 
8112         load_fini();
8113 
8114         free(ud_ctarg);
8115         free(ud_oldtarg);
8116         free(ud_name);
8117         ud_ctarg = ud_oldtarg = ud_name = NULL;
8118 
8119         scf_transaction_destroy(ud_tx);
8120         ud_tx = NULL;
8121         scf_iter_destroy(ud_iter);
8122         scf_iter_destroy(ud_iter2);
8123         ud_iter = ud_iter2 = NULL;
8124         scf_value_destroy(ud_val);
8125         ud_val = NULL;
8126         scf_property_destroy(ud_prop);
8127         scf_property_destroy(ud_dpt_prop);
8128         ud_prop = ud_dpt_prop = NULL;
8129         scf_pg_destroy(ud_pg);
8130         scf_pg_destroy(ud_cur_depts_pg);
8131         scf_pg_destroy(ud_run_dpts_pg);
8132         ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8133         scf_snaplevel_destroy(ud_snpl);
8134         ud_snpl = NULL;
8135         scf_instance_destroy(ud_inst);
8136         ud_inst = NULL;
8137 
8138         free(imp_str);
8139         free(imp_tsname);
8140         free(imp_fe1);
8141         free(imp_fe2);
8142         imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8143 
8144         cookie = NULL;
8145         while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8146             NULL) {
8147                 free((char *)old_dpt->sc_pgroup_name);
8148                 free((char *)old_dpt->sc_pgroup_fmri);
8149                 internal_pgroup_free(old_dpt);
8150         }
8151         uu_list_destroy(imp_deleted_dpts);
8152 
8153         scf_transaction_destroy(imp_tx);
8154         imp_tx = NULL;
8155         scf_iter_destroy(imp_iter);
8156         scf_iter_destroy(imp_rpg_iter);
8157         scf_iter_destroy(imp_up_iter);
8158         imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8159         scf_property_destroy(imp_prop);
8160         imp_prop = NULL;
8161         scf_pg_destroy(imp_pg);
8162         scf_pg_destroy(imp_pg2);
8163         imp_pg = imp_pg2 = NULL;
8164         scf_snaplevel_destroy(imp_snpl);
8165         scf_snaplevel_destroy(imp_rsnpl);
8166         imp_snpl = imp_rsnpl = NULL;
8167         scf_snapshot_destroy(imp_snap);
8168         scf_snapshot_destroy(imp_lisnap);
8169         scf_snapshot_destroy(imp_tlisnap);
8170         scf_snapshot_destroy(imp_rsnap);
8171         imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8172         scf_instance_destroy(imp_inst);
8173         scf_instance_destroy(imp_tinst);
8174         imp_inst = imp_tinst = NULL;
8175         scf_service_destroy(imp_svc);
8176         scf_service_destroy(imp_tsvc);
8177         imp_svc = imp_tsvc = NULL;
8178         scf_scope_destroy(imp_scope);
8179         imp_scope = NULL;
8180 
8181         load_fini();
8182 }
8183 
8184 int
8185 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8186 {
8187         scf_callback_t cbdata;
8188         int result = 0;
8189         entity_t *svc, *inst;
8190         uu_list_t *insts;
8191         int r;
8192         pgroup_t *old_dpt;
8193         int annotation_set = 0;
8194 
8195         const char * const emsg_nomem = gettext("Out of memory.\n");
8196         const char * const emsg_nores =
8197             gettext("svc.configd is out of resources.\n");
8198 
8199         lscf_prep_hndl();
8200 
8201         if (alloc_imp_globals())
8202                 goto out;
8203 
8204         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8205                 switch (scf_error()) {
8206                 case SCF_ERROR_CONNECTION_BROKEN:
8207                         warn(gettext("Repository connection broken.\n"));
8208                         repository_teardown();
8209                         result = -1;
8210                         goto out;
8211 
8212                 case SCF_ERROR_NOT_FOUND:
8213                 case SCF_ERROR_INVALID_ARGUMENT:
8214                 case SCF_ERROR_NOT_BOUND:
8215                 case SCF_ERROR_HANDLE_MISMATCH:
8216                 default:
8217                         bad_error("scf_handle_get_scope", scf_error());
8218                 }
8219         }
8220 
8221         /* Set up the auditing annotation. */
8222         if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8223                 annotation_set = 1;
8224         } else {
8225                 switch (scf_error()) {
8226                 case SCF_ERROR_CONNECTION_BROKEN:
8227                         warn(gettext("Repository connection broken.\n"));
8228                         repository_teardown();
8229                         result = -1;
8230                         goto out;
8231 
8232                 case SCF_ERROR_INVALID_ARGUMENT:
8233                 case SCF_ERROR_NOT_BOUND:
8234                 case SCF_ERROR_NO_RESOURCES:
8235                 case SCF_ERROR_INTERNAL:
8236                         bad_error("_scf_set_annotation", scf_error());
8237                         /* NOTREACHED */
8238 
8239                 default:
8240                         /*
8241                          * Do not terminate import because of inability to
8242                          * generate annotation audit event.
8243                          */
8244                         warn(gettext("_scf_set_annotation() unexpectedly "
8245                             "failed with return code of %d\n"), scf_error());
8246                         break;
8247                 }
8248         }
8249 
8250         /*
8251          * Clear the sc_import_state's of all services & instances so we can
8252          * report how far we got if we fail.
8253          */
8254         for (svc = uu_list_first(bndl->sc_bundle_services);
8255             svc != NULL;
8256             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8257                 svc->sc_import_state = 0;
8258 
8259                 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8260                     clear_int, (void *)offsetof(entity_t, sc_import_state),
8261                     UU_DEFAULT) != 0)
8262                         bad_error("uu_list_walk", uu_error());
8263         }
8264 
8265         cbdata.sc_handle = g_hndl;
8266         cbdata.sc_parent = imp_scope;
8267         cbdata.sc_flags = flags;
8268         cbdata.sc_general = NULL;
8269 
8270         if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8271             &cbdata, UU_DEFAULT) == 0) {
8272                 char *eptr;
8273                 /* Success.  Refresh everything. */
8274 
8275                 if (flags & SCI_NOREFRESH || no_refresh) {
8276                         no_refresh = 0;
8277                         result = 0;
8278                         goto out;
8279                 }
8280 
8281                 for (svc = uu_list_first(bndl->sc_bundle_services);
8282                     svc != NULL;
8283                     svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8284                         pgroup_t *dpt;
8285 
8286                         insts = svc->sc_u.sc_service.sc_service_instances;
8287 
8288                         for (inst = uu_list_first(insts);
8289                             inst != NULL;
8290                             inst = uu_list_next(insts, inst)) {
8291                                 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8292                                 switch (r) {
8293                                 case 0:
8294                                         break;
8295 
8296                                 case ENOMEM:
8297                                 case ECONNABORTED:
8298                                 case EPERM:
8299                                 case -1:
8300                                         goto progress;
8301 
8302                                 default:
8303                                         bad_error("imp_refresh_fmri", r);
8304                                 }
8305 
8306                                 inst->sc_import_state = IMPORT_REFRESHED;
8307 
8308                                 for (dpt = uu_list_first(inst->sc_dependents);
8309                                     dpt != NULL;
8310                                     dpt = uu_list_next(inst->sc_dependents,
8311                                     dpt))
8312                                         if (imp_refresh_fmri(
8313                                             dpt->sc_pgroup_fmri,
8314                                             dpt->sc_pgroup_name,
8315                                             inst->sc_fmri) != 0)
8316                                                 goto progress;
8317                         }
8318 
8319                         for (dpt = uu_list_first(svc->sc_dependents);
8320                             dpt != NULL;
8321                             dpt = uu_list_next(svc->sc_dependents, dpt))
8322                                 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8323                                     dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8324                                         goto progress;
8325                 }
8326 
8327                 for (old_dpt = uu_list_first(imp_deleted_dpts);
8328                     old_dpt != NULL;
8329                     old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8330                         if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8331                             old_dpt->sc_pgroup_name,
8332                             old_dpt->sc_parent->sc_fmri) != 0)
8333                                 goto progress;
8334 
8335                 result = 0;
8336 
8337                 /*
8338                  * This snippet of code assumes that we are running svccfg as we
8339                  * normally do -- witih svc.startd running. Of course, that is
8340                  * not actually the case all the time because we also use a
8341                  * varient of svc.configd and svccfg which are only meant to
8342                  * run during the build process. During this time we have no
8343                  * svc.startd, so this check would hang the build process.
8344                  *
8345                  * However, we've also given other consolidations, a bit of a
8346                  * means to tie themselves into a knot. They're not properly
8347                  * using the native build equivalents, but they've been getting
8348                  * away with it anyways. Therefore, if we've found that
8349                  * SVCCFG_REPOSITORY is set indicating that a separate configd
8350                  * should be spun up, then we have to assume it's not using a
8351                  * startd and we should not do this check.
8352                  */
8353 #ifndef NATIVE_BUILD
8354                 /*
8355                  * Verify that the restarter group is preset
8356                  */
8357                 eptr = getenv("SVCCFG_REPOSITORY");
8358                 for (svc = uu_list_first(bndl->sc_bundle_services);
8359                     svc != NULL && eptr == NULL;
8360                     svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8361 
8362                         insts = svc->sc_u.sc_service.sc_service_instances;
8363 
8364                         for (inst = uu_list_first(insts);
8365                             inst != NULL;
8366                             inst = uu_list_next(insts, inst)) {
8367                                 if (lscf_instance_verify(imp_scope, svc,
8368                                     inst) != 0)
8369                                         goto progress;
8370                         }
8371                 }
8372 #endif
8373                 goto out;
8374 
8375         }
8376 
8377         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8378                 bad_error("uu_list_walk", uu_error());
8379 
8380 printerr:
8381         /* If the error hasn't been printed yet, do so here. */
8382         switch (cbdata.sc_err) {
8383         case ECONNABORTED:
8384                 warn(gettext("Repository connection broken.\n"));
8385                 break;
8386 
8387         case ENOMEM:
8388                 warn(emsg_nomem);
8389                 break;
8390 
8391         case ENOSPC:
8392                 warn(emsg_nores);
8393                 break;
8394 
8395         case EROFS:
8396                 warn(gettext("Repository is read-only.\n"));
8397                 break;
8398 
8399         case EACCES:
8400                 warn(gettext("Repository backend denied access.\n"));
8401                 break;
8402 
8403         case EPERM:
8404         case EINVAL:
8405         case EEXIST:
8406         case EBUSY:
8407         case EBADF:
8408         case -1:
8409                 break;
8410 
8411         default:
8412                 bad_error("lscf_service_import", cbdata.sc_err);
8413         }
8414 
8415 progress:
8416         warn(gettext("Import of %s failed.  Progress:\n"), filename);
8417 
8418         for (svc = uu_list_first(bndl->sc_bundle_services);
8419             svc != NULL;
8420             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8421                 insts = svc->sc_u.sc_service.sc_service_instances;
8422 
8423                 warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8424                     import_progress(svc->sc_import_state));
8425 
8426                 for (inst = uu_list_first(insts);
8427                     inst != NULL;
8428                     inst = uu_list_next(insts, inst))
8429                         warn(gettext("    Instance \"%s\": %s\n"),
8430                             inst->sc_name,
8431                             import_progress(inst->sc_import_state));
8432         }
8433 
8434         if (cbdata.sc_err == ECONNABORTED)
8435                 repository_teardown();
8436 
8437 
8438         result = -1;
8439 
8440 out:
8441         if (annotation_set != 0) {
8442                 /* Turn off annotation.  It is no longer needed. */
8443                 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8444         }
8445 
8446         free_imp_globals();
8447 
8448         return (result);
8449 }
8450 
8451 /*
8452  * _lscf_import_err() summarize the error handling returned by
8453  * lscf_import_{instance | service}_pgs
8454  * Return values are:
8455  * IMPORT_NEXT
8456  * IMPORT_OUT
8457  * IMPORT_BAD
8458  */
8459 
8460 #define IMPORT_BAD      -1
8461 #define IMPORT_NEXT     0
8462 #define IMPORT_OUT      1
8463 
8464 static int
8465 _lscf_import_err(int err, const char *fmri)
8466 {
8467         switch (err) {
8468         case 0:
8469                 if (g_verbose)
8470                         warn(gettext("%s updated.\n"), fmri);
8471                 return (IMPORT_NEXT);
8472 
8473         case ECONNABORTED:
8474                 warn(gettext("Could not update %s "
8475                     "(repository connection broken).\n"), fmri);
8476                 return (IMPORT_OUT);
8477 
8478         case ENOMEM:
8479                 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8480                 return (IMPORT_OUT);
8481 
8482         case ENOSPC:
8483                 warn(gettext("Could not update %s "
8484                     "(repository server out of resources).\n"), fmri);
8485                 return (IMPORT_OUT);
8486 
8487         case ECANCELED:
8488                 warn(gettext(
8489                     "Could not update %s (deleted).\n"), fmri);
8490                 return (IMPORT_NEXT);
8491 
8492         case EPERM:
8493         case EINVAL:
8494         case EBUSY:
8495                 return (IMPORT_NEXT);
8496 
8497         case EROFS:
8498                 warn(gettext("Could not update %s (repository read-only).\n"),
8499                     fmri);
8500                 return (IMPORT_OUT);
8501 
8502         case EACCES:
8503                 warn(gettext("Could not update %s "
8504                     "(backend access denied).\n"), fmri);
8505                 return (IMPORT_NEXT);
8506 
8507         case EEXIST:
8508         default:
8509                 return (IMPORT_BAD);
8510         }
8511 
8512         /*NOTREACHED*/
8513 }
8514 
8515 /*
8516  * The global imp_svc and imp_inst should be set by the caller in the
8517  * check to make sure the service and instance exist that the apply is
8518  * working on.
8519  */
8520 static int
8521 lscf_dependent_apply(void *dpg, void *e)
8522 {
8523         scf_callback_t cb;
8524         pgroup_t *dpt_pgroup = dpg;
8525         pgroup_t *deldpt;
8526         entity_t *ent = e;
8527         int tissvc;
8528         void *sc_ent, *tent;
8529         scf_error_t serr;
8530         int r;
8531 
8532         const char * const dependents = "dependents";
8533         const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8534 
8535         if (issvc)
8536                 sc_ent = imp_svc;
8537         else
8538                 sc_ent = imp_inst;
8539 
8540         if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8541             imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8542             scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8543             imp_prop) != 0) {
8544                 switch (scf_error()) {
8545                 case SCF_ERROR_NOT_FOUND:
8546                 case SCF_ERROR_DELETED:
8547                         break;
8548 
8549                 case SCF_ERROR_CONNECTION_BROKEN:
8550                 case SCF_ERROR_NOT_SET:
8551                 case SCF_ERROR_INVALID_ARGUMENT:
8552                 case SCF_ERROR_HANDLE_MISMATCH:
8553                 case SCF_ERROR_NOT_BOUND:
8554                 default:
8555                         bad_error("entity_get_pg", scf_error());
8556                 }
8557         } else {
8558                 /*
8559                  * Found the dependents/<wip dep> so check to
8560                  * see if the service is different.  If so
8561                  * store the service for later refresh, and
8562                  * delete the wip dependency from the service
8563                  */
8564                 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8565                         switch (scf_error()) {
8566                                 case SCF_ERROR_DELETED:
8567                                         break;
8568 
8569                                 case SCF_ERROR_CONNECTION_BROKEN:
8570                                 case SCF_ERROR_NOT_SET:
8571                                 case SCF_ERROR_INVALID_ARGUMENT:
8572                                 case SCF_ERROR_HANDLE_MISMATCH:
8573                                 case SCF_ERROR_NOT_BOUND:
8574                                 default:
8575                                         bad_error("scf_property_get_value",
8576                                             scf_error());
8577                         }
8578                 }
8579 
8580                 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8581                     max_scf_value_len + 1) < 0)
8582                         bad_error("scf_value_get_as_string", scf_error());
8583 
8584                 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8585                 switch (r) {
8586                 case 1:
8587                         break;
8588                 case 0:
8589                         if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8590                             &tissvc)) != SCF_ERROR_NONE) {
8591                                 if (serr == SCF_ERROR_NOT_FOUND) {
8592                                         break;
8593                                 } else {
8594                                         bad_error("fmri_to_entity", serr);
8595                                 }
8596                         }
8597 
8598                         if (entity_get_pg(tent, tissvc,
8599                             dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8600                                 serr = scf_error();
8601                                 if (serr == SCF_ERROR_NOT_FOUND ||
8602                                     serr == SCF_ERROR_DELETED) {
8603                                         break;
8604                                 } else {
8605                                         bad_error("entity_get_pg", scf_error());
8606                                 }
8607                         }
8608 
8609                         if (scf_pg_delete(imp_pg) != 0) {
8610                                 serr = scf_error();
8611                                 if (serr == SCF_ERROR_NOT_FOUND ||
8612                                     serr == SCF_ERROR_DELETED) {
8613                                         break;
8614                                 } else {
8615                                         bad_error("scf_pg_delete", scf_error());
8616                                 }
8617                         }
8618 
8619                         deldpt = internal_pgroup_new();
8620                         if (deldpt == NULL)
8621                                 return (ENOMEM);
8622                         deldpt->sc_pgroup_name =
8623                             strdup(dpt_pgroup->sc_pgroup_name);
8624                         deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8625                         if (deldpt->sc_pgroup_name == NULL ||
8626                             deldpt->sc_pgroup_fmri == NULL)
8627                                 return (ENOMEM);
8628                         deldpt->sc_parent = (entity_t *)ent;
8629                         if (uu_list_insert_after(imp_deleted_dpts, NULL,
8630                             deldpt) != 0)
8631                                 uu_die(gettext("libuutil error: %s\n"),
8632                                     uu_strerror(uu_error()));
8633 
8634                         break;
8635                 default:
8636                         bad_error("fmri_equal", r);
8637                 }
8638         }
8639 
8640         cb.sc_handle = g_hndl;
8641         cb.sc_parent = ent;
8642         cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8643         cb.sc_source_fmri = ent->sc_fmri;
8644         cb.sc_target_fmri = ent->sc_fmri;
8645         cb.sc_trans = NULL;
8646         cb.sc_flags = SCI_FORCE;
8647 
8648         if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8649                 return (UU_WALK_ERROR);
8650 
8651         r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8652         switch (r) {
8653         case 0:
8654                 break;
8655 
8656         case ENOMEM:
8657         case ECONNABORTED:
8658         case EPERM:
8659         case -1:
8660                 warn(gettext("Unable to refresh \"%s\"\n"),
8661                     dpt_pgroup->sc_pgroup_fmri);
8662                 return (UU_WALK_ERROR);
8663 
8664         default:
8665                 bad_error("imp_refresh_fmri", r);
8666         }
8667 
8668         return (UU_WALK_NEXT);
8669 }
8670 
8671 /*
8672  * Returns
8673  *   0 - success
8674  *   -1 - lscf_import_instance_pgs() failed.
8675  */
8676 int
8677 lscf_bundle_apply(bundle_t *bndl, const char *file)
8678 {
8679         pgroup_t *old_dpt;
8680         entity_t *svc, *inst;
8681         int annotation_set = 0;
8682         int ret = 0;
8683         int r = 0;
8684 
8685         lscf_prep_hndl();
8686 
8687         if ((ret = alloc_imp_globals()))
8688                 goto out;
8689 
8690         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8691                 scfdie();
8692 
8693         /*
8694          * Set the strings to be used for the security audit annotation
8695          * event.
8696          */
8697         if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8698                 annotation_set = 1;
8699         } else {
8700                 switch (scf_error()) {
8701                 case SCF_ERROR_CONNECTION_BROKEN:
8702                         warn(gettext("Repository connection broken.\n"));
8703                         goto out;
8704 
8705                 case SCF_ERROR_INVALID_ARGUMENT:
8706                 case SCF_ERROR_NOT_BOUND:
8707                 case SCF_ERROR_NO_RESOURCES:
8708                 case SCF_ERROR_INTERNAL:
8709                         bad_error("_scf_set_annotation", scf_error());
8710                         /* NOTREACHED */
8711 
8712                 default:
8713                         /*
8714                          * Do not abort apply operation because of
8715                          * inability to create annotation audit event.
8716                          */
8717                         warn(gettext("_scf_set_annotation() unexpectedly "
8718                             "failed with return code of %d\n"), scf_error());
8719                         break;
8720                 }
8721         }
8722 
8723         for (svc = uu_list_first(bndl->sc_bundle_services);
8724             svc != NULL;
8725             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8726                 int refresh = 0;
8727 
8728                 if (scf_scope_get_service(imp_scope, svc->sc_name,
8729                     imp_svc) != 0) {
8730                         switch (scf_error()) {
8731                         case SCF_ERROR_NOT_FOUND:
8732                                 if (g_verbose)
8733                                         warn(gettext("Ignoring nonexistent "
8734                                             "service %s.\n"), svc->sc_name);
8735                                 continue;
8736 
8737                         default:
8738                                 scfdie();
8739                         }
8740                 }
8741 
8742                 /*
8743                  * If there were missing types in the profile, then need to
8744                  * attempt to find the types.
8745                  */
8746                 if (svc->sc_miss_type) {
8747                         if (uu_list_numnodes(svc->sc_pgroups) &&
8748                             uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8749                             svc, UU_DEFAULT) != 0) {
8750                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8751                                         bad_error("uu_list_walk", uu_error());
8752 
8753                                 ret = -1;
8754                                 continue;
8755                         }
8756 
8757                         for (inst = uu_list_first(
8758                             svc->sc_u.sc_service.sc_service_instances);
8759                             inst != NULL;
8760                             inst = uu_list_next(
8761                             svc->sc_u.sc_service.sc_service_instances, inst)) {
8762                                 /*
8763                                  * If the instance doesn't exist just
8764                                  * skip to the next instance and let the
8765                                  * import note the missing instance.
8766                                  */
8767                                 if (scf_service_get_instance(imp_svc,
8768                                     inst->sc_name, imp_inst) != 0)
8769                                         continue;
8770 
8771                                 if (uu_list_walk(inst->sc_pgroups,
8772                                     find_current_pg_type, inst,
8773                                     UU_DEFAULT) != 0) {
8774                                         if (uu_error() !=
8775                                             UU_ERROR_CALLBACK_FAILED)
8776                                                 bad_error("uu_list_walk",
8777                                                     uu_error());
8778 
8779                                         ret = -1;
8780                                         inst->sc_miss_type = B_TRUE;
8781                                 }
8782                         }
8783                 }
8784 
8785                 /*
8786                  * if we have pgs in the profile, we need to refresh ALL
8787                  * instances of the service
8788                  */
8789                 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8790                         refresh = 1;
8791                         r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8792                             SCI_FORCE | SCI_KEEP);
8793                         switch (_lscf_import_err(r, svc->sc_fmri)) {
8794                         case IMPORT_NEXT:
8795                                 break;
8796 
8797                         case IMPORT_OUT:
8798                                 goto out;
8799 
8800                         case IMPORT_BAD:
8801                         default:
8802                                 bad_error("lscf_import_service_pgs", r);
8803                         }
8804                 }
8805 
8806                 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8807                         uu_list_walk(svc->sc_dependents,
8808                             lscf_dependent_apply, svc, UU_DEFAULT);
8809                 }
8810 
8811                 for (inst = uu_list_first(
8812                     svc->sc_u.sc_service.sc_service_instances);
8813                     inst != NULL;
8814                     inst = uu_list_next(
8815                     svc->sc_u.sc_service.sc_service_instances, inst)) {
8816                         /*
8817                          * This instance still has missing types
8818                          * so skip it.
8819                          */
8820                         if (inst->sc_miss_type) {
8821                                 if (g_verbose)
8822                                         warn(gettext("Ignoring instance "
8823                                             "%s:%s with missing types\n"),
8824                                             inst->sc_parent->sc_name,
8825                                             inst->sc_name);
8826 
8827                                 continue;
8828                         }
8829 
8830                         if (scf_service_get_instance(imp_svc, inst->sc_name,
8831                             imp_inst) != 0) {
8832                                 switch (scf_error()) {
8833                                 case SCF_ERROR_NOT_FOUND:
8834                                         if (g_verbose)
8835                                                 warn(gettext("Ignoring "
8836                                                     "nonexistant instance "
8837                                                     "%s:%s.\n"),
8838                                                     inst->sc_parent->sc_name,
8839                                                     inst->sc_name);
8840                                         continue;
8841 
8842                                 default:
8843                                         scfdie();
8844                                 }
8845                         }
8846 
8847                         /*
8848                          * If the instance does not have a general/enabled
8849                          * property and no last-import snapshot then the
8850                          * instance is not a fully installed instance and
8851                          * should not have a profile applied to it.
8852                          *
8853                          * This could happen if a service/instance declares
8854                          * a dependent on behalf of another service/instance.
8855                          *
8856                          */
8857                         if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8858                             imp_snap) != 0) {
8859                                 if (scf_instance_get_pg(imp_inst,
8860                                     SCF_PG_GENERAL, imp_pg) != 0 ||
8861                                     scf_pg_get_property(imp_pg,
8862                                     SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8863                                         if (g_verbose)
8864                                                 warn(gettext("Ignoreing "
8865                                                     "partial instance "
8866                                                     "%s:%s.\n"),
8867                                                     inst->sc_parent->sc_name,
8868                                                     inst->sc_name);
8869                                         continue;
8870                                 }
8871                         }
8872 
8873                         r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8874                             inst, SCI_FORCE | SCI_KEEP);
8875                         switch (_lscf_import_err(r, inst->sc_fmri)) {
8876                         case IMPORT_NEXT:
8877                                 break;
8878 
8879                         case IMPORT_OUT:
8880                                 goto out;
8881 
8882                         case IMPORT_BAD:
8883                         default:
8884                                 bad_error("lscf_import_instance_pgs", r);
8885                         }
8886 
8887                         if (uu_list_numnodes(inst->sc_dependents) != 0) {
8888                                 uu_list_walk(inst->sc_dependents,
8889                                     lscf_dependent_apply, inst, UU_DEFAULT);
8890                         }
8891 
8892                         /* refresh only if there is no pgs in the service */
8893                         if (refresh == 0)
8894                                 (void) refresh_entity(0, imp_inst,
8895                                     inst->sc_fmri, NULL, NULL, NULL);
8896                 }
8897 
8898                 if (refresh == 1) {
8899                         char *name_buf = safe_malloc(max_scf_name_len + 1);
8900 
8901                         (void) refresh_entity(1, imp_svc, svc->sc_name,
8902                             imp_inst, imp_iter, name_buf);
8903                         free(name_buf);
8904                 }
8905 
8906                 for (old_dpt = uu_list_first(imp_deleted_dpts);
8907                     old_dpt != NULL;
8908                     old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8909                         if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8910                             old_dpt->sc_pgroup_name,
8911                             old_dpt->sc_parent->sc_fmri) != 0) {
8912                                 warn(gettext("Unable to refresh \"%s\"\n"),
8913                                     old_dpt->sc_pgroup_fmri);
8914                         }
8915                 }
8916         }
8917 
8918 out:
8919         if (annotation_set) {
8920                 /* Remove security audit annotation strings. */
8921                 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8922         }
8923 
8924         free_imp_globals();
8925         return (ret);
8926 }
8927 
8928 
8929 /*
8930  * Export.  These functions create and output an XML tree of a service
8931  * description from the repository.  This is largely the inverse of
8932  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8933  *
8934  * - We must include any properties which are not represented specifically by
8935  *   a service manifest, e.g., properties created by an admin post-import.  To
8936  *   do so we'll iterate through all properties and deal with each
8937  *   apropriately.
8938  *
8939  * - Children of services and instances must must be in the order set by the
8940  *   DTD, but we iterate over the properties in undefined order.  The elements
8941  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8942  *   number of classes of them, however, we'll keep the classes separate and
8943  *   assemble them in order.
8944  */
8945 
8946 /*
8947  * Convenience function to handle xmlSetProp errors (and type casting).
8948  */
8949 static void
8950 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8951 {
8952         if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8953                 uu_die(gettext("Could not set XML property.\n"));
8954 }
8955 
8956 /*
8957  * Convenience function to set an XML attribute to the single value of an
8958  * astring property.  If the value happens to be the default, don't set the
8959  * attribute.  "dval" should be the default value supplied by the DTD, or
8960  * NULL for no default.
8961  */
8962 static int
8963 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8964     const char *name, const char *dval)
8965 {
8966         scf_value_t *val;
8967         ssize_t len;
8968         char *str;
8969 
8970         val = scf_value_create(g_hndl);
8971         if (val == NULL)
8972                 scfdie();
8973 
8974         if (prop_get_val(prop, val) != 0) {
8975                 scf_value_destroy(val);
8976                 return (-1);
8977         }
8978 
8979         len = scf_value_get_as_string(val, NULL, 0);
8980         if (len < 0)
8981                 scfdie();
8982 
8983         str = safe_malloc(len + 1);
8984 
8985         if (scf_value_get_as_string(val, str, len + 1) < 0)
8986                 scfdie();
8987 
8988         scf_value_destroy(val);
8989 
8990         if (dval == NULL || strcmp(str, dval) != 0)
8991                 safe_setprop(n, name, str);
8992 
8993         free(str);
8994 
8995         return (0);
8996 }
8997 
8998 /*
8999  * As above, but the attribute is always set.
9000  */
9001 static int
9002 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9003 {
9004         return (set_attr_from_prop_default(prop, n, name, NULL));
9005 }
9006 
9007 /*
9008  * Dump the given document onto f, with "'s replaced by ''s.
9009  */
9010 static int
9011 write_service_bundle(xmlDocPtr doc, FILE *f)
9012 {
9013         xmlChar *mem;
9014         int sz, i;
9015 
9016         mem = NULL;
9017         xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9018 
9019         if (mem == NULL) {
9020                 semerr(gettext("Could not dump XML tree.\n"));
9021                 return (-1);
9022         }
9023 
9024         /*
9025          * Fortunately libxml produces &quot; instead of ", so we can blindly
9026          * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9027          * &apos; code?!
9028          */
9029         for (i = 0; i < sz; ++i) {
9030                 char c = (char)mem[i];
9031 
9032                 if (c == '"')
9033                         (void) fputc('\'', f);
9034                 else if (c == '\'')
9035                         (void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9036                 else
9037                         (void) fputc(c, f);
9038         }
9039 
9040         return (0);
9041 }
9042 
9043 /*
9044  * Create the DOM elements in elts necessary to (generically) represent prop
9045  * (i.e., a property or propval element).  If the name of the property is
9046  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9047  */
9048 static void
9049 export_property(scf_property_t *prop, const char *name_arg,
9050     struct pg_elts *elts, int flags)
9051 {
9052         const char *type;
9053         scf_error_t err = 0;
9054         xmlNodePtr pnode, lnode;
9055         char *lnname;
9056         int ret;
9057 
9058         /* name */
9059         if (name_arg != NULL) {
9060                 (void) strcpy(exp_str, name_arg);
9061         } else {
9062                 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9063                         scfdie();
9064         }
9065 
9066         /* type */
9067         type = prop_to_typestr(prop);
9068         if (type == NULL)
9069                 uu_die(gettext("Can't export property %s: unknown type.\n"),
9070                     exp_str);
9071 
9072         /* If we're exporting values, and there's just one, export it here. */
9073         if (!(flags & SCE_ALL_VALUES))
9074                 goto empty;
9075 
9076         if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9077                 xmlNodePtr n;
9078 
9079                 /* Single value, so use propval */
9080                 n = xmlNewNode(NULL, (xmlChar *)"propval");
9081                 if (n == NULL)
9082                         uu_die(emsg_create_xml);
9083 
9084                 safe_setprop(n, name_attr, exp_str);
9085                 safe_setprop(n, type_attr, type);
9086 
9087                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9088                         scfdie();
9089                 safe_setprop(n, value_attr, exp_str);
9090 
9091                 if (elts->propvals == NULL)
9092                         elts->propvals = n;
9093                 else
9094                         (void) xmlAddSibling(elts->propvals, n);
9095 
9096                 return;
9097         }
9098 
9099         err = scf_error();
9100 
9101         if (err == SCF_ERROR_PERMISSION_DENIED) {
9102                 semerr(emsg_permission_denied);
9103                 return;
9104         }
9105 
9106         if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9107             err != SCF_ERROR_NOT_FOUND &&
9108             err != SCF_ERROR_PERMISSION_DENIED)
9109                 scfdie();
9110 
9111 empty:
9112         /* Multiple (or no) values, so use property */
9113         pnode = xmlNewNode(NULL, (xmlChar *)"property");
9114         if (pnode == NULL)
9115                 uu_die(emsg_create_xml);
9116 
9117         safe_setprop(pnode, name_attr, exp_str);
9118         safe_setprop(pnode, type_attr, type);
9119 
9120         if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9121                 lnname = uu_msprintf("%s_list", type);
9122                 if (lnname == NULL)
9123                         uu_die(gettext("Could not create string"));
9124 
9125                 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9126                 if (lnode == NULL)
9127                         uu_die(emsg_create_xml);
9128 
9129                 uu_free(lnname);
9130 
9131                 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9132                         scfdie();
9133 
9134                 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9135                     1) {
9136                         xmlNodePtr vn;
9137 
9138                         vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9139                             NULL);
9140                         if (vn == NULL)
9141                                 uu_die(emsg_create_xml);
9142 
9143                         if (scf_value_get_as_string(exp_val, exp_str,
9144                             exp_str_sz) < 0)
9145                                 scfdie();
9146                         safe_setprop(vn, value_attr, exp_str);
9147                 }
9148                 if (ret != 0)
9149                         scfdie();
9150         }
9151 
9152         if (elts->properties == NULL)
9153                 elts->properties = pnode;
9154         else
9155                 (void) xmlAddSibling(elts->properties, pnode);
9156 }
9157 
9158 /*
9159  * Add a property_group element for this property group to elts.
9160  */
9161 static void
9162 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9163 {
9164         xmlNodePtr n;
9165         struct pg_elts elts;
9166         int ret;
9167         boolean_t read_protected;
9168 
9169         n = xmlNewNode(NULL, (xmlChar *)"property_group");
9170 
9171         /* name */
9172         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9173                 scfdie();
9174         safe_setprop(n, name_attr, exp_str);
9175 
9176         /* type */
9177         if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9178                 scfdie();
9179         safe_setprop(n, type_attr, exp_str);
9180 
9181         /* properties */
9182         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9183                 scfdie();
9184 
9185         (void) memset(&elts, 0, sizeof (elts));
9186 
9187         /*
9188          * If this property group is not read protected, we always want to
9189          * output all the values.  Otherwise, we only output the values if the
9190          * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9191          */
9192         if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9193                 scfdie();
9194 
9195         if (!read_protected)
9196                 flags |= SCE_ALL_VALUES;
9197 
9198         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9199                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9200                         scfdie();
9201 
9202                 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9203                         xmlNodePtr m;
9204 
9205                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9206                         if (m == NULL)
9207                                 uu_die(emsg_create_xml);
9208 
9209                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9210                                 elts.stability = m;
9211                                 continue;
9212                         }
9213 
9214                         xmlFreeNode(m);
9215                 }
9216 
9217                 export_property(exp_prop, NULL, &elts, flags);
9218         }
9219         if (ret == -1)
9220                 scfdie();
9221 
9222         (void) xmlAddChild(n, elts.stability);
9223         (void) xmlAddChildList(n, elts.propvals);
9224         (void) xmlAddChildList(n, elts.properties);
9225 
9226         if (eelts->property_groups == NULL)
9227                 eelts->property_groups = n;
9228         else
9229                 (void) xmlAddSibling(eelts->property_groups, n);
9230 }
9231 
9232 /*
9233  * Create an XML node representing the dependency described by the given
9234  * property group and put it in eelts.  Unless the dependency is not valid, in
9235  * which case create a generic property_group element which represents it and
9236  * put it in eelts.
9237  */
9238 static void
9239 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9240 {
9241         xmlNodePtr n;
9242         int err = 0, ret;
9243         struct pg_elts elts;
9244 
9245         n = xmlNewNode(NULL, (xmlChar *)"dependency");
9246         if (n == NULL)
9247                 uu_die(emsg_create_xml);
9248 
9249         /*
9250          * If the external flag is present, skip this dependency because it
9251          * should have been created by another manifest.
9252          */
9253         if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9254                 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9255                     prop_get_val(exp_prop, exp_val) == 0) {
9256                         uint8_t b;
9257 
9258                         if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9259                                 scfdie();
9260 
9261                         if (b)
9262                                 return;
9263                 }
9264         } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9265                 scfdie();
9266 
9267         /* Get the required attributes. */
9268 
9269         /* name */
9270         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9271                 scfdie();
9272         safe_setprop(n, name_attr, exp_str);
9273 
9274         /* grouping */
9275         if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9276             set_attr_from_prop(exp_prop, n, "grouping") != 0)
9277                 err = 1;
9278 
9279         /* restart_on */
9280         if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9281             set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9282                 err = 1;
9283 
9284         /* type */
9285         if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9286             set_attr_from_prop(exp_prop, n, type_attr) != 0)
9287                 err = 1;
9288 
9289         /*
9290          * entities: Not required, but if we create no children, it will be
9291          * created as empty on import, so fail if it's missing.
9292          */
9293         if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9294             prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9295                 scf_iter_t *eiter;
9296                 int ret2;
9297 
9298                 eiter = scf_iter_create(g_hndl);
9299                 if (eiter == NULL)
9300                         scfdie();
9301 
9302                 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9303                         scfdie();
9304 
9305                 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9306                         xmlNodePtr ch;
9307 
9308                         if (scf_value_get_astring(exp_val, exp_str,
9309                             exp_str_sz) < 0)
9310                                 scfdie();
9311 
9312                         /*
9313                          * service_fmri's must be first, so we can add them
9314                          * here.
9315                          */
9316                         ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9317                             NULL);
9318                         if (ch == NULL)
9319                                 uu_die(emsg_create_xml);
9320 
9321                         safe_setprop(ch, value_attr, exp_str);
9322                 }
9323                 if (ret2 == -1)
9324                         scfdie();
9325 
9326                 scf_iter_destroy(eiter);
9327         } else
9328                 err = 1;
9329 
9330         if (err) {
9331                 xmlFreeNode(n);
9332 
9333                 export_pg(pg, eelts, SCE_ALL_VALUES);
9334 
9335                 return;
9336         }
9337 
9338         /* Iterate through the properties & handle each. */
9339         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9340                 scfdie();
9341 
9342         (void) memset(&elts, 0, sizeof (elts));
9343 
9344         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9345                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9346                         scfdie();
9347 
9348                 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9349                     strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9350                     strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9351                     strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9352                         continue;
9353                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9354                         xmlNodePtr m;
9355 
9356                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9357                         if (m == NULL)
9358                                 uu_die(emsg_create_xml);
9359 
9360                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9361                                 elts.stability = m;
9362                                 continue;
9363                         }
9364 
9365                         xmlFreeNode(m);
9366                 }
9367 
9368                 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9369         }
9370         if (ret == -1)
9371                 scfdie();
9372 
9373         (void) xmlAddChild(n, elts.stability);
9374         (void) xmlAddChildList(n, elts.propvals);
9375         (void) xmlAddChildList(n, elts.properties);
9376 
9377         if (eelts->dependencies == NULL)
9378                 eelts->dependencies = n;
9379         else
9380                 (void) xmlAddSibling(eelts->dependencies, n);
9381 }
9382 
9383 static xmlNodePtr
9384 export_method_environment(scf_propertygroup_t *pg)
9385 {
9386         xmlNodePtr env;
9387         int ret;
9388         int children = 0;
9389 
9390         if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9391                 return (NULL);
9392 
9393         env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9394         if (env == NULL)
9395                 uu_die(emsg_create_xml);
9396 
9397         if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9398                 scfdie();
9399 
9400         if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9401                 scfdie();
9402 
9403         while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9404                 xmlNodePtr ev;
9405                 char *cp;
9406 
9407                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9408                         scfdie();
9409 
9410                 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9411                         warn(gettext("Invalid environment variable \"%s\".\n"),
9412                             exp_str);
9413                         continue;
9414                 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9415                         warn(gettext("Invalid environment variable \"%s\"; "
9416                             "\"SMF_\" prefix is reserved.\n"), exp_str);
9417                         continue;
9418                 }
9419 
9420                 *cp = '\0';
9421                 cp++;
9422 
9423                 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9424                 if (ev == NULL)
9425                         uu_die(emsg_create_xml);
9426 
9427                 safe_setprop(ev, name_attr, exp_str);
9428                 safe_setprop(ev, value_attr, cp);
9429                 children++;
9430         }
9431 
9432         if (ret != 0)
9433                 scfdie();
9434 
9435         if (children == 0) {
9436                 xmlFreeNode(env);
9437                 return (NULL);
9438         }
9439 
9440         return (env);
9441 }
9442 
9443 /*
9444  * As above, but for a method property group.
9445  */
9446 static void
9447 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9448 {
9449         xmlNodePtr n, env;
9450         char *str;
9451         int err = 0, nonenv, ret;
9452         uint8_t use_profile;
9453         struct pg_elts elts;
9454         xmlNodePtr ctxt = NULL;
9455 
9456         n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9457 
9458         /* Get the required attributes. */
9459 
9460         /* name */
9461         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9462                 scfdie();
9463         safe_setprop(n, name_attr, exp_str);
9464 
9465         /* type */
9466         if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9467             set_attr_from_prop(exp_prop, n, type_attr) != 0)
9468                 err = 1;
9469 
9470         /* exec */
9471         if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9472             set_attr_from_prop(exp_prop, n, "exec") != 0)
9473                 err = 1;
9474 
9475         /* timeout */
9476         if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9477             prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9478             prop_get_val(exp_prop, exp_val) == 0) {
9479                 uint64_t c;
9480 
9481                 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9482                         scfdie();
9483 
9484                 str = uu_msprintf("%llu", c);
9485                 if (str == NULL)
9486                         uu_die(gettext("Could not create string"));
9487 
9488                 safe_setprop(n, "timeout_seconds", str);
9489                 free(str);
9490         } else
9491                 err = 1;
9492 
9493         if (err) {
9494                 xmlFreeNode(n);
9495 
9496                 export_pg(pg, eelts, SCE_ALL_VALUES);
9497 
9498                 return;
9499         }
9500 
9501 
9502         /*
9503          * If we're going to have a method_context child, we need to know
9504          * before we iterate through the properties.  Since method_context's
9505          * are optional, we don't want to complain about any properties
9506          * missing if none of them are there.  Thus we can't use the
9507          * convenience functions.
9508          */
9509         nonenv =
9510             scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9511             SCF_SUCCESS ||
9512             scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9513             SCF_SUCCESS ||
9514             scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9515             SCF_SUCCESS ||
9516             scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9517             SCF_SUCCESS ||
9518             scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9519             SCF_SUCCESS;
9520 
9521         if (nonenv) {
9522                 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9523                 if (ctxt == NULL)
9524                         uu_die(emsg_create_xml);
9525 
9526                 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9527                     0 &&
9528                     set_attr_from_prop_default(exp_prop, ctxt,
9529                     "working_directory", ":default") != 0)
9530                         err = 1;
9531 
9532                 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9533                     set_attr_from_prop_default(exp_prop, ctxt, "project",
9534                     ":default") != 0)
9535                         err = 1;
9536 
9537                 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9538                     0 &&
9539                     set_attr_from_prop_default(exp_prop, ctxt,
9540                     "resource_pool", ":default") != 0)
9541                         err = 1;
9542 
9543                 if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9544                     set_attr_from_prop_default(exp_prop, ctxt,
9545                     "security_flags", ":default") != 0)
9546                         err = 1;
9547 
9548                 /*
9549                  * We only want to complain about profile or credential
9550                  * properties if we will use them.  To determine that we must
9551                  * examine USE_PROFILE.
9552                  */
9553                 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9554                     prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9555                     prop_get_val(exp_prop, exp_val) == 0) {
9556                         if (scf_value_get_boolean(exp_val, &use_profile) !=
9557                             SCF_SUCCESS) {
9558                                 scfdie();
9559                         }
9560 
9561                         if (use_profile) {
9562                                 xmlNodePtr prof;
9563 
9564                                 prof = xmlNewChild(ctxt, NULL,
9565                                     (xmlChar *)"method_profile", NULL);
9566                                 if (prof == NULL)
9567                                         uu_die(emsg_create_xml);
9568 
9569                                 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9570                                     exp_prop) != 0 ||
9571                                     set_attr_from_prop(exp_prop, prof,
9572                                     name_attr) != 0)
9573                                         err = 1;
9574                         } else {
9575                                 xmlNodePtr cred;
9576 
9577                                 cred = xmlNewChild(ctxt, NULL,
9578                                     (xmlChar *)"method_credential", NULL);
9579                                 if (cred == NULL)
9580                                         uu_die(emsg_create_xml);
9581 
9582                                 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9583                                     exp_prop) != 0 ||
9584                                     set_attr_from_prop(exp_prop, cred,
9585                                     "user") != 0) {
9586                                         err = 1;
9587                                 }
9588 
9589                                 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9590                                     exp_prop) == 0 &&
9591                                     set_attr_from_prop_default(exp_prop, cred,
9592                                     "group", ":default") != 0)
9593                                         err = 1;
9594 
9595                                 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9596                                     exp_prop) == 0 &&
9597                                     set_attr_from_prop_default(exp_prop, cred,
9598                                     "supp_groups", ":default") != 0)
9599                                         err = 1;
9600 
9601                                 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9602                                     exp_prop) == 0 &&
9603                                     set_attr_from_prop_default(exp_prop, cred,
9604                                     "privileges", ":default") != 0)
9605                                         err = 1;
9606 
9607                                 if (pg_get_prop(pg,
9608                                     SCF_PROPERTY_LIMIT_PRIVILEGES,
9609                                     exp_prop) == 0 &&
9610                                     set_attr_from_prop_default(exp_prop, cred,
9611                                     "limit_privileges", ":default") != 0)
9612                                         err = 1;
9613                         }
9614                 }
9615         }
9616 
9617         if ((env = export_method_environment(pg)) != NULL) {
9618                 if (ctxt == NULL) {
9619                         ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9620                         if (ctxt == NULL)
9621                                 uu_die(emsg_create_xml);
9622                 }
9623                 (void) xmlAddChild(ctxt, env);
9624         }
9625 
9626         if (env != NULL || (nonenv && err == 0))
9627                 (void) xmlAddChild(n, ctxt);
9628         else
9629                 xmlFreeNode(ctxt);
9630 
9631         nonenv = (err == 0);
9632 
9633         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9634                 scfdie();
9635 
9636         (void) memset(&elts, 0, sizeof (elts));
9637 
9638         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9639                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9640                         scfdie();
9641 
9642                 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9643                     strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9644                     strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9645                         continue;
9646                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9647                         xmlNodePtr m;
9648 
9649                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9650                         if (m == NULL)
9651                                 uu_die(emsg_create_xml);
9652 
9653                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9654                                 elts.stability = m;
9655                                 continue;
9656                         }
9657 
9658                         xmlFreeNode(m);
9659                 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9660                     0 ||
9661                     strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9662                     strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9663                     strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9664                         if (nonenv)
9665                                 continue;
9666                 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9667                     strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9668                     strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9669                     strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9670                     strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9671                     strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9672                         if (nonenv && !use_profile)
9673                                 continue;
9674                 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9675                         if (nonenv && use_profile)
9676                                 continue;
9677                 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9678                         if (env != NULL)
9679                                 continue;
9680                 }
9681 
9682                 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9683         }
9684         if (ret == -1)
9685                 scfdie();
9686 
9687         (void) xmlAddChild(n, elts.stability);
9688         (void) xmlAddChildList(n, elts.propvals);
9689         (void) xmlAddChildList(n, elts.properties);
9690 
9691         if (eelts->exec_methods == NULL)
9692                 eelts->exec_methods = n;
9693         else
9694                 (void) xmlAddSibling(eelts->exec_methods, n);
9695 }
9696 
9697 static void
9698 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9699     struct entity_elts *eelts)
9700 {
9701         xmlNodePtr pgnode;
9702 
9703         pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9704         if (pgnode == NULL)
9705                 uu_die(emsg_create_xml);
9706 
9707         safe_setprop(pgnode, name_attr, name);
9708         safe_setprop(pgnode, type_attr, type);
9709 
9710         (void) xmlAddChildList(pgnode, elts->propvals);
9711         (void) xmlAddChildList(pgnode, elts->properties);
9712 
9713         if (eelts->property_groups == NULL)
9714                 eelts->property_groups = pgnode;
9715         else
9716                 (void) xmlAddSibling(eelts->property_groups, pgnode);
9717 }
9718 
9719 /*
9720  * Process the general property group for a service.  This is the one with the
9721  * goodies.
9722  */
9723 static void
9724 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9725 {
9726         struct pg_elts elts;
9727         int ret;
9728 
9729         /*
9730          * In case there are properties which don't correspond to child
9731          * entities of the service entity, we'll set up a pg_elts structure to
9732          * put them in.
9733          */
9734         (void) memset(&elts, 0, sizeof (elts));
9735 
9736         /* Walk the properties, looking for special ones. */
9737         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9738                 scfdie();
9739 
9740         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9741                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9742                         scfdie();
9743 
9744                 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9745                         if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9746                             prop_get_val(exp_prop, exp_val) == 0) {
9747                                 uint8_t b;
9748 
9749                                 if (scf_value_get_boolean(exp_val, &b) !=
9750                                     SCF_SUCCESS)
9751                                         scfdie();
9752 
9753                                 if (b) {
9754                                         selts->single_instance =
9755                                             xmlNewNode(NULL,
9756                                             (xmlChar *)"single_instance");
9757                                         if (selts->single_instance == NULL)
9758                                                 uu_die(emsg_create_xml);
9759                                 }
9760 
9761                                 continue;
9762                         }
9763                 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9764                         xmlNodePtr rnode, sfnode;
9765 
9766                         rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9767                         if (rnode == NULL)
9768                                 uu_die(emsg_create_xml);
9769 
9770                         sfnode = xmlNewChild(rnode, NULL,
9771                             (xmlChar *)"service_fmri", NULL);
9772                         if (sfnode == NULL)
9773                                 uu_die(emsg_create_xml);
9774 
9775                         if (set_attr_from_prop(exp_prop, sfnode,
9776                             value_attr) == 0) {
9777                                 selts->restarter = rnode;
9778                                 continue;
9779                         }
9780 
9781                         xmlFreeNode(rnode);
9782                 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9783                     0) {
9784                         xmlNodePtr s;
9785 
9786                         s = xmlNewNode(NULL, (xmlChar *)"stability");
9787                         if (s == NULL)
9788                                 uu_die(emsg_create_xml);
9789 
9790                         if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9791                                 selts->stability = s;
9792                                 continue;
9793                         }
9794 
9795                         xmlFreeNode(s);
9796                 }
9797 
9798                 export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9799         }
9800         if (ret == -1)
9801                 scfdie();
9802 
9803         if (elts.propvals != NULL || elts.properties != NULL)
9804                 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9805                     selts);
9806 }
9807 
9808 static void
9809 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9810 {
9811         xmlNodePtr n, prof, cred, env;
9812         uint8_t use_profile;
9813         int ret, err = 0;
9814 
9815         n = xmlNewNode(NULL, (xmlChar *)"method_context");
9816 
9817         env = export_method_environment(pg);
9818 
9819         /* Need to know whether we'll use a profile or not. */
9820         if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9821             prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9822             prop_get_val(exp_prop, exp_val) == 0) {
9823                 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9824                         scfdie();
9825 
9826                 if (use_profile)
9827                         prof =
9828                             xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9829                             NULL);
9830                 else
9831                         cred =
9832                             xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9833                             NULL);
9834         }
9835 
9836         if (env != NULL)
9837                 (void) xmlAddChild(n, env);
9838 
9839         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9840                 scfdie();
9841 
9842         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9843                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9844                         scfdie();
9845 
9846                 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9847                         if (set_attr_from_prop(exp_prop, n,
9848                             "working_directory") != 0)
9849                                 err = 1;
9850                 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9851                         if (set_attr_from_prop(exp_prop, n, "project") != 0)
9852                                 err = 1;
9853                 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9854                         if (set_attr_from_prop(exp_prop, n,
9855                             "resource_pool") != 0)
9856                                 err = 1;
9857                 } else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9858                         if (set_attr_from_prop(exp_prop, n,
9859                             "security_flags") != 0)
9860                                 err = 1;
9861                 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9862                         /* EMPTY */
9863                 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9864                         if (use_profile ||
9865                             set_attr_from_prop(exp_prop, cred, "user") != 0)
9866                                 err = 1;
9867                 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9868                         if (use_profile ||
9869                             set_attr_from_prop(exp_prop, cred, "group") != 0)
9870                                 err = 1;
9871                 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9872                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9873                             "supp_groups") != 0)
9874                                 err = 1;
9875                 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9876                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9877                             "privileges") != 0)
9878                                 err = 1;
9879                 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9880                     0) {
9881                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9882                             "limit_privileges") != 0)
9883                                 err = 1;
9884                 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9885                         if (!use_profile || set_attr_from_prop(exp_prop,
9886                             prof, name_attr) != 0)
9887                                 err = 1;
9888                 } else {
9889                         /* Can't have generic properties in method_context's */
9890                         err = 1;
9891                 }
9892         }
9893         if (ret == -1)
9894                 scfdie();
9895 
9896         if (err && env == NULL) {
9897                 xmlFreeNode(n);
9898                 export_pg(pg, elts, SCE_ALL_VALUES);
9899                 return;
9900         }
9901 
9902         elts->method_context = n;
9903 }
9904 
9905 /*
9906  * Given a dependency property group in the tfmri entity (target fmri), return
9907  * a dependent element which represents it.
9908  */
9909 static xmlNodePtr
9910 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9911 {
9912         uint8_t b;
9913         xmlNodePtr n, sf;
9914         int err = 0, ret;
9915         struct pg_elts pgelts;
9916 
9917         /*
9918          * If external isn't set to true then exporting the service will
9919          * export this as a normal dependency, so we should stop to avoid
9920          * duplication.
9921          */
9922         if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9923             scf_property_get_value(exp_prop, exp_val) != 0 ||
9924             scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9925                 if (g_verbose) {
9926                         warn(gettext("Dependent \"%s\" cannot be exported "
9927                             "properly because the \"%s\" property of the "
9928                             "\"%s\" dependency of %s is not set to true.\n"),
9929                             name, scf_property_external, name, tfmri);
9930                 }
9931 
9932                 return (NULL);
9933         }
9934 
9935         n = xmlNewNode(NULL, (xmlChar *)"dependent");
9936         if (n == NULL)
9937                 uu_die(emsg_create_xml);
9938 
9939         safe_setprop(n, name_attr, name);
9940 
9941         /* Get the required attributes */
9942         if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9943             set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9944                 err = 1;
9945 
9946         if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9947             set_attr_from_prop(exp_prop, n, "grouping") != 0)
9948                 err = 1;
9949 
9950         if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9951             prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9952             prop_get_val(exp_prop, exp_val) == 0) {
9953                 /* EMPTY */
9954         } else
9955                 err = 1;
9956 
9957         if (err) {
9958                 xmlFreeNode(n);
9959                 return (NULL);
9960         }
9961 
9962         sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9963         if (sf == NULL)
9964                 uu_die(emsg_create_xml);
9965 
9966         safe_setprop(sf, value_attr, tfmri);
9967 
9968         /*
9969          * Now add elements for the other properties.
9970          */
9971         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9972                 scfdie();
9973 
9974         (void) memset(&pgelts, 0, sizeof (pgelts));
9975 
9976         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9977                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9978                         scfdie();
9979 
9980                 if (strcmp(exp_str, scf_property_external) == 0 ||
9981                     strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9982                     strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9983                     strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9984                         continue;
9985                 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9986                         if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9987                             prop_get_val(exp_prop, exp_val) == 0) {
9988                                 char type[sizeof ("service") + 1];
9989 
9990                                 if (scf_value_get_astring(exp_val, type,
9991                                     sizeof (type)) < 0)
9992                                         scfdie();
9993 
9994                                 if (strcmp(type, "service") == 0)
9995                                         continue;
9996                         }
9997                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9998                         xmlNodePtr s;
9999 
10000                         s = xmlNewNode(NULL, (xmlChar *)"stability");
10001                         if (s == NULL)
10002                                 uu_die(emsg_create_xml);
10003 
10004                         if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10005                                 pgelts.stability = s;
10006                                 continue;
10007                         }
10008 
10009                         xmlFreeNode(s);
10010                 }
10011 
10012                 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10013         }
10014         if (ret == -1)
10015                 scfdie();
10016 
10017         (void) xmlAddChild(n, pgelts.stability);
10018         (void) xmlAddChildList(n, pgelts.propvals);
10019         (void) xmlAddChildList(n, pgelts.properties);
10020 
10021         return (n);
10022 }
10023 
10024 static void
10025 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10026 {
10027         scf_propertygroup_t *opg;
10028         scf_iter_t *iter;
10029         char *type, *fmri;
10030         int ret;
10031         struct pg_elts pgelts;
10032         xmlNodePtr n;
10033         scf_error_t serr;
10034 
10035         if ((opg = scf_pg_create(g_hndl)) == NULL ||
10036             (iter = scf_iter_create(g_hndl)) == NULL)
10037                 scfdie();
10038 
10039         /* Can't use exp_prop_iter due to export_dependent(). */
10040         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10041                 scfdie();
10042 
10043         type = safe_malloc(max_scf_pg_type_len + 1);
10044 
10045         /* Get an extra byte so we can tell if values are too long. */
10046         fmri = safe_malloc(max_scf_fmri_len + 2);
10047 
10048         (void) memset(&pgelts, 0, sizeof (pgelts));
10049 
10050         while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10051                 void *entity;
10052                 int isservice;
10053                 scf_type_t ty;
10054 
10055                 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10056                         scfdie();
10057 
10058                 if ((ty != SCF_TYPE_ASTRING &&
10059                     prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10060                     prop_get_val(exp_prop, exp_val) != 0) {
10061                         export_property(exp_prop, NULL, &pgelts,
10062                             SCE_ALL_VALUES);
10063                         continue;
10064                 }
10065 
10066                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10067                         scfdie();
10068 
10069                 if (scf_value_get_astring(exp_val, fmri,
10070                     max_scf_fmri_len + 2) < 0)
10071                         scfdie();
10072 
10073                 /* Look for a dependency group in the target fmri. */
10074                 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10075                 switch (serr) {
10076                 case SCF_ERROR_NONE:
10077                         break;
10078 
10079                 case SCF_ERROR_NO_MEMORY:
10080                         uu_die(gettext("Out of memory.\n"));
10081                         /* NOTREACHED */
10082 
10083                 case SCF_ERROR_INVALID_ARGUMENT:
10084                         if (g_verbose) {
10085                                 if (scf_property_to_fmri(exp_prop, fmri,
10086                                     max_scf_fmri_len + 2) < 0)
10087                                         scfdie();
10088 
10089                                 warn(gettext("The value of %s is not a valid "
10090                                     "FMRI.\n"), fmri);
10091                         }
10092 
10093                         export_property(exp_prop, exp_str, &pgelts,
10094                             SCE_ALL_VALUES);
10095                         continue;
10096 
10097                 case SCF_ERROR_CONSTRAINT_VIOLATED:
10098                         if (g_verbose) {
10099                                 if (scf_property_to_fmri(exp_prop, fmri,
10100                                     max_scf_fmri_len + 2) < 0)
10101                                         scfdie();
10102 
10103                                 warn(gettext("The value of %s does not specify "
10104                                     "a service or an instance.\n"), fmri);
10105                         }
10106 
10107                         export_property(exp_prop, exp_str, &pgelts,
10108                             SCE_ALL_VALUES);
10109                         continue;
10110 
10111                 case SCF_ERROR_NOT_FOUND:
10112                         if (g_verbose) {
10113                                 if (scf_property_to_fmri(exp_prop, fmri,
10114                                     max_scf_fmri_len + 2) < 0)
10115                                         scfdie();
10116 
10117                                 warn(gettext("The entity specified by %s does "
10118                                     "not exist.\n"), fmri);
10119                         }
10120 
10121                         export_property(exp_prop, exp_str, &pgelts,
10122                             SCE_ALL_VALUES);
10123                         continue;
10124 
10125                 default:
10126 #ifndef NDEBUG
10127                         (void) fprintf(stderr, "%s:%d: %s() failed with "
10128                             "unexpected error %d.\n", __FILE__, __LINE__,
10129                             "fmri_to_entity", serr);
10130 #endif
10131                         abort();
10132                 }
10133 
10134                 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10135                         if (scf_error() != SCF_ERROR_NOT_FOUND)
10136                                 scfdie();
10137 
10138                         warn(gettext("Entity %s is missing dependency property "
10139                             "group %s.\n"), fmri, exp_str);
10140 
10141                         export_property(exp_prop, NULL, &pgelts,
10142                             SCE_ALL_VALUES);
10143                         continue;
10144                 }
10145 
10146                 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10147                         scfdie();
10148 
10149                 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10150                         if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10151                                 scfdie();
10152 
10153                         warn(gettext("Property group %s is not of "
10154                             "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10155 
10156                         export_property(exp_prop, NULL, &pgelts,
10157                             SCE_ALL_VALUES);
10158                         continue;
10159                 }
10160 
10161                 n = export_dependent(opg, exp_str, fmri);
10162                 if (n == NULL) {
10163                         export_property(exp_prop, exp_str, &pgelts,
10164                             SCE_ALL_VALUES);
10165                 } else {
10166                         if (eelts->dependents == NULL)
10167                                 eelts->dependents = n;
10168                         else
10169                                 (void) xmlAddSibling(eelts->dependents,
10170                                     n);
10171                 }
10172         }
10173         if (ret == -1)
10174                 scfdie();
10175 
10176         free(fmri);
10177         free(type);
10178 
10179         scf_iter_destroy(iter);
10180         scf_pg_destroy(opg);
10181 
10182         if (pgelts.propvals != NULL || pgelts.properties != NULL)
10183                 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10184                     eelts);
10185 }
10186 
10187 static void
10188 make_node(xmlNodePtr *nodep, const char *name)
10189 {
10190         if (*nodep == NULL) {
10191                 *nodep = xmlNewNode(NULL, (xmlChar *)name);
10192                 if (*nodep == NULL)
10193                         uu_die(emsg_create_xml);
10194         }
10195 }
10196 
10197 static xmlNodePtr
10198 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10199 {
10200         int ret;
10201         xmlNodePtr parent = NULL;
10202         xmlNodePtr loctext = NULL;
10203 
10204         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10205                 scfdie();
10206 
10207         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10208                 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10209                     prop_get_val(exp_prop, exp_val) != 0)
10210                         continue;
10211 
10212                 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10213                         scfdie();
10214 
10215                 make_node(&parent, parname);
10216                 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10217                     (xmlChar *)exp_str);
10218                 if (loctext == NULL)
10219                         uu_die(emsg_create_xml);
10220 
10221                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10222                         scfdie();
10223 
10224                 safe_setprop(loctext, "xml:lang", exp_str);
10225         }
10226 
10227         if (ret == -1)
10228                 scfdie();
10229 
10230         return (parent);
10231 }
10232 
10233 static xmlNodePtr
10234 export_tm_manpage(scf_propertygroup_t *pg)
10235 {
10236         xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10237         if (manpage == NULL)
10238                 uu_die(emsg_create_xml);
10239 
10240         if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10241             set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10242             pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10243             set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10244                 xmlFreeNode(manpage);
10245                 return (NULL);
10246         }
10247 
10248         if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10249                 (void) set_attr_from_prop_default(exp_prop,
10250                     manpage, "manpath", ":default");
10251 
10252         return (manpage);
10253 }
10254 
10255 static xmlNodePtr
10256 export_tm_doc_link(scf_propertygroup_t *pg)
10257 {
10258         xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10259         if (doc_link == NULL)
10260                 uu_die(emsg_create_xml);
10261 
10262         if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10263             set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10264             pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10265             set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10266                 xmlFreeNode(doc_link);
10267                 return (NULL);
10268         }
10269         return (doc_link);
10270 }
10271 
10272 /*
10273  * Process template information for a service or instances.
10274  */
10275 static void
10276 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10277     struct template_elts *telts)
10278 {
10279         size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10280         size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10281         xmlNodePtr child = NULL;
10282 
10283         if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10284                 scfdie();
10285 
10286         if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10287                 telts->common_name = export_tm_loctext(pg, "common_name");
10288                 if (telts->common_name == NULL)
10289                         export_pg(pg, elts, SCE_ALL_VALUES);
10290                 return;
10291         } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10292                 telts->description = export_tm_loctext(pg, "description");
10293                 if (telts->description == NULL)
10294                         export_pg(pg, elts, SCE_ALL_VALUES);
10295                 return;
10296         }
10297 
10298         if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10299                 child = export_tm_manpage(pg);
10300         } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10301                 child = export_tm_doc_link(pg);
10302         }
10303 
10304         if (child != NULL) {
10305                 make_node(&telts->documentation, "documentation");
10306                 (void) xmlAddChild(telts->documentation, child);
10307         } else {
10308                 export_pg(pg, elts, SCE_ALL_VALUES);
10309         }
10310 }
10311 
10312 /*
10313  * Process parameter and paramval elements
10314  */
10315 static void
10316 export_parameter(scf_property_t *prop, const char *name,
10317     struct params_elts *elts)
10318 {
10319         xmlNodePtr param;
10320         scf_error_t err = 0;
10321         int ret;
10322 
10323         if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10324                 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10325                         uu_die(emsg_create_xml);
10326 
10327                 safe_setprop(param, name_attr, name);
10328 
10329                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10330                         scfdie();
10331                 safe_setprop(param, value_attr, exp_str);
10332 
10333                 if (elts->paramval == NULL)
10334                         elts->paramval = param;
10335                 else
10336                         (void) xmlAddSibling(elts->paramval, param);
10337 
10338                 return;
10339         }
10340 
10341         err = scf_error();
10342 
10343         if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10344             err != SCF_ERROR_NOT_FOUND)
10345                 scfdie();
10346 
10347         if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10348                 uu_die(emsg_create_xml);
10349 
10350         safe_setprop(param, name_attr, name);
10351 
10352         if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10353                 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10354                         scfdie();
10355 
10356                 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10357                     1) {
10358                         xmlNodePtr vn;
10359 
10360                         if ((vn = xmlNewChild(param, NULL,
10361                             (xmlChar *)"value_node", NULL)) == NULL)
10362                                 uu_die(emsg_create_xml);
10363 
10364                         if (scf_value_get_as_string(exp_val, exp_str,
10365                             exp_str_sz) < 0)
10366                                 scfdie();
10367 
10368                         safe_setprop(vn, value_attr, exp_str);
10369                 }
10370                 if (ret != 0)
10371                         scfdie();
10372         }
10373 
10374         if (elts->parameter == NULL)
10375                 elts->parameter = param;
10376         else
10377                 (void) xmlAddSibling(elts->parameter, param);
10378 }
10379 
10380 /*
10381  * Process notification parameters for a service or instance
10382  */
10383 static void
10384 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10385 {
10386         xmlNodePtr n, event, *type;
10387         struct params_elts *eelts;
10388         int ret, err, i;
10389 
10390         n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10391         event = xmlNewNode(NULL, (xmlChar *)"event");
10392         if (n == NULL || event == NULL)
10393                 uu_die(emsg_create_xml);
10394 
10395         /* event value */
10396         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10397                 scfdie();
10398         safe_setprop(event, value_attr, exp_str);
10399 
10400         (void) xmlAddChild(n, event);
10401 
10402         if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10403             (eelts = calloc(URI_SCHEME_NUM,
10404             sizeof (struct params_elts))) == NULL)
10405                 uu_die(gettext("Out of memory.\n"));
10406 
10407         err = 0;
10408 
10409         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10410                 scfdie();
10411 
10412         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10413                 char *t, *p;
10414 
10415                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10416                         scfdie();
10417 
10418                 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10419                         /*
10420                          * this is not a well formed notification parameters
10421                          * element, we should export as regular pg
10422                          */
10423                         err = 1;
10424                         break;
10425                 }
10426 
10427                 if ((i = check_uri_protocol(t)) < 0) {
10428                         err = 1;
10429                         break;
10430                 }
10431 
10432                 if (type[i] == NULL) {
10433                         if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10434                             NULL)
10435                                 uu_die(emsg_create_xml);
10436 
10437                         safe_setprop(type[i], name_attr, t);
10438                 }
10439                 if (strcmp(p, active_attr) == 0) {
10440                         if (set_attr_from_prop(exp_prop, type[i],
10441                             active_attr) != 0) {
10442                                 err = 1;
10443                                 break;
10444                         }
10445                         continue;
10446                 }
10447                 /*
10448                  * We export the parameter
10449                  */
10450                 export_parameter(exp_prop, p, &eelts[i]);
10451         }
10452 
10453         if (ret == -1)
10454                 scfdie();
10455 
10456         if (err == 1) {
10457                 for (i = 0; i < URI_SCHEME_NUM; ++i)
10458                         xmlFree(type[i]);
10459                 free(type);
10460 
10461                 export_pg(pg, elts, SCE_ALL_VALUES);
10462 
10463                 return;
10464         } else {
10465                 for (i = 0; i < URI_SCHEME_NUM; ++i)
10466                         if (type[i] != NULL) {
10467                                 (void) xmlAddChildList(type[i],
10468                                     eelts[i].paramval);
10469                                 (void) xmlAddChildList(type[i],
10470                                     eelts[i].parameter);
10471                                 (void) xmlAddSibling(event, type[i]);
10472                         }
10473         }
10474         free(type);
10475 
10476         if (elts->notify_params == NULL)
10477                 elts->notify_params = n;
10478         else
10479                 (void) xmlAddSibling(elts->notify_params, n);
10480 }
10481 
10482 /*
10483  * Process the general property group for an instance.
10484  */
10485 static void
10486 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10487     struct entity_elts *elts)
10488 {
10489         uint8_t enabled;
10490         struct pg_elts pgelts;
10491         int ret;
10492 
10493         /* enabled */
10494         if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10495             prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10496             prop_get_val(exp_prop, exp_val) == 0) {
10497                 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10498                         scfdie();
10499         } else {
10500                 enabled = 0;
10501         }
10502 
10503         safe_setprop(inode, enabled_attr, enabled ? true : false);
10504 
10505         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10506                 scfdie();
10507 
10508         (void) memset(&pgelts, 0, sizeof (pgelts));
10509 
10510         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10511                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10512                         scfdie();
10513 
10514                 if (strcmp(exp_str, scf_property_enabled) == 0) {
10515                         continue;
10516                 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10517                         xmlNodePtr rnode, sfnode;
10518 
10519                         rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10520                         if (rnode == NULL)
10521                                 uu_die(emsg_create_xml);
10522 
10523                         sfnode = xmlNewChild(rnode, NULL,
10524                             (xmlChar *)"service_fmri", NULL);
10525                         if (sfnode == NULL)
10526                                 uu_die(emsg_create_xml);
10527 
10528                         if (set_attr_from_prop(exp_prop, sfnode,
10529                             value_attr) == 0) {
10530                                 elts->restarter = rnode;
10531                                 continue;
10532                         }
10533 
10534                         xmlFreeNode(rnode);
10535                 }
10536 
10537                 export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10538         }
10539         if (ret == -1)
10540                 scfdie();
10541 
10542         if (pgelts.propvals != NULL || pgelts.properties != NULL)
10543                 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10544                     elts);
10545 }
10546 
10547 /*
10548  * Put an instance element for the given instance into selts.
10549  */
10550 static void
10551 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10552 {
10553         xmlNodePtr n;
10554         boolean_t isdefault;
10555         struct entity_elts elts;
10556         struct template_elts template_elts;
10557         int ret;
10558 
10559         n = xmlNewNode(NULL, (xmlChar *)"instance");
10560         if (n == NULL)
10561                 uu_die(emsg_create_xml);
10562 
10563         /* name */
10564         if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10565                 scfdie();
10566         safe_setprop(n, name_attr, exp_str);
10567         isdefault = strcmp(exp_str, "default") == 0;
10568 
10569         /* check existance of general pg (since general/enabled is required) */
10570         if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10571                 if (scf_error() != SCF_ERROR_NOT_FOUND)
10572                         scfdie();
10573 
10574                 if (g_verbose) {
10575                         if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10576                                 scfdie();
10577 
10578                         warn(gettext("Instance %s has no general property "
10579                             "group; it will be marked disabled.\n"), exp_str);
10580                 }
10581 
10582                 safe_setprop(n, enabled_attr, false);
10583         } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10584             strcmp(exp_str, scf_group_framework) != 0) {
10585                 if (g_verbose) {
10586                         if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10587                                 scfdie();
10588 
10589                         warn(gettext("Property group %s is not of type "
10590                             "framework; the instance will be marked "
10591                             "disabled.\n"), exp_str);
10592                 }
10593 
10594                 safe_setprop(n, enabled_attr, false);
10595         }
10596 
10597         /* property groups */
10598         if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10599                 scfdie();
10600 
10601         (void) memset(&elts, 0, sizeof (elts));
10602         (void) memset(&template_elts, 0, sizeof (template_elts));
10603 
10604         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10605                 uint32_t pgflags;
10606 
10607                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10608                         scfdie();
10609 
10610                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10611                         continue;
10612 
10613                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10614                         scfdie();
10615 
10616                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10617                         export_dependency(exp_pg, &elts);
10618                         continue;
10619                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10620                         export_method(exp_pg, &elts);
10621                         continue;
10622                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10623                         if (scf_pg_get_name(exp_pg, exp_str,
10624                             max_scf_name_len + 1) < 0)
10625                                 scfdie();
10626 
10627                         if (strcmp(exp_str, scf_pg_general) == 0) {
10628                                 export_inst_general(exp_pg, n, &elts);
10629                                 continue;
10630                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10631                             0) {
10632                                 export_method_context(exp_pg, &elts);
10633                                 continue;
10634                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10635                                 export_dependents(exp_pg, &elts);
10636                                 continue;
10637                         }
10638                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10639                         export_template(exp_pg, &elts, &template_elts);
10640                         continue;
10641                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10642                         export_notify_params(exp_pg, &elts);
10643                         continue;
10644                 }
10645 
10646                 /* Ordinary pg. */
10647                 export_pg(exp_pg, &elts, flags);
10648         }
10649         if (ret == -1)
10650                 scfdie();
10651 
10652         if (template_elts.common_name != NULL) {
10653                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10654                 (void) xmlAddChild(elts.template, template_elts.common_name);
10655                 (void) xmlAddChild(elts.template, template_elts.description);
10656                 (void) xmlAddChild(elts.template, template_elts.documentation);
10657         } else {
10658                 xmlFreeNode(template_elts.description);
10659                 xmlFreeNode(template_elts.documentation);
10660         }
10661 
10662         if (isdefault && elts.restarter == NULL &&
10663             elts.dependencies == NULL && elts.method_context == NULL &&
10664             elts.exec_methods == NULL && elts.notify_params == NULL &&
10665             elts.property_groups == NULL && elts.template == NULL) {
10666                 xmlChar *eval;
10667 
10668                 /* This is a default instance */
10669                 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10670 
10671                 xmlFreeNode(n);
10672 
10673                 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10674                 if (n == NULL)
10675                         uu_die(emsg_create_xml);
10676 
10677                 safe_setprop(n, enabled_attr, (char *)eval);
10678                 xmlFree(eval);
10679 
10680                 selts->create_default_instance = n;
10681         } else {
10682                 /* Assemble the children in order. */
10683                 (void) xmlAddChild(n, elts.restarter);
10684                 (void) xmlAddChildList(n, elts.dependencies);
10685                 (void) xmlAddChildList(n, elts.dependents);
10686                 (void) xmlAddChild(n, elts.method_context);
10687                 (void) xmlAddChildList(n, elts.exec_methods);
10688                 (void) xmlAddChildList(n, elts.notify_params);
10689                 (void) xmlAddChildList(n, elts.property_groups);
10690                 (void) xmlAddChild(n, elts.template);
10691 
10692                 if (selts->instances == NULL)
10693                         selts->instances = n;
10694                 else
10695                         (void) xmlAddSibling(selts->instances, n);
10696         }
10697 }
10698 
10699 /*
10700  * Return a service element for the given service.
10701  */
10702 static xmlNodePtr
10703 export_service(scf_service_t *svc, int flags)
10704 {
10705         xmlNodePtr snode;
10706         struct entity_elts elts;
10707         struct template_elts template_elts;
10708         int ret;
10709 
10710         snode = xmlNewNode(NULL, (xmlChar *)"service");
10711         if (snode == NULL)
10712                 uu_die(emsg_create_xml);
10713 
10714         /* Get & set name attribute */
10715         if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10716                 scfdie();
10717         safe_setprop(snode, name_attr, exp_str);
10718 
10719         safe_setprop(snode, type_attr, "service");
10720         safe_setprop(snode, "version", "0");
10721 
10722         /* Acquire child elements. */
10723         if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10724                 scfdie();
10725 
10726         (void) memset(&elts, 0, sizeof (elts));
10727         (void) memset(&template_elts, 0, sizeof (template_elts));
10728 
10729         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10730                 uint32_t pgflags;
10731 
10732                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10733                         scfdie();
10734 
10735                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10736                         continue;
10737 
10738                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10739                         scfdie();
10740 
10741                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10742                         export_dependency(exp_pg, &elts);
10743                         continue;
10744                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10745                         export_method(exp_pg, &elts);
10746                         continue;
10747                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10748                         if (scf_pg_get_name(exp_pg, exp_str,
10749                             max_scf_name_len + 1) < 0)
10750                                 scfdie();
10751 
10752                         if (strcmp(exp_str, scf_pg_general) == 0) {
10753                                 export_svc_general(exp_pg, &elts);
10754                                 continue;
10755                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10756                             0) {
10757                                 export_method_context(exp_pg, &elts);
10758                                 continue;
10759                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10760                                 export_dependents(exp_pg, &elts);
10761                                 continue;
10762                         } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10763                                 continue;
10764                         }
10765                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10766                         export_template(exp_pg, &elts, &template_elts);
10767                         continue;
10768                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10769                         export_notify_params(exp_pg, &elts);
10770                         continue;
10771                 }
10772 
10773                 export_pg(exp_pg, &elts, flags);
10774         }
10775         if (ret == -1)
10776                 scfdie();
10777 
10778         if (template_elts.common_name != NULL) {
10779                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10780                 (void) xmlAddChild(elts.template, template_elts.common_name);
10781                 (void) xmlAddChild(elts.template, template_elts.description);
10782                 (void) xmlAddChild(elts.template, template_elts.documentation);
10783         } else {
10784                 xmlFreeNode(template_elts.description);
10785                 xmlFreeNode(template_elts.documentation);
10786         }
10787 
10788         /* Iterate instances */
10789         if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10790                 scfdie();
10791 
10792         while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10793                 export_instance(exp_inst, &elts, flags);
10794         if (ret == -1)
10795                 scfdie();
10796 
10797         /* Now add all of the accumulated elements in order. */
10798         (void) xmlAddChild(snode, elts.create_default_instance);
10799         (void) xmlAddChild(snode, elts.single_instance);
10800         (void) xmlAddChild(snode, elts.restarter);
10801         (void) xmlAddChildList(snode, elts.dependencies);
10802         (void) xmlAddChildList(snode, elts.dependents);
10803         (void) xmlAddChild(snode, elts.method_context);
10804         (void) xmlAddChildList(snode, elts.exec_methods);
10805         (void) xmlAddChildList(snode, elts.notify_params);
10806         (void) xmlAddChildList(snode, elts.property_groups);
10807         (void) xmlAddChildList(snode, elts.instances);
10808         (void) xmlAddChild(snode, elts.stability);
10809         (void) xmlAddChild(snode, elts.template);
10810 
10811         return (snode);
10812 }
10813 
10814 static int
10815 export_callback(void *data, scf_walkinfo_t *wip)
10816 {
10817         FILE *f;
10818         xmlDocPtr doc;
10819         xmlNodePtr sb;
10820         int result;
10821         struct export_args *argsp = (struct export_args *)data;
10822 
10823         if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10824             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10825             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10826             (exp_val = scf_value_create(g_hndl)) == NULL ||
10827             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10828             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10829             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10830             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10831                 scfdie();
10832 
10833         exp_str_sz = max_scf_len + 1;
10834         exp_str = safe_malloc(exp_str_sz);
10835 
10836         if (argsp->filename != NULL) {
10837                 errno = 0;
10838                 f = fopen(argsp->filename, "wb");
10839                 if (f == NULL) {
10840                         if (errno == 0)
10841                                 uu_die(gettext("Could not open \"%s\": no free "
10842                                     "stdio streams.\n"), argsp->filename);
10843                         else
10844                                 uu_die(gettext("Could not open \"%s\""),
10845                                     argsp->filename);
10846                 }
10847         } else
10848                 f = stdout;
10849 
10850         doc = xmlNewDoc((xmlChar *)"1.0");
10851         if (doc == NULL)
10852                 uu_die(gettext("Could not create XML document.\n"));
10853 
10854         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10855             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10856                 uu_die(emsg_create_xml);
10857 
10858         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10859         if (sb == NULL)
10860                 uu_die(emsg_create_xml);
10861         safe_setprop(sb, type_attr, "manifest");
10862         safe_setprop(sb, name_attr, "export");
10863         (void) xmlAddSibling(doc->children, sb);
10864 
10865         (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10866 
10867         result = write_service_bundle(doc, f);
10868 
10869         free(exp_str);
10870         scf_iter_destroy(exp_val_iter);
10871         scf_iter_destroy(exp_prop_iter);
10872         scf_iter_destroy(exp_pg_iter);
10873         scf_iter_destroy(exp_inst_iter);
10874         scf_value_destroy(exp_val);
10875         scf_property_destroy(exp_prop);
10876         scf_pg_destroy(exp_pg);
10877         scf_instance_destroy(exp_inst);
10878 
10879         xmlFreeDoc(doc);
10880 
10881         if (f != stdout)
10882                 (void) fclose(f);
10883 
10884         return (result);
10885 }
10886 
10887 /*
10888  * Get the service named by fmri, build an XML tree which represents it, and
10889  * dump it into filename (or stdout if filename is NULL).
10890  */
10891 int
10892 lscf_service_export(char *fmri, const char *filename, int flags)
10893 {
10894         struct export_args args;
10895         char *fmridup;
10896         const char *scope, *svc, *inst;
10897         size_t cblen = 3 * max_scf_name_len;
10898         char *canonbuf = alloca(cblen);
10899         int ret, err;
10900 
10901         lscf_prep_hndl();
10902 
10903         bzero(&args, sizeof (args));
10904         args.filename = filename;
10905         args.flags = flags;
10906 
10907         /*
10908          * If some poor user has passed an exact instance FMRI, of the sort
10909          * one might cut and paste from svcs(1) or an error message, warn
10910          * and chop off the instance instead of failing.
10911          */
10912         fmridup = alloca(strlen(fmri) + 1);
10913         (void) strcpy(fmridup, fmri);
10914         if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10915             sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10916             scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10917             inst != NULL) {
10918                 (void) strlcpy(canonbuf, "svc:/", cblen);
10919                 if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10920                         (void) strlcat(canonbuf, "/", cblen);
10921                         (void) strlcat(canonbuf, scope, cblen);
10922                 }
10923                 (void) strlcat(canonbuf, svc, cblen);
10924                 fmri = canonbuf;
10925 
10926                 warn(gettext("Only services may be exported; ignoring "
10927                     "instance portion of argument.\n"));
10928         }
10929 
10930         err = 0;
10931         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10932             SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10933             &args, &err, semerr)) != 0) {
10934                 if (ret != -1)
10935                         semerr(gettext("Failed to walk instances: %s\n"),
10936                             scf_strerror(ret));
10937                 return (-1);
10938         }
10939 
10940         /*
10941          * Error message has already been printed.
10942          */
10943         if (err != 0)
10944                 return (-1);
10945 
10946         return (0);
10947 }
10948 
10949 
10950 /*
10951  * Archive
10952  */
10953 
10954 static xmlNodePtr
10955 make_archive(int flags)
10956 {
10957         xmlNodePtr sb;
10958         scf_scope_t *scope;
10959         scf_service_t *svc;
10960         scf_iter_t *iter;
10961         int r;
10962 
10963         if ((scope = scf_scope_create(g_hndl)) == NULL ||
10964             (svc = scf_service_create(g_hndl)) == NULL ||
10965             (iter = scf_iter_create(g_hndl)) == NULL ||
10966             (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10967             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10968             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10969             (exp_val = scf_value_create(g_hndl)) == NULL ||
10970             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10971             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10972             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10973             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10974                 scfdie();
10975 
10976         exp_str_sz = max_scf_len + 1;
10977         exp_str = safe_malloc(exp_str_sz);
10978 
10979         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10980         if (sb == NULL)
10981                 uu_die(emsg_create_xml);
10982         safe_setprop(sb, type_attr, "archive");
10983         safe_setprop(sb, name_attr, "none");
10984 
10985         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10986                 scfdie();
10987         if (scf_iter_scope_services(iter, scope) != 0)
10988                 scfdie();
10989 
10990         for (;;) {
10991                 r = scf_iter_next_service(iter, svc);
10992                 if (r == 0)
10993                         break;
10994                 if (r != 1)
10995                         scfdie();
10996 
10997                 if (scf_service_get_name(svc, exp_str,
10998                     max_scf_name_len + 1) < 0)
10999                         scfdie();
11000 
11001                 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11002                         continue;
11003 
11004                 (void) xmlAddChild(sb, export_service(svc, flags));
11005         }
11006 
11007         free(exp_str);
11008 
11009         scf_iter_destroy(exp_val_iter);
11010         scf_iter_destroy(exp_prop_iter);
11011         scf_iter_destroy(exp_pg_iter);
11012         scf_iter_destroy(exp_inst_iter);
11013         scf_value_destroy(exp_val);
11014         scf_property_destroy(exp_prop);
11015         scf_pg_destroy(exp_pg);
11016         scf_instance_destroy(exp_inst);
11017         scf_iter_destroy(iter);
11018         scf_service_destroy(svc);
11019         scf_scope_destroy(scope);
11020 
11021         return (sb);
11022 }
11023 
11024 int
11025 lscf_archive(const char *filename, int flags)
11026 {
11027         FILE *f;
11028         xmlDocPtr doc;
11029         int result;
11030 
11031         lscf_prep_hndl();
11032 
11033         if (filename != NULL) {
11034                 errno = 0;
11035                 f = fopen(filename, "wb");
11036                 if (f == NULL) {
11037                         if (errno == 0)
11038                                 uu_die(gettext("Could not open \"%s\": no free "
11039                                     "stdio streams.\n"), filename);
11040                         else
11041                                 uu_die(gettext("Could not open \"%s\""),
11042                                     filename);
11043                 }
11044         } else
11045                 f = stdout;
11046 
11047         doc = xmlNewDoc((xmlChar *)"1.0");
11048         if (doc == NULL)
11049                 uu_die(gettext("Could not create XML document.\n"));
11050 
11051         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11052             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11053                 uu_die(emsg_create_xml);
11054 
11055         (void) xmlAddSibling(doc->children, make_archive(flags));
11056 
11057         result = write_service_bundle(doc, f);
11058 
11059         xmlFreeDoc(doc);
11060 
11061         if (f != stdout)
11062                 (void) fclose(f);
11063 
11064         return (result);
11065 }
11066 
11067 
11068 /*
11069  * "Extract" a profile.
11070  */
11071 int
11072 lscf_profile_extract(const char *filename)
11073 {
11074         FILE *f;
11075         xmlDocPtr doc;
11076         xmlNodePtr sb, snode, inode;
11077         scf_scope_t *scope;
11078         scf_service_t *svc;
11079         scf_instance_t *inst;
11080         scf_propertygroup_t *pg;
11081         scf_property_t *prop;
11082         scf_value_t *val;
11083         scf_iter_t *siter, *iiter;
11084         int r, s;
11085         char *namebuf;
11086         uint8_t b;
11087         int result;
11088 
11089         lscf_prep_hndl();
11090 
11091         if (filename != NULL) {
11092                 errno = 0;
11093                 f = fopen(filename, "wb");
11094                 if (f == NULL) {
11095                         if (errno == 0)
11096                                 uu_die(gettext("Could not open \"%s\": no "
11097                                     "free stdio streams.\n"), filename);
11098                         else
11099                                 uu_die(gettext("Could not open \"%s\""),
11100                                     filename);
11101                 }
11102         } else
11103                 f = stdout;
11104 
11105         doc = xmlNewDoc((xmlChar *)"1.0");
11106         if (doc == NULL)
11107                 uu_die(gettext("Could not create XML document.\n"));
11108 
11109         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11110             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11111                 uu_die(emsg_create_xml);
11112 
11113         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11114         if (sb == NULL)
11115                 uu_die(emsg_create_xml);
11116         safe_setprop(sb, type_attr, "profile");
11117         safe_setprop(sb, name_attr, "extract");
11118         (void) xmlAddSibling(doc->children, sb);
11119 
11120         if ((scope = scf_scope_create(g_hndl)) == NULL ||
11121             (svc = scf_service_create(g_hndl)) == NULL ||
11122             (inst = scf_instance_create(g_hndl)) == NULL ||
11123             (pg = scf_pg_create(g_hndl)) == NULL ||
11124             (prop = scf_property_create(g_hndl)) == NULL ||
11125             (val = scf_value_create(g_hndl)) == NULL ||
11126             (siter = scf_iter_create(g_hndl)) == NULL ||
11127             (iiter = scf_iter_create(g_hndl)) == NULL)
11128                 scfdie();
11129 
11130         if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11131                 scfdie();
11132 
11133         if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11134                 scfdie();
11135 
11136         namebuf = safe_malloc(max_scf_name_len + 1);
11137 
11138         while ((r = scf_iter_next_service(siter, svc)) == 1) {
11139                 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11140                         scfdie();
11141 
11142                 snode = xmlNewNode(NULL, (xmlChar *)"service");
11143                 if (snode == NULL)
11144                         uu_die(emsg_create_xml);
11145 
11146                 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11147                     0)
11148                         scfdie();
11149 
11150                 safe_setprop(snode, name_attr, namebuf);
11151 
11152                 safe_setprop(snode, type_attr, "service");
11153                 safe_setprop(snode, "version", "0");
11154 
11155                 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11156                         if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11157                             SCF_SUCCESS) {
11158                                 if (scf_error() != SCF_ERROR_NOT_FOUND)
11159                                         scfdie();
11160 
11161                                 if (g_verbose) {
11162                                         ssize_t len;
11163                                         char *fmri;
11164 
11165                                         len =
11166                                             scf_instance_to_fmri(inst, NULL, 0);
11167                                         if (len < 0)
11168                                                 scfdie();
11169 
11170                                         fmri = safe_malloc(len + 1);
11171 
11172                                         if (scf_instance_to_fmri(inst, fmri,
11173                                             len + 1) < 0)
11174                                                 scfdie();
11175 
11176                                         warn("Instance %s has no \"%s\" "
11177                                             "property group.\n", fmri,
11178                                             scf_pg_general);
11179 
11180                                         free(fmri);
11181                                 }
11182 
11183                                 continue;
11184                         }
11185 
11186                         if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11187                             prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11188                             prop_get_val(prop, val) != 0)
11189                                 continue;
11190 
11191                         inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11192                             NULL);
11193                         if (inode == NULL)
11194                                 uu_die(emsg_create_xml);
11195 
11196                         if (scf_instance_get_name(inst, namebuf,
11197                             max_scf_name_len + 1) < 0)
11198                                 scfdie();
11199 
11200                         safe_setprop(inode, name_attr, namebuf);
11201 
11202                         if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11203                                 scfdie();
11204 
11205                         safe_setprop(inode, enabled_attr, b ? true : false);
11206                 }
11207                 if (s < 0)
11208                         scfdie();
11209 
11210                 if (snode->children != NULL)
11211                         (void) xmlAddChild(sb, snode);
11212                 else
11213                         xmlFreeNode(snode);
11214         }
11215         if (r < 0)
11216                 scfdie();
11217 
11218         free(namebuf);
11219 
11220         result = write_service_bundle(doc, f);
11221 
11222         xmlFreeDoc(doc);
11223 
11224         if (f != stdout)
11225                 (void) fclose(f);
11226 
11227         return (result);
11228 }
11229 
11230 
11231 /*
11232  * Entity manipulation commands
11233  */
11234 
11235 /*
11236  * Entity selection.  If no entity is selected, then the current scope is in
11237  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11238  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11239  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11240  * cur_inst will be non-NULL.
11241  */
11242 
11243 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11244 static int
11245 select_inst(const char *name)
11246 {
11247         scf_instance_t *inst;
11248         scf_error_t err;
11249 
11250         assert(cur_svc != NULL);
11251 
11252         inst = scf_instance_create(g_hndl);
11253         if (inst == NULL)
11254                 scfdie();
11255 
11256         if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11257                 cur_inst = inst;
11258                 return (0);
11259         }
11260 
11261         err = scf_error();
11262         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11263                 scfdie();
11264 
11265         scf_instance_destroy(inst);
11266         return (1);
11267 }
11268 
11269 /* Returns as above. */
11270 static int
11271 select_svc(const char *name)
11272 {
11273         scf_service_t *svc;
11274         scf_error_t err;
11275 
11276         assert(cur_scope != NULL);
11277 
11278         svc = scf_service_create(g_hndl);
11279         if (svc == NULL)
11280                 scfdie();
11281 
11282         if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11283                 cur_svc = svc;
11284                 return (0);
11285         }
11286 
11287         err = scf_error();
11288         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11289                 scfdie();
11290 
11291         scf_service_destroy(svc);
11292         return (1);
11293 }
11294 
11295 /* ARGSUSED */
11296 static int
11297 select_callback(void *unused, scf_walkinfo_t *wip)
11298 {
11299         scf_instance_t *inst;
11300         scf_service_t *svc;
11301         scf_scope_t *scope;
11302 
11303         if (wip->inst != NULL) {
11304                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11305                     (svc = scf_service_create(g_hndl)) == NULL ||
11306                     (inst = scf_instance_create(g_hndl)) == NULL)
11307                         scfdie();
11308 
11309                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11310                     inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11311                         scfdie();
11312         } else {
11313                 assert(wip->svc != NULL);
11314 
11315                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11316                     (svc = scf_service_create(g_hndl)) == NULL)
11317                         scfdie();
11318 
11319                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11320                     NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11321                         scfdie();
11322 
11323                 inst = NULL;
11324         }
11325 
11326         /* Clear out the current selection */
11327         assert(cur_scope != NULL);
11328         scf_scope_destroy(cur_scope);
11329         scf_service_destroy(cur_svc);
11330         scf_instance_destroy(cur_inst);
11331 
11332         cur_scope = scope;
11333         cur_svc = svc;
11334         cur_inst = inst;
11335 
11336         return (0);
11337 }
11338 
11339 static int
11340 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11341 {
11342         char **fmri = fmri_p;
11343 
11344         *fmri = strdup(wip->fmri);
11345         if (*fmri == NULL)
11346                 uu_die(gettext("Out of memory.\n"));
11347 
11348         return (0);
11349 }
11350 
11351 /*
11352  * validate [fmri]
11353  * Perform the validation of an FMRI instance.
11354  */
11355 void
11356 lscf_validate_fmri(const char *fmri)
11357 {
11358         int ret = 0;
11359         size_t inst_sz;
11360         char *inst_fmri = NULL;
11361         scf_tmpl_errors_t *errs = NULL;
11362         char *snapbuf = NULL;
11363 
11364         lscf_prep_hndl();
11365 
11366         if (fmri == NULL) {
11367                 inst_sz = max_scf_fmri_len + 1;
11368                 inst_fmri = safe_malloc(inst_sz);
11369 
11370                 if (cur_snap != NULL) {
11371                         snapbuf = safe_malloc(max_scf_name_len + 1);
11372                         if (scf_snapshot_get_name(cur_snap, snapbuf,
11373                             max_scf_name_len + 1) < 0)
11374                                 scfdie();
11375                 }
11376                 if (cur_inst == NULL) {
11377                         semerr(gettext("No instance selected\n"));
11378                         goto cleanup;
11379                 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11380                     inst_sz) >= inst_sz) {
11381                         /* sanity check. Should never get here */
11382                         uu_die(gettext("Unexpected error! file %s, line %d\n"),
11383                             __FILE__, __LINE__);
11384                 }
11385         } else {
11386                 scf_error_t scf_err;
11387                 int err = 0;
11388 
11389                 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11390                     validate_callback, &inst_fmri, &err, semerr)) != 0) {
11391                         uu_warn("Failed to walk instances: %s\n",
11392                             scf_strerror(scf_err));
11393                         goto cleanup;
11394                 }
11395                 if (err != 0) {
11396                         /* error message displayed by scf_walk_fmri */
11397                         goto cleanup;
11398                 }
11399         }
11400 
11401         ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11402             SCF_TMPL_VALIDATE_FLAG_CURRENT);
11403         if (ret == -1) {
11404                 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11405                         warn(gettext("Template data for %s is invalid. "
11406                             "Consider reverting to a previous snapshot or "
11407                             "restoring original configuration.\n"), inst_fmri);
11408                 } else {
11409                         uu_warn("%s: %s\n",
11410                             gettext("Error validating the instance"),
11411                             scf_strerror(scf_error()));
11412                 }
11413         } else if (ret == 1 && errs != NULL) {
11414                 scf_tmpl_error_t *err = NULL;
11415                 char *msg;
11416                 size_t len = 256;       /* initial error buffer size */
11417                 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11418                     SCF_TMPL_STRERROR_HUMAN : 0;
11419 
11420                 msg = safe_malloc(len);
11421 
11422                 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11423                         int ret;
11424 
11425                         if ((ret = scf_tmpl_strerror(err, msg, len,
11426                             flag)) >= len) {
11427                                 len = ret + 1;
11428                                 msg = realloc(msg, len);
11429                                 if (msg == NULL)
11430                                         uu_die(gettext(
11431                                             "Out of memory.\n"));
11432                                 (void) scf_tmpl_strerror(err, msg, len,
11433                                     flag);
11434                         }
11435                         (void) fprintf(stderr, "%s\n", msg);
11436                 }
11437                 if (msg != NULL)
11438                         free(msg);
11439         }
11440         if (errs != NULL)
11441                 scf_tmpl_errors_destroy(errs);
11442 
11443 cleanup:
11444         free(inst_fmri);
11445         free(snapbuf);
11446 }
11447 
11448 static void
11449 lscf_validate_file(const char *filename)
11450 {
11451         tmpl_errors_t *errs;
11452 
11453         bundle_t *b = internal_bundle_new();
11454         if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11455                 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11456                         tmpl_errors_print(stderr, errs, "");
11457                         semerr(gettext("Validation failed.\n"));
11458                 }
11459                 tmpl_errors_destroy(errs);
11460         }
11461         (void) internal_bundle_free(b);
11462 }
11463 
11464 /*
11465  * validate [fmri|file]
11466  */
11467 void
11468 lscf_validate(const char *arg)
11469 {
11470         const char *str;
11471 
11472         if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11473             sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11474                 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11475                 lscf_validate_file(str);
11476         } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11477             sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11478                 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11479                 lscf_validate_fmri(str);
11480         } else if (access(arg, R_OK | F_OK) == 0) {
11481                 lscf_validate_file(arg);
11482         } else {
11483                 lscf_validate_fmri(arg);
11484         }
11485 }
11486 
11487 void
11488 lscf_select(const char *fmri)
11489 {
11490         int ret, err;
11491 
11492         lscf_prep_hndl();
11493 
11494         if (cur_snap != NULL) {
11495                 struct snaplevel *elt;
11496                 char *buf;
11497 
11498                 /* Error unless name is that of the next level. */
11499                 elt = uu_list_next(cur_levels, cur_elt);
11500                 if (elt == NULL) {
11501                         semerr(gettext("No children.\n"));
11502                         return;
11503                 }
11504 
11505                 buf = safe_malloc(max_scf_name_len + 1);
11506 
11507                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11508                     max_scf_name_len + 1) < 0)
11509                         scfdie();
11510 
11511                 if (strcmp(buf, fmri) != 0) {
11512                         semerr(gettext("No such child.\n"));
11513                         free(buf);
11514                         return;
11515                 }
11516 
11517                 free(buf);
11518 
11519                 cur_elt = elt;
11520                 cur_level = elt->sl;
11521                 return;
11522         }
11523 
11524         /*
11525          * Special case for 'svc:', which takes the user to the scope level.
11526          */
11527         if (strcmp(fmri, "svc:") == 0) {
11528                 scf_instance_destroy(cur_inst);
11529                 scf_service_destroy(cur_svc);
11530                 cur_inst = NULL;
11531                 cur_svc = NULL;
11532                 return;
11533         }
11534 
11535         /*
11536          * Special case for ':properties'.  This appears as part of 'list' but
11537          * can't be selected.  Give a more helpful error message in this case.
11538          */
11539         if (strcmp(fmri, ":properties") == 0) {
11540                 semerr(gettext(":properties is not an entity.  Try 'listprop' "
11541                     "to list properties.\n"));
11542                 return;
11543         }
11544 
11545         /*
11546          * First try the argument as relative to the current selection.
11547          */
11548         if (cur_inst != NULL) {
11549                 /* EMPTY */;
11550         } else if (cur_svc != NULL) {
11551                 if (select_inst(fmri) != 1)
11552                         return;
11553         } else {
11554                 if (select_svc(fmri) != 1)
11555                         return;
11556         }
11557 
11558         err = 0;
11559         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11560             select_callback, NULL, &err, semerr)) != 0) {
11561                 semerr(gettext("Failed to walk instances: %s\n"),
11562                     scf_strerror(ret));
11563         }
11564 }
11565 
11566 void
11567 lscf_unselect(void)
11568 {
11569         lscf_prep_hndl();
11570 
11571         if (cur_snap != NULL) {
11572                 struct snaplevel *elt;
11573 
11574                 elt = uu_list_prev(cur_levels, cur_elt);
11575                 if (elt == NULL) {
11576                         semerr(gettext("No parent levels.\n"));
11577                 } else {
11578                         cur_elt = elt;
11579                         cur_level = elt->sl;
11580                 }
11581         } else if (cur_inst != NULL) {
11582                 scf_instance_destroy(cur_inst);
11583                 cur_inst = NULL;
11584         } else if (cur_svc != NULL) {
11585                 scf_service_destroy(cur_svc);
11586                 cur_svc = NULL;
11587         } else {
11588                 semerr(gettext("Cannot unselect at scope level.\n"));
11589         }
11590 }
11591 
11592 /*
11593  * Return the FMRI of the current selection, for the prompt.
11594  */
11595 void
11596 lscf_get_selection_str(char *buf, size_t bufsz)
11597 {
11598         char *cp;
11599         ssize_t fmrilen, szret;
11600         boolean_t deleted = B_FALSE;
11601 
11602         if (g_hndl == NULL) {
11603                 (void) strlcpy(buf, "svc:", bufsz);
11604                 return;
11605         }
11606 
11607         if (cur_level != NULL) {
11608                 assert(cur_snap != NULL);
11609 
11610                 /* [ snapshot ] FMRI [: instance ] */
11611                 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11612                     + 2 + max_scf_name_len + 1 + 1);
11613 
11614                 buf[0] = '[';
11615 
11616                 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11617                     max_scf_name_len + 1);
11618                 if (szret < 0) {
11619                         if (scf_error() != SCF_ERROR_DELETED)
11620                                 scfdie();
11621 
11622                         goto snap_deleted;
11623                 }
11624 
11625                 (void) strcat(buf, "]svc:/");
11626 
11627                 cp = strchr(buf, '\0');
11628 
11629                 szret = scf_snaplevel_get_service_name(cur_level, cp,
11630                     max_scf_name_len + 1);
11631                 if (szret < 0) {
11632                         if (scf_error() != SCF_ERROR_DELETED)
11633                                 scfdie();
11634 
11635                         goto snap_deleted;
11636                 }
11637 
11638                 cp = strchr(cp, '\0');
11639 
11640                 if (snaplevel_is_instance(cur_level)) {
11641                         *cp++ = ':';
11642 
11643                         if (scf_snaplevel_get_instance_name(cur_level, cp,
11644                             max_scf_name_len + 1) < 0) {
11645                                 if (scf_error() != SCF_ERROR_DELETED)
11646                                         scfdie();
11647 
11648                                 goto snap_deleted;
11649                         }
11650                 } else {
11651                         *cp++ = '[';
11652                         *cp++ = ':';
11653 
11654                         if (scf_instance_get_name(cur_inst, cp,
11655                             max_scf_name_len + 1) < 0) {
11656                                 if (scf_error() != SCF_ERROR_DELETED)
11657                                         scfdie();
11658 
11659                                 goto snap_deleted;
11660                         }
11661 
11662                         (void) strcat(buf, "]");
11663                 }
11664 
11665                 return;
11666 
11667 snap_deleted:
11668                 deleted = B_TRUE;
11669                 free(buf);
11670                 unselect_cursnap();
11671         }
11672 
11673         assert(cur_snap == NULL);
11674 
11675         if (cur_inst != NULL) {
11676                 assert(cur_svc != NULL);
11677                 assert(cur_scope != NULL);
11678 
11679                 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11680                 if (fmrilen >= 0) {
11681                         assert(fmrilen < bufsz);
11682                         if (deleted)
11683                                 warn(emsg_deleted);
11684                         return;
11685                 }
11686 
11687                 if (scf_error() != SCF_ERROR_DELETED)
11688                         scfdie();
11689 
11690                 deleted = B_TRUE;
11691 
11692                 scf_instance_destroy(cur_inst);
11693                 cur_inst = NULL;
11694         }
11695 
11696         if (cur_svc != NULL) {
11697                 assert(cur_scope != NULL);
11698 
11699                 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11700                 if (szret >= 0) {
11701                         assert(szret < bufsz);
11702                         if (deleted)
11703                                 warn(emsg_deleted);
11704                         return;
11705                 }
11706 
11707                 if (scf_error() != SCF_ERROR_DELETED)
11708                         scfdie();
11709 
11710                 deleted = B_TRUE;
11711                 scf_service_destroy(cur_svc);
11712                 cur_svc = NULL;
11713         }
11714 
11715         assert(cur_scope != NULL);
11716         fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11717 
11718         if (fmrilen < 0)
11719                 scfdie();
11720 
11721         assert(fmrilen < bufsz);
11722         if (deleted)
11723                 warn(emsg_deleted);
11724 }
11725 
11726 /*
11727  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11728  * :statistics) are listed for the current selection.
11729  */
11730 void
11731 lscf_list(const char *pattern)
11732 {
11733         scf_iter_t *iter;
11734         char *buf;
11735         int ret;
11736 
11737         lscf_prep_hndl();
11738 
11739         if (cur_level != NULL) {
11740                 struct snaplevel *elt;
11741 
11742                 (void) fputs(COLON_NAMESPACES, stdout);
11743 
11744                 elt = uu_list_next(cur_levels, cur_elt);
11745                 if (elt == NULL)
11746                         return;
11747 
11748                 /*
11749                  * For now, we know that the next level is an instance.  But
11750                  * if we ever have multiple scopes, this could be complicated.
11751                  */
11752                 buf = safe_malloc(max_scf_name_len + 1);
11753                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11754                     max_scf_name_len + 1) >= 0) {
11755                         (void) puts(buf);
11756                 } else {
11757                         if (scf_error() != SCF_ERROR_DELETED)
11758                                 scfdie();
11759                 }
11760 
11761                 free(buf);
11762 
11763                 return;
11764         }
11765 
11766         if (cur_inst != NULL) {
11767                 (void) fputs(COLON_NAMESPACES, stdout);
11768                 return;
11769         }
11770 
11771         iter = scf_iter_create(g_hndl);
11772         if (iter == NULL)
11773                 scfdie();
11774 
11775         buf = safe_malloc(max_scf_name_len + 1);
11776 
11777         if (cur_svc != NULL) {
11778                 /* List the instances in this service. */
11779                 scf_instance_t *inst;
11780 
11781                 inst = scf_instance_create(g_hndl);
11782                 if (inst == NULL)
11783                         scfdie();
11784 
11785                 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11786                         safe_printf(COLON_NAMESPACES);
11787 
11788                         for (;;) {
11789                                 ret = scf_iter_next_instance(iter, inst);
11790                                 if (ret == 0)
11791                                         break;
11792                                 if (ret != 1) {
11793                                         if (scf_error() != SCF_ERROR_DELETED)
11794                                                 scfdie();
11795 
11796                                         break;
11797                                 }
11798 
11799                                 if (scf_instance_get_name(inst, buf,
11800                                     max_scf_name_len + 1) >= 0) {
11801                                         if (pattern == NULL ||
11802                                             fnmatch(pattern, buf, 0) == 0)
11803                                                 (void) puts(buf);
11804                                 } else {
11805                                         if (scf_error() != SCF_ERROR_DELETED)
11806                                                 scfdie();
11807                                 }
11808                         }
11809                 } else {
11810                         if (scf_error() != SCF_ERROR_DELETED)
11811                                 scfdie();
11812                 }
11813 
11814                 scf_instance_destroy(inst);
11815         } else {
11816                 /* List the services in this scope. */
11817                 scf_service_t *svc;
11818 
11819                 assert(cur_scope != NULL);
11820 
11821                 svc = scf_service_create(g_hndl);
11822                 if (svc == NULL)
11823                         scfdie();
11824 
11825                 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11826                         scfdie();
11827 
11828                 for (;;) {
11829                         ret = scf_iter_next_service(iter, svc);
11830                         if (ret == 0)
11831                                 break;
11832                         if (ret != 1)
11833                                 scfdie();
11834 
11835                         if (scf_service_get_name(svc, buf,
11836                             max_scf_name_len + 1) >= 0) {
11837                                 if (pattern == NULL ||
11838                                     fnmatch(pattern, buf, 0) == 0)
11839                                         safe_printf("%s\n", buf);
11840                         } else {
11841                                 if (scf_error() != SCF_ERROR_DELETED)
11842                                         scfdie();
11843                         }
11844                 }
11845 
11846                 scf_service_destroy(svc);
11847         }
11848 
11849         free(buf);
11850         scf_iter_destroy(iter);
11851 }
11852 
11853 /*
11854  * Entity addition.  Creates an empty entity in the current selection.
11855  */
11856 void
11857 lscf_add(const char *name)
11858 {
11859         lscf_prep_hndl();
11860 
11861         if (cur_snap != NULL) {
11862                 semerr(emsg_cant_modify_snapshots);
11863         } else if (cur_inst != NULL) {
11864                 semerr(gettext("Cannot add entities to an instance.\n"));
11865         } else if (cur_svc != NULL) {
11866 
11867                 if (scf_service_add_instance(cur_svc, name, NULL) !=
11868                     SCF_SUCCESS) {
11869                         switch (scf_error()) {
11870                         case SCF_ERROR_INVALID_ARGUMENT:
11871                                 semerr(gettext("Invalid name.\n"));
11872                                 break;
11873 
11874                         case SCF_ERROR_EXISTS:
11875                                 semerr(gettext("Instance already exists.\n"));
11876                                 break;
11877 
11878                         case SCF_ERROR_PERMISSION_DENIED:
11879                                 semerr(emsg_permission_denied);
11880                                 break;
11881 
11882                         default:
11883                                 scfdie();
11884                         }
11885                 }
11886         } else {
11887                 assert(cur_scope != NULL);
11888 
11889                 if (scf_scope_add_service(cur_scope, name, NULL) !=
11890                     SCF_SUCCESS) {
11891                         switch (scf_error()) {
11892                         case SCF_ERROR_INVALID_ARGUMENT:
11893                                 semerr(gettext("Invalid name.\n"));
11894                                 break;
11895 
11896                         case SCF_ERROR_EXISTS:
11897                                 semerr(gettext("Service already exists.\n"));
11898                                 break;
11899 
11900                         case SCF_ERROR_PERMISSION_DENIED:
11901                                 semerr(emsg_permission_denied);
11902                                 break;
11903 
11904                         case SCF_ERROR_BACKEND_READONLY:
11905                                 semerr(emsg_read_only);
11906                                 break;
11907 
11908                         default:
11909                                 scfdie();
11910                         }
11911                 }
11912         }
11913 }
11914 
11915 /* return 1 if the entity has no persistent pgs, else return 0 */
11916 static int
11917 entity_has_no_pgs(void *ent, int isservice)
11918 {
11919         scf_iter_t *iter = NULL;
11920         scf_propertygroup_t *pg = NULL;
11921         uint32_t flags;
11922         int err;
11923         int ret = 1;
11924 
11925         if ((iter = scf_iter_create(g_hndl)) == NULL ||
11926             (pg = scf_pg_create(g_hndl)) == NULL)
11927                 scfdie();
11928 
11929         if (isservice) {
11930                 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11931                         scfdie();
11932         } else {
11933                 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11934                         scfdie();
11935         }
11936 
11937         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11938                 if (scf_pg_get_flags(pg, &flags) != 0)
11939                         scfdie();
11940 
11941                 /* skip nonpersistent pgs */
11942                 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11943                         continue;
11944 
11945                 ret = 0;
11946                 break;
11947         }
11948 
11949         if (err == -1)
11950                 scfdie();
11951 
11952         scf_pg_destroy(pg);
11953         scf_iter_destroy(iter);
11954 
11955         return (ret);
11956 }
11957 
11958 /* return 1 if the service has no instances, else return 0 */
11959 static int
11960 svc_has_no_insts(scf_service_t *svc)
11961 {
11962         scf_instance_t *inst;
11963         scf_iter_t *iter;
11964         int r;
11965         int ret = 1;
11966 
11967         if ((inst = scf_instance_create(g_hndl)) == NULL ||
11968             (iter = scf_iter_create(g_hndl)) == NULL)
11969                 scfdie();
11970 
11971         if (scf_iter_service_instances(iter, svc) != 0)
11972                 scfdie();
11973 
11974         r = scf_iter_next_instance(iter, inst);
11975         if (r == 1) {
11976                 ret = 0;
11977         } else if (r == 0) {
11978                 ret = 1;
11979         } else if (r == -1) {
11980                 scfdie();
11981         } else {
11982                 bad_error("scf_iter_next_instance", r);
11983         }
11984 
11985         scf_iter_destroy(iter);
11986         scf_instance_destroy(inst);
11987 
11988         return (ret);
11989 }
11990 
11991 /*
11992  * Entity deletion.
11993  */
11994 
11995 /*
11996  * Delete the property group <fmri>/:properties/<name>.  Returns
11997  * SCF_ERROR_NONE on success (or if the entity is not found),
11998  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11999  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12000  * denied.
12001  */
12002 static scf_error_t
12003 delete_dependency_pg(const char *fmri, const char *name)
12004 {
12005         void *entity = NULL;
12006         int isservice;
12007         scf_propertygroup_t *pg = NULL;
12008         scf_error_t result;
12009         char *pgty;
12010         scf_service_t *svc = NULL;
12011         scf_instance_t *inst = NULL;
12012         scf_iter_t *iter = NULL;
12013         char *name_buf = NULL;
12014 
12015         result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12016         switch (result) {
12017         case SCF_ERROR_NONE:
12018                 break;
12019 
12020         case SCF_ERROR_NO_MEMORY:
12021                 uu_die(gettext("Out of memory.\n"));
12022                 /* NOTREACHED */
12023 
12024         case SCF_ERROR_INVALID_ARGUMENT:
12025         case SCF_ERROR_CONSTRAINT_VIOLATED:
12026                 return (SCF_ERROR_INVALID_ARGUMENT);
12027 
12028         case SCF_ERROR_NOT_FOUND:
12029                 result = SCF_ERROR_NONE;
12030                 goto out;
12031 
12032         default:
12033                 bad_error("fmri_to_entity", result);
12034         }
12035 
12036         pg = scf_pg_create(g_hndl);
12037         if (pg == NULL)
12038                 scfdie();
12039 
12040         if (entity_get_pg(entity, isservice, name, pg) != 0) {
12041                 if (scf_error() != SCF_ERROR_NOT_FOUND)
12042                         scfdie();
12043 
12044                 result = SCF_ERROR_NONE;
12045                 goto out;
12046         }
12047 
12048         pgty = safe_malloc(max_scf_pg_type_len + 1);
12049 
12050         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12051                 scfdie();
12052 
12053         if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12054                 result = SCF_ERROR_TYPE_MISMATCH;
12055                 free(pgty);
12056                 goto out;
12057         }
12058 
12059         free(pgty);
12060 
12061         if (scf_pg_delete(pg) != 0) {
12062                 result = scf_error();
12063                 if (result != SCF_ERROR_PERMISSION_DENIED)
12064                         scfdie();
12065                 goto out;
12066         }
12067 
12068         /*
12069          * We have to handle the case where we've just deleted the last
12070          * property group of a "dummy" entity (instance or service).
12071          * A "dummy" entity is an entity only present to hold an
12072          * external dependency.
12073          * So, in the case we deleted the last property group then we
12074          * can also delete the entity. If the entity is an instance then
12075          * we must verify if this was the last instance for the service
12076          * and if it is, we can also delete the service if it doesn't
12077          * have any property group either.
12078          */
12079 
12080         result = SCF_ERROR_NONE;
12081 
12082         if (isservice) {
12083                 svc = (scf_service_t *)entity;
12084 
12085                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
12086                     (iter = scf_iter_create(g_hndl)) == NULL)
12087                         scfdie();
12088 
12089                 name_buf = safe_malloc(max_scf_name_len + 1);
12090         } else {
12091                 inst = (scf_instance_t *)entity;
12092         }
12093 
12094         /*
12095          * If the entity is an instance and we've just deleted its last
12096          * property group then we should delete it.
12097          */
12098         if (!isservice && entity_has_no_pgs(entity, isservice)) {
12099                 /* find the service before deleting the inst. - needed later */
12100                 if ((svc = scf_service_create(g_hndl)) == NULL)
12101                         scfdie();
12102 
12103                 if (scf_instance_get_parent(inst, svc) != 0)
12104                         scfdie();
12105 
12106                 /* delete the instance */
12107                 if (scf_instance_delete(inst) != 0) {
12108                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12109                                 scfdie();
12110 
12111                         result = SCF_ERROR_PERMISSION_DENIED;
12112                         goto out;
12113                 }
12114                 /* no need to refresh the instance */
12115                 inst = NULL;
12116         }
12117 
12118         /*
12119          * If the service has no more instances and pgs or we just deleted the
12120          * last instance and the service doesn't have anymore propery groups
12121          * then the service should be deleted.
12122          */
12123         if (svc != NULL &&
12124             svc_has_no_insts(svc) &&
12125             entity_has_no_pgs((void *)svc, 1)) {
12126                 if (scf_service_delete(svc) == 0) {
12127                         if (isservice) {
12128                                 /* no need to refresh the service */
12129                                 svc = NULL;
12130                         }
12131 
12132                         goto out;
12133                 }
12134 
12135                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12136                         scfdie();
12137 
12138                 result = SCF_ERROR_PERMISSION_DENIED;
12139         }
12140 
12141         /* if the entity has not been deleted, refresh it */
12142         if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12143                 (void) refresh_entity(isservice, entity, fmri, inst, iter,
12144                     name_buf);
12145         }
12146 
12147 out:
12148         if (isservice && (inst != NULL && iter != NULL)) {
12149                 free(name_buf);
12150                 scf_iter_destroy(iter);
12151                 scf_instance_destroy(inst);
12152         }
12153 
12154         if (!isservice && svc != NULL) {
12155                 scf_service_destroy(svc);
12156         }
12157 
12158         scf_pg_destroy(pg);
12159         if (entity != NULL)
12160                 entity_destroy(entity, isservice);
12161 
12162         return (result);
12163 }
12164 
12165 static int
12166 delete_dependents(scf_propertygroup_t *pg)
12167 {
12168         char *pgty, *name, *fmri;
12169         scf_property_t *prop;
12170         scf_value_t *val;
12171         scf_iter_t *iter;
12172         int r;
12173         scf_error_t err;
12174 
12175         /* Verify that the pg has the correct type. */
12176         pgty = safe_malloc(max_scf_pg_type_len + 1);
12177         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12178                 scfdie();
12179 
12180         if (strcmp(pgty, scf_group_framework) != 0) {
12181                 if (g_verbose) {
12182                         fmri = safe_malloc(max_scf_fmri_len + 1);
12183                         if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12184                                 scfdie();
12185 
12186                         warn(gettext("Property group %s is not of expected "
12187                             "type %s.\n"), fmri, scf_group_framework);
12188 
12189                         free(fmri);
12190                 }
12191 
12192                 free(pgty);
12193                 return (-1);
12194         }
12195 
12196         free(pgty);
12197 
12198         /* map delete_dependency_pg onto the properties. */
12199         if ((prop = scf_property_create(g_hndl)) == NULL ||
12200             (val = scf_value_create(g_hndl)) == NULL ||
12201             (iter = scf_iter_create(g_hndl)) == NULL)
12202                 scfdie();
12203 
12204         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12205                 scfdie();
12206 
12207         name = safe_malloc(max_scf_name_len + 1);
12208         fmri = safe_malloc(max_scf_fmri_len + 2);
12209 
12210         while ((r = scf_iter_next_property(iter, prop)) == 1) {
12211                 scf_type_t ty;
12212 
12213                 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12214                         scfdie();
12215 
12216                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12217                         scfdie();
12218 
12219                 if ((ty != SCF_TYPE_ASTRING &&
12220                     prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12221                     prop_get_val(prop, val) != 0)
12222                         continue;
12223 
12224                 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12225                         scfdie();
12226 
12227                 err = delete_dependency_pg(fmri, name);
12228                 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12229                         if (scf_property_to_fmri(prop, fmri,
12230                             max_scf_fmri_len + 2) < 0)
12231                                 scfdie();
12232 
12233                         warn(gettext("Value of %s is not a valid FMRI.\n"),
12234                             fmri);
12235                 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12236                         warn(gettext("Property group \"%s\" of entity \"%s\" "
12237                             "does not have dependency type.\n"), name, fmri);
12238                 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12239                         warn(gettext("Could not delete property group \"%s\" "
12240                             "of entity \"%s\" (permission denied).\n"), name,
12241                             fmri);
12242                 }
12243         }
12244         if (r == -1)
12245                 scfdie();
12246 
12247         scf_value_destroy(val);
12248         scf_property_destroy(prop);
12249 
12250         return (0);
12251 }
12252 
12253 /*
12254  * Returns 1 if the instance may be running, and 0 otherwise.
12255  */
12256 static int
12257 inst_is_running(scf_instance_t *inst)
12258 {
12259         scf_propertygroup_t *pg;
12260         scf_property_t *prop;
12261         scf_value_t *val;
12262         char buf[MAX_SCF_STATE_STRING_SZ];
12263         int ret = 0;
12264         ssize_t szret;
12265 
12266         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12267             (prop = scf_property_create(g_hndl)) == NULL ||
12268             (val = scf_value_create(g_hndl)) == NULL)
12269                 scfdie();
12270 
12271         if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12272                 if (scf_error() != SCF_ERROR_NOT_FOUND)
12273                         scfdie();
12274                 goto out;
12275         }
12276 
12277         if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12278             prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12279             prop_get_val(prop, val) != 0)
12280                 goto out;
12281 
12282         szret = scf_value_get_astring(val, buf, sizeof (buf));
12283         assert(szret >= 0);
12284 
12285         ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12286             strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12287 
12288 out:
12289         scf_value_destroy(val);
12290         scf_property_destroy(prop);
12291         scf_pg_destroy(pg);
12292         return (ret);
12293 }
12294 
12295 static uint8_t
12296 pg_is_external_dependency(scf_propertygroup_t *pg)
12297 {
12298         char *type;
12299         scf_value_t *val;
12300         scf_property_t *prop;
12301         uint8_t b = B_FALSE;
12302 
12303         type = safe_malloc(max_scf_pg_type_len + 1);
12304 
12305         if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12306                 scfdie();
12307 
12308         if ((prop = scf_property_create(g_hndl)) == NULL ||
12309             (val = scf_value_create(g_hndl)) == NULL)
12310                 scfdie();
12311 
12312         if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12313                 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12314                         if (scf_property_get_value(prop, val) != 0)
12315                                 scfdie();
12316                         if (scf_value_get_boolean(val, &b) != 0)
12317                                 scfdie();
12318                 }
12319         }
12320 
12321         free(type);
12322         (void) scf_value_destroy(val);
12323         (void) scf_property_destroy(prop);
12324 
12325         return (b);
12326 }
12327 
12328 #define DELETE_FAILURE                  -1
12329 #define DELETE_SUCCESS_NOEXTDEPS        0
12330 #define DELETE_SUCCESS_EXTDEPS          1
12331 
12332 /*
12333  * lscf_instance_delete() deletes an instance.  Before calling
12334  * scf_instance_delete(), though, we make sure the instance isn't
12335  * running and delete dependencies in other entities which the instance
12336  * declared as "dependents".  If there are dependencies which were
12337  * created for other entities, then instead of deleting the instance we
12338  * make it "empty" by deleting all other property groups and all
12339  * snapshots.
12340  *
12341  * lscf_instance_delete() verifies that there is no external dependency pgs
12342  * before suppressing the instance. If there is, then we must not remove them
12343  * now in case the instance is re-created otherwise the dependencies would be
12344  * lost. The external dependency pgs will be removed if the dependencies are
12345  * removed.
12346  *
12347  * Returns:
12348  *  DELETE_FAILURE              on failure
12349  *  DELETE_SUCCESS_NOEXTDEPS    on success - no external dependencies
12350  *  DELETE_SUCCESS_EXTDEPS      on success - external dependencies
12351  */
12352 static int
12353 lscf_instance_delete(scf_instance_t *inst, int force)
12354 {
12355         scf_propertygroup_t *pg;
12356         scf_snapshot_t *snap;
12357         scf_iter_t *iter;
12358         int err;
12359         int external = 0;
12360 
12361         /* If we're not forcing and the instance is running, refuse. */
12362         if (!force && inst_is_running(inst)) {
12363                 char *fmri;
12364 
12365                 fmri = safe_malloc(max_scf_fmri_len + 1);
12366 
12367                 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12368                         scfdie();
12369 
12370                 semerr(gettext("Instance %s may be running.  "
12371                     "Use delete -f if it is not.\n"), fmri);
12372 
12373                 free(fmri);
12374                 return (DELETE_FAILURE);
12375         }
12376 
12377         pg = scf_pg_create(g_hndl);
12378         if (pg == NULL)
12379                 scfdie();
12380 
12381         if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12382                 (void) delete_dependents(pg);
12383         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12384                 scfdie();
12385 
12386         scf_pg_destroy(pg);
12387 
12388         /*
12389          * If the instance has some external dependencies then we must
12390          * keep them in case the instance is reimported otherwise the
12391          * dependencies would be lost on reimport.
12392          */
12393         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12394             (pg = scf_pg_create(g_hndl)) == NULL)
12395                 scfdie();
12396 
12397         if (scf_iter_instance_pgs(iter, inst) < 0)
12398                 scfdie();
12399 
12400         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12401                 if (pg_is_external_dependency(pg)) {
12402                         external = 1;
12403                         continue;
12404                 }
12405 
12406                 if (scf_pg_delete(pg) != 0) {
12407                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12408                                 scfdie();
12409                         else {
12410                                 semerr(emsg_permission_denied);
12411 
12412                                 (void) scf_iter_destroy(iter);
12413                                 (void) scf_pg_destroy(pg);
12414                                 return (DELETE_FAILURE);
12415                         }
12416                 }
12417         }
12418 
12419         if (err == -1)
12420                 scfdie();
12421 
12422         (void) scf_iter_destroy(iter);
12423         (void) scf_pg_destroy(pg);
12424 
12425         if (external) {
12426                 /*
12427                  * All the pgs have been deleted for the instance except
12428                  * the ones holding the external dependencies.
12429                  * For the job to be complete, we must also delete the
12430                  * snapshots associated with the instance.
12431                  */
12432                 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12433                     NULL)
12434                         scfdie();
12435                 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12436                         scfdie();
12437 
12438                 if (scf_iter_instance_snapshots(iter, inst) == -1)
12439                         scfdie();
12440 
12441                 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12442                         if (_scf_snapshot_delete(snap) != 0) {
12443                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12444                                         scfdie();
12445 
12446                                 semerr(emsg_permission_denied);
12447 
12448                                 (void) scf_iter_destroy(iter);
12449                                 (void) scf_snapshot_destroy(snap);
12450                                 return (DELETE_FAILURE);
12451                         }
12452                 }
12453 
12454                 if (err == -1)
12455                         scfdie();
12456 
12457                 (void) scf_iter_destroy(iter);
12458                 (void) scf_snapshot_destroy(snap);
12459                 return (DELETE_SUCCESS_EXTDEPS);
12460         }
12461 
12462         if (scf_instance_delete(inst) != 0) {
12463                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12464                         scfdie();
12465 
12466                 semerr(emsg_permission_denied);
12467 
12468                 return (DELETE_FAILURE);
12469         }
12470 
12471         return (DELETE_SUCCESS_NOEXTDEPS);
12472 }
12473 
12474 /*
12475  * lscf_service_delete() deletes a service.  Before calling
12476  * scf_service_delete(), though, we call lscf_instance_delete() for
12477  * each of the instances and delete dependencies in other entities
12478  * which were created as "dependents" of this service.  If there are
12479  * dependencies which were created for other entities, then we delete
12480  * all other property groups in the service and leave it as "empty".
12481  *
12482  * lscf_service_delete() verifies that there is no external dependency
12483  * pgs at the instance & service level before suppressing the service.
12484  * If there is, then we must not remove them now in case the service
12485  * is re-imported otherwise the dependencies would be lost. The external
12486  * dependency pgs will be removed if the dependencies are removed.
12487  *
12488  * Returns:
12489  *   DELETE_FAILURE             on failure
12490  *   DELETE_SUCCESS_NOEXTDEPS   on success - no external dependencies
12491  *   DELETE_SUCCESS_EXTDEPS     on success - external dependencies
12492  */
12493 static int
12494 lscf_service_delete(scf_service_t *svc, int force)
12495 {
12496         int r;
12497         scf_instance_t *inst;
12498         scf_propertygroup_t *pg;
12499         scf_iter_t *iter;
12500         int ret;
12501         int external = 0;
12502 
12503         if ((inst = scf_instance_create(g_hndl)) == NULL ||
12504             (pg = scf_pg_create(g_hndl)) == NULL ||
12505             (iter = scf_iter_create(g_hndl)) == NULL)
12506                 scfdie();
12507 
12508         if (scf_iter_service_instances(iter, svc) != 0)
12509                 scfdie();
12510 
12511         for (r = scf_iter_next_instance(iter, inst);
12512             r == 1;
12513             r = scf_iter_next_instance(iter, inst)) {
12514 
12515                 ret = lscf_instance_delete(inst, force);
12516                 if (ret == DELETE_FAILURE) {
12517                         scf_iter_destroy(iter);
12518                         scf_pg_destroy(pg);
12519                         scf_instance_destroy(inst);
12520                         return (DELETE_FAILURE);
12521                 }
12522 
12523                 /*
12524                  * Record the fact that there is some external dependencies
12525                  * at the instance level.
12526                  */
12527                 if (ret == DELETE_SUCCESS_EXTDEPS)
12528                         external |= 1;
12529         }
12530 
12531         if (r != 0)
12532                 scfdie();
12533 
12534         /* Delete dependency property groups in dependent services. */
12535         if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12536                 (void) delete_dependents(pg);
12537         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12538                 scfdie();
12539 
12540         scf_iter_destroy(iter);
12541         scf_pg_destroy(pg);
12542         scf_instance_destroy(inst);
12543 
12544         /*
12545          * If the service has some external dependencies then we don't
12546          * want to remove them in case the service is re-imported.
12547          */
12548         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12549             (iter = scf_iter_create(g_hndl)) == NULL)
12550                 scfdie();
12551 
12552         if (scf_iter_service_pgs(iter, svc) < 0)
12553                 scfdie();
12554 
12555         while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12556                 if (pg_is_external_dependency(pg)) {
12557                         external |= 2;
12558                         continue;
12559                 }
12560 
12561                 if (scf_pg_delete(pg) != 0) {
12562                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12563                                 scfdie();
12564                         else {
12565                                 semerr(emsg_permission_denied);
12566 
12567                                 (void) scf_iter_destroy(iter);
12568                                 (void) scf_pg_destroy(pg);
12569                                 return (DELETE_FAILURE);
12570                         }
12571                 }
12572         }
12573 
12574         if (r == -1)
12575                 scfdie();
12576 
12577         (void) scf_iter_destroy(iter);
12578         (void) scf_pg_destroy(pg);
12579 
12580         if (external != 0)
12581                 return (DELETE_SUCCESS_EXTDEPS);
12582 
12583         if (scf_service_delete(svc) == 0)
12584                 return (DELETE_SUCCESS_NOEXTDEPS);
12585 
12586         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12587                 scfdie();
12588 
12589         semerr(emsg_permission_denied);
12590         return (DELETE_FAILURE);
12591 }
12592 
12593 static int
12594 delete_callback(void *data, scf_walkinfo_t *wip)
12595 {
12596         int force = (int)data;
12597 
12598         if (wip->inst != NULL)
12599                 (void) lscf_instance_delete(wip->inst, force);
12600         else
12601                 (void) lscf_service_delete(wip->svc, force);
12602 
12603         return (0);
12604 }
12605 
12606 void
12607 lscf_delete(const char *fmri, int force)
12608 {
12609         scf_service_t *svc;
12610         scf_instance_t *inst;
12611         int ret;
12612 
12613         lscf_prep_hndl();
12614 
12615         if (cur_snap != NULL) {
12616                 if (!snaplevel_is_instance(cur_level)) {
12617                         char *buf;
12618 
12619                         buf = safe_malloc(max_scf_name_len + 1);
12620                         if (scf_instance_get_name(cur_inst, buf,
12621                             max_scf_name_len + 1) >= 0) {
12622                                 if (strcmp(buf, fmri) == 0) {
12623                                         semerr(emsg_cant_modify_snapshots);
12624                                         free(buf);
12625                                         return;
12626                                 }
12627                         } else if (scf_error() != SCF_ERROR_DELETED) {
12628                                 scfdie();
12629                         }
12630                         free(buf);
12631                 }
12632         } else if (cur_inst != NULL) {
12633                 /* EMPTY */;
12634         } else if (cur_svc != NULL) {
12635                 inst = scf_instance_create(g_hndl);
12636                 if (inst == NULL)
12637                         scfdie();
12638 
12639                 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12640                     SCF_SUCCESS) {
12641                         (void) lscf_instance_delete(inst, force);
12642                         scf_instance_destroy(inst);
12643                         return;
12644                 }
12645 
12646                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12647                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12648                         scfdie();
12649 
12650                 scf_instance_destroy(inst);
12651         } else {
12652                 assert(cur_scope != NULL);
12653 
12654                 svc = scf_service_create(g_hndl);
12655                 if (svc == NULL)
12656                         scfdie();
12657 
12658                 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12659                     SCF_SUCCESS) {
12660                         (void) lscf_service_delete(svc, force);
12661                         scf_service_destroy(svc);
12662                         return;
12663                 }
12664 
12665                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12666                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12667                         scfdie();
12668 
12669                 scf_service_destroy(svc);
12670         }
12671 
12672         /*
12673          * Match FMRI to entity.
12674          */
12675         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12676             delete_callback, (void *)force, NULL, semerr)) != 0) {
12677                 semerr(gettext("Failed to walk instances: %s\n"),
12678                     scf_strerror(ret));
12679         }
12680 }
12681 
12682 
12683 
12684 /*
12685  * :properties commands.  These all end with "pg" or "prop" and generally
12686  * operate on the currently selected entity.
12687  */
12688 
12689 /*
12690  * Property listing.  List the property groups, properties, their types and
12691  * their values for the currently selected entity.
12692  */
12693 static void
12694 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12695 {
12696         char *buf;
12697         uint32_t flags;
12698 
12699         buf = safe_malloc(max_scf_pg_type_len + 1);
12700 
12701         if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12702                 scfdie();
12703 
12704         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12705                 scfdie();
12706 
12707         safe_printf("%-*s  %s", namewidth, name, buf);
12708 
12709         if (flags & SCF_PG_FLAG_NONPERSISTENT)
12710                 safe_printf("\tNONPERSISTENT");
12711 
12712         safe_printf("\n");
12713 
12714         free(buf);
12715 }
12716 
12717 static boolean_t
12718 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12719 {
12720         if (scf_property_get_value(prop, val) == 0) {
12721                 return (B_FALSE);
12722         } else {
12723                 switch (scf_error()) {
12724                 case SCF_ERROR_NOT_FOUND:
12725                         return (B_FALSE);
12726                 case SCF_ERROR_PERMISSION_DENIED:
12727                 case SCF_ERROR_CONSTRAINT_VIOLATED:
12728                         return (B_TRUE);
12729                 default:
12730                         scfdie();
12731                         /*NOTREACHED*/
12732                 }
12733         }
12734 }
12735 
12736 static void
12737 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12738 {
12739         scf_iter_t *iter;
12740         scf_value_t *val;
12741         const char *type;
12742         int multiple_strings = 0;
12743         int ret;
12744 
12745         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12746             (val = scf_value_create(g_hndl)) == NULL)
12747                 scfdie();
12748 
12749         type = prop_to_typestr(prop);
12750         assert(type != NULL);
12751 
12752         safe_printf("%-*s  %-7s ", len, name, type);
12753 
12754         if (prop_has_multiple_values(prop, val) &&
12755             (scf_value_type(val) == SCF_TYPE_ASTRING ||
12756             scf_value_type(val) == SCF_TYPE_USTRING))
12757                 multiple_strings = 1;
12758 
12759         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12760                 scfdie();
12761 
12762         while ((ret = scf_iter_next_value(iter, val)) == 1) {
12763                 char *buf;
12764                 ssize_t vlen, szret;
12765 
12766                 vlen = scf_value_get_as_string(val, NULL, 0);
12767                 if (vlen < 0)
12768                         scfdie();
12769 
12770                 buf = safe_malloc(vlen + 1);
12771 
12772                 szret = scf_value_get_as_string(val, buf, vlen + 1);
12773                 if (szret < 0)
12774                         scfdie();
12775                 assert(szret <= vlen);
12776 
12777                 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12778                 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12779                         safe_printf(" \"");
12780                         (void) quote_and_print(buf, stdout, 0);
12781                         (void) putchar('"');
12782                         if (ferror(stdout)) {
12783                                 (void) putchar('\n');
12784                                 uu_die(gettext("Error writing to stdout.\n"));
12785                         }
12786                 } else {
12787                         safe_printf(" %s", buf);
12788                 }
12789 
12790                 free(buf);
12791         }
12792         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12793                 scfdie();
12794 
12795         if (putchar('\n') != '\n')
12796                 uu_die(gettext("Could not output newline"));
12797 }
12798 
12799 /*
12800  * Outputs template property group info for the describe subcommand.
12801  * If 'templates' == 2, verbose output is printed in the format expected
12802  * for describe -v, which includes all templates fields.  If pg is
12803  * not NULL, we're describing the template data, not an existing property
12804  * group, and formatting should be appropriate for describe -t.
12805  */
12806 static void
12807 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12808 {
12809         char *buf;
12810         uint8_t required;
12811         scf_property_t *stability_prop;
12812         scf_value_t *stability_val;
12813 
12814         if (templates == 0)
12815                 return;
12816 
12817         if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12818             (stability_val = scf_value_create(g_hndl)) == NULL)
12819                 scfdie();
12820 
12821         if (templates == 2 && pg != NULL) {
12822                 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12823                     stability_prop) == 0) {
12824                         if (prop_check_type(stability_prop,
12825                             SCF_TYPE_ASTRING) == 0 &&
12826                             prop_get_val(stability_prop, stability_val) == 0) {
12827                                 char *stability;
12828 
12829                                 stability = safe_malloc(max_scf_value_len + 1);
12830 
12831                                 if (scf_value_get_astring(stability_val,
12832                                     stability, max_scf_value_len + 1) == -1 &&
12833                                     scf_error() != SCF_ERROR_NOT_FOUND)
12834                                         scfdie();
12835 
12836                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
12837                                     gettext("stability"), stability);
12838 
12839                                 free(stability);
12840                         }
12841                 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12842                         scfdie();
12843         }
12844 
12845         scf_property_destroy(stability_prop);
12846         scf_value_destroy(stability_val);
12847 
12848         if (pgt == NULL)
12849                 return;
12850 
12851         if (pg == NULL || templates == 2) {
12852                 /* print type info only if scf_tmpl_pg_name succeeds */
12853                 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12854                         if (pg != NULL)
12855                                 safe_printf("%s", TMPL_INDENT);
12856                         safe_printf("%s: ", gettext("name"));
12857                         safe_printf("%s\n", buf);
12858                         free(buf);
12859                 }
12860 
12861                 /* print type info only if scf_tmpl_pg_type succeeds */
12862                 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12863                         if (pg != NULL)
12864                                 safe_printf("%s", TMPL_INDENT);
12865                         safe_printf("%s: ", gettext("type"));
12866                         safe_printf("%s\n", buf);
12867                         free(buf);
12868                 }
12869         }
12870 
12871         if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12872                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12873                     required ? "true" : "false");
12874 
12875         if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12876                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12877                     buf);
12878                 free(buf);
12879         }
12880 
12881         if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12882                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12883                     buf);
12884                 free(buf);
12885         }
12886 
12887         if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12888                 if (templates == 2)
12889                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12890                             gettext("description"), buf);
12891                 else
12892                         safe_printf("%s%s\n", TMPL_INDENT, buf);
12893                 free(buf);
12894         }
12895 
12896 }
12897 
12898 /*
12899  * With as_value set to true, indent as appropriate for the value level.
12900  * If false, indent to appropriate level for inclusion in constraint
12901  * or choice printout.
12902  */
12903 static void
12904 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12905     int as_value)
12906 {
12907         char *buf;
12908 
12909         if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12910                 if (as_value == 0)
12911                         safe_printf("%s", TMPL_CHOICE_INDENT);
12912                 else
12913                         safe_printf("%s", TMPL_INDENT);
12914                 safe_printf("%s: %s\n", gettext("value common name"), buf);
12915                 free(buf);
12916         }
12917 
12918         if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12919                 if (as_value == 0)
12920                         safe_printf("%s", TMPL_CHOICE_INDENT);
12921                 else
12922                         safe_printf("%s", TMPL_INDENT);
12923                 safe_printf("%s: %s\n", gettext("value description"), buf);
12924                 free(buf);
12925         }
12926 }
12927 
12928 static void
12929 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12930 {
12931         safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12932         /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12933         safe_printf("%s\n", val_buf);
12934 
12935         print_template_value_details(prt, val_buf, 1);
12936 }
12937 
12938 static void
12939 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12940 {
12941         int i, printed = 0;
12942         scf_values_t values;
12943         scf_count_ranges_t c_ranges;
12944         scf_int_ranges_t i_ranges;
12945 
12946         printed = 0;
12947         i = 0;
12948         if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12949                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12950                     gettext("value constraints"));
12951                 printed++;
12952                 for (i = 0; i < values.value_count; ++i) {
12953                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12954                             gettext("value name"), values.values_as_strings[i]);
12955                         if (verbose == 1)
12956                                 print_template_value_details(prt,
12957                                     values.values_as_strings[i], 0);
12958                 }
12959 
12960                 scf_values_destroy(&values);
12961         }
12962 
12963         if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12964                 if (printed++ == 0)
12965                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12966                             gettext("value constraints"));
12967                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12968                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12969                             gettext("range"), c_ranges.scr_min[i],
12970                             c_ranges.scr_max[i]);
12971                 }
12972                 scf_count_ranges_destroy(&c_ranges);
12973         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12974             scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12975                 if (printed++ == 0)
12976                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12977                             gettext("value constraints"));
12978                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12979                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12980                             gettext("range"), i_ranges.sir_min[i],
12981                             i_ranges.sir_max[i]);
12982                 }
12983                 scf_int_ranges_destroy(&i_ranges);
12984         }
12985 }
12986 
12987 static void
12988 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12989 {
12990         int i = 0, printed = 0;
12991         scf_values_t values;
12992         scf_count_ranges_t c_ranges;
12993         scf_int_ranges_t i_ranges;
12994 
12995         printed = 0;
12996         if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12997                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12998                     gettext("value constraints"));
12999                 printed++;
13000                 for (i = 0; i < values.value_count; i++) {
13001                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13002                             gettext("value name"), values.values_as_strings[i]);
13003                         if (verbose == 1)
13004                                 print_template_value_details(prt,
13005                                     values.values_as_strings[i], 0);
13006                 }
13007 
13008                 scf_values_destroy(&values);
13009         }
13010 
13011         if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13012                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13013                         if (printed++ == 0)
13014                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13015                                     gettext("value choices"));
13016                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13017                             gettext("range"), c_ranges.scr_min[i],
13018                             c_ranges.scr_max[i]);
13019                 }
13020                 scf_count_ranges_destroy(&c_ranges);
13021         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13022             scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13023                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13024                         if (printed++ == 0)
13025                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13026                                     gettext("value choices"));
13027                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13028                             gettext("range"), i_ranges.sir_min[i],
13029                             i_ranges.sir_max[i]);
13030                 }
13031                 scf_int_ranges_destroy(&i_ranges);
13032         }
13033 }
13034 
13035 static void
13036 list_values_by_template(scf_prop_tmpl_t *prt)
13037 {
13038         print_template_constraints(prt, 1);
13039         print_template_choices(prt, 1);
13040 }
13041 
13042 static void
13043 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13044 {
13045         char *val_buf;
13046         scf_iter_t *iter;
13047         scf_value_t *val;
13048         int ret;
13049 
13050         if ((iter = scf_iter_create(g_hndl)) == NULL ||
13051             (val = scf_value_create(g_hndl)) == NULL)
13052                 scfdie();
13053 
13054         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13055                 scfdie();
13056 
13057         val_buf = safe_malloc(max_scf_value_len + 1);
13058 
13059         while ((ret = scf_iter_next_value(iter, val)) == 1) {
13060                 if (scf_value_get_as_string(val, val_buf,
13061                     max_scf_value_len + 1) < 0)
13062                         scfdie();
13063 
13064                 print_template_value(prt, val_buf);
13065         }
13066         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13067                 scfdie();
13068         free(val_buf);
13069 
13070         print_template_constraints(prt, 0);
13071         print_template_choices(prt, 0);
13072 
13073 }
13074 
13075 /*
13076  * Outputs property info for the describe subcommand
13077  * Verbose output if templates == 2, -v option of svccfg describe
13078  * Displays template data if prop is not NULL, -t option of svccfg describe
13079  */
13080 static void
13081 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13082 {
13083         char *buf;
13084         uint8_t u_buf;
13085         int i;
13086         uint64_t min, max;
13087         scf_values_t values;
13088 
13089         if (prt == NULL || templates == 0)
13090                 return;
13091 
13092         if (prop == NULL) {
13093                 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13094                 if (scf_tmpl_prop_name(prt, &buf) > 0) {
13095                         safe_printf("%s\n", buf);
13096                         free(buf);
13097                 } else
13098                         safe_printf("(%s)\n", gettext("any"));
13099         }
13100 
13101         if (prop == NULL || templates == 2) {
13102                 if (prop != NULL)
13103                         safe_printf("%s", TMPL_INDENT);
13104                 else
13105                         safe_printf("%s", TMPL_VALUE_INDENT);
13106                 safe_printf("%s: ", gettext("type"));
13107                 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13108                         safe_printf("%s\n", buf);
13109                         free(buf);
13110                 } else
13111                         safe_printf("(%s)\n", gettext("any"));
13112         }
13113 
13114         if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13115                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13116                     u_buf ? "true" : "false");
13117 
13118         if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13119                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13120                     buf);
13121                 free(buf);
13122         }
13123 
13124         if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13125                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13126                     buf);
13127                 free(buf);
13128         }
13129 
13130         if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13131                 safe_printf("%s%s\n", TMPL_INDENT, buf);
13132                 free(buf);
13133         }
13134 
13135         if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13136                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13137                     scf_tmpl_visibility_to_string(u_buf));
13138 
13139         if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13140                 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13141                     gettext("minimum number of values"), min);
13142                 if (max == ULLONG_MAX) {
13143                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13144                             gettext("maximum number of values"),
13145                             gettext("unlimited"));
13146                 } else {
13147                         safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13148                             gettext("maximum number of values"), max);
13149                 }
13150         }
13151 
13152         if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13153                 for (i = 0; i < values.value_count; i++) {
13154                         if (i == 0) {
13155                                 safe_printf("%s%s:", TMPL_INDENT,
13156                                     gettext("internal separators"));
13157                         }
13158                         safe_printf(" \"%s\"", values.values_as_strings[i]);
13159                 }
13160                 safe_printf("\n");
13161         }
13162 
13163         if (templates != 2)
13164                 return;
13165 
13166         if (prop != NULL)
13167                 list_values_tmpl(prt, prop);
13168         else
13169                 list_values_by_template(prt);
13170 }
13171 
13172 static char *
13173 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13174 {
13175         char *rv;
13176 
13177         rv = _scf_read_single_astring_from_pg(pg, prop_name);
13178         if (rv == NULL) {
13179                 switch (scf_error()) {
13180                 case SCF_ERROR_NOT_FOUND:
13181                         break;
13182                 default:
13183                         scfdie();
13184                 }
13185         }
13186         return (rv);
13187 }
13188 
13189 static void
13190 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13191 {
13192         size_t doc_len;
13193         size_t man_len;
13194         char *pg_name;
13195         char *text = NULL;
13196         int rv;
13197 
13198         doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13199         man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13200         pg_name = safe_malloc(max_scf_name_len + 1);
13201         while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13202                 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13203                         scfdie();
13204                 }
13205                 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13206                         /* Display doc_link and and uri */
13207                         safe_printf("%s%s:\n", TMPL_INDENT,
13208                             gettext("doc_link"));
13209                         text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13210                         if (text != NULL) {
13211                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13212                                     TMPL_INDENT, gettext("name"), text);
13213                                 uu_free(text);
13214                         }
13215                         text = read_astring(pg, SCF_PROPERTY_TM_URI);
13216                         if (text != NULL) {
13217                                 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13218                                     gettext("uri"), text);
13219                                 uu_free(text);
13220                         }
13221                 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13222                     man_len) == 0) {
13223                         /* Display manpage title, section and path */
13224                         safe_printf("%s%s:\n", TMPL_INDENT,
13225                             gettext("manpage"));
13226                         text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13227                         if (text != NULL) {
13228                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13229                                     TMPL_INDENT, gettext("title"), text);
13230                                 uu_free(text);
13231                         }
13232                         text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13233                         if (text != NULL) {
13234                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13235                                     TMPL_INDENT, gettext("section"), text);
13236                                 uu_free(text);
13237                         }
13238                         text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13239                         if (text != NULL) {
13240                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13241                                     TMPL_INDENT, gettext("manpath"), text);
13242                                 uu_free(text);
13243                         }
13244                 }
13245         }
13246         if (rv == -1)
13247                 scfdie();
13248 
13249 done:
13250         free(pg_name);
13251 }
13252 
13253 static void
13254 list_entity_tmpl(int templates)
13255 {
13256         char *common_name = NULL;
13257         char *description = NULL;
13258         char *locale = NULL;
13259         scf_iter_t *iter;
13260         scf_propertygroup_t *pg;
13261         scf_property_t *prop;
13262         int r;
13263         scf_value_t *val;
13264 
13265         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13266             (prop = scf_property_create(g_hndl)) == NULL ||
13267             (val = scf_value_create(g_hndl)) == NULL ||
13268             (iter = scf_iter_create(g_hndl)) == NULL)
13269                 scfdie();
13270 
13271         locale = setlocale(LC_MESSAGES, NULL);
13272 
13273         if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13274                 common_name = safe_malloc(max_scf_value_len + 1);
13275 
13276                 /* Try both the current locale and the "C" locale. */
13277                 if (scf_pg_get_property(pg, locale, prop) == 0 ||
13278                     (scf_error() == SCF_ERROR_NOT_FOUND &&
13279                     scf_pg_get_property(pg, "C", prop) == 0)) {
13280                         if (prop_get_val(prop, val) == 0 &&
13281                             scf_value_get_ustring(val, common_name,
13282                             max_scf_value_len + 1) != -1) {
13283                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
13284                                     gettext("common name"), common_name);
13285                         }
13286                 }
13287         }
13288 
13289         /*
13290          * Do description, manpages, and doc links if templates == 2.
13291          */
13292         if (templates == 2) {
13293                 /* Get the description. */
13294                 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13295                         description = safe_malloc(max_scf_value_len + 1);
13296 
13297                         /* Try both the current locale and the "C" locale. */
13298                         if (scf_pg_get_property(pg, locale, prop) == 0 ||
13299                             (scf_error() == SCF_ERROR_NOT_FOUND &&
13300                             scf_pg_get_property(pg, "C", prop) == 0)) {
13301                                 if (prop_get_val(prop, val) == 0 &&
13302                                     scf_value_get_ustring(val, description,
13303                                     max_scf_value_len + 1) != -1) {
13304                                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13305                                             gettext("description"),
13306                                             description);
13307                                 }
13308                         }
13309                 }
13310 
13311                 /* Process doc_link & manpage elements. */
13312                 if (cur_level != NULL) {
13313                         r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13314                             SCF_GROUP_TEMPLATE);
13315                 } else if (cur_inst != NULL) {
13316                         r = scf_iter_instance_pgs_typed(iter, cur_inst,
13317                             SCF_GROUP_TEMPLATE);
13318                 } else {
13319                         r = scf_iter_service_pgs_typed(iter, cur_svc,
13320                             SCF_GROUP_TEMPLATE);
13321                 }
13322                 if (r == 0) {
13323                         display_documentation(iter, pg);
13324                 }
13325         }
13326 
13327         free(common_name);
13328         free(description);
13329         scf_pg_destroy(pg);
13330         scf_property_destroy(prop);
13331         scf_value_destroy(val);
13332         scf_iter_destroy(iter);
13333 }
13334 
13335 static void
13336 listtmpl(const char *pattern, int templates)
13337 {
13338         scf_pg_tmpl_t *pgt;
13339         scf_prop_tmpl_t *prt;
13340         char *snapbuf = NULL;
13341         char *fmribuf;
13342         char *pg_name = NULL, *prop_name = NULL;
13343         ssize_t prop_name_size;
13344         char *qual_prop_name;
13345         char *search_name;
13346         int listed = 0;
13347 
13348         if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13349             (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13350                 scfdie();
13351 
13352         fmribuf = safe_malloc(max_scf_name_len + 1);
13353         qual_prop_name = safe_malloc(max_scf_name_len + 1);
13354 
13355         if (cur_snap != NULL) {
13356                 snapbuf = safe_malloc(max_scf_name_len + 1);
13357                 if (scf_snapshot_get_name(cur_snap, snapbuf,
13358                     max_scf_name_len + 1) < 0)
13359                         scfdie();
13360         }
13361 
13362         if (cur_inst != NULL) {
13363                 if (scf_instance_to_fmri(cur_inst, fmribuf,
13364                     max_scf_name_len + 1) < 0)
13365                         scfdie();
13366         } else if (cur_svc != NULL) {
13367                 if (scf_service_to_fmri(cur_svc, fmribuf,
13368                     max_scf_name_len + 1) < 0)
13369                         scfdie();
13370         } else
13371                 abort();
13372 
13373         /* If pattern is specified, we want to list only those items. */
13374         while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13375                 listed = 0;
13376                 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13377                     fnmatch(pattern, pg_name, 0) == 0)) {
13378                         list_pg_tmpl(pgt, NULL, templates);
13379                         listed++;
13380                 }
13381 
13382                 scf_tmpl_prop_reset(prt);
13383 
13384                 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13385                         search_name = NULL;
13386                         prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13387                         if ((prop_name_size > 0) && (pg_name != NULL)) {
13388                                 if (snprintf(qual_prop_name,
13389                                     max_scf_name_len + 1, "%s/%s",
13390                                     pg_name, prop_name) >=
13391                                     max_scf_name_len + 1) {
13392                                         prop_name_size = -1;
13393                                 } else {
13394                                         search_name = qual_prop_name;
13395                                 }
13396                         }
13397                         if (listed > 0 || pattern == NULL ||
13398                             (prop_name_size > 0 &&
13399                             fnmatch(pattern, search_name,
13400                             FNM_PATHNAME) == 0))
13401                                 list_prop_tmpl(prt, NULL, templates);
13402                         if (prop_name != NULL) {
13403                                 free(prop_name);
13404                                 prop_name = NULL;
13405                         }
13406                 }
13407                 if (pg_name != NULL) {
13408                         free(pg_name);
13409                         pg_name = NULL;
13410                 }
13411         }
13412 
13413         scf_tmpl_prop_destroy(prt);
13414         scf_tmpl_pg_destroy(pgt);
13415         free(snapbuf);
13416         free(fmribuf);
13417         free(qual_prop_name);
13418 }
13419 
13420 static void
13421 listprop(const char *pattern, int only_pgs, int templates)
13422 {
13423         scf_propertygroup_t *pg;
13424         scf_property_t *prop;
13425         scf_iter_t *iter, *piter;
13426         char *pgnbuf, *prnbuf, *ppnbuf;
13427         scf_pg_tmpl_t *pgt, *pgtp;
13428         scf_prop_tmpl_t *prt;
13429 
13430         void **objects;
13431         char **names;
13432         void **tmpls;
13433         int allocd, i;
13434 
13435         int ret;
13436         ssize_t pgnlen, prnlen, szret;
13437         size_t max_len = 0;
13438 
13439         if (cur_svc == NULL && cur_inst == NULL) {
13440                 semerr(emsg_entity_not_selected);
13441                 return;
13442         }
13443 
13444         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13445             (prop = scf_property_create(g_hndl)) == NULL ||
13446             (iter = scf_iter_create(g_hndl)) == NULL ||
13447             (piter = scf_iter_create(g_hndl)) == NULL ||
13448             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13449             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13450                 scfdie();
13451 
13452         prnbuf = safe_malloc(max_scf_name_len + 1);
13453 
13454         if (cur_level != NULL)
13455                 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13456         else if (cur_inst != NULL)
13457                 ret = scf_iter_instance_pgs(iter, cur_inst);
13458         else
13459                 ret = scf_iter_service_pgs(iter, cur_svc);
13460         if (ret != 0) {
13461                 return;
13462         }
13463 
13464         /*
13465          * We want to only list items which match pattern, and we want the
13466          * second column to line up, so during the first pass we'll save
13467          * matching items, their names, and their templates in objects,
13468          * names, and tmpls, computing the maximum name length as we go,
13469          * and then we'll print them out.
13470          *
13471          * Note: We always keep an extra slot available so the array can be
13472          * NULL-terminated.
13473          */
13474         i = 0;
13475         allocd = 1;
13476         objects = safe_malloc(sizeof (*objects));
13477         names = safe_malloc(sizeof (*names));
13478         tmpls = safe_malloc(sizeof (*tmpls));
13479 
13480         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13481                 int new_pg = 0;
13482                 int print_props = 0;
13483                 pgtp = NULL;
13484 
13485                 pgnlen = scf_pg_get_name(pg, NULL, 0);
13486                 if (pgnlen < 0)
13487                         scfdie();
13488 
13489                 pgnbuf = safe_malloc(pgnlen + 1);
13490 
13491                 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13492                 if (szret < 0)
13493                         scfdie();
13494                 assert(szret <= pgnlen);
13495 
13496                 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13497                         if (scf_error() != SCF_ERROR_NOT_FOUND)
13498                                 scfdie();
13499                         pgtp = NULL;
13500                 } else {
13501                         pgtp = pgt;
13502                 }
13503 
13504                 if (pattern == NULL ||
13505                     fnmatch(pattern, pgnbuf, 0) == 0) {
13506                         if (i+1 >= allocd) {
13507                                 allocd *= 2;
13508                                 objects = realloc(objects,
13509                                     sizeof (*objects) * allocd);
13510                                 names =
13511                                     realloc(names, sizeof (*names) * allocd);
13512                                 tmpls = realloc(tmpls,
13513                                     sizeof (*tmpls) * allocd);
13514                                 if (objects == NULL || names == NULL ||
13515                                     tmpls == NULL)
13516                                         uu_die(gettext("Out of memory"));
13517                         }
13518                         objects[i] = pg;
13519                         names[i] = pgnbuf;
13520 
13521                         if (pgtp == NULL)
13522                                 tmpls[i] = NULL;
13523                         else
13524                                 tmpls[i] = pgt;
13525 
13526                         ++i;
13527 
13528                         if (pgnlen > max_len)
13529                                 max_len = pgnlen;
13530 
13531                         new_pg = 1;
13532                         print_props = 1;
13533                 }
13534 
13535                 if (only_pgs) {
13536                         if (new_pg) {
13537                                 pg = scf_pg_create(g_hndl);
13538                                 if (pg == NULL)
13539                                         scfdie();
13540                                 pgt = scf_tmpl_pg_create(g_hndl);
13541                                 if (pgt == NULL)
13542                                         scfdie();
13543                         } else
13544                                 free(pgnbuf);
13545 
13546                         continue;
13547                 }
13548 
13549                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13550                         scfdie();
13551 
13552                 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13553                         prnlen = scf_property_get_name(prop, prnbuf,
13554                             max_scf_name_len + 1);
13555                         if (prnlen < 0)
13556                                 scfdie();
13557 
13558                         /* Will prepend the property group name and a slash. */
13559                         prnlen += pgnlen + 1;
13560 
13561                         ppnbuf = safe_malloc(prnlen + 1);
13562 
13563                         if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13564                             prnbuf) < 0)
13565                                 uu_die("snprintf");
13566 
13567                         if (pattern == NULL || print_props == 1 ||
13568                             fnmatch(pattern, ppnbuf, 0) == 0) {
13569                                 if (i+1 >= allocd) {
13570                                         allocd *= 2;
13571                                         objects = realloc(objects,
13572                                             sizeof (*objects) * allocd);
13573                                         names = realloc(names,
13574                                             sizeof (*names) * allocd);
13575                                         tmpls = realloc(tmpls,
13576                                             sizeof (*tmpls) * allocd);
13577                                         if (objects == NULL || names == NULL ||
13578                                             tmpls == NULL)
13579                                                 uu_die(gettext(
13580                                                     "Out of memory"));
13581                                 }
13582 
13583                                 objects[i] = prop;
13584                                 names[i] = ppnbuf;
13585 
13586                                 if (pgtp != NULL) {
13587                                         if (scf_tmpl_get_by_prop(pgt, prnbuf,
13588                                             prt, 0) < 0) {
13589                                                 if (scf_error() !=
13590                                                     SCF_ERROR_NOT_FOUND)
13591                                                         scfdie();
13592                                                 tmpls[i] = NULL;
13593                                         } else {
13594                                                 tmpls[i] = prt;
13595                                         }
13596                                 } else {
13597                                         tmpls[i] = NULL;
13598                                 }
13599 
13600                                 ++i;
13601 
13602                                 if (prnlen > max_len)
13603                                         max_len = prnlen;
13604 
13605                                 prop = scf_property_create(g_hndl);
13606                                 prt = scf_tmpl_prop_create(g_hndl);
13607                         } else {
13608                                 free(ppnbuf);
13609                         }
13610                 }
13611 
13612                 if (new_pg) {
13613                         pg = scf_pg_create(g_hndl);
13614                         if (pg == NULL)
13615                                 scfdie();
13616                         pgt = scf_tmpl_pg_create(g_hndl);
13617                         if (pgt == NULL)
13618                                 scfdie();
13619                 } else
13620                         free(pgnbuf);
13621         }
13622         if (ret != 0)
13623                 scfdie();
13624 
13625         objects[i] = NULL;
13626 
13627         scf_pg_destroy(pg);
13628         scf_tmpl_pg_destroy(pgt);
13629         scf_property_destroy(prop);
13630         scf_tmpl_prop_destroy(prt);
13631 
13632         for (i = 0; objects[i] != NULL; ++i) {
13633                 if (strchr(names[i], '/') == NULL) {
13634                         /* property group */
13635                         pg = (scf_propertygroup_t *)objects[i];
13636                         pgt = (scf_pg_tmpl_t *)tmpls[i];
13637                         list_pg_info(pg, names[i], max_len);
13638                         list_pg_tmpl(pgt, pg, templates);
13639                         free(names[i]);
13640                         scf_pg_destroy(pg);
13641                         if (pgt != NULL)
13642                                 scf_tmpl_pg_destroy(pgt);
13643                 } else {
13644                         /* property */
13645                         prop = (scf_property_t *)objects[i];
13646                         prt = (scf_prop_tmpl_t *)tmpls[i];
13647                         list_prop_info(prop, names[i], max_len);
13648                         list_prop_tmpl(prt, prop, templates);
13649                         free(names[i]);
13650                         scf_property_destroy(prop);
13651                         if (prt != NULL)
13652                                 scf_tmpl_prop_destroy(prt);
13653                 }
13654         }
13655 
13656         free(names);
13657         free(objects);
13658         free(tmpls);
13659 }
13660 
13661 void
13662 lscf_listpg(const char *pattern)
13663 {
13664         lscf_prep_hndl();
13665 
13666         listprop(pattern, 1, 0);
13667 }
13668 
13669 /*
13670  * Property group and property creation, setting, and deletion.  setprop (and
13671  * its alias, addprop) can either create a property group of a given type, or
13672  * it can create or set a property to a given type and list of values.
13673  */
13674 void
13675 lscf_addpg(const char *name, const char *type, const char *flags)
13676 {
13677         scf_propertygroup_t *pg;
13678         int ret;
13679         uint32_t flgs = 0;
13680         const char *cp;
13681 
13682 
13683         lscf_prep_hndl();
13684 
13685         if (cur_snap != NULL) {
13686                 semerr(emsg_cant_modify_snapshots);
13687                 return;
13688         }
13689 
13690         if (cur_inst == NULL && cur_svc == NULL) {
13691                 semerr(emsg_entity_not_selected);
13692                 return;
13693         }
13694 
13695         if (flags != NULL) {
13696                 for (cp = flags; *cp != '\0'; ++cp) {
13697                         switch (*cp) {
13698                         case 'P':
13699                                 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13700                                 break;
13701 
13702                         case 'p':
13703                                 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13704                                 break;
13705 
13706                         default:
13707                                 semerr(gettext("Invalid property group flag "
13708                                     "%c."), *cp);
13709                                 return;
13710                         }
13711                 }
13712         }
13713 
13714         pg = scf_pg_create(g_hndl);
13715         if (pg == NULL)
13716                 scfdie();
13717 
13718         if (cur_inst != NULL)
13719                 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13720         else
13721                 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13722 
13723         if (ret != SCF_SUCCESS) {
13724                 switch (scf_error()) {
13725                 case SCF_ERROR_INVALID_ARGUMENT:
13726                         semerr(gettext("Name, type, or flags are invalid.\n"));
13727                         break;
13728 
13729                 case SCF_ERROR_EXISTS:
13730                         semerr(gettext("Property group already exists.\n"));
13731                         break;
13732 
13733                 case SCF_ERROR_PERMISSION_DENIED:
13734                         semerr(emsg_permission_denied);
13735                         break;
13736 
13737                 case SCF_ERROR_BACKEND_ACCESS:
13738                         semerr(gettext("Backend refused access.\n"));
13739                         break;
13740 
13741                 default:
13742                         scfdie();
13743                 }
13744         }
13745 
13746         scf_pg_destroy(pg);
13747 
13748         private_refresh();
13749 }
13750 
13751 void
13752 lscf_delpg(char *name)
13753 {
13754         lscf_prep_hndl();
13755 
13756         if (cur_snap != NULL) {
13757                 semerr(emsg_cant_modify_snapshots);
13758                 return;
13759         }
13760 
13761         if (cur_inst == NULL && cur_svc == NULL) {
13762                 semerr(emsg_entity_not_selected);
13763                 return;
13764         }
13765 
13766         if (strchr(name, '/') != NULL) {
13767                 semerr(emsg_invalid_pg_name, name);
13768                 return;
13769         }
13770 
13771         lscf_delprop(name);
13772 }
13773 
13774 /*
13775  * scf_delhash() is used to remove the property group related to the
13776  * hash entry for a specific manifest in the repository. pgname will be
13777  * constructed from the location of the manifest file. If deathrow isn't 0,
13778  * manifest file doesn't need to exist (manifest string will be used as
13779  * an absolute path).
13780  */
13781 void
13782 lscf_delhash(char *manifest, int deathrow)
13783 {
13784         char *pgname;
13785 
13786         if (cur_snap != NULL ||
13787             cur_inst != NULL || cur_svc != NULL) {
13788                 warn(gettext("error, an entity is selected\n"));
13789                 return;
13790         }
13791 
13792         /* select smf/manifest */
13793         lscf_select(HASH_SVC);
13794         /*
13795          * Translate the manifest file name to property name. In the deathrow
13796          * case, the manifest file does not need to exist.
13797          */
13798         pgname = mhash_filename_to_propname(manifest,
13799             deathrow ? B_TRUE : B_FALSE);
13800         if (pgname == NULL) {
13801                 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13802                 return;
13803         }
13804         /* delete the hash property name */
13805         lscf_delpg(pgname);
13806 }
13807 
13808 void
13809 lscf_listprop(const char *pattern)
13810 {
13811         lscf_prep_hndl();
13812 
13813         listprop(pattern, 0, 0);
13814 }
13815 
13816 int
13817 lscf_setprop(const char *pgname, const char *type, const char *value,
13818     const uu_list_t *values)
13819 {
13820         scf_type_t ty, current_ty;
13821         scf_service_t *svc;
13822         scf_propertygroup_t *pg, *parent_pg;
13823         scf_property_t *prop, *parent_prop;
13824         scf_pg_tmpl_t *pgt;
13825         scf_prop_tmpl_t *prt;
13826         int ret, result = 0;
13827         scf_transaction_t *tx;
13828         scf_transaction_entry_t *e;
13829         scf_value_t *v;
13830         uu_list_walk_t *walk;
13831         string_list_t *sp;
13832         char *propname;
13833         int req_quotes = 0;
13834 
13835         lscf_prep_hndl();
13836 
13837         if ((e = scf_entry_create(g_hndl)) == NULL ||
13838             (svc = scf_service_create(g_hndl)) == NULL ||
13839             (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13840             (pg = scf_pg_create(g_hndl)) == NULL ||
13841             (parent_prop = scf_property_create(g_hndl)) == NULL ||
13842             (prop = scf_property_create(g_hndl)) == NULL ||
13843             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13844             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13845             (tx = scf_transaction_create(g_hndl)) == NULL)
13846                 scfdie();
13847 
13848         if (cur_snap != NULL) {
13849                 semerr(emsg_cant_modify_snapshots);
13850                 goto fail;
13851         }
13852 
13853         if (cur_inst == NULL && cur_svc == NULL) {
13854                 semerr(emsg_entity_not_selected);
13855                 goto fail;
13856         }
13857 
13858         propname = strchr(pgname, '/');
13859         if (propname == NULL) {
13860                 semerr(gettext("Property names must contain a `/'.\n"));
13861                 goto fail;
13862         }
13863 
13864         *propname = '\0';
13865         ++propname;
13866 
13867         if (type != NULL) {
13868                 ty = string_to_type(type);
13869                 if (ty == SCF_TYPE_INVALID) {
13870                         semerr(gettext("Unknown type \"%s\".\n"), type);
13871                         goto fail;
13872                 }
13873         }
13874 
13875         if (cur_inst != NULL)
13876                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13877         else
13878                 ret = scf_service_get_pg(cur_svc, pgname, pg);
13879         if (ret != SCF_SUCCESS) {
13880                 switch (scf_error()) {
13881                 case SCF_ERROR_NOT_FOUND:
13882                         semerr(emsg_no_such_pg, pgname);
13883                         goto fail;
13884 
13885                 case SCF_ERROR_INVALID_ARGUMENT:
13886                         semerr(emsg_invalid_pg_name, pgname);
13887                         goto fail;
13888 
13889                 default:
13890                         scfdie();
13891                         break;
13892                 }
13893         }
13894 
13895         do {
13896                 if (scf_pg_update(pg) == -1)
13897                         scfdie();
13898                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13899                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13900                                 scfdie();
13901 
13902                         semerr(emsg_permission_denied);
13903                         goto fail;
13904                 }
13905 
13906                 ret = scf_pg_get_property(pg, propname, prop);
13907                 if (ret == SCF_SUCCESS) {
13908                         if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13909                                 scfdie();
13910 
13911                         if (type == NULL)
13912                                 ty = current_ty;
13913                         if (scf_transaction_property_change_type(tx, e,
13914                             propname, ty) == -1)
13915                                 scfdie();
13916 
13917                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13918                         /* Infer the type, if possible. */
13919                         if (type == NULL) {
13920                                 /*
13921                                  * First check if we're an instance and the
13922                                  * property is set on the service.
13923                                  */
13924                                 if (cur_inst != NULL &&
13925                                     scf_instance_get_parent(cur_inst,
13926                                     svc) == 0 &&
13927                                     scf_service_get_pg(cur_svc, pgname,
13928                                     parent_pg) == 0 &&
13929                                     scf_pg_get_property(parent_pg, propname,
13930                                     parent_prop) == 0 &&
13931                                     scf_property_type(parent_prop,
13932                                     &current_ty) == 0) {
13933                                         ty = current_ty;
13934 
13935                                 /* Then check for a type set in a template. */
13936                                 } else if (scf_tmpl_get_by_pg(pg, pgt,
13937                                     0) == 0 &&
13938                                     scf_tmpl_get_by_prop(pgt, propname, prt,
13939                                     0) == 0 &&
13940                                     scf_tmpl_prop_type(prt, &current_ty) == 0) {
13941                                         ty = current_ty;
13942 
13943                                 /* If type can't be inferred, fail. */
13944                                 } else {
13945                                         semerr(gettext("Type required for new "
13946                                             "properties.\n"));
13947                                         goto fail;
13948                                 }
13949                         }
13950                         if (scf_transaction_property_new(tx, e, propname,
13951                             ty) == -1)
13952                                 scfdie();
13953                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13954                         semerr(emsg_invalid_prop_name, propname);
13955                         goto fail;
13956                 } else {
13957                         scfdie();
13958                 }
13959 
13960                 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13961                         req_quotes = 1;
13962 
13963                 if (value != NULL) {
13964                         v = string_to_value(value, ty, 0);
13965 
13966                         if (v == NULL)
13967                                 goto fail;
13968 
13969                         ret = scf_entry_add_value(e, v);
13970                         assert(ret == SCF_SUCCESS);
13971                 } else {
13972                         assert(values != NULL);
13973 
13974                         walk = uu_list_walk_start((uu_list_t *)values,
13975                             UU_DEFAULT);
13976                         if (walk == NULL)
13977                                 uu_die(gettext("Could not walk list"));
13978 
13979                         for (sp = uu_list_walk_next(walk); sp != NULL;
13980                             sp = uu_list_walk_next(walk)) {
13981                                 v = string_to_value(sp->str, ty, req_quotes);
13982 
13983                                 if (v == NULL) {
13984                                         scf_entry_destroy_children(e);
13985                                         goto fail;
13986                                 }
13987 
13988                                 ret = scf_entry_add_value(e, v);
13989                                 assert(ret == SCF_SUCCESS);
13990                         }
13991                         uu_list_walk_end(walk);
13992                 }
13993                 result = scf_transaction_commit(tx);
13994 
13995                 scf_transaction_reset(tx);
13996                 scf_entry_destroy_children(e);
13997         } while (result == 0);
13998 
13999         if (result < 0) {
14000                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14001                         scfdie();
14002 
14003                 semerr(emsg_permission_denied);
14004                 goto fail;
14005         }
14006 
14007         ret = 0;
14008 
14009         private_refresh();
14010 
14011         goto cleanup;
14012 
14013 fail:
14014         ret = -1;
14015 
14016 cleanup:
14017         scf_transaction_destroy(tx);
14018         scf_entry_destroy(e);
14019         scf_service_destroy(svc);
14020         scf_pg_destroy(parent_pg);
14021         scf_pg_destroy(pg);
14022         scf_property_destroy(parent_prop);
14023         scf_property_destroy(prop);
14024         scf_tmpl_pg_destroy(pgt);
14025         scf_tmpl_prop_destroy(prt);
14026 
14027         return (ret);
14028 }
14029 
14030 void
14031 lscf_delprop(char *pgn)
14032 {
14033         char *slash, *pn;
14034         scf_propertygroup_t *pg;
14035         scf_transaction_t *tx;
14036         scf_transaction_entry_t *e;
14037         int ret;
14038 
14039 
14040         lscf_prep_hndl();
14041 
14042         if (cur_snap != NULL) {
14043                 semerr(emsg_cant_modify_snapshots);
14044                 return;
14045         }
14046 
14047         if (cur_inst == NULL && cur_svc == NULL) {
14048                 semerr(emsg_entity_not_selected);
14049                 return;
14050         }
14051 
14052         pg = scf_pg_create(g_hndl);
14053         if (pg == NULL)
14054                 scfdie();
14055 
14056         slash = strchr(pgn, '/');
14057         if (slash == NULL) {
14058                 pn = NULL;
14059         } else {
14060                 *slash = '\0';
14061                 pn = slash + 1;
14062         }
14063 
14064         if (cur_inst != NULL)
14065                 ret = scf_instance_get_pg(cur_inst, pgn, pg);
14066         else
14067                 ret = scf_service_get_pg(cur_svc, pgn, pg);
14068         if (ret != SCF_SUCCESS) {
14069                 switch (scf_error()) {
14070                 case SCF_ERROR_NOT_FOUND:
14071                         semerr(emsg_no_such_pg, pgn);
14072                         break;
14073 
14074                 case SCF_ERROR_INVALID_ARGUMENT:
14075                         semerr(emsg_invalid_pg_name, pgn);
14076                         break;
14077 
14078                 default:
14079                         scfdie();
14080                 }
14081 
14082                 scf_pg_destroy(pg);
14083 
14084                 return;
14085         }
14086 
14087         if (pn == NULL) {
14088                 /* Try to delete the property group. */
14089                 if (scf_pg_delete(pg) != SCF_SUCCESS) {
14090                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14091                                 scfdie();
14092 
14093                         semerr(emsg_permission_denied);
14094                 } else {
14095                         private_refresh();
14096                 }
14097 
14098                 scf_pg_destroy(pg);
14099                 return;
14100         }
14101 
14102         e = scf_entry_create(g_hndl);
14103         tx = scf_transaction_create(g_hndl);
14104 
14105         do {
14106                 if (scf_pg_update(pg) == -1)
14107                         scfdie();
14108                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14109                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14110                                 scfdie();
14111 
14112                         semerr(emsg_permission_denied);
14113                         break;
14114                 }
14115 
14116                 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14117                         if (scf_error() == SCF_ERROR_NOT_FOUND) {
14118                                 semerr(gettext("No such property %s/%s.\n"),
14119                                     pgn, pn);
14120                                 break;
14121                         } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14122                                 semerr(emsg_invalid_prop_name, pn);
14123                                 break;
14124                         } else {
14125                                 scfdie();
14126                         }
14127                 }
14128 
14129                 ret = scf_transaction_commit(tx);
14130 
14131                 if (ret == 0)
14132                         scf_transaction_reset(tx);
14133         } while (ret == 0);
14134 
14135         if (ret < 0) {
14136                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14137                         scfdie();
14138 
14139                 semerr(emsg_permission_denied);
14140         } else {
14141                 private_refresh();
14142         }
14143 
14144         scf_transaction_destroy(tx);
14145         scf_entry_destroy(e);
14146         scf_pg_destroy(pg);
14147 }
14148 
14149 /*
14150  * Property editing.
14151  */
14152 
14153 static int
14154 write_edit_script(FILE *strm)
14155 {
14156         char *fmribuf;
14157         ssize_t fmrilen;
14158 
14159         scf_propertygroup_t *pg;
14160         scf_property_t *prop;
14161         scf_value_t *val;
14162         scf_type_t ty;
14163         int ret, result = 0;
14164         scf_iter_t *iter, *piter, *viter;
14165         char *buf, *tybuf, *pname;
14166         const char *emsg_write_error;
14167 
14168 
14169         emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14170 
14171 
14172         /* select fmri */
14173         if (cur_inst != NULL) {
14174                 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14175                 if (fmrilen < 0)
14176                         scfdie();
14177                 fmribuf = safe_malloc(fmrilen + 1);
14178                 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14179                         scfdie();
14180         } else {
14181                 assert(cur_svc != NULL);
14182                 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14183                 if (fmrilen < 0)
14184                         scfdie();
14185                 fmribuf = safe_malloc(fmrilen + 1);
14186                 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14187                         scfdie();
14188         }
14189 
14190         if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14191                 warn(emsg_write_error, strerror(errno));
14192                 free(fmribuf);
14193                 return (-1);
14194         }
14195 
14196         free(fmribuf);
14197 
14198 
14199         if ((pg = scf_pg_create(g_hndl)) == NULL ||
14200             (prop = scf_property_create(g_hndl)) == NULL ||
14201             (val = scf_value_create(g_hndl)) == NULL ||
14202             (iter = scf_iter_create(g_hndl)) == NULL ||
14203             (piter = scf_iter_create(g_hndl)) == NULL ||
14204             (viter = scf_iter_create(g_hndl)) == NULL)
14205                 scfdie();
14206 
14207         buf = safe_malloc(max_scf_name_len + 1);
14208         tybuf = safe_malloc(max_scf_pg_type_len + 1);
14209         pname = safe_malloc(max_scf_name_len + 1);
14210 
14211         if (cur_inst != NULL)
14212                 ret = scf_iter_instance_pgs(iter, cur_inst);
14213         else
14214                 ret = scf_iter_service_pgs(iter, cur_svc);
14215         if (ret != SCF_SUCCESS)
14216                 scfdie();
14217 
14218         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14219                 int ret2;
14220 
14221                 /*
14222                  * # delprop pg
14223                  * # addpg pg type
14224                  */
14225                 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14226                         scfdie();
14227 
14228                 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14229                         scfdie();
14230 
14231                 if (fprintf(strm, "# Property group \"%s\"\n"
14232                     "# delprop %s\n"
14233                     "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14234                         warn(emsg_write_error, strerror(errno));
14235                         result = -1;
14236                         goto out;
14237                 }
14238 
14239                 /* # setprop pg/prop = (values) */
14240 
14241                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14242                         scfdie();
14243 
14244                 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14245                         int first = 1;
14246                         int ret3;
14247                         int multiple;
14248                         int is_str;
14249                         scf_type_t bty;
14250 
14251                         if (scf_property_get_name(prop, pname,
14252                             max_scf_name_len + 1) < 0)
14253                                 scfdie();
14254 
14255                         if (scf_property_type(prop, &ty) != 0)
14256                                 scfdie();
14257 
14258                         multiple = prop_has_multiple_values(prop, val);
14259 
14260                         if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14261                             pname, scf_type_to_string(ty), multiple ? "(" : "")
14262                             < 0) {
14263                                 warn(emsg_write_error, strerror(errno));
14264                                 result = -1;
14265                                 goto out;
14266                         }
14267 
14268                         (void) scf_type_base_type(ty, &bty);
14269                         is_str = (bty == SCF_TYPE_ASTRING);
14270 
14271                         if (scf_iter_property_values(viter, prop) !=
14272                             SCF_SUCCESS)
14273                                 scfdie();
14274 
14275                         while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14276                                 char *buf;
14277                                 ssize_t buflen;
14278 
14279                                 buflen = scf_value_get_as_string(val, NULL, 0);
14280                                 if (buflen < 0)
14281                                         scfdie();
14282 
14283                                 buf = safe_malloc(buflen + 1);
14284 
14285                                 if (scf_value_get_as_string(val, buf,
14286                                     buflen + 1) < 0)
14287                                         scfdie();
14288 
14289                                 if (first)
14290                                         first = 0;
14291                                 else {
14292                                         if (putc(' ', strm) != ' ') {
14293                                                 warn(emsg_write_error,
14294                                                     strerror(errno));
14295                                                 result = -1;
14296                                                 goto out;
14297                                         }
14298                                 }
14299 
14300                                 if ((is_str && multiple) ||
14301                                     strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14302                                         (void) putc('"', strm);
14303                                         (void) quote_and_print(buf, strm, 1);
14304                                         (void) putc('"', strm);
14305 
14306                                         if (ferror(strm)) {
14307                                                 warn(emsg_write_error,
14308                                                     strerror(errno));
14309                                                 result = -1;
14310                                                 goto out;
14311                                         }
14312                                 } else {
14313                                         if (fprintf(strm, "%s", buf) < 0) {
14314                                                 warn(emsg_write_error,
14315                                                     strerror(errno));
14316                                                 result = -1;
14317                                                 goto out;
14318                                         }
14319                                 }
14320 
14321                                 free(buf);
14322                         }
14323                         if (ret3 < 0 &&
14324                             scf_error() != SCF_ERROR_PERMISSION_DENIED)
14325                                 scfdie();
14326 
14327                         /* Write closing paren if mult-value property */
14328                         if ((multiple && putc(')', strm) == EOF) ||
14329 
14330                             /* Write final newline */
14331                             fputc('\n', strm) == EOF) {
14332                                 warn(emsg_write_error, strerror(errno));
14333                                 result = -1;
14334                                 goto out;
14335                         }
14336                 }
14337                 if (ret2 < 0)
14338                         scfdie();
14339 
14340                 if (fputc('\n', strm) == EOF) {
14341                         warn(emsg_write_error, strerror(errno));
14342                         result = -1;
14343                         goto out;
14344                 }
14345         }
14346         if (ret < 0)
14347                 scfdie();
14348 
14349 out:
14350         free(pname);
14351         free(tybuf);
14352         free(buf);
14353         scf_iter_destroy(viter);
14354         scf_iter_destroy(piter);
14355         scf_iter_destroy(iter);
14356         scf_value_destroy(val);
14357         scf_property_destroy(prop);
14358         scf_pg_destroy(pg);
14359 
14360         if (result == 0) {
14361                 if (fflush(strm) != 0) {
14362                         warn(emsg_write_error, strerror(errno));
14363                         return (-1);
14364                 }
14365         }
14366 
14367         return (result);
14368 }
14369 
14370 int
14371 lscf_editprop()
14372 {
14373         char *buf, *editor;
14374         size_t bufsz;
14375         int tmpfd;
14376         char tempname[] = TEMP_FILE_PATTERN;
14377 
14378         lscf_prep_hndl();
14379 
14380         if (cur_snap != NULL) {
14381                 semerr(emsg_cant_modify_snapshots);
14382                 return (-1);
14383         }
14384 
14385         if (cur_svc == NULL && cur_inst == NULL) {
14386                 semerr(emsg_entity_not_selected);
14387                 return (-1);
14388         }
14389 
14390         tmpfd = mkstemp(tempname);
14391         if (tmpfd == -1) {
14392                 semerr(gettext("Could not create temporary file.\n"));
14393                 return (-1);
14394         }
14395 
14396         (void) strcpy(tempfilename, tempname);
14397 
14398         tempfile = fdopen(tmpfd, "r+");
14399         if (tempfile == NULL) {
14400                 warn(gettext("Could not create temporary file.\n"));
14401                 if (close(tmpfd) == -1)
14402                         warn(gettext("Could not close temporary file: %s.\n"),
14403                             strerror(errno));
14404 
14405                 remove_tempfile();
14406 
14407                 return (-1);
14408         }
14409 
14410         if (write_edit_script(tempfile) == -1) {
14411                 remove_tempfile();
14412                 return (-1);
14413         }
14414 
14415         editor = getenv("EDITOR");
14416         if (editor == NULL)
14417                 editor = "vi";
14418 
14419         bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14420         buf = safe_malloc(bufsz);
14421 
14422         if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14423                 uu_die(gettext("Error creating editor command"));
14424 
14425         if (system(buf) == -1) {
14426                 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14427                     strerror(errno));
14428                 free(buf);
14429                 remove_tempfile();
14430                 return (-1);
14431         }
14432 
14433         free(buf);
14434 
14435         (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14436 
14437         remove_tempfile();
14438 
14439         return (0);
14440 }
14441 
14442 static void
14443 add_string(uu_list_t *strlist, const char *str)
14444 {
14445         string_list_t *elem;
14446         elem = safe_malloc(sizeof (*elem));
14447         uu_list_node_init(elem, &elem->node, string_pool);
14448         elem->str = safe_strdup(str);
14449         if (uu_list_append(strlist, elem) != 0)
14450                 uu_die(gettext("libuutil error: %s\n"),
14451                     uu_strerror(uu_error()));
14452 }
14453 
14454 static int
14455 remove_string(uu_list_t *strlist, const char *str)
14456 {
14457         uu_list_walk_t  *elems;
14458         string_list_t   *sp;
14459 
14460         /*
14461          * Find the element that needs to be removed.
14462          */
14463         elems = uu_list_walk_start(strlist, UU_DEFAULT);
14464         while ((sp = uu_list_walk_next(elems)) != NULL) {
14465                 if (strcmp(sp->str, str) == 0)
14466                         break;
14467         }
14468         uu_list_walk_end(elems);
14469 
14470         /*
14471          * Returning 1 here as the value was not found, this
14472          * might not be an error.  Leave it to the caller to
14473          * decide.
14474          */
14475         if (sp == NULL) {
14476                 return (1);
14477         }
14478 
14479         uu_list_remove(strlist, sp);
14480 
14481         free(sp->str);
14482         free(sp);
14483 
14484         return (0);
14485 }
14486 
14487 /*
14488  * Get all property values that don't match the given glob pattern,
14489  * if a pattern is specified.
14490  */
14491 static void
14492 get_prop_values(scf_property_t *prop, uu_list_t *values,
14493     const char *pattern)
14494 {
14495         scf_iter_t *iter;
14496         scf_value_t *val;
14497         int ret;
14498 
14499         if ((iter = scf_iter_create(g_hndl)) == NULL ||
14500             (val = scf_value_create(g_hndl)) == NULL)
14501                 scfdie();
14502 
14503         if (scf_iter_property_values(iter, prop) != 0)
14504                 scfdie();
14505 
14506         while ((ret = scf_iter_next_value(iter, val)) == 1) {
14507                 char *buf;
14508                 ssize_t vlen, szret;
14509 
14510                 vlen = scf_value_get_as_string(val, NULL, 0);
14511                 if (vlen < 0)
14512                         scfdie();
14513 
14514                 buf = safe_malloc(vlen + 1);
14515 
14516                 szret = scf_value_get_as_string(val, buf, vlen + 1);
14517                 if (szret < 0)
14518                         scfdie();
14519                 assert(szret <= vlen);
14520 
14521                 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14522                         add_string(values, buf);
14523 
14524                 free(buf);
14525         }
14526 
14527         if (ret == -1)
14528                 scfdie();
14529 
14530         scf_value_destroy(val);
14531         scf_iter_destroy(iter);
14532 }
14533 
14534 static int
14535 lscf_setpropvalue(const char *pgname, const char *type,
14536     const char *arg, int isadd, int isnotfoundok)
14537 {
14538         scf_type_t ty;
14539         scf_propertygroup_t *pg;
14540         scf_property_t *prop;
14541         int ret, result = 0;
14542         scf_transaction_t *tx;
14543         scf_transaction_entry_t *e;
14544         scf_value_t *v;
14545         string_list_t *sp;
14546         char *propname;
14547         uu_list_t *values;
14548         uu_list_walk_t *walk;
14549         void *cookie = NULL;
14550         char *pattern = NULL;
14551 
14552         lscf_prep_hndl();
14553 
14554         if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14555                 uu_die(gettext("Could not create property list: %s\n"),
14556                     uu_strerror(uu_error()));
14557 
14558         if (!isadd)
14559                 pattern = safe_strdup(arg);
14560 
14561         if ((e = scf_entry_create(g_hndl)) == NULL ||
14562             (pg = scf_pg_create(g_hndl)) == NULL ||
14563             (prop = scf_property_create(g_hndl)) == NULL ||
14564             (tx = scf_transaction_create(g_hndl)) == NULL)
14565                 scfdie();
14566 
14567         if (cur_snap != NULL) {
14568                 semerr(emsg_cant_modify_snapshots);
14569                 goto fail;
14570         }
14571 
14572         if (cur_inst == NULL && cur_svc == NULL) {
14573                 semerr(emsg_entity_not_selected);
14574                 goto fail;
14575         }
14576 
14577         propname = strchr(pgname, '/');
14578         if (propname == NULL) {
14579                 semerr(gettext("Property names must contain a `/'.\n"));
14580                 goto fail;
14581         }
14582 
14583         *propname = '\0';
14584         ++propname;
14585 
14586         if (type != NULL) {
14587                 ty = string_to_type(type);
14588                 if (ty == SCF_TYPE_INVALID) {
14589                         semerr(gettext("Unknown type \"%s\".\n"), type);
14590                         goto fail;
14591                 }
14592         }
14593 
14594         if (cur_inst != NULL)
14595                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14596         else
14597                 ret = scf_service_get_pg(cur_svc, pgname, pg);
14598         if (ret != 0) {
14599                 switch (scf_error()) {
14600                 case SCF_ERROR_NOT_FOUND:
14601                         if (isnotfoundok) {
14602                                 result = 0;
14603                         } else {
14604                                 semerr(emsg_no_such_pg, pgname);
14605                                 result = -1;
14606                         }
14607                         goto out;
14608 
14609                 case SCF_ERROR_INVALID_ARGUMENT:
14610                         semerr(emsg_invalid_pg_name, pgname);
14611                         goto fail;
14612 
14613                 default:
14614                         scfdie();
14615                 }
14616         }
14617 
14618         do {
14619                 if (scf_pg_update(pg) == -1)
14620                         scfdie();
14621                 if (scf_transaction_start(tx, pg) != 0) {
14622                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14623                                 scfdie();
14624 
14625                         semerr(emsg_permission_denied);
14626                         goto fail;
14627                 }
14628 
14629                 ret = scf_pg_get_property(pg, propname, prop);
14630                 if (ret == 0) {
14631                         scf_type_t ptype;
14632                         char *pat = pattern;
14633 
14634                         if (scf_property_type(prop, &ptype) != 0)
14635                                 scfdie();
14636 
14637                         if (isadd) {
14638                                 if (type != NULL && ptype != ty) {
14639                                         semerr(gettext("Property \"%s\" is not "
14640                                             "of type \"%s\".\n"), propname,
14641                                             type);
14642                                         goto fail;
14643                                 }
14644 
14645                                 pat = NULL;
14646                         } else {
14647                                 size_t len = strlen(pat);
14648                                 if (len > 0 && pat[len - 1] == '\"')
14649                                         pat[len - 1] = '\0';
14650                                 if (len > 0 && pat[0] == '\"')
14651                                         pat++;
14652                         }
14653 
14654                         ty = ptype;
14655 
14656                         get_prop_values(prop, values, pat);
14657 
14658                         if (isadd)
14659                                 add_string(values, arg);
14660 
14661                         if (scf_transaction_property_change(tx, e,
14662                             propname, ty) == -1)
14663                                 scfdie();
14664                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14665                         if (isadd) {
14666                                 if (type == NULL) {
14667                                         semerr(gettext("Type required "
14668                                             "for new properties.\n"));
14669                                         goto fail;
14670                                 }
14671 
14672                                 add_string(values, arg);
14673 
14674                                 if (scf_transaction_property_new(tx, e,
14675                                     propname, ty) == -1)
14676                                         scfdie();
14677                         } else if (isnotfoundok) {
14678                                 result = 0;
14679                                 goto out;
14680                         } else {
14681                                 semerr(gettext("No such property %s/%s.\n"),
14682                                     pgname, propname);
14683                                 result = -1;
14684                                 goto out;
14685                         }
14686                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14687                         semerr(emsg_invalid_prop_name, propname);
14688                         goto fail;
14689                 } else {
14690                         scfdie();
14691                 }
14692 
14693                 walk = uu_list_walk_start(values, UU_DEFAULT);
14694                 if (walk == NULL)
14695                         uu_die(gettext("Could not walk property list.\n"));
14696 
14697                 for (sp = uu_list_walk_next(walk); sp != NULL;
14698                     sp = uu_list_walk_next(walk)) {
14699                         v = string_to_value(sp->str, ty, 0);
14700 
14701                         if (v == NULL) {
14702                                 scf_entry_destroy_children(e);
14703                                 goto fail;
14704                         }
14705                         ret = scf_entry_add_value(e, v);
14706                         assert(ret == 0);
14707                 }
14708                 uu_list_walk_end(walk);
14709 
14710                 result = scf_transaction_commit(tx);
14711 
14712                 scf_transaction_reset(tx);
14713                 scf_entry_destroy_children(e);
14714         } while (result == 0);
14715 
14716         if (result < 0) {
14717                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14718                         scfdie();
14719 
14720                 semerr(emsg_permission_denied);
14721                 goto fail;
14722         }
14723 
14724         result = 0;
14725 
14726         private_refresh();
14727 
14728 out:
14729         scf_transaction_destroy(tx);
14730         scf_entry_destroy(e);
14731         scf_pg_destroy(pg);
14732         scf_property_destroy(prop);
14733         free(pattern);
14734 
14735         while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14736                 free(sp->str);
14737                 free(sp);
14738         }
14739 
14740         uu_list_destroy(values);
14741 
14742         return (result);
14743 
14744 fail:
14745         result = -1;
14746         goto out;
14747 }
14748 
14749 int
14750 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14751 {
14752         return (lscf_setpropvalue(pgname, type, value, 1, 0));
14753 }
14754 
14755 int
14756 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14757 {
14758         return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14759 }
14760 
14761 /*
14762  * Look for a standard start method, first in the instance (if any),
14763  * then the service.
14764  */
14765 static const char *
14766 start_method_name(int *in_instance)
14767 {
14768         scf_propertygroup_t *pg;
14769         char **p;
14770         int ret;
14771         scf_instance_t *inst = cur_inst;
14772 
14773         if ((pg = scf_pg_create(g_hndl)) == NULL)
14774                 scfdie();
14775 
14776 again:
14777         for (p = start_method_names; *p != NULL; p++) {
14778                 if (inst != NULL)
14779                         ret = scf_instance_get_pg(inst, *p, pg);
14780                 else
14781                         ret = scf_service_get_pg(cur_svc, *p, pg);
14782 
14783                 if (ret == 0) {
14784                         size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14785                         char *buf = safe_malloc(bufsz);
14786 
14787                         if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14788                                 free(buf);
14789                                 continue;
14790                         }
14791                         if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14792                                 free(buf);
14793                                 continue;
14794                         }
14795 
14796                         free(buf);
14797                         *in_instance = (inst != NULL);
14798                         scf_pg_destroy(pg);
14799                         return (*p);
14800                 }
14801 
14802                 if (scf_error() == SCF_ERROR_NOT_FOUND)
14803                         continue;
14804 
14805                 scfdie();
14806         }
14807 
14808         if (inst != NULL) {
14809                 inst = NULL;
14810                 goto again;
14811         }
14812 
14813         scf_pg_destroy(pg);
14814         return (NULL);
14815 }
14816 
14817 static int
14818 addpg(const char *name, const char *type)
14819 {
14820         scf_propertygroup_t *pg;
14821         int ret;
14822 
14823         pg = scf_pg_create(g_hndl);
14824         if (pg == NULL)
14825                 scfdie();
14826 
14827         if (cur_inst != NULL)
14828                 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14829         else
14830                 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14831 
14832         if (ret != 0) {
14833                 switch (scf_error()) {
14834                 case SCF_ERROR_EXISTS:
14835                         ret = 0;
14836                         break;
14837 
14838                 case SCF_ERROR_PERMISSION_DENIED:
14839                         semerr(emsg_permission_denied);
14840                         break;
14841 
14842                 default:
14843                         scfdie();
14844                 }
14845         }
14846 
14847         scf_pg_destroy(pg);
14848         return (ret);
14849 }
14850 
14851 int
14852 lscf_setenv(uu_list_t *args, int isunset)
14853 {
14854         int ret = 0;
14855         size_t i;
14856         int argc;
14857         char **argv = NULL;
14858         string_list_t *slp;
14859         char *pattern;
14860         char *prop;
14861         int do_service = 0;
14862         int do_instance = 0;
14863         const char *method = NULL;
14864         const char *name = NULL;
14865         const char *value = NULL;
14866         scf_instance_t *saved_cur_inst = cur_inst;
14867 
14868         lscf_prep_hndl();
14869 
14870         argc = uu_list_numnodes(args);
14871         if (argc < 1)
14872                 goto usage;
14873 
14874         argv = calloc(argc + 1, sizeof (char *));
14875         if (argv == NULL)
14876                 uu_die(gettext("Out of memory.\n"));
14877 
14878         for (slp = uu_list_first(args), i = 0;
14879             slp != NULL;
14880             slp = uu_list_next(args, slp), ++i)
14881                 argv[i] = slp->str;
14882 
14883         argv[i] = NULL;
14884 
14885         opterr = 0;
14886         optind = 0;
14887         for (;;) {
14888                 ret = getopt(argc, argv, "sim:");
14889                 if (ret == -1)
14890                         break;
14891 
14892                 switch (ret) {
14893                 case 's':
14894                         do_service = 1;
14895                         cur_inst = NULL;
14896                         break;
14897 
14898                 case 'i':
14899                         do_instance = 1;
14900                         break;
14901 
14902                 case 'm':
14903                         method = optarg;
14904                         break;
14905 
14906                 case '?':
14907                         goto usage;
14908 
14909                 default:
14910                         bad_error("getopt", ret);
14911                 }
14912         }
14913 
14914         argc -= optind;
14915         if ((do_service && do_instance) ||
14916             (isunset && argc != 1) ||
14917             (!isunset && argc != 2))
14918                 goto usage;
14919 
14920         name = argv[optind];
14921         if (!isunset)
14922                 value = argv[optind + 1];
14923 
14924         if (cur_snap != NULL) {
14925                 semerr(emsg_cant_modify_snapshots);
14926                 ret = -1;
14927                 goto out;
14928         }
14929 
14930         if (cur_inst == NULL && cur_svc == NULL) {
14931                 semerr(emsg_entity_not_selected);
14932                 ret = -1;
14933                 goto out;
14934         }
14935 
14936         if (do_instance && cur_inst == NULL) {
14937                 semerr(gettext("No instance is selected.\n"));
14938                 ret = -1;
14939                 goto out;
14940         }
14941 
14942         if (do_service && cur_svc == NULL) {
14943                 semerr(gettext("No service is selected.\n"));
14944                 ret = -1;
14945                 goto out;
14946         }
14947 
14948         if (method == NULL) {
14949                 if (do_instance || do_service) {
14950                         method = "method_context";
14951                         if (!isunset) {
14952                                 ret = addpg("method_context",
14953                                     SCF_GROUP_FRAMEWORK);
14954                                 if (ret != 0)
14955                                         goto out;
14956                         }
14957                 } else {
14958                         int in_instance;
14959                         method = start_method_name(&in_instance);
14960                         if (method == NULL) {
14961                                 semerr(gettext(
14962                                     "Couldn't find start method; please "
14963                                     "specify a method with '-m'.\n"));
14964                                 ret = -1;
14965                                 goto out;
14966                         }
14967                         if (!in_instance)
14968                                 cur_inst = NULL;
14969                 }
14970         } else {
14971                 scf_propertygroup_t *pg;
14972                 size_t bufsz;
14973                 char *buf;
14974                 int ret;
14975 
14976                 if ((pg = scf_pg_create(g_hndl)) == NULL)
14977                         scfdie();
14978 
14979                 if (cur_inst != NULL)
14980                         ret = scf_instance_get_pg(cur_inst, method, pg);
14981                 else
14982                         ret = scf_service_get_pg(cur_svc, method, pg);
14983 
14984                 if (ret != 0) {
14985                         scf_pg_destroy(pg);
14986                         switch (scf_error()) {
14987                         case SCF_ERROR_NOT_FOUND:
14988                                 semerr(gettext("Couldn't find the method "
14989                                     "\"%s\".\n"), method);
14990                                 goto out;
14991 
14992                         case SCF_ERROR_INVALID_ARGUMENT:
14993                                 semerr(gettext("Invalid method name \"%s\".\n"),
14994                                     method);
14995                                 goto out;
14996 
14997                         default:
14998                                 scfdie();
14999                         }
15000                 }
15001 
15002                 bufsz = strlen(SCF_GROUP_METHOD) + 1;
15003                 buf = safe_malloc(bufsz);
15004 
15005                 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15006                     strcmp(buf, SCF_GROUP_METHOD) != 0) {
15007                         semerr(gettext("Property group \"%s\" is not of type "
15008                             "\"method\".\n"), method);
15009                         ret = -1;
15010                         free(buf);
15011                         scf_pg_destroy(pg);
15012                         goto out;
15013                 }
15014 
15015                 free(buf);
15016                 scf_pg_destroy(pg);
15017         }
15018 
15019         prop = uu_msprintf("%s/environment", method);
15020         pattern = uu_msprintf("%s=*", name);
15021 
15022         if (prop == NULL || pattern == NULL)
15023                 uu_die(gettext("Out of memory.\n"));
15024 
15025         ret = lscf_delpropvalue(prop, pattern, !isunset);
15026 
15027         if (ret == 0 && !isunset) {
15028                 uu_free(pattern);
15029                 uu_free(prop);
15030                 prop = uu_msprintf("%s/environment", method);
15031                 pattern = uu_msprintf("%s=%s", name, value);
15032                 if (prop == NULL || pattern == NULL)
15033                         uu_die(gettext("Out of memory.\n"));
15034                 ret = lscf_addpropvalue(prop, "astring:", pattern);
15035         }
15036         uu_free(pattern);
15037         uu_free(prop);
15038 
15039 out:
15040         cur_inst = saved_cur_inst;
15041 
15042         free(argv);
15043         return (ret);
15044 usage:
15045         ret = -2;
15046         goto out;
15047 }
15048 
15049 /*
15050  * Snapshot commands
15051  */
15052 
15053 void
15054 lscf_listsnap()
15055 {
15056         scf_snapshot_t *snap;
15057         scf_iter_t *iter;
15058         char *nb;
15059         int r;
15060 
15061         lscf_prep_hndl();
15062 
15063         if (cur_inst == NULL) {
15064                 semerr(gettext("Instance not selected.\n"));
15065                 return;
15066         }
15067 
15068         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15069             (iter = scf_iter_create(g_hndl)) == NULL)
15070                 scfdie();
15071 
15072         if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15073                 scfdie();
15074 
15075         nb = safe_malloc(max_scf_name_len + 1);
15076 
15077         while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15078                 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15079                         scfdie();
15080 
15081                 (void) puts(nb);
15082         }
15083         if (r < 0)
15084                 scfdie();
15085 
15086         free(nb);
15087         scf_iter_destroy(iter);
15088         scf_snapshot_destroy(snap);
15089 }
15090 
15091 void
15092 lscf_selectsnap(const char *name)
15093 {
15094         scf_snapshot_t *snap;
15095         scf_snaplevel_t *level;
15096 
15097         lscf_prep_hndl();
15098 
15099         if (cur_inst == NULL) {
15100                 semerr(gettext("Instance not selected.\n"));
15101                 return;
15102         }
15103 
15104         if (cur_snap != NULL) {
15105                 if (name != NULL) {
15106                         char *cur_snap_name;
15107                         boolean_t nochange;
15108 
15109                         cur_snap_name = safe_malloc(max_scf_name_len + 1);
15110 
15111                         if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15112                             max_scf_name_len + 1) < 0)
15113                                 scfdie();
15114 
15115                         nochange = strcmp(name, cur_snap_name) == 0;
15116 
15117                         free(cur_snap_name);
15118 
15119                         if (nochange)
15120                                 return;
15121                 }
15122 
15123                 unselect_cursnap();
15124         }
15125 
15126         if (name == NULL)
15127                 return;
15128 
15129         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15130             (level = scf_snaplevel_create(g_hndl)) == NULL)
15131                 scfdie();
15132 
15133         if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15134             SCF_SUCCESS) {
15135                 switch (scf_error()) {
15136                 case SCF_ERROR_INVALID_ARGUMENT:
15137                         semerr(gettext("Invalid name \"%s\".\n"), name);
15138                         break;
15139 
15140                 case SCF_ERROR_NOT_FOUND:
15141                         semerr(gettext("No such snapshot \"%s\".\n"), name);
15142                         break;
15143 
15144                 default:
15145                         scfdie();
15146                 }
15147 
15148                 scf_snaplevel_destroy(level);
15149                 scf_snapshot_destroy(snap);
15150                 return;
15151         }
15152 
15153         /* Load the snaplevels into our list. */
15154         cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15155         if (cur_levels == NULL)
15156                 uu_die(gettext("Could not create list: %s\n"),
15157                     uu_strerror(uu_error()));
15158 
15159         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15160                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15161                         scfdie();
15162 
15163                 semerr(gettext("Snapshot has no snaplevels.\n"));
15164 
15165                 scf_snaplevel_destroy(level);
15166                 scf_snapshot_destroy(snap);
15167                 return;
15168         }
15169 
15170         cur_snap = snap;
15171 
15172         for (;;) {
15173                 cur_elt = safe_malloc(sizeof (*cur_elt));
15174                 uu_list_node_init(cur_elt, &cur_elt->list_node,
15175                     snaplevel_pool);
15176                 cur_elt->sl = level;
15177                 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15178                         uu_die(gettext("libuutil error: %s\n"),
15179                             uu_strerror(uu_error()));
15180 
15181                 level = scf_snaplevel_create(g_hndl);
15182                 if (level == NULL)
15183                         scfdie();
15184 
15185                 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15186                     level) != SCF_SUCCESS) {
15187                         if (scf_error() != SCF_ERROR_NOT_FOUND)
15188                                 scfdie();
15189 
15190                         scf_snaplevel_destroy(level);
15191                         break;
15192                 }
15193         }
15194 
15195         cur_elt = uu_list_last(cur_levels);
15196         cur_level = cur_elt->sl;
15197 }
15198 
15199 /*
15200  * Copies the properties & values in src to dst.  Assumes src won't change.
15201  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15202  * and 0 on success.
15203  *
15204  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15205  * property, if it is copied and has type boolean.  (See comment in
15206  * lscf_revert()).
15207  */
15208 static int
15209 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15210     uint8_t enabled)
15211 {
15212         scf_transaction_t *tx;
15213         scf_iter_t *iter, *viter;
15214         scf_property_t *prop;
15215         scf_value_t *v;
15216         char *nbuf;
15217         int r;
15218 
15219         tx = scf_transaction_create(g_hndl);
15220         if (tx == NULL)
15221                 scfdie();
15222 
15223         if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15224                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15225                         scfdie();
15226 
15227                 scf_transaction_destroy(tx);
15228 
15229                 return (-1);
15230         }
15231 
15232         if ((iter = scf_iter_create(g_hndl)) == NULL ||
15233             (prop = scf_property_create(g_hndl)) == NULL ||
15234             (viter = scf_iter_create(g_hndl)) == NULL)
15235                 scfdie();
15236 
15237         nbuf = safe_malloc(max_scf_name_len + 1);
15238 
15239         if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15240                 scfdie();
15241 
15242         for (;;) {
15243                 scf_transaction_entry_t *e;
15244                 scf_type_t ty;
15245 
15246                 r = scf_iter_next_property(iter, prop);
15247                 if (r == -1)
15248                         scfdie();
15249                 if (r == 0)
15250                         break;
15251 
15252                 e = scf_entry_create(g_hndl);
15253                 if (e == NULL)
15254                         scfdie();
15255 
15256                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15257                         scfdie();
15258 
15259                 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15260                         scfdie();
15261 
15262                 if (scf_transaction_property_new(tx, e, nbuf,
15263                     ty) != SCF_SUCCESS)
15264                         scfdie();
15265 
15266                 if ((enabled == 0 || enabled == 1) &&
15267                     strcmp(nbuf, scf_property_enabled) == 0 &&
15268                     ty == SCF_TYPE_BOOLEAN) {
15269                         v = scf_value_create(g_hndl);
15270                         if (v == NULL)
15271                                 scfdie();
15272 
15273                         scf_value_set_boolean(v, enabled);
15274 
15275                         if (scf_entry_add_value(e, v) != 0)
15276                                 scfdie();
15277                 } else {
15278                         if (scf_iter_property_values(viter, prop) != 0)
15279                                 scfdie();
15280 
15281                         for (;;) {
15282                                 v = scf_value_create(g_hndl);
15283                                 if (v == NULL)
15284                                         scfdie();
15285 
15286                                 r = scf_iter_next_value(viter, v);
15287                                 if (r == -1)
15288                                         scfdie();
15289                                 if (r == 0) {
15290                                         scf_value_destroy(v);
15291                                         break;
15292                                 }
15293 
15294                                 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15295                                         scfdie();
15296                         }
15297                 }
15298         }
15299 
15300         free(nbuf);
15301         scf_iter_destroy(viter);
15302         scf_property_destroy(prop);
15303         scf_iter_destroy(iter);
15304 
15305         r = scf_transaction_commit(tx);
15306         if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15307                 scfdie();
15308 
15309         scf_transaction_destroy_children(tx);
15310         scf_transaction_destroy(tx);
15311 
15312         switch (r) {
15313         case 1:         return (0);
15314         case 0:         return (-2);
15315         case -1:        return (-1);
15316 
15317         default:
15318                 abort();
15319         }
15320 
15321         /* NOTREACHED */
15322 }
15323 
15324 void
15325 lscf_revert(const char *snapname)
15326 {
15327         scf_snapshot_t *snap, *prev;
15328         scf_snaplevel_t *level, *nlevel;
15329         scf_iter_t *iter;
15330         scf_propertygroup_t *pg, *npg;
15331         scf_property_t *prop;
15332         scf_value_t *val;
15333         char *nbuf, *tbuf;
15334         uint8_t enabled;
15335 
15336         lscf_prep_hndl();
15337 
15338         if (cur_inst == NULL) {
15339                 semerr(gettext("Instance not selected.\n"));
15340                 return;
15341         }
15342 
15343         if (snapname != NULL) {
15344                 snap = scf_snapshot_create(g_hndl);
15345                 if (snap == NULL)
15346                         scfdie();
15347 
15348                 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15349                     SCF_SUCCESS) {
15350                         switch (scf_error()) {
15351                         case SCF_ERROR_INVALID_ARGUMENT:
15352                                 semerr(gettext("Invalid snapshot name "
15353                                     "\"%s\".\n"), snapname);
15354                                 break;
15355 
15356                         case SCF_ERROR_NOT_FOUND:
15357                                 semerr(gettext("No such snapshot.\n"));
15358                                 break;
15359 
15360                         default:
15361                                 scfdie();
15362                         }
15363 
15364                         scf_snapshot_destroy(snap);
15365                         return;
15366                 }
15367         } else {
15368                 if (cur_snap != NULL) {
15369                         snap = cur_snap;
15370                 } else {
15371                         semerr(gettext("No snapshot selected.\n"));
15372                         return;
15373                 }
15374         }
15375 
15376         if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15377             (level = scf_snaplevel_create(g_hndl)) == NULL ||
15378             (iter = scf_iter_create(g_hndl)) == NULL ||
15379             (pg = scf_pg_create(g_hndl)) == NULL ||
15380             (npg = scf_pg_create(g_hndl)) == NULL ||
15381             (prop = scf_property_create(g_hndl)) == NULL ||
15382             (val = scf_value_create(g_hndl)) == NULL)
15383                 scfdie();
15384 
15385         nbuf = safe_malloc(max_scf_name_len + 1);
15386         tbuf = safe_malloc(max_scf_pg_type_len + 1);
15387 
15388         /* Take the "previous" snapshot before we blow away the properties. */
15389         if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15390                 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15391                         scfdie();
15392         } else {
15393                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15394                         scfdie();
15395 
15396                 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15397                         scfdie();
15398         }
15399 
15400         /* Save general/enabled, since we're probably going to replace it. */
15401         enabled = 2;
15402         if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15403             scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15404             scf_property_get_value(prop, val) == 0)
15405                 (void) scf_value_get_boolean(val, &enabled);
15406 
15407         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15408                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15409                         scfdie();
15410 
15411                 goto out;
15412         }
15413 
15414         for (;;) {
15415                 boolean_t isinst;
15416                 uint32_t flags;
15417                 int r;
15418 
15419                 /* Clear the properties from the corresponding entity. */
15420                 isinst = snaplevel_is_instance(level);
15421 
15422                 if (!isinst)
15423                         r = scf_iter_service_pgs(iter, cur_svc);
15424                 else
15425                         r = scf_iter_instance_pgs(iter, cur_inst);
15426                 if (r != SCF_SUCCESS)
15427                         scfdie();
15428 
15429                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15430                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15431                                 scfdie();
15432 
15433                         /* Skip nonpersistent pgs. */
15434                         if (flags & SCF_PG_FLAG_NONPERSISTENT)
15435                                 continue;
15436 
15437                         if (scf_pg_delete(pg) != SCF_SUCCESS) {
15438                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15439                                         scfdie();
15440 
15441                                 semerr(emsg_permission_denied);
15442                                 goto out;
15443                         }
15444                 }
15445                 if (r == -1)
15446                         scfdie();
15447 
15448                 /* Copy the properties to the corresponding entity. */
15449                 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15450                         scfdie();
15451 
15452                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15453                         if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15454                                 scfdie();
15455 
15456                         if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15457                             0)
15458                                 scfdie();
15459 
15460                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15461                                 scfdie();
15462 
15463                         if (!isinst)
15464                                 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15465                                     flags, npg);
15466                         else
15467                                 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15468                                     flags, npg);
15469                         if (r != SCF_SUCCESS) {
15470                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15471                                         scfdie();
15472 
15473                                 semerr(emsg_permission_denied);
15474                                 goto out;
15475                         }
15476 
15477                         if ((enabled == 0 || enabled == 1) &&
15478                             strcmp(nbuf, scf_pg_general) == 0)
15479                                 r = pg_copy(pg, npg, enabled);
15480                         else
15481                                 r = pg_copy(pg, npg, 2);
15482 
15483                         switch (r) {
15484                         case 0:
15485                                 break;
15486 
15487                         case -1:
15488                                 semerr(emsg_permission_denied);
15489                                 goto out;
15490 
15491                         case -2:
15492                                 semerr(gettext(
15493                                     "Interrupted by another change.\n"));
15494                                 goto out;
15495 
15496                         default:
15497                                 abort();
15498                         }
15499                 }
15500                 if (r == -1)
15501                         scfdie();
15502 
15503                 /* Get next level. */
15504                 nlevel = scf_snaplevel_create(g_hndl);
15505                 if (nlevel == NULL)
15506                         scfdie();
15507 
15508                 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15509                     SCF_SUCCESS) {
15510                         if (scf_error() != SCF_ERROR_NOT_FOUND)
15511                                 scfdie();
15512 
15513                         scf_snaplevel_destroy(nlevel);
15514                         break;
15515                 }
15516 
15517                 scf_snaplevel_destroy(level);
15518                 level = nlevel;
15519         }
15520 
15521         if (snapname == NULL) {
15522                 lscf_selectsnap(NULL);
15523                 snap = NULL;            /* cur_snap has been destroyed */
15524         }
15525 
15526 out:
15527         free(tbuf);
15528         free(nbuf);
15529         scf_value_destroy(val);
15530         scf_property_destroy(prop);
15531         scf_pg_destroy(npg);
15532         scf_pg_destroy(pg);
15533         scf_iter_destroy(iter);
15534         scf_snaplevel_destroy(level);
15535         scf_snapshot_destroy(prev);
15536         if (snap != cur_snap)
15537                 scf_snapshot_destroy(snap);
15538 }
15539 
15540 void
15541 lscf_refresh(void)
15542 {
15543         ssize_t fmrilen;
15544         size_t bufsz;
15545         char *fmribuf;
15546         int r;
15547 
15548         lscf_prep_hndl();
15549 
15550         if (cur_inst == NULL) {
15551                 semerr(gettext("Instance not selected.\n"));
15552                 return;
15553         }
15554 
15555         bufsz = max_scf_fmri_len + 1;
15556         fmribuf = safe_malloc(bufsz);
15557         fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15558         if (fmrilen < 0) {
15559                 free(fmribuf);
15560                 if (scf_error() != SCF_ERROR_DELETED)
15561                         scfdie();
15562                 scf_instance_destroy(cur_inst);
15563                 cur_inst = NULL;
15564                 warn(emsg_deleted);
15565                 return;
15566         }
15567         assert(fmrilen < bufsz);
15568 
15569         r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15570         switch (r) {
15571         case 0:
15572                 break;
15573 
15574         case ECONNABORTED:
15575                 warn(gettext("Could not refresh %s "
15576                     "(repository connection broken).\n"), fmribuf);
15577                 break;
15578 
15579         case ECANCELED:
15580                 warn(emsg_deleted);
15581                 break;
15582 
15583         case EPERM:
15584                 warn(gettext("Could not refresh %s "
15585                     "(permission denied).\n"), fmribuf);
15586                 break;
15587 
15588         case ENOSPC:
15589                 warn(gettext("Could not refresh %s "
15590                     "(repository server out of resources).\n"),
15591                     fmribuf);
15592                 break;
15593 
15594         case EACCES:
15595         default:
15596                 bad_error("refresh_entity", scf_error());
15597         }
15598 
15599         free(fmribuf);
15600 }
15601 
15602 /*
15603  * describe [-v] [-t] [pg/prop]
15604  */
15605 int
15606 lscf_describe(uu_list_t *args, int hasargs)
15607 {
15608         int ret = 0;
15609         size_t i;
15610         int argc;
15611         char **argv = NULL;
15612         string_list_t *slp;
15613         int do_verbose = 0;
15614         int do_templates = 0;
15615         char *pattern = NULL;
15616 
15617         lscf_prep_hndl();
15618 
15619         if (hasargs != 0)  {
15620                 argc = uu_list_numnodes(args);
15621                 if (argc < 1)
15622                         goto usage;
15623 
15624                 argv = calloc(argc + 1, sizeof (char *));
15625                 if (argv == NULL)
15626                         uu_die(gettext("Out of memory.\n"));
15627 
15628                 for (slp = uu_list_first(args), i = 0;
15629                     slp != NULL;
15630                     slp = uu_list_next(args, slp), ++i)
15631                         argv[i] = slp->str;
15632 
15633                 argv[i] = NULL;
15634 
15635                 /*
15636                  * We start optind = 0 because our list of arguments
15637                  * starts at argv[0]
15638                  */
15639                 optind = 0;
15640                 opterr = 0;
15641                 for (;;) {
15642                         ret = getopt(argc, argv, "vt");
15643                         if (ret == -1)
15644                                 break;
15645 
15646                         switch (ret) {
15647                         case 'v':
15648                                 do_verbose = 1;
15649                                 break;
15650 
15651                         case 't':
15652                                 do_templates = 1;
15653                                 break;
15654 
15655                         case '?':
15656                                 goto usage;
15657 
15658                         default:
15659                                 bad_error("getopt", ret);
15660                         }
15661                 }
15662 
15663                 pattern = argv[optind];
15664         }
15665 
15666         if (cur_inst == NULL && cur_svc == NULL) {
15667                 semerr(emsg_entity_not_selected);
15668                 ret = -1;
15669                 goto out;
15670         }
15671 
15672         /*
15673          * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15674          * output if their last parameter is set to 2.  Less information is
15675          * produced if the parameter is set to 1.
15676          */
15677         if (pattern == NULL) {
15678                 if (do_verbose == 1)
15679                         list_entity_tmpl(2);
15680                 else
15681                         list_entity_tmpl(1);
15682         }
15683 
15684         if (do_templates == 0) {
15685                 if (do_verbose == 1)
15686                         listprop(pattern, 0, 2);
15687                 else
15688                         listprop(pattern, 0, 1);
15689         } else {
15690                 if (do_verbose == 1)
15691                         listtmpl(pattern, 2);
15692                 else
15693                         listtmpl(pattern, 1);
15694         }
15695 
15696         ret = 0;
15697 out:
15698         if (argv != NULL)
15699                 free(argv);
15700         return (ret);
15701 usage:
15702         ret = -2;
15703         goto out;
15704 }
15705 
15706 #define PARAM_ACTIVE    ((const char *) "active")
15707 #define PARAM_INACTIVE  ((const char *) "inactive")
15708 #define PARAM_SMTP_TO   ((const char *) "to")
15709 
15710 /*
15711  * tokenize()
15712  * Breaks down the string according to the tokens passed.
15713  * Caller is responsible for freeing array of pointers returned.
15714  * Returns NULL on failure
15715  */
15716 char **
15717 tokenize(char *str, const char *sep)
15718 {
15719         char *token, *lasts;
15720         char **buf;
15721         int n = 0;      /* number of elements */
15722         int size = 8;   /* size of the array (initial) */
15723 
15724         buf = safe_malloc(size * sizeof (char *));
15725 
15726         for (token = strtok_r(str, sep, &lasts); token != NULL;
15727             token = strtok_r(NULL, sep, &lasts), ++n) {
15728                 if (n + 1 >= size) {
15729                         size *= 2;
15730                         if ((buf = realloc(buf, size * sizeof (char *))) ==
15731                             NULL) {
15732                                 uu_die(gettext("Out of memory"));
15733                         }
15734                 }
15735                 buf[n] = token;
15736         }
15737         /* NULL terminate the pointer array */
15738         buf[n] = NULL;
15739 
15740         return (buf);
15741 }
15742 
15743 int32_t
15744 check_tokens(char **p)
15745 {
15746         int32_t smf = 0;
15747         int32_t fma = 0;
15748 
15749         while (*p) {
15750                 int32_t t = string_to_tset(*p);
15751 
15752                 if (t == 0) {
15753                         if (is_fma_token(*p) == 0)
15754                                 return (INVALID_TOKENS);
15755                         fma = 1; /* this token is an fma event */
15756                 } else {
15757                         smf |= t;
15758                 }
15759 
15760                 if (smf != 0 && fma == 1)
15761                         return (MIXED_TOKENS);
15762                 ++p;
15763         }
15764 
15765         if (smf > 0)
15766                 return (smf);
15767         else if (fma == 1)
15768                 return (FMA_TOKENS);
15769 
15770         return (INVALID_TOKENS);
15771 }
15772 
15773 static int
15774 get_selection_str(char *fmri, size_t sz)
15775 {
15776         if (g_hndl == NULL) {
15777                 semerr(emsg_entity_not_selected);
15778                 return (-1);
15779         } else if (cur_level != NULL) {
15780                 semerr(emsg_invalid_for_snapshot);
15781                 return (-1);
15782         } else {
15783                 lscf_get_selection_str(fmri, sz);
15784         }
15785 
15786         return (0);
15787 }
15788 
15789 void
15790 lscf_delnotify(const char *set, int global)
15791 {
15792         char *str = strdup(set);
15793         char **pgs;
15794         char **p;
15795         int32_t tset;
15796         char *fmri = NULL;
15797 
15798         if (str == NULL)
15799                 uu_die(gettext("Out of memory.\n"));
15800 
15801         pgs = tokenize(str, ",");
15802 
15803         if ((tset = check_tokens(pgs)) > 0) {
15804                 size_t sz = max_scf_fmri_len + 1;
15805 
15806                 fmri = safe_malloc(sz);
15807                 if (global) {
15808                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15809                 } else if (get_selection_str(fmri, sz) != 0) {
15810                         goto out;
15811                 }
15812 
15813                 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15814                     tset) != SCF_SUCCESS) {
15815                         uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15816                             scf_strerror(scf_error()));
15817                 }
15818         } else if (tset == FMA_TOKENS) {
15819                 if (global) {
15820                         semerr(gettext("Can't use option '-g' with FMA event "
15821                             "definitions\n"));
15822                         goto out;
15823                 }
15824 
15825                 for (p = pgs; *p; ++p) {
15826                         if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15827                             SCF_SUCCESS) {
15828                                 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15829                                     scf_strerror(scf_error()));
15830                                 goto out;
15831                         }
15832                 }
15833         } else if (tset == MIXED_TOKENS) {
15834                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15835                 goto out;
15836         } else {
15837                 uu_die(gettext("Invalid input.\n"));
15838         }
15839 
15840 out:
15841         free(fmri);
15842         free(pgs);
15843         free(str);
15844 }
15845 
15846 void
15847 lscf_listnotify(const char *set, int global)
15848 {
15849         char *str = safe_strdup(set);
15850         char **pgs;
15851         char **p;
15852         int32_t tset;
15853         nvlist_t *nvl;
15854         char *fmri = NULL;
15855 
15856         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15857                 uu_die(gettext("Out of memory.\n"));
15858 
15859         pgs = tokenize(str, ",");
15860 
15861         if ((tset = check_tokens(pgs)) > 0) {
15862                 size_t sz = max_scf_fmri_len + 1;
15863 
15864                 fmri = safe_malloc(sz);
15865                 if (global) {
15866                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15867                 } else if (get_selection_str(fmri, sz) != 0) {
15868                         goto out;
15869                 }
15870 
15871                 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15872                     SCF_SUCCESS) {
15873                         if (scf_error() != SCF_ERROR_NOT_FOUND &&
15874                             scf_error() != SCF_ERROR_DELETED)
15875                                 uu_warn(gettext(
15876                                     "Failed listnotify: %s\n"),
15877                                     scf_strerror(scf_error()));
15878                         goto out;
15879                 }
15880 
15881                 listnotify_print(nvl, NULL);
15882         } else if (tset == FMA_TOKENS) {
15883                 if (global) {
15884                         semerr(gettext("Can't use option '-g' with FMA event "
15885                             "definitions\n"));
15886                         goto out;
15887                 }
15888 
15889                 for (p = pgs; *p; ++p) {
15890                         if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15891                             SCF_SUCCESS) {
15892                                 /*
15893                                  * if the preferences have just been deleted
15894                                  * or does not exist, just skip.
15895                                  */
15896                                 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15897                                     scf_error() == SCF_ERROR_DELETED)
15898                                         continue;
15899                                 uu_warn(gettext(
15900                                     "Failed listnotify: %s\n"),
15901                                     scf_strerror(scf_error()));
15902                                 goto out;
15903                         }
15904                         listnotify_print(nvl, re_tag(*p));
15905                 }
15906         } else if (tset == MIXED_TOKENS) {
15907                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15908                 goto out;
15909         } else {
15910                 semerr(gettext("Invalid input.\n"));
15911         }
15912 
15913 out:
15914         nvlist_free(nvl);
15915         free(fmri);
15916         free(pgs);
15917         free(str);
15918 }
15919 
15920 static char *
15921 strip_quotes_and_blanks(char *s)
15922 {
15923         char *start = s;
15924         char *end = strrchr(s, '\"');
15925 
15926         if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15927                 start = s + 1;
15928                 while (isblank(*start))
15929                         start++;
15930                 while (isblank(*(end - 1)) && end > start) {
15931                         end--;
15932                 }
15933                 *end = '\0';
15934         }
15935 
15936         return (start);
15937 }
15938 
15939 static int
15940 set_active(nvlist_t *mech, const char *hier_part)
15941 {
15942         boolean_t b;
15943 
15944         if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15945                 b = B_TRUE;
15946         } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15947                 b = B_FALSE;
15948         } else {
15949                 return (-1);
15950         }
15951 
15952         if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15953                 uu_die(gettext("Out of memory.\n"));
15954 
15955         return (0);
15956 }
15957 
15958 static int
15959 add_snmp_params(nvlist_t *mech, char *hier_part)
15960 {
15961         return (set_active(mech, hier_part));
15962 }
15963 
15964 static int
15965 add_syslog_params(nvlist_t *mech, char *hier_part)
15966 {
15967         return (set_active(mech, hier_part));
15968 }
15969 
15970 /*
15971  * add_mailto_paramas()
15972  * parse the hier_part of mailto URI
15973  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15974  * or mailto:{[active]|inactive}
15975  */
15976 static int
15977 add_mailto_params(nvlist_t *mech, char *hier_part)
15978 {
15979         const char *tok = "?&";
15980         char *p;
15981         char *lasts;
15982         char *param;
15983         char *val;
15984 
15985         /*
15986          * If the notification parametes are in the form of
15987          *
15988          *   malito:{[active]|inactive}
15989          *
15990          * we set the property accordingly and return.
15991          * Otherwise, we make the notification type active and
15992          * process the hier_part.
15993          */
15994         if (set_active(mech, hier_part) == 0)
15995                 return (0);
15996         else if (set_active(mech, PARAM_ACTIVE) != 0)
15997                 return (-1);
15998 
15999         if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16000                 /*
16001                  * sanity check: we only get here if hier_part = "", but
16002                  * that's handled by set_active
16003                  */
16004                 uu_die("strtok_r");
16005         }
16006 
16007         if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16008                 uu_die(gettext("Out of memory.\n"));
16009 
16010         while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16011                 if ((param = strtok_r(p, "=", &val)) != NULL)
16012                         if (nvlist_add_string(mech, param, val) != 0)
16013                                 uu_die(gettext("Out of memory.\n"));
16014 
16015         return (0);
16016 }
16017 
16018 static int
16019 uri_split(char *uri, char **scheme, char **hier_part)
16020 {
16021         int r = -1;
16022 
16023         if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16024             *hier_part == NULL) {
16025                 semerr(gettext("'%s' is not an URI\n"), uri);
16026                 return (r);
16027         }
16028 
16029         if ((r = check_uri_scheme(*scheme)) < 0) {
16030                 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16031                 return (r);
16032         }
16033 
16034         return (r);
16035 }
16036 
16037 static int
16038 process_uri(nvlist_t *params, char *uri)
16039 {
16040         char *scheme;
16041         char *hier_part;
16042         nvlist_t *mech;
16043         int index;
16044         int r;
16045 
16046         if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16047                 return (-1);
16048 
16049         if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16050                 uu_die(gettext("Out of memory.\n"));
16051 
16052         switch (index) {
16053         case 0:
16054                 /* error messages displayed by called function */
16055                 r = add_mailto_params(mech, hier_part);
16056                 break;
16057 
16058         case 1:
16059                 if ((r = add_snmp_params(mech, hier_part)) != 0)
16060                         semerr(gettext("Not valid parameters: '%s'\n"),
16061                             hier_part);
16062                 break;
16063 
16064         case 2:
16065                 if ((r = add_syslog_params(mech, hier_part)) != 0)
16066                         semerr(gettext("Not valid parameters: '%s'\n"),
16067                             hier_part);
16068                 break;
16069 
16070         default:
16071                 r = -1;
16072         }
16073 
16074         if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16075             mech) != 0)
16076                 uu_die(gettext("Out of memory.\n"));
16077 
16078         nvlist_free(mech);
16079         return (r);
16080 }
16081 
16082 static int
16083 set_params(nvlist_t *params, char **p)
16084 {
16085         char *uri;
16086 
16087         if (p == NULL)
16088                 /* sanity check */
16089                 uu_die("set_params");
16090 
16091         while (*p) {
16092                 uri = strip_quotes_and_blanks(*p);
16093                 if (process_uri(params, uri) != 0)
16094                         return (-1);
16095 
16096                 ++p;
16097         }
16098 
16099         return (0);
16100 }
16101 
16102 static int
16103 setnotify(const char *e, char **p, int global)
16104 {
16105         char *str = safe_strdup(e);
16106         char **events;
16107         int32_t tset;
16108         int r = -1;
16109         nvlist_t *nvl, *params;
16110         char *fmri = NULL;
16111 
16112         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16113             nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16114             nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16115             SCF_NOTIFY_PARAMS_VERSION) != 0)
16116                 uu_die(gettext("Out of memory.\n"));
16117 
16118         events = tokenize(str, ",");
16119 
16120         if ((tset = check_tokens(events)) > 0) {
16121                 /* SMF state transitions parameters */
16122                 size_t sz = max_scf_fmri_len + 1;
16123 
16124                 fmri = safe_malloc(sz);
16125                 if (global) {
16126                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16127                 } else if (get_selection_str(fmri, sz) != 0) {
16128                         goto out;
16129                 }
16130 
16131                 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16132                     nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16133                         uu_die(gettext("Out of memory.\n"));
16134 
16135                 if ((r = set_params(params, p)) == 0) {
16136                         if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16137                             params) != 0)
16138                                 uu_die(gettext("Out of memory.\n"));
16139 
16140                         if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16141                             nvl) != SCF_SUCCESS) {
16142                                 r = -1;
16143                                 uu_warn(gettext(
16144                                     "Failed smf_notify_set_params(3SCF): %s\n"),
16145                                     scf_strerror(scf_error()));
16146                         }
16147                 }
16148         } else if (tset == FMA_TOKENS) {
16149                 /* FMA event parameters */
16150                 if (global) {
16151                         semerr(gettext("Can't use option '-g' with FMA event "
16152                             "definitions\n"));
16153                         goto out;
16154                 }
16155 
16156                 if ((r = set_params(params, p)) != 0)
16157                         goto out;
16158 
16159                 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16160                         uu_die(gettext("Out of memory.\n"));
16161 
16162                 while (*events) {
16163                         if (smf_notify_set_params(de_tag(*events), nvl) !=
16164                             SCF_SUCCESS)
16165                                 uu_warn(gettext(
16166                                     "Failed smf_notify_set_params(3SCF) for "
16167                                     "event %s: %s\n"), *events,
16168                                     scf_strerror(scf_error()));
16169                         events++;
16170                 }
16171         } else if (tset == MIXED_TOKENS) {
16172                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16173         } else {
16174                 /* Sanity check */
16175                 uu_die(gettext("Invalid input.\n"));
16176         }
16177 
16178 out:
16179         nvlist_free(nvl);
16180         nvlist_free(params);
16181         free(fmri);
16182         free(str);
16183 
16184         return (r);
16185 }
16186 
16187 int
16188 lscf_setnotify(uu_list_t *args)
16189 {
16190         int argc;
16191         char **argv = NULL;
16192         string_list_t *slp;
16193         int global;
16194         char *events;
16195         char **p;
16196         int i;
16197         int ret;
16198 
16199         if ((argc = uu_list_numnodes(args)) < 2)
16200                 goto usage;
16201 
16202         argv = calloc(argc + 1, sizeof (char *));
16203         if (argv == NULL)
16204                 uu_die(gettext("Out of memory.\n"));
16205 
16206         for (slp = uu_list_first(args), i = 0;
16207             slp != NULL;
16208             slp = uu_list_next(args, slp), ++i)
16209                 argv[i] = slp->str;
16210 
16211         argv[i] = NULL;
16212 
16213         if (strcmp(argv[0], "-g") == 0) {
16214                 global = 1;
16215                 events = argv[1];
16216                 p = argv + 2;
16217         } else {
16218                 global = 0;
16219                 events = argv[0];
16220                 p = argv + 1;
16221         }
16222 
16223         ret = setnotify(events, p, global);
16224 
16225 out:
16226         free(argv);
16227         return (ret);
16228 
16229 usage:
16230         ret = -2;
16231         goto out;
16232 }
16233 
16234 /*
16235  * Creates a list of instance name strings associated with a service. If
16236  * wohandcrafted flag is set, get only instances that have a last-import
16237  * snapshot, instances that were imported via svccfg.
16238  */
16239 static uu_list_t *
16240 create_instance_list(scf_service_t *svc, int wohandcrafted)
16241 {
16242         scf_snapshot_t  *snap = NULL;
16243         scf_instance_t  *inst;
16244         scf_iter_t      *inst_iter;
16245         uu_list_t       *instances;
16246         char            *instname;
16247         int             r;
16248 
16249         inst_iter = scf_iter_create(g_hndl);
16250         inst = scf_instance_create(g_hndl);
16251         if (inst_iter == NULL || inst == NULL) {
16252                 uu_warn(gettext("Could not create instance or iterator\n"));
16253                 scfdie();
16254         }
16255 
16256         if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16257                 return (instances);
16258 
16259         if (scf_iter_service_instances(inst_iter, svc) != 0) {
16260                 switch (scf_error()) {
16261                 case SCF_ERROR_CONNECTION_BROKEN:
16262                 case SCF_ERROR_DELETED:
16263                         uu_list_destroy(instances);
16264                         instances = NULL;
16265                         goto out;
16266 
16267                 case SCF_ERROR_HANDLE_MISMATCH:
16268                 case SCF_ERROR_NOT_BOUND:
16269                 case SCF_ERROR_NOT_SET:
16270                 default:
16271                         bad_error("scf_iter_service_instances", scf_error());
16272                 }
16273         }
16274 
16275         instname = safe_malloc(max_scf_name_len + 1);
16276         while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16277                 if (r == -1) {
16278                         (void) uu_warn(gettext("Unable to iterate through "
16279                             "instances to create instance list : %s\n"),
16280                             scf_strerror(scf_error()));
16281 
16282                         uu_list_destroy(instances);
16283                         instances = NULL;
16284                         goto out;
16285                 }
16286 
16287                 /*
16288                  * If the instance does not have a last-import snapshot
16289                  * then do not add it to the list as it is a hand-crafted
16290                  * instance that should not be managed.
16291                  */
16292                 if (wohandcrafted) {
16293                         if (snap == NULL &&
16294                             (snap = scf_snapshot_create(g_hndl)) == NULL) {
16295                                 uu_warn(gettext("Unable to create snapshot "
16296                                     "entity\n"));
16297                                 scfdie();
16298                         }
16299 
16300                         if (scf_instance_get_snapshot(inst,
16301                             snap_lastimport, snap) != 0) {
16302                                 switch (scf_error()) {
16303                                 case SCF_ERROR_NOT_FOUND :
16304                                 case SCF_ERROR_DELETED:
16305                                         continue;
16306 
16307                                 case SCF_ERROR_CONNECTION_BROKEN:
16308                                         uu_list_destroy(instances);
16309                                         instances = NULL;
16310                                         goto out;
16311 
16312                                 case SCF_ERROR_HANDLE_MISMATCH:
16313                                 case SCF_ERROR_NOT_BOUND:
16314                                 case SCF_ERROR_NOT_SET:
16315                                 default:
16316                                         bad_error("scf_iter_service_instances",
16317                                             scf_error());
16318                                 }
16319                         }
16320                 }
16321 
16322                 if (scf_instance_get_name(inst, instname,
16323                     max_scf_name_len + 1) < 0) {
16324                         switch (scf_error()) {
16325                         case SCF_ERROR_NOT_FOUND :
16326                                 continue;
16327 
16328                         case SCF_ERROR_CONNECTION_BROKEN:
16329                         case SCF_ERROR_DELETED:
16330                                 uu_list_destroy(instances);
16331                                 instances = NULL;
16332                                 goto out;
16333 
16334                         case SCF_ERROR_HANDLE_MISMATCH:
16335                         case SCF_ERROR_NOT_BOUND:
16336                         case SCF_ERROR_NOT_SET:
16337                         default:
16338                                 bad_error("scf_iter_service_instances",
16339                                     scf_error());
16340                         }
16341                 }
16342 
16343                 add_string(instances, instname);
16344         }
16345 
16346 out:
16347         if (snap)
16348                 scf_snapshot_destroy(snap);
16349 
16350         scf_instance_destroy(inst);
16351         scf_iter_destroy(inst_iter);
16352         free(instname);
16353         return (instances);
16354 }
16355 
16356 /*
16357  * disable an instance but wait for the instance to
16358  * move out of the running state.
16359  *
16360  * Returns 0 : if the instance did not disable
16361  * Returns non-zero : if the instance disabled.
16362  *
16363  */
16364 static int
16365 disable_instance(scf_instance_t *instance)
16366 {
16367         char    *fmribuf;
16368         int     enabled = 10000;
16369 
16370         if (inst_is_running(instance)) {
16371                 fmribuf = safe_malloc(max_scf_name_len + 1);
16372                 if (scf_instance_to_fmri(instance, fmribuf,
16373                     max_scf_name_len + 1) < 0) {
16374                         free(fmribuf);
16375                         return (0);
16376                 }
16377 
16378                 /*
16379                  * If the instance cannot be disabled then return
16380                  * failure to disable and let the caller decide
16381                  * if that is of importance.
16382                  */
16383                 if (smf_disable_instance(fmribuf, 0) != 0) {
16384                         free(fmribuf);
16385                         return (0);
16386                 }
16387 
16388                 while (enabled) {
16389                         if (!inst_is_running(instance))
16390                                 break;
16391 
16392                         (void) poll(NULL, 0, 5);
16393                         enabled = enabled - 5;
16394                 }
16395 
16396                 free(fmribuf);
16397         }
16398 
16399         return (enabled);
16400 }
16401 
16402 /*
16403  * Function to compare two service_manifest structures.
16404  */
16405 /* ARGSUSED2 */
16406 static int
16407 service_manifest_compare(const void *left, const void *right, void *unused)
16408 {
16409         service_manifest_t *l = (service_manifest_t *)left;
16410         service_manifest_t *r = (service_manifest_t *)right;
16411         int rc;
16412 
16413         rc = strcmp(l->servicename, r->servicename);
16414 
16415         return (rc);
16416 }
16417 
16418 /*
16419  * Look for the provided service in the service to manifest
16420  * tree.  If the service exists, and a manifest was provided
16421  * then add the manifest to that service.  If the service
16422  * does not exist, then add the service and manifest to the
16423  * list.
16424  *
16425  * If the manifest is NULL, return the element if found.  If
16426  * the service is not found return NULL.
16427  */
16428 service_manifest_t *
16429 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16430 {
16431         service_manifest_t      elem;
16432         service_manifest_t      *fnelem;
16433         uu_avl_index_t          marker;
16434 
16435         elem.servicename = svnbuf;
16436         fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16437 
16438         if (mfst) {
16439                 if (fnelem) {
16440                         add_string(fnelem->mfstlist, strdup(mfst));
16441                 } else {
16442                         fnelem = safe_malloc(sizeof (*fnelem));
16443                         fnelem->servicename = safe_strdup(svnbuf);
16444                         if ((fnelem->mfstlist =
16445                             uu_list_create(string_pool, NULL, 0)) == NULL)
16446                                 uu_die(gettext("Could not create property "
16447                                     "list: %s\n"), uu_strerror(uu_error()));
16448 
16449                         add_string(fnelem->mfstlist, safe_strdup(mfst));
16450 
16451                         uu_avl_insert(service_manifest_tree, fnelem, marker);
16452                 }
16453         }
16454 
16455         return (fnelem);
16456 }
16457 
16458 /*
16459  * Create the service to manifest avl tree.
16460  *
16461  * Walk each of the manifests currently installed in the supported
16462  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16463  * each of the manifests, inventory the services and add them to
16464  * the tree.
16465  *
16466  * Code that calls this function should make sure fileystem/minimal is online,
16467  * /var is available, since this function walks the /var/svc/manifest directory.
16468  */
16469 static void
16470 create_manifest_tree(void)
16471 {
16472         manifest_info_t **entry;
16473         manifest_info_t **manifests;
16474         uu_list_walk_t  *svcs;
16475         bundle_t        *b;
16476         entity_t        *mfsvc;
16477         char            *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16478         int             c, status;
16479 
16480         if (service_manifest_pool)
16481                 return;
16482 
16483         /*
16484          * Create the list pool for the service manifest list
16485          */
16486         service_manifest_pool = uu_avl_pool_create("service_manifest",
16487             sizeof (service_manifest_t),
16488             offsetof(service_manifest_t, svcmfst_node),
16489             service_manifest_compare, UU_DEFAULT);
16490         if (service_manifest_pool == NULL)
16491                 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16492                     uu_strerror(uu_error()));
16493 
16494         /*
16495          * Create the list
16496          */
16497         service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16498             UU_DEFAULT);
16499         if (service_manifest_tree == NULL)
16500                 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16501                     uu_strerror(uu_error()));
16502 
16503         /*
16504          * Walk the manifests adding the service(s) from each manifest.
16505          *
16506          * If a service already exists add the manifest to the manifest
16507          * list for that service.  This covers the case of a service that
16508          * is supported by multiple manifest files.
16509          */
16510         for (c = 0; dirs[c]; c++) {
16511                 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16512                 if (status < 0) {
16513                         uu_warn(gettext("file tree walk of %s encountered "
16514                             "error %s\n"), dirs[c], strerror(errno));
16515 
16516                         uu_avl_destroy(service_manifest_tree);
16517                         service_manifest_tree = NULL;
16518                         return;
16519                 }
16520 
16521                 /*
16522                  * If a manifest that was in the list is not found
16523                  * then skip and go to the next manifest file.
16524                  */
16525                 if (manifests != NULL) {
16526                         for (entry = manifests; *entry != NULL; entry++) {
16527                                 b = internal_bundle_new();
16528                                 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16529                                     SVCCFG_OP_IMPORT) != 0) {
16530                                         internal_bundle_free(b);
16531                                         continue;
16532                                 }
16533 
16534                                 svcs = uu_list_walk_start(b->sc_bundle_services,
16535                                     0);
16536                                 if (svcs == NULL) {
16537                                         internal_bundle_free(b);
16538                                         continue;
16539                                 }
16540 
16541                                 while ((mfsvc = uu_list_walk_next(svcs)) !=
16542                                     NULL) {
16543                                         /* Add manifest to service */
16544                                         (void) find_add_svc_mfst(mfsvc->sc_name,
16545                                             (*entry)->mi_path);
16546                                 }
16547 
16548                                 uu_list_walk_end(svcs);
16549                                 internal_bundle_free(b);
16550                         }
16551 
16552                         free_manifest_array(manifests);
16553                 }
16554         }
16555 }
16556 
16557 /*
16558  * Check the manifest history file to see
16559  * if the service was ever installed from
16560  * one of the supported directories.
16561  *
16562  * Return Values :
16563  *      -1 - if there's error reading manifest history file
16564  *       1 - if the service is not found
16565  *       0 - if the service is found
16566  */
16567 static int
16568 check_mfst_history(const char *svcname)
16569 {
16570         struct stat     st;
16571         caddr_t         mfsthist_start;
16572         char            *svnbuf;
16573         int             fd;
16574         int             r = 1;
16575 
16576         fd = open(MFSTHISTFILE, O_RDONLY);
16577         if (fd == -1) {
16578                 uu_warn(gettext("Unable to open the history file\n"));
16579                 return (-1);
16580         }
16581 
16582         if (fstat(fd, &st) == -1) {
16583                 uu_warn(gettext("Unable to stat the history file\n"));
16584                 return (-1);
16585         }
16586 
16587         mfsthist_start = mmap(0, st.st_size, PROT_READ,
16588             MAP_PRIVATE, fd, 0);
16589 
16590         (void) close(fd);
16591         if (mfsthist_start == MAP_FAILED ||
16592             *(mfsthist_start + st.st_size) != '\0') {
16593                 (void) munmap(mfsthist_start, st.st_size);
16594                 return (-1);
16595         }
16596 
16597         /*
16598          * The manifest history file is a space delimited list
16599          * of service and instance to manifest linkage.  Adding
16600          * a space to the end of the service name so to get only
16601          * the service that is being searched for.
16602          */
16603         svnbuf = uu_msprintf("%s ", svcname);
16604         if (svnbuf == NULL)
16605                 uu_die(gettext("Out of memory"));
16606 
16607         if (strstr(mfsthist_start, svnbuf) != NULL)
16608                 r = 0;
16609 
16610         (void) munmap(mfsthist_start, st.st_size);
16611         uu_free(svnbuf);
16612         return (r);
16613 }
16614 
16615 /*
16616  * Take down each of the instances in the service
16617  * and remove them, then delete the service.
16618  */
16619 static void
16620 teardown_service(scf_service_t *svc, const char *svnbuf)
16621 {
16622         scf_instance_t  *instance;
16623         scf_iter_t      *iter;
16624         int             r;
16625 
16626         safe_printf(gettext("Delete service %s as there are no "
16627             "supporting manifests\n"), svnbuf);
16628 
16629         instance = scf_instance_create(g_hndl);
16630         iter = scf_iter_create(g_hndl);
16631         if (iter == NULL || instance == NULL) {
16632                 uu_warn(gettext("Unable to create supporting entities to "
16633                     "teardown the service\n"));
16634                 uu_warn(gettext("scf error is : %s\n"),
16635                     scf_strerror(scf_error()));
16636                 scfdie();
16637         }
16638 
16639         if (scf_iter_service_instances(iter, svc) != 0) {
16640                 switch (scf_error()) {
16641                 case SCF_ERROR_CONNECTION_BROKEN:
16642                 case SCF_ERROR_DELETED:
16643                         goto out;
16644 
16645                 case SCF_ERROR_HANDLE_MISMATCH:
16646                 case SCF_ERROR_NOT_BOUND:
16647                 case SCF_ERROR_NOT_SET:
16648                 default:
16649                         bad_error("scf_iter_service_instances",
16650                             scf_error());
16651                 }
16652         }
16653 
16654         while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16655                 if (r == -1) {
16656                         uu_warn(gettext("Error - %s\n"),
16657                             scf_strerror(scf_error()));
16658                         goto out;
16659                 }
16660 
16661                 (void) disable_instance(instance);
16662         }
16663 
16664         /*
16665          * Delete the service... forcing the deletion in case
16666          * any of the instances did not disable.
16667          */
16668         (void) lscf_service_delete(svc, 1);
16669 out:
16670         scf_instance_destroy(instance);
16671         scf_iter_destroy(iter);
16672 }
16673 
16674 /*
16675  * Get the list of instances supported by the manifest
16676  * file.
16677  *
16678  * Return 0 if there are no instances.
16679  *
16680  * Return -1 if there are errors attempting to collect instances.
16681  *
16682  * Return the count of instances found if there are no errors.
16683  *
16684  */
16685 static int
16686 check_instance_support(char *mfstfile, const char *svcname,
16687     uu_list_t *instances)
16688 {
16689         uu_list_walk_t  *svcs, *insts;
16690         uu_list_t       *ilist;
16691         bundle_t        *b;
16692         entity_t        *mfsvc, *mfinst;
16693         const char      *svcn;
16694         int             rminstcnt = 0;
16695 
16696 
16697         b = internal_bundle_new();
16698 
16699         if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16700                 /*
16701                  * Unable to process the manifest file for
16702                  * instance support, so just return as
16703                  * don't want to remove instances that could
16704                  * not be accounted for that might exist here.
16705                  */
16706                 internal_bundle_free(b);
16707                 return (0);
16708         }
16709 
16710         svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16711         if (svcs == NULL) {
16712                 internal_bundle_free(b);
16713                 return (0);
16714         }
16715 
16716         svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16717             (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16718 
16719         while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16720                 if (strcmp(mfsvc->sc_name, svcn) == 0)
16721                         break;
16722         }
16723         uu_list_walk_end(svcs);
16724 
16725         if (mfsvc == NULL) {
16726                 internal_bundle_free(b);
16727                 return (-1);
16728         }
16729 
16730         ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16731         if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16732                 internal_bundle_free(b);
16733                 return (0);
16734         }
16735 
16736         while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16737                 /*
16738                  * Remove the instance from the instances list.
16739                  * The unaccounted for instances will be removed
16740                  * from the service once all manifests are
16741                  * processed.
16742                  */
16743                 (void) remove_string(instances,
16744                     mfinst->sc_name);
16745                 rminstcnt++;
16746         }
16747 
16748         uu_list_walk_end(insts);
16749         internal_bundle_free(b);
16750 
16751         return (rminstcnt);
16752 }
16753 
16754 /*
16755  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16756  * 'false' to indicate there's no manifest file(s) found for the service.
16757  */
16758 static void
16759 svc_add_no_support(scf_service_t *svc)
16760 {
16761         char    *pname;
16762 
16763         /* Add no support */
16764         cur_svc = svc;
16765         if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16766                 return;
16767 
16768         pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16769         if (pname == NULL)
16770                 uu_die(gettext("Out of memory.\n"));
16771 
16772         (void) lscf_addpropvalue(pname, "boolean:", "0");
16773 
16774         uu_free(pname);
16775         cur_svc = NULL;
16776 }
16777 
16778 /*
16779  * This function handles all upgrade scenarios for a service that doesn't have
16780  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16781  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16782  * manifest(s) mapping. Manifests under supported directories are inventoried
16783  * and a property is added for each file that delivers configuration to the
16784  * service.  A service that has no corresponding manifest files (deleted) are
16785  * removed from repository.
16786  *
16787  * Unsupported services:
16788  *
16789  * A service is considered unsupported if there is no corresponding manifest
16790  * in the supported directories for that service and the service isn't in the
16791  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16792  * services and instances that were delivered by Solaris before the introduction
16793  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16794  * the path to the manifest file that defined the service or instance.
16795  *
16796  * Another type of unsupported services is 'handcrafted' services,
16797  * programmatically created services or services created by dependent entries
16798  * in other manifests. A handcrafted service is identified by its lack of any
16799  * instance containing last-import snapshot which is created during svccfg
16800  * import.
16801  *
16802  * This function sets a flag for unsupported services by setting services'
16803  * SCF_PG_MANIFESTFILES/support property to false.
16804  */
16805 static void
16806 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16807 {
16808         service_manifest_t      *elem;
16809         uu_list_walk_t          *mfwalk;
16810         string_list_t           *mfile;
16811         uu_list_t               *instances;
16812         const char              *sname;
16813         char                    *pname;
16814         int                     r;
16815 
16816         /*
16817          * Since there's no guarantee manifests under /var are available during
16818          * early import, don't perform any upgrade during early import.
16819          */
16820         if (IGNORE_VAR)
16821                 return;
16822 
16823         if (service_manifest_tree == NULL) {
16824                 create_manifest_tree();
16825         }
16826 
16827         /*
16828          * Find service's supporting manifest(s) after
16829          * stripping off the svc:/ prefix that is part
16830          * of the fmri that is not used in the service
16831          * manifest bundle list.
16832          */
16833         sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16834             strlen(SCF_FMRI_SERVICE_PREFIX);
16835         elem = find_add_svc_mfst(sname, NULL);
16836         if (elem == NULL) {
16837 
16838                 /*
16839                  * A handcrafted service, one that has no instance containing
16840                  * last-import snapshot, should get unsupported flag.
16841                  */
16842                 instances = create_instance_list(svc, 1);
16843                 if (instances == NULL) {
16844                         uu_warn(gettext("Unable to create instance list %s\n"),
16845                             svcname);
16846                         return;
16847                 }
16848 
16849                 if (uu_list_numnodes(instances) == 0) {
16850                         svc_add_no_support(svc);
16851                         return;
16852                 }
16853 
16854                 /*
16855                  * If the service is in the history file, and its supporting
16856                  * manifests are not found, we can safely delete the service
16857                  * because its manifests are removed from the system.
16858                  *
16859                  * Services not found in the history file are not delivered by
16860                  * Solaris and/or delivered outside supported directories, set
16861                  * unsupported flag for these services.
16862                  */
16863                 r = check_mfst_history(svcname);
16864                 if (r == -1)
16865                         return;
16866 
16867                 if (r) {
16868                         /* Set unsupported flag for service  */
16869                         svc_add_no_support(svc);
16870                 } else {
16871                         /* Delete the service */
16872                         teardown_service(svc, svcname);
16873                 }
16874 
16875                 return;
16876         }
16877 
16878         /*
16879          * Walk through the list of manifests and add them
16880          * to the service.
16881          *
16882          * Create a manifestfiles pg and add the property.
16883          */
16884         mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16885         if (mfwalk == NULL)
16886                 return;
16887 
16888         cur_svc = svc;
16889         r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16890         if (r != 0) {
16891                 cur_svc = NULL;
16892                 return;
16893         }
16894 
16895         while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16896                 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16897                     mhash_filename_to_propname(mfile->str, 0));
16898                 if (pname == NULL)
16899                         uu_die(gettext("Out of memory.\n"));
16900 
16901                 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16902                 uu_free(pname);
16903         }
16904         uu_list_walk_end(mfwalk);
16905 
16906         cur_svc = NULL;
16907 }
16908 
16909 /*
16910  * Take a service and process the manifest file entires to see if
16911  * there is continued support for the service and instances.  If
16912  * not cleanup as appropriate.
16913  *
16914  * If a service does not have a manifest files entry flag it for
16915  * upgrade and return.
16916  *
16917  * For each manifestfiles property check if the manifest file is
16918  * under the supported /lib/svc/manifest or /var/svc/manifest path
16919  * and if not then return immediately as this service is not supported
16920  * by the cleanup mechanism and should be ignored.
16921  *
16922  * For each manifest file that is supported, check to see if the
16923  * file exists.  If not then remove the manifest file property
16924  * from the service and the smf/manifest hash table.  If the manifest
16925  * file exists then verify that it supports the instances that are
16926  * part of the service.
16927  *
16928  * Once all manifest files have been accounted for remove any instances
16929  * that are no longer supported in the service.
16930  *
16931  * Return values :
16932  * 0 - Successfully processed the service
16933  * non-zero - failed to process the service
16934  *
16935  * On most errors, will just return to wait and get the next service,
16936  * unless in case of unable to create the needed structures which is
16937  * most likely a fatal error that is not going to be recoverable.
16938  */
16939 int
16940 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16941 {
16942         struct mpg_mfile        *mpntov;
16943         struct mpg_mfile        **mpvarry = NULL;
16944         scf_service_t           *svc;
16945         scf_propertygroup_t     *mpg;
16946         scf_property_t          *mp;
16947         scf_value_t             *mv;
16948         scf_iter_t              *mi;
16949         scf_instance_t          *instance;
16950         uu_list_walk_t          *insts;
16951         uu_list_t               *instances = NULL;
16952         boolean_t               activity = (boolean_t)act;
16953         char                    *mpnbuf;
16954         char                    *mpvbuf;
16955         char                    *pgpropbuf;
16956         int                     mfstcnt, rminstct, instct, mfstmax;
16957         int                     index;
16958         int                     r = 0;
16959 
16960         assert(g_hndl != NULL);
16961         assert(wip->svc != NULL);
16962         assert(wip->fmri != NULL);
16963 
16964         svc = wip->svc;
16965 
16966         mpg = scf_pg_create(g_hndl);
16967         mp = scf_property_create(g_hndl);
16968         mi = scf_iter_create(g_hndl);
16969         mv = scf_value_create(g_hndl);
16970         instance = scf_instance_create(g_hndl);
16971 
16972         if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16973             instance == NULL) {
16974                 uu_warn(gettext("Unable to create the supporting entities\n"));
16975                 uu_warn(gettext("scf error is : %s\n"),
16976                     scf_strerror(scf_error()));
16977                 scfdie();
16978         }
16979 
16980         /*
16981          * Get the manifestfiles property group to be parsed for
16982          * files existence.
16983          */
16984         if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16985                 switch (scf_error()) {
16986                 case SCF_ERROR_NOT_FOUND:
16987                         upgrade_svc_mfst_connection(svc, wip->fmri);
16988                         break;
16989                 case SCF_ERROR_DELETED:
16990                 case SCF_ERROR_CONNECTION_BROKEN:
16991                         goto out;
16992 
16993                 case SCF_ERROR_HANDLE_MISMATCH:
16994                 case SCF_ERROR_NOT_BOUND:
16995                 case SCF_ERROR_NOT_SET:
16996                 default:
16997                         bad_error("scf_iter_pg_properties",
16998                             scf_error());
16999                 }
17000 
17001                 goto out;
17002         }
17003 
17004         /*
17005          * Iterate through each of the manifestfiles properties
17006          * to determine what manifestfiles are available.
17007          *
17008          * If a manifest file is supported then increment the
17009          * count and therefore the service is safe.
17010          */
17011         if (scf_iter_pg_properties(mi, mpg) != 0) {
17012                 switch (scf_error()) {
17013                 case SCF_ERROR_DELETED:
17014                 case SCF_ERROR_CONNECTION_BROKEN:
17015                         goto out;
17016 
17017                 case SCF_ERROR_HANDLE_MISMATCH:
17018                 case SCF_ERROR_NOT_BOUND:
17019                 case SCF_ERROR_NOT_SET:
17020                 default:
17021                         bad_error("scf_iter_pg_properties",
17022                             scf_error());
17023                 }
17024         }
17025 
17026         mfstcnt = 0;
17027         mfstmax = MFSTFILE_MAX;
17028         mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17029         while ((r = scf_iter_next_property(mi, mp)) != 0) {
17030                 if (r == -1)
17031                         bad_error(gettext("Unable to iterate through "
17032                             "manifestfiles properties : %s"),
17033                             scf_error());
17034 
17035                 mpntov = safe_malloc(sizeof (struct mpg_mfile));
17036                 mpnbuf = safe_malloc(max_scf_name_len + 1);
17037                 mpvbuf = safe_malloc(max_scf_value_len + 1);
17038                 mpntov->mpg = mpnbuf;
17039                 mpntov->mfile = mpvbuf;
17040                 mpntov->access = 1;
17041                 if (scf_property_get_name(mp, mpnbuf,
17042                     max_scf_name_len + 1) < 0) {
17043                         uu_warn(gettext("Unable to get manifest file "
17044                             "property : %s\n"),
17045                             scf_strerror(scf_error()));
17046 
17047                         switch (scf_error()) {
17048                         case SCF_ERROR_DELETED:
17049                         case SCF_ERROR_CONNECTION_BROKEN:
17050                                 r = scferror2errno(scf_error());
17051                                 goto out_free;
17052 
17053                         case SCF_ERROR_HANDLE_MISMATCH:
17054                         case SCF_ERROR_NOT_BOUND:
17055                         case SCF_ERROR_NOT_SET:
17056                         default:
17057                                 bad_error("scf_iter_pg_properties",
17058                                     scf_error());
17059                         }
17060                 }
17061 
17062                 /*
17063                  * The support property is a boolean value that indicates
17064                  * if the service is supported for manifest file deletion.
17065                  * Currently at this time there is no code that sets this
17066                  * value to true.  So while we could just let this be caught
17067                  * by the support check below, in the future this by be set
17068                  * to true and require processing.  So for that, go ahead
17069                  * and check here, and just return if false.  Otherwise,
17070                  * fall through expecting that other support checks will
17071                  * handle the entries.
17072                  */
17073                 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17074                         uint8_t support;
17075 
17076                         if (scf_property_get_value(mp, mv) != 0 ||
17077                             scf_value_get_boolean(mv, &support) != 0) {
17078                                 uu_warn(gettext("Unable to get the manifest "
17079                                     "support value: %s\n"),
17080                                     scf_strerror(scf_error()));
17081 
17082                                 switch (scf_error()) {
17083                                 case SCF_ERROR_DELETED:
17084                                 case SCF_ERROR_CONNECTION_BROKEN:
17085                                         r = scferror2errno(scf_error());
17086                                         goto out_free;
17087 
17088                                 case SCF_ERROR_HANDLE_MISMATCH:
17089                                 case SCF_ERROR_NOT_BOUND:
17090                                 case SCF_ERROR_NOT_SET:
17091                                 default:
17092                                         bad_error("scf_iter_pg_properties",
17093                                             scf_error());
17094                                 }
17095                         }
17096 
17097                         if (support == B_FALSE)
17098                                 goto out_free;
17099                 }
17100 
17101                 /*
17102                  * Anything with a manifest outside of the supported
17103                  * directories, immediately bail out because that makes
17104                  * this service non-supported.  We don't even want
17105                  * to do instance processing in this case because the
17106                  * instances could be part of the non-supported manifest.
17107                  */
17108                 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17109                         /*
17110                          * Manifest is not in /lib/svc, so we need to
17111                          * consider the /var/svc case.
17112                          */
17113                         if (strncmp(mpnbuf, VARSVC_PR,
17114                             strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17115                                 /*
17116                                  * Either the manifest is not in /var/svc or
17117                                  * /var is not yet mounted.  We ignore the
17118                                  * manifest either because it is not in a
17119                                  * standard location or because we cannot
17120                                  * currently access the manifest.
17121                                  */
17122                                 goto out_free;
17123                         }
17124                 }
17125 
17126                 /*
17127                  * Get the value to of the manifest file for this entry
17128                  * for access verification and instance support
17129                  * verification if it still exists.
17130                  *
17131                  * During Early Manifest Import if the manifest is in
17132                  * /var/svc then it may not yet be available for checking
17133                  * so we must determine if /var/svc is available.  If not
17134                  * then defer until Late Manifest Import to cleanup.
17135                  */
17136                 if (scf_property_get_value(mp, mv) != 0) {
17137                         uu_warn(gettext("Unable to get the manifest file "
17138                             "value: %s\n"),
17139                             scf_strerror(scf_error()));
17140 
17141                         switch (scf_error()) {
17142                         case SCF_ERROR_DELETED:
17143                         case SCF_ERROR_CONNECTION_BROKEN:
17144                                 r = scferror2errno(scf_error());
17145                                 goto out_free;
17146 
17147                         case SCF_ERROR_HANDLE_MISMATCH:
17148                         case SCF_ERROR_NOT_BOUND:
17149                         case SCF_ERROR_NOT_SET:
17150                         default:
17151                                 bad_error("scf_property_get_value",
17152                                     scf_error());
17153                         }
17154                 }
17155 
17156                 if (scf_value_get_astring(mv, mpvbuf,
17157                     max_scf_value_len + 1) < 0) {
17158                         uu_warn(gettext("Unable to get the manifest "
17159                             "file : %s\n"),
17160                             scf_strerror(scf_error()));
17161 
17162                         switch (scf_error()) {
17163                         case SCF_ERROR_DELETED:
17164                         case SCF_ERROR_CONNECTION_BROKEN:
17165                                 r = scferror2errno(scf_error());
17166                                 goto out_free;
17167 
17168                         case SCF_ERROR_HANDLE_MISMATCH:
17169                         case SCF_ERROR_NOT_BOUND:
17170                         case SCF_ERROR_NOT_SET:
17171                         default:
17172                                 bad_error("scf_value_get_astring",
17173                                     scf_error());
17174                         }
17175                 }
17176 
17177                 mpvarry[mfstcnt] = mpntov;
17178                 mfstcnt++;
17179 
17180                 /*
17181                  * Check for the need to reallocate array
17182                  */
17183                 if (mfstcnt >= (mfstmax - 1)) {
17184                         struct mpg_mfile **newmpvarry;
17185 
17186                         mfstmax = mfstmax * 2;
17187                         newmpvarry = realloc(mpvarry,
17188                             sizeof (struct mpg_mfile *) * mfstmax);
17189 
17190                         if (newmpvarry == NULL)
17191                                 goto out_free;
17192 
17193                         mpvarry = newmpvarry;
17194                 }
17195 
17196                 mpvarry[mfstcnt] = NULL;
17197         }
17198 
17199         for (index = 0; mpvarry[index]; index++) {
17200                 mpntov = mpvarry[index];
17201 
17202                 /*
17203                  * Check to see if the manifestfile is accessable, if so hand
17204                  * this service and manifestfile off to be processed for
17205                  * instance support.
17206                  */
17207                 mpnbuf = mpntov->mpg;
17208                 mpvbuf = mpntov->mfile;
17209                 if (access(mpvbuf, F_OK) != 0) {
17210                         mpntov->access = 0;
17211                         activity++;
17212                         mfstcnt--;
17213                         /* Remove the entry from the service */
17214                         cur_svc = svc;
17215                         pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17216                             mpnbuf);
17217                         if (pgpropbuf == NULL)
17218                                 uu_die(gettext("Out of memory.\n"));
17219 
17220                         lscf_delprop(pgpropbuf);
17221                         cur_svc = NULL;
17222 
17223                         uu_free(pgpropbuf);
17224                 }
17225         }
17226 
17227         /*
17228          * If mfstcnt is 0, none of the manifests that supported the service
17229          * existed so remove the service.
17230          */
17231         if (mfstcnt == 0) {
17232                 teardown_service(svc, wip->fmri);
17233 
17234                 goto out_free;
17235         }
17236 
17237         if (activity) {
17238                 int     nosvcsupport = 0;
17239 
17240                 /*
17241                  * If the list of service instances is NULL then
17242                  * create the list.
17243                  */
17244                 instances = create_instance_list(svc, 1);
17245                 if (instances == NULL) {
17246                         uu_warn(gettext("Unable to create instance list %s\n"),
17247                             wip->fmri);
17248                         goto out_free;
17249                 }
17250 
17251                 rminstct = uu_list_numnodes(instances);
17252                 instct = rminstct;
17253 
17254                 for (index = 0; mpvarry[index]; index++) {
17255                         mpntov = mpvarry[index];
17256                         if (mpntov->access == 0)
17257                                 continue;
17258 
17259                         mpnbuf = mpntov->mpg;
17260                         mpvbuf = mpntov->mfile;
17261                         r = check_instance_support(mpvbuf, wip->fmri,
17262                             instances);
17263                         if (r == -1) {
17264                                 nosvcsupport++;
17265                         } else {
17266                                 rminstct -= r;
17267                         }
17268                 }
17269 
17270                 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17271                         teardown_service(svc, wip->fmri);
17272 
17273                         goto out_free;
17274                 }
17275         }
17276 
17277         /*
17278          * If there are instances left on the instance list, then
17279          * we must remove them.
17280          */
17281         if (instances != NULL && uu_list_numnodes(instances)) {
17282                 string_list_t *sp;
17283 
17284                 insts = uu_list_walk_start(instances, 0);
17285                 while ((sp = uu_list_walk_next(insts)) != NULL) {
17286                         /*
17287                          * Remove the instance from the instances list.
17288                          */
17289                         safe_printf(gettext("Delete instance %s from "
17290                             "service %s\n"), sp->str, wip->fmri);
17291                         if (scf_service_get_instance(svc, sp->str,
17292                             instance) != SCF_SUCCESS) {
17293                                 (void) uu_warn("scf_error - %s\n",
17294                                     scf_strerror(scf_error()));
17295 
17296                                 continue;
17297                         }
17298 
17299                         (void) disable_instance(instance);
17300 
17301                         (void) lscf_instance_delete(instance, 1);
17302                 }
17303                 scf_instance_destroy(instance);
17304                 uu_list_walk_end(insts);
17305         }
17306 
17307 out_free:
17308         if (mpvarry) {
17309                 struct mpg_mfile *fmpntov;
17310 
17311                 for (index = 0; mpvarry[index]; index++) {
17312                         fmpntov  = mpvarry[index];
17313                         if (fmpntov->mpg == mpnbuf)
17314                                 mpnbuf = NULL;
17315                         free(fmpntov->mpg);
17316 
17317                         if (fmpntov->mfile == mpvbuf)
17318                                 mpvbuf = NULL;
17319                         free(fmpntov->mfile);
17320 
17321                         if (fmpntov == mpntov)
17322                                 mpntov = NULL;
17323                         free(fmpntov);
17324                 }
17325                 if (mpnbuf)
17326                         free(mpnbuf);
17327                 if (mpvbuf)
17328                         free(mpvbuf);
17329                 if (mpntov)
17330                         free(mpntov);
17331 
17332                 free(mpvarry);
17333         }
17334 out:
17335         scf_pg_destroy(mpg);
17336         scf_property_destroy(mp);
17337         scf_iter_destroy(mi);
17338         scf_value_destroy(mv);
17339 
17340         return (0);
17341 }
17342 
17343 /*
17344  * Take the service and search for the manifestfiles property
17345  * in each of the property groups.  If the manifest file
17346  * associated with the property does not exist then remove
17347  * the property group.
17348  */
17349 int
17350 lscf_hash_cleanup()
17351 {
17352         scf_service_t           *svc;
17353         scf_scope_t             *scope;
17354         scf_propertygroup_t     *pg;
17355         scf_property_t          *prop;
17356         scf_value_t             *val;
17357         scf_iter_t              *iter;
17358         char                    *pgname = NULL;
17359         char                    *mfile = NULL;
17360         int                     r;
17361 
17362         svc = scf_service_create(g_hndl);
17363         scope = scf_scope_create(g_hndl);
17364         pg = scf_pg_create(g_hndl);
17365         prop = scf_property_create(g_hndl);
17366         val = scf_value_create(g_hndl);
17367         iter = scf_iter_create(g_hndl);
17368         if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17369             svc == NULL || scope == NULL) {
17370                 uu_warn(gettext("Unable to create a property group, or "
17371                     "property\n"));
17372                 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17373                     "pg is not NULL");
17374                 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17375                     "prop is not NULL");
17376                 uu_warn("%s\n", val == NULL ? "val is NULL" :
17377                     "val is not NULL");
17378                 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17379                     "iter is not NULL");
17380                 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17381                     "svc is not NULL");
17382                 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17383                     "scope is not NULL");
17384                 uu_warn(gettext("scf error is : %s\n"),
17385                     scf_strerror(scf_error()));
17386                 scfdie();
17387         }
17388 
17389         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17390                 switch (scf_error()) {
17391                 case SCF_ERROR_CONNECTION_BROKEN:
17392                 case SCF_ERROR_NOT_FOUND:
17393                         goto out;
17394 
17395                 case SCF_ERROR_HANDLE_MISMATCH:
17396                 case SCF_ERROR_NOT_BOUND:
17397                 case SCF_ERROR_INVALID_ARGUMENT:
17398                 default:
17399                         bad_error("scf_handle_get_scope", scf_error());
17400                 }
17401         }
17402 
17403         if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17404                 uu_warn(gettext("Unable to process the hash service, %s\n"),
17405                     HASH_SVC);
17406                 goto out;
17407         }
17408 
17409         pgname = safe_malloc(max_scf_name_len + 1);
17410         mfile = safe_malloc(max_scf_value_len + 1);
17411 
17412         if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17413                 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17414                     scf_strerror(scf_error()));
17415                 goto out;
17416         }
17417 
17418         while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17419                 if (r == -1)
17420                         goto out;
17421 
17422                 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17423                         switch (scf_error()) {
17424                         case SCF_ERROR_DELETED:
17425                                 return (ENODEV);
17426 
17427                         case SCF_ERROR_CONNECTION_BROKEN:
17428                                 return (ECONNABORTED);
17429 
17430                         case SCF_ERROR_NOT_SET:
17431                         case SCF_ERROR_NOT_BOUND:
17432                         default:
17433                                 bad_error("scf_pg_get_name", scf_error());
17434                         }
17435                 }
17436                 if (IGNORE_VAR) {
17437                         if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17438                                 continue;
17439                 }
17440 
17441                 /*
17442                  * If unable to get the property continue as this is an
17443                  * entry that has no location to check against.
17444                  */
17445                 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17446                         continue;
17447                 }
17448 
17449                 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17450                         uu_warn(gettext("Unable to get value from %s\n"),
17451                             pgname);
17452 
17453                         switch (scf_error()) {
17454                         case SCF_ERROR_DELETED:
17455                         case SCF_ERROR_CONSTRAINT_VIOLATED:
17456                         case SCF_ERROR_NOT_FOUND:
17457                         case SCF_ERROR_NOT_SET:
17458                                 continue;
17459 
17460                         case SCF_ERROR_CONNECTION_BROKEN:
17461                                 r = scferror2errno(scf_error());
17462                                 goto out;
17463 
17464                         case SCF_ERROR_HANDLE_MISMATCH:
17465                         case SCF_ERROR_NOT_BOUND:
17466                         default:
17467                                 bad_error("scf_property_get_value",
17468                                     scf_error());
17469                         }
17470                 }
17471 
17472                 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17473                     == -1) {
17474                         uu_warn(gettext("Unable to get astring from %s : %s\n"),
17475                             pgname, scf_strerror(scf_error()));
17476 
17477                         switch (scf_error()) {
17478                         case SCF_ERROR_NOT_SET:
17479                         case SCF_ERROR_TYPE_MISMATCH:
17480                                 continue;
17481 
17482                         default:
17483                                 bad_error("scf_value_get_astring", scf_error());
17484                         }
17485                 }
17486 
17487                 if (access(mfile, F_OK) == 0)
17488                         continue;
17489 
17490                 (void) scf_pg_delete(pg);
17491         }
17492 
17493 out:
17494         scf_scope_destroy(scope);
17495         scf_service_destroy(svc);
17496         scf_pg_destroy(pg);
17497         scf_property_destroy(prop);
17498         scf_value_destroy(val);
17499         scf_iter_destroy(iter);
17500         free(pgname);
17501         free(mfile);
17502 
17503         return (0);
17504 }
17505 
17506 #ifndef NATIVE_BUILD
17507 /* ARGSUSED */
17508 CPL_MATCH_FN(complete_select)
17509 {
17510         const char *arg0, *arg1, *arg1end;
17511         int word_start, err = 0, r;
17512         size_t len;
17513         char *buf;
17514 
17515         lscf_prep_hndl();
17516 
17517         arg0 = line + strspn(line, " \t");
17518         assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17519 
17520         arg1 = arg0 + sizeof ("select") - 1;
17521         arg1 += strspn(arg1, " \t");
17522         word_start = arg1 - line;
17523 
17524         arg1end = arg1 + strcspn(arg1, " \t");
17525         if (arg1end < line + word_end)
17526                 return (0);
17527 
17528         len = line + word_end - arg1;
17529 
17530         buf = safe_malloc(max_scf_name_len + 1);
17531 
17532         if (cur_snap != NULL) {
17533                 return (0);
17534         } else if (cur_inst != NULL) {
17535                 return (0);
17536         } else if (cur_svc != NULL) {
17537                 scf_instance_t *inst;
17538                 scf_iter_t *iter;
17539 
17540                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17541                     (iter = scf_iter_create(g_hndl)) == NULL)
17542                         scfdie();
17543 
17544                 if (scf_iter_service_instances(iter, cur_svc) != 0)
17545                         scfdie();
17546 
17547                 for (;;) {
17548                         r = scf_iter_next_instance(iter, inst);
17549                         if (r == 0)
17550                                 break;
17551                         if (r != 1)
17552                                 scfdie();
17553 
17554                         if (scf_instance_get_name(inst, buf,
17555                             max_scf_name_len + 1) < 0)
17556                                 scfdie();
17557 
17558                         if (strncmp(buf, arg1, len) == 0) {
17559                                 err = cpl_add_completion(cpl, line, word_start,
17560                                     word_end, buf + len, "", " ");
17561                                 if (err != 0)
17562                                         break;
17563                         }
17564                 }
17565 
17566                 scf_iter_destroy(iter);
17567                 scf_instance_destroy(inst);
17568 
17569                 return (err);
17570         } else {
17571                 scf_service_t *svc;
17572                 scf_iter_t *iter;
17573 
17574                 assert(cur_scope != NULL);
17575 
17576                 if ((svc = scf_service_create(g_hndl)) == NULL ||
17577                     (iter = scf_iter_create(g_hndl)) == NULL)
17578                         scfdie();
17579 
17580                 if (scf_iter_scope_services(iter, cur_scope) != 0)
17581                         scfdie();
17582 
17583                 for (;;) {
17584                         r = scf_iter_next_service(iter, svc);
17585                         if (r == 0)
17586                                 break;
17587                         if (r != 1)
17588                                 scfdie();
17589 
17590                         if (scf_service_get_name(svc, buf,
17591                             max_scf_name_len + 1) < 0)
17592                                 scfdie();
17593 
17594                         if (strncmp(buf, arg1, len) == 0) {
17595                                 err = cpl_add_completion(cpl, line, word_start,
17596                                     word_end, buf + len, "", " ");
17597                                 if (err != 0)
17598                                         break;
17599                         }
17600                 }
17601 
17602                 scf_iter_destroy(iter);
17603                 scf_service_destroy(svc);
17604 
17605                 return (err);
17606         }
17607 }
17608 
17609 /* ARGSUSED */
17610 CPL_MATCH_FN(complete_command)
17611 {
17612         uint32_t scope = 0;
17613 
17614         if (cur_snap != NULL)
17615                 scope = CS_SNAP;
17616         else if (cur_inst != NULL)
17617                 scope = CS_INST;
17618         else if (cur_svc != NULL)
17619                 scope = CS_SVC;
17620         else
17621                 scope = CS_SCOPE;
17622 
17623         return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17624 }
17625 #endif  /* NATIVE_BUILD */