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