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 2012 Milan Jurik. All rights reserved.
  25  */
  26 
  27 
  28 #include <alloca.h>
  29 #include <assert.h>
  30 #include <ctype.h>
  31 #include <door.h>
  32 #include <errno.h>
  33 #include <fcntl.h>
  34 #include <fnmatch.h>
  35 #include <inttypes.h>
  36 #include <libintl.h>
  37 #include <libnvpair.h>
  38 #include <libscf.h>
  39 #include <libscf_priv.h>
  40 #include <libtecla.h>
  41 #include <libuutil.h>
  42 #include <limits.h>
  43 #include <locale.h>
  44 #include <stdarg.h>
  45 #include <string.h>
  46 #include <strings.h>
  47 #include <unistd.h>
  48 #include <wait.h>
  49 #include <poll.h>
  50 
  51 #include <libxml/tree.h>
  52 
  53 #include <sys/param.h>
  54 
  55 #include <sys/stat.h>
  56 #include <sys/mman.h>
  57 
  58 #include "svccfg.h"
  59 #include "notify_params.h"
  60 #include "manifest_hash.h"
  61 #include "manifest_find.h"
  62 
  63 /* The colon namespaces in each entity (each followed by a newline). */
  64 #define COLON_NAMESPACES        ":properties\n"
  65 
  66 #define TEMP_FILE_PATTERN       "/tmp/svccfg-XXXXXX"
  67 
  68 /* These are characters which the lexer requires to be in double-quotes. */
  69 #define CHARS_TO_QUOTE          " \t\n\\>=\"()"
  70 
  71 #define HASH_SIZE               16
  72 #define HASH_PG_TYPE            "framework"
  73 #define HASH_PG_FLAGS           0
  74 #define HASH_PROP               "md5sum"
  75 
  76 /*
  77  * Indentation used in the output of the describe subcommand.
  78  */
  79 #define TMPL_VALUE_INDENT       "  "
  80 #define TMPL_INDENT             "    "
  81 #define TMPL_INDENT_2X          "        "
  82 #define TMPL_CHOICE_INDENT      "      "
  83 
  84 /*
  85  * Directory locations for manifests
  86  */
  87 #define VARSVC_DIR              "/var/svc/manifest"
  88 #define LIBSVC_DIR              "/lib/svc/manifest"
  89 #define VARSVC_PR               "var_svc_manifest"
  90 #define LIBSVC_PR               "lib_svc_manifest"
  91 #define MFSTFILEPR              "manifestfile"
  92 
  93 #define SUPPORTPROP             "support"
  94 
  95 #define MFSTHISTFILE            "/lib/svc/share/mfsthistory"
  96 
  97 #define MFSTFILE_MAX            16
  98 
  99 /*
 100  * These are the classes of elements which may appear as children of service
 101  * or instance elements in XML manifests.
 102  */
 103 struct entity_elts {
 104         xmlNodePtr      create_default_instance;
 105         xmlNodePtr      single_instance;
 106         xmlNodePtr      restarter;
 107         xmlNodePtr      dependencies;
 108         xmlNodePtr      dependents;
 109         xmlNodePtr      method_context;
 110         xmlNodePtr      exec_methods;
 111         xmlNodePtr      notify_params;
 112         xmlNodePtr      property_groups;
 113         xmlNodePtr      instances;
 114         xmlNodePtr      stability;
 115         xmlNodePtr      template;
 116 };
 117 
 118 /*
 119  * Likewise for property_group elements.
 120  */
 121 struct pg_elts {
 122         xmlNodePtr      stability;
 123         xmlNodePtr      propvals;
 124         xmlNodePtr      properties;
 125 };
 126 
 127 /*
 128  * Likewise for template elements.
 129  */
 130 struct template_elts {
 131         xmlNodePtr      common_name;
 132         xmlNodePtr      description;
 133         xmlNodePtr      documentation;
 134 };
 135 
 136 /*
 137  * Likewise for type (for notification parameters) elements.
 138  */
 139 struct params_elts {
 140         xmlNodePtr      paramval;
 141         xmlNodePtr      parameter;
 142 };
 143 
 144 /*
 145  * This structure is for snaplevel lists.  They are convenient because libscf
 146  * only allows traversing snaplevels in one direction.
 147  */
 148 struct snaplevel {
 149         uu_list_node_t  list_node;
 150         scf_snaplevel_t *sl;
 151 };
 152 
 153 /*
 154  * This is used for communication between lscf_service_export and
 155  * export_callback.
 156  */
 157 struct export_args {
 158         const char      *filename;
 159         int             flags;
 160 };
 161 
 162 /*
 163  * The service_manifest structure is used by the upgrade process
 164  * to create a list of service to manifest linkages from the manifests
 165  * in a set of given directories.
 166  */
 167 typedef struct service_manifest {
 168         const char      *servicename;
 169         uu_list_t       *mfstlist;
 170         size_t  mfstlist_sz;
 171 
 172         uu_avl_node_t   svcmfst_node;
 173 } service_manifest_t;
 174 
 175 /*
 176  * Structure to track the manifest file property group
 177  * and the manifest file associated with that property
 178  * group.  Also, a flag to keep the access once it has
 179  * been checked.
 180  */
 181 struct mpg_mfile {
 182         char    *mpg;
 183         char    *mfile;
 184         int     access;
 185 };
 186 
 187 const char * const scf_pg_general = SCF_PG_GENERAL;
 188 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
 189 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
 190 const char * const scf_property_external = "external";
 191 
 192 const char * const snap_initial = "initial";
 193 const char * const snap_lastimport = "last-import";
 194 const char * const snap_previous = "previous";
 195 const char * const snap_running = "running";
 196 
 197 scf_handle_t *g_hndl = NULL;    /* only valid after lscf_prep_hndl() */
 198 
 199 ssize_t max_scf_fmri_len;
 200 ssize_t max_scf_name_len;
 201 ssize_t max_scf_pg_type_len;
 202 ssize_t max_scf_value_len;
 203 static size_t max_scf_len;
 204 
 205 static scf_scope_t *cur_scope;
 206 static scf_service_t *cur_svc = NULL;
 207 static scf_instance_t *cur_inst = NULL;
 208 static scf_snapshot_t *cur_snap = NULL;
 209 static scf_snaplevel_t *cur_level = NULL;
 210 
 211 static uu_list_pool_t *snaplevel_pool;
 212 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
 213 static uu_list_t *cur_levels;
 214 static struct snaplevel *cur_elt;               /* cur_elt->sl == cur_level */
 215 
 216 static FILE *tempfile = NULL;
 217 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
 218 
 219 static const char *emsg_entity_not_selected;
 220 static const char *emsg_permission_denied;
 221 static const char *emsg_create_xml;
 222 static const char *emsg_cant_modify_snapshots;
 223 static const char *emsg_invalid_for_snapshot;
 224 static const char *emsg_read_only;
 225 static const char *emsg_deleted;
 226 static const char *emsg_invalid_pg_name;
 227 static const char *emsg_invalid_prop_name;
 228 static const char *emsg_no_such_pg;
 229 static const char *emsg_fmri_invalid_pg_name;
 230 static const char *emsg_fmri_invalid_pg_name_type;
 231 static const char *emsg_pg_added;
 232 static const char *emsg_pg_changed;
 233 static const char *emsg_pg_deleted;
 234 static const char *emsg_pg_mod_perm;
 235 static const char *emsg_pg_add_perm;
 236 static const char *emsg_pg_del_perm;
 237 static const char *emsg_snap_perm;
 238 static const char *emsg_dpt_dangling;
 239 static const char *emsg_dpt_no_dep;
 240 
 241 static int li_only = 0;
 242 static int no_refresh = 0;
 243 
 244 /* import globals, to minimize allocations */
 245 static scf_scope_t *imp_scope = NULL;
 246 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
 247 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
 248 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
 249 static scf_snapshot_t *imp_rsnap = NULL;
 250 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
 251 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
 252 static scf_property_t *imp_prop = NULL;
 253 static scf_iter_t *imp_iter = NULL;
 254 static scf_iter_t *imp_rpg_iter = NULL;
 255 static scf_iter_t *imp_up_iter = NULL;
 256 static scf_transaction_t *imp_tx = NULL;        /* always reset this */
 257 static char *imp_str = NULL;
 258 static size_t imp_str_sz;
 259 static char *imp_tsname = NULL;
 260 static char *imp_fe1 = NULL;            /* for fmri_equal() */
 261 static char *imp_fe2 = NULL;
 262 static uu_list_t *imp_deleted_dpts = NULL;      /* pgroup_t's to refresh */
 263 
 264 /* upgrade_dependents() globals */
 265 static scf_instance_t *ud_inst = NULL;
 266 static scf_snaplevel_t *ud_snpl = NULL;
 267 static scf_propertygroup_t *ud_pg = NULL;
 268 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
 269 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
 270 static int ud_run_dpts_pg_set = 0;
 271 static scf_property_t *ud_prop = NULL;
 272 static scf_property_t *ud_dpt_prop = NULL;
 273 static scf_value_t *ud_val = NULL;
 274 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
 275 static scf_transaction_t *ud_tx = NULL;
 276 static char *ud_ctarg = NULL;
 277 static char *ud_oldtarg = NULL;
 278 static char *ud_name = NULL;
 279 
 280 /* export globals */
 281 static scf_instance_t *exp_inst;
 282 static scf_propertygroup_t *exp_pg;
 283 static scf_property_t *exp_prop;
 284 static scf_value_t *exp_val;
 285 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
 286 static char *exp_str;
 287 static size_t exp_str_sz;
 288 
 289 /* cleanup globals */
 290 static uu_avl_pool_t *service_manifest_pool = NULL;
 291 static uu_avl_t *service_manifest_tree = NULL;
 292 
 293 static void scfdie_lineno(int lineno) __NORETURN;
 294 
 295 static char *start_method_names[] = {
 296         "start",
 297         "inetd_start",
 298         NULL
 299 };
 300 
 301 static struct uri_scheme {
 302         const char *scheme;
 303         const char *protocol;
 304 } uri_scheme[] = {
 305         { "mailto", "smtp" },
 306         { "snmp", "snmp" },
 307         { "syslog", "syslog" },
 308         { NULL, NULL }
 309 };
 310 #define URI_SCHEME_NUM ((sizeof (uri_scheme) / \
 311     sizeof (struct uri_scheme)) - 1)
 312 
 313 static int
 314 check_uri_scheme(const char *scheme)
 315 {
 316         int i;
 317 
 318         for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
 319                 if (strcmp(scheme, uri_scheme[i].scheme) == 0)
 320                         return (i);
 321         }
 322 
 323         return (-1);
 324 }
 325 
 326 static int
 327 check_uri_protocol(const char *p)
 328 {
 329         int i;
 330 
 331         for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
 332                 if (strcmp(p, uri_scheme[i].protocol) == 0)
 333                         return (i);
 334         }
 335 
 336         return (-1);
 337 }
 338 
 339 /*
 340  * For unexpected libscf errors.
 341  */
 342 #ifdef NDEBUG
 343 
 344 static void scfdie(void) __NORETURN;
 345 
 346 static void
 347 scfdie(void)
 348 {
 349         scf_error_t err = scf_error();
 350 
 351         if (err == SCF_ERROR_CONNECTION_BROKEN)
 352                 uu_die(gettext("Repository connection broken.  Exiting.\n"));
 353 
 354         uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
 355             scf_strerror(err));
 356 }
 357 
 358 #else
 359 
 360 #define scfdie()        scfdie_lineno(__LINE__)
 361 
 362 static void
 363 scfdie_lineno(int lineno)
 364 {
 365         scf_error_t err = scf_error();
 366 
 367         if (err == SCF_ERROR_CONNECTION_BROKEN)
 368                 uu_die(gettext("Repository connection broken.  Exiting.\n"));
 369 
 370         uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
 371             ": %s.\n"), lineno, scf_strerror(err));
 372 }
 373 
 374 #endif
 375 
 376 static void
 377 scfwarn(void)
 378 {
 379         warn(gettext("Unexpected libscf error: %s.\n"),
 380             scf_strerror(scf_error()));
 381 }
 382 
 383 /*
 384  * Clear a field of a structure.
 385  */
 386 static int
 387 clear_int(void *a, void *b)
 388 {
 389         /* LINTED */
 390         *(int *)((char *)a + (size_t)b) = 0;
 391 
 392         return (UU_WALK_NEXT);
 393 }
 394 
 395 static int
 396 scferror2errno(scf_error_t err)
 397 {
 398         switch (err) {
 399         case SCF_ERROR_BACKEND_ACCESS:
 400                 return (EACCES);
 401 
 402         case SCF_ERROR_BACKEND_READONLY:
 403                 return (EROFS);
 404 
 405         case SCF_ERROR_CONNECTION_BROKEN:
 406                 return (ECONNABORTED);
 407 
 408         case SCF_ERROR_CONSTRAINT_VIOLATED:
 409         case SCF_ERROR_INVALID_ARGUMENT:
 410                 return (EINVAL);
 411 
 412         case SCF_ERROR_DELETED:
 413                 return (ECANCELED);
 414 
 415         case SCF_ERROR_EXISTS:
 416                 return (EEXIST);
 417 
 418         case SCF_ERROR_NO_MEMORY:
 419                 return (ENOMEM);
 420 
 421         case SCF_ERROR_NO_RESOURCES:
 422                 return (ENOSPC);
 423 
 424         case SCF_ERROR_NOT_FOUND:
 425                 return (ENOENT);
 426 
 427         case SCF_ERROR_PERMISSION_DENIED:
 428                 return (EPERM);
 429 
 430         default:
 431 #ifndef NDEBUG
 432                 (void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
 433                     __FILE__, __LINE__, err);
 434 #else
 435                 (void) fprintf(stderr, "Unknown libscf error %d.\n", err);
 436 #endif
 437                 abort();
 438                 /* NOTREACHED */
 439         }
 440 }
 441 
 442 static int
 443 entity_get_pg(void *ent, int issvc, const char *name,
 444     scf_propertygroup_t *pg)
 445 {
 446         if (issvc)
 447                 return (scf_service_get_pg(ent, name, pg));
 448         else
 449                 return (scf_instance_get_pg(ent, name, pg));
 450 }
 451 
 452 static void
 453 entity_destroy(void *ent, int issvc)
 454 {
 455         if (issvc)
 456                 scf_service_destroy(ent);
 457         else
 458                 scf_instance_destroy(ent);
 459 }
 460 
 461 static int
 462 get_pg(const char *pg_name, scf_propertygroup_t *pg)
 463 {
 464         int ret;
 465 
 466         if (cur_level != NULL)
 467                 ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
 468         else if (cur_inst != NULL)
 469                 ret = scf_instance_get_pg(cur_inst, pg_name, pg);
 470         else
 471                 ret = scf_service_get_pg(cur_svc, pg_name, pg);
 472 
 473         return (ret);
 474 }
 475 
 476 /*
 477  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
 478  * snaplevel.  Otherwise find the instance snaplevel.
 479  *
 480  * Returns
 481  *   0 - success
 482  *   ECONNABORTED - repository connection broken
 483  *   ECANCELED - instance containing snap was deleted
 484  *   ENOENT - snap has no snaplevels
 485  *          - requested snaplevel not found
 486  */
 487 static int
 488 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
 489 {
 490         if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
 491                 switch (scf_error()) {
 492                 case SCF_ERROR_CONNECTION_BROKEN:
 493                 case SCF_ERROR_DELETED:
 494                 case SCF_ERROR_NOT_FOUND:
 495                         return (scferror2errno(scf_error()));
 496 
 497                 case SCF_ERROR_HANDLE_MISMATCH:
 498                 case SCF_ERROR_NOT_BOUND:
 499                 case SCF_ERROR_NOT_SET:
 500                 default:
 501                         bad_error("scf_snapshot_get_base_snaplevel",
 502                             scf_error());
 503                 }
 504         }
 505 
 506         for (;;) {
 507                 ssize_t ssz;
 508 
 509                 ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
 510                 if (ssz >= 0) {
 511                         if (!get_svc)
 512                                 return (0);
 513                 } else {
 514                         switch (scf_error()) {
 515                         case SCF_ERROR_CONSTRAINT_VIOLATED:
 516                                 if (get_svc)
 517                                         return (0);
 518                                 break;
 519 
 520                         case SCF_ERROR_DELETED:
 521                         case SCF_ERROR_CONNECTION_BROKEN:
 522                                 return (scferror2errno(scf_error()));
 523 
 524                         case SCF_ERROR_NOT_SET:
 525                         case SCF_ERROR_NOT_BOUND:
 526                         default:
 527                                 bad_error("scf_snaplevel_get_instance_name",
 528                                     scf_error());
 529                         }
 530                 }
 531 
 532                 if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
 533                         switch (scf_error()) {
 534                         case SCF_ERROR_NOT_FOUND:
 535                         case SCF_ERROR_CONNECTION_BROKEN:
 536                         case SCF_ERROR_DELETED:
 537                                 return (scferror2errno(scf_error()));
 538 
 539                         case SCF_ERROR_HANDLE_MISMATCH:
 540                         case SCF_ERROR_NOT_BOUND:
 541                         case SCF_ERROR_NOT_SET:
 542                         case SCF_ERROR_INVALID_ARGUMENT:
 543                         default:
 544                                 bad_error("scf_snaplevel_get_next_snaplevel",
 545                                     scf_error());
 546                         }
 547                 }
 548         }
 549 }
 550 
 551 /*
 552  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
 553  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
 554  * the property group named name in it.  If it doesn't have a running
 555  * snapshot, set pg to the instance's current property group named name.
 556  *
 557  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
 558  * its instances.  If one has a running snapshot with a service snaplevel, set
 559  * pg to the property group named name in it.  If no such snaplevel could be
 560  * found, set pg to the service's current property group named name.
 561  *
 562  * iter, inst, snap, and snpl are required scratch objects.
 563  *
 564  * Returns
 565  *   0 - success
 566  *   ECONNABORTED - repository connection broken
 567  *   ECANCELED - ent was deleted
 568  *   ENOENT - no such property group
 569  *   EINVAL - name is an invalid property group name
 570  *   EBADF - found running snapshot is missing a snaplevel
 571  */
 572 static int
 573 entity_get_running_pg(void *ent, int issvc, const char *name,
 574     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
 575     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
 576 {
 577         int r;
 578 
 579         if (issvc) {
 580                 /* Search for an instance with a running snapshot. */
 581                 if (scf_iter_service_instances(iter, ent) != 0) {
 582                         switch (scf_error()) {
 583                         case SCF_ERROR_DELETED:
 584                         case SCF_ERROR_CONNECTION_BROKEN:
 585                                 return (scferror2errno(scf_error()));
 586 
 587                         case SCF_ERROR_NOT_SET:
 588                         case SCF_ERROR_NOT_BOUND:
 589                         case SCF_ERROR_HANDLE_MISMATCH:
 590                         default:
 591                                 bad_error("scf_iter_service_instances",
 592                                     scf_error());
 593                         }
 594                 }
 595 
 596                 for (;;) {
 597                         r = scf_iter_next_instance(iter, inst);
 598                         if (r == 0) {
 599                                 if (scf_service_get_pg(ent, name, pg) == 0)
 600                                         return (0);
 601 
 602                                 switch (scf_error()) {
 603                                 case SCF_ERROR_DELETED:
 604                                 case SCF_ERROR_NOT_FOUND:
 605                                 case SCF_ERROR_INVALID_ARGUMENT:
 606                                 case SCF_ERROR_CONNECTION_BROKEN:
 607                                         return (scferror2errno(scf_error()));
 608 
 609                                 case SCF_ERROR_NOT_BOUND:
 610                                 case SCF_ERROR_HANDLE_MISMATCH:
 611                                 case SCF_ERROR_NOT_SET:
 612                                 default:
 613                                         bad_error("scf_service_get_pg",
 614                                             scf_error());
 615                                 }
 616                         }
 617                         if (r != 1) {
 618                                 switch (scf_error()) {
 619                                 case SCF_ERROR_DELETED:
 620                                 case SCF_ERROR_CONNECTION_BROKEN:
 621                                         return (scferror2errno(scf_error()));
 622 
 623                                 case SCF_ERROR_INVALID_ARGUMENT:
 624                                 case SCF_ERROR_NOT_SET:
 625                                 case SCF_ERROR_NOT_BOUND:
 626                                 case SCF_ERROR_HANDLE_MISMATCH:
 627                                 default:
 628                                         bad_error("scf_iter_next_instance",
 629                                             scf_error());
 630                                 }
 631                         }
 632 
 633                         if (scf_instance_get_snapshot(inst, snap_running,
 634                             snap) == 0)
 635                                 break;
 636 
 637                         switch (scf_error()) {
 638                         case SCF_ERROR_NOT_FOUND:
 639                         case SCF_ERROR_DELETED:
 640                                 continue;
 641 
 642                         case SCF_ERROR_CONNECTION_BROKEN:
 643                                 return (ECONNABORTED);
 644 
 645                         case SCF_ERROR_HANDLE_MISMATCH:
 646                         case SCF_ERROR_INVALID_ARGUMENT:
 647                         case SCF_ERROR_NOT_SET:
 648                         case SCF_ERROR_NOT_BOUND:
 649                         default:
 650                                 bad_error("scf_instance_get_snapshot",
 651                                     scf_error());
 652                         }
 653                 }
 654         } else {
 655                 if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
 656                         switch (scf_error()) {
 657                         case SCF_ERROR_NOT_FOUND:
 658                                 break;
 659 
 660                         case SCF_ERROR_DELETED:
 661                         case SCF_ERROR_CONNECTION_BROKEN:
 662                                 return (scferror2errno(scf_error()));
 663 
 664                         case SCF_ERROR_NOT_BOUND:
 665                         case SCF_ERROR_HANDLE_MISMATCH:
 666                         case SCF_ERROR_INVALID_ARGUMENT:
 667                         case SCF_ERROR_NOT_SET:
 668                         default:
 669                                 bad_error("scf_instance_get_snapshot",
 670                                     scf_error());
 671                         }
 672 
 673                         if (scf_instance_get_pg(ent, name, pg) == 0)
 674                                 return (0);
 675 
 676                         switch (scf_error()) {
 677                         case SCF_ERROR_DELETED:
 678                         case SCF_ERROR_NOT_FOUND:
 679                         case SCF_ERROR_INVALID_ARGUMENT:
 680                         case SCF_ERROR_CONNECTION_BROKEN:
 681                                 return (scferror2errno(scf_error()));
 682 
 683                         case SCF_ERROR_NOT_BOUND:
 684                         case SCF_ERROR_HANDLE_MISMATCH:
 685                         case SCF_ERROR_NOT_SET:
 686                         default:
 687                                 bad_error("scf_instance_get_pg", scf_error());
 688                         }
 689                 }
 690         }
 691 
 692         r = get_snaplevel(snap, issvc, snpl);
 693         switch (r) {
 694         case 0:
 695                 break;
 696 
 697         case ECONNABORTED:
 698         case ECANCELED:
 699                 return (r);
 700 
 701         case ENOENT:
 702                 return (EBADF);
 703 
 704         default:
 705                 bad_error("get_snaplevel", r);
 706         }
 707 
 708         if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
 709                 return (0);
 710 
 711         switch (scf_error()) {
 712         case SCF_ERROR_DELETED:
 713         case SCF_ERROR_INVALID_ARGUMENT:
 714         case SCF_ERROR_CONNECTION_BROKEN:
 715         case SCF_ERROR_NOT_FOUND:
 716                 return (scferror2errno(scf_error()));
 717 
 718         case SCF_ERROR_NOT_BOUND:
 719         case SCF_ERROR_HANDLE_MISMATCH:
 720         case SCF_ERROR_NOT_SET:
 721         default:
 722                 bad_error("scf_snaplevel_get_pg", scf_error());
 723                 /* NOTREACHED */
 724         }
 725 }
 726 
 727 /*
 728  * To be registered with atexit().
 729  */
 730 static void
 731 remove_tempfile(void)
 732 {
 733         int ret;
 734 
 735         if (tempfile != NULL) {
 736                 if (fclose(tempfile) == EOF)
 737                         (void) warn(gettext("Could not close temporary file"));
 738                 tempfile = NULL;
 739         }
 740 
 741         if (tempfilename[0] != '\0') {
 742                 do {
 743                         ret = remove(tempfilename);
 744                 } while (ret == -1 && errno == EINTR);
 745                 if (ret == -1)
 746                         warn(gettext("Could not remove temporary file"));
 747                 tempfilename[0] = '\0';
 748         }
 749 }
 750 
 751 /*
 752  * Launch private svc.configd(1M) for manipulating alternate repositories.
 753  */
 754 static void
 755 start_private_repository(engine_state_t *est)
 756 {
 757         int fd, stat;
 758         struct door_info info;
 759         pid_t pid;
 760 
 761         /*
 762          * 1.  Create a temporary file for the door.
 763          */
 764         if (est->sc_repo_doorname != NULL)
 765                 free((void *)est->sc_repo_doorname);
 766 
 767         est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
 768         if (est->sc_repo_doorname == NULL)
 769                 uu_die(gettext("Could not acquire temporary filename"));
 770 
 771         fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
 772         if (fd < 0)
 773                 uu_die(gettext("Could not create temporary file for "
 774                     "repository server"));
 775 
 776         (void) close(fd);
 777 
 778         /*
 779          * 2.  Launch a configd with that door, using the specified
 780          * repository.
 781          */
 782         if ((est->sc_repo_pid = fork()) == 0) {
 783                 (void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
 784                     "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
 785                     NULL);
 786                 uu_die(gettext("Could not execute %s"), est->sc_repo_server);
 787         } else if (est->sc_repo_pid == -1)
 788                 uu_die(gettext("Attempt to fork failed"));
 789 
 790         do {
 791                 pid = waitpid(est->sc_repo_pid, &stat, 0);
 792         } while (pid == -1 && errno == EINTR);
 793 
 794         if (pid == -1)
 795                 uu_die(gettext("Could not waitpid() for repository server"));
 796 
 797         if (!WIFEXITED(stat)) {
 798                 uu_die(gettext("Repository server failed (status %d).\n"),
 799                     stat);
 800         } else if (WEXITSTATUS(stat) != 0) {
 801                 uu_die(gettext("Repository server failed (exit %d).\n"),
 802                     WEXITSTATUS(stat));
 803         }
 804 
 805         /*
 806          * See if it was successful by checking if the door is a door.
 807          */
 808 
 809         fd = open(est->sc_repo_doorname, O_RDWR);
 810         if (fd < 0)
 811                 uu_die(gettext("Could not open door \"%s\""),
 812                     est->sc_repo_doorname);
 813 
 814         if (door_info(fd, &info) < 0)
 815                 uu_die(gettext("Unexpected door_info() error"));
 816 
 817         if (close(fd) == -1)
 818                 warn(gettext("Could not close repository door"),
 819                     strerror(errno));
 820 
 821         est->sc_repo_pid = info.di_target;
 822 }
 823 
 824 void
 825 lscf_cleanup(void)
 826 {
 827         /*
 828          * In the case where we've launched a private svc.configd(1M)
 829          * instance, we must terminate our child and remove the temporary
 830          * rendezvous point.
 831          */
 832         if (est->sc_repo_pid > 0) {
 833                 (void) kill(est->sc_repo_pid, SIGTERM);
 834                 (void) waitpid(est->sc_repo_pid, NULL, 0);
 835                 (void) unlink(est->sc_repo_doorname);
 836 
 837                 est->sc_repo_pid = 0;
 838         }
 839 }
 840 
 841 void
 842 unselect_cursnap(void)
 843 {
 844         void *cookie;
 845 
 846         cur_level = NULL;
 847 
 848         cookie = NULL;
 849         while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
 850                 scf_snaplevel_destroy(cur_elt->sl);
 851                 free(cur_elt);
 852         }
 853 
 854         scf_snapshot_destroy(cur_snap);
 855         cur_snap = NULL;
 856 }
 857 
 858 void
 859 lscf_prep_hndl(void)
 860 {
 861         if (g_hndl != NULL)
 862                 return;
 863 
 864         g_hndl = scf_handle_create(SCF_VERSION);
 865         if (g_hndl == NULL)
 866                 scfdie();
 867 
 868         if (est->sc_repo_filename != NULL)
 869                 start_private_repository(est);
 870 
 871         if (est->sc_repo_doorname != NULL) {
 872                 scf_value_t *repo_value;
 873                 int ret;
 874 
 875                 repo_value = scf_value_create(g_hndl);
 876                 if (repo_value == NULL)
 877                         scfdie();
 878 
 879                 ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
 880                 assert(ret == SCF_SUCCESS);
 881 
 882                 if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
 883                     SCF_SUCCESS)
 884                         scfdie();
 885 
 886                 scf_value_destroy(repo_value);
 887         }
 888 
 889         if (scf_handle_bind(g_hndl) != 0)
 890                 uu_die(gettext("Could not connect to repository server: %s.\n"),
 891                     scf_strerror(scf_error()));
 892 
 893         cur_scope = scf_scope_create(g_hndl);
 894         if (cur_scope == NULL)
 895                 scfdie();
 896 
 897         if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
 898                 scfdie();
 899 }
 900 
 901 static void
 902 repository_teardown(void)
 903 {
 904         if (g_hndl != NULL) {
 905                 if (cur_snap != NULL)
 906                         unselect_cursnap();
 907                 scf_instance_destroy(cur_inst);
 908                 scf_service_destroy(cur_svc);
 909                 scf_scope_destroy(cur_scope);
 910                 scf_handle_destroy(g_hndl);
 911                 cur_inst = NULL;
 912                 cur_svc = NULL;
 913                 cur_scope = NULL;
 914                 g_hndl = NULL;
 915                 lscf_cleanup();
 916         }
 917 }
 918 
 919 void
 920 lscf_set_repository(const char *repfile, int force)
 921 {
 922         repository_teardown();
 923 
 924         if (est->sc_repo_filename != NULL) {
 925                 free((void *)est->sc_repo_filename);
 926                 est->sc_repo_filename = NULL;
 927         }
 928 
 929         if ((force == 0) && (access(repfile, R_OK) != 0)) {
 930                 /*
 931                  * Repository file does not exist
 932                  * or has no read permission.
 933                  */
 934                 warn(gettext("Cannot access \"%s\": %s\n"),
 935                     repfile, strerror(errno));
 936         } else {
 937                 est->sc_repo_filename = safe_strdup(repfile);
 938         }
 939 
 940         lscf_prep_hndl();
 941 }
 942 
 943 void
 944 lscf_init()
 945 {
 946         if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
 947             (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
 948             (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
 949             0 ||
 950             (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
 951                 scfdie();
 952 
 953         max_scf_len = max_scf_fmri_len;
 954         if (max_scf_name_len > max_scf_len)
 955                 max_scf_len = max_scf_name_len;
 956         if (max_scf_pg_type_len > max_scf_len)
 957                 max_scf_len = max_scf_pg_type_len;
 958         /*
 959          * When a value of type opaque is represented as a string, the
 960          * string contains 2 characters for every byte of data.  That is
 961          * because the string contains the hex representation of the opaque
 962          * value.
 963          */
 964         if (2 * max_scf_value_len > max_scf_len)
 965                 max_scf_len = 2 * max_scf_value_len;
 966 
 967         if (atexit(remove_tempfile) != 0)
 968                 uu_die(gettext("Could not register atexit() function"));
 969 
 970         emsg_entity_not_selected = gettext("An entity is not selected.\n");
 971         emsg_permission_denied = gettext("Permission denied.\n");
 972         emsg_create_xml = gettext("Could not create XML node.\n");
 973         emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
 974         emsg_invalid_for_snapshot =
 975             gettext("Invalid operation on a snapshot.\n");
 976         emsg_read_only = gettext("Backend read-only.\n");
 977         emsg_deleted = gettext("Current selection has been deleted.\n");
 978         emsg_invalid_pg_name =
 979             gettext("Invalid property group name \"%s\".\n");
 980         emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
 981         emsg_no_such_pg = gettext("No such property group \"%s\".\n");
 982         emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
 983             "with invalid name \"%s\".\n");
 984         emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
 985             "group with invalid name \"%s\" or type \"%s\".\n");
 986         emsg_pg_added = gettext("%s changed unexpectedly "
 987             "(property group \"%s\" added).\n");
 988         emsg_pg_changed = gettext("%s changed unexpectedly "
 989             "(property group \"%s\" changed).\n");
 990         emsg_pg_deleted = gettext("%s changed unexpectedly "
 991             "(property group \"%s\" or an ancestor was deleted).\n");
 992         emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
 993             "in %s (permission denied).\n");
 994         emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
 995             "in %s (permission denied).\n");
 996         emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
 997             "in %s (permission denied).\n");
 998         emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
 999             "(permission denied).\n");
1000         emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1001             "new dependent \"%s\" because it already exists).  Warning: The "
1002             "current dependent's target (%s) does not exist.\n");
1003         emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1004             "dependent \"%s\" because it already exists).  Warning: The "
1005             "current dependent's target (%s) does not have a dependency named "
1006             "\"%s\" as expected.\n");
1007 
1008         string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1009             offsetof(string_list_t, node), NULL, 0);
1010         snaplevel_pool = uu_list_pool_create("snaplevels",
1011             sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1012             NULL, 0);
1013 }
1014 
1015 
1016 static const char *
1017 prop_to_typestr(const scf_property_t *prop)
1018 {
1019         scf_type_t ty;
1020 
1021         if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1022                 scfdie();
1023 
1024         return (scf_type_to_string(ty));
1025 }
1026 
1027 static scf_type_t
1028 string_to_type(const char *type)
1029 {
1030         size_t len = strlen(type);
1031         char *buf;
1032 
1033         if (len == 0 || type[len - 1] != ':')
1034                 return (SCF_TYPE_INVALID);
1035 
1036         buf = (char *)alloca(len + 1);
1037         (void) strlcpy(buf, type, len + 1);
1038         buf[len - 1] = 0;
1039 
1040         return (scf_string_to_type(buf));
1041 }
1042 
1043 static scf_value_t *
1044 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1045 {
1046         scf_value_t *v;
1047         char *dup, *nstr;
1048         size_t len;
1049 
1050         v = scf_value_create(g_hndl);
1051         if (v == NULL)
1052                 scfdie();
1053 
1054         len = strlen(str);
1055         if (require_quotes &&
1056             (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1057                 semerr(gettext("Multiple string values or string values "
1058                     "with spaces must be quoted with '\"'.\n"));
1059                 scf_value_destroy(v);
1060                 return (NULL);
1061         }
1062 
1063         nstr = dup = safe_strdup(str);
1064         if (dup[0] == '\"') {
1065                 /*
1066                  * Strip out the first and the last quote.
1067                  */
1068                 dup[len - 1] = '\0';
1069                 nstr = dup + 1;
1070         }
1071 
1072         if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1073                 assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1074                 semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1075                     scf_type_to_string(ty), nstr);
1076                 scf_value_destroy(v);
1077                 v = NULL;
1078         }
1079         free(dup);
1080         return (v);
1081 }
1082 
1083 /*
1084  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1085  * Optionally append a comment prefix ('#') to newlines ('\n').
1086  */
1087 static int
1088 quote_and_print(const char *str, FILE *strm, int commentnl)
1089 {
1090         const char *cp;
1091 
1092         for (cp = str; *cp != '\0'; ++cp) {
1093                 if (*cp == '"' || *cp == '\\')
1094                         (void) putc('\\', strm);
1095 
1096                 (void) putc(*cp, strm);
1097 
1098                 if (commentnl && *cp == '\n') {
1099                         (void) putc('#', strm);
1100                 }
1101         }
1102 
1103         return (ferror(strm));
1104 }
1105 
1106 /*
1107  * These wrappers around lowlevel functions provide consistent error checking
1108  * and warnings.
1109  */
1110 static int
1111 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1112 {
1113         if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1114                 return (0);
1115 
1116         if (scf_error() != SCF_ERROR_NOT_FOUND)
1117                 scfdie();
1118 
1119         if (g_verbose) {
1120                 ssize_t len;
1121                 char *fmri;
1122 
1123                 len = scf_pg_to_fmri(pg, NULL, 0);
1124                 if (len < 0)
1125                         scfdie();
1126 
1127                 fmri = safe_malloc(len + 1);
1128 
1129                 if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1130                         scfdie();
1131 
1132                 warn(gettext("Expected property %s of property group %s is "
1133                     "missing.\n"), propname, fmri);
1134 
1135                 free(fmri);
1136         }
1137 
1138         return (-1);
1139 }
1140 
1141 static int
1142 prop_check_type(scf_property_t *prop, scf_type_t ty)
1143 {
1144         scf_type_t pty;
1145 
1146         if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1147                 scfdie();
1148 
1149         if (ty == pty)
1150                 return (0);
1151 
1152         if (g_verbose) {
1153                 ssize_t len;
1154                 char *fmri;
1155                 const char *tystr;
1156 
1157                 len = scf_property_to_fmri(prop, NULL, 0);
1158                 if (len < 0)
1159                         scfdie();
1160 
1161                 fmri = safe_malloc(len + 1);
1162 
1163                 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1164                         scfdie();
1165 
1166                 tystr = scf_type_to_string(ty);
1167                 if (tystr == NULL)
1168                         tystr = "?";
1169 
1170                 warn(gettext("Property %s is not of expected type %s.\n"),
1171                     fmri, tystr);
1172 
1173                 free(fmri);
1174         }
1175 
1176         return (-1);
1177 }
1178 
1179 static int
1180 prop_get_val(scf_property_t *prop, scf_value_t *val)
1181 {
1182         scf_error_t err;
1183 
1184         if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1185                 return (0);
1186 
1187         err = scf_error();
1188 
1189         if (err != SCF_ERROR_NOT_FOUND &&
1190             err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1191             err != SCF_ERROR_PERMISSION_DENIED)
1192                 scfdie();
1193 
1194         if (g_verbose) {
1195                 ssize_t len;
1196                 char *fmri, *emsg;
1197 
1198                 len = scf_property_to_fmri(prop, NULL, 0);
1199                 if (len < 0)
1200                         scfdie();
1201 
1202                 fmri = safe_malloc(len + 1);
1203 
1204                 if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1205                         scfdie();
1206 
1207                 if (err == SCF_ERROR_NOT_FOUND)
1208                         emsg = gettext("Property %s has no values; expected "
1209                             "one.\n");
1210                 else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1211                         emsg = gettext("Property %s has multiple values; "
1212                             "expected one.\n");
1213                 else
1214                         emsg = gettext("No permission to read property %s.\n");
1215 
1216                 warn(emsg, fmri);
1217 
1218                 free(fmri);
1219         }
1220 
1221         return (-1);
1222 }
1223 
1224 
1225 static boolean_t
1226 snaplevel_is_instance(const scf_snaplevel_t *level)
1227 {
1228         if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1229                 if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1230                         scfdie();
1231                 return (0);
1232         } else {
1233                 return (1);
1234         }
1235 }
1236 
1237 /*
1238  * Decode FMRI into a service or instance, and put the result in *ep.  If
1239  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1240  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1241  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1242  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1243  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1244  * whether *ep is a service.
1245  */
1246 static scf_error_t
1247 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1248 {
1249         char *fmri_copy;
1250         const char *sstr, *istr, *pgstr;
1251         scf_service_t *svc;
1252         scf_instance_t *inst;
1253 
1254         fmri_copy = strdup(fmri);
1255         if (fmri_copy == NULL)
1256                 return (SCF_ERROR_NO_MEMORY);
1257 
1258         if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1259             SCF_SUCCESS) {
1260                 free(fmri_copy);
1261                 return (SCF_ERROR_INVALID_ARGUMENT);
1262         }
1263 
1264         free(fmri_copy);
1265 
1266         if (sstr == NULL || pgstr != NULL)
1267                 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1268 
1269         if (istr == NULL) {
1270                 svc = scf_service_create(h);
1271                 if (svc == NULL)
1272                         return (SCF_ERROR_NO_MEMORY);
1273 
1274                 if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1275                     SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1276                         if (scf_error() != SCF_ERROR_NOT_FOUND)
1277                                 scfdie();
1278 
1279                         return (SCF_ERROR_NOT_FOUND);
1280                 }
1281 
1282                 *ep = svc;
1283                 *isservice = 1;
1284         } else {
1285                 inst = scf_instance_create(h);
1286                 if (inst == NULL)
1287                         return (SCF_ERROR_NO_MEMORY);
1288 
1289                 if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1290                     NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1291                         if (scf_error() != SCF_ERROR_NOT_FOUND)
1292                                 scfdie();
1293 
1294                         return (SCF_ERROR_NOT_FOUND);
1295                 }
1296 
1297                 *ep = inst;
1298                 *isservice = 0;
1299         }
1300 
1301         return (SCF_ERROR_NONE);
1302 }
1303 
1304 /*
1305  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1306  * *ep, and set or clear *isservicep if it is a service or an instance.
1307  * Returns
1308  *   SCF_ERROR_NONE - success
1309  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1310  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1311  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1312  *   SCF_ERROR_NOT_FOUND - no such scope
1313  *   SCF_ERROR_PERMISSION_DENIED
1314  *   SCF_ERROR_BACKEND_READONLY
1315  *   SCF_ERROR_BACKEND_ACCESS
1316  */
1317 static scf_error_t
1318 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1319 {
1320         char *fmri_copy;
1321         const char *scstr, *sstr, *istr, *pgstr;
1322         scf_scope_t *scope = NULL;
1323         scf_service_t *svc = NULL;
1324         scf_instance_t *inst = NULL;
1325         scf_error_t scfe;
1326 
1327         fmri_copy = safe_strdup(fmri);
1328 
1329         if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1330             0) {
1331                 free(fmri_copy);
1332                 return (SCF_ERROR_INVALID_ARGUMENT);
1333         }
1334 
1335         if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1336                 free(fmri_copy);
1337                 return (SCF_ERROR_CONSTRAINT_VIOLATED);
1338         }
1339 
1340         *ep = NULL;
1341 
1342         if ((scope = scf_scope_create(h)) == NULL ||
1343             (svc = scf_service_create(h)) == NULL ||
1344             (inst = scf_instance_create(h)) == NULL) {
1345                 scfe = SCF_ERROR_NO_MEMORY;
1346                 goto out;
1347         }
1348 
1349 get_scope:
1350         if (scf_handle_get_scope(h, scstr, scope) != 0) {
1351                 switch (scf_error()) {
1352                 case SCF_ERROR_CONNECTION_BROKEN:
1353                         scfdie();
1354                         /* NOTREACHED */
1355 
1356                 case SCF_ERROR_NOT_FOUND:
1357                         scfe = SCF_ERROR_NOT_FOUND;
1358                         goto out;
1359 
1360                 case SCF_ERROR_HANDLE_MISMATCH:
1361                 case SCF_ERROR_NOT_BOUND:
1362                 case SCF_ERROR_INVALID_ARGUMENT:
1363                 default:
1364                         bad_error("scf_handle_get_scope", scf_error());
1365                 }
1366         }
1367 
1368 get_svc:
1369         if (scf_scope_get_service(scope, sstr, svc) != 0) {
1370                 switch (scf_error()) {
1371                 case SCF_ERROR_CONNECTION_BROKEN:
1372                         scfdie();
1373                         /* NOTREACHED */
1374 
1375                 case SCF_ERROR_DELETED:
1376                         goto get_scope;
1377 
1378                 case SCF_ERROR_NOT_FOUND:
1379                         break;
1380 
1381                 case SCF_ERROR_HANDLE_MISMATCH:
1382                 case SCF_ERROR_INVALID_ARGUMENT:
1383                 case SCF_ERROR_NOT_BOUND:
1384                 case SCF_ERROR_NOT_SET:
1385                 default:
1386                         bad_error("scf_scope_get_service", scf_error());
1387                 }
1388 
1389                 if (scf_scope_add_service(scope, sstr, svc) != 0) {
1390                         switch (scf_error()) {
1391                         case SCF_ERROR_CONNECTION_BROKEN:
1392                                 scfdie();
1393                                 /* NOTREACHED */
1394 
1395                         case SCF_ERROR_DELETED:
1396                                 goto get_scope;
1397 
1398                         case SCF_ERROR_PERMISSION_DENIED:
1399                         case SCF_ERROR_BACKEND_READONLY:
1400                         case SCF_ERROR_BACKEND_ACCESS:
1401                                 scfe = scf_error();
1402                                 goto out;
1403 
1404                         case SCF_ERROR_HANDLE_MISMATCH:
1405                         case SCF_ERROR_INVALID_ARGUMENT:
1406                         case SCF_ERROR_NOT_BOUND:
1407                         case SCF_ERROR_NOT_SET:
1408                         default:
1409                                 bad_error("scf_scope_get_service", scf_error());
1410                         }
1411                 }
1412         }
1413 
1414         if (istr == NULL) {
1415                 scfe = SCF_ERROR_NONE;
1416                 *ep = svc;
1417                 *isservicep = 1;
1418                 goto out;
1419         }
1420 
1421 get_inst:
1422         if (scf_service_get_instance(svc, istr, inst) != 0) {
1423                 switch (scf_error()) {
1424                 case SCF_ERROR_CONNECTION_BROKEN:
1425                         scfdie();
1426                         /* NOTREACHED */
1427 
1428                 case SCF_ERROR_DELETED:
1429                         goto get_svc;
1430 
1431                 case SCF_ERROR_NOT_FOUND:
1432                         break;
1433 
1434                 case SCF_ERROR_HANDLE_MISMATCH:
1435                 case SCF_ERROR_INVALID_ARGUMENT:
1436                 case SCF_ERROR_NOT_BOUND:
1437                 case SCF_ERROR_NOT_SET:
1438                 default:
1439                         bad_error("scf_service_get_instance", scf_error());
1440                 }
1441 
1442                 if (scf_service_add_instance(svc, istr, inst) != 0) {
1443                         switch (scf_error()) {
1444                         case SCF_ERROR_CONNECTION_BROKEN:
1445                                 scfdie();
1446                                 /* NOTREACHED */
1447 
1448                         case SCF_ERROR_DELETED:
1449                                 goto get_svc;
1450 
1451                         case SCF_ERROR_PERMISSION_DENIED:
1452                         case SCF_ERROR_BACKEND_READONLY:
1453                         case SCF_ERROR_BACKEND_ACCESS:
1454                                 scfe = scf_error();
1455                                 goto out;
1456 
1457                         case SCF_ERROR_HANDLE_MISMATCH:
1458                         case SCF_ERROR_INVALID_ARGUMENT:
1459                         case SCF_ERROR_NOT_BOUND:
1460                         case SCF_ERROR_NOT_SET:
1461                         default:
1462                                 bad_error("scf_service_add_instance",
1463                                     scf_error());
1464                         }
1465                 }
1466         }
1467 
1468         scfe = SCF_ERROR_NONE;
1469         *ep = inst;
1470         *isservicep = 0;
1471 
1472 out:
1473         if (*ep != inst)
1474                 scf_instance_destroy(inst);
1475         if (*ep != svc)
1476                 scf_service_destroy(svc);
1477         scf_scope_destroy(scope);
1478         free(fmri_copy);
1479         return (scfe);
1480 }
1481 
1482 /*
1483  * Create or update a snapshot of inst.  snap is a required scratch object.
1484  *
1485  * Returns
1486  *   0 - success
1487  *   ECONNABORTED - repository connection broken
1488  *   EPERM - permission denied
1489  *   ENOSPC - configd is out of resources
1490  *   ECANCELED - inst was deleted
1491  *   -1 - unknown libscf error (message printed)
1492  */
1493 static int
1494 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1495 {
1496 again:
1497         if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1498                 if (_scf_snapshot_take_attach(inst, snap) != 0) {
1499                         switch (scf_error()) {
1500                         case SCF_ERROR_CONNECTION_BROKEN:
1501                         case SCF_ERROR_PERMISSION_DENIED:
1502                         case SCF_ERROR_NO_RESOURCES:
1503                                 return (scferror2errno(scf_error()));
1504 
1505                         case SCF_ERROR_NOT_SET:
1506                         case SCF_ERROR_INVALID_ARGUMENT:
1507                         default:
1508                                 bad_error("_scf_snapshot_take_attach",
1509                                     scf_error());
1510                         }
1511                 }
1512         } else {
1513                 switch (scf_error()) {
1514                 case SCF_ERROR_NOT_FOUND:
1515                         break;
1516 
1517                 case SCF_ERROR_DELETED:
1518                 case SCF_ERROR_CONNECTION_BROKEN:
1519                         return (scferror2errno(scf_error()));
1520 
1521                 case SCF_ERROR_HANDLE_MISMATCH:
1522                 case SCF_ERROR_NOT_BOUND:
1523                 case SCF_ERROR_INVALID_ARGUMENT:
1524                 case SCF_ERROR_NOT_SET:
1525                 default:
1526                         bad_error("scf_instance_get_snapshot", scf_error());
1527                 }
1528 
1529                 if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1530                         switch (scf_error()) {
1531                         case SCF_ERROR_EXISTS:
1532                                 goto again;
1533 
1534                         case SCF_ERROR_CONNECTION_BROKEN:
1535                         case SCF_ERROR_NO_RESOURCES:
1536                         case SCF_ERROR_PERMISSION_DENIED:
1537                                 return (scferror2errno(scf_error()));
1538 
1539                         default:
1540                                 scfwarn();
1541                                 return (-1);
1542 
1543                         case SCF_ERROR_NOT_SET:
1544                         case SCF_ERROR_INTERNAL:
1545                         case SCF_ERROR_INVALID_ARGUMENT:
1546                         case SCF_ERROR_HANDLE_MISMATCH:
1547                                 bad_error("_scf_snapshot_take_new",
1548                                     scf_error());
1549                         }
1550                 }
1551         }
1552 
1553         return (0);
1554 }
1555 
1556 static int
1557 refresh_running_snapshot(void *entity)
1558 {
1559         scf_snapshot_t *snap;
1560         int r;
1561 
1562         if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1563                 scfdie();
1564         r = take_snap(entity, snap_running, snap);
1565         scf_snapshot_destroy(snap);
1566 
1567         return (r);
1568 }
1569 
1570 /*
1571  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1572  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1573  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1574  * for scratch space.  Returns
1575  *   0 - success
1576  *   ECONNABORTED - repository connection broken
1577  *   ECANCELED - entity was deleted
1578  *   EACCES - backend denied access
1579  *   EPERM - permission denied
1580  *   ENOSPC - repository server out of resources
1581  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1582  */
1583 static int
1584 refresh_entity(int isservice, void *entity, const char *fmri,
1585     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1586 {
1587         scf_error_t scfe;
1588         int r;
1589 
1590         if (!isservice) {
1591                 /*
1592                  * Let restarter handles refreshing and making new running
1593                  * snapshot only if operating on a live repository and not
1594                  * running in early import.
1595                  */
1596                 if (est->sc_repo_filename == NULL &&
1597                     est->sc_repo_doorname == NULL &&
1598                     est->sc_in_emi == 0) {
1599                         if (_smf_refresh_instance_i(entity) == 0) {
1600                                 if (g_verbose)
1601                                         warn(gettext("Refreshed %s.\n"), fmri);
1602                                 return (0);
1603                         }
1604 
1605                         switch (scf_error()) {
1606                         case SCF_ERROR_BACKEND_ACCESS:
1607                                 return (EACCES);
1608 
1609                         case SCF_ERROR_PERMISSION_DENIED:
1610                                 return (EPERM);
1611 
1612                         default:
1613                                 return (-1);
1614                         }
1615                 } else {
1616                         r = refresh_running_snapshot(entity);
1617                         switch (r) {
1618                         case 0:
1619                                 break;
1620 
1621                         case ECONNABORTED:
1622                         case ECANCELED:
1623                         case EPERM:
1624                         case ENOSPC:
1625                                 break;
1626 
1627                         default:
1628                                 bad_error("refresh_running_snapshot",
1629                                     scf_error());
1630                         }
1631 
1632                         return (r);
1633                 }
1634         }
1635 
1636         if (scf_iter_service_instances(iter, entity) != 0) {
1637                 switch (scf_error()) {
1638                 case SCF_ERROR_CONNECTION_BROKEN:
1639                         return (ECONNABORTED);
1640 
1641                 case SCF_ERROR_DELETED:
1642                         return (ECANCELED);
1643 
1644                 case SCF_ERROR_HANDLE_MISMATCH:
1645                 case SCF_ERROR_NOT_BOUND:
1646                 case SCF_ERROR_NOT_SET:
1647                 default:
1648                         bad_error("scf_iter_service_instances", scf_error());
1649                 }
1650         }
1651 
1652         for (;;) {
1653                 r = scf_iter_next_instance(iter, inst);
1654                 if (r == 0)
1655                         break;
1656                 if (r != 1) {
1657                         switch (scf_error()) {
1658                         case SCF_ERROR_CONNECTION_BROKEN:
1659                                 return (ECONNABORTED);
1660 
1661                         case SCF_ERROR_DELETED:
1662                                 return (ECANCELED);
1663 
1664                         case SCF_ERROR_HANDLE_MISMATCH:
1665                         case SCF_ERROR_NOT_BOUND:
1666                         case SCF_ERROR_NOT_SET:
1667                         case SCF_ERROR_INVALID_ARGUMENT:
1668                         default:
1669                                 bad_error("scf_iter_next_instance",
1670                                     scf_error());
1671                         }
1672                 }
1673 
1674                 /*
1675                  * Similarly, just take a new running snapshot if operating on
1676                  * a non-live repository or running during early import.
1677                  */
1678                 if (est->sc_repo_filename != NULL ||
1679                     est->sc_repo_doorname != NULL ||
1680                     est->sc_in_emi == 1) {
1681                         r = refresh_running_snapshot(inst);
1682                         switch (r) {
1683                         case 0:
1684                                 continue;
1685 
1686                         case ECONNABORTED:
1687                         case ECANCELED:
1688                         case EPERM:
1689                         case ENOSPC:
1690                                 break;
1691                         default:
1692                                 bad_error("refresh_running_snapshot",
1693                                     scf_error());
1694                         }
1695 
1696                         return (r);
1697 
1698                 }
1699 
1700                 if (_smf_refresh_instance_i(inst) == 0) {
1701                         if (g_verbose) {
1702                                 if (scf_instance_get_name(inst, name_buf,
1703                                     max_scf_name_len + 1) < 0)
1704                                         (void) strcpy(name_buf, "?");
1705 
1706                                 warn(gettext("Refreshed %s:%s.\n"),
1707                                     fmri, name_buf);
1708                         }
1709                 } else {
1710                         if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1711                             g_verbose) {
1712                                 scfe = scf_error();
1713 
1714                                 if (scf_instance_to_fmri(inst, name_buf,
1715                                     max_scf_name_len + 1) < 0)
1716                                         (void) strcpy(name_buf, "?");
1717 
1718                                 warn(gettext(
1719                                     "Refresh of %s:%s failed: %s.\n"), fmri,
1720                                     name_buf, scf_strerror(scfe));
1721                         }
1722                 }
1723         }
1724 
1725         return (0);
1726 }
1727 
1728 static void
1729 private_refresh(void)
1730 {
1731         scf_instance_t *pinst = NULL;
1732         scf_iter_t *piter = NULL;
1733         ssize_t fmrilen;
1734         size_t bufsz;
1735         char *fmribuf;
1736         void *ent;
1737         int issvc;
1738         int r;
1739 
1740         if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1741                 return;
1742 
1743         assert(cur_svc != NULL);
1744 
1745         bufsz = max_scf_fmri_len + 1;
1746         fmribuf = safe_malloc(bufsz);
1747         if (cur_inst) {
1748                 issvc = 0;
1749                 ent = cur_inst;
1750                 fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1751         } else {
1752                 issvc = 1;
1753                 ent = cur_svc;
1754                 fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1755                 if ((pinst = scf_instance_create(g_hndl)) == NULL)
1756                         scfdie();
1757 
1758                 if ((piter = scf_iter_create(g_hndl)) == NULL)
1759                         scfdie();
1760         }
1761         if (fmrilen < 0) {
1762                 free(fmribuf);
1763                 if (scf_error() != SCF_ERROR_DELETED)
1764                         scfdie();
1765 
1766                 warn(emsg_deleted);
1767                 return;
1768         }
1769         assert(fmrilen < bufsz);
1770 
1771         r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1772         switch (r) {
1773         case 0:
1774                 break;
1775 
1776         case ECONNABORTED:
1777                 warn(gettext("Could not refresh %s "
1778                     "(repository connection broken).\n"), fmribuf);
1779                 break;
1780 
1781         case ECANCELED:
1782                 warn(emsg_deleted);
1783                 break;
1784 
1785         case EPERM:
1786                 warn(gettext("Could not refresh %s "
1787                     "(permission denied).\n"), fmribuf);
1788                 break;
1789 
1790         case ENOSPC:
1791                 warn(gettext("Could not refresh %s "
1792                     "(repository server out of resources).\n"),
1793                     fmribuf);
1794                 break;
1795 
1796         case EACCES:
1797         default:
1798                 bad_error("refresh_entity", scf_error());
1799         }
1800 
1801         if (issvc) {
1802                 scf_instance_destroy(pinst);
1803                 scf_iter_destroy(piter);
1804         }
1805 
1806         free(fmribuf);
1807 }
1808 
1809 
1810 static int
1811 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1812 {
1813         cbp->sc_err = scferror2errno(err);
1814         return (UU_WALK_ERROR);
1815 }
1816 
1817 static int
1818 stash_scferror(scf_callback_t *cbp)
1819 {
1820         return (stash_scferror_err(cbp, scf_error()));
1821 }
1822 
1823 static int select_inst(const char *);
1824 static int select_svc(const char *);
1825 
1826 /*
1827  * Take a property that does not have a type and check to see if a type
1828  * exists or can be gleened from the current data.  Set the type.
1829  *
1830  * Check the current level (instance) and then check the higher level
1831  * (service).  This could be the case for adding a new property to
1832  * the instance that's going to "override" a service level property.
1833  *
1834  * For a property :
1835  * 1. Take the type from an existing property
1836  * 2. Take the type from a template entry
1837  *
1838  * If the type can not be found, then leave the type as is, and let the import
1839  * report the problem of the missing type.
1840  */
1841 static int
1842 find_current_prop_type(void *p, void *g)
1843 {
1844         property_t *prop = p;
1845         scf_callback_t *lcb = g;
1846         pgroup_t *pg = NULL;
1847 
1848         const char *fmri = NULL;
1849         char *lfmri = NULL;
1850         char *cur_selection = NULL;
1851 
1852         scf_propertygroup_t *sc_pg = NULL;
1853         scf_property_t *sc_prop = NULL;
1854         scf_pg_tmpl_t *t_pg = NULL;
1855         scf_prop_tmpl_t *t_prop = NULL;
1856         scf_type_t prop_type;
1857 
1858         value_t *vp;
1859         int issvc = lcb->sc_service;
1860         int r = UU_WALK_ERROR;
1861 
1862         if (prop->sc_value_type != SCF_TYPE_INVALID)
1863                 return (UU_WALK_NEXT);
1864 
1865         t_prop = scf_tmpl_prop_create(g_hndl);
1866         sc_prop = scf_property_create(g_hndl);
1867         if (sc_prop == NULL || t_prop == NULL) {
1868                 warn(gettext("Unable to create the property to attempt and "
1869                     "find a missing type.\n"));
1870 
1871                 scf_property_destroy(sc_prop);
1872                 scf_tmpl_prop_destroy(t_prop);
1873 
1874                 return (UU_WALK_ERROR);
1875         }
1876 
1877         if (lcb->sc_flags == 1) {
1878                 pg = lcb->sc_parent;
1879                 issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1880                 fmri = pg->sc_parent->sc_fmri;
1881 retry_pg:
1882                 if (cur_svc && cur_selection == NULL) {
1883                         cur_selection = safe_malloc(max_scf_fmri_len + 1);
1884                         lscf_get_selection_str(cur_selection,
1885                             max_scf_fmri_len + 1);
1886 
1887                         if (strcmp(cur_selection, fmri) != 0) {
1888                                 lscf_select(fmri);
1889                         } else {
1890                                 free(cur_selection);
1891                                 cur_selection = NULL;
1892                         }
1893                 } else {
1894                         lscf_select(fmri);
1895                 }
1896 
1897                 if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1898                         warn(gettext("Unable to create property group to "
1899                             "find a missing property type.\n"));
1900 
1901                         goto out;
1902                 }
1903 
1904                 if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1905                         /*
1906                          * If this is the sc_pg from the parent
1907                          * let the caller clean up the sc_pg,
1908                          * and just throw it away in this case.
1909                          */
1910                         if (sc_pg != lcb->sc_parent)
1911                                 scf_pg_destroy(sc_pg);
1912 
1913                         sc_pg = NULL;
1914                         if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1915                                 warn(gettext("Unable to create template "
1916                                     "property group to find a property "
1917                                     "type.\n"));
1918 
1919                                 goto out;
1920                         }
1921 
1922                         if (scf_tmpl_get_by_pg_name(fmri, NULL,
1923                             pg->sc_pgroup_name, NULL, t_pg,
1924                             SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1925                                 /*
1926                                  * if instance get service and jump back
1927                                  */
1928                                 scf_tmpl_pg_destroy(t_pg);
1929                                 t_pg = NULL;
1930                                 if (issvc == 0) {
1931                                         entity_t *e = pg->sc_parent->sc_parent;
1932 
1933                                         fmri = e->sc_fmri;
1934                                         issvc = 1;
1935                                         goto retry_pg;
1936                                 } else {
1937                                         goto out;
1938                                 }
1939                         }
1940                 }
1941         } else {
1942                 sc_pg = lcb->sc_parent;
1943         }
1944 
1945         /*
1946          * Attempt to get the type from an existing property.  If the property
1947          * cannot be found then attempt to get the type from a template entry
1948          * for the property.
1949          *
1950          * Finally, if at the instance level look at the service level.
1951          */
1952         if (sc_pg != NULL &&
1953             pg_get_prop(sc_pg, prop->sc_property_name,
1954             sc_prop) == SCF_SUCCESS &&
1955             scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1956                 prop->sc_value_type = prop_type;
1957 
1958                 /*
1959                  * Found a type, update the value types and validate
1960                  * the actual value against this type.
1961                  */
1962                 for (vp = uu_list_first(prop->sc_property_values);
1963                     vp != NULL;
1964                     vp = uu_list_next(prop->sc_property_values, vp)) {
1965                         vp->sc_type = prop->sc_value_type;
1966                         lxml_store_value(vp, 0, NULL);
1967                 }
1968 
1969                 r = UU_WALK_NEXT;
1970                 goto out;
1971         }
1972 
1973         /*
1974          * If we get here with t_pg set to NULL then we had to have
1975          * gotten an sc_pg but that sc_pg did not have the property
1976          * we are looking for.   So if the t_pg is not null look up
1977          * the template entry for the property.
1978          *
1979          * If the t_pg is null then need to attempt to get a matching
1980          * template entry for the sc_pg, and see if there is a property
1981          * entry for that template entry.
1982          */
1983 do_tmpl :
1984         if (t_pg != NULL &&
1985             scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1986             t_prop, 0) == SCF_SUCCESS) {
1987                 if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1988                         prop->sc_value_type = prop_type;
1989 
1990                         /*
1991                          * Found a type, update the value types and validate
1992                          * the actual value against this type.
1993                          */
1994                         for (vp = uu_list_first(prop->sc_property_values);
1995                             vp != NULL;
1996                             vp = uu_list_next(prop->sc_property_values, vp)) {
1997                                 vp->sc_type = prop->sc_value_type;
1998                                 lxml_store_value(vp, 0, NULL);
1999                         }
2000 
2001                         r = UU_WALK_NEXT;
2002                         goto out;
2003                 }
2004         } else {
2005                 if (t_pg == NULL && sc_pg) {
2006                         if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2007                                 warn(gettext("Unable to create template "
2008                                     "property group to find a property "
2009                                     "type.\n"));
2010 
2011                                 goto out;
2012                         }
2013 
2014                         if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2015                                 scf_tmpl_pg_destroy(t_pg);
2016                                 t_pg = NULL;
2017                         } else {
2018                                 goto do_tmpl;
2019                         }
2020                 }
2021         }
2022 
2023         if (issvc == 0) {
2024                 scf_instance_t *i;
2025                 scf_service_t *s;
2026 
2027                 issvc = 1;
2028                 if (lcb->sc_flags == 1) {
2029                         entity_t *e = pg->sc_parent->sc_parent;
2030 
2031                         fmri = e->sc_fmri;
2032                         goto retry_pg;
2033                 }
2034 
2035                 /*
2036                  * because lcb->sc_flags was not set then this means
2037                  * the pg was not used and can be used here.
2038                  */
2039                 if ((pg = internal_pgroup_new()) == NULL) {
2040                         warn(gettext("Could not create internal property group "
2041                             "to find a missing type."));
2042 
2043                         goto out;
2044                 }
2045 
2046                 pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2047                 if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2048                     max_scf_name_len + 1) < 0)
2049                                 goto out;
2050 
2051                 i = scf_instance_create(g_hndl);
2052                 s = scf_service_create(g_hndl);
2053                 if (i == NULL || s == NULL ||
2054                     scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2055                         warn(gettext("Could not get a service for the instance "
2056                             "to find a missing type."));
2057 
2058                         goto out;
2059                 }
2060 
2061                 /*
2062                  * Check to see truly at the instance level.
2063                  */
2064                 lfmri = safe_malloc(max_scf_fmri_len + 1);
2065                 if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2066                     scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2067                         goto out;
2068                 else
2069                         fmri = (const char *)lfmri;
2070 
2071                 goto retry_pg;
2072         }
2073 
2074 out :
2075         if (sc_pg != lcb->sc_parent) {
2076                 scf_pg_destroy(sc_pg);
2077         }
2078 
2079         /*
2080          * If this is true then the pg was allocated
2081          * here, and the name was set so need to free
2082          * the name and the pg.
2083          */
2084         if (pg != NULL && pg != lcb->sc_parent) {
2085                 free((char *)pg->sc_pgroup_name);
2086                 internal_pgroup_free(pg);
2087         }
2088 
2089         if (cur_selection) {
2090                 lscf_select(cur_selection);
2091                 free(cur_selection);
2092         }
2093 
2094         scf_tmpl_pg_destroy(t_pg);
2095         scf_tmpl_prop_destroy(t_prop);
2096         scf_property_destroy(sc_prop);
2097 
2098         if (r != UU_WALK_NEXT)
2099                 warn(gettext("Could not find property type for \"%s\" "
2100                     "from \"%s\"\n"), prop->sc_property_name,
2101                     fmri != NULL ? fmri : lcb->sc_source_fmri);
2102 
2103         free(lfmri);
2104 
2105         return (r);
2106 }
2107 
2108 /*
2109  * Take a property group that does not have a type and check to see if a type
2110  * exists or can be gleened from the current data.  Set the type.
2111  *
2112  * Check the current level (instance) and then check the higher level
2113  * (service).  This could be the case for adding a new property to
2114  * the instance that's going to "override" a service level property.
2115  *
2116  * For a property group
2117  * 1. Take the type from an existing property group
2118  * 2. Take the type from a template entry
2119  *
2120  * If the type can not be found, then leave the type as is, and let the import
2121  * report the problem of the missing type.
2122  */
2123 static int
2124 find_current_pg_type(void *p, void *sori)
2125 {
2126         entity_t *si = sori;
2127         pgroup_t *pg = p;
2128 
2129         const char *ofmri, *fmri;
2130         char *cur_selection = NULL;
2131         char *pg_type = NULL;
2132 
2133         scf_propertygroup_t *sc_pg = NULL;
2134         scf_pg_tmpl_t *t_pg = NULL;
2135 
2136         int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2137         int r = UU_WALK_ERROR;
2138 
2139         ofmri = fmri = si->sc_fmri;
2140         if (pg->sc_pgroup_type != NULL) {
2141                 r = UU_WALK_NEXT;
2142 
2143                 goto out;
2144         }
2145 
2146         sc_pg = scf_pg_create(g_hndl);
2147         if (sc_pg == NULL) {
2148                 warn(gettext("Unable to create property group to attempt "
2149                     "and find a missing type.\n"));
2150 
2151                 return (UU_WALK_ERROR);
2152         }
2153 
2154         /*
2155          * Using get_pg() requires that the cur_svc/cur_inst be
2156          * via lscf_select.  Need to preserve the current selection
2157          * if going to use lscf_select() to set up the cur_svc/cur_inst
2158          */
2159         if (cur_svc) {
2160                 cur_selection = safe_malloc(max_scf_fmri_len + 1);
2161                 lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2162         }
2163 
2164         /*
2165          * If the property group exists get the type, and set
2166          * the pgroup_t type of that type.
2167          *
2168          * If not the check for a template pg_pattern entry
2169          * and take the type from that.
2170          */
2171 retry_svc:
2172         lscf_select(fmri);
2173 
2174         if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2175                 pg_type = safe_malloc(max_scf_pg_type_len + 1);
2176                 if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2177                     max_scf_pg_type_len + 1) != -1) {
2178                         pg->sc_pgroup_type = pg_type;
2179 
2180                         r = UU_WALK_NEXT;
2181                         goto out;
2182                 } else {
2183                         free(pg_type);
2184                 }
2185         } else {
2186                 if ((t_pg == NULL) &&
2187                     (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2188                         goto out;
2189 
2190                 if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2191                     NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2192                     scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2193                         pg->sc_pgroup_type = pg_type;
2194 
2195                         r = UU_WALK_NEXT;
2196                         goto out;
2197                 }
2198         }
2199 
2200         /*
2201          * If type is not found at the instance level then attempt to
2202          * find the type at the service level.
2203          */
2204         if (!issvc) {
2205                 si = si->sc_parent;
2206                 fmri = si->sc_fmri;
2207                 issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2208                 goto retry_svc;
2209         }
2210 
2211 out :
2212         if (cur_selection) {
2213                 lscf_select(cur_selection);
2214                 free(cur_selection);
2215         }
2216 
2217         /*
2218          * Now walk the properties of the property group to make sure that
2219          * all properties have the correct type and values are valid for
2220          * those types.
2221          */
2222         if (r == UU_WALK_NEXT) {
2223                 scf_callback_t cb;
2224 
2225                 cb.sc_service = issvc;
2226                 cb.sc_source_fmri = ofmri;
2227                 if (sc_pg != NULL) {
2228                         cb.sc_parent = sc_pg;
2229                         cb.sc_flags = 0;
2230                 } else {
2231                         cb.sc_parent = pg;
2232                         cb.sc_flags = 1;
2233                 }
2234 
2235                 if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2236                     &cb, UU_DEFAULT) != 0) {
2237                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2238                                 bad_error("uu_list_walk", uu_error());
2239 
2240                         r = UU_WALK_ERROR;
2241                 }
2242         } else {
2243                 warn(gettext("Could not find property group type for "
2244                     "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2245         }
2246 
2247         scf_tmpl_pg_destroy(t_pg);
2248         scf_pg_destroy(sc_pg);
2249 
2250         return (r);
2251 }
2252 
2253 /*
2254  * Import.  These functions import a bundle into the repository.
2255  */
2256 
2257 /*
2258  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2259  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2260  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2261  * lcbdata->sc_err to
2262  *   ENOMEM - out of memory
2263  *   ECONNABORTED - repository connection broken
2264  *   ECANCELED - sc_trans's property group was deleted
2265  *   EINVAL - p's name is invalid (error printed)
2266  *          - p has an invalid value (error printed)
2267  */
2268 static int
2269 lscf_property_import(void *v, void *pvt)
2270 {
2271         property_t *p = v;
2272         scf_callback_t *lcbdata = pvt;
2273         value_t *vp;
2274         scf_transaction_t *trans = lcbdata->sc_trans;
2275         scf_transaction_entry_t *entr;
2276         scf_value_t *val;
2277         scf_type_t tp;
2278 
2279         if ((lcbdata->sc_flags & SCI_NOENABLED ||
2280             lcbdata->sc_flags & SCI_DELAYENABLE) &&
2281             strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2282                 lcbdata->sc_enable = p;
2283                 return (UU_WALK_NEXT);
2284         }
2285 
2286         entr = scf_entry_create(lcbdata->sc_handle);
2287         if (entr == NULL) {
2288                 switch (scf_error()) {
2289                 case SCF_ERROR_NO_MEMORY:
2290                         return (stash_scferror(lcbdata));
2291 
2292                 case SCF_ERROR_INVALID_ARGUMENT:
2293                 default:
2294                         bad_error("scf_entry_create", scf_error());
2295                 }
2296         }
2297 
2298         tp = p->sc_value_type;
2299 
2300         if (scf_transaction_property_new(trans, entr,
2301             p->sc_property_name, tp) != 0) {
2302                 switch (scf_error()) {
2303                 case SCF_ERROR_INVALID_ARGUMENT:
2304                         semerr(emsg_invalid_prop_name, p->sc_property_name);
2305                         scf_entry_destroy(entr);
2306                         return (stash_scferror(lcbdata));
2307 
2308                 case SCF_ERROR_EXISTS:
2309                         break;
2310 
2311                 case SCF_ERROR_DELETED:
2312                 case SCF_ERROR_CONNECTION_BROKEN:
2313                         scf_entry_destroy(entr);
2314                         return (stash_scferror(lcbdata));
2315 
2316                 case SCF_ERROR_NOT_BOUND:
2317                 case SCF_ERROR_HANDLE_MISMATCH:
2318                 case SCF_ERROR_NOT_SET:
2319                 default:
2320                         bad_error("scf_transaction_property_new", scf_error());
2321                 }
2322 
2323                 if (scf_transaction_property_change_type(trans, entr,
2324                     p->sc_property_name, tp) != 0) {
2325                         switch (scf_error()) {
2326                         case SCF_ERROR_DELETED:
2327                         case SCF_ERROR_CONNECTION_BROKEN:
2328                                 scf_entry_destroy(entr);
2329                                 return (stash_scferror(lcbdata));
2330 
2331                         case SCF_ERROR_INVALID_ARGUMENT:
2332                                 semerr(emsg_invalid_prop_name,
2333                                     p->sc_property_name);
2334                                 scf_entry_destroy(entr);
2335                                 return (stash_scferror(lcbdata));
2336 
2337                         case SCF_ERROR_NOT_FOUND:
2338                         case SCF_ERROR_NOT_SET:
2339                         case SCF_ERROR_HANDLE_MISMATCH:
2340                         case SCF_ERROR_NOT_BOUND:
2341                         default:
2342                                 bad_error(
2343                                     "scf_transaction_property_change_type",
2344                                     scf_error());
2345                         }
2346                 }
2347         }
2348 
2349         for (vp = uu_list_first(p->sc_property_values);
2350             vp != NULL;
2351             vp = uu_list_next(p->sc_property_values, vp)) {
2352                 val = scf_value_create(g_hndl);
2353                 if (val == NULL) {
2354                         switch (scf_error()) {
2355                         case SCF_ERROR_NO_MEMORY:
2356                                 return (stash_scferror(lcbdata));
2357 
2358                         case SCF_ERROR_INVALID_ARGUMENT:
2359                         default:
2360                                 bad_error("scf_value_create", scf_error());
2361                         }
2362                 }
2363 
2364                 switch (tp) {
2365                 case SCF_TYPE_BOOLEAN:
2366                         scf_value_set_boolean(val, vp->sc_u.sc_count);
2367                         break;
2368                 case SCF_TYPE_COUNT:
2369                         scf_value_set_count(val, vp->sc_u.sc_count);
2370                         break;
2371                 case SCF_TYPE_INTEGER:
2372                         scf_value_set_integer(val, vp->sc_u.sc_integer);
2373                         break;
2374                 default:
2375                         assert(vp->sc_u.sc_string != NULL);
2376                         if (scf_value_set_from_string(val, tp,
2377                             vp->sc_u.sc_string) != 0) {
2378                                 if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2379                                         bad_error("scf_value_set_from_string",
2380                                             scf_error());
2381 
2382                                 warn(gettext("Value \"%s\" is not a valid "
2383                                     "%s.\n"), vp->sc_u.sc_string,
2384                                     scf_type_to_string(tp));
2385                                 scf_value_destroy(val);
2386                                 return (stash_scferror(lcbdata));
2387                         }
2388                         break;
2389                 }
2390 
2391                 if (scf_entry_add_value(entr, val) != 0)
2392                         bad_error("scf_entry_add_value", scf_error());
2393         }
2394 
2395         return (UU_WALK_NEXT);
2396 }
2397 
2398 /*
2399  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2400  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2401  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2402  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2403  * lcbdata->sc_err to
2404  *   ECONNABORTED - repository connection broken
2405  *   ENOMEM - out of memory
2406  *   ENOSPC - svc.configd is out of resources
2407  *   ECANCELED - sc_parent was deleted
2408  *   EPERM - could not create property group (permission denied) (error printed)
2409  *         - could not modify property group (permission denied) (error printed)
2410  *         - could not delete property group (permission denied) (error printed)
2411  *   EROFS - could not create property group (repository is read-only)
2412  *         - could not delete property group (repository is read-only)
2413  *   EACCES - could not create property group (backend access denied)
2414  *          - could not delete property group (backend access denied)
2415  *   EEXIST - could not create property group (already exists)
2416  *   EINVAL - invalid property group name (error printed)
2417  *          - invalid property name (error printed)
2418  *          - invalid value (error printed)
2419  *   EBUSY - new property group deleted (error printed)
2420  *         - new property group changed (error printed)
2421  *         - property group added (error printed)
2422  *         - property group deleted (error printed)
2423  */
2424 static int
2425 entity_pgroup_import(void *v, void *pvt)
2426 {
2427         pgroup_t *p = v;
2428         scf_callback_t cbdata;
2429         scf_callback_t *lcbdata = pvt;
2430         void *ent = lcbdata->sc_parent;
2431         int issvc = lcbdata->sc_service;
2432         int r;
2433 
2434         const char * const pg_changed = gettext("%s changed unexpectedly "
2435             "(new property group \"%s\" changed).\n");
2436 
2437         /* Never import deleted property groups. */
2438         if (p->sc_pgroup_delete) {
2439                 if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2440                     entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2441                         goto delete_pg;
2442                 }
2443                 return (UU_WALK_NEXT);
2444         }
2445 
2446         if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2447             strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2448                 lcbdata->sc_general = p;
2449                 return (UU_WALK_NEXT);
2450         }
2451 
2452 add_pg:
2453         if (issvc)
2454                 r = scf_service_add_pg(ent, p->sc_pgroup_name,
2455                     p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2456         else
2457                 r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2458                     p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2459         if (r != 0) {
2460                 switch (scf_error()) {
2461                 case SCF_ERROR_DELETED:
2462                 case SCF_ERROR_CONNECTION_BROKEN:
2463                 case SCF_ERROR_BACKEND_READONLY:
2464                 case SCF_ERROR_BACKEND_ACCESS:
2465                 case SCF_ERROR_NO_RESOURCES:
2466                         return (stash_scferror(lcbdata));
2467 
2468                 case SCF_ERROR_EXISTS:
2469                         if (lcbdata->sc_flags & SCI_FORCE)
2470                                 break;
2471                         return (stash_scferror(lcbdata));
2472 
2473                 case SCF_ERROR_INVALID_ARGUMENT:
2474                         warn(emsg_fmri_invalid_pg_name_type,
2475                             lcbdata->sc_source_fmri,
2476                             p->sc_pgroup_name, p->sc_pgroup_type);
2477                         return (stash_scferror(lcbdata));
2478 
2479                 case SCF_ERROR_PERMISSION_DENIED:
2480                         warn(emsg_pg_add_perm, p->sc_pgroup_name,
2481                             lcbdata->sc_target_fmri);
2482                         return (stash_scferror(lcbdata));
2483 
2484                 case SCF_ERROR_NOT_BOUND:
2485                 case SCF_ERROR_HANDLE_MISMATCH:
2486                 case SCF_ERROR_NOT_SET:
2487                 default:
2488                         bad_error("scf_service_add_pg", scf_error());
2489                 }
2490 
2491                 if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2492                         switch (scf_error()) {
2493                         case SCF_ERROR_CONNECTION_BROKEN:
2494                         case SCF_ERROR_DELETED:
2495                                 return (stash_scferror(lcbdata));
2496 
2497                         case SCF_ERROR_INVALID_ARGUMENT:
2498                                 warn(emsg_fmri_invalid_pg_name,
2499                                     lcbdata->sc_source_fmri,
2500                                     p->sc_pgroup_name);
2501                                 return (stash_scferror(lcbdata));
2502 
2503                         case SCF_ERROR_NOT_FOUND:
2504                                 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2505                                     p->sc_pgroup_name);
2506                                 lcbdata->sc_err = EBUSY;
2507                                 return (UU_WALK_ERROR);
2508 
2509                         case SCF_ERROR_NOT_BOUND:
2510                         case SCF_ERROR_HANDLE_MISMATCH:
2511                         case SCF_ERROR_NOT_SET:
2512                         default:
2513                                 bad_error("entity_get_pg", scf_error());
2514                         }
2515                 }
2516 
2517                 if (lcbdata->sc_flags & SCI_KEEP)
2518                         goto props;
2519 
2520 delete_pg:
2521                 if (scf_pg_delete(imp_pg) != 0) {
2522                         switch (scf_error()) {
2523                         case SCF_ERROR_DELETED:
2524                                 warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2525                                     p->sc_pgroup_name);
2526                                 lcbdata->sc_err = EBUSY;
2527                                 return (UU_WALK_ERROR);
2528 
2529                         case SCF_ERROR_PERMISSION_DENIED:
2530                                 warn(emsg_pg_del_perm, p->sc_pgroup_name,
2531                                     lcbdata->sc_target_fmri);
2532                                 return (stash_scferror(lcbdata));
2533 
2534                         case SCF_ERROR_BACKEND_READONLY:
2535                         case SCF_ERROR_BACKEND_ACCESS:
2536                         case SCF_ERROR_CONNECTION_BROKEN:
2537                                 return (stash_scferror(lcbdata));
2538 
2539                         case SCF_ERROR_NOT_SET:
2540                         default:
2541                                 bad_error("scf_pg_delete", scf_error());
2542                         }
2543                 }
2544 
2545                 if (p->sc_pgroup_delete)
2546                         return (UU_WALK_NEXT);
2547 
2548                 goto add_pg;
2549         }
2550 
2551 props:
2552 
2553         /*
2554          * Add properties to property group, if any.
2555          */
2556         cbdata.sc_handle = lcbdata->sc_handle;
2557         cbdata.sc_parent = imp_pg;
2558         cbdata.sc_flags = lcbdata->sc_flags;
2559         cbdata.sc_trans = imp_tx;
2560         cbdata.sc_enable = NULL;
2561 
2562         if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2563                 switch (scf_error()) {
2564                 case SCF_ERROR_BACKEND_ACCESS:
2565                 case SCF_ERROR_BACKEND_READONLY:
2566                 case SCF_ERROR_CONNECTION_BROKEN:
2567                         return (stash_scferror(lcbdata));
2568 
2569                 case SCF_ERROR_DELETED:
2570                         warn(pg_changed, lcbdata->sc_target_fmri,
2571                             p->sc_pgroup_name);
2572                         lcbdata->sc_err = EBUSY;
2573                         return (UU_WALK_ERROR);
2574 
2575                 case SCF_ERROR_PERMISSION_DENIED:
2576                         warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2577                             lcbdata->sc_target_fmri);
2578                         return (stash_scferror(lcbdata));
2579 
2580                 case SCF_ERROR_NOT_BOUND:
2581                 case SCF_ERROR_NOT_SET:
2582                 case SCF_ERROR_IN_USE:
2583                 case SCF_ERROR_HANDLE_MISMATCH:
2584                 default:
2585                         bad_error("scf_transaction_start", scf_error());
2586                 }
2587         }
2588 
2589         if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2590             UU_DEFAULT) != 0) {
2591                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2592                         bad_error("uu_list_walk", uu_error());
2593                 scf_transaction_reset(imp_tx);
2594 
2595                 lcbdata->sc_err = cbdata.sc_err;
2596                 if (cbdata.sc_err == ECANCELED) {
2597                         warn(pg_changed, lcbdata->sc_target_fmri,
2598                             p->sc_pgroup_name);
2599                         lcbdata->sc_err = EBUSY;
2600                 }
2601                 return (UU_WALK_ERROR);
2602         }
2603 
2604         if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2605                 cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2606 
2607                 /*
2608                  * take the snapshot running snapshot then
2609                  * import the stored general/enable property
2610                  */
2611                 r = take_snap(ent, snap_running, imp_rsnap);
2612                 switch (r) {
2613                 case 0:
2614                         break;
2615 
2616                 case ECONNABORTED:
2617                         warn(gettext("Could not take %s snapshot on import "
2618                             "(repository connection broken).\n"),
2619                             snap_running);
2620                         lcbdata->sc_err = r;
2621                         return (UU_WALK_ERROR);
2622                 case ECANCELED:
2623                         warn(emsg_deleted);
2624                         lcbdata->sc_err = r;
2625                         return (UU_WALK_ERROR);
2626 
2627                 case EPERM:
2628                         warn(gettext("Could not take %s snapshot "
2629                             "(permission denied).\n"), snap_running);
2630                         lcbdata->sc_err = r;
2631                         return (UU_WALK_ERROR);
2632 
2633                 case ENOSPC:
2634                         warn(gettext("Could not take %s snapshot"
2635                             "(repository server out of resources).\n"),
2636                             snap_running);
2637                         lcbdata->sc_err = r;
2638                         return (UU_WALK_ERROR);
2639 
2640                 default:
2641                         bad_error("take_snap", r);
2642                 }
2643 
2644                 r = lscf_property_import(cbdata.sc_enable, &cbdata);
2645                 if (r != UU_WALK_NEXT) {
2646                         if (r != UU_WALK_ERROR)
2647                                 bad_error("lscf_property_import", r);
2648                         return (EINVAL);
2649                 }
2650         }
2651 
2652         r = scf_transaction_commit(imp_tx);
2653         switch (r) {
2654         case 1:
2655                 r = UU_WALK_NEXT;
2656                 break;
2657 
2658         case 0:
2659                 warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2660                 lcbdata->sc_err = EBUSY;
2661                 r = UU_WALK_ERROR;
2662                 break;
2663 
2664         case -1:
2665                 switch (scf_error()) {
2666                 case SCF_ERROR_BACKEND_READONLY:
2667                 case SCF_ERROR_BACKEND_ACCESS:
2668                 case SCF_ERROR_CONNECTION_BROKEN:
2669                 case SCF_ERROR_NO_RESOURCES:
2670                         r = stash_scferror(lcbdata);
2671                         break;
2672 
2673                 case SCF_ERROR_DELETED:
2674                         warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2675                             p->sc_pgroup_name);
2676                         lcbdata->sc_err = EBUSY;
2677                         r = UU_WALK_ERROR;
2678                         break;
2679 
2680                 case SCF_ERROR_PERMISSION_DENIED:
2681                         warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2682                             lcbdata->sc_target_fmri);
2683                         r = stash_scferror(lcbdata);
2684                         break;
2685 
2686                 case SCF_ERROR_NOT_SET:
2687                 case SCF_ERROR_INVALID_ARGUMENT:
2688                 case SCF_ERROR_NOT_BOUND:
2689                 default:
2690                         bad_error("scf_transaction_commit", scf_error());
2691                 }
2692                 break;
2693 
2694         default:
2695                 bad_error("scf_transaction_commit", r);
2696         }
2697 
2698         scf_transaction_destroy_children(imp_tx);
2699 
2700         return (r);
2701 }
2702 
2703 /*
2704  * Returns
2705  *   0 - success
2706  *   ECONNABORTED - repository connection broken
2707  *   ENOMEM - out of memory
2708  *   ENOSPC - svc.configd is out of resources
2709  *   ECANCELED - inst was deleted
2710  *   EPERM - could not create property group (permission denied) (error printed)
2711  *         - could not modify property group (permission denied) (error printed)
2712  *   EROFS - could not create property group (repository is read-only)
2713  *   EACCES - could not create property group (backend access denied)
2714  *   EEXIST - could not create property group (already exists)
2715  *   EINVAL - invalid property group name (error printed)
2716  *          - invalid property name (error printed)
2717  *          - invalid value (error printed)
2718  *   EBUSY - new property group changed (error printed)
2719  */
2720 static int
2721 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2722     const entity_t *isvc, int flags)
2723 {
2724         scf_callback_t cbdata;
2725 
2726         cbdata.sc_handle = scf_service_handle(svc);
2727         cbdata.sc_parent = svc;
2728         cbdata.sc_service = 1;
2729         cbdata.sc_general = 0;
2730         cbdata.sc_enable = 0;
2731         cbdata.sc_flags = flags;
2732         cbdata.sc_source_fmri = isvc->sc_fmri;
2733         cbdata.sc_target_fmri = target_fmri;
2734 
2735         /*
2736          * If the op is set, then add the flag to the callback
2737          * flags for later use.
2738          */
2739         if (isvc->sc_op != SVCCFG_OP_NONE) {
2740                 switch (isvc->sc_op) {
2741                 case SVCCFG_OP_IMPORT :
2742                         cbdata.sc_flags |= SCI_OP_IMPORT;
2743                         break;
2744                 case SVCCFG_OP_APPLY :
2745                         cbdata.sc_flags |= SCI_OP_APPLY;
2746                         break;
2747                 case SVCCFG_OP_RESTORE :
2748                         cbdata.sc_flags |= SCI_OP_RESTORE;
2749                         break;
2750                 default :
2751                         uu_die(gettext("lscf_import_service_pgs : "
2752                             "Unknown op stored in the service entity\n"));
2753 
2754                 }
2755         }
2756 
2757         if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2758             UU_DEFAULT) != 0) {
2759                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2760                         bad_error("uu_list_walk", uu_error());
2761 
2762                 return (cbdata.sc_err);
2763         }
2764 
2765         return (0);
2766 }
2767 
2768 /*
2769  * Returns
2770  *   0 - success
2771  *   ECONNABORTED - repository connection broken
2772  *   ENOMEM - out of memory
2773  *   ENOSPC - svc.configd is out of resources
2774  *   ECANCELED - inst was deleted
2775  *   EPERM - could not create property group (permission denied) (error printed)
2776  *         - could not modify property group (permission denied) (error printed)
2777  *   EROFS - could not create property group (repository is read-only)
2778  *   EACCES - could not create property group (backend access denied)
2779  *   EEXIST - could not create property group (already exists)
2780  *   EINVAL - invalid property group name (error printed)
2781  *          - invalid property name (error printed)
2782  *          - invalid value (error printed)
2783  *   EBUSY - new property group changed (error printed)
2784  */
2785 static int
2786 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2787     const entity_t *iinst, int flags)
2788 {
2789         scf_callback_t cbdata;
2790 
2791         cbdata.sc_handle = scf_instance_handle(inst);
2792         cbdata.sc_parent = inst;
2793         cbdata.sc_service = 0;
2794         cbdata.sc_general = NULL;
2795         cbdata.sc_enable = NULL;
2796         cbdata.sc_flags = flags;
2797         cbdata.sc_source_fmri = iinst->sc_fmri;
2798         cbdata.sc_target_fmri = target_fmri;
2799 
2800         /*
2801          * If the op is set, then add the flag to the callback
2802          * flags for later use.
2803          */
2804         if (iinst->sc_op != SVCCFG_OP_NONE) {
2805                 switch (iinst->sc_op) {
2806                 case SVCCFG_OP_IMPORT :
2807                         cbdata.sc_flags |= SCI_OP_IMPORT;
2808                         break;
2809                 case SVCCFG_OP_APPLY :
2810                         cbdata.sc_flags |= SCI_OP_APPLY;
2811                         break;
2812                 case SVCCFG_OP_RESTORE :
2813                         cbdata.sc_flags |= SCI_OP_RESTORE;
2814                         break;
2815                 default :
2816                         uu_die(gettext("lscf_import_instance_pgs : "
2817                             "Unknown op stored in the instance entity\n"));
2818                 }
2819         }
2820 
2821         if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2822             UU_DEFAULT) != 0) {
2823                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2824                         bad_error("uu_list_walk", uu_error());
2825 
2826                 return (cbdata.sc_err);
2827         }
2828 
2829         if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2830                 cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2831                 /*
2832                  * If importing with the SCI_NOENABLED flag then
2833                  * skip the delay, but if not then add the delay
2834                  * of the enable property.
2835                  */
2836                 if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2837                         cbdata.sc_flags |= SCI_DELAYENABLE;
2838                 }
2839 
2840                 if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2841                     != UU_WALK_NEXT)
2842                         return (cbdata.sc_err);
2843         }
2844 
2845         return (0);
2846 }
2847 
2848 /*
2849  * Report the reasons why we can't upgrade pg2 to pg1.
2850  */
2851 static void
2852 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2853     int new)
2854 {
2855         property_t *p1, *p2;
2856 
2857         assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2858 
2859         if (!pg_attrs_equal(pg1, pg2, fmri, new))
2860                 return;
2861 
2862         for (p1 = uu_list_first(pg1->sc_pgroup_props);
2863             p1 != NULL;
2864             p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2865                 p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2866                 if (p2 != NULL) {
2867                         (void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2868                             new);
2869                         continue;
2870                 }
2871 
2872                 if (new)
2873                         warn(gettext("Conflict upgrading %s (new property "
2874                             "group \"%s\" is missing property \"%s\").\n"),
2875                             fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2876                 else
2877                         warn(gettext("Conflict upgrading %s (property "
2878                             "\"%s/%s\" is missing).\n"), fmri,
2879                             pg1->sc_pgroup_name, p1->sc_property_name);
2880         }
2881 
2882         /*
2883          * Since pg1 should be from the manifest, any properties in pg2 which
2884          * aren't in pg1 shouldn't be reported as conflicts.
2885          */
2886 }
2887 
2888 /*
2889  * Add transaction entries to tx which will upgrade cur's pg according to old
2890  * & new.
2891  *
2892  * Returns
2893  *   0 - success
2894  *   EINVAL - new has a property with an invalid name or value (message emitted)
2895  *   ENOMEM - out of memory
2896  */
2897 static int
2898 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2899     pgroup_t *cur, int speak, const char *fmri)
2900 {
2901         property_t *p, *new_p, *cur_p;
2902         scf_transaction_entry_t *e;
2903         int r;
2904         int is_general;
2905         int is_protected;
2906 
2907         if (uu_list_walk(new->sc_pgroup_props, clear_int,
2908             (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2909                 bad_error("uu_list_walk", uu_error());
2910 
2911         is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2912 
2913         for (p = uu_list_first(old->sc_pgroup_props);
2914             p != NULL;
2915             p = uu_list_next(old->sc_pgroup_props, p)) {
2916                 /* p is a property in the old property group. */
2917 
2918                 /* Protect live properties. */
2919                 is_protected = 0;
2920                 if (is_general) {
2921                         if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2922                             0 ||
2923                             strcmp(p->sc_property_name,
2924                             SCF_PROPERTY_RESTARTER) == 0)
2925                                 is_protected = 1;
2926                 }
2927 
2928                 /* Look for the same property in the new properties. */
2929                 new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2930                 if (new_p != NULL) {
2931                         new_p->sc_seen = 1;
2932 
2933                         /*
2934                          * If the new property is the same as the old, don't do
2935                          * anything (leave any user customizations).
2936                          */
2937                         if (prop_equal(p, new_p, NULL, NULL, 0))
2938                                 continue;
2939 
2940                         if (new_p->sc_property_override)
2941                                 goto upgrade;
2942                 }
2943 
2944                 cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2945                 if (cur_p == NULL) {
2946                         /*
2947                          * p has been deleted from the repository.  If we were
2948                          * going to delete it anyway, do nothing.  Otherwise
2949                          * report a conflict.
2950                          */
2951                         if (new_p == NULL)
2952                                 continue;
2953 
2954                         if (is_protected)
2955                                 continue;
2956 
2957                         warn(gettext("Conflict upgrading %s "
2958                             "(property \"%s/%s\" is missing).\n"), fmri,
2959                             old->sc_pgroup_name, p->sc_property_name);
2960                         continue;
2961                 }
2962 
2963                 if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2964                         /*
2965                          * Conflict.  Don't warn if the property is already the
2966                          * way we want it, though.
2967                          */
2968                         if (is_protected)
2969                                 continue;
2970 
2971                         if (new_p == NULL)
2972                                 (void) prop_equal(p, cur_p, fmri,
2973                                     old->sc_pgroup_name, 0);
2974                         else
2975                                 (void) prop_equal(cur_p, new_p, fmri,
2976                                     old->sc_pgroup_name, 0);
2977                         continue;
2978                 }
2979 
2980                 if (is_protected) {
2981                         if (speak)
2982                                 warn(gettext("%s: Refusing to upgrade "
2983                                     "\"%s/%s\" (live property).\n"), fmri,
2984                                     old->sc_pgroup_name, p->sc_property_name);
2985                         continue;
2986                 }
2987 
2988 upgrade:
2989                 /* p hasn't been customized in the repository.  Upgrade it. */
2990                 if (new_p == NULL) {
2991                         /* p was deleted.  Delete from cur if unchanged. */
2992                         if (speak)
2993                                 warn(gettext(
2994                                     "%s: Deleting property \"%s/%s\".\n"),
2995                                     fmri, old->sc_pgroup_name,
2996                                     p->sc_property_name);
2997 
2998                         e = scf_entry_create(g_hndl);
2999                         if (e == NULL)
3000                                 return (ENOMEM);
3001 
3002                         if (scf_transaction_property_delete(tx, e,
3003                             p->sc_property_name) != 0) {
3004                                 switch (scf_error()) {
3005                                 case SCF_ERROR_DELETED:
3006                                         scf_entry_destroy(e);
3007                                         return (ECANCELED);
3008 
3009                                 case SCF_ERROR_CONNECTION_BROKEN:
3010                                         scf_entry_destroy(e);
3011                                         return (ECONNABORTED);
3012 
3013                                 case SCF_ERROR_NOT_FOUND:
3014                                         /*
3015                                          * This can happen if cur is from the
3016                                          * running snapshot (and it differs
3017                                          * from the live properties).
3018                                          */
3019                                         scf_entry_destroy(e);
3020                                         break;
3021 
3022                                 case SCF_ERROR_HANDLE_MISMATCH:
3023                                 case SCF_ERROR_NOT_BOUND:
3024                                 case SCF_ERROR_NOT_SET:
3025                                 case SCF_ERROR_INVALID_ARGUMENT:
3026                                 default:
3027                                         bad_error(
3028                                             "scf_transaction_property_delete",
3029                                             scf_error());
3030                                 }
3031                         }
3032                 } else {
3033                         scf_callback_t ctx;
3034 
3035                         if (speak)
3036                                 warn(gettext(
3037                                     "%s: Upgrading property \"%s/%s\".\n"),
3038                                     fmri, old->sc_pgroup_name,
3039                                     p->sc_property_name);
3040 
3041                         ctx.sc_handle = g_hndl;
3042                         ctx.sc_trans = tx;
3043                         ctx.sc_flags = 0;
3044 
3045                         r = lscf_property_import(new_p, &ctx);
3046                         if (r != UU_WALK_NEXT) {
3047                                 if (r != UU_WALK_ERROR)
3048                                         bad_error("lscf_property_import", r);
3049                                 return (EINVAL);
3050                         }
3051                 }
3052         }
3053 
3054         /* Go over the properties which were added. */
3055         for (new_p = uu_list_first(new->sc_pgroup_props);
3056             new_p != NULL;
3057             new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3058                 if (new_p->sc_seen)
3059                         continue;
3060 
3061                 /* This is a new property. */
3062                 cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3063                 if (cur_p == NULL) {
3064                         scf_callback_t ctx;
3065 
3066                         ctx.sc_handle = g_hndl;
3067                         ctx.sc_trans = tx;
3068                         ctx.sc_flags = 0;
3069 
3070                         r = lscf_property_import(new_p, &ctx);
3071                         if (r != UU_WALK_NEXT) {
3072                                 if (r != UU_WALK_ERROR)
3073                                         bad_error("lscf_property_import", r);
3074                                 return (EINVAL);
3075                         }
3076                         continue;
3077                 }
3078 
3079                 /*
3080                  * Report a conflict if the new property differs from the
3081                  * current one.  Unless it's general/enabled, since that's
3082                  * never in the last-import snapshot.
3083                  */
3084                 if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3085                     0 &&
3086                     strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3087                         continue;
3088 
3089                 (void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3090         }
3091 
3092         return (0);
3093 }
3094 
3095 /*
3096  * Upgrade pg according to old & new.
3097  *
3098  * Returns
3099  *   0 - success
3100  *   ECONNABORTED - repository connection broken
3101  *   ENOMEM - out of memory
3102  *   ENOSPC - svc.configd is out of resources
3103  *   ECANCELED - pg was deleted
3104  *   EPERM - couldn't modify pg (permission denied)
3105  *   EROFS - couldn't modify pg (backend read-only)
3106  *   EACCES - couldn't modify pg (backend access denied)
3107  *   EINVAL - new has a property with invalid name or value (error printed)
3108  *   EBUSY - pg changed unexpectedly
3109  */
3110 static int
3111 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3112     pgroup_t *new, int speak, const char *fmri)
3113 {
3114         int r;
3115 
3116         if (scf_transaction_start(imp_tx, pg) != 0) {
3117                 switch (scf_error()) {
3118                 case SCF_ERROR_CONNECTION_BROKEN:
3119                 case SCF_ERROR_DELETED:
3120                 case SCF_ERROR_PERMISSION_DENIED:
3121                 case SCF_ERROR_BACKEND_READONLY:
3122                 case SCF_ERROR_BACKEND_ACCESS:
3123                         return (scferror2errno(scf_error()));
3124 
3125                 case SCF_ERROR_HANDLE_MISMATCH:
3126                 case SCF_ERROR_IN_USE:
3127                 case SCF_ERROR_NOT_BOUND:
3128                 case SCF_ERROR_NOT_SET:
3129                 default:
3130                         bad_error("scf_transaction_start", scf_error());
3131                 }
3132         }
3133 
3134         r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3135         switch (r) {
3136         case 0:
3137                 break;
3138 
3139         case EINVAL:
3140         case ENOMEM:
3141                 scf_transaction_destroy_children(imp_tx);
3142                 return (r);
3143 
3144         default:
3145                 bad_error("add_upgrade_entries", r);
3146         }
3147 
3148         r = scf_transaction_commit(imp_tx);
3149 
3150         scf_transaction_destroy_children(imp_tx);
3151 
3152         switch (r) {
3153         case 1:
3154                 break;
3155 
3156         case 0:
3157                 return (EBUSY);
3158 
3159         case -1:
3160                 switch (scf_error()) {
3161                 case SCF_ERROR_CONNECTION_BROKEN:
3162                 case SCF_ERROR_NO_RESOURCES:
3163                 case SCF_ERROR_PERMISSION_DENIED:
3164                 case SCF_ERROR_BACKEND_READONLY:
3165                 case SCF_ERROR_BACKEND_ACCESS:
3166                 case SCF_ERROR_DELETED:
3167                         return (scferror2errno(scf_error()));
3168 
3169                 case SCF_ERROR_NOT_BOUND:
3170                 case SCF_ERROR_INVALID_ARGUMENT:
3171                 case SCF_ERROR_NOT_SET:
3172                 default:
3173                         bad_error("scf_transaction_commit", scf_error());
3174                 }
3175 
3176         default:
3177                 bad_error("scf_transaction_commit", r);
3178         }
3179 
3180         return (0);
3181 }
3182 
3183 /*
3184  * Compares two entity FMRIs.  Returns
3185  *
3186  *   1 - equal
3187  *   0 - not equal
3188  *   -1 - f1 is invalid or not an entity
3189  *   -2 - f2 is invalid or not an entity
3190  */
3191 static int
3192 fmri_equal(const char *f1, const char *f2)
3193 {
3194         int r;
3195         const char *s1, *i1, *pg1;
3196         const char *s2, *i2, *pg2;
3197 
3198         if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3199                 return (-1);
3200         if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3201                 return (-1);
3202 
3203         if (s1 == NULL || pg1 != NULL)
3204                 return (-1);
3205 
3206         if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3207                 return (-2);
3208         if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3209                 return (-2);
3210 
3211         if (s2 == NULL || pg2 != NULL)
3212                 return (-2);
3213 
3214         r = strcmp(s1, s2);
3215         if (r != 0)
3216                 return (0);
3217 
3218         if (i1 == NULL && i2 == NULL)
3219                 return (1);
3220 
3221         if (i1 == NULL || i2 == NULL)
3222                 return (0);
3223 
3224         return (strcmp(i1, i2) == 0);
3225 }
3226 
3227 /*
3228  * Import a dependent by creating a dependency property group in the dependent
3229  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3230  * dependents pg, and add an entry to create a new property for this
3231  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3232  *
3233  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3234  * lcbdata->sc_err to
3235  *   ECONNABORTED - repository connection broken
3236  *   ENOMEM - out of memory
3237  *   ENOSPC - configd is out of resources
3238  *   EINVAL - target is invalid (error printed)
3239  *          - target is not an entity (error printed)
3240  *          - dependent has invalid name (error printed)
3241  *          - invalid property name (error printed)
3242  *          - invalid value (error printed)
3243  *          - scope of target does not exist (error printed)
3244  *   EPERM - couldn't create target (permission denied) (error printed)
3245  *         - couldn't create dependency pg (permission denied) (error printed)
3246  *         - couldn't modify dependency pg (permission denied) (error printed)
3247  *   EROFS - couldn't create target (repository read-only)
3248  *         - couldn't create dependency pg (repository read-only)
3249  *   EACCES - couldn't create target (backend access denied)
3250  *          - couldn't create dependency pg (backend access denied)
3251  *   ECANCELED - sc_trans's pg was deleted
3252  *   EALREADY - property for dependent already exists in sc_trans's pg
3253  *   EEXIST - dependency pg already exists in target (error printed)
3254  *   EBUSY - target deleted (error printed)
3255  *         - property group changed during import (error printed)
3256  */
3257 static int
3258 lscf_dependent_import(void *a1, void *pvt)
3259 {
3260         pgroup_t *pgrp = a1;
3261         scf_callback_t *lcbdata = pvt;
3262 
3263         int isservice;
3264         int ret;
3265         scf_transaction_entry_t *e;
3266         scf_value_t *val;
3267         scf_callback_t dependent_cbdata;
3268         scf_error_t scfe;
3269 
3270         /*
3271          * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3272          * it's invalid, we fail before modifying the repository.
3273          */
3274         scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3275             &dependent_cbdata.sc_parent, &isservice);
3276         switch (scfe) {
3277         case SCF_ERROR_NONE:
3278                 break;
3279 
3280         case SCF_ERROR_NO_MEMORY:
3281                 return (stash_scferror_err(lcbdata, scfe));
3282 
3283         case SCF_ERROR_INVALID_ARGUMENT:
3284                 semerr(gettext("The FMRI for the \"%s\" dependent is "
3285                     "invalid.\n"), pgrp->sc_pgroup_name);
3286                 return (stash_scferror_err(lcbdata, scfe));
3287 
3288         case SCF_ERROR_CONSTRAINT_VIOLATED:
3289                 semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3290                     "specifies neither a service nor an instance.\n"),
3291                     pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3292                 return (stash_scferror_err(lcbdata, scfe));
3293 
3294         case SCF_ERROR_NOT_FOUND:
3295                 scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3296                     &dependent_cbdata.sc_parent, &isservice);
3297                 switch (scfe) {
3298                 case SCF_ERROR_NONE:
3299                         break;
3300 
3301                 case SCF_ERROR_NO_MEMORY:
3302                 case SCF_ERROR_BACKEND_READONLY:
3303                 case SCF_ERROR_BACKEND_ACCESS:
3304                         return (stash_scferror_err(lcbdata, scfe));
3305 
3306                 case SCF_ERROR_NOT_FOUND:
3307                         semerr(gettext("The scope in FMRI \"%s\" for the "
3308                             "\"%s\" dependent does not exist.\n"),
3309                             pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3310                         lcbdata->sc_err = EINVAL;
3311                         return (UU_WALK_ERROR);
3312 
3313                 case SCF_ERROR_PERMISSION_DENIED:
3314                         warn(gettext(
3315                             "Could not create %s (permission denied).\n"),
3316                             pgrp->sc_pgroup_fmri);
3317                         return (stash_scferror_err(lcbdata, scfe));
3318 
3319                 case SCF_ERROR_INVALID_ARGUMENT:
3320                 case SCF_ERROR_CONSTRAINT_VIOLATED:
3321                 default:
3322                         bad_error("create_entity", scfe);
3323                 }
3324                 break;
3325 
3326         default:
3327                 bad_error("fmri_to_entity", scfe);
3328         }
3329 
3330         if (lcbdata->sc_trans != NULL) {
3331                 e = scf_entry_create(lcbdata->sc_handle);
3332                 if (e == NULL) {
3333                         if (scf_error() != SCF_ERROR_NO_MEMORY)
3334                                 bad_error("scf_entry_create", scf_error());
3335 
3336                         entity_destroy(dependent_cbdata.sc_parent, isservice);
3337                         return (stash_scferror(lcbdata));
3338                 }
3339 
3340                 if (scf_transaction_property_new(lcbdata->sc_trans, e,
3341                     pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3342                         switch (scf_error()) {
3343                         case SCF_ERROR_INVALID_ARGUMENT:
3344                                 warn(gettext("Dependent of %s has invalid name "
3345                                     "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3346                                     pgrp->sc_pgroup_name);
3347                                 /* FALLTHROUGH */
3348 
3349                         case SCF_ERROR_DELETED:
3350                         case SCF_ERROR_CONNECTION_BROKEN:
3351                                 scf_entry_destroy(e);
3352                                 entity_destroy(dependent_cbdata.sc_parent,
3353                                     isservice);
3354                                 return (stash_scferror(lcbdata));
3355 
3356                         case SCF_ERROR_EXISTS:
3357                                 scf_entry_destroy(e);
3358                                 entity_destroy(dependent_cbdata.sc_parent,
3359                                     isservice);
3360                                 lcbdata->sc_err = EALREADY;
3361                                 return (UU_WALK_ERROR);
3362 
3363                         case SCF_ERROR_NOT_BOUND:
3364                         case SCF_ERROR_HANDLE_MISMATCH:
3365                         case SCF_ERROR_NOT_SET:
3366                         default:
3367                                 bad_error("scf_transaction_property_new",
3368                                     scf_error());
3369                         }
3370                 }
3371 
3372                 val = scf_value_create(lcbdata->sc_handle);
3373                 if (val == NULL) {
3374                         if (scf_error() != SCF_ERROR_NO_MEMORY)
3375                                 bad_error("scf_value_create", scf_error());
3376 
3377                         entity_destroy(dependent_cbdata.sc_parent, isservice);
3378                         return (stash_scferror(lcbdata));
3379                 }
3380 
3381                 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3382                     pgrp->sc_pgroup_fmri) != 0)
3383                         /* invalid should have been caught above */
3384                         bad_error("scf_value_set_from_string", scf_error());
3385 
3386                 if (scf_entry_add_value(e, val) != 0)
3387                         bad_error("scf_entry_add_value", scf_error());
3388         }
3389 
3390         /* Add the property group to the target entity. */
3391 
3392         dependent_cbdata.sc_handle = lcbdata->sc_handle;
3393         dependent_cbdata.sc_flags = lcbdata->sc_flags;
3394         dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3395         dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3396 
3397         ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3398 
3399         entity_destroy(dependent_cbdata.sc_parent, isservice);
3400 
3401         if (ret == UU_WALK_NEXT)
3402                 return (ret);
3403 
3404         if (ret != UU_WALK_ERROR)
3405                 bad_error("entity_pgroup_import", ret);
3406 
3407         switch (dependent_cbdata.sc_err) {
3408         case ECANCELED:
3409                 warn(gettext("%s deleted unexpectedly.\n"),
3410                     pgrp->sc_pgroup_fmri);
3411                 lcbdata->sc_err = EBUSY;
3412                 break;
3413 
3414         case EEXIST:
3415                 warn(gettext("Could not create \"%s\" dependency in %s "
3416                     "(already exists).\n"), pgrp->sc_pgroup_name,
3417                     pgrp->sc_pgroup_fmri);
3418                 /* FALLTHROUGH */
3419 
3420         default:
3421                 lcbdata->sc_err = dependent_cbdata.sc_err;
3422         }
3423 
3424         return (UU_WALK_ERROR);
3425 }
3426 
3427 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3428     const scf_snaplevel_t *, scf_transaction_t *);
3429 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3430     const pgroup_t *);
3431 
3432 /*
3433  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3434  * the current dependent targets from running (the snaplevel of a running
3435  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3436  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3437  * dependent targets and dependency properties from li_dpts_pg (the
3438  * "dependents" property group in snpl) and snpl (the snaplevel which
3439  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3440  * snpl doesn't have a "dependents" property group, and any dependents in ient
3441  * are new.
3442  *
3443  * Returns
3444  *   0 - success
3445  *   ECONNABORTED - repository connection broken
3446  *   ENOMEM - out of memory
3447  *   ENOSPC - configd is out of resources
3448  *   ECANCELED - ent was deleted
3449  *   ENODEV - the entity containing li_dpts_pg was deleted
3450  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3451  *         - couldn't upgrade dependent (permission denied) (error printed)
3452  *         - couldn't create dependent (permission denied) (error printed)
3453  *   EROFS - could not modify dependents pg (repository read-only)
3454  *         - couldn't upgrade dependent (repository read-only)
3455  *         - couldn't create dependent (repository read-only)
3456  *   EACCES - could not modify dependents pg (backend access denied)
3457  *          - could not upgrade dependent (backend access denied)
3458  *          - could not create dependent (backend access denied)
3459  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3460  *         - dependent target deleted (error printed)
3461  *         - dependent pg changed (error printed)
3462  *   EINVAL - new dependent is invalid (error printed)
3463  *   EBADF - snpl is corrupt (error printed)
3464  *         - snpl has corrupt pg (error printed)
3465  *         - dependency pg in target is corrupt (error printed)
3466  *         - target has corrupt snapshot (error printed)
3467  *   EEXIST - dependency pg already existed in target service (error printed)
3468  */
3469 static int
3470 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3471     const scf_snaplevel_t *snpl, const entity_t *ient,
3472     const scf_snaplevel_t *running, void *ent)
3473 {
3474         pgroup_t *new_dpt_pgroup;
3475         scf_callback_t cbdata;
3476         int r, unseen, tx_started = 0;
3477         int have_cur_depts;
3478 
3479         const char * const dependents = "dependents";
3480 
3481         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3482 
3483         if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3484                 /* Nothing to do. */
3485                 return (0);
3486 
3487         /* Fetch the current version of the "dependents" property group. */
3488         have_cur_depts = 1;
3489         if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3490                 switch (scf_error()) {
3491                 case SCF_ERROR_NOT_FOUND:
3492                         break;
3493 
3494                 case SCF_ERROR_DELETED:
3495                 case SCF_ERROR_CONNECTION_BROKEN:
3496                         return (scferror2errno(scf_error()));
3497 
3498                 case SCF_ERROR_NOT_SET:
3499                 case SCF_ERROR_INVALID_ARGUMENT:
3500                 case SCF_ERROR_HANDLE_MISMATCH:
3501                 case SCF_ERROR_NOT_BOUND:
3502                 default:
3503                         bad_error("entity_get_pg", scf_error());
3504                 }
3505 
3506                 have_cur_depts = 0;
3507         }
3508 
3509         /* Fetch the running version of the "dependents" property group. */
3510         ud_run_dpts_pg_set = 0;
3511         if (running != NULL)
3512                 r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3513         else
3514                 r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3515         if (r == 0) {
3516                 ud_run_dpts_pg_set = 1;
3517         } else {
3518                 switch (scf_error()) {
3519                 case SCF_ERROR_NOT_FOUND:
3520                         break;
3521 
3522                 case SCF_ERROR_DELETED:
3523                 case SCF_ERROR_CONNECTION_BROKEN:
3524                         return (scferror2errno(scf_error()));
3525 
3526                 case SCF_ERROR_NOT_SET:
3527                 case SCF_ERROR_INVALID_ARGUMENT:
3528                 case SCF_ERROR_HANDLE_MISMATCH:
3529                 case SCF_ERROR_NOT_BOUND:
3530                 default:
3531                         bad_error(running ? "scf_snaplevel_get_pg" :
3532                             "entity_get_pg", scf_error());
3533                 }
3534         }
3535 
3536         /*
3537          * Clear the seen fields of the dependents, so we can tell which ones
3538          * are new.
3539          */
3540         if (uu_list_walk(ient->sc_dependents, clear_int,
3541             (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3542                 bad_error("uu_list_walk", uu_error());
3543 
3544         if (li_dpts_pg != NULL) {
3545                 /*
3546                  * Each property in li_dpts_pg represents a dependent tag in
3547                  * the old manifest.  For each, call upgrade_dependent(),
3548                  * which will change ud_cur_depts_pg or dependencies in other
3549                  * services as appropriate.  Note (a) that changes to
3550                  * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3551                  * made en masse, and (b) it's ok if the entity doesn't have
3552                  * a current version of the "dependents" property group,
3553                  * because we'll just consider all dependents as customized
3554                  * (by being deleted).
3555                  */
3556 
3557                 if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3558                         switch (scf_error()) {
3559                         case SCF_ERROR_DELETED:
3560                                 return (ENODEV);
3561 
3562                         case SCF_ERROR_CONNECTION_BROKEN:
3563                                 return (ECONNABORTED);
3564 
3565                         case SCF_ERROR_HANDLE_MISMATCH:
3566                         case SCF_ERROR_NOT_BOUND:
3567                         case SCF_ERROR_NOT_SET:
3568                         default:
3569                                 bad_error("scf_iter_pg_properties",
3570                                     scf_error());
3571                         }
3572                 }
3573 
3574                 if (have_cur_depts &&
3575                     scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3576                         switch (scf_error()) {
3577                         case SCF_ERROR_BACKEND_ACCESS:
3578                         case SCF_ERROR_BACKEND_READONLY:
3579                         case SCF_ERROR_CONNECTION_BROKEN:
3580                                 return (scferror2errno(scf_error()));
3581 
3582                         case SCF_ERROR_DELETED:
3583                                 warn(emsg_pg_deleted, ient->sc_fmri,
3584                                     dependents);
3585                                 return (EBUSY);
3586 
3587                         case SCF_ERROR_PERMISSION_DENIED:
3588                                 warn(emsg_pg_mod_perm, dependents,
3589                                     ient->sc_fmri);
3590                                 return (scferror2errno(scf_error()));
3591 
3592                         case SCF_ERROR_HANDLE_MISMATCH:
3593                         case SCF_ERROR_IN_USE:
3594                         case SCF_ERROR_NOT_BOUND:
3595                         case SCF_ERROR_NOT_SET:
3596                         default:
3597                                 bad_error("scf_transaction_start", scf_error());
3598                         }
3599                 }
3600                 tx_started = have_cur_depts;
3601 
3602                 for (;;) {
3603                         r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3604                         if (r == 0)
3605                                 break;
3606                         if (r == 1) {
3607                                 r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3608                                     tx_started ? ud_tx : NULL);
3609                                 switch (r) {
3610                                 case 0:
3611                                         continue;
3612 
3613                                 case ECONNABORTED:
3614                                 case ENOMEM:
3615                                 case ENOSPC:
3616                                 case EBADF:
3617                                 case EBUSY:
3618                                 case EINVAL:
3619                                 case EPERM:
3620                                 case EROFS:
3621                                 case EACCES:
3622                                 case EEXIST:
3623                                         break;
3624 
3625                                 case ECANCELED:
3626                                         r = ENODEV;
3627                                         break;
3628 
3629                                 default:
3630                                         bad_error("upgrade_dependent", r);
3631                                 }
3632 
3633                                 if (tx_started)
3634                                         scf_transaction_destroy_children(ud_tx);
3635                                 return (r);
3636                         }
3637                         if (r != -1)
3638                                 bad_error("scf_iter_next_property", r);
3639 
3640                         switch (scf_error()) {
3641                         case SCF_ERROR_DELETED:
3642                                 r = ENODEV;
3643                                 break;
3644 
3645                         case SCF_ERROR_CONNECTION_BROKEN:
3646                                 r = ECONNABORTED;
3647                                 break;
3648 
3649                         case SCF_ERROR_NOT_SET:
3650                         case SCF_ERROR_INVALID_ARGUMENT:
3651                         case SCF_ERROR_NOT_BOUND:
3652                         case SCF_ERROR_HANDLE_MISMATCH:
3653                         default:
3654                                 bad_error("scf_iter_next_property",
3655                                     scf_error());
3656                         }
3657 
3658                         if (tx_started)
3659                                 scf_transaction_destroy_children(ud_tx);
3660                         return (r);
3661                 }
3662         }
3663 
3664         /* import unseen dependents */
3665         unseen = 0;
3666         for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3667             new_dpt_pgroup != NULL;
3668             new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3669             new_dpt_pgroup)) {
3670                 if (!new_dpt_pgroup->sc_pgroup_seen) {
3671                         unseen = 1;
3672                         break;
3673                 }
3674         }
3675 
3676         /* If there are none, exit early. */
3677         if (unseen == 0)
3678                 goto commit;
3679 
3680         /* Set up for lscf_dependent_import() */
3681         cbdata.sc_handle = g_hndl;
3682         cbdata.sc_parent = ent;
3683         cbdata.sc_service = issvc;
3684         cbdata.sc_flags = 0;
3685 
3686         if (!have_cur_depts) {
3687                 /*
3688                  * We have new dependents to import, so we need a "dependents"
3689                  * property group.
3690                  */
3691                 if (issvc)
3692                         r = scf_service_add_pg(ent, dependents,
3693                             SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3694                 else
3695                         r = scf_instance_add_pg(ent, dependents,
3696                             SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3697                 if (r != 0) {
3698                         switch (scf_error()) {
3699                         case SCF_ERROR_DELETED:
3700                         case SCF_ERROR_CONNECTION_BROKEN:
3701                         case SCF_ERROR_BACKEND_READONLY:
3702                         case SCF_ERROR_BACKEND_ACCESS:
3703                         case SCF_ERROR_NO_RESOURCES:
3704                                 return (scferror2errno(scf_error()));
3705 
3706                         case SCF_ERROR_EXISTS:
3707                                 warn(emsg_pg_added, ient->sc_fmri, dependents);
3708                                 return (EBUSY);
3709 
3710                         case SCF_ERROR_PERMISSION_DENIED:
3711                                 warn(emsg_pg_add_perm, dependents,
3712                                     ient->sc_fmri);
3713                                 return (scferror2errno(scf_error()));
3714 
3715                         case SCF_ERROR_NOT_BOUND:
3716                         case SCF_ERROR_HANDLE_MISMATCH:
3717                         case SCF_ERROR_INVALID_ARGUMENT:
3718                         case SCF_ERROR_NOT_SET:
3719                         default:
3720                                 bad_error("scf_service_add_pg", scf_error());
3721                         }
3722                 }
3723         }
3724 
3725         cbdata.sc_trans = ud_tx;
3726 
3727         if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3728                 switch (scf_error()) {
3729                 case SCF_ERROR_CONNECTION_BROKEN:
3730                 case SCF_ERROR_BACKEND_ACCESS:
3731                 case SCF_ERROR_BACKEND_READONLY:
3732                         return (scferror2errno(scf_error()));
3733 
3734                 case SCF_ERROR_DELETED:
3735                         warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3736                         return (EBUSY);
3737 
3738                 case SCF_ERROR_PERMISSION_DENIED:
3739                         warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3740                         return (scferror2errno(scf_error()));
3741 
3742                 case SCF_ERROR_HANDLE_MISMATCH:
3743                 case SCF_ERROR_IN_USE:
3744                 case SCF_ERROR_NOT_BOUND:
3745                 case SCF_ERROR_NOT_SET:
3746                 default:
3747                         bad_error("scf_transaction_start", scf_error());
3748                 }
3749         }
3750         tx_started = 1;
3751 
3752         for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3753             new_dpt_pgroup != NULL;
3754             new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3755             new_dpt_pgroup)) {
3756                 if (new_dpt_pgroup->sc_pgroup_seen)
3757                         continue;
3758 
3759                 if (ud_run_dpts_pg_set) {
3760                         /*
3761                          * If the dependent is already there, then we have
3762                          * a conflict.
3763                          */
3764                         if (scf_pg_get_property(ud_run_dpts_pg,
3765                             new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3766                                 r = handle_dependent_conflict(ient, ud_prop,
3767                                     new_dpt_pgroup);
3768                                 switch (r) {
3769                                 case 0:
3770                                         continue;
3771 
3772                                 case ECONNABORTED:
3773                                 case ENOMEM:
3774                                 case EBUSY:
3775                                 case EBADF:
3776                                 case EINVAL:
3777                                         scf_transaction_destroy_children(ud_tx);
3778                                         return (r);
3779 
3780                                 default:
3781                                         bad_error("handle_dependent_conflict",
3782                                             r);
3783                                 }
3784                         } else {
3785                                 switch (scf_error()) {
3786                                 case SCF_ERROR_NOT_FOUND:
3787                                         break;
3788 
3789                                 case SCF_ERROR_INVALID_ARGUMENT:
3790                                         warn(emsg_fmri_invalid_pg_name,
3791                                             ient->sc_fmri,
3792                                             new_dpt_pgroup->sc_pgroup_name);
3793                                         scf_transaction_destroy_children(ud_tx);
3794                                         return (EINVAL);
3795 
3796                                 case SCF_ERROR_DELETED:
3797                                         warn(emsg_pg_deleted, ient->sc_fmri,
3798                                             new_dpt_pgroup->sc_pgroup_name);
3799                                         scf_transaction_destroy_children(ud_tx);
3800                                         return (EBUSY);
3801 
3802                                 case SCF_ERROR_CONNECTION_BROKEN:
3803                                         scf_transaction_destroy_children(ud_tx);
3804                                         return (ECONNABORTED);
3805 
3806                                 case SCF_ERROR_NOT_BOUND:
3807                                 case SCF_ERROR_HANDLE_MISMATCH:
3808                                 case SCF_ERROR_NOT_SET:
3809                                 default:
3810                                         bad_error("scf_pg_get_property",
3811                                             scf_error());
3812                                 }
3813                         }
3814                 }
3815 
3816                 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3817                 if (r != UU_WALK_NEXT) {
3818                         if (r != UU_WALK_ERROR)
3819                                 bad_error("lscf_dependent_import", r);
3820 
3821                         if (cbdata.sc_err == EALREADY) {
3822                                 /* Collisions were handled preemptively. */
3823                                 bad_error("lscf_dependent_import",
3824                                     cbdata.sc_err);
3825                         }
3826 
3827                         scf_transaction_destroy_children(ud_tx);
3828                         return (cbdata.sc_err);
3829                 }
3830         }
3831 
3832 commit:
3833         if (!tx_started)
3834                 return (0);
3835 
3836         r = scf_transaction_commit(ud_tx);
3837 
3838         scf_transaction_destroy_children(ud_tx);
3839 
3840         switch (r) {
3841         case 1:
3842                 return (0);
3843 
3844         case 0:
3845                 warn(emsg_pg_changed, ient->sc_fmri, dependents);
3846                 return (EBUSY);
3847 
3848         case -1:
3849                 break;
3850 
3851         default:
3852                 bad_error("scf_transaction_commit", r);
3853         }
3854 
3855         switch (scf_error()) {
3856         case SCF_ERROR_CONNECTION_BROKEN:
3857         case SCF_ERROR_BACKEND_READONLY:
3858         case SCF_ERROR_BACKEND_ACCESS:
3859         case SCF_ERROR_NO_RESOURCES:
3860                 return (scferror2errno(scf_error()));
3861 
3862         case SCF_ERROR_DELETED:
3863                 warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3864                 return (EBUSY);
3865 
3866         case SCF_ERROR_PERMISSION_DENIED:
3867                 warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3868                 return (scferror2errno(scf_error()));
3869 
3870         case SCF_ERROR_NOT_BOUND:
3871         case SCF_ERROR_INVALID_ARGUMENT:
3872         case SCF_ERROR_NOT_SET:
3873         default:
3874                 bad_error("scf_transaction_destroy", scf_error());
3875                 /* NOTREACHED */
3876         }
3877 }
3878 
3879 /*
3880  * Used to add the manifests to the list of currently supported manifests.
3881  * We can modify the existing manifest list removing entries if the files
3882  * don't exist.
3883  *
3884  * Get the old list and the new file name
3885  * If the new file name is in the list return
3886  * If not then add the file to the list.
3887  * As we process the list check to see if the files in the old list exist
3888  *      if not then remove the file from the list.
3889  * Commit the list of manifest file names.
3890  *
3891  */
3892 static int
3893 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3894     const scf_snaplevel_t *running, void *ent)
3895 {
3896         scf_propertygroup_t *ud_mfsts_pg = NULL;
3897         scf_property_t *ud_prop = NULL;
3898         scf_iter_t *ud_prop_iter;
3899         scf_value_t *fname_value;
3900         scf_callback_t cbdata;
3901         pgroup_t *mfst_pgroup;
3902         property_t *mfst_prop;
3903         property_t *old_prop;
3904         char *pname;
3905         char *fval;
3906         char *old_pname;
3907         char *old_fval;
3908         int no_upgrade_pg;
3909         int mfst_seen;
3910         int r;
3911 
3912         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3913 
3914         /*
3915          * This should always be the service base on the code
3916          * path, and the fact that the manifests pg is a service
3917          * level property group only.
3918          */
3919         ud_mfsts_pg = scf_pg_create(g_hndl);
3920         ud_prop = scf_property_create(g_hndl);
3921         ud_prop_iter = scf_iter_create(g_hndl);
3922         fname_value = scf_value_create(g_hndl);
3923 
3924         /* Fetch the "manifests" property group */
3925         no_upgrade_pg = 0;
3926         r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3927             ud_mfsts_pg);
3928         if (r != 0) {
3929                 switch (scf_error()) {
3930                 case SCF_ERROR_NOT_FOUND:
3931                         no_upgrade_pg = 1;
3932                         break;
3933 
3934                 case SCF_ERROR_DELETED:
3935                 case SCF_ERROR_CONNECTION_BROKEN:
3936                         return (scferror2errno(scf_error()));
3937 
3938                 case SCF_ERROR_NOT_SET:
3939                 case SCF_ERROR_INVALID_ARGUMENT:
3940                 case SCF_ERROR_HANDLE_MISMATCH:
3941                 case SCF_ERROR_NOT_BOUND:
3942                 default:
3943                         bad_error(running ? "scf_snaplevel_get_pg" :
3944                             "entity_get_pg", scf_error());
3945                 }
3946         }
3947 
3948         if (no_upgrade_pg) {
3949                 cbdata.sc_handle = g_hndl;
3950                 cbdata.sc_parent = ent;
3951                 cbdata.sc_service = issvc;
3952                 cbdata.sc_flags = SCI_FORCE;
3953                 cbdata.sc_source_fmri = ient->sc_fmri;
3954                 cbdata.sc_target_fmri = ient->sc_fmri;
3955 
3956                 if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3957                         return (cbdata.sc_err);
3958 
3959                 return (0);
3960         }
3961 
3962         /* Fetch the new manifests property group */
3963         for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3964             mfst_pgroup != NULL;
3965             mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3966                 if (strcmp(mfst_pgroup->sc_pgroup_name,
3967                     SCF_PG_MANIFESTFILES) == 0)
3968                         break;
3969         }
3970 
3971         if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3972             SCF_SUCCESS)
3973                 return (-1);
3974 
3975         if ((pname = malloc(MAXPATHLEN)) == NULL)
3976                 return (ENOMEM);
3977         if ((fval = malloc(MAXPATHLEN)) == NULL) {
3978                 free(pname);
3979                 return (ENOMEM);
3980         }
3981 
3982         while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3983                 mfst_seen = 0;
3984                 if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3985                         continue;
3986 
3987                 for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3988                     mfst_prop != NULL;
3989                     mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3990                     mfst_prop)) {
3991                         if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3992                                 mfst_seen = 1;
3993                         }
3994                 }
3995 
3996                 /*
3997                  * If the manifest is not seen then add it to the new mfst
3998                  * property list to get proccessed into the repo.
3999                  */
4000                 if (mfst_seen == 0) {
4001                         /*
4002                          * If we cannot get the value then there is no
4003                          * reason to attempt to attach the value to
4004                          * the property group
4005                          */
4006                         if (prop_get_val(ud_prop, fname_value) == 0 &&
4007                             scf_value_get_astring(fname_value, fval,
4008                             MAXPATHLEN) != -1)  {
4009                                 old_pname = safe_strdup(pname);
4010                                 old_fval = safe_strdup(fval);
4011                                 old_prop = internal_property_create(old_pname,
4012                                     SCF_TYPE_ASTRING, 1, old_fval);
4013 
4014                                 /*
4015                                  * Already checked to see if the property exists
4016                                  * in the group, and it does not.
4017                                  */
4018                                 (void) internal_attach_property(mfst_pgroup,
4019                                     old_prop);
4020                         }
4021                 }
4022         }
4023         free(pname);
4024         free(fval);
4025 
4026         cbdata.sc_handle = g_hndl;
4027         cbdata.sc_parent = ent;
4028         cbdata.sc_service = issvc;
4029         cbdata.sc_flags = SCI_FORCE;
4030         cbdata.sc_source_fmri = ient->sc_fmri;
4031         cbdata.sc_target_fmri = ient->sc_fmri;
4032 
4033         if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4034                 return (cbdata.sc_err);
4035 
4036         return (r);
4037 }
4038 
4039 /*
4040  * prop is taken to be a property in the "dependents" property group of snpl,
4041  * which is taken to be the snaplevel of a last-import snapshot corresponding
4042  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4043  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4044  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4045  * of the entity ient represents (possibly in the running snapshot).  If it
4046  * needs to be changed, an entry will be added to tx, if not NULL.
4047  *
4048  * Returns
4049  *   0 - success
4050  *   ECONNABORTED - repository connection broken
4051  *   ENOMEM - out of memory
4052  *   ENOSPC - configd was out of resources
4053  *   ECANCELED - snpl's entity was deleted
4054  *   EINVAL - dependent target is invalid (error printed)
4055  *          - dependent is invalid (error printed)
4056  *   EBADF - snpl is corrupt (error printed)
4057  *         - snpl has corrupt pg (error printed)
4058  *         - dependency pg in target is corrupt (error printed)
4059  *         - running snapshot in dependent is missing snaplevel (error printed)
4060  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4061  *         - couldn't create dependent (permission denied) (error printed)
4062  *         - couldn't modify dependent pg (permission denied) (error printed)
4063  *   EROFS - couldn't delete dependency pg (repository read-only)
4064  *         - couldn't create dependent (repository read-only)
4065  *   EACCES - couldn't delete dependency pg (backend access denied)
4066  *          - couldn't create dependent (backend access denied)
4067  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4068  *         - tx's pg was deleted (error printed)
4069  *         - dependent pg was changed or deleted (error printed)
4070  *   EEXIST - dependency pg already exists in new target (error printed)
4071  */
4072 static int
4073 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4074     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4075 {
4076         pgroup_t pgrp;
4077         scf_type_t ty;
4078         pgroup_t *new_dpt_pgroup;
4079         pgroup_t *old_dpt_pgroup = NULL;
4080         pgroup_t *current_pg;
4081         pgroup_t *dpt;
4082         scf_callback_t cbdata;
4083         int tissvc;
4084         void *target_ent;
4085         scf_error_t serr;
4086         int r;
4087         scf_transaction_entry_t *ent;
4088 
4089         const char * const cf_inval = gettext("Conflict upgrading %s "
4090             "(dependent \"%s\" has invalid dependents property).\n");
4091         const char * const cf_missing = gettext("Conflict upgrading %s "
4092             "(dependent \"%s\" is missing).\n");
4093         const char * const cf_newdpg = gettext("Conflict upgrading %s "
4094             "(dependent \"%s\" has new dependency property group).\n");
4095         const char * const cf_newtarg = gettext("Conflict upgrading %s "
4096             "(dependent \"%s\" has new target).\n");
4097         const char * const li_corrupt =
4098             gettext("%s: \"last-import\" snapshot is corrupt.\n");
4099         const char * const upgrading =
4100             gettext("%s: Upgrading dependent \"%s\".\n");
4101         const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4102             "corrupt (missing snaplevel).\n");
4103 
4104         if (scf_property_type(prop, &ty) != 0) {
4105                 switch (scf_error()) {
4106                 case SCF_ERROR_DELETED:
4107                 case SCF_ERROR_CONNECTION_BROKEN:
4108                         return (scferror2errno(scf_error()));
4109 
4110                 case SCF_ERROR_NOT_BOUND:
4111                 case SCF_ERROR_NOT_SET:
4112                 default:
4113                         bad_error("scf_property_type", scf_error());
4114                 }
4115         }
4116 
4117         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4118                 warn(li_corrupt, ient->sc_fmri);
4119                 return (EBADF);
4120         }
4121 
4122         /*
4123          * prop represents a dependent in the old manifest.  It is named after
4124          * the dependent.
4125          */
4126         if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4127                 switch (scf_error()) {
4128                 case SCF_ERROR_DELETED:
4129                 case SCF_ERROR_CONNECTION_BROKEN:
4130                         return (scferror2errno(scf_error()));
4131 
4132                 case SCF_ERROR_NOT_BOUND:
4133                 case SCF_ERROR_NOT_SET:
4134                 default:
4135                         bad_error("scf_property_get_name", scf_error());
4136                 }
4137         }
4138 
4139         /* See if it's in the new manifest. */
4140         pgrp.sc_pgroup_name = ud_name;
4141         new_dpt_pgroup =
4142             uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4143 
4144         /* If it's not, delete it... if it hasn't been customized. */
4145         if (new_dpt_pgroup == NULL) {
4146                 if (!ud_run_dpts_pg_set)
4147                         return (0);
4148 
4149                 if (scf_property_get_value(prop, ud_val) != 0) {
4150                         switch (scf_error()) {
4151                         case SCF_ERROR_NOT_FOUND:
4152                         case SCF_ERROR_CONSTRAINT_VIOLATED:
4153                                 warn(li_corrupt, ient->sc_fmri);
4154                                 return (EBADF);
4155 
4156                         case SCF_ERROR_DELETED:
4157                         case SCF_ERROR_CONNECTION_BROKEN:
4158                                 return (scferror2errno(scf_error()));
4159 
4160                         case SCF_ERROR_HANDLE_MISMATCH:
4161                         case SCF_ERROR_NOT_BOUND:
4162                         case SCF_ERROR_NOT_SET:
4163                         case SCF_ERROR_PERMISSION_DENIED:
4164                         default:
4165                                 bad_error("scf_property_get_value",
4166                                     scf_error());
4167                         }
4168                 }
4169 
4170                 if (scf_value_get_as_string(ud_val, ud_oldtarg,
4171                     max_scf_value_len + 1) < 0)
4172                         bad_error("scf_value_get_as_string", scf_error());
4173 
4174                 if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4175                     0) {
4176                         switch (scf_error()) {
4177                         case SCF_ERROR_NOT_FOUND:
4178                                 return (0);
4179 
4180                         case SCF_ERROR_CONNECTION_BROKEN:
4181                                 return (scferror2errno(scf_error()));
4182 
4183                         case SCF_ERROR_DELETED:
4184                                 warn(emsg_pg_deleted, ient->sc_fmri,
4185                                     "dependents");
4186                                 return (EBUSY);
4187 
4188                         case SCF_ERROR_INVALID_ARGUMENT:
4189                         case SCF_ERROR_NOT_BOUND:
4190                         case SCF_ERROR_HANDLE_MISMATCH:
4191                         case SCF_ERROR_NOT_SET:
4192                         default:
4193                                 bad_error("scf_pg_get_property", scf_error());
4194                         }
4195                 }
4196                 if (scf_property_get_value(ud_prop, ud_val) != 0) {
4197                         switch (scf_error()) {
4198                         case SCF_ERROR_NOT_FOUND:
4199                         case SCF_ERROR_CONSTRAINT_VIOLATED:
4200                                 warn(cf_inval, ient->sc_fmri, ud_name);
4201                                 return (0);
4202 
4203                         case SCF_ERROR_DELETED:
4204                         case SCF_ERROR_CONNECTION_BROKEN:
4205                                 return (scferror2errno(scf_error()));
4206 
4207                         case SCF_ERROR_HANDLE_MISMATCH:
4208                         case SCF_ERROR_NOT_BOUND:
4209                         case SCF_ERROR_NOT_SET:
4210                         case SCF_ERROR_PERMISSION_DENIED:
4211                         default:
4212                                 bad_error("scf_property_get_value",
4213                                     scf_error());
4214                         }
4215                 }
4216 
4217                 ty = scf_value_type(ud_val);
4218                 assert(ty != SCF_TYPE_INVALID);
4219                 if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4220                         warn(cf_inval, ient->sc_fmri, ud_name);
4221                         return (0);
4222                 }
4223 
4224                 if (scf_value_get_as_string(ud_val, ud_ctarg,
4225                     max_scf_value_len + 1) < 0)
4226                         bad_error("scf_value_get_as_string", scf_error());
4227 
4228                 r = fmri_equal(ud_ctarg, ud_oldtarg);
4229                 switch (r) {
4230                 case 1:
4231                         break;
4232 
4233                 case 0:
4234                 case -1:        /* warn? */
4235                         warn(cf_newtarg, ient->sc_fmri, ud_name);
4236                         return (0);
4237 
4238                 case -2:
4239                         warn(li_corrupt, ient->sc_fmri);
4240                         return (EBADF);
4241 
4242                 default:
4243                         bad_error("fmri_equal", r);
4244                 }
4245 
4246                 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4247                         switch (scf_error()) {
4248                         case SCF_ERROR_NOT_FOUND:
4249                                 warn(li_corrupt, ient->sc_fmri);
4250                                 return (EBADF);
4251 
4252                         case SCF_ERROR_DELETED:
4253                         case SCF_ERROR_CONNECTION_BROKEN:
4254                                 return (scferror2errno(scf_error()));
4255 
4256                         case SCF_ERROR_NOT_BOUND:
4257                         case SCF_ERROR_HANDLE_MISMATCH:
4258                         case SCF_ERROR_INVALID_ARGUMENT:
4259                         case SCF_ERROR_NOT_SET:
4260                         default:
4261                                 bad_error("scf_snaplevel_get_pg", scf_error());
4262                         }
4263                 }
4264 
4265                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4266                     snap_lastimport);
4267                 switch (r) {
4268                 case 0:
4269                         break;
4270 
4271                 case ECANCELED:
4272                 case ECONNABORTED:
4273                 case ENOMEM:
4274                 case EBADF:
4275                         return (r);
4276 
4277                 case EACCES:
4278                 default:
4279                         bad_error("load_pg", r);
4280                 }
4281 
4282                 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4283                 switch (serr) {
4284                 case SCF_ERROR_NONE:
4285                         break;
4286 
4287                 case SCF_ERROR_NO_MEMORY:
4288                         internal_pgroup_free(old_dpt_pgroup);
4289                         return (ENOMEM);
4290 
4291                 case SCF_ERROR_NOT_FOUND:
4292                         internal_pgroup_free(old_dpt_pgroup);
4293                         goto delprop;
4294 
4295                 case SCF_ERROR_CONSTRAINT_VIOLATED:     /* caught above */
4296                 case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
4297                 default:
4298                         bad_error("fmri_to_entity", serr);
4299                 }
4300 
4301                 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4302                     ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4303                 switch (r) {
4304                 case 0:
4305                         break;
4306 
4307                 case ECONNABORTED:
4308                         internal_pgroup_free(old_dpt_pgroup);
4309                         return (r);
4310 
4311                 case ECANCELED:
4312                 case ENOENT:
4313                         internal_pgroup_free(old_dpt_pgroup);
4314                         goto delprop;
4315 
4316                 case EBADF:
4317                         warn(r_no_lvl, ud_ctarg);
4318                         internal_pgroup_free(old_dpt_pgroup);
4319                         return (r);
4320 
4321                 case EINVAL:
4322                 default:
4323                         bad_error("entity_get_running_pg", r);
4324                 }
4325 
4326                 /* load it */
4327                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4328                 switch (r) {
4329                 case 0:
4330                         break;
4331 
4332                 case ECANCELED:
4333                         internal_pgroup_free(old_dpt_pgroup);
4334                         goto delprop;
4335 
4336                 case ECONNABORTED:
4337                 case ENOMEM:
4338                 case EBADF:
4339                         internal_pgroup_free(old_dpt_pgroup);
4340                         return (r);
4341 
4342                 case EACCES:
4343                 default:
4344                         bad_error("load_pg", r);
4345                 }
4346 
4347                 /* compare property groups */
4348                 if (!pg_equal(old_dpt_pgroup, current_pg)) {
4349                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4350                         internal_pgroup_free(old_dpt_pgroup);
4351                         internal_pgroup_free(current_pg);
4352                         return (0);
4353                 }
4354 
4355                 internal_pgroup_free(old_dpt_pgroup);
4356                 internal_pgroup_free(current_pg);
4357 
4358                 if (g_verbose)
4359                         warn(gettext("%s: Deleting dependent \"%s\".\n"),
4360                             ient->sc_fmri, ud_name);
4361 
4362                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4363                         switch (scf_error()) {
4364                         case SCF_ERROR_NOT_FOUND:
4365                         case SCF_ERROR_DELETED:
4366                                 internal_pgroup_free(old_dpt_pgroup);
4367                                 goto delprop;
4368 
4369                         case SCF_ERROR_CONNECTION_BROKEN:
4370                                 internal_pgroup_free(old_dpt_pgroup);
4371                                 return (ECONNABORTED);
4372 
4373                         case SCF_ERROR_NOT_SET:
4374                         case SCF_ERROR_INVALID_ARGUMENT:
4375                         case SCF_ERROR_HANDLE_MISMATCH:
4376                         case SCF_ERROR_NOT_BOUND:
4377                         default:
4378                                 bad_error("entity_get_pg", scf_error());
4379                         }
4380                 }
4381 
4382                 if (scf_pg_delete(ud_pg) != 0) {
4383                         switch (scf_error()) {
4384                         case SCF_ERROR_DELETED:
4385                                 break;
4386 
4387                         case SCF_ERROR_CONNECTION_BROKEN:
4388                         case SCF_ERROR_BACKEND_READONLY:
4389                         case SCF_ERROR_BACKEND_ACCESS:
4390                                 return (scferror2errno(scf_error()));
4391 
4392                         case SCF_ERROR_PERMISSION_DENIED:
4393                                 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4394                                 return (scferror2errno(scf_error()));
4395 
4396                         case SCF_ERROR_NOT_SET:
4397                         default:
4398                                 bad_error("scf_pg_delete", scf_error());
4399                         }
4400                 }
4401 
4402                 /*
4403                  * This service was changed, so it must be refreshed.  But
4404                  * since it's not mentioned in the new manifest, we have to
4405                  * record its FMRI here for use later.  We record the name
4406                  * & the entity (via sc_parent) in case we need to print error
4407                  * messages during the refresh.
4408                  */
4409                 dpt = internal_pgroup_new();
4410                 if (dpt == NULL)
4411                         return (ENOMEM);
4412                 dpt->sc_pgroup_name = strdup(ud_name);
4413                 dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4414                 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4415                         return (ENOMEM);
4416                 dpt->sc_parent = (entity_t *)ient;
4417                 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4418                         uu_die(gettext("libuutil error: %s\n"),
4419                             uu_strerror(uu_error()));
4420 
4421 delprop:
4422                 if (tx == NULL)
4423                         return (0);
4424 
4425                 ent = scf_entry_create(g_hndl);
4426                 if (ent == NULL)
4427                         return (ENOMEM);
4428 
4429                 if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4430                         scf_entry_destroy(ent);
4431                         switch (scf_error()) {
4432                         case SCF_ERROR_DELETED:
4433                                 warn(emsg_pg_deleted, ient->sc_fmri,
4434                                     "dependents");
4435                                 return (EBUSY);
4436 
4437                         case SCF_ERROR_CONNECTION_BROKEN:
4438                                 return (scferror2errno(scf_error()));
4439 
4440                         case SCF_ERROR_NOT_FOUND:
4441                                 break;
4442 
4443                         case SCF_ERROR_HANDLE_MISMATCH:
4444                         case SCF_ERROR_NOT_BOUND:
4445                         case SCF_ERROR_INVALID_ARGUMENT:
4446                         case SCF_ERROR_NOT_SET:
4447                         default:
4448                                 bad_error("scf_transaction_property_delete",
4449                                     scf_error());
4450                         }
4451                 }
4452 
4453                 return (0);
4454         }
4455 
4456         new_dpt_pgroup->sc_pgroup_seen = 1;
4457 
4458         /*
4459          * Decide whether the dependent has changed in the manifest.
4460          */
4461         /* Compare the target. */
4462         if (scf_property_get_value(prop, ud_val) != 0) {
4463                 switch (scf_error()) {
4464                 case SCF_ERROR_NOT_FOUND:
4465                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4466                         warn(li_corrupt, ient->sc_fmri);
4467                         return (EBADF);
4468 
4469                 case SCF_ERROR_DELETED:
4470                 case SCF_ERROR_CONNECTION_BROKEN:
4471                         return (scferror2errno(scf_error()));
4472 
4473                 case SCF_ERROR_HANDLE_MISMATCH:
4474                 case SCF_ERROR_NOT_BOUND:
4475                 case SCF_ERROR_NOT_SET:
4476                 case SCF_ERROR_PERMISSION_DENIED:
4477                 default:
4478                         bad_error("scf_property_get_value", scf_error());
4479                 }
4480         }
4481 
4482         if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4483             0)
4484                 bad_error("scf_value_get_as_string", scf_error());
4485 
4486         /*
4487          * If the fmri's are not equal then the old fmri will need to
4488          * be refreshed to ensure that the changes are properly updated
4489          * in that service.
4490          */
4491         r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4492         switch (r) {
4493         case 0:
4494                 dpt = internal_pgroup_new();
4495                 if (dpt == NULL)
4496                         return (ENOMEM);
4497                 dpt->sc_pgroup_name = strdup(ud_name);
4498                 dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4499                 if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4500                         return (ENOMEM);
4501                 dpt->sc_parent = (entity_t *)ient;
4502                 if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4503                         uu_die(gettext("libuutil error: %s\n"),
4504                             uu_strerror(uu_error()));
4505                 break;
4506 
4507         case 1:
4508                 /* Compare the dependency pgs. */
4509                 if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4510                         switch (scf_error()) {
4511                         case SCF_ERROR_NOT_FOUND:
4512                                 warn(li_corrupt, ient->sc_fmri);
4513                                 return (EBADF);
4514 
4515                         case SCF_ERROR_DELETED:
4516                         case SCF_ERROR_CONNECTION_BROKEN:
4517                                 return (scferror2errno(scf_error()));
4518 
4519                         case SCF_ERROR_NOT_BOUND:
4520                         case SCF_ERROR_HANDLE_MISMATCH:
4521                         case SCF_ERROR_INVALID_ARGUMENT:
4522                         case SCF_ERROR_NOT_SET:
4523                         default:
4524                                 bad_error("scf_snaplevel_get_pg", scf_error());
4525                         }
4526                 }
4527 
4528                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4529                     snap_lastimport);
4530                 switch (r) {
4531                 case 0:
4532                         break;
4533 
4534                 case ECANCELED:
4535                 case ECONNABORTED:
4536                 case ENOMEM:
4537                 case EBADF:
4538                         return (r);
4539 
4540                 case EACCES:
4541                 default:
4542                         bad_error("load_pg", r);
4543                 }
4544 
4545                 if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4546                         /* no change, leave customizations */
4547                         internal_pgroup_free(old_dpt_pgroup);
4548                         return (0);
4549                 }
4550                 break;
4551 
4552         case -1:
4553                 warn(li_corrupt, ient->sc_fmri);
4554                 return (EBADF);
4555 
4556         case -2:
4557                 warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4558                     ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4559                 return (EINVAL);
4560 
4561         default:
4562                 bad_error("fmri_equal", r);
4563         }
4564 
4565         /*
4566          * The dependent has changed in the manifest.  Upgrade the current
4567          * properties if they haven't been customized.
4568          */
4569 
4570         /*
4571          * If new_dpt_pgroup->sc_override, then act as though the property
4572          * group hasn't been customized.
4573          */
4574         if (new_dpt_pgroup->sc_pgroup_override) {
4575                 (void) strcpy(ud_ctarg, ud_oldtarg);
4576                 goto nocust;
4577         }
4578 
4579         if (!ud_run_dpts_pg_set) {
4580                 warn(cf_missing, ient->sc_fmri, ud_name);
4581                 r = 0;
4582                 goto out;
4583         } else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4584                 switch (scf_error()) {
4585                 case SCF_ERROR_NOT_FOUND:
4586                         warn(cf_missing, ient->sc_fmri, ud_name);
4587                         r = 0;
4588                         goto out;
4589 
4590                 case SCF_ERROR_CONNECTION_BROKEN:
4591                         r = scferror2errno(scf_error());
4592                         goto out;
4593 
4594                 case SCF_ERROR_DELETED:
4595                         warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4596                         r = EBUSY;
4597                         goto out;
4598 
4599                 case SCF_ERROR_INVALID_ARGUMENT:
4600                 case SCF_ERROR_NOT_BOUND:
4601                 case SCF_ERROR_HANDLE_MISMATCH:
4602                 case SCF_ERROR_NOT_SET:
4603                 default:
4604                         bad_error("scf_pg_get_property", scf_error());
4605                 }
4606         }
4607 
4608         if (scf_property_get_value(ud_prop, ud_val) != 0) {
4609                 switch (scf_error()) {
4610                 case SCF_ERROR_NOT_FOUND:
4611                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4612                         warn(cf_inval, ient->sc_fmri, ud_name);
4613                         r = 0;
4614                         goto out;
4615 
4616                 case SCF_ERROR_DELETED:
4617                 case SCF_ERROR_CONNECTION_BROKEN:
4618                         r = scferror2errno(scf_error());
4619                         goto out;
4620 
4621                 case SCF_ERROR_HANDLE_MISMATCH:
4622                 case SCF_ERROR_NOT_BOUND:
4623                 case SCF_ERROR_NOT_SET:
4624                 case SCF_ERROR_PERMISSION_DENIED:
4625                 default:
4626                         bad_error("scf_property_get_value", scf_error());
4627                 }
4628         }
4629 
4630         ty = scf_value_type(ud_val);
4631         assert(ty != SCF_TYPE_INVALID);
4632         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4633                 warn(cf_inval, ient->sc_fmri, ud_name);
4634                 r = 0;
4635                 goto out;
4636         }
4637         if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4638             0)
4639                 bad_error("scf_value_get_as_string", scf_error());
4640 
4641         r = fmri_equal(ud_ctarg, ud_oldtarg);
4642         if (r == -1) {
4643                 warn(cf_inval, ient->sc_fmri, ud_name);
4644                 r = 0;
4645                 goto out;
4646         } else if (r == -2) {
4647                 warn(li_corrupt, ient->sc_fmri);
4648                 r = EBADF;
4649                 goto out;
4650         } else if (r == 0) {
4651                 /*
4652                  * Target has been changed.  Only abort now if it's been
4653                  * changed to something other than what's in the manifest.
4654                  */
4655                 r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4656                 if (r == -1) {
4657                         warn(cf_inval, ient->sc_fmri, ud_name);
4658                         r = 0;
4659                         goto out;
4660                 } else if (r == 0) {
4661                         warn(cf_newtarg, ient->sc_fmri, ud_name);
4662                         r = 0;
4663                         goto out;
4664                 } else if (r != 1) {
4665                         /* invalid sc_pgroup_fmri caught above */
4666                         bad_error("fmri_equal", r);
4667                 }
4668 
4669                 /*
4670                  * Fetch the current dependency pg.  If it's what the manifest
4671                  * says, then no problem.
4672                  */
4673                 serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4674                 switch (serr) {
4675                 case SCF_ERROR_NONE:
4676                         break;
4677 
4678                 case SCF_ERROR_NOT_FOUND:
4679                         warn(cf_missing, ient->sc_fmri, ud_name);
4680                         r = 0;
4681                         goto out;
4682 
4683                 case SCF_ERROR_NO_MEMORY:
4684                         r = ENOMEM;
4685                         goto out;
4686 
4687                 case SCF_ERROR_CONSTRAINT_VIOLATED:
4688                 case SCF_ERROR_INVALID_ARGUMENT:
4689                 default:
4690                         bad_error("fmri_to_entity", serr);
4691                 }
4692 
4693                 r = entity_get_running_pg(target_ent, tissvc, ud_name,
4694                     ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4695                 switch (r) {
4696                 case 0:
4697                         break;
4698 
4699                 case ECONNABORTED:
4700                         goto out;
4701 
4702                 case ECANCELED:
4703                 case ENOENT:
4704                         warn(cf_missing, ient->sc_fmri, ud_name);
4705                         r = 0;
4706                         goto out;
4707 
4708                 case EBADF:
4709                         warn(r_no_lvl, ud_ctarg);
4710                         goto out;
4711 
4712                 case EINVAL:
4713                 default:
4714                         bad_error("entity_get_running_pg", r);
4715                 }
4716 
4717                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4718                 switch (r) {
4719                 case 0:
4720                         break;
4721 
4722                 case ECANCELED:
4723                         warn(cf_missing, ient->sc_fmri, ud_name);
4724                         r = 0;
4725                         goto out;
4726 
4727                 case ECONNABORTED:
4728                 case ENOMEM:
4729                 case EBADF:
4730                         goto out;
4731 
4732                 case EACCES:
4733                 default:
4734                         bad_error("load_pg", r);
4735                 }
4736 
4737                 if (!pg_equal(current_pg, new_dpt_pgroup))
4738                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4739                 internal_pgroup_free(current_pg);
4740                 r = 0;
4741                 goto out;
4742         } else if (r != 1) {
4743                 bad_error("fmri_equal", r);
4744         }
4745 
4746 nocust:
4747         /*
4748          * Target has not been customized.  Check the dependency property
4749          * group.
4750          */
4751 
4752         if (old_dpt_pgroup == NULL) {
4753                 if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4754                     ud_pg) != 0) {
4755                         switch (scf_error()) {
4756                         case SCF_ERROR_NOT_FOUND:
4757                                 warn(li_corrupt, ient->sc_fmri);
4758                                 return (EBADF);
4759 
4760                         case SCF_ERROR_DELETED:
4761                         case SCF_ERROR_CONNECTION_BROKEN:
4762                                 return (scferror2errno(scf_error()));
4763 
4764                         case SCF_ERROR_NOT_BOUND:
4765                         case SCF_ERROR_HANDLE_MISMATCH:
4766                         case SCF_ERROR_INVALID_ARGUMENT:
4767                         case SCF_ERROR_NOT_SET:
4768                         default:
4769                                 bad_error("scf_snaplevel_get_pg", scf_error());
4770                         }
4771                 }
4772 
4773                 r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4774                     snap_lastimport);
4775                 switch (r) {
4776                 case 0:
4777                         break;
4778 
4779                 case ECANCELED:
4780                 case ECONNABORTED:
4781                 case ENOMEM:
4782                 case EBADF:
4783                         return (r);
4784 
4785                 case EACCES:
4786                 default:
4787                         bad_error("load_pg", r);
4788                 }
4789         }
4790         serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4791         switch (serr) {
4792         case SCF_ERROR_NONE:
4793                 break;
4794 
4795         case SCF_ERROR_NOT_FOUND:
4796                 warn(cf_missing, ient->sc_fmri, ud_name);
4797                 r = 0;
4798                 goto out;
4799 
4800         case SCF_ERROR_NO_MEMORY:
4801                 r = ENOMEM;
4802                 goto out;
4803 
4804         case SCF_ERROR_CONSTRAINT_VIOLATED:
4805         case SCF_ERROR_INVALID_ARGUMENT:
4806         default:
4807                 bad_error("fmri_to_entity", serr);
4808         }
4809 
4810         r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4811             ud_iter2, ud_inst, imp_snap, ud_snpl);
4812         switch (r) {
4813         case 0:
4814                 break;
4815 
4816         case ECONNABORTED:
4817                 goto out;
4818 
4819         case ECANCELED:
4820         case ENOENT:
4821                 warn(cf_missing, ient->sc_fmri, ud_name);
4822                 r = 0;
4823                 goto out;
4824 
4825         case EBADF:
4826                 warn(r_no_lvl, ud_ctarg);
4827                 goto out;
4828 
4829         case EINVAL:
4830         default:
4831                 bad_error("entity_get_running_pg", r);
4832         }
4833 
4834         r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4835         switch (r) {
4836         case 0:
4837                 break;
4838 
4839         case ECANCELED:
4840                 warn(cf_missing, ient->sc_fmri, ud_name);
4841                 goto out;
4842 
4843         case ECONNABORTED:
4844         case ENOMEM:
4845         case EBADF:
4846                 goto out;
4847 
4848         case EACCES:
4849         default:
4850                 bad_error("load_pg", r);
4851         }
4852 
4853         if (!pg_equal(current_pg, old_dpt_pgroup)) {
4854                 if (!pg_equal(current_pg, new_dpt_pgroup))
4855                         warn(cf_newdpg, ient->sc_fmri, ud_name);
4856                 internal_pgroup_free(current_pg);
4857                 r = 0;
4858                 goto out;
4859         }
4860 
4861         /* Uncustomized.  Upgrade. */
4862 
4863         r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4864         switch (r) {
4865         case 1:
4866                 if (pg_equal(current_pg, new_dpt_pgroup)) {
4867                         /* Already upgraded. */
4868                         internal_pgroup_free(current_pg);
4869                         r = 0;
4870                         goto out;
4871                 }
4872 
4873                 internal_pgroup_free(current_pg);
4874 
4875                 /* upgrade current_pg */
4876                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4877                         switch (scf_error()) {
4878                         case SCF_ERROR_CONNECTION_BROKEN:
4879                                 r = scferror2errno(scf_error());
4880                                 goto out;
4881 
4882                         case SCF_ERROR_DELETED:
4883                                 warn(cf_missing, ient->sc_fmri, ud_name);
4884                                 r = 0;
4885                                 goto out;
4886 
4887                         case SCF_ERROR_NOT_FOUND:
4888                                 break;
4889 
4890                         case SCF_ERROR_INVALID_ARGUMENT:
4891                         case SCF_ERROR_NOT_BOUND:
4892                         case SCF_ERROR_NOT_SET:
4893                         case SCF_ERROR_HANDLE_MISMATCH:
4894                         default:
4895                                 bad_error("entity_get_pg", scf_error());
4896                         }
4897 
4898                         if (tissvc)
4899                                 r = scf_service_add_pg(target_ent, ud_name,
4900                                     SCF_GROUP_DEPENDENCY, 0, ud_pg);
4901                         else
4902                                 r = scf_instance_add_pg(target_ent, ud_name,
4903                                     SCF_GROUP_DEPENDENCY, 0, ud_pg);
4904                         if (r != 0) {
4905                                 switch (scf_error()) {
4906                                 case SCF_ERROR_CONNECTION_BROKEN:
4907                                 case SCF_ERROR_NO_RESOURCES:
4908                                 case SCF_ERROR_BACKEND_READONLY:
4909                                 case SCF_ERROR_BACKEND_ACCESS:
4910                                         r = scferror2errno(scf_error());
4911                                         goto out;
4912 
4913                                 case SCF_ERROR_DELETED:
4914                                         warn(cf_missing, ient->sc_fmri,
4915                                             ud_name);
4916                                         r = 0;
4917                                         goto out;
4918 
4919                                 case SCF_ERROR_PERMISSION_DENIED:
4920                                         warn(emsg_pg_deleted, ud_ctarg,
4921                                             ud_name);
4922                                         r = EPERM;
4923                                         goto out;
4924 
4925                                 case SCF_ERROR_EXISTS:
4926                                         warn(emsg_pg_added, ud_ctarg, ud_name);
4927                                         r = EBUSY;
4928                                         goto out;
4929 
4930                                 case SCF_ERROR_NOT_BOUND:
4931                                 case SCF_ERROR_HANDLE_MISMATCH:
4932                                 case SCF_ERROR_INVALID_ARGUMENT:
4933                                 case SCF_ERROR_NOT_SET:
4934                                 default:
4935                                         bad_error("entity_add_pg", scf_error());
4936                                 }
4937                         }
4938                 }
4939 
4940                 r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4941                 switch (r) {
4942                 case 0:
4943                         break;
4944 
4945                 case ECANCELED:
4946                         warn(cf_missing, ient->sc_fmri, ud_name);
4947                         goto out;
4948 
4949                 case ECONNABORTED:
4950                 case ENOMEM:
4951                 case EBADF:
4952                         goto out;
4953 
4954                 case EACCES:
4955                 default:
4956                         bad_error("load_pg", r);
4957                 }
4958 
4959                 if (g_verbose)
4960                         warn(upgrading, ient->sc_fmri, ud_name);
4961 
4962                 r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4963                     new_dpt_pgroup, 0, ient->sc_fmri);
4964                 switch (r) {
4965                 case 0:
4966                         break;
4967 
4968                 case ECANCELED:
4969                         warn(emsg_pg_deleted, ud_ctarg, ud_name);
4970                         r = EBUSY;
4971                         goto out;
4972 
4973                 case EPERM:
4974                         warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4975                         goto out;
4976 
4977                 case EBUSY:
4978                         warn(emsg_pg_changed, ud_ctarg, ud_name);
4979                         goto out;
4980 
4981                 case ECONNABORTED:
4982                 case ENOMEM:
4983                 case ENOSPC:
4984                 case EROFS:
4985                 case EACCES:
4986                 case EINVAL:
4987                         goto out;
4988 
4989                 default:
4990                         bad_error("upgrade_pg", r);
4991                 }
4992                 break;
4993 
4994         case 0: {
4995                 scf_transaction_entry_t *ent;
4996                 scf_value_t *val;
4997 
4998                 internal_pgroup_free(current_pg);
4999 
5000                 /* delete old pg */
5001                 if (g_verbose)
5002                         warn(upgrading, ient->sc_fmri, ud_name);
5003 
5004                 if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5005                         switch (scf_error()) {
5006                         case SCF_ERROR_CONNECTION_BROKEN:
5007                                 r = scferror2errno(scf_error());
5008                                 goto out;
5009 
5010                         case SCF_ERROR_DELETED:
5011                                 warn(cf_missing, ient->sc_fmri, ud_name);
5012                                 r = 0;
5013                                 goto out;
5014 
5015                         case SCF_ERROR_NOT_FOUND:
5016                                 break;
5017 
5018                         case SCF_ERROR_INVALID_ARGUMENT:
5019                         case SCF_ERROR_NOT_BOUND:
5020                         case SCF_ERROR_NOT_SET:
5021                         case SCF_ERROR_HANDLE_MISMATCH:
5022                         default:
5023                                 bad_error("entity_get_pg", scf_error());
5024                         }
5025                 } else if (scf_pg_delete(ud_pg) != 0) {
5026                         switch (scf_error()) {
5027                         case SCF_ERROR_DELETED:
5028                                 break;
5029 
5030                         case SCF_ERROR_CONNECTION_BROKEN:
5031                         case SCF_ERROR_BACKEND_READONLY:
5032                         case SCF_ERROR_BACKEND_ACCESS:
5033                                 r = scferror2errno(scf_error());
5034                                 goto out;
5035 
5036                         case SCF_ERROR_PERMISSION_DENIED:
5037                                 warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5038                                 r = scferror2errno(scf_error());
5039                                 goto out;
5040 
5041                         case SCF_ERROR_NOT_SET:
5042                         default:
5043                                 bad_error("scf_pg_delete", scf_error());
5044                         }
5045                 }
5046 
5047                 /* import new one */
5048                 cbdata.sc_handle = g_hndl;
5049                 cbdata.sc_trans = NULL;         /* handled below */
5050                 cbdata.sc_flags = 0;
5051 
5052                 r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5053                 if (r != UU_WALK_NEXT) {
5054                         if (r != UU_WALK_ERROR)
5055                                 bad_error("lscf_dependent_import", r);
5056 
5057                         r = cbdata.sc_err;
5058                         goto out;
5059                 }
5060 
5061                 if (tx == NULL)
5062                         break;
5063 
5064                 if ((ent = scf_entry_create(g_hndl)) == NULL ||
5065                     (val = scf_value_create(g_hndl)) == NULL) {
5066                         if (scf_error() == SCF_ERROR_NO_MEMORY)
5067                                 return (ENOMEM);
5068 
5069                         bad_error("scf_entry_create", scf_error());
5070                 }
5071 
5072                 if (scf_transaction_property_change_type(tx, ent, ud_name,
5073                     SCF_TYPE_FMRI) != 0) {
5074                         switch (scf_error()) {
5075                         case SCF_ERROR_CONNECTION_BROKEN:
5076                                 r = scferror2errno(scf_error());
5077                                 goto out;
5078 
5079                         case SCF_ERROR_DELETED:
5080                                 warn(emsg_pg_deleted, ient->sc_fmri,
5081                                     "dependents");
5082                                 r = EBUSY;
5083                                 goto out;
5084 
5085                         case SCF_ERROR_NOT_FOUND:
5086                                 break;
5087 
5088                         case SCF_ERROR_NOT_BOUND:
5089                         case SCF_ERROR_HANDLE_MISMATCH:
5090                         case SCF_ERROR_INVALID_ARGUMENT:
5091                         case SCF_ERROR_NOT_SET:
5092                         default:
5093                                 bad_error("scf_transaction_property_"
5094                                     "change_type", scf_error());
5095                         }
5096 
5097                         if (scf_transaction_property_new(tx, ent, ud_name,
5098                             SCF_TYPE_FMRI) != 0) {
5099                                 switch (scf_error()) {
5100                                 case SCF_ERROR_CONNECTION_BROKEN:
5101                                         r = scferror2errno(scf_error());
5102                                         goto out;
5103 
5104                                 case SCF_ERROR_DELETED:
5105                                         warn(emsg_pg_deleted, ient->sc_fmri,
5106                                             "dependents");
5107                                         r = EBUSY;
5108                                         goto out;
5109 
5110                                 case SCF_ERROR_EXISTS:
5111                                         warn(emsg_pg_changed, ient->sc_fmri,
5112                                             "dependents");
5113                                         r = EBUSY;
5114                                         goto out;
5115 
5116                                 case SCF_ERROR_INVALID_ARGUMENT:
5117                                 case SCF_ERROR_HANDLE_MISMATCH:
5118                                 case SCF_ERROR_NOT_BOUND:
5119                                 case SCF_ERROR_NOT_SET:
5120                                 default:
5121                                         bad_error("scf_transaction_property_"
5122                                             "new", scf_error());
5123                                 }
5124                         }
5125                 }
5126 
5127                 if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5128                     new_dpt_pgroup->sc_pgroup_fmri) != 0)
5129                         /* invalid sc_pgroup_fmri caught above */
5130                         bad_error("scf_value_set_from_string",
5131                             scf_error());
5132 
5133                 if (scf_entry_add_value(ent, val) != 0)
5134                         bad_error("scf_entry_add_value", scf_error());
5135                 break;
5136         }
5137 
5138         case -2:
5139                 warn(li_corrupt, ient->sc_fmri);
5140                 internal_pgroup_free(current_pg);
5141                 r = EBADF;
5142                 goto out;
5143 
5144         case -1:
5145         default:
5146                 /* invalid sc_pgroup_fmri caught above */
5147                 bad_error("fmri_equal", r);
5148         }
5149 
5150         r = 0;
5151 
5152 out:
5153         if (old_dpt_pgroup != NULL)
5154                 internal_pgroup_free(old_dpt_pgroup);
5155 
5156         return (r);
5157 }
5158 
5159 /*
5160  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5161  * would import it, except it seems to exist in the service anyway.  Compare
5162  * the existent dependent with the one we would import, and report any
5163  * differences (if there are none, be silent).  prop is the property which
5164  * represents the existent dependent (in the dependents property group) in the
5165  * entity corresponding to ient.
5166  *
5167  * Returns
5168  *   0 - success (Sort of.  At least, we can continue importing.)
5169  *   ECONNABORTED - repository connection broken
5170  *   EBUSY - ancestor of prop was deleted (error printed)
5171  *   ENOMEM - out of memory
5172  *   EBADF - corrupt property group (error printed)
5173  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5174  */
5175 static int
5176 handle_dependent_conflict(const entity_t * const ient,
5177     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5178 {
5179         int r;
5180         scf_type_t ty;
5181         scf_error_t scfe;
5182         void *tptr;
5183         int tissvc;
5184         pgroup_t *pgroup;
5185 
5186         if (scf_property_get_value(prop, ud_val) != 0) {
5187                 switch (scf_error()) {
5188                 case SCF_ERROR_CONNECTION_BROKEN:
5189                         return (scferror2errno(scf_error()));
5190 
5191                 case SCF_ERROR_DELETED:
5192                         warn(emsg_pg_deleted, ient->sc_fmri,
5193                             new_dpt_pgroup->sc_pgroup_name);
5194                         return (EBUSY);
5195 
5196                 case SCF_ERROR_CONSTRAINT_VIOLATED:
5197                 case SCF_ERROR_NOT_FOUND:
5198                         warn(gettext("Conflict upgrading %s (not importing "
5199                             "dependent \"%s\" because it already exists.)  "
5200                             "Warning: The \"%s/%2$s\" property has more or "
5201                             "fewer than one value)).\n"), ient->sc_fmri,
5202                             new_dpt_pgroup->sc_pgroup_name, "dependents");
5203                         return (0);
5204 
5205                 case SCF_ERROR_HANDLE_MISMATCH:
5206                 case SCF_ERROR_NOT_BOUND:
5207                 case SCF_ERROR_NOT_SET:
5208                 case SCF_ERROR_PERMISSION_DENIED:
5209                 default:
5210                         bad_error("scf_property_get_value",
5211                             scf_error());
5212                 }
5213         }
5214 
5215         ty = scf_value_type(ud_val);
5216         assert(ty != SCF_TYPE_INVALID);
5217         if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5218                 warn(gettext("Conflict upgrading %s (not importing dependent "
5219                     "\"%s\" because it already exists).  Warning: The "
5220                     "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5221                     ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5222                     scf_type_to_string(ty), "dependents");
5223                 return (0);
5224         }
5225 
5226         if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5227             0)
5228                 bad_error("scf_value_get_as_string", scf_error());
5229 
5230         r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5231         switch (r) {
5232         case 0:
5233                 warn(gettext("Conflict upgrading %s (not importing dependent "
5234                     "\"%s\" (target \"%s\") because it already exists with "
5235                     "target \"%s\").\n"), ient->sc_fmri,
5236                     new_dpt_pgroup->sc_pgroup_name,
5237                     new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5238                 return (0);
5239 
5240         case 1:
5241                 break;
5242 
5243         case -1:
5244                 warn(gettext("Conflict upgrading %s (not importing dependent "
5245                     "\"%s\" because it already exists).  Warning: The current "
5246                     "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5247                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5248                 return (0);
5249 
5250         case -2:
5251                 warn(gettext("Dependent \"%s\" of %s has invalid target "
5252                     "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5253                     new_dpt_pgroup->sc_pgroup_fmri);
5254                 return (EINVAL);
5255 
5256         default:
5257                 bad_error("fmri_equal", r);
5258         }
5259 
5260         /* compare dependency pgs in target */
5261         scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5262         switch (scfe) {
5263         case SCF_ERROR_NONE:
5264                 break;
5265 
5266         case SCF_ERROR_NO_MEMORY:
5267                 return (ENOMEM);
5268 
5269         case SCF_ERROR_NOT_FOUND:
5270                 warn(emsg_dpt_dangling, ient->sc_fmri,
5271                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5272                 return (0);
5273 
5274         case SCF_ERROR_CONSTRAINT_VIOLATED:
5275         case SCF_ERROR_INVALID_ARGUMENT:
5276         default:
5277                 bad_error("fmri_to_entity", scfe);
5278         }
5279 
5280         r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5281             ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5282         switch (r) {
5283         case 0:
5284                 break;
5285 
5286         case ECONNABORTED:
5287                 return (r);
5288 
5289         case ECANCELED:
5290                 warn(emsg_dpt_dangling, ient->sc_fmri,
5291                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5292                 return (0);
5293 
5294         case EBADF:
5295                 if (tissvc)
5296                         warn(gettext("%s has an instance with a \"%s\" "
5297                             "snapshot which is missing a snaplevel.\n"),
5298                             ud_ctarg, "running");
5299                 else
5300                         warn(gettext("%s has a \"%s\" snapshot which is "
5301                             "missing a snaplevel.\n"), ud_ctarg, "running");
5302                 /* FALLTHROUGH */
5303 
5304         case ENOENT:
5305                 warn(emsg_dpt_no_dep, ient->sc_fmri,
5306                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5307                     new_dpt_pgroup->sc_pgroup_name);
5308                 return (0);
5309 
5310         case EINVAL:
5311         default:
5312                 bad_error("entity_get_running_pg", r);
5313         }
5314 
5315         pgroup = internal_pgroup_new();
5316         if (pgroup == NULL)
5317                 return (ENOMEM);
5318 
5319         r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5320         switch (r) {
5321         case 0:
5322                 break;
5323 
5324         case ECONNABORTED:
5325         case EBADF:
5326         case ENOMEM:
5327                 internal_pgroup_free(pgroup);
5328                 return (r);
5329 
5330         case ECANCELED:
5331                 warn(emsg_dpt_no_dep, ient->sc_fmri,
5332                     new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5333                     new_dpt_pgroup->sc_pgroup_name);
5334                 internal_pgroup_free(pgroup);
5335                 return (0);
5336 
5337         case EACCES:
5338         default:
5339                 bad_error("load_pg", r);
5340         }
5341 
5342         /* report differences */
5343         report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5344         internal_pgroup_free(pgroup);
5345         return (0);
5346 }
5347 
5348 /*
5349  * lipg is a property group in the last-import snapshot of ent, which is an
5350  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5351  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5352  * in ents's property groups, compare and upgrade ent appropriately.
5353  *
5354  * Returns
5355  *   0 - success
5356  *   ECONNABORTED - repository connection broken
5357  *   ENOMEM - out of memory
5358  *   ENOSPC - configd is out of resources
5359  *   EINVAL - ient has invalid dependent (error printed)
5360  *          - ient has invalid pgroup_t (error printed)
5361  *   ECANCELED - ent has been deleted
5362  *   ENODEV - entity containing lipg has been deleted
5363  *          - entity containing running has been deleted
5364  *   EPERM - could not delete pg (permission denied) (error printed)
5365  *         - couldn't upgrade dependents (permission denied) (error printed)
5366  *         - couldn't import pg (permission denied) (error printed)
5367  *         - couldn't upgrade pg (permission denied) (error printed)
5368  *   EROFS - could not delete pg (repository read-only)
5369  *         - couldn't upgrade dependents (repository read-only)
5370  *         - couldn't import pg (repository read-only)
5371  *         - couldn't upgrade pg (repository read-only)
5372  *   EACCES - could not delete pg (backend access denied)
5373  *          - couldn't upgrade dependents (backend access denied)
5374  *          - couldn't import pg (backend access denied)
5375  *          - couldn't upgrade pg (backend access denied)
5376  *          - couldn't read property (backend access denied)
5377  *   EBUSY - property group was added (error printed)
5378  *         - property group was deleted (error printed)
5379  *         - property group changed (error printed)
5380  *         - "dependents" pg was added, changed, or deleted (error printed)
5381  *         - dependent target deleted (error printed)
5382  *         - dependent pg changed (error printed)
5383  *   EBADF - imp_snpl is corrupt (error printed)
5384  *         - ent has bad pg (error printed)
5385  *   EEXIST - dependent collision in target service (error printed)
5386  */
5387 static int
5388 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5389     const scf_snaplevel_t *running)
5390 {
5391         int r;
5392         pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5393         scf_callback_t cbdata;
5394 
5395         const char * const cf_pg_missing =
5396             gettext("Conflict upgrading %s (property group %s is missing)\n");
5397         const char * const deleting =
5398             gettext("%s: Deleting property group \"%s\".\n");
5399 
5400         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5401 
5402         /* Skip dependent property groups. */
5403         if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5404                 switch (scf_error()) {
5405                 case SCF_ERROR_DELETED:
5406                         return (ENODEV);
5407 
5408                 case SCF_ERROR_CONNECTION_BROKEN:
5409                         return (ECONNABORTED);
5410 
5411                 case SCF_ERROR_NOT_SET:
5412                 case SCF_ERROR_NOT_BOUND:
5413                 default:
5414                         bad_error("scf_pg_get_type", scf_error());
5415                 }
5416         }
5417 
5418         if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5419                 if (scf_pg_get_property(lipg, "external", NULL) == 0)
5420                         return (0);
5421 
5422                 switch (scf_error()) {
5423                 case SCF_ERROR_NOT_FOUND:
5424                         break;
5425 
5426                 case SCF_ERROR_CONNECTION_BROKEN:
5427                         return (ECONNABORTED);
5428 
5429                 case SCF_ERROR_DELETED:
5430                         return (ENODEV);
5431 
5432                 case SCF_ERROR_INVALID_ARGUMENT:
5433                 case SCF_ERROR_NOT_BOUND:
5434                 case SCF_ERROR_HANDLE_MISMATCH:
5435                 case SCF_ERROR_NOT_SET:
5436                 default:
5437                         bad_error("scf_pg_get_property", scf_error());
5438                 }
5439         }
5440 
5441         /* lookup pg in new properties */
5442         if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5443                 switch (scf_error()) {
5444                 case SCF_ERROR_DELETED:
5445                         return (ENODEV);
5446 
5447                 case SCF_ERROR_CONNECTION_BROKEN:
5448                         return (ECONNABORTED);
5449 
5450                 case SCF_ERROR_NOT_SET:
5451                 case SCF_ERROR_NOT_BOUND:
5452                 default:
5453                         bad_error("scf_pg_get_name", scf_error());
5454                 }
5455         }
5456 
5457         pgrp.sc_pgroup_name = imp_str;
5458         mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5459 
5460         if (mpg != NULL)
5461                 mpg->sc_pgroup_seen = 1;
5462 
5463         /* Special handling for dependents */
5464         if (strcmp(imp_str, "dependents") == 0)
5465                 return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5466 
5467         if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5468                 return (upgrade_manifestfiles(NULL, ient, running, ent));
5469 
5470         if (mpg == NULL || mpg->sc_pgroup_delete) {
5471                 /* property group was deleted from manifest */
5472                 if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5473                         switch (scf_error()) {
5474                         case SCF_ERROR_NOT_FOUND:
5475                                 return (0);
5476 
5477                         case SCF_ERROR_DELETED:
5478                         case SCF_ERROR_CONNECTION_BROKEN:
5479                                 return (scferror2errno(scf_error()));
5480 
5481                         case SCF_ERROR_INVALID_ARGUMENT:
5482                         case SCF_ERROR_HANDLE_MISMATCH:
5483                         case SCF_ERROR_NOT_BOUND:
5484                         case SCF_ERROR_NOT_SET:
5485                         default:
5486                                 bad_error("entity_get_pg", scf_error());
5487                         }
5488                 }
5489 
5490                 if (mpg != NULL && mpg->sc_pgroup_delete) {
5491                         if (g_verbose)
5492                                 warn(deleting, ient->sc_fmri, imp_str);
5493                         if (scf_pg_delete(imp_pg2) == 0)
5494                                 return (0);
5495 
5496                         switch (scf_error()) {
5497                         case SCF_ERROR_DELETED:
5498                                 return (0);
5499 
5500                         case SCF_ERROR_CONNECTION_BROKEN:
5501                         case SCF_ERROR_BACKEND_READONLY:
5502                         case SCF_ERROR_BACKEND_ACCESS:
5503                                 return (scferror2errno(scf_error()));
5504 
5505                         case SCF_ERROR_PERMISSION_DENIED:
5506                                 warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5507                                 return (scferror2errno(scf_error()));
5508 
5509                         case SCF_ERROR_NOT_SET:
5510                         default:
5511                                 bad_error("scf_pg_delete", scf_error());
5512                         }
5513                 }
5514 
5515                 r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5516                 switch (r) {
5517                 case 0:
5518                         break;
5519 
5520                 case ECANCELED:
5521                         return (ENODEV);
5522 
5523                 case ECONNABORTED:
5524                 case ENOMEM:
5525                 case EBADF:
5526                 case EACCES:
5527                         return (r);
5528 
5529                 default:
5530                         bad_error("load_pg", r);
5531                 }
5532 
5533                 r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5534                 switch (r) {
5535                 case 0:
5536                         break;
5537 
5538                 case ECANCELED:
5539                 case ECONNABORTED:
5540                 case ENOMEM:
5541                 case EBADF:
5542                 case EACCES:
5543                         internal_pgroup_free(lipg_i);
5544                         return (r);
5545 
5546                 default:
5547                         bad_error("load_pg", r);
5548                 }
5549 
5550                 if (pg_equal(lipg_i, curpg_i)) {
5551                         if (g_verbose)
5552                                 warn(deleting, ient->sc_fmri, imp_str);
5553                         if (scf_pg_delete(imp_pg2) != 0) {
5554                                 switch (scf_error()) {
5555                                 case SCF_ERROR_DELETED:
5556                                         break;
5557 
5558                                 case SCF_ERROR_CONNECTION_BROKEN:
5559                                         internal_pgroup_free(lipg_i);
5560                                         internal_pgroup_free(curpg_i);
5561                                         return (ECONNABORTED);
5562 
5563                                 case SCF_ERROR_NOT_SET:
5564                                 case SCF_ERROR_NOT_BOUND:
5565                                 default:
5566                                         bad_error("scf_pg_delete", scf_error());
5567                                 }
5568                         }
5569                 } else {
5570                         report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5571                 }
5572 
5573                 internal_pgroup_free(lipg_i);
5574                 internal_pgroup_free(curpg_i);
5575 
5576                 return (0);
5577         }
5578 
5579         /*
5580          * Only dependent pgs can have override set, and we skipped those
5581          * above.
5582          */
5583         assert(!mpg->sc_pgroup_override);
5584 
5585         /* compare */
5586         r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5587         switch (r) {
5588         case 0:
5589                 break;
5590 
5591         case ECANCELED:
5592                 return (ENODEV);
5593 
5594         case ECONNABORTED:
5595         case EBADF:
5596         case ENOMEM:
5597         case EACCES:
5598                 return (r);
5599 
5600         default:
5601                 bad_error("load_pg", r);
5602         }
5603 
5604         if (pg_equal(mpg, lipg_i)) {
5605                 /* The manifest pg has not changed.  Move on. */
5606                 r = 0;
5607                 goto out;
5608         }
5609 
5610         /* upgrade current properties according to lipg & mpg */
5611         if (running != NULL)
5612                 r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5613         else
5614                 r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5615         if (r != 0) {
5616                 switch (scf_error()) {
5617                 case SCF_ERROR_CONNECTION_BROKEN:
5618                         r = scferror2errno(scf_error());
5619                         goto out;
5620 
5621                 case SCF_ERROR_DELETED:
5622                         if (running != NULL)
5623                                 r = ENODEV;
5624                         else
5625                                 r = ECANCELED;
5626                         goto out;
5627 
5628                 case SCF_ERROR_NOT_FOUND:
5629                         break;
5630 
5631                 case SCF_ERROR_INVALID_ARGUMENT:
5632                 case SCF_ERROR_HANDLE_MISMATCH:
5633                 case SCF_ERROR_NOT_BOUND:
5634                 case SCF_ERROR_NOT_SET:
5635                 default:
5636                         bad_error("entity_get_pg", scf_error());
5637                 }
5638 
5639                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5640 
5641                 r = 0;
5642                 goto out;
5643         }
5644 
5645         r = load_pg_attrs(imp_pg2, &curpg_i);
5646         switch (r) {
5647         case 0:
5648                 break;
5649 
5650         case ECANCELED:
5651                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5652                 r = 0;
5653                 goto out;
5654 
5655         case ECONNABORTED:
5656         case ENOMEM:
5657                 goto out;
5658 
5659         default:
5660                 bad_error("load_pg_attrs", r);
5661         }
5662 
5663         if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5664                 (void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5665                 internal_pgroup_free(curpg_i);
5666                 r = 0;
5667                 goto out;
5668         }
5669 
5670         internal_pgroup_free(curpg_i);
5671 
5672         r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5673         switch (r) {
5674         case 0:
5675                 break;
5676 
5677         case ECANCELED:
5678                 warn(cf_pg_missing, ient->sc_fmri, imp_str);
5679                 r = 0;
5680                 goto out;
5681 
5682         case ECONNABORTED:
5683         case EBADF:
5684         case ENOMEM:
5685         case EACCES:
5686                 goto out;
5687 
5688         default:
5689                 bad_error("load_pg", r);
5690         }
5691 
5692         if (pg_equal(lipg_i, curpg_i) &&
5693             !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5694                 int do_delete = 1;
5695 
5696                 if (g_verbose)
5697                         warn(gettext("%s: Upgrading property group \"%s\".\n"),
5698                             ient->sc_fmri, mpg->sc_pgroup_name);
5699 
5700                 internal_pgroup_free(curpg_i);
5701 
5702                 if (running != NULL &&
5703                     entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5704                         switch (scf_error()) {
5705                         case SCF_ERROR_DELETED:
5706                                 r = ECANCELED;
5707                                 goto out;
5708 
5709                         case SCF_ERROR_NOT_FOUND:
5710                                 do_delete = 0;
5711                                 break;
5712 
5713                         case SCF_ERROR_CONNECTION_BROKEN:
5714                                 r = scferror2errno(scf_error());
5715                                 goto out;
5716 
5717                         case SCF_ERROR_HANDLE_MISMATCH:
5718                         case SCF_ERROR_INVALID_ARGUMENT:
5719                         case SCF_ERROR_NOT_SET:
5720                         case SCF_ERROR_NOT_BOUND:
5721                         default:
5722                                 bad_error("entity_get_pg", scf_error());
5723                         }
5724                 }
5725 
5726                 if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5727                         switch (scf_error()) {
5728                         case SCF_ERROR_DELETED:
5729                                 break;
5730 
5731                         case SCF_ERROR_CONNECTION_BROKEN:
5732                         case SCF_ERROR_BACKEND_READONLY:
5733                         case SCF_ERROR_BACKEND_ACCESS:
5734                                 r = scferror2errno(scf_error());
5735                                 goto out;
5736 
5737                         case SCF_ERROR_PERMISSION_DENIED:
5738                                 warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5739                                     ient->sc_fmri);
5740                                 r = scferror2errno(scf_error());
5741                                 goto out;
5742 
5743                         case SCF_ERROR_NOT_SET:
5744                         case SCF_ERROR_NOT_BOUND:
5745                         default:
5746                                 bad_error("scf_pg_delete", scf_error());
5747                         }
5748                 }
5749 
5750                 cbdata.sc_handle = g_hndl;
5751                 cbdata.sc_parent = ent;
5752                 cbdata.sc_service = issvc;
5753                 cbdata.sc_flags = 0;
5754                 cbdata.sc_source_fmri = ient->sc_fmri;
5755                 cbdata.sc_target_fmri = ient->sc_fmri;
5756 
5757                 r = entity_pgroup_import(mpg, &cbdata);
5758                 switch (r) {
5759                 case UU_WALK_NEXT:
5760                         r = 0;
5761                         goto out;
5762 
5763                 case UU_WALK_ERROR:
5764                         if (cbdata.sc_err == EEXIST) {
5765                                 warn(emsg_pg_added, ient->sc_fmri,
5766                                     mpg->sc_pgroup_name);
5767                                 r = EBUSY;
5768                         } else {
5769                                 r = cbdata.sc_err;
5770                         }
5771                         goto out;
5772 
5773                 default:
5774                         bad_error("entity_pgroup_import", r);
5775                 }
5776         }
5777 
5778         if (running != NULL &&
5779             entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5780                 switch (scf_error()) {
5781                 case SCF_ERROR_CONNECTION_BROKEN:
5782                 case SCF_ERROR_DELETED:
5783                         r = scferror2errno(scf_error());
5784                         goto out;
5785 
5786                 case SCF_ERROR_NOT_FOUND:
5787                         break;
5788 
5789                 case SCF_ERROR_HANDLE_MISMATCH:
5790                 case SCF_ERROR_INVALID_ARGUMENT:
5791                 case SCF_ERROR_NOT_SET:
5792                 case SCF_ERROR_NOT_BOUND:
5793                 default:
5794                         bad_error("entity_get_pg", scf_error());
5795                 }
5796 
5797                 cbdata.sc_handle = g_hndl;
5798                 cbdata.sc_parent = ent;
5799                 cbdata.sc_service = issvc;
5800                 cbdata.sc_flags = SCI_FORCE;
5801                 cbdata.sc_source_fmri = ient->sc_fmri;
5802                 cbdata.sc_target_fmri = ient->sc_fmri;
5803 
5804                 r = entity_pgroup_import(mpg, &cbdata);
5805                 switch (r) {
5806                 case UU_WALK_NEXT:
5807                         r = 0;
5808                         goto out;
5809 
5810                 case UU_WALK_ERROR:
5811                         if (cbdata.sc_err == EEXIST) {
5812                                 warn(emsg_pg_added, ient->sc_fmri,
5813                                     mpg->sc_pgroup_name);
5814                                 r = EBUSY;
5815                         } else {
5816                                 r = cbdata.sc_err;
5817                         }
5818                         goto out;
5819 
5820                 default:
5821                         bad_error("entity_pgroup_import", r);
5822                 }
5823         }
5824 
5825         r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5826         internal_pgroup_free(curpg_i);
5827         switch (r) {
5828         case 0:
5829                 ient->sc_import_state = IMPORT_PROP_BEGUN;
5830                 break;
5831 
5832         case ECANCELED:
5833                 warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5834                 r = EBUSY;
5835                 break;
5836 
5837         case EPERM:
5838                 warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5839                 break;
5840 
5841         case EBUSY:
5842                 warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5843                 break;
5844 
5845         case ECONNABORTED:
5846         case ENOMEM:
5847         case ENOSPC:
5848         case EROFS:
5849         case EACCES:
5850         case EINVAL:
5851                 break;
5852 
5853         default:
5854                 bad_error("upgrade_pg", r);
5855         }
5856 
5857 out:
5858         internal_pgroup_free(lipg_i);
5859         return (r);
5860 }
5861 
5862 /*
5863  * Upgrade the properties of ent according to snpl & ient.
5864  *
5865  * Returns
5866  *   0 - success
5867  *   ECONNABORTED - repository connection broken
5868  *   ENOMEM - out of memory
5869  *   ENOSPC - configd is out of resources
5870  *   ECANCELED - ent was deleted
5871  *   ENODEV - entity containing snpl was deleted
5872  *          - entity containing running was deleted
5873  *   EBADF - imp_snpl is corrupt (error printed)
5874  *         - ent has corrupt pg (error printed)
5875  *         - dependent has corrupt pg (error printed)
5876  *         - dependent target has a corrupt snapshot (error printed)
5877  *   EBUSY - pg was added, changed, or deleted (error printed)
5878  *         - dependent target was deleted (error printed)
5879  *         - dependent pg changed (error printed)
5880  *   EINVAL - invalid property group name (error printed)
5881  *          - invalid property name (error printed)
5882  *          - invalid value (error printed)
5883  *          - ient has invalid pgroup or dependent (error printed)
5884  *   EPERM - could not create property group (permission denied) (error printed)
5885  *         - could not modify property group (permission denied) (error printed)
5886  *         - couldn't delete, upgrade, or import pg or dependent (error printed)
5887  *   EROFS - could not create property group (repository read-only)
5888  *         - couldn't delete, upgrade, or import pg or dependent
5889  *   EACCES - could not create property group (backend access denied)
5890  *          - couldn't delete, upgrade, or import pg or dependent
5891  *   EEXIST - dependent collision in target service (error printed)
5892  */
5893 static int
5894 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5895     entity_t *ient)
5896 {
5897         pgroup_t *pg, *rpg;
5898         int r;
5899         uu_list_t *pgs = ient->sc_pgroups;
5900 
5901         const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5902 
5903         /* clear sc_sceen for pgs */
5904         if (uu_list_walk(pgs, clear_int,
5905             (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5906                 bad_error("uu_list_walk", uu_error());
5907 
5908         if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5909                 switch (scf_error()) {
5910                 case SCF_ERROR_DELETED:
5911                         return (ENODEV);
5912 
5913                 case SCF_ERROR_CONNECTION_BROKEN:
5914                         return (ECONNABORTED);
5915 
5916                 case SCF_ERROR_NOT_SET:
5917                 case SCF_ERROR_NOT_BOUND:
5918                 case SCF_ERROR_HANDLE_MISMATCH:
5919                 default:
5920                         bad_error("scf_iter_snaplevel_pgs", scf_error());
5921                 }
5922         }
5923 
5924         for (;;) {
5925                 r = scf_iter_next_pg(imp_up_iter, imp_pg);
5926                 if (r == 0)
5927                         break;
5928                 if (r == 1) {
5929                         r = process_old_pg(imp_pg, ient, ent, running);
5930                         switch (r) {
5931                         case 0:
5932                                 break;
5933 
5934                         case ECONNABORTED:
5935                         case ENOMEM:
5936                         case ENOSPC:
5937                         case ECANCELED:
5938                         case ENODEV:
5939                         case EPERM:
5940                         case EROFS:
5941                         case EACCES:
5942                         case EBADF:
5943                         case EBUSY:
5944                         case EINVAL:
5945                         case EEXIST:
5946                                 return (r);
5947 
5948                         default:
5949                                 bad_error("process_old_pg", r);
5950                         }
5951                         continue;
5952                 }
5953                 if (r != -1)
5954                         bad_error("scf_iter_next_pg", r);
5955 
5956                 switch (scf_error()) {
5957                 case SCF_ERROR_DELETED:
5958                         return (ENODEV);
5959 
5960                 case SCF_ERROR_CONNECTION_BROKEN:
5961                         return (ECONNABORTED);
5962 
5963                 case SCF_ERROR_HANDLE_MISMATCH:
5964                 case SCF_ERROR_NOT_BOUND:
5965                 case SCF_ERROR_NOT_SET:
5966                 case SCF_ERROR_INVALID_ARGUMENT:
5967                 default:
5968                         bad_error("scf_iter_next_pg", scf_error());
5969                 }
5970         }
5971 
5972         for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5973                 if (pg->sc_pgroup_seen)
5974                         continue;
5975 
5976                 /* pg is new */
5977 
5978                 if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5979                         r = upgrade_dependents(NULL, imp_snpl, ient, running,
5980                             ent);
5981                         switch (r) {
5982                         case 0:
5983                                 break;
5984 
5985                         case ECONNABORTED:
5986                         case ENOMEM:
5987                         case ENOSPC:
5988                         case ECANCELED:
5989                         case ENODEV:
5990                         case EBADF:
5991                         case EBUSY:
5992                         case EINVAL:
5993                         case EPERM:
5994                         case EROFS:
5995                         case EACCES:
5996                         case EEXIST:
5997                                 return (r);
5998 
5999                         default:
6000                                 bad_error("upgrade_dependents", r);
6001                         }
6002                         continue;
6003                 }
6004 
6005                 if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6006                         r = upgrade_manifestfiles(pg, ient, running, ent);
6007                         switch (r) {
6008                         case 0:
6009                                 break;
6010 
6011                         case ECONNABORTED:
6012                         case ENOMEM:
6013                         case ENOSPC:
6014                         case ECANCELED:
6015                         case ENODEV:
6016                         case EBADF:
6017                         case EBUSY:
6018                         case EINVAL:
6019                         case EPERM:
6020                         case EROFS:
6021                         case EACCES:
6022                         case EEXIST:
6023                                 return (r);
6024 
6025                         default:
6026                                 bad_error("upgrade_manifestfiles", r);
6027                         }
6028                         continue;
6029                 }
6030 
6031                 if (running != NULL) {
6032                         r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6033                             imp_pg);
6034                 } else {
6035                         r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6036                             imp_pg);
6037                 }
6038                 if (r != 0) {
6039                         scf_callback_t cbdata;
6040 
6041                         switch (scf_error()) {
6042                         case SCF_ERROR_NOT_FOUND:
6043                                 break;
6044 
6045                         case SCF_ERROR_CONNECTION_BROKEN:
6046                                 return (scferror2errno(scf_error()));
6047 
6048                         case SCF_ERROR_DELETED:
6049                                 if (running != NULL)
6050                                         return (ENODEV);
6051                                 else
6052                                         return (scferror2errno(scf_error()));
6053 
6054                         case SCF_ERROR_INVALID_ARGUMENT:
6055                                 warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6056                                     pg->sc_pgroup_name);
6057                                 return (EINVAL);
6058 
6059                         case SCF_ERROR_NOT_SET:
6060                         case SCF_ERROR_HANDLE_MISMATCH:
6061                         case SCF_ERROR_NOT_BOUND:
6062                         default:
6063                                 bad_error("entity_get_pg", scf_error());
6064                         }
6065 
6066                         /* User doesn't have pg, so import it. */
6067 
6068                         cbdata.sc_handle = g_hndl;
6069                         cbdata.sc_parent = ent;
6070                         cbdata.sc_service = issvc;
6071                         cbdata.sc_flags = SCI_FORCE;
6072                         cbdata.sc_source_fmri = ient->sc_fmri;
6073                         cbdata.sc_target_fmri = ient->sc_fmri;
6074 
6075                         r = entity_pgroup_import(pg, &cbdata);
6076                         switch (r) {
6077                         case UU_WALK_NEXT:
6078                                 ient->sc_import_state = IMPORT_PROP_BEGUN;
6079                                 continue;
6080 
6081                         case UU_WALK_ERROR:
6082                                 if (cbdata.sc_err == EEXIST) {
6083                                         warn(emsg_pg_added, ient->sc_fmri,
6084                                             pg->sc_pgroup_name);
6085                                         return (EBUSY);
6086                                 }
6087                                 return (cbdata.sc_err);
6088 
6089                         default:
6090                                 bad_error("entity_pgroup_import", r);
6091                         }
6092                 }
6093 
6094                 /* report differences between pg & current */
6095                 r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6096                 switch (r) {
6097                 case 0:
6098                         break;
6099 
6100                 case ECANCELED:
6101                         warn(emsg_pg_deleted, ient->sc_fmri,
6102                             pg->sc_pgroup_name);
6103                         return (EBUSY);
6104 
6105                 case ECONNABORTED:
6106                 case EBADF:
6107                 case ENOMEM:
6108                 case EACCES:
6109                         return (r);
6110 
6111                 default:
6112                         bad_error("load_pg", r);
6113                 }
6114                 report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6115                 internal_pgroup_free(rpg);
6116                 rpg = NULL;
6117         }
6118 
6119         return (0);
6120 }
6121 
6122 /*
6123  * Import an instance.  If it doesn't exist, create it.  If it has
6124  * a last-import snapshot, upgrade its properties.  Finish by updating its
6125  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6126  * could have been created for a dependent tag in another manifest.  Import the
6127  * new properties.  If there's a conflict, don't override, like now?
6128  *
6129  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6130  * lcbdata->sc_err to
6131  *   ECONNABORTED - repository connection broken
6132  *   ENOMEM - out of memory
6133  *   ENOSPC - svc.configd is out of resources
6134  *   EEXIST - dependency collision in dependent service (error printed)
6135  *   EPERM - couldn't create temporary instance (permission denied)
6136  *         - couldn't import into temporary instance (permission denied)
6137  *         - couldn't take snapshot (permission denied)
6138  *         - couldn't upgrade properties (permission denied)
6139  *         - couldn't import properties (permission denied)
6140  *         - couldn't import dependents (permission denied)
6141  *   EROFS - couldn't create temporary instance (repository read-only)
6142  *         - couldn't import into temporary instance (repository read-only)
6143  *         - couldn't upgrade properties (repository read-only)
6144  *         - couldn't import properties (repository read-only)
6145  *         - couldn't import dependents (repository read-only)
6146  *   EACCES - couldn't create temporary instance (backend access denied)
6147  *          - couldn't import into temporary instance (backend access denied)
6148  *          - couldn't upgrade properties (backend access denied)
6149  *          - couldn't import properties (backend access denied)
6150  *          - couldn't import dependents (backend access denied)
6151  *   EINVAL - invalid instance name (error printed)
6152  *          - invalid pgroup_t's (error printed)
6153  *          - invalid dependents (error printed)
6154  *   EBUSY - temporary service deleted (error printed)
6155  *         - temporary instance deleted (error printed)
6156  *         - temporary instance changed (error printed)
6157  *         - temporary instance already exists (error printed)
6158  *         - instance deleted (error printed)
6159  *   EBADF - instance has corrupt last-import snapshot (error printed)
6160  *         - instance is corrupt (error printed)
6161  *         - dependent has corrupt pg (error printed)
6162  *         - dependent target has a corrupt snapshot (error printed)
6163  *   -1 - unknown libscf error (error printed)
6164  */
6165 static int
6166 lscf_instance_import(void *v, void *pvt)
6167 {
6168         entity_t *inst = v;
6169         scf_callback_t ctx;
6170         scf_callback_t *lcbdata = pvt;
6171         scf_service_t *rsvc = lcbdata->sc_parent;
6172         int r;
6173         scf_snaplevel_t *running;
6174         int flags = lcbdata->sc_flags;
6175 
6176         const char * const emsg_tdel =
6177             gettext("Temporary instance svc:/%s:%s was deleted.\n");
6178         const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6179             "changed unexpectedly.\n");
6180         const char * const emsg_del = gettext("%s changed unexpectedly "
6181             "(instance \"%s\" was deleted.)\n");
6182         const char * const emsg_badsnap = gettext(
6183             "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6184 
6185         /*
6186          * prepare last-import snapshot:
6187          * create temporary instance (service was precreated)
6188          * populate with properties from bundle
6189          * take snapshot
6190          */
6191         if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6192                 switch (scf_error()) {
6193                 case SCF_ERROR_CONNECTION_BROKEN:
6194                 case SCF_ERROR_NO_RESOURCES:
6195                 case SCF_ERROR_BACKEND_READONLY:
6196                 case SCF_ERROR_BACKEND_ACCESS:
6197                         return (stash_scferror(lcbdata));
6198 
6199                 case SCF_ERROR_EXISTS:
6200                         warn(gettext("Temporary service svc:/%s "
6201                             "changed unexpectedly (instance \"%s\" added).\n"),
6202                             imp_tsname, inst->sc_name);
6203                         lcbdata->sc_err = EBUSY;
6204                         return (UU_WALK_ERROR);
6205 
6206                 case SCF_ERROR_DELETED:
6207                         warn(gettext("Temporary service svc:/%s "
6208                             "was deleted unexpectedly.\n"), imp_tsname);
6209                         lcbdata->sc_err = EBUSY;
6210                         return (UU_WALK_ERROR);
6211 
6212                 case SCF_ERROR_INVALID_ARGUMENT:
6213                         warn(gettext("Invalid instance name \"%s\".\n"),
6214                             inst->sc_name);
6215                         return (stash_scferror(lcbdata));
6216 
6217                 case SCF_ERROR_PERMISSION_DENIED:
6218                         warn(gettext("Could not create temporary instance "
6219                             "\"%s\" in svc:/%s (permission denied).\n"),
6220                             inst->sc_name, imp_tsname);
6221                         return (stash_scferror(lcbdata));
6222 
6223                 case SCF_ERROR_HANDLE_MISMATCH:
6224                 case SCF_ERROR_NOT_BOUND:
6225                 case SCF_ERROR_NOT_SET:
6226                 default:
6227                         bad_error("scf_service_add_instance", scf_error());
6228                 }
6229         }
6230 
6231         r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6232             inst->sc_name);
6233         if (r < 0)
6234                 bad_error("snprintf", errno);
6235 
6236         r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6237             lcbdata->sc_flags | SCI_NOENABLED);
6238         switch (r) {
6239         case 0:
6240                 break;
6241 
6242         case ECANCELED:
6243                 warn(emsg_tdel, imp_tsname, inst->sc_name);
6244                 lcbdata->sc_err = EBUSY;
6245                 r = UU_WALK_ERROR;
6246                 goto deltemp;
6247 
6248         case EEXIST:
6249                 warn(emsg_tchg, imp_tsname, inst->sc_name);
6250                 lcbdata->sc_err = EBUSY;
6251                 r = UU_WALK_ERROR;
6252                 goto deltemp;
6253 
6254         case ECONNABORTED:
6255                 goto connaborted;
6256 
6257         case ENOMEM:
6258         case ENOSPC:
6259         case EPERM:
6260         case EROFS:
6261         case EACCES:
6262         case EINVAL:
6263         case EBUSY:
6264                 lcbdata->sc_err = r;
6265                 r = UU_WALK_ERROR;
6266                 goto deltemp;
6267 
6268         default:
6269                 bad_error("lscf_import_instance_pgs", r);
6270         }
6271 
6272         r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6273             inst->sc_name);
6274         if (r < 0)
6275                 bad_error("snprintf", errno);
6276 
6277         ctx.sc_handle = lcbdata->sc_handle;
6278         ctx.sc_parent = imp_tinst;
6279         ctx.sc_service = 0;
6280         ctx.sc_source_fmri = inst->sc_fmri;
6281         ctx.sc_target_fmri = imp_str;
6282         if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6283             UU_DEFAULT) != 0) {
6284                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6285                         bad_error("uu_list_walk", uu_error());
6286 
6287                 switch (ctx.sc_err) {
6288                 case ECONNABORTED:
6289                         goto connaborted;
6290 
6291                 case ECANCELED:
6292                         warn(emsg_tdel, imp_tsname, inst->sc_name);
6293                         lcbdata->sc_err = EBUSY;
6294                         break;
6295 
6296                 case EEXIST:
6297                         warn(emsg_tchg, imp_tsname, inst->sc_name);
6298                         lcbdata->sc_err = EBUSY;
6299                         break;
6300 
6301                 default:
6302                         lcbdata->sc_err = ctx.sc_err;
6303                 }
6304                 r = UU_WALK_ERROR;
6305                 goto deltemp;
6306         }
6307 
6308         if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6309             inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6310                 switch (scf_error()) {
6311                 case SCF_ERROR_CONNECTION_BROKEN:
6312                         goto connaborted;
6313 
6314                 case SCF_ERROR_NO_RESOURCES:
6315                         r = stash_scferror(lcbdata);
6316                         goto deltemp;
6317 
6318                 case SCF_ERROR_EXISTS:
6319                         warn(emsg_tchg, imp_tsname, inst->sc_name);
6320                         lcbdata->sc_err = EBUSY;
6321                         r = UU_WALK_ERROR;
6322                         goto deltemp;
6323 
6324                 case SCF_ERROR_PERMISSION_DENIED:
6325                         warn(gettext("Could not take \"%s\" snapshot of %s "
6326                             "(permission denied).\n"), snap_lastimport,
6327                             imp_str);
6328                         r = stash_scferror(lcbdata);
6329                         goto deltemp;
6330 
6331                 default:
6332                         scfwarn();
6333                         lcbdata->sc_err = -1;
6334                         r = UU_WALK_ERROR;
6335                         goto deltemp;
6336 
6337                 case SCF_ERROR_HANDLE_MISMATCH:
6338                 case SCF_ERROR_INVALID_ARGUMENT:
6339                 case SCF_ERROR_NOT_SET:
6340                         bad_error("_scf_snapshot_take_new_named", scf_error());
6341                 }
6342         }
6343 
6344         if (lcbdata->sc_flags & SCI_FRESH)
6345                 goto fresh;
6346 
6347         if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6348                 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6349                     imp_lisnap) != 0) {
6350                         switch (scf_error()) {
6351                         case SCF_ERROR_DELETED:
6352                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6353                                     inst->sc_name);
6354                                 lcbdata->sc_err = EBUSY;
6355                                 r = UU_WALK_ERROR;
6356                                 goto deltemp;
6357 
6358                         case SCF_ERROR_NOT_FOUND:
6359                                 flags |= SCI_FORCE;
6360                                 goto nosnap;
6361 
6362                         case SCF_ERROR_CONNECTION_BROKEN:
6363                                 goto connaborted;
6364 
6365                         case SCF_ERROR_INVALID_ARGUMENT:
6366                         case SCF_ERROR_HANDLE_MISMATCH:
6367                         case SCF_ERROR_NOT_BOUND:
6368                         case SCF_ERROR_NOT_SET:
6369                         default:
6370                                 bad_error("scf_instance_get_snapshot",
6371                                     scf_error());
6372                         }
6373                 }
6374 
6375                 /* upgrade */
6376 
6377                 /*
6378                  * compare new properties with last-import properties
6379                  * upgrade current properties
6380                  */
6381                 /* clear sc_sceen for pgs */
6382                 if (uu_list_walk(inst->sc_pgroups, clear_int,
6383                     (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6384                     0)
6385                         bad_error("uu_list_walk", uu_error());
6386 
6387                 r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6388                 switch (r) {
6389                 case 0:
6390                         break;
6391 
6392                 case ECONNABORTED:
6393                         goto connaborted;
6394 
6395                 case ECANCELED:
6396                         warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6397                         lcbdata->sc_err = EBUSY;
6398                         r = UU_WALK_ERROR;
6399                         goto deltemp;
6400 
6401                 case ENOENT:
6402                         warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6403                         lcbdata->sc_err = EBADF;
6404                         r = UU_WALK_ERROR;
6405                         goto deltemp;
6406 
6407                 default:
6408                         bad_error("get_snaplevel", r);
6409                 }
6410 
6411                 if (scf_instance_get_snapshot(imp_inst, snap_running,
6412                     imp_rsnap) != 0) {
6413                         switch (scf_error()) {
6414                         case SCF_ERROR_DELETED:
6415                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6416                                     inst->sc_name);
6417                                 lcbdata->sc_err = EBUSY;
6418                                 r = UU_WALK_ERROR;
6419                                 goto deltemp;
6420 
6421                         case SCF_ERROR_NOT_FOUND:
6422                                 break;
6423 
6424                         case SCF_ERROR_CONNECTION_BROKEN:
6425                                 goto connaborted;
6426 
6427                         case SCF_ERROR_INVALID_ARGUMENT:
6428                         case SCF_ERROR_HANDLE_MISMATCH:
6429                         case SCF_ERROR_NOT_BOUND:
6430                         case SCF_ERROR_NOT_SET:
6431                         default:
6432                                 bad_error("scf_instance_get_snapshot",
6433                                     scf_error());
6434                         }
6435 
6436                         running = NULL;
6437                 } else {
6438                         r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6439                         switch (r) {
6440                         case 0:
6441                                 running = imp_rsnpl;
6442                                 break;
6443 
6444                         case ECONNABORTED:
6445                                 goto connaborted;
6446 
6447                         case ECANCELED:
6448                                 warn(emsg_del, inst->sc_parent->sc_fmri,
6449                                     inst->sc_name);
6450                                 lcbdata->sc_err = EBUSY;
6451                                 r = UU_WALK_ERROR;
6452                                 goto deltemp;
6453 
6454                         case ENOENT:
6455                                 warn(emsg_badsnap, snap_running, inst->sc_fmri);
6456                                 lcbdata->sc_err = EBADF;
6457                                 r = UU_WALK_ERROR;
6458                                 goto deltemp;
6459 
6460                         default:
6461                                 bad_error("get_snaplevel", r);
6462                         }
6463                 }
6464 
6465                 r = upgrade_props(imp_inst, running, imp_snpl, inst);
6466                 switch (r) {
6467                 case 0:
6468                         break;
6469 
6470                 case ECANCELED:
6471                 case ENODEV:
6472                         warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6473                         lcbdata->sc_err = EBUSY;
6474                         r = UU_WALK_ERROR;
6475                         goto deltemp;
6476 
6477                 case ECONNABORTED:
6478                         goto connaborted;
6479 
6480                 case ENOMEM:
6481                 case ENOSPC:
6482                 case EBADF:
6483                 case EBUSY:
6484                 case EINVAL:
6485                 case EPERM:
6486                 case EROFS:
6487                 case EACCES:
6488                 case EEXIST:
6489                         lcbdata->sc_err = r;
6490                         r = UU_WALK_ERROR;
6491                         goto deltemp;
6492 
6493                 default:
6494                         bad_error("upgrade_props", r);
6495                 }
6496 
6497                 inst->sc_import_state = IMPORT_PROP_DONE;
6498         } else {
6499                 switch (scf_error()) {
6500                 case SCF_ERROR_CONNECTION_BROKEN:
6501                         goto connaborted;
6502 
6503                 case SCF_ERROR_NOT_FOUND:
6504                         break;
6505 
6506                 case SCF_ERROR_INVALID_ARGUMENT:        /* caught above */
6507                 case SCF_ERROR_HANDLE_MISMATCH:
6508                 case SCF_ERROR_NOT_BOUND:
6509                 case SCF_ERROR_NOT_SET:
6510                 default:
6511                         bad_error("scf_service_get_instance", scf_error());
6512                 }
6513 
6514 fresh:
6515                 /* create instance */
6516                 if (scf_service_add_instance(rsvc, inst->sc_name,
6517                     imp_inst) != 0) {
6518                         switch (scf_error()) {
6519                         case SCF_ERROR_CONNECTION_BROKEN:
6520                                 goto connaborted;
6521 
6522                         case SCF_ERROR_NO_RESOURCES:
6523                         case SCF_ERROR_BACKEND_READONLY:
6524                         case SCF_ERROR_BACKEND_ACCESS:
6525                                 r = stash_scferror(lcbdata);
6526                                 goto deltemp;
6527 
6528                         case SCF_ERROR_EXISTS:
6529                                 warn(gettext("%s changed unexpectedly "
6530                                     "(instance \"%s\" added).\n"),
6531                                     inst->sc_parent->sc_fmri, inst->sc_name);
6532                                 lcbdata->sc_err = EBUSY;
6533                                 r = UU_WALK_ERROR;
6534                                 goto deltemp;
6535 
6536                         case SCF_ERROR_PERMISSION_DENIED:
6537                                 warn(gettext("Could not create \"%s\" instance "
6538                                     "in %s (permission denied).\n"),
6539                                     inst->sc_name, inst->sc_parent->sc_fmri);
6540                                 r = stash_scferror(lcbdata);
6541                                 goto deltemp;
6542 
6543                         case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6544                         case SCF_ERROR_HANDLE_MISMATCH:
6545                         case SCF_ERROR_NOT_BOUND:
6546                         case SCF_ERROR_NOT_SET:
6547                         default:
6548                                 bad_error("scf_service_add_instance",
6549                                     scf_error());
6550                         }
6551                 }
6552 
6553 nosnap:
6554                 /*
6555                  * Create a last-import snapshot to serve as an attachment
6556                  * point for the real one from the temporary instance.  Since
6557                  * the contents is irrelevant, take it now, while the instance
6558                  * is empty, to minimize svc.configd's work.
6559                  */
6560                 if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6561                     imp_lisnap) != 0) {
6562                         switch (scf_error()) {
6563                         case SCF_ERROR_CONNECTION_BROKEN:
6564                                 goto connaborted;
6565 
6566                         case SCF_ERROR_NO_RESOURCES:
6567                                 r = stash_scferror(lcbdata);
6568                                 goto deltemp;
6569 
6570                         case SCF_ERROR_EXISTS:
6571                                 warn(gettext("%s changed unexpectedly "
6572                                     "(snapshot \"%s\" added).\n"),
6573                                     inst->sc_fmri, snap_lastimport);
6574                                 lcbdata->sc_err = EBUSY;
6575                                 r = UU_WALK_ERROR;
6576                                 goto deltemp;
6577 
6578                         case SCF_ERROR_PERMISSION_DENIED:
6579                                 warn(gettext("Could not take \"%s\" snapshot "
6580                                     "of %s (permission denied).\n"),
6581                                     snap_lastimport, inst->sc_fmri);
6582                                 r = stash_scferror(lcbdata);
6583                                 goto deltemp;
6584 
6585                         default:
6586                                 scfwarn();
6587                                 lcbdata->sc_err = -1;
6588                                 r = UU_WALK_ERROR;
6589                                 goto deltemp;
6590 
6591                         case SCF_ERROR_NOT_SET:
6592                         case SCF_ERROR_INTERNAL:
6593                         case SCF_ERROR_INVALID_ARGUMENT:
6594                         case SCF_ERROR_HANDLE_MISMATCH:
6595                                 bad_error("_scf_snapshot_take_new",
6596                                     scf_error());
6597                         }
6598                 }
6599 
6600                 if (li_only)
6601                         goto lionly;
6602 
6603                 inst->sc_import_state = IMPORT_PROP_BEGUN;
6604 
6605                 r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6606                     flags);
6607                 switch (r) {
6608                 case 0:
6609                         break;
6610 
6611                 case ECONNABORTED:
6612                         goto connaborted;
6613 
6614                 case ECANCELED:
6615                         warn(gettext("%s changed unexpectedly "
6616                             "(instance \"%s\" deleted).\n"),
6617                             inst->sc_parent->sc_fmri, inst->sc_name);
6618                         lcbdata->sc_err = EBUSY;
6619                         r = UU_WALK_ERROR;
6620                         goto deltemp;
6621 
6622                 case EEXIST:
6623                         warn(gettext("%s changed unexpectedly "
6624                             "(property group added).\n"), inst->sc_fmri);
6625                         lcbdata->sc_err = EBUSY;
6626                         r = UU_WALK_ERROR;
6627                         goto deltemp;
6628 
6629                 default:
6630                         lcbdata->sc_err = r;
6631                         r = UU_WALK_ERROR;
6632                         goto deltemp;
6633 
6634                 case EINVAL:    /* caught above */
6635                         bad_error("lscf_import_instance_pgs", r);
6636                 }
6637 
6638                 ctx.sc_parent = imp_inst;
6639                 ctx.sc_service = 0;
6640                 ctx.sc_trans = NULL;
6641                 ctx.sc_flags = 0;
6642                 if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6643                     &ctx, UU_DEFAULT) != 0) {
6644                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6645                                 bad_error("uu_list_walk", uu_error());
6646 
6647                         if (ctx.sc_err == ECONNABORTED)
6648                                 goto connaborted;
6649                         lcbdata->sc_err = ctx.sc_err;
6650                         r = UU_WALK_ERROR;
6651                         goto deltemp;
6652                 }
6653 
6654                 inst->sc_import_state = IMPORT_PROP_DONE;
6655 
6656                 if (g_verbose)
6657                         warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6658                             snap_initial, inst->sc_fmri);
6659                 r = take_snap(imp_inst, snap_initial, imp_snap);
6660                 switch (r) {
6661                 case 0:
6662                         break;
6663 
6664                 case ECONNABORTED:
6665                         goto connaborted;
6666 
6667                 case ENOSPC:
6668                 case -1:
6669                         lcbdata->sc_err = r;
6670                         r = UU_WALK_ERROR;
6671                         goto deltemp;
6672 
6673                 case ECANCELED:
6674                         warn(gettext("%s changed unexpectedly "
6675                             "(instance %s deleted).\n"),
6676                             inst->sc_parent->sc_fmri, inst->sc_name);
6677                         lcbdata->sc_err = r;
6678                         r = UU_WALK_ERROR;
6679                         goto deltemp;
6680 
6681                 case EPERM:
6682                         warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6683                         lcbdata->sc_err = r;
6684                         r = UU_WALK_ERROR;
6685                         goto deltemp;
6686 
6687                 default:
6688                         bad_error("take_snap", r);
6689                 }
6690         }
6691 
6692 lionly:
6693         if (lcbdata->sc_flags & SCI_NOSNAP)
6694                 goto deltemp;
6695 
6696         /* transfer snapshot from temporary instance */
6697         if (g_verbose)
6698                 warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6699                     snap_lastimport, inst->sc_fmri);
6700         if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6701                 switch (scf_error()) {
6702                 case SCF_ERROR_CONNECTION_BROKEN:
6703                         goto connaborted;
6704 
6705                 case SCF_ERROR_NO_RESOURCES:
6706                         r = stash_scferror(lcbdata);
6707                         goto deltemp;
6708 
6709                 case SCF_ERROR_PERMISSION_DENIED:
6710                         warn(gettext("Could not take \"%s\" snapshot for %s "
6711                             "(permission denied).\n"), snap_lastimport,
6712                             inst->sc_fmri);
6713                         r = stash_scferror(lcbdata);
6714                         goto deltemp;
6715 
6716                 case SCF_ERROR_NOT_SET:
6717                 case SCF_ERROR_HANDLE_MISMATCH:
6718                 default:
6719                         bad_error("_scf_snapshot_attach", scf_error());
6720                 }
6721         }
6722 
6723         inst->sc_import_state = IMPORT_COMPLETE;
6724 
6725         r = UU_WALK_NEXT;
6726 
6727 deltemp:
6728         /* delete temporary instance */
6729         if (scf_instance_delete(imp_tinst) != 0) {
6730                 switch (scf_error()) {
6731                 case SCF_ERROR_DELETED:
6732                         break;
6733 
6734                 case SCF_ERROR_CONNECTION_BROKEN:
6735                         goto connaborted;
6736 
6737                 case SCF_ERROR_NOT_SET:
6738                 case SCF_ERROR_NOT_BOUND:
6739                 default:
6740                         bad_error("scf_instance_delete", scf_error());
6741                 }
6742         }
6743 
6744         return (r);
6745 
6746 connaborted:
6747         warn(gettext("Could not delete svc:/%s:%s "
6748             "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6749         lcbdata->sc_err = ECONNABORTED;
6750         return (UU_WALK_ERROR);
6751 }
6752 
6753 /*
6754  * If the service is missing, create it, import its properties, and import the
6755  * instances.  Since the service is brand new, it should be empty, and if we
6756  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6757  *
6758  * If the service exists, we want to upgrade its properties and import the
6759  * instances.  Upgrade requires a last-import snapshot, though, which are
6760  * children of instances, so first we'll have to go through the instances
6761  * looking for a last-import snapshot.  If we don't find one then we'll just
6762  * override-import the service properties (but don't delete existing
6763  * properties: another service might have declared us as a dependent).  Before
6764  * we change anything, though, we want to take the previous snapshots.  We
6765  * also give lscf_instance_import() a leg up on taking last-import snapshots
6766  * by importing the manifest's service properties into a temporary service.
6767  *
6768  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6769  * sets lcbdata->sc_err to
6770  *   ECONNABORTED - repository connection broken
6771  *   ENOMEM - out of memory
6772  *   ENOSPC - svc.configd is out of resources
6773  *   EPERM - couldn't create temporary service (error printed)
6774  *         - couldn't import into temp service (error printed)
6775  *         - couldn't create service (error printed)
6776  *         - couldn't import dependent (error printed)
6777  *         - couldn't take snapshot (error printed)
6778  *         - couldn't create instance (error printed)
6779  *         - couldn't create, modify, or delete pg (error printed)
6780  *         - couldn't create, modify, or delete dependent (error printed)
6781  *         - couldn't import instance (error printed)
6782  *   EROFS - couldn't create temporary service (repository read-only)
6783  *         - couldn't import into temporary service (repository read-only)
6784  *         - couldn't create service (repository read-only)
6785  *         - couldn't import dependent (repository read-only)
6786  *         - couldn't create instance (repository read-only)
6787  *         - couldn't create, modify, or delete pg or dependent
6788  *         - couldn't import instance (repository read-only)
6789  *   EACCES - couldn't create temporary service (backend access denied)
6790  *          - couldn't import into temporary service (backend access denied)
6791  *          - couldn't create service (backend access denied)
6792  *          - couldn't import dependent (backend access denied)
6793  *          - couldn't create instance (backend access denied)
6794  *          - couldn't create, modify, or delete pg or dependent
6795  *          - couldn't import instance (backend access denied)
6796  *   EINVAL - service name is invalid (error printed)
6797  *          - service name is too long (error printed)
6798  *          - s has invalid pgroup (error printed)
6799  *          - s has invalid dependent (error printed)
6800  *          - instance name is invalid (error printed)
6801  *          - instance entity_t is invalid (error printed)
6802  *   EEXIST - couldn't create temporary service (already exists) (error printed)
6803  *          - couldn't import dependent (dependency pg already exists) (printed)
6804  *          - dependency collision in dependent service (error printed)
6805  *   EBUSY - temporary service deleted (error printed)
6806  *         - property group added to temporary service (error printed)
6807  *         - new property group changed or was deleted (error printed)
6808  *         - service was added unexpectedly (error printed)
6809  *         - service was deleted unexpectedly (error printed)
6810  *         - property group added to new service (error printed)
6811  *         - instance added unexpectedly (error printed)
6812  *         - instance deleted unexpectedly (error printed)
6813  *         - dependent service deleted unexpectedly (error printed)
6814  *         - pg was added, changed, or deleted (error printed)
6815  *         - dependent pg changed (error printed)
6816  *         - temporary instance added, changed, or deleted (error printed)
6817  *   EBADF - a last-import snapshot is corrupt (error printed)
6818  *         - the service is corrupt (error printed)
6819  *         - a dependent is corrupt (error printed)
6820  *         - an instance is corrupt (error printed)
6821  *         - an instance has a corrupt last-import snapshot (error printed)
6822  *         - dependent target has a corrupt snapshot (error printed)
6823  *   -1 - unknown libscf error (error printed)
6824  */
6825 static int
6826 lscf_service_import(void *v, void *pvt)
6827 {
6828         entity_t *s = v;
6829         scf_callback_t cbdata;
6830         scf_callback_t *lcbdata = pvt;
6831         scf_scope_t *scope = lcbdata->sc_parent;
6832         entity_t *inst, linst;
6833         int r;
6834         int fresh = 0;
6835         scf_snaplevel_t *running;
6836         int have_ge = 0;
6837 
6838         const char * const ts_deleted = gettext("Temporary service svc:/%s "
6839             "was deleted unexpectedly.\n");
6840         const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6841             "changed unexpectedly (property group added).\n");
6842         const char * const s_deleted =
6843             gettext("%s was deleted unexpectedly.\n");
6844         const char * const i_deleted =
6845             gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6846         const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6847             "is corrupt (missing service snaplevel).\n");
6848         const char * const s_mfile_upd =
6849             gettext("Unable to update the manifest file connection "
6850             "for %s\n");
6851 
6852         li_only = 0;
6853         /* Validate the service name */
6854         if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6855                 switch (scf_error()) {
6856                 case SCF_ERROR_CONNECTION_BROKEN:
6857                         return (stash_scferror(lcbdata));
6858 
6859                 case SCF_ERROR_INVALID_ARGUMENT:
6860                         warn(gettext("\"%s\" is an invalid service name.  "
6861                             "Cannot import.\n"), s->sc_name);
6862                         return (stash_scferror(lcbdata));
6863 
6864                 case SCF_ERROR_NOT_FOUND:
6865                         break;
6866 
6867                 case SCF_ERROR_HANDLE_MISMATCH:
6868                 case SCF_ERROR_NOT_BOUND:
6869                 case SCF_ERROR_NOT_SET:
6870                 default:
6871                         bad_error("scf_scope_get_service", scf_error());
6872                 }
6873         }
6874 
6875         /* create temporary service */
6876         /*
6877          * the size of the buffer was reduced to max_scf_name_len to prevent
6878          * hitting bug 6681151.  After the bug fix, the size of the buffer
6879          * should be restored to its original value (max_scf_name_len +1)
6880          */
6881         r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6882         if (r < 0)
6883                 bad_error("snprintf", errno);
6884         if (r > max_scf_name_len) {
6885                 warn(gettext(
6886                     "Service name \"%s\" is too long.  Cannot import.\n"),
6887                     s->sc_name);
6888                 lcbdata->sc_err = EINVAL;
6889                 return (UU_WALK_ERROR);
6890         }
6891 
6892         if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6893                 switch (scf_error()) {
6894                 case SCF_ERROR_CONNECTION_BROKEN:
6895                 case SCF_ERROR_NO_RESOURCES:
6896                 case SCF_ERROR_BACKEND_READONLY:
6897                 case SCF_ERROR_BACKEND_ACCESS:
6898                         return (stash_scferror(lcbdata));
6899 
6900                 case SCF_ERROR_EXISTS:
6901                         warn(gettext(
6902                             "Temporary service \"%s\" must be deleted before "
6903                             "this manifest can be imported.\n"), imp_tsname);
6904                         return (stash_scferror(lcbdata));
6905 
6906                 case SCF_ERROR_PERMISSION_DENIED:
6907                         warn(gettext("Could not create temporary service "
6908                             "\"%s\" (permission denied).\n"), imp_tsname);
6909                         return (stash_scferror(lcbdata));
6910 
6911                 case SCF_ERROR_INVALID_ARGUMENT:
6912                 case SCF_ERROR_HANDLE_MISMATCH:
6913                 case SCF_ERROR_NOT_BOUND:
6914                 case SCF_ERROR_NOT_SET:
6915                 default:
6916                         bad_error("scf_scope_add_service", scf_error());
6917                 }
6918         }
6919 
6920         r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6921         if (r < 0)
6922                 bad_error("snprintf", errno);
6923 
6924         cbdata.sc_handle = lcbdata->sc_handle;
6925         cbdata.sc_parent = imp_tsvc;
6926         cbdata.sc_service = 1;
6927         cbdata.sc_source_fmri = s->sc_fmri;
6928         cbdata.sc_target_fmri = imp_str;
6929         cbdata.sc_flags = 0;
6930 
6931         if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6932             UU_DEFAULT) != 0) {
6933                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6934                         bad_error("uu_list_walk", uu_error());
6935 
6936                 lcbdata->sc_err = cbdata.sc_err;
6937                 switch (cbdata.sc_err) {
6938                 case ECONNABORTED:
6939                         goto connaborted;
6940 
6941                 case ECANCELED:
6942                         warn(ts_deleted, imp_tsname);
6943                         lcbdata->sc_err = EBUSY;
6944                         return (UU_WALK_ERROR);
6945 
6946                 case EEXIST:
6947                         warn(ts_pg_added, imp_tsname);
6948                         lcbdata->sc_err = EBUSY;
6949                         return (UU_WALK_ERROR);
6950                 }
6951 
6952                 r = UU_WALK_ERROR;
6953                 goto deltemp;
6954         }
6955 
6956         if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6957             UU_DEFAULT) != 0) {
6958                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6959                         bad_error("uu_list_walk", uu_error());
6960 
6961                 lcbdata->sc_err = cbdata.sc_err;
6962                 switch (cbdata.sc_err) {
6963                 case ECONNABORTED:
6964                         goto connaborted;
6965 
6966                 case ECANCELED:
6967                         warn(ts_deleted, imp_tsname);
6968                         lcbdata->sc_err = EBUSY;
6969                         return (UU_WALK_ERROR);
6970 
6971                 case EEXIST:
6972                         warn(ts_pg_added, imp_tsname);
6973                         lcbdata->sc_err = EBUSY;
6974                         return (UU_WALK_ERROR);
6975                 }
6976 
6977                 r = UU_WALK_ERROR;
6978                 goto deltemp;
6979         }
6980 
6981         if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6982                 switch (scf_error()) {
6983                 case SCF_ERROR_NOT_FOUND:
6984                         break;
6985 
6986                 case SCF_ERROR_CONNECTION_BROKEN:
6987                         goto connaborted;
6988 
6989                 case SCF_ERROR_INVALID_ARGUMENT:
6990                 case SCF_ERROR_HANDLE_MISMATCH:
6991                 case SCF_ERROR_NOT_BOUND:
6992                 case SCF_ERROR_NOT_SET:
6993                 default:
6994                         bad_error("scf_scope_get_service", scf_error());
6995                 }
6996 
6997                 if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6998                         switch (scf_error()) {
6999                         case SCF_ERROR_CONNECTION_BROKEN:
7000                                 goto connaborted;
7001 
7002                         case SCF_ERROR_NO_RESOURCES:
7003                         case SCF_ERROR_BACKEND_READONLY:
7004                         case SCF_ERROR_BACKEND_ACCESS:
7005                                 r = stash_scferror(lcbdata);
7006                                 goto deltemp;
7007 
7008                         case SCF_ERROR_EXISTS:
7009                                 warn(gettext("Scope \"%s\" changed unexpectedly"
7010                                     " (service \"%s\" added).\n"),
7011                                     SCF_SCOPE_LOCAL, s->sc_name);
7012                                 lcbdata->sc_err = EBUSY;
7013                                 goto deltemp;
7014 
7015                         case SCF_ERROR_PERMISSION_DENIED:
7016                                 warn(gettext("Could not create service \"%s\" "
7017                                     "(permission denied).\n"), s->sc_name);
7018                                 goto deltemp;
7019 
7020                         case SCF_ERROR_INVALID_ARGUMENT:
7021                         case SCF_ERROR_HANDLE_MISMATCH:
7022                         case SCF_ERROR_NOT_BOUND:
7023                         case SCF_ERROR_NOT_SET:
7024                         default:
7025                                 bad_error("scf_scope_add_service", scf_error());
7026                         }
7027                 }
7028 
7029                 s->sc_import_state = IMPORT_PROP_BEGUN;
7030 
7031                 /* import service properties */
7032                 cbdata.sc_handle = lcbdata->sc_handle;
7033                 cbdata.sc_parent = imp_svc;
7034                 cbdata.sc_service = 1;
7035                 cbdata.sc_flags = lcbdata->sc_flags;
7036                 cbdata.sc_source_fmri = s->sc_fmri;
7037                 cbdata.sc_target_fmri = s->sc_fmri;
7038 
7039                 if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7040                     &cbdata, UU_DEFAULT) != 0) {
7041                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7042                                 bad_error("uu_list_walk", uu_error());
7043 
7044                         lcbdata->sc_err = cbdata.sc_err;
7045                         switch (cbdata.sc_err) {
7046                         case ECONNABORTED:
7047                                 goto connaborted;
7048 
7049                         case ECANCELED:
7050                                 warn(s_deleted, s->sc_fmri);
7051                                 lcbdata->sc_err = EBUSY;
7052                                 return (UU_WALK_ERROR);
7053 
7054                         case EEXIST:
7055                                 warn(gettext("%s changed unexpectedly "
7056                                     "(property group added).\n"), s->sc_fmri);
7057                                 lcbdata->sc_err = EBUSY;
7058                                 return (UU_WALK_ERROR);
7059 
7060                         case EINVAL:
7061                                 /* caught above */
7062                                 bad_error("entity_pgroup_import",
7063                                     cbdata.sc_err);
7064                         }
7065 
7066                         r = UU_WALK_ERROR;
7067                         goto deltemp;
7068                 }
7069 
7070                 cbdata.sc_trans = NULL;
7071                 cbdata.sc_flags = 0;
7072                 if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7073                     &cbdata, UU_DEFAULT) != 0) {
7074                         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7075                                 bad_error("uu_list_walk", uu_error());
7076 
7077                         lcbdata->sc_err = cbdata.sc_err;
7078                         if (cbdata.sc_err == ECONNABORTED)
7079                                 goto connaborted;
7080                         r = UU_WALK_ERROR;
7081                         goto deltemp;
7082                 }
7083 
7084                 s->sc_import_state = IMPORT_PROP_DONE;
7085 
7086                 /*
7087                  * This is a new service, so we can't take previous snapshots
7088                  * or upgrade service properties.
7089                  */
7090                 fresh = 1;
7091                 goto instances;
7092         }
7093 
7094         /* Clear sc_seen for the instances. */
7095         if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7096             (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7097                 bad_error("uu_list_walk", uu_error());
7098 
7099         /*
7100          * Take previous snapshots for all instances.  Even for ones not
7101          * mentioned in the bundle, since we might change their service
7102          * properties.
7103          */
7104         if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7105                 switch (scf_error()) {
7106                 case SCF_ERROR_CONNECTION_BROKEN:
7107                         goto connaborted;
7108 
7109                 case SCF_ERROR_DELETED:
7110                         warn(s_deleted, s->sc_fmri);
7111                         lcbdata->sc_err = EBUSY;
7112                         r = UU_WALK_ERROR;
7113                         goto deltemp;
7114 
7115                 case SCF_ERROR_HANDLE_MISMATCH:
7116                 case SCF_ERROR_NOT_BOUND:
7117                 case SCF_ERROR_NOT_SET:
7118                 default:
7119                         bad_error("scf_iter_service_instances", scf_error());
7120                 }
7121         }
7122 
7123         for (;;) {
7124                 r = scf_iter_next_instance(imp_iter, imp_inst);
7125                 if (r == 0)
7126                         break;
7127                 if (r != 1) {
7128                         switch (scf_error()) {
7129                         case SCF_ERROR_DELETED:
7130                                 warn(s_deleted, s->sc_fmri);
7131                                 lcbdata->sc_err = EBUSY;
7132                                 r = UU_WALK_ERROR;
7133                                 goto deltemp;
7134 
7135                         case SCF_ERROR_CONNECTION_BROKEN:
7136                                 goto connaborted;
7137 
7138                         case SCF_ERROR_NOT_BOUND:
7139                         case SCF_ERROR_HANDLE_MISMATCH:
7140                         case SCF_ERROR_INVALID_ARGUMENT:
7141                         case SCF_ERROR_NOT_SET:
7142                         default:
7143                                 bad_error("scf_iter_next_instance",
7144                                     scf_error());
7145                         }
7146                 }
7147 
7148                 if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7149                         switch (scf_error()) {
7150                         case SCF_ERROR_DELETED:
7151                                 continue;
7152 
7153                         case SCF_ERROR_CONNECTION_BROKEN:
7154                                 goto connaborted;
7155 
7156                         case SCF_ERROR_NOT_SET:
7157                         case SCF_ERROR_NOT_BOUND:
7158                         default:
7159                                 bad_error("scf_instance_get_name", scf_error());
7160                         }
7161                 }
7162 
7163                 if (g_verbose)
7164                         warn(gettext(
7165                             "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7166                             snap_previous, s->sc_name, imp_str);
7167 
7168                 r = take_snap(imp_inst, snap_previous, imp_snap);
7169                 switch (r) {
7170                 case 0:
7171                         break;
7172 
7173                 case ECANCELED:
7174                         continue;
7175 
7176                 case ECONNABORTED:
7177                         goto connaborted;
7178 
7179                 case EPERM:
7180                         warn(gettext("Could not take \"%s\" snapshot of "
7181                             "svc:/%s:%s (permission denied).\n"),
7182                             snap_previous, s->sc_name, imp_str);
7183                         lcbdata->sc_err = r;
7184                         return (UU_WALK_ERROR);
7185 
7186                 case ENOSPC:
7187                 case -1:
7188                         lcbdata->sc_err = r;
7189                         r = UU_WALK_ERROR;
7190                         goto deltemp;
7191 
7192                 default:
7193                         bad_error("take_snap", r);
7194                 }
7195 
7196                 linst.sc_name = imp_str;
7197                 inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7198                     &linst, NULL, NULL);
7199                 if (inst != NULL) {
7200                         inst->sc_import_state = IMPORT_PREVIOUS;
7201                         inst->sc_seen = 1;
7202                 }
7203         }
7204 
7205         /*
7206          * Create the new instances and take previous snapshots of
7207          * them.  This is not necessary, but it maximizes data preservation.
7208          */
7209         for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7210             inst != NULL;
7211             inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7212             inst)) {
7213                 if (inst->sc_seen)
7214                         continue;
7215 
7216                 if (scf_service_add_instance(imp_svc, inst->sc_name,
7217                     imp_inst) != 0) {
7218                         switch (scf_error()) {
7219                         case SCF_ERROR_CONNECTION_BROKEN:
7220                                 goto connaborted;
7221 
7222                         case SCF_ERROR_BACKEND_READONLY:
7223                         case SCF_ERROR_BACKEND_ACCESS:
7224                         case SCF_ERROR_NO_RESOURCES:
7225                                 r = stash_scferror(lcbdata);
7226                                 goto deltemp;
7227 
7228                         case SCF_ERROR_EXISTS:
7229                                 warn(gettext("%s changed unexpectedly "
7230                                     "(instance \"%s\" added).\n"), s->sc_fmri,
7231                                     inst->sc_name);
7232                                 lcbdata->sc_err = EBUSY;
7233                                 r = UU_WALK_ERROR;
7234                                 goto deltemp;
7235 
7236                         case SCF_ERROR_INVALID_ARGUMENT:
7237                                 warn(gettext("Service \"%s\" has instance with "
7238                                     "invalid name \"%s\".\n"), s->sc_name,
7239                                     inst->sc_name);
7240                                 r = stash_scferror(lcbdata);
7241                                 goto deltemp;
7242 
7243                         case SCF_ERROR_PERMISSION_DENIED:
7244                                 warn(gettext("Could not create instance \"%s\" "
7245                                     "in %s (permission denied).\n"),
7246                                     inst->sc_name, s->sc_fmri);
7247                                 r = stash_scferror(lcbdata);
7248                                 goto deltemp;
7249 
7250                         case SCF_ERROR_HANDLE_MISMATCH:
7251                         case SCF_ERROR_NOT_BOUND:
7252                         case SCF_ERROR_NOT_SET:
7253                         default:
7254                                 bad_error("scf_service_add_instance",
7255                                     scf_error());
7256                         }
7257                 }
7258 
7259                 if (g_verbose)
7260                         warn(gettext("Taking \"%s\" snapshot for "
7261                             "new service %s.\n"), snap_previous, inst->sc_fmri);
7262                 r = take_snap(imp_inst, snap_previous, imp_snap);
7263                 switch (r) {
7264                 case 0:
7265                         break;
7266 
7267                 case ECANCELED:
7268                         warn(i_deleted, s->sc_fmri, inst->sc_name);
7269                         lcbdata->sc_err = EBUSY;
7270                         r = UU_WALK_ERROR;
7271                         goto deltemp;
7272 
7273                 case ECONNABORTED:
7274                         goto connaborted;
7275 
7276                 case EPERM:
7277                         warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7278                         lcbdata->sc_err = r;
7279                         r = UU_WALK_ERROR;
7280                         goto deltemp;
7281 
7282                 case ENOSPC:
7283                 case -1:
7284                         r = UU_WALK_ERROR;
7285                         goto deltemp;
7286 
7287                 default:
7288                         bad_error("take_snap", r);
7289                 }
7290         }
7291 
7292         s->sc_import_state = IMPORT_PREVIOUS;
7293 
7294         /*
7295          * Upgrade service properties, if we can find a last-import snapshot.
7296          * Any will do because we don't support different service properties
7297          * in different manifests, so all snaplevels of the service in all of
7298          * the last-import snapshots of the instances should be the same.
7299          */
7300         if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7301                 switch (scf_error()) {
7302                 case SCF_ERROR_CONNECTION_BROKEN:
7303                         goto connaborted;
7304 
7305                 case SCF_ERROR_DELETED:
7306                         warn(s_deleted, s->sc_fmri);
7307                         lcbdata->sc_err = EBUSY;
7308                         r = UU_WALK_ERROR;
7309                         goto deltemp;
7310 
7311                 case SCF_ERROR_HANDLE_MISMATCH:
7312                 case SCF_ERROR_NOT_BOUND:
7313                 case SCF_ERROR_NOT_SET:
7314                 default:
7315                         bad_error("scf_iter_service_instances", scf_error());
7316                 }
7317         }
7318 
7319         for (;;) {
7320                 r = scf_iter_next_instance(imp_iter, imp_inst);
7321                 if (r == -1) {
7322                         switch (scf_error()) {
7323                         case SCF_ERROR_DELETED:
7324                                 warn(s_deleted, s->sc_fmri);
7325                                 lcbdata->sc_err = EBUSY;
7326                                 r = UU_WALK_ERROR;
7327                                 goto deltemp;
7328 
7329                         case SCF_ERROR_CONNECTION_BROKEN:
7330                                 goto connaborted;
7331 
7332                         case SCF_ERROR_NOT_BOUND:
7333                         case SCF_ERROR_HANDLE_MISMATCH:
7334                         case SCF_ERROR_INVALID_ARGUMENT:
7335                         case SCF_ERROR_NOT_SET:
7336                         default:
7337                                 bad_error("scf_iter_next_instance",
7338                                     scf_error());
7339                         }
7340                 }
7341 
7342                 if (r == 0) {
7343                         /*
7344                          * Didn't find any last-import snapshots.  Override-
7345                          * import the properties.  Unless one of the instances
7346                          * has a general/enabled property, in which case we're
7347                          * probably running a last-import-capable svccfg for
7348                          * the first time, and we should only take the
7349                          * last-import snapshot.
7350                          */
7351                         if (have_ge) {
7352                                 pgroup_t *mfpg;
7353                                 scf_callback_t mfcbdata;
7354 
7355                                 li_only = 1;
7356                                 no_refresh = 1;
7357                                 /*
7358                                  * Need to go ahead and import the manifestfiles
7359                                  * pg if it exists. If the last-import snapshot
7360                                  * upgrade code is ever removed this code can
7361                                  * be removed as well.
7362                                  */
7363                                 mfpg = internal_pgroup_find(s,
7364                                     SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7365 
7366                                 if (mfpg) {
7367                                         mfcbdata.sc_handle = g_hndl;
7368                                         mfcbdata.sc_parent = imp_svc;
7369                                         mfcbdata.sc_service = 1;
7370                                         mfcbdata.sc_flags = SCI_FORCE;
7371                                         mfcbdata.sc_source_fmri = s->sc_fmri;
7372                                         mfcbdata.sc_target_fmri = s->sc_fmri;
7373                                         if (entity_pgroup_import(mfpg,
7374                                             &mfcbdata) != UU_WALK_NEXT) {
7375                                                 warn(s_mfile_upd, s->sc_fmri);
7376                                                 r = UU_WALK_ERROR;
7377                                                 goto deltemp;
7378                                         }
7379                                 }
7380                                 break;
7381                         }
7382 
7383                         s->sc_import_state = IMPORT_PROP_BEGUN;
7384 
7385                         cbdata.sc_handle = g_hndl;
7386                         cbdata.sc_parent = imp_svc;
7387                         cbdata.sc_service = 1;
7388                         cbdata.sc_flags = SCI_FORCE;
7389                         cbdata.sc_source_fmri = s->sc_fmri;
7390                         cbdata.sc_target_fmri = s->sc_fmri;
7391                         if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7392                             &cbdata, UU_DEFAULT) != 0) {
7393                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7394                                         bad_error("uu_list_walk", uu_error());
7395                                 lcbdata->sc_err = cbdata.sc_err;
7396                                 switch (cbdata.sc_err) {
7397                                 case ECONNABORTED:
7398                                         goto connaborted;
7399 
7400                                 case ECANCELED:
7401                                         warn(s_deleted, s->sc_fmri);
7402                                         lcbdata->sc_err = EBUSY;
7403                                         break;
7404 
7405                                 case EINVAL:    /* caught above */
7406                                 case EEXIST:
7407                                         bad_error("entity_pgroup_import",
7408                                             cbdata.sc_err);
7409                                 }
7410 
7411                                 r = UU_WALK_ERROR;
7412                                 goto deltemp;
7413                         }
7414 
7415                         cbdata.sc_trans = NULL;
7416                         cbdata.sc_flags = 0;
7417                         if (uu_list_walk(s->sc_dependents,
7418                             lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7419                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7420                                         bad_error("uu_list_walk", uu_error());
7421                                 lcbdata->sc_err = cbdata.sc_err;
7422                                 if (cbdata.sc_err == ECONNABORTED)
7423                                         goto connaborted;
7424                                 r = UU_WALK_ERROR;
7425                                 goto deltemp;
7426                         }
7427                         break;
7428                 }
7429 
7430                 if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7431                     imp_snap) != 0) {
7432                         switch (scf_error()) {
7433                         case SCF_ERROR_DELETED:
7434                                 continue;
7435 
7436                         case SCF_ERROR_NOT_FOUND:
7437                                 break;
7438 
7439                         case SCF_ERROR_CONNECTION_BROKEN:
7440                                 goto connaborted;
7441 
7442                         case SCF_ERROR_HANDLE_MISMATCH:
7443                         case SCF_ERROR_NOT_BOUND:
7444                         case SCF_ERROR_INVALID_ARGUMENT:
7445                         case SCF_ERROR_NOT_SET:
7446                         default:
7447                                 bad_error("scf_instance_get_snapshot",
7448                                     scf_error());
7449                         }
7450 
7451                         if (have_ge)
7452                                 continue;
7453 
7454                         /*
7455                          * Check for a general/enabled property.  This is how
7456                          * we tell whether to import if there turn out to be
7457                          * no last-import snapshots.
7458                          */
7459                         if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7460                             imp_pg) == 0) {
7461                                 if (scf_pg_get_property(imp_pg,
7462                                     SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7463                                         have_ge = 1;
7464                                 } else {
7465                                         switch (scf_error()) {
7466                                         case SCF_ERROR_DELETED:
7467                                         case SCF_ERROR_NOT_FOUND:
7468                                                 continue;
7469 
7470                                         case SCF_ERROR_INVALID_ARGUMENT:
7471                                         case SCF_ERROR_HANDLE_MISMATCH:
7472                                         case SCF_ERROR_CONNECTION_BROKEN:
7473                                         case SCF_ERROR_NOT_BOUND:
7474                                         case SCF_ERROR_NOT_SET:
7475                                         default:
7476                                                 bad_error("scf_pg_get_property",
7477                                                     scf_error());
7478                                         }
7479                                 }
7480                         } else {
7481                                 switch (scf_error()) {
7482                                 case SCF_ERROR_DELETED:
7483                                 case SCF_ERROR_NOT_FOUND:
7484                                         continue;
7485 
7486                                 case SCF_ERROR_CONNECTION_BROKEN:
7487                                         goto connaborted;
7488 
7489                                 case SCF_ERROR_NOT_BOUND:
7490                                 case SCF_ERROR_NOT_SET:
7491                                 case SCF_ERROR_INVALID_ARGUMENT:
7492                                 case SCF_ERROR_HANDLE_MISMATCH:
7493                                 default:
7494                                         bad_error("scf_instance_get_pg",
7495                                             scf_error());
7496                                 }
7497                         }
7498                         continue;
7499                 }
7500 
7501                 /* find service snaplevel */
7502                 r = get_snaplevel(imp_snap, 1, imp_snpl);
7503                 switch (r) {
7504                 case 0:
7505                         break;
7506 
7507                 case ECONNABORTED:
7508                         goto connaborted;
7509 
7510                 case ECANCELED:
7511                         continue;
7512 
7513                 case ENOENT:
7514                         if (scf_instance_get_name(imp_inst, imp_str,
7515                             imp_str_sz) < 0)
7516                                 (void) strcpy(imp_str, "?");
7517                         warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7518                         lcbdata->sc_err = EBADF;
7519                         r = UU_WALK_ERROR;
7520                         goto deltemp;
7521 
7522                 default:
7523                         bad_error("get_snaplevel", r);
7524                 }
7525 
7526                 if (scf_instance_get_snapshot(imp_inst, snap_running,
7527                     imp_rsnap) != 0) {
7528                         switch (scf_error()) {
7529                         case SCF_ERROR_DELETED:
7530                                 continue;
7531 
7532                         case SCF_ERROR_NOT_FOUND:
7533                                 break;
7534 
7535                         case SCF_ERROR_CONNECTION_BROKEN:
7536                                 goto connaborted;
7537 
7538                         case SCF_ERROR_INVALID_ARGUMENT:
7539                         case SCF_ERROR_HANDLE_MISMATCH:
7540                         case SCF_ERROR_NOT_BOUND:
7541                         case SCF_ERROR_NOT_SET:
7542                         default:
7543                                 bad_error("scf_instance_get_snapshot",
7544                                     scf_error());
7545                         }
7546                         running = NULL;
7547                 } else {
7548                         r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7549                         switch (r) {
7550                         case 0:
7551                                 running = imp_rsnpl;
7552                                 break;
7553 
7554                         case ECONNABORTED:
7555                                 goto connaborted;
7556 
7557                         case ECANCELED:
7558                                 continue;
7559 
7560                         case ENOENT:
7561                                 if (scf_instance_get_name(imp_inst, imp_str,
7562                                     imp_str_sz) < 0)
7563                                         (void) strcpy(imp_str, "?");
7564                                 warn(badsnap, snap_running, s->sc_name,
7565                                     imp_str);
7566                                 lcbdata->sc_err = EBADF;
7567                                 r = UU_WALK_ERROR;
7568                                 goto deltemp;
7569 
7570                         default:
7571                                 bad_error("get_snaplevel", r);
7572                         }
7573                 }
7574 
7575                 if (g_verbose) {
7576                         if (scf_instance_get_name(imp_inst, imp_str,
7577                             imp_str_sz) < 0)
7578                                 (void) strcpy(imp_str, "?");
7579                         warn(gettext("Upgrading properties of %s according to "
7580                             "instance \"%s\".\n"), s->sc_fmri, imp_str);
7581                 }
7582 
7583                 /* upgrade service properties */
7584                 r = upgrade_props(imp_svc, running, imp_snpl, s);
7585                 if (r == 0)
7586                         break;
7587 
7588                 switch (r) {
7589                 case ECONNABORTED:
7590                         goto connaborted;
7591 
7592                 case ECANCELED:
7593                         warn(s_deleted, s->sc_fmri);
7594                         lcbdata->sc_err = EBUSY;
7595                         break;
7596 
7597                 case ENODEV:
7598                         if (scf_instance_get_name(imp_inst, imp_str,
7599                             imp_str_sz) < 0)
7600                                 (void) strcpy(imp_str, "?");
7601                         warn(i_deleted, s->sc_fmri, imp_str);
7602                         lcbdata->sc_err = EBUSY;
7603                         break;
7604 
7605                 default:
7606                         lcbdata->sc_err = r;
7607                 }
7608 
7609                 r = UU_WALK_ERROR;
7610                 goto deltemp;
7611         }
7612 
7613         s->sc_import_state = IMPORT_PROP_DONE;
7614 
7615 instances:
7616         /* import instances */
7617         cbdata.sc_handle = lcbdata->sc_handle;
7618         cbdata.sc_parent = imp_svc;
7619         cbdata.sc_service = 1;
7620         cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7621         cbdata.sc_general = NULL;
7622 
7623         if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7624             lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7625                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7626                         bad_error("uu_list_walk", uu_error());
7627 
7628                 lcbdata->sc_err = cbdata.sc_err;
7629                 if (cbdata.sc_err == ECONNABORTED)
7630                         goto connaborted;
7631                 r = UU_WALK_ERROR;
7632                 goto deltemp;
7633         }
7634 
7635         s->sc_import_state = IMPORT_COMPLETE;
7636         r = UU_WALK_NEXT;
7637 
7638 deltemp:
7639         /* delete temporary service */
7640         if (scf_service_delete(imp_tsvc) != 0) {
7641                 switch (scf_error()) {
7642                 case SCF_ERROR_DELETED:
7643                         break;
7644 
7645                 case SCF_ERROR_CONNECTION_BROKEN:
7646                         goto connaborted;
7647 
7648                 case SCF_ERROR_EXISTS:
7649                         warn(gettext(
7650                             "Could not delete svc:/%s (instances exist).\n"),
7651                             imp_tsname);
7652                         break;
7653 
7654                 case SCF_ERROR_NOT_SET:
7655                 case SCF_ERROR_NOT_BOUND:
7656                 default:
7657                         bad_error("scf_service_delete", scf_error());
7658                 }
7659         }
7660 
7661         return (r);
7662 
7663 connaborted:
7664         warn(gettext("Could not delete svc:/%s "
7665             "(repository connection broken).\n"), imp_tsname);
7666         lcbdata->sc_err = ECONNABORTED;
7667         return (UU_WALK_ERROR);
7668 }
7669 
7670 static const char *
7671 import_progress(int st)
7672 {
7673         switch (st) {
7674         case 0:
7675                 return (gettext("not reached."));
7676 
7677         case IMPORT_PREVIOUS:
7678                 return (gettext("previous snapshot taken."));
7679 
7680         case IMPORT_PROP_BEGUN:
7681                 return (gettext("some properties imported."));
7682 
7683         case IMPORT_PROP_DONE:
7684                 return (gettext("properties imported."));
7685 
7686         case IMPORT_COMPLETE:
7687                 return (gettext("imported."));
7688 
7689         case IMPORT_REFRESHED:
7690                 return (gettext("refresh requested."));
7691 
7692         default:
7693 #ifndef NDEBUG
7694                 (void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7695                     __FILE__, __LINE__, st);
7696 #endif
7697                 abort();
7698                 /* NOTREACHED */
7699         }
7700 }
7701 
7702 /*
7703  * Returns
7704  *   0 - success
7705  *     - fmri wasn't found (error printed)
7706  *     - entity was deleted (error printed)
7707  *     - backend denied access (error printed)
7708  *   ENOMEM - out of memory (error printed)
7709  *   ECONNABORTED - repository connection broken (error printed)
7710  *   EPERM - permission denied (error printed)
7711  *   -1 - unknown libscf error (error printed)
7712  */
7713 static int
7714 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7715 {
7716         scf_error_t serr;
7717         void *ent;
7718         int issvc;
7719         int r;
7720 
7721         const char *deleted = gettext("Could not refresh %s (deleted).\n");
7722         const char *dpt_deleted = gettext("Could not refresh %s "
7723             "(dependent \"%s\" of %s) (deleted).\n");
7724 
7725         serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7726         switch (serr) {
7727         case SCF_ERROR_NONE:
7728                 break;
7729 
7730         case SCF_ERROR_NO_MEMORY:
7731                 if (name == NULL)
7732                         warn(gettext("Could not refresh %s (out of memory).\n"),
7733                             fmri);
7734                 else
7735                         warn(gettext("Could not refresh %s "
7736                             "(dependent \"%s\" of %s) (out of memory).\n"),
7737                             fmri, name, d_fmri);
7738                 return (ENOMEM);
7739 
7740         case SCF_ERROR_NOT_FOUND:
7741                 if (name == NULL)
7742                         warn(deleted, fmri);
7743                 else
7744                         warn(dpt_deleted, fmri, name, d_fmri);
7745                 return (0);
7746 
7747         case SCF_ERROR_INVALID_ARGUMENT:
7748         case SCF_ERROR_CONSTRAINT_VIOLATED:
7749         default:
7750                 bad_error("fmri_to_entity", serr);
7751         }
7752 
7753         r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7754         switch (r) {
7755         case 0:
7756                 break;
7757 
7758         case ECONNABORTED:
7759                 if (name != NULL)
7760                         warn(gettext("Could not refresh %s "
7761                             "(dependent \"%s\" of %s) "
7762                             "(repository connection broken).\n"), fmri, name,
7763                             d_fmri);
7764                 return (r);
7765 
7766         case ECANCELED:
7767                 if (name == NULL)
7768                         warn(deleted, fmri);
7769                 else
7770                         warn(dpt_deleted, fmri, name, d_fmri);
7771                 return (0);
7772 
7773         case EACCES:
7774                 if (!g_verbose)
7775                         return (0);
7776                 if (name == NULL)
7777                         warn(gettext("Could not refresh %s "
7778                             "(backend access denied).\n"), fmri);
7779                 else
7780                         warn(gettext("Could not refresh %s "
7781                             "(dependent \"%s\" of %s) "
7782                             "(backend access denied).\n"), fmri, name, d_fmri);
7783                 return (0);
7784 
7785         case EPERM:
7786                 if (name == NULL)
7787                         warn(gettext("Could not refresh %s "
7788                             "(permission denied).\n"), fmri);
7789                 else
7790                         warn(gettext("Could not refresh %s "
7791                             "(dependent \"%s\" of %s) "
7792                             "(permission denied).\n"), fmri, name, d_fmri);
7793                 return (r);
7794 
7795         case ENOSPC:
7796                 if (name == NULL)
7797                         warn(gettext("Could not refresh %s "
7798                             "(repository server out of resources).\n"),
7799                             fmri);
7800                 else
7801                         warn(gettext("Could not refresh %s "
7802                             "(dependent \"%s\" of %s) "
7803                             "(repository server out of resources).\n"),
7804                             fmri, name, d_fmri);
7805                 return (r);
7806 
7807         case -1:
7808                 scfwarn();
7809                 return (r);
7810 
7811         default:
7812                 bad_error("refresh_entity", r);
7813         }
7814 
7815         if (issvc)
7816                 scf_service_destroy(ent);
7817         else
7818                 scf_instance_destroy(ent);
7819 
7820         return (0);
7821 }
7822 
7823 static int
7824 alloc_imp_globals()
7825 {
7826         int r;
7827 
7828         const char * const emsg_nomem = gettext("Out of memory.\n");
7829         const char * const emsg_nores =
7830             gettext("svc.configd is out of resources.\n");
7831 
7832         imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7833             max_scf_name_len : max_scf_fmri_len) + 1;
7834 
7835         if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7836             (imp_svc = scf_service_create(g_hndl)) == NULL ||
7837             (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7838             (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7839             (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7840             (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7841             (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7842             (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7843             (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7844             (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7845             (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7846             (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7847             (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7848             (imp_prop = scf_property_create(g_hndl)) == NULL ||
7849             (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7850             (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7851             (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7852             (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7853             (imp_str = malloc(imp_str_sz)) == NULL ||
7854             (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7855             (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7856             (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7857             (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7858             (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7859             (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7860             (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7861             (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7862             (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7863             (ud_prop = scf_property_create(g_hndl)) == NULL ||
7864             (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7865             (ud_val = scf_value_create(g_hndl)) == NULL ||
7866             (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7867             (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7868             (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7869             (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7870             (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7871             (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7872                 if (scf_error() == SCF_ERROR_NO_RESOURCES)
7873                         warn(emsg_nores);
7874                 else
7875                         warn(emsg_nomem);
7876 
7877                 return (-1);
7878         }
7879 
7880         r = load_init();
7881         switch (r) {
7882         case 0:
7883                 break;
7884 
7885         case ENOMEM:
7886                 warn(emsg_nomem);
7887                 return (-1);
7888 
7889         default:
7890                 bad_error("load_init", r);
7891         }
7892 
7893         return (0);
7894 }
7895 
7896 static void
7897 free_imp_globals()
7898 {
7899         pgroup_t *old_dpt;
7900         void *cookie;
7901 
7902         load_fini();
7903 
7904         free(ud_ctarg);
7905         free(ud_oldtarg);
7906         free(ud_name);
7907         ud_ctarg = ud_oldtarg = ud_name = NULL;
7908 
7909         scf_transaction_destroy(ud_tx);
7910         ud_tx = NULL;
7911         scf_iter_destroy(ud_iter);
7912         scf_iter_destroy(ud_iter2);
7913         ud_iter = ud_iter2 = NULL;
7914         scf_value_destroy(ud_val);
7915         ud_val = NULL;
7916         scf_property_destroy(ud_prop);
7917         scf_property_destroy(ud_dpt_prop);
7918         ud_prop = ud_dpt_prop = NULL;
7919         scf_pg_destroy(ud_pg);
7920         scf_pg_destroy(ud_cur_depts_pg);
7921         scf_pg_destroy(ud_run_dpts_pg);
7922         ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7923         scf_snaplevel_destroy(ud_snpl);
7924         ud_snpl = NULL;
7925         scf_instance_destroy(ud_inst);
7926         ud_inst = NULL;
7927 
7928         free(imp_str);
7929         free(imp_tsname);
7930         free(imp_fe1);
7931         free(imp_fe2);
7932         imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7933 
7934         cookie = NULL;
7935         while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7936             NULL) {
7937                 free((char *)old_dpt->sc_pgroup_name);
7938                 free((char *)old_dpt->sc_pgroup_fmri);
7939                 internal_pgroup_free(old_dpt);
7940         }
7941         uu_list_destroy(imp_deleted_dpts);
7942 
7943         scf_transaction_destroy(imp_tx);
7944         imp_tx = NULL;
7945         scf_iter_destroy(imp_iter);
7946         scf_iter_destroy(imp_rpg_iter);
7947         scf_iter_destroy(imp_up_iter);
7948         imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7949         scf_property_destroy(imp_prop);
7950         imp_prop = NULL;
7951         scf_pg_destroy(imp_pg);
7952         scf_pg_destroy(imp_pg2);
7953         imp_pg = imp_pg2 = NULL;
7954         scf_snaplevel_destroy(imp_snpl);
7955         scf_snaplevel_destroy(imp_rsnpl);
7956         imp_snpl = imp_rsnpl = NULL;
7957         scf_snapshot_destroy(imp_snap);
7958         scf_snapshot_destroy(imp_lisnap);
7959         scf_snapshot_destroy(imp_tlisnap);
7960         scf_snapshot_destroy(imp_rsnap);
7961         imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7962         scf_instance_destroy(imp_inst);
7963         scf_instance_destroy(imp_tinst);
7964         imp_inst = imp_tinst = NULL;
7965         scf_service_destroy(imp_svc);
7966         scf_service_destroy(imp_tsvc);
7967         imp_svc = imp_tsvc = NULL;
7968         scf_scope_destroy(imp_scope);
7969         imp_scope = NULL;
7970 
7971         load_fini();
7972 }
7973 
7974 int
7975 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7976 {
7977         scf_callback_t cbdata;
7978         int result = 0;
7979         entity_t *svc, *inst;
7980         uu_list_t *insts;
7981         int r;
7982         pgroup_t *old_dpt;
7983         int annotation_set = 0;
7984 
7985         const char * const emsg_nomem = gettext("Out of memory.\n");
7986         const char * const emsg_nores =
7987             gettext("svc.configd is out of resources.\n");
7988 
7989         lscf_prep_hndl();
7990 
7991         if (alloc_imp_globals())
7992                 goto out;
7993 
7994         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7995                 switch (scf_error()) {
7996                 case SCF_ERROR_CONNECTION_BROKEN:
7997                         warn(gettext("Repository connection broken.\n"));
7998                         repository_teardown();
7999                         result = -1;
8000                         goto out;
8001 
8002                 case SCF_ERROR_NOT_FOUND:
8003                 case SCF_ERROR_INVALID_ARGUMENT:
8004                 case SCF_ERROR_NOT_BOUND:
8005                 case SCF_ERROR_HANDLE_MISMATCH:
8006                 default:
8007                         bad_error("scf_handle_get_scope", scf_error());
8008                 }
8009         }
8010 
8011         /* Set up the auditing annotation. */
8012         if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8013                 annotation_set = 1;
8014         } else {
8015                 switch (scf_error()) {
8016                 case SCF_ERROR_CONNECTION_BROKEN:
8017                         warn(gettext("Repository connection broken.\n"));
8018                         repository_teardown();
8019                         result = -1;
8020                         goto out;
8021 
8022                 case SCF_ERROR_INVALID_ARGUMENT:
8023                 case SCF_ERROR_NOT_BOUND:
8024                 case SCF_ERROR_NO_RESOURCES:
8025                 case SCF_ERROR_INTERNAL:
8026                         bad_error("_scf_set_annotation", scf_error());
8027                         /* NOTREACHED */
8028 
8029                 default:
8030                         /*
8031                          * Do not terminate import because of inability to
8032                          * generate annotation audit event.
8033                          */
8034                         warn(gettext("_scf_set_annotation() unexpectedly "
8035                             "failed with return code of %d\n"), scf_error());
8036                         break;
8037                 }
8038         }
8039 
8040         /*
8041          * Clear the sc_import_state's of all services & instances so we can
8042          * report how far we got if we fail.
8043          */
8044         for (svc = uu_list_first(bndl->sc_bundle_services);
8045             svc != NULL;
8046             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8047                 svc->sc_import_state = 0;
8048 
8049                 if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8050                     clear_int, (void *)offsetof(entity_t, sc_import_state),
8051                     UU_DEFAULT) != 0)
8052                         bad_error("uu_list_walk", uu_error());
8053         }
8054 
8055         cbdata.sc_handle = g_hndl;
8056         cbdata.sc_parent = imp_scope;
8057         cbdata.sc_flags = flags;
8058         cbdata.sc_general = NULL;
8059 
8060         if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8061             &cbdata, UU_DEFAULT) == 0) {
8062                 /* Success.  Refresh everything. */
8063 
8064                 if (flags & SCI_NOREFRESH || no_refresh) {
8065                         no_refresh = 0;
8066                         result = 0;
8067                         goto out;
8068                 }
8069 
8070                 for (svc = uu_list_first(bndl->sc_bundle_services);
8071                     svc != NULL;
8072                     svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8073                         pgroup_t *dpt;
8074 
8075                         insts = svc->sc_u.sc_service.sc_service_instances;
8076 
8077                         for (inst = uu_list_first(insts);
8078                             inst != NULL;
8079                             inst = uu_list_next(insts, inst)) {
8080                                 r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8081                                 switch (r) {
8082                                 case 0:
8083                                         break;
8084 
8085                                 case ENOMEM:
8086                                 case ECONNABORTED:
8087                                 case EPERM:
8088                                 case -1:
8089                                         goto progress;
8090 
8091                                 default:
8092                                         bad_error("imp_refresh_fmri", r);
8093                                 }
8094 
8095                                 inst->sc_import_state = IMPORT_REFRESHED;
8096 
8097                                 for (dpt = uu_list_first(inst->sc_dependents);
8098                                     dpt != NULL;
8099                                     dpt = uu_list_next(inst->sc_dependents,
8100                                     dpt))
8101                                         if (imp_refresh_fmri(
8102                                             dpt->sc_pgroup_fmri,
8103                                             dpt->sc_pgroup_name,
8104                                             inst->sc_fmri) != 0)
8105                                                 goto progress;
8106                         }
8107 
8108                         for (dpt = uu_list_first(svc->sc_dependents);
8109                             dpt != NULL;
8110                             dpt = uu_list_next(svc->sc_dependents, dpt))
8111                                 if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8112                                     dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8113                                         goto progress;
8114                 }
8115 
8116                 for (old_dpt = uu_list_first(imp_deleted_dpts);
8117                     old_dpt != NULL;
8118                     old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8119                         if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8120                             old_dpt->sc_pgroup_name,
8121                             old_dpt->sc_parent->sc_fmri) != 0)
8122                                 goto progress;
8123 
8124                 result = 0;
8125                 goto out;
8126         }
8127 
8128         if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8129                 bad_error("uu_list_walk", uu_error());
8130 
8131 printerr:
8132         /* If the error hasn't been printed yet, do so here. */
8133         switch (cbdata.sc_err) {
8134         case ECONNABORTED:
8135                 warn(gettext("Repository connection broken.\n"));
8136                 break;
8137 
8138         case ENOMEM:
8139                 warn(emsg_nomem);
8140                 break;
8141 
8142         case ENOSPC:
8143                 warn(emsg_nores);
8144                 break;
8145 
8146         case EROFS:
8147                 warn(gettext("Repository is read-only.\n"));
8148                 break;
8149 
8150         case EACCES:
8151                 warn(gettext("Repository backend denied access.\n"));
8152                 break;
8153 
8154         case EPERM:
8155         case EINVAL:
8156         case EEXIST:
8157         case EBUSY:
8158         case EBADF:
8159         case -1:
8160                 break;
8161 
8162         default:
8163                 bad_error("lscf_service_import", cbdata.sc_err);
8164         }
8165 
8166 progress:
8167         warn(gettext("Import of %s failed.  Progress:\n"), filename);
8168 
8169         for (svc = uu_list_first(bndl->sc_bundle_services);
8170             svc != NULL;
8171             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8172                 insts = svc->sc_u.sc_service.sc_service_instances;
8173 
8174                 warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8175                     import_progress(svc->sc_import_state));
8176 
8177                 for (inst = uu_list_first(insts);
8178                     inst != NULL;
8179                     inst = uu_list_next(insts, inst))
8180                         warn(gettext("    Instance \"%s\": %s\n"),
8181                             inst->sc_name,
8182                             import_progress(inst->sc_import_state));
8183         }
8184 
8185         if (cbdata.sc_err == ECONNABORTED)
8186                 repository_teardown();
8187 
8188 
8189         result = -1;
8190 
8191 out:
8192         if (annotation_set != 0) {
8193                 /* Turn off annotation.  It is no longer needed. */
8194                 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8195         }
8196 
8197         free_imp_globals();
8198 
8199         return (result);
8200 }
8201 
8202 /*
8203  * _lscf_import_err() summarize the error handling returned by
8204  * lscf_import_{instance | service}_pgs
8205  * Return values are:
8206  * IMPORT_NEXT
8207  * IMPORT_OUT
8208  * IMPORT_BAD
8209  */
8210 
8211 #define IMPORT_BAD      -1
8212 #define IMPORT_NEXT     0
8213 #define IMPORT_OUT      1
8214 
8215 static int
8216 _lscf_import_err(int err, const char *fmri)
8217 {
8218         switch (err) {
8219         case 0:
8220                 if (g_verbose)
8221                         warn(gettext("%s updated.\n"), fmri);
8222                 return (IMPORT_NEXT);
8223 
8224         case ECONNABORTED:
8225                 warn(gettext("Could not update %s "
8226                     "(repository connection broken).\n"), fmri);
8227                 return (IMPORT_OUT);
8228 
8229         case ENOMEM:
8230                 warn(gettext("Could not update %s (out of memory).\n"), fmri);
8231                 return (IMPORT_OUT);
8232 
8233         case ENOSPC:
8234                 warn(gettext("Could not update %s "
8235                     "(repository server out of resources).\n"), fmri);
8236                 return (IMPORT_OUT);
8237 
8238         case ECANCELED:
8239                 warn(gettext(
8240                     "Could not update %s (deleted).\n"), fmri);
8241                 return (IMPORT_NEXT);
8242 
8243         case EPERM:
8244         case EINVAL:
8245         case EBUSY:
8246                 return (IMPORT_NEXT);
8247 
8248         case EROFS:
8249                 warn(gettext("Could not update %s (repository read-only).\n"),
8250                     fmri);
8251                 return (IMPORT_OUT);
8252 
8253         case EACCES:
8254                 warn(gettext("Could not update %s "
8255                     "(backend access denied).\n"), fmri);
8256                 return (IMPORT_NEXT);
8257 
8258         case EEXIST:
8259         default:
8260                 return (IMPORT_BAD);
8261         }
8262 
8263         /*NOTREACHED*/
8264 }
8265 
8266 /*
8267  * The global imp_svc and imp_inst should be set by the caller in the
8268  * check to make sure the service and instance exist that the apply is
8269  * working on.
8270  */
8271 static int
8272 lscf_dependent_apply(void *dpg, void *e)
8273 {
8274         scf_callback_t cb;
8275         pgroup_t *dpt_pgroup = dpg;
8276         pgroup_t *deldpt;
8277         entity_t *ent = e;
8278         int tissvc;
8279         void *sc_ent, *tent;
8280         scf_error_t serr;
8281         int r;
8282 
8283         const char * const dependents = "dependents";
8284         const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8285 
8286         if (issvc)
8287                 sc_ent = imp_svc;
8288         else
8289                 sc_ent = imp_inst;
8290 
8291         if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8292             imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8293             scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8294             imp_prop) != 0) {
8295                 switch (scf_error()) {
8296                 case SCF_ERROR_NOT_FOUND:
8297                 case SCF_ERROR_DELETED:
8298                         break;
8299 
8300                 case SCF_ERROR_CONNECTION_BROKEN:
8301                 case SCF_ERROR_NOT_SET:
8302                 case SCF_ERROR_INVALID_ARGUMENT:
8303                 case SCF_ERROR_HANDLE_MISMATCH:
8304                 case SCF_ERROR_NOT_BOUND:
8305                 default:
8306                         bad_error("entity_get_pg", scf_error());
8307                 }
8308         } else {
8309                 /*
8310                  * Found the dependents/<wip dep> so check to
8311                  * see if the service is different.  If so
8312                  * store the service for later refresh, and
8313                  * delete the wip dependency from the service
8314                  */
8315                 if (scf_property_get_value(imp_prop, ud_val) != 0) {
8316                         switch (scf_error()) {
8317                                 case SCF_ERROR_DELETED:
8318                                         break;
8319 
8320                                 case SCF_ERROR_CONNECTION_BROKEN:
8321                                 case SCF_ERROR_NOT_SET:
8322                                 case SCF_ERROR_INVALID_ARGUMENT:
8323                                 case SCF_ERROR_HANDLE_MISMATCH:
8324                                 case SCF_ERROR_NOT_BOUND:
8325                                 default:
8326                                         bad_error("scf_property_get_value",
8327                                             scf_error());
8328                         }
8329                 }
8330 
8331                 if (scf_value_get_as_string(ud_val, ud_oldtarg,
8332                     max_scf_value_len + 1) < 0)
8333                         bad_error("scf_value_get_as_string", scf_error());
8334 
8335                 r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8336                 switch (r) {
8337                 case 1:
8338                         break;
8339                 case 0:
8340                         if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8341                             &tissvc)) != SCF_ERROR_NONE) {
8342                                 if (serr == SCF_ERROR_NOT_FOUND) {
8343                                         break;
8344                                 } else {
8345                                         bad_error("fmri_to_entity", serr);
8346                                 }
8347                         }
8348 
8349                         if (entity_get_pg(tent, tissvc,
8350                             dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8351                                 serr = scf_error();
8352                                 if (serr == SCF_ERROR_NOT_FOUND ||
8353                                     serr == SCF_ERROR_DELETED) {
8354                                         break;
8355                                 } else {
8356                                         bad_error("entity_get_pg", scf_error());
8357                                 }
8358                         }
8359 
8360                         if (scf_pg_delete(imp_pg) != 0) {
8361                                 serr = scf_error();
8362                                 if (serr == SCF_ERROR_NOT_FOUND ||
8363                                     serr == SCF_ERROR_DELETED) {
8364                                         break;
8365                                 } else {
8366                                         bad_error("scf_pg_delete", scf_error());
8367                                 }
8368                         }
8369 
8370                         deldpt = internal_pgroup_new();
8371                         if (deldpt == NULL)
8372                                 return (ENOMEM);
8373                         deldpt->sc_pgroup_name =
8374                             strdup(dpt_pgroup->sc_pgroup_name);
8375                         deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8376                         if (deldpt->sc_pgroup_name == NULL ||
8377                             deldpt->sc_pgroup_fmri == NULL)
8378                                 return (ENOMEM);
8379                         deldpt->sc_parent = (entity_t *)ent;
8380                         if (uu_list_insert_after(imp_deleted_dpts, NULL,
8381                             deldpt) != 0)
8382                                 uu_die(gettext("libuutil error: %s\n"),
8383                                     uu_strerror(uu_error()));
8384 
8385                         break;
8386                 default:
8387                         bad_error("fmri_equal", r);
8388                 }
8389         }
8390 
8391         cb.sc_handle = g_hndl;
8392         cb.sc_parent = ent;
8393         cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8394         cb.sc_source_fmri = ent->sc_fmri;
8395         cb.sc_target_fmri = ent->sc_fmri;
8396         cb.sc_trans = NULL;
8397         cb.sc_flags = SCI_FORCE;
8398 
8399         if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8400                 return (UU_WALK_ERROR);
8401 
8402         r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8403         switch (r) {
8404         case 0:
8405                 break;
8406 
8407         case ENOMEM:
8408         case ECONNABORTED:
8409         case EPERM:
8410         case -1:
8411                 warn(gettext("Unable to refresh \"%s\"\n"),
8412                     dpt_pgroup->sc_pgroup_fmri);
8413                 return (UU_WALK_ERROR);
8414 
8415         default:
8416                 bad_error("imp_refresh_fmri", r);
8417         }
8418 
8419         return (UU_WALK_NEXT);
8420 }
8421 
8422 /*
8423  * Returns
8424  *   0 - success
8425  *   -1 - lscf_import_instance_pgs() failed.
8426  */
8427 int
8428 lscf_bundle_apply(bundle_t *bndl, const char *file)
8429 {
8430         pgroup_t *old_dpt;
8431         entity_t *svc, *inst;
8432         int annotation_set = 0;
8433         int ret = 0;
8434         int r = 0;
8435 
8436         lscf_prep_hndl();
8437 
8438         if ((ret = alloc_imp_globals()))
8439                 goto out;
8440 
8441         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8442                 scfdie();
8443 
8444         /*
8445          * Set the strings to be used for the security audit annotation
8446          * event.
8447          */
8448         if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8449                 annotation_set = 1;
8450         } else {
8451                 switch (scf_error()) {
8452                 case SCF_ERROR_CONNECTION_BROKEN:
8453                         warn(gettext("Repository connection broken.\n"));
8454                         goto out;
8455 
8456                 case SCF_ERROR_INVALID_ARGUMENT:
8457                 case SCF_ERROR_NOT_BOUND:
8458                 case SCF_ERROR_NO_RESOURCES:
8459                 case SCF_ERROR_INTERNAL:
8460                         bad_error("_scf_set_annotation", scf_error());
8461                         /* NOTREACHED */
8462 
8463                 default:
8464                         /*
8465                          * Do not abort apply operation because of
8466                          * inability to create annotation audit event.
8467                          */
8468                         warn(gettext("_scf_set_annotation() unexpectedly "
8469                             "failed with return code of %d\n"), scf_error());
8470                         break;
8471                 }
8472         }
8473 
8474         for (svc = uu_list_first(bndl->sc_bundle_services);
8475             svc != NULL;
8476             svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8477                 int refresh = 0;
8478 
8479                 if (scf_scope_get_service(imp_scope, svc->sc_name,
8480                     imp_svc) != 0) {
8481                         switch (scf_error()) {
8482                         case SCF_ERROR_NOT_FOUND:
8483                                 if (g_verbose)
8484                                         warn(gettext("Ignoring nonexistent "
8485                                             "service %s.\n"), svc->sc_name);
8486                                 continue;
8487 
8488                         default:
8489                                 scfdie();
8490                         }
8491                 }
8492 
8493                 /*
8494                  * If there were missing types in the profile, then need to
8495                  * attempt to find the types.
8496                  */
8497                 if (svc->sc_miss_type) {
8498                         if (uu_list_numnodes(svc->sc_pgroups) &&
8499                             uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8500                             svc, UU_DEFAULT) != 0) {
8501                                 if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8502                                         bad_error("uu_list_walk", uu_error());
8503 
8504                                 ret = -1;
8505                                 continue;
8506                         }
8507 
8508                         for (inst = uu_list_first(
8509                             svc->sc_u.sc_service.sc_service_instances);
8510                             inst != NULL;
8511                             inst = uu_list_next(
8512                             svc->sc_u.sc_service.sc_service_instances, inst)) {
8513                                 /*
8514                                  * If the instance doesn't exist just
8515                                  * skip to the next instance and let the
8516                                  * import note the missing instance.
8517                                  */
8518                                 if (scf_service_get_instance(imp_svc,
8519                                     inst->sc_name, imp_inst) != 0)
8520                                         continue;
8521 
8522                                 if (uu_list_walk(inst->sc_pgroups,
8523                                     find_current_pg_type, inst,
8524                                     UU_DEFAULT) != 0) {
8525                                         if (uu_error() !=
8526                                             UU_ERROR_CALLBACK_FAILED)
8527                                                 bad_error("uu_list_walk",
8528                                                     uu_error());
8529 
8530                                         ret = -1;
8531                                         inst->sc_miss_type = B_TRUE;
8532                                 }
8533                         }
8534                 }
8535 
8536                 /*
8537                  * if we have pgs in the profile, we need to refresh ALL
8538                  * instances of the service
8539                  */
8540                 if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8541                         refresh = 1;
8542                         r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8543                             SCI_FORCE | SCI_KEEP);
8544                         switch (_lscf_import_err(r, svc->sc_fmri)) {
8545                         case IMPORT_NEXT:
8546                                 break;
8547 
8548                         case IMPORT_OUT:
8549                                 goto out;
8550 
8551                         case IMPORT_BAD:
8552                         default:
8553                                 bad_error("lscf_import_service_pgs", r);
8554                         }
8555                 }
8556 
8557                 if (uu_list_numnodes(svc->sc_dependents) != 0) {
8558                         uu_list_walk(svc->sc_dependents,
8559                             lscf_dependent_apply, svc, UU_DEFAULT);
8560                 }
8561 
8562                 for (inst = uu_list_first(
8563                     svc->sc_u.sc_service.sc_service_instances);
8564                     inst != NULL;
8565                     inst = uu_list_next(
8566                     svc->sc_u.sc_service.sc_service_instances, inst)) {
8567                         /*
8568                          * This instance still has missing types
8569                          * so skip it.
8570                          */
8571                         if (inst->sc_miss_type) {
8572                                 if (g_verbose)
8573                                         warn(gettext("Ignoring instance "
8574                                             "%s:%s with missing types\n"),
8575                                             inst->sc_parent->sc_name,
8576                                             inst->sc_name);
8577 
8578                                 continue;
8579                         }
8580 
8581                         if (scf_service_get_instance(imp_svc, inst->sc_name,
8582                             imp_inst) != 0) {
8583                                 switch (scf_error()) {
8584                                 case SCF_ERROR_NOT_FOUND:
8585                                         if (g_verbose)
8586                                                 warn(gettext("Ignoring "
8587                                                     "nonexistant instance "
8588                                                     "%s:%s.\n"),
8589                                                     inst->sc_parent->sc_name,
8590                                                     inst->sc_name);
8591                                         continue;
8592 
8593                                 default:
8594                                         scfdie();
8595                                 }
8596                         }
8597 
8598                         /*
8599                          * If the instance does not have a general/enabled
8600                          * property and no last-import snapshot then the
8601                          * instance is not a fully installed instance and
8602                          * should not have a profile applied to it.
8603                          *
8604                          * This could happen if a service/instance declares
8605                          * a dependent on behalf of another service/instance.
8606                          *
8607                          */
8608                         if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8609                             imp_snap) != 0) {
8610                                 if (scf_instance_get_pg(imp_inst,
8611                                     SCF_PG_GENERAL, imp_pg) != 0 ||
8612                                     scf_pg_get_property(imp_pg,
8613                                     SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8614                                         if (g_verbose)
8615                                                 warn(gettext("Ignoreing "
8616                                                     "partial instance "
8617                                                     "%s:%s.\n"),
8618                                                     inst->sc_parent->sc_name,
8619                                                     inst->sc_name);
8620                                         continue;
8621                                 }
8622                         }
8623 
8624                         r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8625                             inst, SCI_FORCE | SCI_KEEP);
8626                         switch (_lscf_import_err(r, inst->sc_fmri)) {
8627                         case IMPORT_NEXT:
8628                                 break;
8629 
8630                         case IMPORT_OUT:
8631                                 goto out;
8632 
8633                         case IMPORT_BAD:
8634                         default:
8635                                 bad_error("lscf_import_instance_pgs", r);
8636                         }
8637 
8638                         if (uu_list_numnodes(inst->sc_dependents) != 0) {
8639                                 uu_list_walk(inst->sc_dependents,
8640                                     lscf_dependent_apply, inst, UU_DEFAULT);
8641                         }
8642 
8643                         /* refresh only if there is no pgs in the service */
8644                         if (refresh == 0)
8645                                 (void) refresh_entity(0, imp_inst,
8646                                     inst->sc_fmri, NULL, NULL, NULL);
8647                 }
8648 
8649                 if (refresh == 1) {
8650                         char *name_buf = safe_malloc(max_scf_name_len + 1);
8651 
8652                         (void) refresh_entity(1, imp_svc, svc->sc_name,
8653                             imp_inst, imp_iter, name_buf);
8654                         free(name_buf);
8655                 }
8656 
8657                 for (old_dpt = uu_list_first(imp_deleted_dpts);
8658                     old_dpt != NULL;
8659                     old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8660                         if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8661                             old_dpt->sc_pgroup_name,
8662                             old_dpt->sc_parent->sc_fmri) != 0) {
8663                                 warn(gettext("Unable to refresh \"%s\"\n"),
8664                                     old_dpt->sc_pgroup_fmri);
8665                         }
8666                 }
8667         }
8668 
8669 out:
8670         if (annotation_set) {
8671                 /* Remove security audit annotation strings. */
8672                 (void) _scf_set_annotation(g_hndl, NULL, NULL);
8673         }
8674 
8675         free_imp_globals();
8676         return (ret);
8677 }
8678 
8679 
8680 /*
8681  * Export.  These functions create and output an XML tree of a service
8682  * description from the repository.  This is largely the inverse of
8683  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8684  *
8685  * - We must include any properties which are not represented specifically by
8686  *   a service manifest, e.g., properties created by an admin post-import.  To
8687  *   do so we'll iterate through all properties and deal with each
8688  *   apropriately.
8689  *
8690  * - Children of services and instances must must be in the order set by the
8691  *   DTD, but we iterate over the properties in undefined order.  The elements
8692  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8693  *   number of classes of them, however, we'll keep the classes separate and
8694  *   assemble them in order.
8695  */
8696 
8697 /*
8698  * Convenience function to handle xmlSetProp errors (and type casting).
8699  */
8700 static void
8701 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8702 {
8703         if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8704                 uu_die(gettext("Could not set XML property.\n"));
8705 }
8706 
8707 /*
8708  * Convenience function to set an XML attribute to the single value of an
8709  * astring property.  If the value happens to be the default, don't set the
8710  * attribute.  "dval" should be the default value supplied by the DTD, or
8711  * NULL for no default.
8712  */
8713 static int
8714 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8715     const char *name, const char *dval)
8716 {
8717         scf_value_t *val;
8718         ssize_t len;
8719         char *str;
8720 
8721         val = scf_value_create(g_hndl);
8722         if (val == NULL)
8723                 scfdie();
8724 
8725         if (prop_get_val(prop, val) != 0) {
8726                 scf_value_destroy(val);
8727                 return (-1);
8728         }
8729 
8730         len = scf_value_get_as_string(val, NULL, 0);
8731         if (len < 0)
8732                 scfdie();
8733 
8734         str = safe_malloc(len + 1);
8735 
8736         if (scf_value_get_as_string(val, str, len + 1) < 0)
8737                 scfdie();
8738 
8739         scf_value_destroy(val);
8740 
8741         if (dval == NULL || strcmp(str, dval) != 0)
8742                 safe_setprop(n, name, str);
8743 
8744         free(str);
8745 
8746         return (0);
8747 }
8748 
8749 /*
8750  * As above, but the attribute is always set.
8751  */
8752 static int
8753 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
8754 {
8755         return (set_attr_from_prop_default(prop, n, name, NULL));
8756 }
8757 
8758 /*
8759  * Dump the given document onto f, with "'s replaced by ''s.
8760  */
8761 static int
8762 write_service_bundle(xmlDocPtr doc, FILE *f)
8763 {
8764         xmlChar *mem;
8765         int sz, i;
8766 
8767         mem = NULL;
8768         xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
8769 
8770         if (mem == NULL) {
8771                 semerr(gettext("Could not dump XML tree.\n"));
8772                 return (-1);
8773         }
8774 
8775         /*
8776          * Fortunately libxml produces &quot; instead of ", so we can blindly
8777          * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
8778          * &apos; code?!
8779          */
8780         for (i = 0; i < sz; ++i) {
8781                 char c = (char)mem[i];
8782 
8783                 if (c == '"')
8784                         (void) fputc('\'', f);
8785                 else if (c == '\'')
8786                         (void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
8787                 else
8788                         (void) fputc(c, f);
8789         }
8790 
8791         return (0);
8792 }
8793 
8794 /*
8795  * Create the DOM elements in elts necessary to (generically) represent prop
8796  * (i.e., a property or propval element).  If the name of the property is
8797  * known, it should be passed as name_arg.  Otherwise, pass NULL.
8798  */
8799 static void
8800 export_property(scf_property_t *prop, const char *name_arg,
8801     struct pg_elts *elts, int flags)
8802 {
8803         const char *type;
8804         scf_error_t err = 0;
8805         xmlNodePtr pnode, lnode;
8806         char *lnname;
8807         int ret;
8808 
8809         /* name */
8810         if (name_arg != NULL) {
8811                 (void) strcpy(exp_str, name_arg);
8812         } else {
8813                 if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8814                         scfdie();
8815         }
8816 
8817         /* type */
8818         type = prop_to_typestr(prop);
8819         if (type == NULL)
8820                 uu_die(gettext("Can't export property %s: unknown type.\n"),
8821                     exp_str);
8822 
8823         /* If we're exporting values, and there's just one, export it here. */
8824         if (!(flags & SCE_ALL_VALUES))
8825                 goto empty;
8826 
8827         if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8828                 xmlNodePtr n;
8829 
8830                 /* Single value, so use propval */
8831                 n = xmlNewNode(NULL, (xmlChar *)"propval");
8832                 if (n == NULL)
8833                         uu_die(emsg_create_xml);
8834 
8835                 safe_setprop(n, name_attr, exp_str);
8836                 safe_setprop(n, type_attr, type);
8837 
8838                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8839                         scfdie();
8840                 safe_setprop(n, value_attr, exp_str);
8841 
8842                 if (elts->propvals == NULL)
8843                         elts->propvals = n;
8844                 else
8845                         (void) xmlAddSibling(elts->propvals, n);
8846 
8847                 return;
8848         }
8849 
8850         err = scf_error();
8851 
8852         if (err == SCF_ERROR_PERMISSION_DENIED) {
8853                 semerr(emsg_permission_denied);
8854                 return;
8855         }
8856 
8857         if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8858             err != SCF_ERROR_NOT_FOUND &&
8859             err != SCF_ERROR_PERMISSION_DENIED)
8860                 scfdie();
8861 
8862 empty:
8863         /* Multiple (or no) values, so use property */
8864         pnode = xmlNewNode(NULL, (xmlChar *)"property");
8865         if (pnode == NULL)
8866                 uu_die(emsg_create_xml);
8867 
8868         safe_setprop(pnode, name_attr, exp_str);
8869         safe_setprop(pnode, type_attr, type);
8870 
8871         if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8872                 lnname = uu_msprintf("%s_list", type);
8873                 if (lnname == NULL)
8874                         uu_die(gettext("Could not create string"));
8875 
8876                 lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8877                 if (lnode == NULL)
8878                         uu_die(emsg_create_xml);
8879 
8880                 uu_free(lnname);
8881 
8882                 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8883                         scfdie();
8884 
8885                 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8886                     1) {
8887                         xmlNodePtr vn;
8888 
8889                         vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8890                             NULL);
8891                         if (vn == NULL)
8892                                 uu_die(emsg_create_xml);
8893 
8894                         if (scf_value_get_as_string(exp_val, exp_str,
8895                             exp_str_sz) < 0)
8896                                 scfdie();
8897                         safe_setprop(vn, value_attr, exp_str);
8898                 }
8899                 if (ret != 0)
8900                         scfdie();
8901         }
8902 
8903         if (elts->properties == NULL)
8904                 elts->properties = pnode;
8905         else
8906                 (void) xmlAddSibling(elts->properties, pnode);
8907 }
8908 
8909 /*
8910  * Add a property_group element for this property group to elts.
8911  */
8912 static void
8913 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8914 {
8915         xmlNodePtr n;
8916         struct pg_elts elts;
8917         int ret;
8918         boolean_t read_protected;
8919 
8920         n = xmlNewNode(NULL, (xmlChar *)"property_group");
8921 
8922         /* name */
8923         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8924                 scfdie();
8925         safe_setprop(n, name_attr, exp_str);
8926 
8927         /* type */
8928         if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8929                 scfdie();
8930         safe_setprop(n, type_attr, exp_str);
8931 
8932         /* properties */
8933         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8934                 scfdie();
8935 
8936         (void) memset(&elts, 0, sizeof (elts));
8937 
8938         /*
8939          * If this property group is not read protected, we always want to
8940          * output all the values.  Otherwise, we only output the values if the
8941          * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8942          */
8943         if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8944                 scfdie();
8945 
8946         if (!read_protected)
8947                 flags |= SCE_ALL_VALUES;
8948 
8949         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8950                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8951                         scfdie();
8952 
8953                 if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8954                         xmlNodePtr m;
8955 
8956                         m = xmlNewNode(NULL, (xmlChar *)"stability");
8957                         if (m == NULL)
8958                                 uu_die(emsg_create_xml);
8959 
8960                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8961                                 elts.stability = m;
8962                                 continue;
8963                         }
8964 
8965                         xmlFreeNode(m);
8966                 }
8967 
8968                 export_property(exp_prop, NULL, &elts, flags);
8969         }
8970         if (ret == -1)
8971                 scfdie();
8972 
8973         (void) xmlAddChild(n, elts.stability);
8974         (void) xmlAddChildList(n, elts.propvals);
8975         (void) xmlAddChildList(n, elts.properties);
8976 
8977         if (eelts->property_groups == NULL)
8978                 eelts->property_groups = n;
8979         else
8980                 (void) xmlAddSibling(eelts->property_groups, n);
8981 }
8982 
8983 /*
8984  * Create an XML node representing the dependency described by the given
8985  * property group and put it in eelts.  Unless the dependency is not valid, in
8986  * which case create a generic property_group element which represents it and
8987  * put it in eelts.
8988  */
8989 static void
8990 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8991 {
8992         xmlNodePtr n;
8993         int err = 0, ret;
8994         struct pg_elts elts;
8995 
8996         n = xmlNewNode(NULL, (xmlChar *)"dependency");
8997         if (n == NULL)
8998                 uu_die(emsg_create_xml);
8999 
9000         /*
9001          * If the external flag is present, skip this dependency because it
9002          * should have been created by another manifest.
9003          */
9004         if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9005                 if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9006                     prop_get_val(exp_prop, exp_val) == 0) {
9007                         uint8_t b;
9008 
9009                         if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9010                                 scfdie();
9011 
9012                         if (b)
9013                                 return;
9014                 }
9015         } else if (scf_error() != SCF_ERROR_NOT_FOUND)
9016                 scfdie();
9017 
9018         /* Get the required attributes. */
9019 
9020         /* name */
9021         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9022                 scfdie();
9023         safe_setprop(n, name_attr, exp_str);
9024 
9025         /* grouping */
9026         if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9027             set_attr_from_prop(exp_prop, n, "grouping") != 0)
9028                 err = 1;
9029 
9030         /* restart_on */
9031         if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9032             set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9033                 err = 1;
9034 
9035         /* type */
9036         if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9037             set_attr_from_prop(exp_prop, n, type_attr) != 0)
9038                 err = 1;
9039 
9040         /*
9041          * entities: Not required, but if we create no children, it will be
9042          * created as empty on import, so fail if it's missing.
9043          */
9044         if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9045             prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9046                 scf_iter_t *eiter;
9047                 int ret2;
9048 
9049                 eiter = scf_iter_create(g_hndl);
9050                 if (eiter == NULL)
9051                         scfdie();
9052 
9053                 if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9054                         scfdie();
9055 
9056                 while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9057                         xmlNodePtr ch;
9058 
9059                         if (scf_value_get_astring(exp_val, exp_str,
9060                             exp_str_sz) < 0)
9061                                 scfdie();
9062 
9063                         /*
9064                          * service_fmri's must be first, so we can add them
9065                          * here.
9066                          */
9067                         ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9068                             NULL);
9069                         if (ch == NULL)
9070                                 uu_die(emsg_create_xml);
9071 
9072                         safe_setprop(ch, value_attr, exp_str);
9073                 }
9074                 if (ret2 == -1)
9075                         scfdie();
9076 
9077                 scf_iter_destroy(eiter);
9078         } else
9079                 err = 1;
9080 
9081         if (err) {
9082                 xmlFreeNode(n);
9083 
9084                 export_pg(pg, eelts, 0);
9085 
9086                 return;
9087         }
9088 
9089         /* Iterate through the properties & handle each. */
9090         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9091                 scfdie();
9092 
9093         (void) memset(&elts, 0, sizeof (elts));
9094 
9095         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9096                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9097                         scfdie();
9098 
9099                 if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9100                     strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9101                     strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9102                     strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9103                         continue;
9104                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9105                         xmlNodePtr m;
9106 
9107                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9108                         if (m == NULL)
9109                                 uu_die(emsg_create_xml);
9110 
9111                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9112                                 elts.stability = m;
9113                                 continue;
9114                         }
9115 
9116                         xmlFreeNode(m);
9117                 }
9118 
9119                 export_property(exp_prop, exp_str, &elts, 0);
9120         }
9121         if (ret == -1)
9122                 scfdie();
9123 
9124         (void) xmlAddChild(n, elts.stability);
9125         (void) xmlAddChildList(n, elts.propvals);
9126         (void) xmlAddChildList(n, elts.properties);
9127 
9128         if (eelts->dependencies == NULL)
9129                 eelts->dependencies = n;
9130         else
9131                 (void) xmlAddSibling(eelts->dependencies, n);
9132 }
9133 
9134 static xmlNodePtr
9135 export_method_environment(scf_propertygroup_t *pg)
9136 {
9137         xmlNodePtr env;
9138         int ret;
9139         int children = 0;
9140 
9141         if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9142                 return (NULL);
9143 
9144         env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9145         if (env == NULL)
9146                 uu_die(emsg_create_xml);
9147 
9148         if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9149                 scfdie();
9150 
9151         if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9152                 scfdie();
9153 
9154         while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9155                 xmlNodePtr ev;
9156                 char *cp;
9157 
9158                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9159                         scfdie();
9160 
9161                 if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9162                         warn(gettext("Invalid environment variable \"%s\".\n"),
9163                             exp_str);
9164                         continue;
9165                 } else if (strncmp(exp_str, "SMF_", 4) == 0) {
9166                         warn(gettext("Invalid environment variable \"%s\"; "
9167                             "\"SMF_\" prefix is reserved.\n"), exp_str);
9168                         continue;
9169                 }
9170 
9171                 *cp = '\0';
9172                 cp++;
9173 
9174                 ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9175                 if (ev == NULL)
9176                         uu_die(emsg_create_xml);
9177 
9178                 safe_setprop(ev, name_attr, exp_str);
9179                 safe_setprop(ev, value_attr, cp);
9180                 children++;
9181         }
9182 
9183         if (ret != 0)
9184                 scfdie();
9185 
9186         if (children == 0) {
9187                 xmlFreeNode(env);
9188                 return (NULL);
9189         }
9190 
9191         return (env);
9192 }
9193 
9194 /*
9195  * As above, but for a method property group.
9196  */
9197 static void
9198 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9199 {
9200         xmlNodePtr n, env;
9201         char *str;
9202         int err = 0, nonenv, ret;
9203         uint8_t use_profile;
9204         struct pg_elts elts;
9205         xmlNodePtr ctxt = NULL;
9206 
9207         n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9208 
9209         /* Get the required attributes. */
9210 
9211         /* name */
9212         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9213                 scfdie();
9214         safe_setprop(n, name_attr, exp_str);
9215 
9216         /* type */
9217         if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9218             set_attr_from_prop(exp_prop, n, type_attr) != 0)
9219                 err = 1;
9220 
9221         /* exec */
9222         if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9223             set_attr_from_prop(exp_prop, n, "exec") != 0)
9224                 err = 1;
9225 
9226         /* timeout */
9227         if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9228             prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9229             prop_get_val(exp_prop, exp_val) == 0) {
9230                 uint64_t c;
9231 
9232                 if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9233                         scfdie();
9234 
9235                 str = uu_msprintf("%llu", c);
9236                 if (str == NULL)
9237                         uu_die(gettext("Could not create string"));
9238 
9239                 safe_setprop(n, "timeout_seconds", str);
9240                 free(str);
9241         } else
9242                 err = 1;
9243 
9244         if (err) {
9245                 xmlFreeNode(n);
9246 
9247                 export_pg(pg, eelts, 0);
9248 
9249                 return;
9250         }
9251 
9252 
9253         /*
9254          * If we're going to have a method_context child, we need to know
9255          * before we iterate through the properties.  Since method_context's
9256          * are optional, we don't want to complain about any properties
9257          * missing if none of them are there.  Thus we can't use the
9258          * convenience functions.
9259          */
9260         nonenv =
9261             scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9262             SCF_SUCCESS ||
9263             scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9264             SCF_SUCCESS ||
9265             scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9266             SCF_SUCCESS ||
9267             scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9268             SCF_SUCCESS;
9269 
9270         if (nonenv) {
9271                 ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9272                 if (ctxt == NULL)
9273                         uu_die(emsg_create_xml);
9274 
9275                 if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9276                     0 &&
9277                     set_attr_from_prop_default(exp_prop, ctxt,
9278                     "working_directory", ":default") != 0)
9279                         err = 1;
9280 
9281                 if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9282                     set_attr_from_prop_default(exp_prop, ctxt, "project",
9283                     ":default") != 0)
9284                         err = 1;
9285 
9286                 if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9287                     0 &&
9288                     set_attr_from_prop_default(exp_prop, ctxt,
9289                     "resource_pool", ":default") != 0)
9290                         err = 1;
9291                 /*
9292                  * We only want to complain about profile or credential
9293                  * properties if we will use them.  To determine that we must
9294                  * examine USE_PROFILE.
9295                  */
9296                 if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9297                     prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9298                     prop_get_val(exp_prop, exp_val) == 0) {
9299                         if (scf_value_get_boolean(exp_val, &use_profile) !=
9300                             SCF_SUCCESS) {
9301                                 scfdie();
9302                         }
9303 
9304                         if (use_profile) {
9305                                 xmlNodePtr prof;
9306 
9307                                 prof = xmlNewChild(ctxt, NULL,
9308                                     (xmlChar *)"method_profile", NULL);
9309                                 if (prof == NULL)
9310                                         uu_die(emsg_create_xml);
9311 
9312                                 if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9313                                     exp_prop) != 0 ||
9314                                     set_attr_from_prop(exp_prop, prof,
9315                                     name_attr) != 0)
9316                                         err = 1;
9317                         } else {
9318                                 xmlNodePtr cred;
9319 
9320                                 cred = xmlNewChild(ctxt, NULL,
9321                                     (xmlChar *)"method_credential", NULL);
9322                                 if (cred == NULL)
9323                                         uu_die(emsg_create_xml);
9324 
9325                                 if (pg_get_prop(pg, SCF_PROPERTY_USER,
9326                                     exp_prop) != 0 ||
9327                                     set_attr_from_prop(exp_prop, cred,
9328                                     "user") != 0) {
9329                                         err = 1;
9330                                 }
9331 
9332                                 if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9333                                     exp_prop) == 0 &&
9334                                     set_attr_from_prop_default(exp_prop, cred,
9335                                     "group", ":default") != 0)
9336                                         err = 1;
9337 
9338                                 if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9339                                     exp_prop) == 0 &&
9340                                     set_attr_from_prop_default(exp_prop, cred,
9341                                     "supp_groups", ":default") != 0)
9342                                         err = 1;
9343 
9344                                 if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9345                                     exp_prop) == 0 &&
9346                                     set_attr_from_prop_default(exp_prop, cred,
9347                                     "privileges", ":default") != 0)
9348                                         err = 1;
9349 
9350                                 if (pg_get_prop(pg,
9351                                     SCF_PROPERTY_LIMIT_PRIVILEGES,
9352                                     exp_prop) == 0 &&
9353                                     set_attr_from_prop_default(exp_prop, cred,
9354                                     "limit_privileges", ":default") != 0)
9355                                         err = 1;
9356                         }
9357                 }
9358         }
9359 
9360         if ((env = export_method_environment(pg)) != NULL) {
9361                 if (ctxt == NULL) {
9362                         ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9363                         if (ctxt == NULL)
9364                                 uu_die(emsg_create_xml);
9365                 }
9366                 (void) xmlAddChild(ctxt, env);
9367         }
9368 
9369         if (env != NULL || (nonenv && err == 0))
9370                 (void) xmlAddChild(n, ctxt);
9371         else
9372                 xmlFreeNode(ctxt);
9373 
9374         nonenv = (err == 0);
9375 
9376         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9377                 scfdie();
9378 
9379         (void) memset(&elts, 0, sizeof (elts));
9380 
9381         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9382                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9383                         scfdie();
9384 
9385                 if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9386                     strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9387                     strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9388                         continue;
9389                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9390                         xmlNodePtr m;
9391 
9392                         m = xmlNewNode(NULL, (xmlChar *)"stability");
9393                         if (m == NULL)
9394                                 uu_die(emsg_create_xml);
9395 
9396                         if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9397                                 elts.stability = m;
9398                                 continue;
9399                         }
9400 
9401                         xmlFreeNode(m);
9402                 } else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9403                     0 ||
9404                     strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9405                     strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9406                     strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9407                         if (nonenv)
9408                                 continue;
9409                 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9410                     strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9411                     strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9412                     strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9413                     strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9414                         if (nonenv && !use_profile)
9415                                 continue;
9416                 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9417                         if (nonenv && use_profile)
9418                                 continue;
9419                 } else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9420                         if (env != NULL)
9421                                 continue;
9422                 }
9423 
9424                 export_property(exp_prop, exp_str, &elts, 0);
9425         }
9426         if (ret == -1)
9427                 scfdie();
9428 
9429         (void) xmlAddChild(n, elts.stability);
9430         (void) xmlAddChildList(n, elts.propvals);
9431         (void) xmlAddChildList(n, elts.properties);
9432 
9433         if (eelts->exec_methods == NULL)
9434                 eelts->exec_methods = n;
9435         else
9436                 (void) xmlAddSibling(eelts->exec_methods, n);
9437 }
9438 
9439 static void
9440 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9441     struct entity_elts *eelts)
9442 {
9443         xmlNodePtr pgnode;
9444 
9445         pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9446         if (pgnode == NULL)
9447                 uu_die(emsg_create_xml);
9448 
9449         safe_setprop(pgnode, name_attr, name);
9450         safe_setprop(pgnode, type_attr, type);
9451 
9452         (void) xmlAddChildList(pgnode, elts->propvals);
9453         (void) xmlAddChildList(pgnode, elts->properties);
9454 
9455         if (eelts->property_groups == NULL)
9456                 eelts->property_groups = pgnode;
9457         else
9458                 (void) xmlAddSibling(eelts->property_groups, pgnode);
9459 }
9460 
9461 /*
9462  * Process the general property group for a service.  This is the one with the
9463  * goodies.
9464  */
9465 static void
9466 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9467 {
9468         struct pg_elts elts;
9469         int ret;
9470 
9471         /*
9472          * In case there are properties which don't correspond to child
9473          * entities of the service entity, we'll set up a pg_elts structure to
9474          * put them in.
9475          */
9476         (void) memset(&elts, 0, sizeof (elts));
9477 
9478         /* Walk the properties, looking for special ones. */
9479         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9480                 scfdie();
9481 
9482         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9483                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9484                         scfdie();
9485 
9486                 if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9487                         if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9488                             prop_get_val(exp_prop, exp_val) == 0) {
9489                                 uint8_t b;
9490 
9491                                 if (scf_value_get_boolean(exp_val, &b) !=
9492                                     SCF_SUCCESS)
9493                                         scfdie();
9494 
9495                                 if (b) {
9496                                         selts->single_instance =
9497                                             xmlNewNode(NULL,
9498                                             (xmlChar *)"single_instance");
9499                                         if (selts->single_instance == NULL)
9500                                                 uu_die(emsg_create_xml);
9501                                 }
9502 
9503                                 continue;
9504                         }
9505                 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9506                         xmlNodePtr rnode, sfnode;
9507 
9508                         rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9509                         if (rnode == NULL)
9510                                 uu_die(emsg_create_xml);
9511 
9512                         sfnode = xmlNewChild(rnode, NULL,
9513                             (xmlChar *)"service_fmri", NULL);
9514                         if (sfnode == NULL)
9515                                 uu_die(emsg_create_xml);
9516 
9517                         if (set_attr_from_prop(exp_prop, sfnode,
9518                             value_attr) == 0) {
9519                                 selts->restarter = rnode;
9520                                 continue;
9521                         }
9522 
9523                         xmlFreeNode(rnode);
9524                 } else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9525                     0) {
9526                         xmlNodePtr s;
9527 
9528                         s = xmlNewNode(NULL, (xmlChar *)"stability");
9529                         if (s == NULL)
9530                                 uu_die(emsg_create_xml);
9531 
9532                         if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9533                                 selts->stability = s;
9534                                 continue;
9535                         }
9536 
9537                         xmlFreeNode(s);
9538                 }
9539 
9540                 export_property(exp_prop, exp_str, &elts, 0);
9541         }
9542         if (ret == -1)
9543                 scfdie();
9544 
9545         if (elts.propvals != NULL || elts.properties != NULL)
9546                 export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9547                     selts);
9548 }
9549 
9550 static void
9551 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9552 {
9553         xmlNodePtr n, prof, cred, env;
9554         uint8_t use_profile;
9555         int ret, err = 0;
9556 
9557         n = xmlNewNode(NULL, (xmlChar *)"method_context");
9558 
9559         env = export_method_environment(pg);
9560 
9561         /* Need to know whether we'll use a profile or not. */
9562         if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9563             prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9564             prop_get_val(exp_prop, exp_val) == 0) {
9565                 if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9566                         scfdie();
9567 
9568                 if (use_profile)
9569                         prof =
9570                             xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9571                             NULL);
9572                 else
9573                         cred =
9574                             xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9575                             NULL);
9576         }
9577 
9578         if (env != NULL)
9579                 (void) xmlAddChild(n, env);
9580 
9581         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9582                 scfdie();
9583 
9584         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9585                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9586                         scfdie();
9587 
9588                 if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9589                         if (set_attr_from_prop(exp_prop, n,
9590                             "working_directory") != 0)
9591                                 err = 1;
9592                 } else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9593                         if (set_attr_from_prop(exp_prop, n, "project") != 0)
9594                                 err = 1;
9595                 } else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9596                         if (set_attr_from_prop(exp_prop, n,
9597                             "resource_pool") != 0)
9598                                 err = 1;
9599                 } else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9600                         /* EMPTY */
9601                 } else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9602                         if (use_profile ||
9603                             set_attr_from_prop(exp_prop, cred, "user") != 0)
9604                                 err = 1;
9605                 } else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9606                         if (use_profile ||
9607                             set_attr_from_prop(exp_prop, cred, "group") != 0)
9608                                 err = 1;
9609                 } else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9610                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9611                             "supp_groups") != 0)
9612                                 err = 1;
9613                 } else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9614                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9615                             "privileges") != 0)
9616                                 err = 1;
9617                 } else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9618                     0) {
9619                         if (use_profile || set_attr_from_prop(exp_prop, cred,
9620                             "limit_privileges") != 0)
9621                                 err = 1;
9622                 } else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9623                         if (!use_profile || set_attr_from_prop(exp_prop,
9624                             prof, name_attr) != 0)
9625                                 err = 1;
9626                 } else {
9627                         /* Can't have generic properties in method_context's */
9628                         err = 1;
9629                 }
9630         }
9631         if (ret == -1)
9632                 scfdie();
9633 
9634         if (err && env == NULL) {
9635                 xmlFreeNode(n);
9636                 export_pg(pg, elts, 0);
9637                 return;
9638         }
9639 
9640         elts->method_context = n;
9641 }
9642 
9643 /*
9644  * Given a dependency property group in the tfmri entity (target fmri), return
9645  * a dependent element which represents it.
9646  */
9647 static xmlNodePtr
9648 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9649 {
9650         uint8_t b;
9651         xmlNodePtr n, sf;
9652         int err = 0, ret;
9653         struct pg_elts pgelts;
9654 
9655         /*
9656          * If external isn't set to true then exporting the service will
9657          * export this as a normal dependency, so we should stop to avoid
9658          * duplication.
9659          */
9660         if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9661             scf_property_get_value(exp_prop, exp_val) != 0 ||
9662             scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9663                 if (g_verbose) {
9664                         warn(gettext("Dependent \"%s\" cannot be exported "
9665                             "properly because the \"%s\" property of the "
9666                             "\"%s\" dependency of %s is not set to true.\n"),
9667                             name, scf_property_external, name, tfmri);
9668                 }
9669 
9670                 return (NULL);
9671         }
9672 
9673         n = xmlNewNode(NULL, (xmlChar *)"dependent");
9674         if (n == NULL)
9675                 uu_die(emsg_create_xml);
9676 
9677         safe_setprop(n, name_attr, name);
9678 
9679         /* Get the required attributes */
9680         if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9681             set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9682                 err = 1;
9683 
9684         if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9685             set_attr_from_prop(exp_prop, n, "grouping") != 0)
9686                 err = 1;
9687 
9688         if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9689             prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9690             prop_get_val(exp_prop, exp_val) == 0) {
9691                 /* EMPTY */
9692         } else
9693                 err = 1;
9694 
9695         if (err) {
9696                 xmlFreeNode(n);
9697                 return (NULL);
9698         }
9699 
9700         sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9701         if (sf == NULL)
9702                 uu_die(emsg_create_xml);
9703 
9704         safe_setprop(sf, value_attr, tfmri);
9705 
9706         /*
9707          * Now add elements for the other properties.
9708          */
9709         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9710                 scfdie();
9711 
9712         (void) memset(&pgelts, 0, sizeof (pgelts));
9713 
9714         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9715                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9716                         scfdie();
9717 
9718                 if (strcmp(exp_str, scf_property_external) == 0 ||
9719                     strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9720                     strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9721                     strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9722                         continue;
9723                 } else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9724                         if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9725                             prop_get_val(exp_prop, exp_val) == 0) {
9726                                 char type[sizeof ("service") + 1];
9727 
9728                                 if (scf_value_get_astring(exp_val, type,
9729                                     sizeof (type)) < 0)
9730                                         scfdie();
9731 
9732                                 if (strcmp(type, "service") == 0)
9733                                         continue;
9734                         }
9735                 } else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9736                         xmlNodePtr s;
9737 
9738                         s = xmlNewNode(NULL, (xmlChar *)"stability");
9739                         if (s == NULL)
9740                                 uu_die(emsg_create_xml);
9741 
9742                         if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9743                                 pgelts.stability = s;
9744                                 continue;
9745                         }
9746 
9747                         xmlFreeNode(s);
9748                 }
9749 
9750                 export_property(exp_prop, exp_str, &pgelts, 0);
9751         }
9752         if (ret == -1)
9753                 scfdie();
9754 
9755         (void) xmlAddChild(n, pgelts.stability);
9756         (void) xmlAddChildList(n, pgelts.propvals);
9757         (void) xmlAddChildList(n, pgelts.properties);
9758 
9759         return (n);
9760 }
9761 
9762 static void
9763 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
9764 {
9765         scf_propertygroup_t *opg;
9766         scf_iter_t *iter;
9767         char *type, *fmri;
9768         int ret;
9769         struct pg_elts pgelts;
9770         xmlNodePtr n;
9771         scf_error_t serr;
9772 
9773         if ((opg = scf_pg_create(g_hndl)) == NULL ||
9774             (iter = scf_iter_create(g_hndl)) == NULL)
9775                 scfdie();
9776 
9777         /* Can't use exp_prop_iter due to export_dependent(). */
9778         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
9779                 scfdie();
9780 
9781         type = safe_malloc(max_scf_pg_type_len + 1);
9782 
9783         /* Get an extra byte so we can tell if values are too long. */
9784         fmri = safe_malloc(max_scf_fmri_len + 2);
9785 
9786         (void) memset(&pgelts, 0, sizeof (pgelts));
9787 
9788         while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
9789                 void *entity;
9790                 int isservice;
9791                 scf_type_t ty;
9792 
9793                 if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
9794                         scfdie();
9795 
9796                 if ((ty != SCF_TYPE_ASTRING &&
9797                     prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
9798                     prop_get_val(exp_prop, exp_val) != 0) {
9799                         export_property(exp_prop, NULL, &pgelts, 0);
9800                         continue;
9801                 }
9802 
9803                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9804                         scfdie();
9805 
9806                 if (scf_value_get_astring(exp_val, fmri,
9807                     max_scf_fmri_len + 2) < 0)
9808                         scfdie();
9809 
9810                 /* Look for a dependency group in the target fmri. */
9811                 serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9812                 switch (serr) {
9813                 case SCF_ERROR_NONE:
9814                         break;
9815 
9816                 case SCF_ERROR_NO_MEMORY:
9817                         uu_die(gettext("Out of memory.\n"));
9818                         /* NOTREACHED */
9819 
9820                 case SCF_ERROR_INVALID_ARGUMENT:
9821                         if (g_verbose) {
9822                                 if (scf_property_to_fmri(exp_prop, fmri,
9823                                     max_scf_fmri_len + 2) < 0)
9824                                         scfdie();
9825 
9826                                 warn(gettext("The value of %s is not a valid "
9827                                     "FMRI.\n"), fmri);
9828                         }
9829 
9830                         export_property(exp_prop, exp_str, &pgelts, 0);
9831                         continue;
9832 
9833                 case SCF_ERROR_CONSTRAINT_VIOLATED:
9834                         if (g_verbose) {
9835                                 if (scf_property_to_fmri(exp_prop, fmri,
9836                                     max_scf_fmri_len + 2) < 0)
9837                                         scfdie();
9838 
9839                                 warn(gettext("The value of %s does not specify "
9840                                     "a service or an instance.\n"), fmri);
9841                         }
9842 
9843                         export_property(exp_prop, exp_str, &pgelts, 0);
9844                         continue;
9845 
9846                 case SCF_ERROR_NOT_FOUND:
9847                         if (g_verbose) {
9848                                 if (scf_property_to_fmri(exp_prop, fmri,
9849                                     max_scf_fmri_len + 2) < 0)
9850                                         scfdie();
9851 
9852                                 warn(gettext("The entity specified by %s does "
9853                                     "not exist.\n"), fmri);
9854                         }
9855 
9856                         export_property(exp_prop, exp_str, &pgelts, 0);
9857                         continue;
9858 
9859                 default:
9860 #ifndef NDEBUG
9861                         (void) fprintf(stderr, "%s:%d: %s() failed with "
9862                             "unexpected error %d.\n", __FILE__, __LINE__,
9863                             "fmri_to_entity", serr);
9864 #endif
9865                         abort();
9866                 }
9867 
9868                 if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9869                         if (scf_error() != SCF_ERROR_NOT_FOUND)
9870                                 scfdie();
9871 
9872                         warn(gettext("Entity %s is missing dependency property "
9873                             "group %s.\n"), fmri, exp_str);
9874 
9875                         export_property(exp_prop, NULL, &pgelts, 0);
9876                         continue;
9877                 }
9878 
9879                 if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9880                         scfdie();
9881 
9882                 if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9883                         if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9884                                 scfdie();
9885 
9886                         warn(gettext("Property group %s is not of "
9887                             "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9888 
9889                         export_property(exp_prop, NULL, &pgelts, 0);
9890                         continue;
9891                 }
9892 
9893                 n = export_dependent(opg, exp_str, fmri);
9894                 if (n == NULL)
9895                         export_property(exp_prop, exp_str, &pgelts, 0);
9896                 else {
9897                         if (eelts->dependents == NULL)
9898                                 eelts->dependents = n;
9899                         else
9900                                 (void) xmlAddSibling(eelts->dependents,
9901                                     n);
9902                 }
9903         }
9904         if (ret == -1)
9905                 scfdie();
9906 
9907         free(fmri);
9908         free(type);
9909 
9910         scf_iter_destroy(iter);
9911         scf_pg_destroy(opg);
9912 
9913         if (pgelts.propvals != NULL || pgelts.properties != NULL)
9914                 export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9915                     eelts);
9916 }
9917 
9918 static void
9919 make_node(xmlNodePtr *nodep, const char *name)
9920 {
9921         if (*nodep == NULL) {
9922                 *nodep = xmlNewNode(NULL, (xmlChar *)name);
9923                 if (*nodep == NULL)
9924                         uu_die(emsg_create_xml);
9925         }
9926 }
9927 
9928 static xmlNodePtr
9929 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9930 {
9931         int ret;
9932         xmlNodePtr parent = NULL;
9933         xmlNodePtr loctext = NULL;
9934 
9935         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9936                 scfdie();
9937 
9938         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9939                 if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9940                     prop_get_val(exp_prop, exp_val) != 0)
9941                         continue;
9942 
9943                 if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9944                         scfdie();
9945 
9946                 make_node(&parent, parname);
9947                 loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9948                     (xmlChar *)exp_str);
9949                 if (loctext == NULL)
9950                         uu_die(emsg_create_xml);
9951 
9952                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9953                         scfdie();
9954 
9955                 safe_setprop(loctext, "xml:lang", exp_str);
9956         }
9957 
9958         if (ret == -1)
9959                 scfdie();
9960 
9961         return (parent);
9962 }
9963 
9964 static xmlNodePtr
9965 export_tm_manpage(scf_propertygroup_t *pg)
9966 {
9967         xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9968         if (manpage == NULL)
9969                 uu_die(emsg_create_xml);
9970 
9971         if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9972             set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9973             pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9974             set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9975                 xmlFreeNode(manpage);
9976                 return (NULL);
9977         }
9978 
9979         if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9980                 (void) set_attr_from_prop_default(exp_prop,
9981                     manpage, "manpath", ":default");
9982 
9983         return (manpage);
9984 }
9985 
9986 static xmlNodePtr
9987 export_tm_doc_link(scf_propertygroup_t *pg)
9988 {
9989         xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9990         if (doc_link == NULL)
9991                 uu_die(emsg_create_xml);
9992 
9993         if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9994             set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9995             pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9996             set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9997                 xmlFreeNode(doc_link);
9998                 return (NULL);
9999         }
10000         return (doc_link);
10001 }
10002 
10003 /*
10004  * Process template information for a service or instances.
10005  */
10006 static void
10007 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10008     struct template_elts *telts)
10009 {
10010         size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10011         size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10012         xmlNodePtr child = NULL;
10013 
10014         if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10015                 scfdie();
10016 
10017         if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10018                 telts->common_name = export_tm_loctext(pg, "common_name");
10019                 if (telts->common_name == NULL)
10020                         export_pg(pg, elts, 0);
10021                 return;
10022         } else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10023                 telts->description = export_tm_loctext(pg, "description");
10024                 if (telts->description == NULL)
10025                         export_pg(pg, elts, 0);
10026                 return;
10027         }
10028 
10029         if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10030                 child = export_tm_manpage(pg);
10031         } else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10032                 child = export_tm_doc_link(pg);
10033         }
10034 
10035         if (child != NULL) {
10036                 make_node(&telts->documentation, "documentation");
10037                 (void) xmlAddChild(telts->documentation, child);
10038         } else {
10039                 export_pg(pg, elts, 0);
10040         }
10041 }
10042 
10043 /*
10044  * Process parameter and paramval elements
10045  */
10046 static void
10047 export_parameter(scf_property_t *prop, const char *name,
10048     struct params_elts *elts)
10049 {
10050         xmlNodePtr param;
10051         scf_error_t err = 0;
10052         int ret;
10053 
10054         if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10055                 if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10056                         uu_die(emsg_create_xml);
10057 
10058                 safe_setprop(param, name_attr, name);
10059 
10060                 if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10061                         scfdie();
10062                 safe_setprop(param, value_attr, exp_str);
10063 
10064                 if (elts->paramval == NULL)
10065                         elts->paramval = param;
10066                 else
10067                         (void) xmlAddSibling(elts->paramval, param);
10068 
10069                 return;
10070         }
10071 
10072         err = scf_error();
10073 
10074         if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10075             err != SCF_ERROR_NOT_FOUND)
10076                 scfdie();
10077 
10078         if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10079                 uu_die(emsg_create_xml);
10080 
10081         safe_setprop(param, name_attr, name);
10082 
10083         if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10084                 if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10085                         scfdie();
10086 
10087                 while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10088                     1) {
10089                         xmlNodePtr vn;
10090 
10091                         if ((vn = xmlNewChild(param, NULL,
10092                             (xmlChar *)"value_node", NULL)) == NULL)
10093                                 uu_die(emsg_create_xml);
10094 
10095                         if (scf_value_get_as_string(exp_val, exp_str,
10096                             exp_str_sz) < 0)
10097                                 scfdie();
10098 
10099                         safe_setprop(vn, value_attr, exp_str);
10100                 }
10101                 if (ret != 0)
10102                         scfdie();
10103         }
10104 
10105         if (elts->parameter == NULL)
10106                 elts->parameter = param;
10107         else
10108                 (void) xmlAddSibling(elts->parameter, param);
10109 }
10110 
10111 /*
10112  * Process notification parameters for a service or instance
10113  */
10114 static void
10115 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10116 {
10117         xmlNodePtr n, event, *type;
10118         struct params_elts *eelts;
10119         int ret, err, i;
10120 
10121         n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10122         event = xmlNewNode(NULL, (xmlChar *)"event");
10123         if (n == NULL || event == NULL)
10124                 uu_die(emsg_create_xml);
10125 
10126         /* event value */
10127         if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10128                 scfdie();
10129         safe_setprop(event, value_attr, exp_str);
10130 
10131         (void) xmlAddChild(n, event);
10132 
10133         if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10134             (eelts = calloc(URI_SCHEME_NUM,
10135             sizeof (struct params_elts))) == NULL)
10136                 uu_die(gettext("Out of memory.\n"));
10137 
10138         err = 0;
10139 
10140         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10141                 scfdie();
10142 
10143         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10144                 char *t, *p;
10145 
10146                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10147                         scfdie();
10148 
10149                 if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10150                         /*
10151                          * this is not a well formed notification parameters
10152                          * element, we should export as regular pg
10153                          */
10154                         err = 1;
10155                         break;
10156                 }
10157 
10158                 if ((i = check_uri_protocol(t)) < 0) {
10159                         err = 1;
10160                         break;
10161                 }
10162 
10163                 if (type[i] == NULL) {
10164                         if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10165                             NULL)
10166                                 uu_die(emsg_create_xml);
10167 
10168                         safe_setprop(type[i], name_attr, t);
10169                 }
10170                 if (strcmp(p, active_attr) == 0) {
10171                         if (set_attr_from_prop(exp_prop, type[i],
10172                             active_attr) != 0) {
10173                                 err = 1;
10174                                 break;
10175                         }
10176                         continue;
10177                 }
10178                 /*
10179                  * We export the parameter
10180                  */
10181                 export_parameter(exp_prop, p, &eelts[i]);
10182         }
10183 
10184         if (ret == -1)
10185                 scfdie();
10186 
10187         if (err == 1) {
10188                 for (i = 0; i < URI_SCHEME_NUM; ++i)
10189                         xmlFree(type[i]);
10190                 free(type);
10191 
10192                 export_pg(pg, elts, 0);
10193 
10194                 return;
10195         } else {
10196                 for (i = 0; i < URI_SCHEME_NUM; ++i)
10197                         if (type[i] != NULL) {
10198                                 (void) xmlAddChildList(type[i],
10199                                     eelts[i].paramval);
10200                                 (void) xmlAddChildList(type[i],
10201                                     eelts[i].parameter);
10202                                 (void) xmlAddSibling(event, type[i]);
10203                         }
10204         }
10205         free(type);
10206 
10207         if (elts->notify_params == NULL)
10208                 elts->notify_params = n;
10209         else
10210                 (void) xmlAddSibling(elts->notify_params, n);
10211 }
10212 
10213 /*
10214  * Process the general property group for an instance.
10215  */
10216 static void
10217 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10218     struct entity_elts *elts)
10219 {
10220         uint8_t enabled;
10221         struct pg_elts pgelts;
10222         int ret;
10223 
10224         /* enabled */
10225         if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10226             prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10227             prop_get_val(exp_prop, exp_val) == 0) {
10228                 if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10229                         scfdie();
10230         } else {
10231                 enabled = 0;
10232         }
10233 
10234         safe_setprop(inode, enabled_attr, enabled ? true : false);
10235 
10236         if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10237                 scfdie();
10238 
10239         (void) memset(&pgelts, 0, sizeof (pgelts));
10240 
10241         while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10242                 if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10243                         scfdie();
10244 
10245                 if (strcmp(exp_str, scf_property_enabled) == 0) {
10246                         continue;
10247                 } else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10248                         xmlNodePtr rnode, sfnode;
10249 
10250                         rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10251                         if (rnode == NULL)
10252                                 uu_die(emsg_create_xml);
10253 
10254                         sfnode = xmlNewChild(rnode, NULL,
10255                             (xmlChar *)"service_fmri", NULL);
10256                         if (sfnode == NULL)
10257                                 uu_die(emsg_create_xml);
10258 
10259                         if (set_attr_from_prop(exp_prop, sfnode,
10260                             value_attr) == 0) {
10261                                 elts->restarter = rnode;
10262                                 continue;
10263                         }
10264 
10265                         xmlFreeNode(rnode);
10266                 }
10267 
10268                 export_property(exp_prop, exp_str, &pgelts, 0);
10269         }
10270         if (ret == -1)
10271                 scfdie();
10272 
10273         if (pgelts.propvals != NULL || pgelts.properties != NULL)
10274                 export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10275                     elts);
10276 }
10277 
10278 /*
10279  * Put an instance element for the given instance into selts.
10280  */
10281 static void
10282 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10283 {
10284         xmlNodePtr n;
10285         boolean_t isdefault;
10286         struct entity_elts elts;
10287         struct template_elts template_elts;
10288         int ret;
10289 
10290         n = xmlNewNode(NULL, (xmlChar *)"instance");
10291         if (n == NULL)
10292                 uu_die(emsg_create_xml);
10293 
10294         /* name */
10295         if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10296                 scfdie();
10297         safe_setprop(n, name_attr, exp_str);
10298         isdefault = strcmp(exp_str, "default") == 0;
10299 
10300         /* check existance of general pg (since general/enabled is required) */
10301         if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10302                 if (scf_error() != SCF_ERROR_NOT_FOUND)
10303                         scfdie();
10304 
10305                 if (g_verbose) {
10306                         if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10307                                 scfdie();
10308 
10309                         warn(gettext("Instance %s has no general property "
10310                             "group; it will be marked disabled.\n"), exp_str);
10311                 }
10312 
10313                 safe_setprop(n, enabled_attr, false);
10314         } else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10315             strcmp(exp_str, scf_group_framework) != 0) {
10316                 if (g_verbose) {
10317                         if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10318                                 scfdie();
10319 
10320                         warn(gettext("Property group %s is not of type "
10321                             "framework; the instance will be marked "
10322                             "disabled.\n"), exp_str);
10323                 }
10324 
10325                 safe_setprop(n, enabled_attr, false);
10326         }
10327 
10328         /* property groups */
10329         if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10330                 scfdie();
10331 
10332         (void) memset(&elts, 0, sizeof (elts));
10333         (void) memset(&template_elts, 0, sizeof (template_elts));
10334 
10335         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10336                 uint32_t pgflags;
10337 
10338                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10339                         scfdie();
10340 
10341                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10342                         continue;
10343 
10344                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10345                         scfdie();
10346 
10347                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10348                         export_dependency(exp_pg, &elts);
10349                         continue;
10350                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10351                         export_method(exp_pg, &elts);
10352                         continue;
10353                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10354                         if (scf_pg_get_name(exp_pg, exp_str,
10355                             max_scf_name_len + 1) < 0)
10356                                 scfdie();
10357 
10358                         if (strcmp(exp_str, scf_pg_general) == 0) {
10359                                 export_inst_general(exp_pg, n, &elts);
10360                                 continue;
10361                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10362                             0) {
10363                                 export_method_context(exp_pg, &elts);
10364                                 continue;
10365                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10366                                 export_dependents(exp_pg, &elts);
10367                                 continue;
10368                         }
10369                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10370                         export_template(exp_pg, &elts, &template_elts);
10371                         continue;
10372                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10373                         export_notify_params(exp_pg, &elts);
10374                         continue;
10375                 }
10376 
10377                 /* Ordinary pg. */
10378                 export_pg(exp_pg, &elts, flags);
10379         }
10380         if (ret == -1)
10381                 scfdie();
10382 
10383         if (template_elts.common_name != NULL) {
10384                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10385                 (void) xmlAddChild(elts.template, template_elts.common_name);
10386                 (void) xmlAddChild(elts.template, template_elts.description);
10387                 (void) xmlAddChild(elts.template, template_elts.documentation);
10388         } else {
10389                 xmlFreeNode(template_elts.description);
10390                 xmlFreeNode(template_elts.documentation);
10391         }
10392 
10393         if (isdefault && elts.restarter == NULL &&
10394             elts.dependencies == NULL && elts.method_context == NULL &&
10395             elts.exec_methods == NULL && elts.notify_params == NULL &&
10396             elts.property_groups == NULL && elts.template == NULL) {
10397                 xmlChar *eval;
10398 
10399                 /* This is a default instance */
10400                 eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10401 
10402                 xmlFreeNode(n);
10403 
10404                 n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10405                 if (n == NULL)
10406                         uu_die(emsg_create_xml);
10407 
10408                 safe_setprop(n, enabled_attr, (char *)eval);
10409                 xmlFree(eval);
10410 
10411                 selts->create_default_instance = n;
10412         } else {
10413                 /* Assemble the children in order. */
10414                 (void) xmlAddChild(n, elts.restarter);
10415                 (void) xmlAddChildList(n, elts.dependencies);
10416                 (void) xmlAddChildList(n, elts.dependents);
10417                 (void) xmlAddChild(n, elts.method_context);
10418                 (void) xmlAddChildList(n, elts.exec_methods);
10419                 (void) xmlAddChildList(n, elts.notify_params);
10420                 (void) xmlAddChildList(n, elts.property_groups);
10421                 (void) xmlAddChild(n, elts.template);
10422 
10423                 if (selts->instances == NULL)
10424                         selts->instances = n;
10425                 else
10426                         (void) xmlAddSibling(selts->instances, n);
10427         }
10428 }
10429 
10430 /*
10431  * Return a service element for the given service.
10432  */
10433 static xmlNodePtr
10434 export_service(scf_service_t *svc, int flags)
10435 {
10436         xmlNodePtr snode;
10437         struct entity_elts elts;
10438         struct template_elts template_elts;
10439         int ret;
10440 
10441         snode = xmlNewNode(NULL, (xmlChar *)"service");
10442         if (snode == NULL)
10443                 uu_die(emsg_create_xml);
10444 
10445         /* Get & set name attribute */
10446         if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10447                 scfdie();
10448         safe_setprop(snode, name_attr, exp_str);
10449 
10450         safe_setprop(snode, type_attr, "service");
10451         safe_setprop(snode, "version", "0");
10452 
10453         /* Acquire child elements. */
10454         if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10455                 scfdie();
10456 
10457         (void) memset(&elts, 0, sizeof (elts));
10458         (void) memset(&template_elts, 0, sizeof (template_elts));
10459 
10460         while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10461                 uint32_t pgflags;
10462 
10463                 if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10464                         scfdie();
10465 
10466                 if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10467                         continue;
10468 
10469                 if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10470                         scfdie();
10471 
10472                 if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10473                         export_dependency(exp_pg, &elts);
10474                         continue;
10475                 } else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10476                         export_method(exp_pg, &elts);
10477                         continue;
10478                 } else if (strcmp(exp_str, scf_group_framework) == 0) {
10479                         if (scf_pg_get_name(exp_pg, exp_str,
10480                             max_scf_name_len + 1) < 0)
10481                                 scfdie();
10482 
10483                         if (strcmp(exp_str, scf_pg_general) == 0) {
10484                                 export_svc_general(exp_pg, &elts);
10485                                 continue;
10486                         } else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10487                             0) {
10488                                 export_method_context(exp_pg, &elts);
10489                                 continue;
10490                         } else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10491                                 export_dependents(exp_pg, &elts);
10492                                 continue;
10493                         } else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10494                                 continue;
10495                         }
10496                 } else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10497                         export_template(exp_pg, &elts, &template_elts);
10498                         continue;
10499                 } else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10500                         export_notify_params(exp_pg, &elts);
10501                         continue;
10502                 }
10503 
10504                 export_pg(exp_pg, &elts, flags);
10505         }
10506         if (ret == -1)
10507                 scfdie();
10508 
10509         if (template_elts.common_name != NULL) {
10510                 elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10511                 (void) xmlAddChild(elts.template, template_elts.common_name);
10512                 (void) xmlAddChild(elts.template, template_elts.description);
10513                 (void) xmlAddChild(elts.template, template_elts.documentation);
10514         } else {
10515                 xmlFreeNode(template_elts.description);
10516                 xmlFreeNode(template_elts.documentation);
10517         }
10518 
10519         /* Iterate instances */
10520         if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10521                 scfdie();
10522 
10523         while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10524                 export_instance(exp_inst, &elts, flags);
10525         if (ret == -1)
10526                 scfdie();
10527 
10528         /* Now add all of the accumulated elements in order. */
10529         (void) xmlAddChild(snode, elts.create_default_instance);
10530         (void) xmlAddChild(snode, elts.single_instance);
10531         (void) xmlAddChild(snode, elts.restarter);
10532         (void) xmlAddChildList(snode, elts.dependencies);
10533         (void) xmlAddChildList(snode, elts.dependents);
10534         (void) xmlAddChild(snode, elts.method_context);
10535         (void) xmlAddChildList(snode, elts.exec_methods);
10536         (void) xmlAddChildList(snode, elts.notify_params);
10537         (void) xmlAddChildList(snode, elts.property_groups);
10538         (void) xmlAddChildList(snode, elts.instances);
10539         (void) xmlAddChild(snode, elts.stability);
10540         (void) xmlAddChild(snode, elts.template);
10541 
10542         return (snode);
10543 }
10544 
10545 static int
10546 export_callback(void *data, scf_walkinfo_t *wip)
10547 {
10548         FILE *f;
10549         xmlDocPtr doc;
10550         xmlNodePtr sb;
10551         int result;
10552         struct export_args *argsp = (struct export_args *)data;
10553 
10554         if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10555             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10556             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10557             (exp_val = scf_value_create(g_hndl)) == NULL ||
10558             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10559             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10560             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10561             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10562                 scfdie();
10563 
10564         exp_str_sz = max_scf_len + 1;
10565         exp_str = safe_malloc(exp_str_sz);
10566 
10567         if (argsp->filename != NULL) {
10568                 errno = 0;
10569                 f = fopen(argsp->filename, "wb");
10570                 if (f == NULL) {
10571                         if (errno == 0)
10572                                 uu_die(gettext("Could not open \"%s\": no free "
10573                                     "stdio streams.\n"), argsp->filename);
10574                         else
10575                                 uu_die(gettext("Could not open \"%s\""),
10576                                     argsp->filename);
10577                 }
10578         } else
10579                 f = stdout;
10580 
10581         doc = xmlNewDoc((xmlChar *)"1.0");
10582         if (doc == NULL)
10583                 uu_die(gettext("Could not create XML document.\n"));
10584 
10585         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10586             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10587                 uu_die(emsg_create_xml);
10588 
10589         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10590         if (sb == NULL)
10591                 uu_die(emsg_create_xml);
10592         safe_setprop(sb, type_attr, "manifest");
10593         safe_setprop(sb, name_attr, "export");
10594         (void) xmlAddSibling(doc->children, sb);
10595 
10596         (void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10597 
10598         result = write_service_bundle(doc, f);
10599 
10600         free(exp_str);
10601         scf_iter_destroy(exp_val_iter);
10602         scf_iter_destroy(exp_prop_iter);
10603         scf_iter_destroy(exp_pg_iter);
10604         scf_iter_destroy(exp_inst_iter);
10605         scf_value_destroy(exp_val);
10606         scf_property_destroy(exp_prop);
10607         scf_pg_destroy(exp_pg);
10608         scf_instance_destroy(exp_inst);
10609 
10610         xmlFreeDoc(doc);
10611 
10612         if (f != stdout)
10613                 (void) fclose(f);
10614 
10615         return (result);
10616 }
10617 
10618 /*
10619  * Get the service named by fmri, build an XML tree which represents it, and
10620  * dump it into filename (or stdout if filename is NULL).
10621  */
10622 int
10623 lscf_service_export(char *fmri, const char *filename, int flags)
10624 {
10625         struct export_args args;
10626         int ret, err;
10627 
10628         lscf_prep_hndl();
10629 
10630         bzero(&args, sizeof (args));
10631         args.filename = filename;
10632         args.flags = flags;
10633 
10634         err = 0;
10635         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10636             SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10637             &args, &err, semerr)) != 0) {
10638                 if (ret != -1)
10639                         semerr(gettext("Failed to walk instances: %s\n"),
10640                             scf_strerror(ret));
10641                 return (-1);
10642         }
10643 
10644         /*
10645          * Error message has already been printed.
10646          */
10647         if (err != 0)
10648                 return (-1);
10649 
10650         return (0);
10651 }
10652 
10653 
10654 /*
10655  * Archive
10656  */
10657 
10658 static xmlNodePtr
10659 make_archive(int flags)
10660 {
10661         xmlNodePtr sb;
10662         scf_scope_t *scope;
10663         scf_service_t *svc;
10664         scf_iter_t *iter;
10665         int r;
10666 
10667         if ((scope = scf_scope_create(g_hndl)) == NULL ||
10668             (svc = scf_service_create(g_hndl)) == NULL ||
10669             (iter = scf_iter_create(g_hndl)) == NULL ||
10670             (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10671             (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10672             (exp_prop = scf_property_create(g_hndl)) == NULL ||
10673             (exp_val = scf_value_create(g_hndl)) == NULL ||
10674             (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10675             (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10676             (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10677             (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10678                 scfdie();
10679 
10680         exp_str_sz = max_scf_len + 1;
10681         exp_str = safe_malloc(exp_str_sz);
10682 
10683         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10684         if (sb == NULL)
10685                 uu_die(emsg_create_xml);
10686         safe_setprop(sb, type_attr, "archive");
10687         safe_setprop(sb, name_attr, "none");
10688 
10689         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10690                 scfdie();
10691         if (scf_iter_scope_services(iter, scope) != 0)
10692                 scfdie();
10693 
10694         for (;;) {
10695                 r = scf_iter_next_service(iter, svc);
10696                 if (r == 0)
10697                         break;
10698                 if (r != 1)
10699                         scfdie();
10700 
10701                 if (scf_service_get_name(svc, exp_str,
10702                     max_scf_name_len + 1) < 0)
10703                         scfdie();
10704 
10705                 if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10706                         continue;
10707 
10708                 (void) xmlAddChild(sb, export_service(svc, flags));
10709         }
10710 
10711         free(exp_str);
10712 
10713         scf_iter_destroy(exp_val_iter);
10714         scf_iter_destroy(exp_prop_iter);
10715         scf_iter_destroy(exp_pg_iter);
10716         scf_iter_destroy(exp_inst_iter);
10717         scf_value_destroy(exp_val);
10718         scf_property_destroy(exp_prop);
10719         scf_pg_destroy(exp_pg);
10720         scf_instance_destroy(exp_inst);
10721         scf_iter_destroy(iter);
10722         scf_service_destroy(svc);
10723         scf_scope_destroy(scope);
10724 
10725         return (sb);
10726 }
10727 
10728 int
10729 lscf_archive(const char *filename, int flags)
10730 {
10731         FILE *f;
10732         xmlDocPtr doc;
10733         int result;
10734 
10735         lscf_prep_hndl();
10736 
10737         if (filename != NULL) {
10738                 errno = 0;
10739                 f = fopen(filename, "wb");
10740                 if (f == NULL) {
10741                         if (errno == 0)
10742                                 uu_die(gettext("Could not open \"%s\": no free "
10743                                     "stdio streams.\n"), filename);
10744                         else
10745                                 uu_die(gettext("Could not open \"%s\""),
10746                                     filename);
10747                 }
10748         } else
10749                 f = stdout;
10750 
10751         doc = xmlNewDoc((xmlChar *)"1.0");
10752         if (doc == NULL)
10753                 uu_die(gettext("Could not create XML document.\n"));
10754 
10755         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10756             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10757                 uu_die(emsg_create_xml);
10758 
10759         (void) xmlAddSibling(doc->children, make_archive(flags));
10760 
10761         result = write_service_bundle(doc, f);
10762 
10763         xmlFreeDoc(doc);
10764 
10765         if (f != stdout)
10766                 (void) fclose(f);
10767 
10768         return (result);
10769 }
10770 
10771 
10772 /*
10773  * "Extract" a profile.
10774  */
10775 int
10776 lscf_profile_extract(const char *filename)
10777 {
10778         FILE *f;
10779         xmlDocPtr doc;
10780         xmlNodePtr sb, snode, inode;
10781         scf_scope_t *scope;
10782         scf_service_t *svc;
10783         scf_instance_t *inst;
10784         scf_propertygroup_t *pg;
10785         scf_property_t *prop;
10786         scf_value_t *val;
10787         scf_iter_t *siter, *iiter;
10788         int r, s;
10789         char *namebuf;
10790         uint8_t b;
10791         int result;
10792 
10793         lscf_prep_hndl();
10794 
10795         if (filename != NULL) {
10796                 errno = 0;
10797                 f = fopen(filename, "wb");
10798                 if (f == NULL) {
10799                         if (errno == 0)
10800                                 uu_die(gettext("Could not open \"%s\": no "
10801                                     "free stdio streams.\n"), filename);
10802                         else
10803                                 uu_die(gettext("Could not open \"%s\""),
10804                                     filename);
10805                 }
10806         } else
10807                 f = stdout;
10808 
10809         doc = xmlNewDoc((xmlChar *)"1.0");
10810         if (doc == NULL)
10811                 uu_die(gettext("Could not create XML document.\n"));
10812 
10813         if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10814             (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10815                 uu_die(emsg_create_xml);
10816 
10817         sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10818         if (sb == NULL)
10819                 uu_die(emsg_create_xml);
10820         safe_setprop(sb, type_attr, "profile");
10821         safe_setprop(sb, name_attr, "extract");
10822         (void) xmlAddSibling(doc->children, sb);
10823 
10824         if ((scope = scf_scope_create(g_hndl)) == NULL ||
10825             (svc = scf_service_create(g_hndl)) == NULL ||
10826             (inst = scf_instance_create(g_hndl)) == NULL ||
10827             (pg = scf_pg_create(g_hndl)) == NULL ||
10828             (prop = scf_property_create(g_hndl)) == NULL ||
10829             (val = scf_value_create(g_hndl)) == NULL ||
10830             (siter = scf_iter_create(g_hndl)) == NULL ||
10831             (iiter = scf_iter_create(g_hndl)) == NULL)
10832                 scfdie();
10833 
10834         if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
10835                 scfdie();
10836 
10837         if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
10838                 scfdie();
10839 
10840         namebuf = safe_malloc(max_scf_name_len + 1);
10841 
10842         while ((r = scf_iter_next_service(siter, svc)) == 1) {
10843                 if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
10844                         scfdie();
10845 
10846                 snode = xmlNewNode(NULL, (xmlChar *)"service");
10847                 if (snode == NULL)
10848                         uu_die(emsg_create_xml);
10849 
10850                 if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
10851                     0)
10852                         scfdie();
10853 
10854                 safe_setprop(snode, name_attr, namebuf);
10855 
10856                 safe_setprop(snode, type_attr, "service");
10857                 safe_setprop(snode, "version", "0");
10858 
10859                 while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
10860                         if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
10861                             SCF_SUCCESS) {
10862                                 if (scf_error() != SCF_ERROR_NOT_FOUND)
10863                                         scfdie();
10864 
10865                                 if (g_verbose) {
10866                                         ssize_t len;
10867                                         char *fmri;
10868 
10869                                         len =
10870                                             scf_instance_to_fmri(inst, NULL, 0);
10871                                         if (len < 0)
10872                                                 scfdie();
10873 
10874                                         fmri = safe_malloc(len + 1);
10875 
10876                                         if (scf_instance_to_fmri(inst, fmri,
10877                                             len + 1) < 0)
10878                                                 scfdie();
10879 
10880                                         warn("Instance %s has no \"%s\" "
10881                                             "property group.\n", fmri,
10882                                             scf_pg_general);
10883 
10884                                         free(fmri);
10885                                 }
10886 
10887                                 continue;
10888                         }
10889 
10890                         if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
10891                             prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
10892                             prop_get_val(prop, val) != 0)
10893                                 continue;
10894 
10895                         inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
10896                             NULL);
10897                         if (inode == NULL)
10898                                 uu_die(emsg_create_xml);
10899 
10900                         if (scf_instance_get_name(inst, namebuf,
10901                             max_scf_name_len + 1) < 0)
10902                                 scfdie();
10903 
10904                         safe_setprop(inode, name_attr, namebuf);
10905 
10906                         if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
10907                                 scfdie();
10908 
10909                         safe_setprop(inode, enabled_attr, b ? true : false);
10910                 }
10911                 if (s < 0)
10912                         scfdie();
10913 
10914                 if (snode->children != NULL)
10915                         (void) xmlAddChild(sb, snode);
10916                 else
10917                         xmlFreeNode(snode);
10918         }
10919         if (r < 0)
10920                 scfdie();
10921 
10922         free(namebuf);
10923 
10924         result = write_service_bundle(doc, f);
10925 
10926         xmlFreeDoc(doc);
10927 
10928         if (f != stdout)
10929                 (void) fclose(f);
10930 
10931         return (result);
10932 }
10933 
10934 
10935 /*
10936  * Entity manipulation commands
10937  */
10938 
10939 /*
10940  * Entity selection.  If no entity is selected, then the current scope is in
10941  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
10942  * only cur_inst is NULL, and when an instance is selected, none are NULL.
10943  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
10944  * cur_inst will be non-NULL.
10945  */
10946 
10947 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
10948 static int
10949 select_inst(const char *name)
10950 {
10951         scf_instance_t *inst;
10952         scf_error_t err;
10953 
10954         assert(cur_svc != NULL);
10955 
10956         inst = scf_instance_create(g_hndl);
10957         if (inst == NULL)
10958                 scfdie();
10959 
10960         if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10961                 cur_inst = inst;
10962                 return (0);
10963         }
10964 
10965         err = scf_error();
10966         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10967                 scfdie();
10968 
10969         scf_instance_destroy(inst);
10970         return (1);
10971 }
10972 
10973 /* Returns as above. */
10974 static int
10975 select_svc(const char *name)
10976 {
10977         scf_service_t *svc;
10978         scf_error_t err;
10979 
10980         assert(cur_scope != NULL);
10981 
10982         svc = scf_service_create(g_hndl);
10983         if (svc == NULL)
10984                 scfdie();
10985 
10986         if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10987                 cur_svc = svc;
10988                 return (0);
10989         }
10990 
10991         err = scf_error();
10992         if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10993                 scfdie();
10994 
10995         scf_service_destroy(svc);
10996         return (1);
10997 }
10998 
10999 /* ARGSUSED */
11000 static int
11001 select_callback(void *unused, scf_walkinfo_t *wip)
11002 {
11003         scf_instance_t *inst;
11004         scf_service_t *svc;
11005         scf_scope_t *scope;
11006 
11007         if (wip->inst != NULL) {
11008                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11009                     (svc = scf_service_create(g_hndl)) == NULL ||
11010                     (inst = scf_instance_create(g_hndl)) == NULL)
11011                         scfdie();
11012 
11013                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11014                     inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11015                         scfdie();
11016         } else {
11017                 assert(wip->svc != NULL);
11018 
11019                 if ((scope = scf_scope_create(g_hndl)) == NULL ||
11020                     (svc = scf_service_create(g_hndl)) == NULL)
11021                         scfdie();
11022 
11023                 if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11024                     NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11025                         scfdie();
11026 
11027                 inst = NULL;
11028         }
11029 
11030         /* Clear out the current selection */
11031         assert(cur_scope != NULL);
11032         scf_scope_destroy(cur_scope);
11033         scf_service_destroy(cur_svc);
11034         scf_instance_destroy(cur_inst);
11035 
11036         cur_scope = scope;
11037         cur_svc = svc;
11038         cur_inst = inst;
11039 
11040         return (0);
11041 }
11042 
11043 static int
11044 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11045 {
11046         char **fmri = fmri_p;
11047 
11048         *fmri = strdup(wip->fmri);
11049         if (*fmri == NULL)
11050                 uu_die(gettext("Out of memory.\n"));
11051 
11052         return (0);
11053 }
11054 
11055 /*
11056  * validate [fmri]
11057  * Perform the validation of an FMRI instance.
11058  */
11059 void
11060 lscf_validate_fmri(const char *fmri)
11061 {
11062         int ret = 0;
11063         size_t inst_sz;
11064         char *inst_fmri = NULL;
11065         scf_tmpl_errors_t *errs = NULL;
11066         char *snapbuf = NULL;
11067 
11068         lscf_prep_hndl();
11069 
11070         if (fmri == NULL) {
11071                 inst_sz = max_scf_fmri_len + 1;
11072                 inst_fmri = safe_malloc(inst_sz);
11073 
11074                 if (cur_snap != NULL) {
11075                         snapbuf = safe_malloc(max_scf_name_len + 1);
11076                         if (scf_snapshot_get_name(cur_snap, snapbuf,
11077                             max_scf_name_len + 1) < 0)
11078                                 scfdie();
11079                 }
11080                 if (cur_inst == NULL) {
11081                         semerr(gettext("No instance selected\n"));
11082                         goto cleanup;
11083                 } else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11084                     inst_sz) >= inst_sz) {
11085                         /* sanity check. Should never get here */
11086                         uu_die(gettext("Unexpected error! file %s, line %d\n"),
11087                             __FILE__, __LINE__);
11088                 }
11089         } else {
11090                 scf_error_t scf_err;
11091                 int err = 0;
11092 
11093                 if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11094                     validate_callback, &inst_fmri, &err, semerr)) != 0) {
11095                         uu_warn("Failed to walk instances: %s\n",
11096                             scf_strerror(scf_err));
11097                         goto cleanup;
11098                 }
11099                 if (err != 0) {
11100                         /* error message displayed by scf_walk_fmri */
11101                         goto cleanup;
11102                 }
11103         }
11104 
11105         ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11106             SCF_TMPL_VALIDATE_FLAG_CURRENT);
11107         if (ret == -1) {
11108                 if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11109                         warn(gettext("Template data for %s is invalid. "
11110                             "Consider reverting to a previous snapshot or "
11111                             "restoring original configuration.\n"), inst_fmri);
11112                 } else {
11113                         uu_warn("%s: %s\n",
11114                             gettext("Error validating the instance"),
11115                             scf_strerror(scf_error()));
11116                 }
11117         } else if (ret == 1 && errs != NULL) {
11118                 scf_tmpl_error_t *err = NULL;
11119                 char *msg;
11120                 size_t len = 256;       /* initial error buffer size */
11121                 int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11122                     SCF_TMPL_STRERROR_HUMAN : 0;
11123 
11124                 msg = safe_malloc(len);
11125 
11126                 while ((err = scf_tmpl_next_error(errs)) != NULL) {
11127                         int ret;
11128 
11129                         if ((ret = scf_tmpl_strerror(err, msg, len,
11130                             flag)) >= len) {
11131                                 len = ret + 1;
11132                                 msg = realloc(msg, len);
11133                                 if (msg == NULL)
11134                                         uu_die(gettext(
11135                                             "Out of memory.\n"));
11136                                 (void) scf_tmpl_strerror(err, msg, len,
11137                                     flag);
11138                         }
11139                         (void) fprintf(stderr, "%s\n", msg);
11140                 }
11141                 if (msg != NULL)
11142                         free(msg);
11143         }
11144         if (errs != NULL)
11145                 scf_tmpl_errors_destroy(errs);
11146 
11147 cleanup:
11148         free(inst_fmri);
11149         free(snapbuf);
11150 }
11151 
11152 static void
11153 lscf_validate_file(const char *filename)
11154 {
11155         tmpl_errors_t *errs;
11156 
11157         bundle_t *b = internal_bundle_new();
11158         if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11159                 if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11160                         tmpl_errors_print(stderr, errs, "");
11161                         semerr(gettext("Validation failed.\n"));
11162                 }
11163                 tmpl_errors_destroy(errs);
11164         }
11165         (void) internal_bundle_free(b);
11166 }
11167 
11168 /*
11169  * validate [fmri|file]
11170  */
11171 void
11172 lscf_validate(const char *arg)
11173 {
11174         const char *str;
11175 
11176         if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11177             sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11178                 str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11179                 lscf_validate_file(str);
11180         } else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11181             sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11182                 str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11183                 lscf_validate_fmri(str);
11184         } else if (access(arg, R_OK | F_OK) == 0) {
11185                 lscf_validate_file(arg);
11186         } else {
11187                 lscf_validate_fmri(arg);
11188         }
11189 }
11190 
11191 void
11192 lscf_select(const char *fmri)
11193 {
11194         int ret, err;
11195 
11196         lscf_prep_hndl();
11197 
11198         if (cur_snap != NULL) {
11199                 struct snaplevel *elt;
11200                 char *buf;
11201 
11202                 /* Error unless name is that of the next level. */
11203                 elt = uu_list_next(cur_levels, cur_elt);
11204                 if (elt == NULL) {
11205                         semerr(gettext("No children.\n"));
11206                         return;
11207                 }
11208 
11209                 buf = safe_malloc(max_scf_name_len + 1);
11210 
11211                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11212                     max_scf_name_len + 1) < 0)
11213                         scfdie();
11214 
11215                 if (strcmp(buf, fmri) != 0) {
11216                         semerr(gettext("No such child.\n"));
11217                         free(buf);
11218                         return;
11219                 }
11220 
11221                 free(buf);
11222 
11223                 cur_elt = elt;
11224                 cur_level = elt->sl;
11225                 return;
11226         }
11227 
11228         /*
11229          * Special case for 'svc:', which takes the user to the scope level.
11230          */
11231         if (strcmp(fmri, "svc:") == 0) {
11232                 scf_instance_destroy(cur_inst);
11233                 scf_service_destroy(cur_svc);
11234                 cur_inst = NULL;
11235                 cur_svc = NULL;
11236                 return;
11237         }
11238 
11239         /*
11240          * Special case for ':properties'.  This appears as part of 'list' but
11241          * can't be selected.  Give a more helpful error message in this case.
11242          */
11243         if (strcmp(fmri, ":properties") == 0) {
11244                 semerr(gettext(":properties is not an entity.  Try 'listprop' "
11245                     "to list properties.\n"));
11246                 return;
11247         }
11248 
11249         /*
11250          * First try the argument as relative to the current selection.
11251          */
11252         if (cur_inst != NULL) {
11253                 /* EMPTY */;
11254         } else if (cur_svc != NULL) {
11255                 if (select_inst(fmri) != 1)
11256                         return;
11257         } else {
11258                 if (select_svc(fmri) != 1)
11259                         return;
11260         }
11261 
11262         err = 0;
11263         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11264             select_callback, NULL, &err, semerr)) != 0) {
11265                 semerr(gettext("Failed to walk instances: %s\n"),
11266                     scf_strerror(ret));
11267         }
11268 }
11269 
11270 void
11271 lscf_unselect(void)
11272 {
11273         lscf_prep_hndl();
11274 
11275         if (cur_snap != NULL) {
11276                 struct snaplevel *elt;
11277 
11278                 elt = uu_list_prev(cur_levels, cur_elt);
11279                 if (elt == NULL) {
11280                         semerr(gettext("No parent levels.\n"));
11281                 } else {
11282                         cur_elt = elt;
11283                         cur_level = elt->sl;
11284                 }
11285         } else if (cur_inst != NULL) {
11286                 scf_instance_destroy(cur_inst);
11287                 cur_inst = NULL;
11288         } else if (cur_svc != NULL) {
11289                 scf_service_destroy(cur_svc);
11290                 cur_svc = NULL;
11291         } else {
11292                 semerr(gettext("Cannot unselect at scope level.\n"));
11293         }
11294 }
11295 
11296 /*
11297  * Return the FMRI of the current selection, for the prompt.
11298  */
11299 void
11300 lscf_get_selection_str(char *buf, size_t bufsz)
11301 {
11302         char *cp;
11303         ssize_t fmrilen, szret;
11304         boolean_t deleted = B_FALSE;
11305 
11306         if (g_hndl == NULL) {
11307                 (void) strlcpy(buf, "svc:", bufsz);
11308                 return;
11309         }
11310 
11311         if (cur_level != NULL) {
11312                 assert(cur_snap != NULL);
11313 
11314                 /* [ snapshot ] FMRI [: instance ] */
11315                 assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11316                     + 2 + max_scf_name_len + 1 + 1);
11317 
11318                 buf[0] = '[';
11319 
11320                 szret = scf_snapshot_get_name(cur_snap, buf + 1,
11321                     max_scf_name_len + 1);
11322                 if (szret < 0) {
11323                         if (scf_error() != SCF_ERROR_DELETED)
11324                                 scfdie();
11325 
11326                         goto snap_deleted;
11327                 }
11328 
11329                 (void) strcat(buf, "]svc:/");
11330 
11331                 cp = strchr(buf, '\0');
11332 
11333                 szret = scf_snaplevel_get_service_name(cur_level, cp,
11334                     max_scf_name_len + 1);
11335                 if (szret < 0) {
11336                         if (scf_error() != SCF_ERROR_DELETED)
11337                                 scfdie();
11338 
11339                         goto snap_deleted;
11340                 }
11341 
11342                 cp = strchr(cp, '\0');
11343 
11344                 if (snaplevel_is_instance(cur_level)) {
11345                         *cp++ = ':';
11346 
11347                         if (scf_snaplevel_get_instance_name(cur_level, cp,
11348                             max_scf_name_len + 1) < 0) {
11349                                 if (scf_error() != SCF_ERROR_DELETED)
11350                                         scfdie();
11351 
11352                                 goto snap_deleted;
11353                         }
11354                 } else {
11355                         *cp++ = '[';
11356                         *cp++ = ':';
11357 
11358                         if (scf_instance_get_name(cur_inst, cp,
11359                             max_scf_name_len + 1) < 0) {
11360                                 if (scf_error() != SCF_ERROR_DELETED)
11361                                         scfdie();
11362 
11363                                 goto snap_deleted;
11364                         }
11365 
11366                         (void) strcat(buf, "]");
11367                 }
11368 
11369                 return;
11370 
11371 snap_deleted:
11372                 deleted = B_TRUE;
11373                 free(buf);
11374                 unselect_cursnap();
11375         }
11376 
11377         assert(cur_snap == NULL);
11378 
11379         if (cur_inst != NULL) {
11380                 assert(cur_svc != NULL);
11381                 assert(cur_scope != NULL);
11382 
11383                 fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11384                 if (fmrilen >= 0) {
11385                         assert(fmrilen < bufsz);
11386                         if (deleted)
11387                                 warn(emsg_deleted);
11388                         return;
11389                 }
11390 
11391                 if (scf_error() != SCF_ERROR_DELETED)
11392                         scfdie();
11393 
11394                 deleted = B_TRUE;
11395 
11396                 scf_instance_destroy(cur_inst);
11397                 cur_inst = NULL;
11398         }
11399 
11400         if (cur_svc != NULL) {
11401                 assert(cur_scope != NULL);
11402 
11403                 szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11404                 if (szret >= 0) {
11405                         assert(szret < bufsz);
11406                         if (deleted)
11407                                 warn(emsg_deleted);
11408                         return;
11409                 }
11410 
11411                 if (scf_error() != SCF_ERROR_DELETED)
11412                         scfdie();
11413 
11414                 deleted = B_TRUE;
11415                 scf_service_destroy(cur_svc);
11416                 cur_svc = NULL;
11417         }
11418 
11419         assert(cur_scope != NULL);
11420         fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11421 
11422         if (fmrilen < 0)
11423                 scfdie();
11424 
11425         assert(fmrilen < bufsz);
11426         if (deleted)
11427                 warn(emsg_deleted);
11428 }
11429 
11430 /*
11431  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11432  * :statistics) are listed for the current selection.
11433  */
11434 void
11435 lscf_list(const char *pattern)
11436 {
11437         scf_iter_t *iter;
11438         char *buf;
11439         int ret;
11440 
11441         lscf_prep_hndl();
11442 
11443         if (cur_level != NULL) {
11444                 struct snaplevel *elt;
11445 
11446                 (void) fputs(COLON_NAMESPACES, stdout);
11447 
11448                 elt = uu_list_next(cur_levels, cur_elt);
11449                 if (elt == NULL)
11450                         return;
11451 
11452                 /*
11453                  * For now, we know that the next level is an instance.  But
11454                  * if we ever have multiple scopes, this could be complicated.
11455                  */
11456                 buf = safe_malloc(max_scf_name_len + 1);
11457                 if (scf_snaplevel_get_instance_name(elt->sl, buf,
11458                     max_scf_name_len + 1) >= 0) {
11459                         (void) puts(buf);
11460                 } else {
11461                         if (scf_error() != SCF_ERROR_DELETED)
11462                                 scfdie();
11463                 }
11464 
11465                 free(buf);
11466 
11467                 return;
11468         }
11469 
11470         if (cur_inst != NULL) {
11471                 (void) fputs(COLON_NAMESPACES, stdout);
11472                 return;
11473         }
11474 
11475         iter = scf_iter_create(g_hndl);
11476         if (iter == NULL)
11477                 scfdie();
11478 
11479         buf = safe_malloc(max_scf_name_len + 1);
11480 
11481         if (cur_svc != NULL) {
11482                 /* List the instances in this service. */
11483                 scf_instance_t *inst;
11484 
11485                 inst = scf_instance_create(g_hndl);
11486                 if (inst == NULL)
11487                         scfdie();
11488 
11489                 if (scf_iter_service_instances(iter, cur_svc) == 0) {
11490                         safe_printf(COLON_NAMESPACES);
11491 
11492                         for (;;) {
11493                                 ret = scf_iter_next_instance(iter, inst);
11494                                 if (ret == 0)
11495                                         break;
11496                                 if (ret != 1) {
11497                                         if (scf_error() != SCF_ERROR_DELETED)
11498                                                 scfdie();
11499 
11500                                         break;
11501                                 }
11502 
11503                                 if (scf_instance_get_name(inst, buf,
11504                                     max_scf_name_len + 1) >= 0) {
11505                                         if (pattern == NULL ||
11506                                             fnmatch(pattern, buf, 0) == 0)
11507                                                 (void) puts(buf);
11508                                 } else {
11509                                         if (scf_error() != SCF_ERROR_DELETED)
11510                                                 scfdie();
11511                                 }
11512                         }
11513                 } else {
11514                         if (scf_error() != SCF_ERROR_DELETED)
11515                                 scfdie();
11516                 }
11517 
11518                 scf_instance_destroy(inst);
11519         } else {
11520                 /* List the services in this scope. */
11521                 scf_service_t *svc;
11522 
11523                 assert(cur_scope != NULL);
11524 
11525                 svc = scf_service_create(g_hndl);
11526                 if (svc == NULL)
11527                         scfdie();
11528 
11529                 if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11530                         scfdie();
11531 
11532                 for (;;) {
11533                         ret = scf_iter_next_service(iter, svc);
11534                         if (ret == 0)
11535                                 break;
11536                         if (ret != 1)
11537                                 scfdie();
11538 
11539                         if (scf_service_get_name(svc, buf,
11540                             max_scf_name_len + 1) >= 0) {
11541                                 if (pattern == NULL ||
11542                                     fnmatch(pattern, buf, 0) == 0)
11543                                         safe_printf("%s\n", buf);
11544                         } else {
11545                                 if (scf_error() != SCF_ERROR_DELETED)
11546                                         scfdie();
11547                         }
11548                 }
11549 
11550                 scf_service_destroy(svc);
11551         }
11552 
11553         free(buf);
11554         scf_iter_destroy(iter);
11555 }
11556 
11557 /*
11558  * Entity addition.  Creates an empty entity in the current selection.
11559  */
11560 void
11561 lscf_add(const char *name)
11562 {
11563         lscf_prep_hndl();
11564 
11565         if (cur_snap != NULL) {
11566                 semerr(emsg_cant_modify_snapshots);
11567         } else if (cur_inst != NULL) {
11568                 semerr(gettext("Cannot add entities to an instance.\n"));
11569         } else if (cur_svc != NULL) {
11570 
11571                 if (scf_service_add_instance(cur_svc, name, NULL) !=
11572                     SCF_SUCCESS) {
11573                         switch (scf_error()) {
11574                         case SCF_ERROR_INVALID_ARGUMENT:
11575                                 semerr(gettext("Invalid name.\n"));
11576                                 break;
11577 
11578                         case SCF_ERROR_EXISTS:
11579                                 semerr(gettext("Instance already exists.\n"));
11580                                 break;
11581 
11582                         case SCF_ERROR_PERMISSION_DENIED:
11583                                 semerr(emsg_permission_denied);
11584                                 break;
11585 
11586                         default:
11587                                 scfdie();
11588                         }
11589                 }
11590         } else {
11591                 assert(cur_scope != NULL);
11592 
11593                 if (scf_scope_add_service(cur_scope, name, NULL) !=
11594                     SCF_SUCCESS) {
11595                         switch (scf_error()) {
11596                         case SCF_ERROR_INVALID_ARGUMENT:
11597                                 semerr(gettext("Invalid name.\n"));
11598                                 break;
11599 
11600                         case SCF_ERROR_EXISTS:
11601                                 semerr(gettext("Service already exists.\n"));
11602                                 break;
11603 
11604                         case SCF_ERROR_PERMISSION_DENIED:
11605                                 semerr(emsg_permission_denied);
11606                                 break;
11607 
11608                         case SCF_ERROR_BACKEND_READONLY:
11609                                 semerr(emsg_read_only);
11610                                 break;
11611 
11612                         default:
11613                                 scfdie();
11614                         }
11615                 }
11616         }
11617 }
11618 
11619 /* return 1 if the entity has no persistent pgs, else return 0 */
11620 static int
11621 entity_has_no_pgs(void *ent, int isservice)
11622 {
11623         scf_iter_t *iter = NULL;
11624         scf_propertygroup_t *pg = NULL;
11625         uint32_t flags;
11626         int err;
11627         int ret = 1;
11628 
11629         if ((iter = scf_iter_create(g_hndl)) == NULL ||
11630             (pg = scf_pg_create(g_hndl)) == NULL)
11631                 scfdie();
11632 
11633         if (isservice) {
11634                 if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11635                         scfdie();
11636         } else {
11637                 if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11638                         scfdie();
11639         }
11640 
11641         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11642                 if (scf_pg_get_flags(pg, &flags) != 0)
11643                         scfdie();
11644 
11645                 /* skip nonpersistent pgs */
11646                 if (flags & SCF_PG_FLAG_NONPERSISTENT)
11647                         continue;
11648 
11649                 ret = 0;
11650                 break;
11651         }
11652 
11653         if (err == -1)
11654                 scfdie();
11655 
11656         scf_pg_destroy(pg);
11657         scf_iter_destroy(iter);
11658 
11659         return (ret);
11660 }
11661 
11662 /* return 1 if the service has no instances, else return 0 */
11663 static int
11664 svc_has_no_insts(scf_service_t *svc)
11665 {
11666         scf_instance_t *inst;
11667         scf_iter_t *iter;
11668         int r;
11669         int ret = 1;
11670 
11671         if ((inst = scf_instance_create(g_hndl)) == NULL ||
11672             (iter = scf_iter_create(g_hndl)) == NULL)
11673                 scfdie();
11674 
11675         if (scf_iter_service_instances(iter, svc) != 0)
11676                 scfdie();
11677 
11678         r = scf_iter_next_instance(iter, inst);
11679         if (r == 1) {
11680                 ret = 0;
11681         } else if (r == 0) {
11682                 ret = 1;
11683         } else if (r == -1) {
11684                 scfdie();
11685         } else {
11686                 bad_error("scf_iter_next_instance", r);
11687         }
11688 
11689         scf_iter_destroy(iter);
11690         scf_instance_destroy(inst);
11691 
11692         return (ret);
11693 }
11694 
11695 /*
11696  * Entity deletion.
11697  */
11698 
11699 /*
11700  * Delete the property group <fmri>/:properties/<name>.  Returns
11701  * SCF_ERROR_NONE on success (or if the entity is not found),
11702  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11703  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11704  * denied.
11705  */
11706 static scf_error_t
11707 delete_dependency_pg(const char *fmri, const char *name)
11708 {
11709         void *entity = NULL;
11710         int isservice;
11711         scf_propertygroup_t *pg = NULL;
11712         scf_error_t result;
11713         char *pgty;
11714         scf_service_t *svc = NULL;
11715         scf_instance_t *inst = NULL;
11716         scf_iter_t *iter = NULL;
11717         char *name_buf = NULL;
11718 
11719         result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11720         switch (result) {
11721         case SCF_ERROR_NONE:
11722                 break;
11723 
11724         case SCF_ERROR_NO_MEMORY:
11725                 uu_die(gettext("Out of memory.\n"));
11726                 /* NOTREACHED */
11727 
11728         case SCF_ERROR_INVALID_ARGUMENT:
11729         case SCF_ERROR_CONSTRAINT_VIOLATED:
11730                 return (SCF_ERROR_INVALID_ARGUMENT);
11731 
11732         case SCF_ERROR_NOT_FOUND:
11733                 result = SCF_ERROR_NONE;
11734                 goto out;
11735 
11736         default:
11737                 bad_error("fmri_to_entity", result);
11738         }
11739 
11740         pg = scf_pg_create(g_hndl);
11741         if (pg == NULL)
11742                 scfdie();
11743 
11744         if (entity_get_pg(entity, isservice, name, pg) != 0) {
11745                 if (scf_error() != SCF_ERROR_NOT_FOUND)
11746                         scfdie();
11747 
11748                 result = SCF_ERROR_NONE;
11749                 goto out;
11750         }
11751 
11752         pgty = safe_malloc(max_scf_pg_type_len + 1);
11753 
11754         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11755                 scfdie();
11756 
11757         if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
11758                 result = SCF_ERROR_TYPE_MISMATCH;
11759                 free(pgty);
11760                 goto out;
11761         }
11762 
11763         free(pgty);
11764 
11765         if (scf_pg_delete(pg) != 0) {
11766                 result = scf_error();
11767                 if (result != SCF_ERROR_PERMISSION_DENIED)
11768                         scfdie();
11769                 goto out;
11770         }
11771 
11772         /*
11773          * We have to handle the case where we've just deleted the last
11774          * property group of a "dummy" entity (instance or service).
11775          * A "dummy" entity is an entity only present to hold an
11776          * external dependency.
11777          * So, in the case we deleted the last property group then we
11778          * can also delete the entity. If the entity is an instance then
11779          * we must verify if this was the last instance for the service
11780          * and if it is, we can also delete the service if it doesn't
11781          * have any property group either.
11782          */
11783 
11784         result = SCF_ERROR_NONE;
11785 
11786         if (isservice) {
11787                 svc = (scf_service_t *)entity;
11788 
11789                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
11790                     (iter = scf_iter_create(g_hndl)) == NULL)
11791                         scfdie();
11792 
11793                 name_buf = safe_malloc(max_scf_name_len + 1);
11794         } else {
11795                 inst = (scf_instance_t *)entity;
11796         }
11797 
11798         /*
11799          * If the entity is an instance and we've just deleted its last
11800          * property group then we should delete it.
11801          */
11802         if (!isservice && entity_has_no_pgs(entity, isservice)) {
11803                 /* find the service before deleting the inst. - needed later */
11804                 if ((svc = scf_service_create(g_hndl)) == NULL)
11805                         scfdie();
11806 
11807                 if (scf_instance_get_parent(inst, svc) != 0)
11808                         scfdie();
11809 
11810                 /* delete the instance */
11811                 if (scf_instance_delete(inst) != 0) {
11812                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11813                                 scfdie();
11814 
11815                         result = SCF_ERROR_PERMISSION_DENIED;
11816                         goto out;
11817                 }
11818                 /* no need to refresh the instance */
11819                 inst = NULL;
11820         }
11821 
11822         /*
11823          * If the service has no more instances and pgs or we just deleted the
11824          * last instance and the service doesn't have anymore propery groups
11825          * then the service should be deleted.
11826          */
11827         if (svc != NULL &&
11828             svc_has_no_insts(svc) &&
11829             entity_has_no_pgs((void *)svc, 1)) {
11830                 if (scf_service_delete(svc) == 0) {
11831                         if (isservice) {
11832                                 /* no need to refresh the service */
11833                                 svc = NULL;
11834                         }
11835 
11836                         goto out;
11837                 }
11838 
11839                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11840                         scfdie();
11841 
11842                 result = SCF_ERROR_PERMISSION_DENIED;
11843         }
11844 
11845         /* if the entity has not been deleted, refresh it */
11846         if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
11847                 (void) refresh_entity(isservice, entity, fmri, inst, iter,
11848                     name_buf);
11849         }
11850 
11851 out:
11852         if (isservice && (inst != NULL && iter != NULL)) {
11853                 free(name_buf);
11854                 scf_iter_destroy(iter);
11855                 scf_instance_destroy(inst);
11856         }
11857 
11858         if (!isservice && svc != NULL) {
11859                 scf_service_destroy(svc);
11860         }
11861 
11862         scf_pg_destroy(pg);
11863         if (entity != NULL)
11864                 entity_destroy(entity, isservice);
11865 
11866         return (result);
11867 }
11868 
11869 static int
11870 delete_dependents(scf_propertygroup_t *pg)
11871 {
11872         char *pgty, *name, *fmri;
11873         scf_property_t *prop;
11874         scf_value_t *val;
11875         scf_iter_t *iter;
11876         int r;
11877         scf_error_t err;
11878 
11879         /* Verify that the pg has the correct type. */
11880         pgty = safe_malloc(max_scf_pg_type_len + 1);
11881         if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11882                 scfdie();
11883 
11884         if (strcmp(pgty, scf_group_framework) != 0) {
11885                 if (g_verbose) {
11886                         fmri = safe_malloc(max_scf_fmri_len + 1);
11887                         if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
11888                                 scfdie();
11889 
11890                         warn(gettext("Property group %s is not of expected "
11891                             "type %s.\n"), fmri, scf_group_framework);
11892 
11893                         free(fmri);
11894                 }
11895 
11896                 free(pgty);
11897                 return (-1);
11898         }
11899 
11900         free(pgty);
11901 
11902         /* map delete_dependency_pg onto the properties. */
11903         if ((prop = scf_property_create(g_hndl)) == NULL ||
11904             (val = scf_value_create(g_hndl)) == NULL ||
11905             (iter = scf_iter_create(g_hndl)) == NULL)
11906                 scfdie();
11907 
11908         if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
11909                 scfdie();
11910 
11911         name = safe_malloc(max_scf_name_len + 1);
11912         fmri = safe_malloc(max_scf_fmri_len + 2);
11913 
11914         while ((r = scf_iter_next_property(iter, prop)) == 1) {
11915                 scf_type_t ty;
11916 
11917                 if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
11918                         scfdie();
11919 
11920                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11921                         scfdie();
11922 
11923                 if ((ty != SCF_TYPE_ASTRING &&
11924                     prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
11925                     prop_get_val(prop, val) != 0)
11926                         continue;
11927 
11928                 if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
11929                         scfdie();
11930 
11931                 err = delete_dependency_pg(fmri, name);
11932                 if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
11933                         if (scf_property_to_fmri(prop, fmri,
11934                             max_scf_fmri_len + 2) < 0)
11935                                 scfdie();
11936 
11937                         warn(gettext("Value of %s is not a valid FMRI.\n"),
11938                             fmri);
11939                 } else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
11940                         warn(gettext("Property group \"%s\" of entity \"%s\" "
11941                             "does not have dependency type.\n"), name, fmri);
11942                 } else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
11943                         warn(gettext("Could not delete property group \"%s\" "
11944                             "of entity \"%s\" (permission denied).\n"), name,
11945                             fmri);
11946                 }
11947         }
11948         if (r == -1)
11949                 scfdie();
11950 
11951         scf_value_destroy(val);
11952         scf_property_destroy(prop);
11953 
11954         return (0);
11955 }
11956 
11957 /*
11958  * Returns 1 if the instance may be running, and 0 otherwise.
11959  */
11960 static int
11961 inst_is_running(scf_instance_t *inst)
11962 {
11963         scf_propertygroup_t *pg;
11964         scf_property_t *prop;
11965         scf_value_t *val;
11966         char buf[MAX_SCF_STATE_STRING_SZ];
11967         int ret = 0;
11968         ssize_t szret;
11969 
11970         if ((pg = scf_pg_create(g_hndl)) == NULL ||
11971             (prop = scf_property_create(g_hndl)) == NULL ||
11972             (val = scf_value_create(g_hndl)) == NULL)
11973                 scfdie();
11974 
11975         if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
11976                 if (scf_error() != SCF_ERROR_NOT_FOUND)
11977                         scfdie();
11978                 goto out;
11979         }
11980 
11981         if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
11982             prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
11983             prop_get_val(prop, val) != 0)
11984                 goto out;
11985 
11986         szret = scf_value_get_astring(val, buf, sizeof (buf));
11987         assert(szret >= 0);
11988 
11989         ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11990             strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11991 
11992 out:
11993         scf_value_destroy(val);
11994         scf_property_destroy(prop);
11995         scf_pg_destroy(pg);
11996         return (ret);
11997 }
11998 
11999 static uint8_t
12000 pg_is_external_dependency(scf_propertygroup_t *pg)
12001 {
12002         char *type;
12003         scf_value_t *val;
12004         scf_property_t *prop;
12005         uint8_t b = B_FALSE;
12006 
12007         type = safe_malloc(max_scf_pg_type_len + 1);
12008 
12009         if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12010                 scfdie();
12011 
12012         if ((prop = scf_property_create(g_hndl)) == NULL ||
12013             (val = scf_value_create(g_hndl)) == NULL)
12014                 scfdie();
12015 
12016         if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12017                 if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12018                         if (scf_property_get_value(prop, val) != 0)
12019                                 scfdie();
12020                         if (scf_value_get_boolean(val, &b) != 0)
12021                                 scfdie();
12022                 }
12023         }
12024 
12025         free(type);
12026         (void) scf_value_destroy(val);
12027         (void) scf_property_destroy(prop);
12028 
12029         return (b);
12030 }
12031 
12032 #define DELETE_FAILURE                  -1
12033 #define DELETE_SUCCESS_NOEXTDEPS        0
12034 #define DELETE_SUCCESS_EXTDEPS          1
12035 
12036 /*
12037  * lscf_instance_delete() deletes an instance.  Before calling
12038  * scf_instance_delete(), though, we make sure the instance isn't
12039  * running and delete dependencies in other entities which the instance
12040  * declared as "dependents".  If there are dependencies which were
12041  * created for other entities, then instead of deleting the instance we
12042  * make it "empty" by deleting all other property groups and all
12043  * snapshots.
12044  *
12045  * lscf_instance_delete() verifies that there is no external dependency pgs
12046  * before suppressing the instance. If there is, then we must not remove them
12047  * now in case the instance is re-created otherwise the dependencies would be
12048  * lost. The external dependency pgs will be removed if the dependencies are
12049  * removed.
12050  *
12051  * Returns:
12052  *  DELETE_FAILURE              on failure
12053  *  DELETE_SUCCESS_NOEXTDEPS    on success - no external dependencies
12054  *  DELETE_SUCCESS_EXTDEPS      on success - external dependencies
12055  */
12056 static int
12057 lscf_instance_delete(scf_instance_t *inst, int force)
12058 {
12059         scf_propertygroup_t *pg;
12060         scf_snapshot_t *snap;
12061         scf_iter_t *iter;
12062         int err;
12063         int external = 0;
12064 
12065         /* If we're not forcing and the instance is running, refuse. */
12066         if (!force && inst_is_running(inst)) {
12067                 char *fmri;
12068 
12069                 fmri = safe_malloc(max_scf_fmri_len + 1);
12070 
12071                 if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12072                         scfdie();
12073 
12074                 semerr(gettext("Instance %s may be running.  "
12075                     "Use delete -f if it is not.\n"), fmri);
12076 
12077                 free(fmri);
12078                 return (DELETE_FAILURE);
12079         }
12080 
12081         pg = scf_pg_create(g_hndl);
12082         if (pg == NULL)
12083                 scfdie();
12084 
12085         if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12086                 (void) delete_dependents(pg);
12087         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12088                 scfdie();
12089 
12090         scf_pg_destroy(pg);
12091 
12092         /*
12093          * If the instance has some external dependencies then we must
12094          * keep them in case the instance is reimported otherwise the
12095          * dependencies would be lost on reimport.
12096          */
12097         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12098             (pg = scf_pg_create(g_hndl)) == NULL)
12099                 scfdie();
12100 
12101         if (scf_iter_instance_pgs(iter, inst) < 0)
12102                 scfdie();
12103 
12104         while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12105                 if (pg_is_external_dependency(pg)) {
12106                         external = 1;
12107                         continue;
12108                 }
12109 
12110                 if (scf_pg_delete(pg) != 0) {
12111                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12112                                 scfdie();
12113                         else {
12114                                 semerr(emsg_permission_denied);
12115 
12116                                 (void) scf_iter_destroy(iter);
12117                                 (void) scf_pg_destroy(pg);
12118                                 return (DELETE_FAILURE);
12119                         }
12120                 }
12121         }
12122 
12123         if (err == -1)
12124                 scfdie();
12125 
12126         (void) scf_iter_destroy(iter);
12127         (void) scf_pg_destroy(pg);
12128 
12129         if (external) {
12130                 /*
12131                  * All the pgs have been deleted for the instance except
12132                  * the ones holding the external dependencies.
12133                  * For the job to be complete, we must also delete the
12134                  * snapshots associated with the instance.
12135                  */
12136                 if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12137                     NULL)
12138                         scfdie();
12139                 if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12140                         scfdie();
12141 
12142                 if (scf_iter_instance_snapshots(iter, inst) == -1)
12143                         scfdie();
12144 
12145                 while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12146                         if (_scf_snapshot_delete(snap) != 0) {
12147                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12148                                         scfdie();
12149 
12150                                 semerr(emsg_permission_denied);
12151 
12152                                 (void) scf_iter_destroy(iter);
12153                                 (void) scf_snapshot_destroy(snap);
12154                                 return (DELETE_FAILURE);
12155                         }
12156                 }
12157 
12158                 if (err == -1)
12159                         scfdie();
12160 
12161                 (void) scf_iter_destroy(iter);
12162                 (void) scf_snapshot_destroy(snap);
12163                 return (DELETE_SUCCESS_EXTDEPS);
12164         }
12165 
12166         if (scf_instance_delete(inst) != 0) {
12167                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12168                         scfdie();
12169 
12170                 semerr(emsg_permission_denied);
12171 
12172                 return (DELETE_FAILURE);
12173         }
12174 
12175         return (DELETE_SUCCESS_NOEXTDEPS);
12176 }
12177 
12178 /*
12179  * lscf_service_delete() deletes a service.  Before calling
12180  * scf_service_delete(), though, we call lscf_instance_delete() for
12181  * each of the instances and delete dependencies in other entities
12182  * which were created as "dependents" of this service.  If there are
12183  * dependencies which were created for other entities, then we delete
12184  * all other property groups in the service and leave it as "empty".
12185  *
12186  * lscf_service_delete() verifies that there is no external dependency
12187  * pgs at the instance & service level before suppressing the service.
12188  * If there is, then we must not remove them now in case the service
12189  * is re-imported otherwise the dependencies would be lost. The external
12190  * dependency pgs will be removed if the dependencies are removed.
12191  *
12192  * Returns:
12193  *   DELETE_FAILURE             on failure
12194  *   DELETE_SUCCESS_NOEXTDEPS   on success - no external dependencies
12195  *   DELETE_SUCCESS_EXTDEPS     on success - external dependencies
12196  */
12197 static int
12198 lscf_service_delete(scf_service_t *svc, int force)
12199 {
12200         int r;
12201         scf_instance_t *inst;
12202         scf_propertygroup_t *pg;
12203         scf_iter_t *iter;
12204         int ret;
12205         int external = 0;
12206 
12207         if ((inst = scf_instance_create(g_hndl)) == NULL ||
12208             (pg = scf_pg_create(g_hndl)) == NULL ||
12209             (iter = scf_iter_create(g_hndl)) == NULL)
12210                 scfdie();
12211 
12212         if (scf_iter_service_instances(iter, svc) != 0)
12213                 scfdie();
12214 
12215         for (r = scf_iter_next_instance(iter, inst);
12216             r == 1;
12217             r = scf_iter_next_instance(iter, inst)) {
12218 
12219                 ret = lscf_instance_delete(inst, force);
12220                 if (ret == DELETE_FAILURE) {
12221                         scf_iter_destroy(iter);
12222                         scf_pg_destroy(pg);
12223                         scf_instance_destroy(inst);
12224                         return (DELETE_FAILURE);
12225                 }
12226 
12227                 /*
12228                  * Record the fact that there is some external dependencies
12229                  * at the instance level.
12230                  */
12231                 if (ret == DELETE_SUCCESS_EXTDEPS)
12232                         external |= 1;
12233         }
12234 
12235         if (r != 0)
12236                 scfdie();
12237 
12238         /* Delete dependency property groups in dependent services. */
12239         if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12240                 (void) delete_dependents(pg);
12241         else if (scf_error() != SCF_ERROR_NOT_FOUND)
12242                 scfdie();
12243 
12244         scf_iter_destroy(iter);
12245         scf_pg_destroy(pg);
12246         scf_instance_destroy(inst);
12247 
12248         /*
12249          * If the service has some external dependencies then we don't
12250          * want to remove them in case the service is re-imported.
12251          */
12252         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12253             (iter = scf_iter_create(g_hndl)) == NULL)
12254                 scfdie();
12255 
12256         if (scf_iter_service_pgs(iter, svc) < 0)
12257                 scfdie();
12258 
12259         while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12260                 if (pg_is_external_dependency(pg)) {
12261                         external |= 2;
12262                         continue;
12263                 }
12264 
12265                 if (scf_pg_delete(pg) != 0) {
12266                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12267                                 scfdie();
12268                         else {
12269                                 semerr(emsg_permission_denied);
12270 
12271                                 (void) scf_iter_destroy(iter);
12272                                 (void) scf_pg_destroy(pg);
12273                                 return (DELETE_FAILURE);
12274                         }
12275                 }
12276         }
12277 
12278         if (r == -1)
12279                 scfdie();
12280 
12281         (void) scf_iter_destroy(iter);
12282         (void) scf_pg_destroy(pg);
12283 
12284         if (external != 0)
12285                 return (DELETE_SUCCESS_EXTDEPS);
12286 
12287         if (scf_service_delete(svc) == 0)
12288                 return (DELETE_SUCCESS_NOEXTDEPS);
12289 
12290         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12291                 scfdie();
12292 
12293         semerr(emsg_permission_denied);
12294         return (DELETE_FAILURE);
12295 }
12296 
12297 static int
12298 delete_callback(void *data, scf_walkinfo_t *wip)
12299 {
12300         int force = (int)data;
12301 
12302         if (wip->inst != NULL)
12303                 (void) lscf_instance_delete(wip->inst, force);
12304         else
12305                 (void) lscf_service_delete(wip->svc, force);
12306 
12307         return (0);
12308 }
12309 
12310 void
12311 lscf_delete(const char *fmri, int force)
12312 {
12313         scf_service_t *svc;
12314         scf_instance_t *inst;
12315         int ret;
12316 
12317         lscf_prep_hndl();
12318 
12319         if (cur_snap != NULL) {
12320                 if (!snaplevel_is_instance(cur_level)) {
12321                         char *buf;
12322 
12323                         buf = safe_malloc(max_scf_name_len + 1);
12324                         if (scf_instance_get_name(cur_inst, buf,
12325                             max_scf_name_len + 1) >= 0) {
12326                                 if (strcmp(buf, fmri) == 0) {
12327                                         semerr(emsg_cant_modify_snapshots);
12328                                         free(buf);
12329                                         return;
12330                                 }
12331                         } else if (scf_error() != SCF_ERROR_DELETED) {
12332                                 scfdie();
12333                         }
12334                         free(buf);
12335                 }
12336         } else if (cur_inst != NULL) {
12337                 /* EMPTY */;
12338         } else if (cur_svc != NULL) {
12339                 inst = scf_instance_create(g_hndl);
12340                 if (inst == NULL)
12341                         scfdie();
12342 
12343                 if (scf_service_get_instance(cur_svc, fmri, inst) ==
12344                     SCF_SUCCESS) {
12345                         (void) lscf_instance_delete(inst, force);
12346                         scf_instance_destroy(inst);
12347                         return;
12348                 }
12349 
12350                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12351                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12352                         scfdie();
12353 
12354                 scf_instance_destroy(inst);
12355         } else {
12356                 assert(cur_scope != NULL);
12357 
12358                 svc = scf_service_create(g_hndl);
12359                 if (svc == NULL)
12360                         scfdie();
12361 
12362                 if (scf_scope_get_service(cur_scope, fmri, svc) ==
12363                     SCF_SUCCESS) {
12364                         (void) lscf_service_delete(svc, force);
12365                         scf_service_destroy(svc);
12366                         return;
12367                 }
12368 
12369                 if (scf_error() != SCF_ERROR_NOT_FOUND &&
12370                     scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12371                         scfdie();
12372 
12373                 scf_service_destroy(svc);
12374         }
12375 
12376         /*
12377          * Match FMRI to entity.
12378          */
12379         if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12380             delete_callback, (void *)force, NULL, semerr)) != 0) {
12381                 semerr(gettext("Failed to walk instances: %s\n"),
12382                     scf_strerror(ret));
12383         }
12384 }
12385 
12386 
12387 
12388 /*
12389  * :properties commands.  These all end with "pg" or "prop" and generally
12390  * operate on the currently selected entity.
12391  */
12392 
12393 /*
12394  * Property listing.  List the property groups, properties, their types and
12395  * their values for the currently selected entity.
12396  */
12397 static void
12398 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12399 {
12400         char *buf;
12401         uint32_t flags;
12402 
12403         buf = safe_malloc(max_scf_pg_type_len + 1);
12404 
12405         if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12406                 scfdie();
12407 
12408         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12409                 scfdie();
12410 
12411         safe_printf("%-*s  %s", namewidth, name, buf);
12412 
12413         if (flags & SCF_PG_FLAG_NONPERSISTENT)
12414                 safe_printf("\tNONPERSISTENT");
12415 
12416         safe_printf("\n");
12417 
12418         free(buf);
12419 }
12420 
12421 static boolean_t
12422 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12423 {
12424         if (scf_property_get_value(prop, val) == 0) {
12425                 return (B_FALSE);
12426         } else {
12427                 switch (scf_error()) {
12428                 case SCF_ERROR_NOT_FOUND:
12429                         return (B_FALSE);
12430                 case SCF_ERROR_PERMISSION_DENIED:
12431                 case SCF_ERROR_CONSTRAINT_VIOLATED:
12432                         return (B_TRUE);
12433                 default:
12434                         scfdie();
12435                         /*NOTREACHED*/
12436                 }
12437         }
12438 }
12439 
12440 static void
12441 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12442 {
12443         scf_iter_t *iter;
12444         scf_value_t *val;
12445         const char *type;
12446         int multiple_strings = 0;
12447         int ret;
12448 
12449         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12450             (val = scf_value_create(g_hndl)) == NULL)
12451                 scfdie();
12452 
12453         type = prop_to_typestr(prop);
12454         assert(type != NULL);
12455 
12456         safe_printf("%-*s  %-7s ", len, name, type);
12457 
12458         if (prop_has_multiple_values(prop, val) &&
12459             (scf_value_type(val) == SCF_TYPE_ASTRING ||
12460             scf_value_type(val) == SCF_TYPE_USTRING))
12461                 multiple_strings = 1;
12462 
12463         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12464                 scfdie();
12465 
12466         while ((ret = scf_iter_next_value(iter, val)) == 1) {
12467                 char *buf;
12468                 ssize_t vlen, szret;
12469 
12470                 vlen = scf_value_get_as_string(val, NULL, 0);
12471                 if (vlen < 0)
12472                         scfdie();
12473 
12474                 buf = safe_malloc(vlen + 1);
12475 
12476                 szret = scf_value_get_as_string(val, buf, vlen + 1);
12477                 if (szret < 0)
12478                         scfdie();
12479                 assert(szret <= vlen);
12480 
12481                 /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12482                 if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12483                         safe_printf(" \"");
12484                         (void) quote_and_print(buf, stdout, 0);
12485                         (void) putchar('"');
12486                         if (ferror(stdout)) {
12487                                 (void) putchar('\n');
12488                                 uu_die(gettext("Error writing to stdout.\n"));
12489                         }
12490                 } else {
12491                         safe_printf(" %s", buf);
12492                 }
12493 
12494                 free(buf);
12495         }
12496         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12497                 scfdie();
12498 
12499         if (putchar('\n') != '\n')
12500                 uu_die(gettext("Could not output newline"));
12501 }
12502 
12503 /*
12504  * Outputs template property group info for the describe subcommand.
12505  * If 'templates' == 2, verbose output is printed in the format expected
12506  * for describe -v, which includes all templates fields.  If pg is
12507  * not NULL, we're describing the template data, not an existing property
12508  * group, and formatting should be appropriate for describe -t.
12509  */
12510 static void
12511 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12512 {
12513         char *buf;
12514         uint8_t required;
12515         scf_property_t *stability_prop;
12516         scf_value_t *stability_val;
12517 
12518         if (templates == 0)
12519                 return;
12520 
12521         if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12522             (stability_val = scf_value_create(g_hndl)) == NULL)
12523                 scfdie();
12524 
12525         if (templates == 2 && pg != NULL) {
12526                 if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12527                     stability_prop) == 0) {
12528                         if (prop_check_type(stability_prop,
12529                             SCF_TYPE_ASTRING) == 0 &&
12530                             prop_get_val(stability_prop, stability_val) == 0) {
12531                                 char *stability;
12532 
12533                                 stability = safe_malloc(max_scf_value_len + 1);
12534 
12535                                 if (scf_value_get_astring(stability_val,
12536                                     stability, max_scf_value_len + 1) == -1 &&
12537                                     scf_error() != SCF_ERROR_NOT_FOUND)
12538                                         scfdie();
12539 
12540                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
12541                                     gettext("stability"), stability);
12542 
12543                                 free(stability);
12544                         }
12545                 } else if (scf_error() != SCF_ERROR_NOT_FOUND)
12546                         scfdie();
12547         }
12548 
12549         scf_property_destroy(stability_prop);
12550         scf_value_destroy(stability_val);
12551 
12552         if (pgt == NULL)
12553                 return;
12554 
12555         if (pg == NULL || templates == 2) {
12556                 /* print type info only if scf_tmpl_pg_name succeeds */
12557                 if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12558                         if (pg != NULL)
12559                                 safe_printf("%s", TMPL_INDENT);
12560                         safe_printf("%s: ", gettext("name"));
12561                         safe_printf("%s\n", buf);
12562                         free(buf);
12563                 }
12564 
12565                 /* print type info only if scf_tmpl_pg_type succeeds */
12566                 if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12567                         if (pg != NULL)
12568                                 safe_printf("%s", TMPL_INDENT);
12569                         safe_printf("%s: ", gettext("type"));
12570                         safe_printf("%s\n", buf);
12571                         free(buf);
12572                 }
12573         }
12574 
12575         if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12576                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12577                     required ? "true" : "false");
12578 
12579         if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12580                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12581                     buf);
12582                 free(buf);
12583         }
12584 
12585         if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12586                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12587                     buf);
12588                 free(buf);
12589         }
12590 
12591         if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12592                 if (templates == 2)
12593                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12594                             gettext("description"), buf);
12595                 else
12596                         safe_printf("%s%s\n", TMPL_INDENT, buf);
12597                 free(buf);
12598         }
12599 
12600 }
12601 
12602 /*
12603  * With as_value set to true, indent as appropriate for the value level.
12604  * If false, indent to appropriate level for inclusion in constraint
12605  * or choice printout.
12606  */
12607 static void
12608 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12609     int as_value)
12610 {
12611         char *buf;
12612 
12613         if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12614                 if (as_value == 0)
12615                         safe_printf("%s", TMPL_CHOICE_INDENT);
12616                 else
12617                         safe_printf("%s", TMPL_INDENT);
12618                 safe_printf("%s: %s\n", gettext("value common name"), buf);
12619                 free(buf);
12620         }
12621 
12622         if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12623                 if (as_value == 0)
12624                         safe_printf("%s", TMPL_CHOICE_INDENT);
12625                 else
12626                         safe_printf("%s", TMPL_INDENT);
12627                 safe_printf("%s: %s\n", gettext("value description"), buf);
12628                 free(buf);
12629         }
12630 }
12631 
12632 static void
12633 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12634 {
12635         safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12636         /* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12637         safe_printf("%s\n", val_buf);
12638 
12639         print_template_value_details(prt, val_buf, 1);
12640 }
12641 
12642 static void
12643 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12644 {
12645         int i, printed = 0;
12646         scf_values_t values;
12647         scf_count_ranges_t c_ranges;
12648         scf_int_ranges_t i_ranges;
12649 
12650         printed = 0;
12651         i = 0;
12652         if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12653                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12654                     gettext("value constraints"));
12655                 printed++;
12656                 for (i = 0; i < values.value_count; ++i) {
12657                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12658                             gettext("value name"), values.values_as_strings[i]);
12659                         if (verbose == 1)
12660                                 print_template_value_details(prt,
12661                                     values.values_as_strings[i], 0);
12662                 }
12663 
12664                 scf_values_destroy(&values);
12665         }
12666 
12667         if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12668                 if (printed++ == 0)
12669                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12670                             gettext("value constraints"));
12671                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12672                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12673                             gettext("range"), c_ranges.scr_min[i],
12674                             c_ranges.scr_max[i]);
12675                 }
12676                 scf_count_ranges_destroy(&c_ranges);
12677         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12678             scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12679                 if (printed++ == 0)
12680                         safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12681                             gettext("value constraints"));
12682                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12683                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12684                             gettext("range"), i_ranges.sir_min[i],
12685                             i_ranges.sir_max[i]);
12686                 }
12687                 scf_int_ranges_destroy(&i_ranges);
12688         }
12689 }
12690 
12691 static void
12692 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12693 {
12694         int i = 0, printed = 0;
12695         scf_values_t values;
12696         scf_count_ranges_t c_ranges;
12697         scf_int_ranges_t i_ranges;
12698 
12699         printed = 0;
12700         if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12701                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12702                     gettext("value constraints"));
12703                 printed++;
12704                 for (i = 0; i < values.value_count; i++) {
12705                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12706                             gettext("value name"), values.values_as_strings[i]);
12707                         if (verbose == 1)
12708                                 print_template_value_details(prt,
12709                                     values.values_as_strings[i], 0);
12710                 }
12711 
12712                 scf_values_destroy(&values);
12713         }
12714 
12715         if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12716                 for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12717                         if (printed++ == 0)
12718                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12719                                     gettext("value choices"));
12720                         safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12721                             gettext("range"), c_ranges.scr_min[i],
12722                             c_ranges.scr_max[i]);
12723                 }
12724                 scf_count_ranges_destroy(&c_ranges);
12725         } else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12726             scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12727                 for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12728                         if (printed++ == 0)
12729                                 safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12730                                     gettext("value choices"));
12731                         safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12732                             gettext("range"), i_ranges.sir_min[i],
12733                             i_ranges.sir_max[i]);
12734                 }
12735                 scf_int_ranges_destroy(&i_ranges);
12736         }
12737 }
12738 
12739 static void
12740 list_values_by_template(scf_prop_tmpl_t *prt)
12741 {
12742         print_template_constraints(prt, 1);
12743         print_template_choices(prt, 1);
12744 }
12745 
12746 static void
12747 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
12748 {
12749         char *val_buf;
12750         scf_iter_t *iter;
12751         scf_value_t *val;
12752         int ret;
12753 
12754         if ((iter = scf_iter_create(g_hndl)) == NULL ||
12755             (val = scf_value_create(g_hndl)) == NULL)
12756                 scfdie();
12757 
12758         if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12759                 scfdie();
12760 
12761         val_buf = safe_malloc(max_scf_value_len + 1);
12762 
12763         while ((ret = scf_iter_next_value(iter, val)) == 1) {
12764                 if (scf_value_get_as_string(val, val_buf,
12765                     max_scf_value_len + 1) < 0)
12766                         scfdie();
12767 
12768                 print_template_value(prt, val_buf);
12769         }
12770         if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12771                 scfdie();
12772         free(val_buf);
12773 
12774         print_template_constraints(prt, 0);
12775         print_template_choices(prt, 0);
12776 
12777 }
12778 
12779 /*
12780  * Outputs property info for the describe subcommand
12781  * Verbose output if templates == 2, -v option of svccfg describe
12782  * Displays template data if prop is not NULL, -t option of svccfg describe
12783  */
12784 static void
12785 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
12786 {
12787         char *buf;
12788         uint8_t u_buf;
12789         int i;
12790         uint64_t min, max;
12791         scf_values_t values;
12792 
12793         if (prt == NULL || templates == 0)
12794                 return;
12795 
12796         if (prop == NULL) {
12797                 safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
12798                 if (scf_tmpl_prop_name(prt, &buf) > 0) {
12799                         safe_printf("%s\n", buf);
12800                         free(buf);
12801                 } else
12802                         safe_printf("(%s)\n", gettext("any"));
12803         }
12804 
12805         if (prop == NULL || templates == 2) {
12806                 if (prop != NULL)
12807                         safe_printf("%s", TMPL_INDENT);
12808                 else
12809                         safe_printf("%s", TMPL_VALUE_INDENT);
12810                 safe_printf("%s: ", gettext("type"));
12811                 if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
12812                         safe_printf("%s\n", buf);
12813                         free(buf);
12814                 } else
12815                         safe_printf("(%s)\n", gettext("any"));
12816         }
12817 
12818         if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
12819                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12820                     u_buf ? "true" : "false");
12821 
12822         if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
12823                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12824                     buf);
12825                 free(buf);
12826         }
12827 
12828         if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
12829                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
12830                     buf);
12831                 free(buf);
12832         }
12833 
12834         if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
12835                 safe_printf("%s%s\n", TMPL_INDENT, buf);
12836                 free(buf);
12837         }
12838 
12839         if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
12840                 safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
12841                     scf_tmpl_visibility_to_string(u_buf));
12842 
12843         if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
12844                 safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12845                     gettext("minimum number of values"), min);
12846                 if (max == ULLONG_MAX) {
12847                         safe_printf("%s%s: %s\n", TMPL_INDENT,
12848                             gettext("maximum number of values"),
12849                             gettext("unlimited"));
12850                 } else {
12851                         safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12852                             gettext("maximum number of values"), max);
12853                 }
12854         }
12855 
12856         if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
12857                 for (i = 0; i < values.value_count; i++) {
12858                         if (i == 0) {
12859                                 safe_printf("%s%s:", TMPL_INDENT,
12860                                     gettext("internal separators"));
12861                         }
12862                         safe_printf(" \"%s\"", values.values_as_strings[i]);
12863                 }
12864                 safe_printf("\n");
12865         }
12866 
12867         if (templates != 2)
12868                 return;
12869 
12870         if (prop != NULL)
12871                 list_values_tmpl(prt, prop);
12872         else
12873                 list_values_by_template(prt);
12874 }
12875 
12876 static char *
12877 read_astring(scf_propertygroup_t *pg, const char *prop_name)
12878 {
12879         char *rv;
12880 
12881         rv = _scf_read_single_astring_from_pg(pg, prop_name);
12882         if (rv == NULL) {
12883                 switch (scf_error()) {
12884                 case SCF_ERROR_NOT_FOUND:
12885                         break;
12886                 default:
12887                         scfdie();
12888                 }
12889         }
12890         return (rv);
12891 }
12892 
12893 static void
12894 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
12895 {
12896         size_t doc_len;
12897         size_t man_len;
12898         char *pg_name;
12899         char *text = NULL;
12900         int rv;
12901 
12902         doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
12903         man_len = strlen(SCF_PG_TM_MAN_PREFIX);
12904         pg_name = safe_malloc(max_scf_name_len + 1);
12905         while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
12906                 if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
12907                         scfdie();
12908                 }
12909                 if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
12910                         /* Display doc_link and and uri */
12911                         safe_printf("%s%s:\n", TMPL_INDENT,
12912                             gettext("doc_link"));
12913                         text = read_astring(pg, SCF_PROPERTY_TM_NAME);
12914                         if (text != NULL) {
12915                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12916                                     TMPL_INDENT, gettext("name"), text);
12917                                 uu_free(text);
12918                         }
12919                         text = read_astring(pg, SCF_PROPERTY_TM_URI);
12920                         if (text != NULL) {
12921                                 safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
12922                                     gettext("uri"), text);
12923                                 uu_free(text);
12924                         }
12925                 } else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
12926                     man_len) == 0) {
12927                         /* Display manpage title, section and path */
12928                         safe_printf("%s%s:\n", TMPL_INDENT,
12929                             gettext("manpage"));
12930                         text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
12931                         if (text != NULL) {
12932                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12933                                     TMPL_INDENT, gettext("title"), text);
12934                                 uu_free(text);
12935                         }
12936                         text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
12937                         if (text != NULL) {
12938                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12939                                     TMPL_INDENT, gettext("section"), text);
12940                                 uu_free(text);
12941                         }
12942                         text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
12943                         if (text != NULL) {
12944                                 safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12945                                     TMPL_INDENT, gettext("manpath"), text);
12946                                 uu_free(text);
12947                         }
12948                 }
12949         }
12950         if (rv == -1)
12951                 scfdie();
12952 
12953 done:
12954         free(pg_name);
12955 }
12956 
12957 static void
12958 list_entity_tmpl(int templates)
12959 {
12960         char *common_name = NULL;
12961         char *description = NULL;
12962         char *locale = NULL;
12963         scf_iter_t *iter;
12964         scf_propertygroup_t *pg;
12965         scf_property_t *prop;
12966         int r;
12967         scf_value_t *val;
12968 
12969         if ((pg = scf_pg_create(g_hndl)) == NULL ||
12970             (prop = scf_property_create(g_hndl)) == NULL ||
12971             (val = scf_value_create(g_hndl)) == NULL ||
12972             (iter = scf_iter_create(g_hndl)) == NULL)
12973                 scfdie();
12974 
12975         locale = setlocale(LC_MESSAGES, NULL);
12976 
12977         if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
12978                 common_name = safe_malloc(max_scf_value_len + 1);
12979 
12980                 /* Try both the current locale and the "C" locale. */
12981                 if (scf_pg_get_property(pg, locale, prop) == 0 ||
12982                     (scf_error() == SCF_ERROR_NOT_FOUND &&
12983                     scf_pg_get_property(pg, "C", prop) == 0)) {
12984                         if (prop_get_val(prop, val) == 0 &&
12985                             scf_value_get_ustring(val, common_name,
12986                             max_scf_value_len + 1) != -1) {
12987                                 safe_printf("%s%s: %s\n", TMPL_INDENT,
12988                                     gettext("common name"), common_name);
12989                         }
12990                 }
12991         }
12992 
12993         /*
12994          * Do description, manpages, and doc links if templates == 2.
12995          */
12996         if (templates == 2) {
12997                 /* Get the description. */
12998                 if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12999                         description = safe_malloc(max_scf_value_len + 1);
13000 
13001                         /* Try both the current locale and the "C" locale. */
13002                         if (scf_pg_get_property(pg, locale, prop) == 0 ||
13003                             (scf_error() == SCF_ERROR_NOT_FOUND &&
13004                             scf_pg_get_property(pg, "C", prop) == 0)) {
13005                                 if (prop_get_val(prop, val) == 0 &&
13006                                     scf_value_get_ustring(val, description,
13007                                     max_scf_value_len + 1) != -1) {
13008                                         safe_printf("%s%s: %s\n", TMPL_INDENT,
13009                                             gettext("description"),
13010                                             description);
13011                                 }
13012                         }
13013                 }
13014 
13015                 /* Process doc_link & manpage elements. */
13016                 if (cur_level != NULL) {
13017                         r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13018                             SCF_GROUP_TEMPLATE);
13019                 } else if (cur_inst != NULL) {
13020                         r = scf_iter_instance_pgs_typed(iter, cur_inst,
13021                             SCF_GROUP_TEMPLATE);
13022                 } else {
13023                         r = scf_iter_service_pgs_typed(iter, cur_svc,
13024                             SCF_GROUP_TEMPLATE);
13025                 }
13026                 if (r == 0) {
13027                         display_documentation(iter, pg);
13028                 }
13029         }
13030 
13031         free(common_name);
13032         free(description);
13033         scf_pg_destroy(pg);
13034         scf_property_destroy(prop);
13035         scf_value_destroy(val);
13036         scf_iter_destroy(iter);
13037 }
13038 
13039 static void
13040 listtmpl(const char *pattern, int templates)
13041 {
13042         scf_pg_tmpl_t *pgt;
13043         scf_prop_tmpl_t *prt;
13044         char *snapbuf = NULL;
13045         char *fmribuf;
13046         char *pg_name = NULL, *prop_name = NULL;
13047         ssize_t prop_name_size;
13048         char *qual_prop_name;
13049         char *search_name;
13050         int listed = 0;
13051 
13052         if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13053             (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13054                 scfdie();
13055 
13056         fmribuf = safe_malloc(max_scf_name_len + 1);
13057         qual_prop_name = safe_malloc(max_scf_name_len + 1);
13058 
13059         if (cur_snap != NULL) {
13060                 snapbuf = safe_malloc(max_scf_name_len + 1);
13061                 if (scf_snapshot_get_name(cur_snap, snapbuf,
13062                     max_scf_name_len + 1) < 0)
13063                         scfdie();
13064         }
13065 
13066         if (cur_inst != NULL) {
13067                 if (scf_instance_to_fmri(cur_inst, fmribuf,
13068                     max_scf_name_len + 1) < 0)
13069                         scfdie();
13070         } else if (cur_svc != NULL) {
13071                 if (scf_service_to_fmri(cur_svc, fmribuf,
13072                     max_scf_name_len + 1) < 0)
13073                         scfdie();
13074         } else
13075                 abort();
13076 
13077         /* If pattern is specified, we want to list only those items. */
13078         while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13079                 listed = 0;
13080                 if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13081                     fnmatch(pattern, pg_name, 0) == 0)) {
13082                         list_pg_tmpl(pgt, NULL, templates);
13083                         listed++;
13084                 }
13085 
13086                 scf_tmpl_prop_reset(prt);
13087 
13088                 while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13089                         search_name = NULL;
13090                         prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13091                         if ((prop_name_size > 0) && (pg_name != NULL)) {
13092                                 if (snprintf(qual_prop_name,
13093                                     max_scf_name_len + 1, "%s/%s",
13094                                     pg_name, prop_name) >=
13095                                     max_scf_name_len + 1) {
13096                                         prop_name_size = -1;
13097                                 } else {
13098                                         search_name = qual_prop_name;
13099                                 }
13100                         }
13101                         if (listed > 0 || pattern == NULL ||
13102                             (prop_name_size > 0 &&
13103                             fnmatch(pattern, search_name,
13104                             FNM_PATHNAME) == 0))
13105                                 list_prop_tmpl(prt, NULL, templates);
13106                         if (prop_name != NULL) {
13107                                 free(prop_name);
13108                                 prop_name = NULL;
13109                         }
13110                 }
13111                 if (pg_name != NULL) {
13112                         free(pg_name);
13113                         pg_name = NULL;
13114                 }
13115         }
13116 
13117         scf_tmpl_prop_destroy(prt);
13118         scf_tmpl_pg_destroy(pgt);
13119         free(snapbuf);
13120         free(fmribuf);
13121         free(qual_prop_name);
13122 }
13123 
13124 static void
13125 listprop(const char *pattern, int only_pgs, int templates)
13126 {
13127         scf_propertygroup_t *pg;
13128         scf_property_t *prop;
13129         scf_iter_t *iter, *piter;
13130         char *pgnbuf, *prnbuf, *ppnbuf;
13131         scf_pg_tmpl_t *pgt, *pgtp;
13132         scf_prop_tmpl_t *prt;
13133 
13134         void **objects;
13135         char **names;
13136         void **tmpls;
13137         int allocd, i;
13138 
13139         int ret;
13140         ssize_t pgnlen, prnlen, szret;
13141         size_t max_len = 0;
13142 
13143         if (cur_svc == NULL && cur_inst == NULL) {
13144                 semerr(emsg_entity_not_selected);
13145                 return;
13146         }
13147 
13148         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13149             (prop = scf_property_create(g_hndl)) == NULL ||
13150             (iter = scf_iter_create(g_hndl)) == NULL ||
13151             (piter = scf_iter_create(g_hndl)) == NULL ||
13152             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13153             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13154                 scfdie();
13155 
13156         prnbuf = safe_malloc(max_scf_name_len + 1);
13157 
13158         if (cur_level != NULL)
13159                 ret = scf_iter_snaplevel_pgs(iter, cur_level);
13160         else if (cur_inst != NULL)
13161                 ret = scf_iter_instance_pgs(iter, cur_inst);
13162         else
13163                 ret = scf_iter_service_pgs(iter, cur_svc);
13164         if (ret != 0) {
13165                 return;
13166         }
13167 
13168         /*
13169          * We want to only list items which match pattern, and we want the
13170          * second column to line up, so during the first pass we'll save
13171          * matching items, their names, and their templates in objects,
13172          * names, and tmpls, computing the maximum name length as we go,
13173          * and then we'll print them out.
13174          *
13175          * Note: We always keep an extra slot available so the array can be
13176          * NULL-terminated.
13177          */
13178         i = 0;
13179         allocd = 1;
13180         objects = safe_malloc(sizeof (*objects));
13181         names = safe_malloc(sizeof (*names));
13182         tmpls = safe_malloc(sizeof (*tmpls));
13183 
13184         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13185                 int new_pg = 0;
13186                 int print_props = 0;
13187                 pgtp = NULL;
13188 
13189                 pgnlen = scf_pg_get_name(pg, NULL, 0);
13190                 if (pgnlen < 0)
13191                         scfdie();
13192 
13193                 pgnbuf = safe_malloc(pgnlen + 1);
13194 
13195                 szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13196                 if (szret < 0)
13197                         scfdie();
13198                 assert(szret <= pgnlen);
13199 
13200                 if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13201                         if (scf_error() != SCF_ERROR_NOT_FOUND)
13202                                 scfdie();
13203                         pgtp = NULL;
13204                 } else {
13205                         pgtp = pgt;
13206                 }
13207 
13208                 if (pattern == NULL ||
13209                     fnmatch(pattern, pgnbuf, 0) == 0) {
13210                         if (i+1 >= allocd) {
13211                                 allocd *= 2;
13212                                 objects = realloc(objects,
13213                                     sizeof (*objects) * allocd);
13214                                 names =
13215                                     realloc(names, sizeof (*names) * allocd);
13216                                 tmpls = realloc(tmpls,
13217                                     sizeof (*tmpls) * allocd);
13218                                 if (objects == NULL || names == NULL ||
13219                                     tmpls == NULL)
13220                                         uu_die(gettext("Out of memory"));
13221                         }
13222                         objects[i] = pg;
13223                         names[i] = pgnbuf;
13224 
13225                         if (pgtp == NULL)
13226                                 tmpls[i] = NULL;
13227                         else
13228                                 tmpls[i] = pgt;
13229 
13230                         ++i;
13231 
13232                         if (pgnlen > max_len)
13233                                 max_len = pgnlen;
13234 
13235                         new_pg = 1;
13236                         print_props = 1;
13237                 }
13238 
13239                 if (only_pgs) {
13240                         if (new_pg) {
13241                                 pg = scf_pg_create(g_hndl);
13242                                 if (pg == NULL)
13243                                         scfdie();
13244                                 pgt = scf_tmpl_pg_create(g_hndl);
13245                                 if (pgt == NULL)
13246                                         scfdie();
13247                         } else
13248                                 free(pgnbuf);
13249 
13250                         continue;
13251                 }
13252 
13253                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13254                         scfdie();
13255 
13256                 while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13257                         prnlen = scf_property_get_name(prop, prnbuf,
13258                             max_scf_name_len + 1);
13259                         if (prnlen < 0)
13260                                 scfdie();
13261 
13262                         /* Will prepend the property group name and a slash. */
13263                         prnlen += pgnlen + 1;
13264 
13265                         ppnbuf = safe_malloc(prnlen + 1);
13266 
13267                         if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13268                             prnbuf) < 0)
13269                                 uu_die("snprintf");
13270 
13271                         if (pattern == NULL || print_props == 1 ||
13272                             fnmatch(pattern, ppnbuf, 0) == 0) {
13273                                 if (i+1 >= allocd) {
13274                                         allocd *= 2;
13275                                         objects = realloc(objects,
13276                                             sizeof (*objects) * allocd);
13277                                         names = realloc(names,
13278                                             sizeof (*names) * allocd);
13279                                         tmpls = realloc(tmpls,
13280                                             sizeof (*tmpls) * allocd);
13281                                         if (objects == NULL || names == NULL ||
13282                                             tmpls == NULL)
13283                                                 uu_die(gettext(
13284                                                     "Out of memory"));
13285                                 }
13286 
13287                                 objects[i] = prop;
13288                                 names[i] = ppnbuf;
13289 
13290                                 if (pgtp != NULL) {
13291                                         if (scf_tmpl_get_by_prop(pgt, prnbuf,
13292                                             prt, 0) < 0) {
13293                                                 if (scf_error() !=
13294                                                     SCF_ERROR_NOT_FOUND)
13295                                                         scfdie();
13296                                                 tmpls[i] = NULL;
13297                                         } else {
13298                                                 tmpls[i] = prt;
13299                                         }
13300                                 } else {
13301                                         tmpls[i] = NULL;
13302                                 }
13303 
13304                                 ++i;
13305 
13306                                 if (prnlen > max_len)
13307                                         max_len = prnlen;
13308 
13309                                 prop = scf_property_create(g_hndl);
13310                                 prt = scf_tmpl_prop_create(g_hndl);
13311                         } else {
13312                                 free(ppnbuf);
13313                         }
13314                 }
13315 
13316                 if (new_pg) {
13317                         pg = scf_pg_create(g_hndl);
13318                         if (pg == NULL)
13319                                 scfdie();
13320                         pgt = scf_tmpl_pg_create(g_hndl);
13321                         if (pgt == NULL)
13322                                 scfdie();
13323                 } else
13324                         free(pgnbuf);
13325         }
13326         if (ret != 0)
13327                 scfdie();
13328 
13329         objects[i] = NULL;
13330 
13331         scf_pg_destroy(pg);
13332         scf_tmpl_pg_destroy(pgt);
13333         scf_property_destroy(prop);
13334         scf_tmpl_prop_destroy(prt);
13335 
13336         for (i = 0; objects[i] != NULL; ++i) {
13337                 if (strchr(names[i], '/') == NULL) {
13338                         /* property group */
13339                         pg = (scf_propertygroup_t *)objects[i];
13340                         pgt = (scf_pg_tmpl_t *)tmpls[i];
13341                         list_pg_info(pg, names[i], max_len);
13342                         list_pg_tmpl(pgt, pg, templates);
13343                         free(names[i]);
13344                         scf_pg_destroy(pg);
13345                         if (pgt != NULL)
13346                                 scf_tmpl_pg_destroy(pgt);
13347                 } else {
13348                         /* property */
13349                         prop = (scf_property_t *)objects[i];
13350                         prt = (scf_prop_tmpl_t *)tmpls[i];
13351                         list_prop_info(prop, names[i], max_len);
13352                         list_prop_tmpl(prt, prop, templates);
13353                         free(names[i]);
13354                         scf_property_destroy(prop);
13355                         if (prt != NULL)
13356                                 scf_tmpl_prop_destroy(prt);
13357                 }
13358         }
13359 
13360         free(names);
13361         free(objects);
13362         free(tmpls);
13363 }
13364 
13365 void
13366 lscf_listpg(const char *pattern)
13367 {
13368         lscf_prep_hndl();
13369 
13370         listprop(pattern, 1, 0);
13371 }
13372 
13373 /*
13374  * Property group and property creation, setting, and deletion.  setprop (and
13375  * its alias, addprop) can either create a property group of a given type, or
13376  * it can create or set a property to a given type and list of values.
13377  */
13378 void
13379 lscf_addpg(const char *name, const char *type, const char *flags)
13380 {
13381         scf_propertygroup_t *pg;
13382         int ret;
13383         uint32_t flgs = 0;
13384         const char *cp;
13385 
13386 
13387         lscf_prep_hndl();
13388 
13389         if (cur_snap != NULL) {
13390                 semerr(emsg_cant_modify_snapshots);
13391                 return;
13392         }
13393 
13394         if (cur_inst == NULL && cur_svc == NULL) {
13395                 semerr(emsg_entity_not_selected);
13396                 return;
13397         }
13398 
13399         if (flags != NULL) {
13400                 for (cp = flags; *cp != '\0'; ++cp) {
13401                         switch (*cp) {
13402                         case 'P':
13403                                 flgs |= SCF_PG_FLAG_NONPERSISTENT;
13404                                 break;
13405 
13406                         case 'p':
13407                                 flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13408                                 break;
13409 
13410                         default:
13411                                 semerr(gettext("Invalid property group flag "
13412                                     "%c."), *cp);
13413                                 return;
13414                         }
13415                 }
13416         }
13417 
13418         pg = scf_pg_create(g_hndl);
13419         if (pg == NULL)
13420                 scfdie();
13421 
13422         if (cur_inst != NULL)
13423                 ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13424         else
13425                 ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13426 
13427         if (ret != SCF_SUCCESS) {
13428                 switch (scf_error()) {
13429                 case SCF_ERROR_INVALID_ARGUMENT:
13430                         semerr(gettext("Name, type, or flags are invalid.\n"));
13431                         break;
13432 
13433                 case SCF_ERROR_EXISTS:
13434                         semerr(gettext("Property group already exists.\n"));
13435                         break;
13436 
13437                 case SCF_ERROR_PERMISSION_DENIED:
13438                         semerr(emsg_permission_denied);
13439                         break;
13440 
13441                 case SCF_ERROR_BACKEND_ACCESS:
13442                         semerr(gettext("Backend refused access.\n"));
13443                         break;
13444 
13445                 default:
13446                         scfdie();
13447                 }
13448         }
13449 
13450         scf_pg_destroy(pg);
13451 
13452         private_refresh();
13453 }
13454 
13455 void
13456 lscf_delpg(char *name)
13457 {
13458         lscf_prep_hndl();
13459 
13460         if (cur_snap != NULL) {
13461                 semerr(emsg_cant_modify_snapshots);
13462                 return;
13463         }
13464 
13465         if (cur_inst == NULL && cur_svc == NULL) {
13466                 semerr(emsg_entity_not_selected);
13467                 return;
13468         }
13469 
13470         if (strchr(name, '/') != NULL) {
13471                 semerr(emsg_invalid_pg_name, name);
13472                 return;
13473         }
13474 
13475         lscf_delprop(name);
13476 }
13477 
13478 /*
13479  * scf_delhash() is used to remove the property group related to the
13480  * hash entry for a specific manifest in the repository. pgname will be
13481  * constructed from the location of the manifest file. If deathrow isn't 0,
13482  * manifest file doesn't need to exist (manifest string will be used as
13483  * an absolute path).
13484  */
13485 void
13486 lscf_delhash(char *manifest, int deathrow)
13487 {
13488         char *pgname;
13489 
13490         if (cur_snap != NULL ||
13491             cur_inst != NULL || cur_svc != NULL) {
13492                 warn(gettext("error, an entity is selected\n"));
13493                 return;
13494         }
13495 
13496         /* select smf/manifest */
13497         lscf_select(HASH_SVC);
13498         /*
13499          * Translate the manifest file name to property name. In the deathrow
13500          * case, the manifest file does not need to exist.
13501          */
13502         pgname = mhash_filename_to_propname(manifest,
13503             deathrow ? B_TRUE : B_FALSE);
13504         if (pgname == NULL) {
13505                 warn(gettext("cannot resolve pathname for %s\n"), manifest);
13506                 return;
13507         }
13508         /* delete the hash property name */
13509         lscf_delpg(pgname);
13510 }
13511 
13512 void
13513 lscf_listprop(const char *pattern)
13514 {
13515         lscf_prep_hndl();
13516 
13517         listprop(pattern, 0, 0);
13518 }
13519 
13520 int
13521 lscf_setprop(const char *pgname, const char *type, const char *value,
13522     const uu_list_t *values)
13523 {
13524         scf_type_t ty, current_ty;
13525         scf_service_t *svc;
13526         scf_propertygroup_t *pg, *parent_pg;
13527         scf_property_t *prop, *parent_prop;
13528         scf_pg_tmpl_t *pgt;
13529         scf_prop_tmpl_t *prt;
13530         int ret, result = 0;
13531         scf_transaction_t *tx;
13532         scf_transaction_entry_t *e;
13533         scf_value_t *v;
13534         uu_list_walk_t *walk;
13535         string_list_t *sp;
13536         char *propname;
13537         int req_quotes = 0;
13538 
13539         lscf_prep_hndl();
13540 
13541         if ((e = scf_entry_create(g_hndl)) == NULL ||
13542             (svc = scf_service_create(g_hndl)) == NULL ||
13543             (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13544             (pg = scf_pg_create(g_hndl)) == NULL ||
13545             (parent_prop = scf_property_create(g_hndl)) == NULL ||
13546             (prop = scf_property_create(g_hndl)) == NULL ||
13547             (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13548             (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13549             (tx = scf_transaction_create(g_hndl)) == NULL)
13550                 scfdie();
13551 
13552         if (cur_snap != NULL) {
13553                 semerr(emsg_cant_modify_snapshots);
13554                 goto fail;
13555         }
13556 
13557         if (cur_inst == NULL && cur_svc == NULL) {
13558                 semerr(emsg_entity_not_selected);
13559                 goto fail;
13560         }
13561 
13562         propname = strchr(pgname, '/');
13563         if (propname == NULL) {
13564                 semerr(gettext("Property names must contain a `/'.\n"));
13565                 goto fail;
13566         }
13567 
13568         *propname = '\0';
13569         ++propname;
13570 
13571         if (type != NULL) {
13572                 ty = string_to_type(type);
13573                 if (ty == SCF_TYPE_INVALID) {
13574                         semerr(gettext("Unknown type \"%s\".\n"), type);
13575                         goto fail;
13576                 }
13577         }
13578 
13579         if (cur_inst != NULL)
13580                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
13581         else
13582                 ret = scf_service_get_pg(cur_svc, pgname, pg);
13583         if (ret != SCF_SUCCESS) {
13584                 switch (scf_error()) {
13585                 case SCF_ERROR_NOT_FOUND:
13586                         semerr(emsg_no_such_pg, pgname);
13587                         goto fail;
13588 
13589                 case SCF_ERROR_INVALID_ARGUMENT:
13590                         semerr(emsg_invalid_pg_name, pgname);
13591                         goto fail;
13592 
13593                 default:
13594                         scfdie();
13595                         break;
13596                 }
13597         }
13598 
13599         do {
13600                 if (scf_pg_update(pg) == -1)
13601                         scfdie();
13602                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13603                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13604                                 scfdie();
13605 
13606                         semerr(emsg_permission_denied);
13607                         goto fail;
13608                 }
13609 
13610                 ret = scf_pg_get_property(pg, propname, prop);
13611                 if (ret == SCF_SUCCESS) {
13612                         if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13613                                 scfdie();
13614 
13615                         if (type == NULL)
13616                                 ty = current_ty;
13617                         if (scf_transaction_property_change_type(tx, e,
13618                             propname, ty) == -1)
13619                                 scfdie();
13620 
13621                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13622                         /* Infer the type, if possible. */
13623                         if (type == NULL) {
13624                                 /*
13625                                  * First check if we're an instance and the
13626                                  * property is set on the service.
13627                                  */
13628                                 if (cur_inst != NULL &&
13629                                     scf_instance_get_parent(cur_inst,
13630                                     svc) == 0 &&
13631                                     scf_service_get_pg(cur_svc, pgname,
13632                                     parent_pg) == 0 &&
13633                                     scf_pg_get_property(parent_pg, propname,
13634                                     parent_prop) == 0 &&
13635                                     scf_property_type(parent_prop,
13636                                     &current_ty) == 0) {
13637                                         ty = current_ty;
13638 
13639                                 /* Then check for a type set in a template. */
13640                                 } else if (scf_tmpl_get_by_pg(pg, pgt,
13641                                     0) == 0 &&
13642                                     scf_tmpl_get_by_prop(pgt, propname, prt,
13643                                     0) == 0 &&
13644                                     scf_tmpl_prop_type(prt, &current_ty) == 0) {
13645                                         ty = current_ty;
13646 
13647                                 /* If type can't be inferred, fail. */
13648                                 } else {
13649                                         semerr(gettext("Type required for new "
13650                                             "properties.\n"));
13651                                         goto fail;
13652                                 }
13653                         }
13654                         if (scf_transaction_property_new(tx, e, propname,
13655                             ty) == -1)
13656                                 scfdie();
13657                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13658                         semerr(emsg_invalid_prop_name, propname);
13659                         goto fail;
13660                 } else {
13661                         scfdie();
13662                 }
13663 
13664                 if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13665                         req_quotes = 1;
13666 
13667                 if (value != NULL) {
13668                         v = string_to_value(value, ty, 0);
13669 
13670                         if (v == NULL)
13671                                 goto fail;
13672 
13673                         ret = scf_entry_add_value(e, v);
13674                         assert(ret == SCF_SUCCESS);
13675                 } else {
13676                         assert(values != NULL);
13677 
13678                         walk = uu_list_walk_start((uu_list_t *)values,
13679                             UU_DEFAULT);
13680                         if (walk == NULL)
13681                                 uu_die(gettext("Could not walk list"));
13682 
13683                         for (sp = uu_list_walk_next(walk); sp != NULL;
13684                             sp = uu_list_walk_next(walk)) {
13685                                 v = string_to_value(sp->str, ty, req_quotes);
13686 
13687                                 if (v == NULL) {
13688                                         scf_entry_destroy_children(e);
13689                                         goto fail;
13690                                 }
13691 
13692                                 ret = scf_entry_add_value(e, v);
13693                                 assert(ret == SCF_SUCCESS);
13694                         }
13695                         uu_list_walk_end(walk);
13696                 }
13697                 result = scf_transaction_commit(tx);
13698 
13699                 scf_transaction_reset(tx);
13700                 scf_entry_destroy_children(e);
13701         } while (result == 0);
13702 
13703         if (result < 0) {
13704                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13705                         scfdie();
13706 
13707                 semerr(emsg_permission_denied);
13708                 goto fail;
13709         }
13710 
13711         ret = 0;
13712 
13713         private_refresh();
13714 
13715         goto cleanup;
13716 
13717 fail:
13718         ret = -1;
13719 
13720 cleanup:
13721         scf_transaction_destroy(tx);
13722         scf_entry_destroy(e);
13723         scf_service_destroy(svc);
13724         scf_pg_destroy(parent_pg);
13725         scf_pg_destroy(pg);
13726         scf_property_destroy(parent_prop);
13727         scf_property_destroy(prop);
13728         scf_tmpl_pg_destroy(pgt);
13729         scf_tmpl_prop_destroy(prt);
13730 
13731         return (ret);
13732 }
13733 
13734 void
13735 lscf_delprop(char *pgn)
13736 {
13737         char *slash, *pn;
13738         scf_propertygroup_t *pg;
13739         scf_transaction_t *tx;
13740         scf_transaction_entry_t *e;
13741         int ret;
13742 
13743 
13744         lscf_prep_hndl();
13745 
13746         if (cur_snap != NULL) {
13747                 semerr(emsg_cant_modify_snapshots);
13748                 return;
13749         }
13750 
13751         if (cur_inst == NULL && cur_svc == NULL) {
13752                 semerr(emsg_entity_not_selected);
13753                 return;
13754         }
13755 
13756         pg = scf_pg_create(g_hndl);
13757         if (pg == NULL)
13758                 scfdie();
13759 
13760         slash = strchr(pgn, '/');
13761         if (slash == NULL) {
13762                 pn = NULL;
13763         } else {
13764                 *slash = '\0';
13765                 pn = slash + 1;
13766         }
13767 
13768         if (cur_inst != NULL)
13769                 ret = scf_instance_get_pg(cur_inst, pgn, pg);
13770         else
13771                 ret = scf_service_get_pg(cur_svc, pgn, pg);
13772         if (ret != SCF_SUCCESS) {
13773                 switch (scf_error()) {
13774                 case SCF_ERROR_NOT_FOUND:
13775                         semerr(emsg_no_such_pg, pgn);
13776                         break;
13777 
13778                 case SCF_ERROR_INVALID_ARGUMENT:
13779                         semerr(emsg_invalid_pg_name, pgn);
13780                         break;
13781 
13782                 default:
13783                         scfdie();
13784                 }
13785 
13786                 scf_pg_destroy(pg);
13787 
13788                 return;
13789         }
13790 
13791         if (pn == NULL) {
13792                 /* Try to delete the property group. */
13793                 if (scf_pg_delete(pg) != SCF_SUCCESS) {
13794                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13795                                 scfdie();
13796 
13797                         semerr(emsg_permission_denied);
13798                 } else {
13799                         private_refresh();
13800                 }
13801 
13802                 scf_pg_destroy(pg);
13803                 return;
13804         }
13805 
13806         e = scf_entry_create(g_hndl);
13807         tx = scf_transaction_create(g_hndl);
13808 
13809         do {
13810                 if (scf_pg_update(pg) == -1)
13811                         scfdie();
13812                 if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13813                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13814                                 scfdie();
13815 
13816                         semerr(emsg_permission_denied);
13817                         break;
13818                 }
13819 
13820                 if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
13821                         if (scf_error() == SCF_ERROR_NOT_FOUND) {
13822                                 semerr(gettext("No such property %s/%s.\n"),
13823                                     pgn, pn);
13824                                 break;
13825                         } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13826                                 semerr(emsg_invalid_prop_name, pn);
13827                                 break;
13828                         } else {
13829                                 scfdie();
13830                         }
13831                 }
13832 
13833                 ret = scf_transaction_commit(tx);
13834 
13835                 if (ret == 0)
13836                         scf_transaction_reset(tx);
13837         } while (ret == 0);
13838 
13839         if (ret < 0) {
13840                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13841                         scfdie();
13842 
13843                 semerr(emsg_permission_denied);
13844         } else {
13845                 private_refresh();
13846         }
13847 
13848         scf_transaction_destroy(tx);
13849         scf_entry_destroy(e);
13850         scf_pg_destroy(pg);
13851 }
13852 
13853 /*
13854  * Property editing.
13855  */
13856 
13857 static int
13858 write_edit_script(FILE *strm)
13859 {
13860         char *fmribuf;
13861         ssize_t fmrilen;
13862 
13863         scf_propertygroup_t *pg;
13864         scf_property_t *prop;
13865         scf_value_t *val;
13866         scf_type_t ty;
13867         int ret, result = 0;
13868         scf_iter_t *iter, *piter, *viter;
13869         char *buf, *tybuf, *pname;
13870         const char *emsg_write_error;
13871 
13872 
13873         emsg_write_error = gettext("Error writing temoprary file: %s.\n");
13874 
13875 
13876         /* select fmri */
13877         if (cur_inst != NULL) {
13878                 fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
13879                 if (fmrilen < 0)
13880                         scfdie();
13881                 fmribuf = safe_malloc(fmrilen + 1);
13882                 if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
13883                         scfdie();
13884         } else {
13885                 assert(cur_svc != NULL);
13886                 fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
13887                 if (fmrilen < 0)
13888                         scfdie();
13889                 fmribuf = safe_malloc(fmrilen + 1);
13890                 if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
13891                         scfdie();
13892         }
13893 
13894         if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
13895                 warn(emsg_write_error, strerror(errno));
13896                 free(fmribuf);
13897                 return (-1);
13898         }
13899 
13900         free(fmribuf);
13901 
13902 
13903         if ((pg = scf_pg_create(g_hndl)) == NULL ||
13904             (prop = scf_property_create(g_hndl)) == NULL ||
13905             (val = scf_value_create(g_hndl)) == NULL ||
13906             (iter = scf_iter_create(g_hndl)) == NULL ||
13907             (piter = scf_iter_create(g_hndl)) == NULL ||
13908             (viter = scf_iter_create(g_hndl)) == NULL)
13909                 scfdie();
13910 
13911         buf = safe_malloc(max_scf_name_len + 1);
13912         tybuf = safe_malloc(max_scf_pg_type_len + 1);
13913         pname = safe_malloc(max_scf_name_len + 1);
13914 
13915         if (cur_inst != NULL)
13916                 ret = scf_iter_instance_pgs(iter, cur_inst);
13917         else
13918                 ret = scf_iter_service_pgs(iter, cur_svc);
13919         if (ret != SCF_SUCCESS)
13920                 scfdie();
13921 
13922         while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13923                 int ret2;
13924 
13925                 /*
13926                  * # delprop pg
13927                  * # addpg pg type
13928                  */
13929                 if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
13930                         scfdie();
13931 
13932                 if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
13933                         scfdie();
13934 
13935                 if (fprintf(strm, "# Property group \"%s\"\n"
13936                     "# delprop %s\n"
13937                     "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
13938                         warn(emsg_write_error, strerror(errno));
13939                         result = -1;
13940                         goto out;
13941                 }
13942 
13943                 /* # setprop pg/prop = (values) */
13944 
13945                 if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13946                         scfdie();
13947 
13948                 while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
13949                         int first = 1;
13950                         int ret3;
13951                         int multiple;
13952                         int is_str;
13953                         scf_type_t bty;
13954 
13955                         if (scf_property_get_name(prop, pname,
13956                             max_scf_name_len + 1) < 0)
13957                                 scfdie();
13958 
13959                         if (scf_property_type(prop, &ty) != 0)
13960                                 scfdie();
13961 
13962                         multiple = prop_has_multiple_values(prop, val);
13963 
13964                         if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13965                             pname, scf_type_to_string(ty), multiple ? "(" : "")
13966                             < 0) {
13967                                 warn(emsg_write_error, strerror(errno));
13968                                 result = -1;
13969                                 goto out;
13970                         }
13971 
13972                         (void) scf_type_base_type(ty, &bty);
13973                         is_str = (bty == SCF_TYPE_ASTRING);
13974 
13975                         if (scf_iter_property_values(viter, prop) !=
13976                             SCF_SUCCESS)
13977                                 scfdie();
13978 
13979                         while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
13980                                 char *buf;
13981                                 ssize_t buflen;
13982 
13983                                 buflen = scf_value_get_as_string(val, NULL, 0);
13984                                 if (buflen < 0)
13985                                         scfdie();
13986 
13987                                 buf = safe_malloc(buflen + 1);
13988 
13989                                 if (scf_value_get_as_string(val, buf,
13990                                     buflen + 1) < 0)
13991                                         scfdie();
13992 
13993                                 if (first)
13994                                         first = 0;
13995                                 else {
13996                                         if (putc(' ', strm) != ' ') {
13997                                                 warn(emsg_write_error,
13998                                                     strerror(errno));
13999                                                 result = -1;
14000                                                 goto out;
14001                                         }
14002                                 }
14003 
14004                                 if ((is_str && multiple) ||
14005                                     strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14006                                         (void) putc('"', strm);
14007                                         (void) quote_and_print(buf, strm, 1);
14008                                         (void) putc('"', strm);
14009 
14010                                         if (ferror(strm)) {
14011                                                 warn(emsg_write_error,
14012                                                     strerror(errno));
14013                                                 result = -1;
14014                                                 goto out;
14015                                         }
14016                                 } else {
14017                                         if (fprintf(strm, "%s", buf) < 0) {
14018                                                 warn(emsg_write_error,
14019                                                     strerror(errno));
14020                                                 result = -1;
14021                                                 goto out;
14022                                         }
14023                                 }
14024 
14025                                 free(buf);
14026                         }
14027                         if (ret3 < 0 &&
14028                             scf_error() != SCF_ERROR_PERMISSION_DENIED)
14029                                 scfdie();
14030 
14031                         /* Write closing paren if mult-value property */
14032                         if ((multiple && putc(')', strm) == EOF) ||
14033 
14034                             /* Write final newline */
14035                             fputc('\n', strm) == EOF) {
14036                                 warn(emsg_write_error, strerror(errno));
14037                                 result = -1;
14038                                 goto out;
14039                         }
14040                 }
14041                 if (ret2 < 0)
14042                         scfdie();
14043 
14044                 if (fputc('\n', strm) == EOF) {
14045                         warn(emsg_write_error, strerror(errno));
14046                         result = -1;
14047                         goto out;
14048                 }
14049         }
14050         if (ret < 0)
14051                 scfdie();
14052 
14053 out:
14054         free(pname);
14055         free(tybuf);
14056         free(buf);
14057         scf_iter_destroy(viter);
14058         scf_iter_destroy(piter);
14059         scf_iter_destroy(iter);
14060         scf_value_destroy(val);
14061         scf_property_destroy(prop);
14062         scf_pg_destroy(pg);
14063 
14064         if (result == 0) {
14065                 if (fflush(strm) != 0) {
14066                         warn(emsg_write_error, strerror(errno));
14067                         return (-1);
14068                 }
14069         }
14070 
14071         return (result);
14072 }
14073 
14074 int
14075 lscf_editprop()
14076 {
14077         char *buf, *editor;
14078         size_t bufsz;
14079         int tmpfd;
14080         char tempname[] = TEMP_FILE_PATTERN;
14081 
14082         lscf_prep_hndl();
14083 
14084         if (cur_snap != NULL) {
14085                 semerr(emsg_cant_modify_snapshots);
14086                 return (-1);
14087         }
14088 
14089         if (cur_svc == NULL && cur_inst == NULL) {
14090                 semerr(emsg_entity_not_selected);
14091                 return (-1);
14092         }
14093 
14094         tmpfd = mkstemp(tempname);
14095         if (tmpfd == -1) {
14096                 semerr(gettext("Could not create temporary file.\n"));
14097                 return (-1);
14098         }
14099 
14100         (void) strcpy(tempfilename, tempname);
14101 
14102         tempfile = fdopen(tmpfd, "r+");
14103         if (tempfile == NULL) {
14104                 warn(gettext("Could not create temporary file.\n"));
14105                 if (close(tmpfd) == -1)
14106                         warn(gettext("Could not close temporary file: %s.\n"),
14107                             strerror(errno));
14108 
14109                 remove_tempfile();
14110 
14111                 return (-1);
14112         }
14113 
14114         if (write_edit_script(tempfile) == -1) {
14115                 remove_tempfile();
14116                 return (-1);
14117         }
14118 
14119         editor = getenv("EDITOR");
14120         if (editor == NULL)
14121                 editor = "vi";
14122 
14123         bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14124         buf = safe_malloc(bufsz);
14125 
14126         if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14127                 uu_die(gettext("Error creating editor command"));
14128 
14129         if (system(buf) == -1) {
14130                 semerr(gettext("Could not launch editor %s: %s\n"), editor,
14131                     strerror(errno));
14132                 free(buf);
14133                 remove_tempfile();
14134                 return (-1);
14135         }
14136 
14137         free(buf);
14138 
14139         (void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14140 
14141         remove_tempfile();
14142 
14143         return (0);
14144 }
14145 
14146 static void
14147 add_string(uu_list_t *strlist, const char *str)
14148 {
14149         string_list_t *elem;
14150         elem = safe_malloc(sizeof (*elem));
14151         uu_list_node_init(elem, &elem->node, string_pool);
14152         elem->str = safe_strdup(str);
14153         if (uu_list_append(strlist, elem) != 0)
14154                 uu_die(gettext("libuutil error: %s\n"),
14155                     uu_strerror(uu_error()));
14156 }
14157 
14158 static int
14159 remove_string(uu_list_t *strlist, const char *str)
14160 {
14161         uu_list_walk_t  *elems;
14162         string_list_t   *sp;
14163 
14164         /*
14165          * Find the element that needs to be removed.
14166          */
14167         elems = uu_list_walk_start(strlist, UU_DEFAULT);
14168         while ((sp = uu_list_walk_next(elems)) != NULL) {
14169                 if (strcmp(sp->str, str) == 0)
14170                         break;
14171         }
14172         uu_list_walk_end(elems);
14173 
14174         /*
14175          * Returning 1 here as the value was not found, this
14176          * might not be an error.  Leave it to the caller to
14177          * decide.
14178          */
14179         if (sp == NULL) {
14180                 return (1);
14181         }
14182 
14183         uu_list_remove(strlist, sp);
14184 
14185         free(sp->str);
14186         free(sp);
14187 
14188         return (0);
14189 }
14190 
14191 /*
14192  * Get all property values that don't match the given glob pattern,
14193  * if a pattern is specified.
14194  */
14195 static void
14196 get_prop_values(scf_property_t *prop, uu_list_t *values,
14197     const char *pattern)
14198 {
14199         scf_iter_t *iter;
14200         scf_value_t *val;
14201         int ret;
14202 
14203         if ((iter = scf_iter_create(g_hndl)) == NULL ||
14204             (val = scf_value_create(g_hndl)) == NULL)
14205                 scfdie();
14206 
14207         if (scf_iter_property_values(iter, prop) != 0)
14208                 scfdie();
14209 
14210         while ((ret = scf_iter_next_value(iter, val)) == 1) {
14211                 char *buf;
14212                 ssize_t vlen, szret;
14213 
14214                 vlen = scf_value_get_as_string(val, NULL, 0);
14215                 if (vlen < 0)
14216                         scfdie();
14217 
14218                 buf = safe_malloc(vlen + 1);
14219 
14220                 szret = scf_value_get_as_string(val, buf, vlen + 1);
14221                 if (szret < 0)
14222                         scfdie();
14223                 assert(szret <= vlen);
14224 
14225                 if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14226                         add_string(values, buf);
14227 
14228                 free(buf);
14229         }
14230 
14231         if (ret == -1)
14232                 scfdie();
14233 
14234         scf_value_destroy(val);
14235         scf_iter_destroy(iter);
14236 }
14237 
14238 static int
14239 lscf_setpropvalue(const char *pgname, const char *type,
14240     const char *arg, int isadd, int isnotfoundok)
14241 {
14242         scf_type_t ty;
14243         scf_propertygroup_t *pg;
14244         scf_property_t *prop;
14245         int ret, result = 0;
14246         scf_transaction_t *tx;
14247         scf_transaction_entry_t *e;
14248         scf_value_t *v;
14249         string_list_t *sp;
14250         char *propname;
14251         uu_list_t *values;
14252         uu_list_walk_t *walk;
14253         void *cookie = NULL;
14254         char *pattern = NULL;
14255 
14256         lscf_prep_hndl();
14257 
14258         if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14259                 uu_die(gettext("Could not create property list: %s\n"),
14260                     uu_strerror(uu_error()));
14261 
14262         if (!isadd)
14263                 pattern = safe_strdup(arg);
14264 
14265         if ((e = scf_entry_create(g_hndl)) == NULL ||
14266             (pg = scf_pg_create(g_hndl)) == NULL ||
14267             (prop = scf_property_create(g_hndl)) == NULL ||
14268             (tx = scf_transaction_create(g_hndl)) == NULL)
14269                 scfdie();
14270 
14271         if (cur_snap != NULL) {
14272                 semerr(emsg_cant_modify_snapshots);
14273                 goto fail;
14274         }
14275 
14276         if (cur_inst == NULL && cur_svc == NULL) {
14277                 semerr(emsg_entity_not_selected);
14278                 goto fail;
14279         }
14280 
14281         propname = strchr(pgname, '/');
14282         if (propname == NULL) {
14283                 semerr(gettext("Property names must contain a `/'.\n"));
14284                 goto fail;
14285         }
14286 
14287         *propname = '\0';
14288         ++propname;
14289 
14290         if (type != NULL) {
14291                 ty = string_to_type(type);
14292                 if (ty == SCF_TYPE_INVALID) {
14293                         semerr(gettext("Unknown type \"%s\".\n"), type);
14294                         goto fail;
14295                 }
14296         }
14297 
14298         if (cur_inst != NULL)
14299                 ret = scf_instance_get_pg(cur_inst, pgname, pg);
14300         else
14301                 ret = scf_service_get_pg(cur_svc, pgname, pg);
14302         if (ret != 0) {
14303                 switch (scf_error()) {
14304                 case SCF_ERROR_NOT_FOUND:
14305                         if (isnotfoundok) {
14306                                 result = 0;
14307                         } else {
14308                                 semerr(emsg_no_such_pg, pgname);
14309                                 result = -1;
14310                         }
14311                         goto out;
14312 
14313                 case SCF_ERROR_INVALID_ARGUMENT:
14314                         semerr(emsg_invalid_pg_name, pgname);
14315                         goto fail;
14316 
14317                 default:
14318                         scfdie();
14319                 }
14320         }
14321 
14322         do {
14323                 if (scf_pg_update(pg) == -1)
14324                         scfdie();
14325                 if (scf_transaction_start(tx, pg) != 0) {
14326                         if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14327                                 scfdie();
14328 
14329                         semerr(emsg_permission_denied);
14330                         goto fail;
14331                 }
14332 
14333                 ret = scf_pg_get_property(pg, propname, prop);
14334                 if (ret == 0) {
14335                         scf_type_t ptype;
14336                         char *pat = pattern;
14337 
14338                         if (scf_property_type(prop, &ptype) != 0)
14339                                 scfdie();
14340 
14341                         if (isadd) {
14342                                 if (type != NULL && ptype != ty) {
14343                                         semerr(gettext("Property \"%s\" is not "
14344                                             "of type \"%s\".\n"), propname,
14345                                             type);
14346                                         goto fail;
14347                                 }
14348 
14349                                 pat = NULL;
14350                         } else {
14351                                 size_t len = strlen(pat);
14352                                 if (len > 0 && pat[len - 1] == '\"')
14353                                         pat[len - 1] = '\0';
14354                                 if (len > 0 && pat[0] == '\"')
14355                                         pat++;
14356                         }
14357 
14358                         ty = ptype;
14359 
14360                         get_prop_values(prop, values, pat);
14361 
14362                         if (isadd)
14363                                 add_string(values, arg);
14364 
14365                         if (scf_transaction_property_change(tx, e,
14366                             propname, ty) == -1)
14367                                 scfdie();
14368                 } else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14369                         if (isadd) {
14370                                 if (type == NULL) {
14371                                         semerr(gettext("Type required "
14372                                             "for new properties.\n"));
14373                                         goto fail;
14374                                 }
14375 
14376                                 add_string(values, arg);
14377 
14378                                 if (scf_transaction_property_new(tx, e,
14379                                     propname, ty) == -1)
14380                                         scfdie();
14381                         } else if (isnotfoundok) {
14382                                 result = 0;
14383                                 goto out;
14384                         } else {
14385                                 semerr(gettext("No such property %s/%s.\n"),
14386                                     pgname, propname);
14387                                 result = -1;
14388                                 goto out;
14389                         }
14390                 } else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14391                         semerr(emsg_invalid_prop_name, propname);
14392                         goto fail;
14393                 } else {
14394                         scfdie();
14395                 }
14396 
14397                 walk = uu_list_walk_start(values, UU_DEFAULT);
14398                 if (walk == NULL)
14399                         uu_die(gettext("Could not walk property list.\n"));
14400 
14401                 for (sp = uu_list_walk_next(walk); sp != NULL;
14402                     sp = uu_list_walk_next(walk)) {
14403                         v = string_to_value(sp->str, ty, 0);
14404 
14405                         if (v == NULL) {
14406                                 scf_entry_destroy_children(e);
14407                                 goto fail;
14408                         }
14409                         ret = scf_entry_add_value(e, v);
14410                         assert(ret == 0);
14411                 }
14412                 uu_list_walk_end(walk);
14413 
14414                 result = scf_transaction_commit(tx);
14415 
14416                 scf_transaction_reset(tx);
14417                 scf_entry_destroy_children(e);
14418         } while (result == 0);
14419 
14420         if (result < 0) {
14421                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14422                         scfdie();
14423 
14424                 semerr(emsg_permission_denied);
14425                 goto fail;
14426         }
14427 
14428         result = 0;
14429 
14430         private_refresh();
14431 
14432 out:
14433         scf_transaction_destroy(tx);
14434         scf_entry_destroy(e);
14435         scf_pg_destroy(pg);
14436         scf_property_destroy(prop);
14437         free(pattern);
14438 
14439         while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14440                 free(sp->str);
14441                 free(sp);
14442         }
14443 
14444         uu_list_destroy(values);
14445 
14446         return (result);
14447 
14448 fail:
14449         result = -1;
14450         goto out;
14451 }
14452 
14453 int
14454 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14455 {
14456         return (lscf_setpropvalue(pgname, type, value, 1, 0));
14457 }
14458 
14459 int
14460 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14461 {
14462         return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14463 }
14464 
14465 /*
14466  * Look for a standard start method, first in the instance (if any),
14467  * then the service.
14468  */
14469 static const char *
14470 start_method_name(int *in_instance)
14471 {
14472         scf_propertygroup_t *pg;
14473         char **p;
14474         int ret;
14475         scf_instance_t *inst = cur_inst;
14476 
14477         if ((pg = scf_pg_create(g_hndl)) == NULL)
14478                 scfdie();
14479 
14480 again:
14481         for (p = start_method_names; *p != NULL; p++) {
14482                 if (inst != NULL)
14483                         ret = scf_instance_get_pg(inst, *p, pg);
14484                 else
14485                         ret = scf_service_get_pg(cur_svc, *p, pg);
14486 
14487                 if (ret == 0) {
14488                         size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14489                         char *buf = safe_malloc(bufsz);
14490 
14491                         if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14492                                 free(buf);
14493                                 continue;
14494                         }
14495                         if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14496                                 free(buf);
14497                                 continue;
14498                         }
14499 
14500                         free(buf);
14501                         *in_instance = (inst != NULL);
14502                         scf_pg_destroy(pg);
14503                         return (*p);
14504                 }
14505 
14506                 if (scf_error() == SCF_ERROR_NOT_FOUND)
14507                         continue;
14508 
14509                 scfdie();
14510         }
14511 
14512         if (inst != NULL) {
14513                 inst = NULL;
14514                 goto again;
14515         }
14516 
14517         scf_pg_destroy(pg);
14518         return (NULL);
14519 }
14520 
14521 static int
14522 addpg(const char *name, const char *type)
14523 {
14524         scf_propertygroup_t *pg;
14525         int ret;
14526 
14527         pg = scf_pg_create(g_hndl);
14528         if (pg == NULL)
14529                 scfdie();
14530 
14531         if (cur_inst != NULL)
14532                 ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14533         else
14534                 ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14535 
14536         if (ret != 0) {
14537                 switch (scf_error()) {
14538                 case SCF_ERROR_EXISTS:
14539                         ret = 0;
14540                         break;
14541 
14542                 case SCF_ERROR_PERMISSION_DENIED:
14543                         semerr(emsg_permission_denied);
14544                         break;
14545 
14546                 default:
14547                         scfdie();
14548                 }
14549         }
14550 
14551         scf_pg_destroy(pg);
14552         return (ret);
14553 }
14554 
14555 int
14556 lscf_setenv(uu_list_t *args, int isunset)
14557 {
14558         int ret = 0;
14559         size_t i;
14560         int argc;
14561         char **argv = NULL;
14562         string_list_t *slp;
14563         char *pattern;
14564         char *prop;
14565         int do_service = 0;
14566         int do_instance = 0;
14567         const char *method = NULL;
14568         const char *name = NULL;
14569         const char *value = NULL;
14570         scf_instance_t *saved_cur_inst = cur_inst;
14571 
14572         lscf_prep_hndl();
14573 
14574         argc = uu_list_numnodes(args);
14575         if (argc < 1)
14576                 goto usage;
14577 
14578         argv = calloc(argc + 1, sizeof (char *));
14579         if (argv == NULL)
14580                 uu_die(gettext("Out of memory.\n"));
14581 
14582         for (slp = uu_list_first(args), i = 0;
14583             slp != NULL;
14584             slp = uu_list_next(args, slp), ++i)
14585                 argv[i] = slp->str;
14586 
14587         argv[i] = NULL;
14588 
14589         opterr = 0;
14590         optind = 0;
14591         for (;;) {
14592                 ret = getopt(argc, argv, "sim:");
14593                 if (ret == -1)
14594                         break;
14595 
14596                 switch (ret) {
14597                 case 's':
14598                         do_service = 1;
14599                         cur_inst = NULL;
14600                         break;
14601 
14602                 case 'i':
14603                         do_instance = 1;
14604                         break;
14605 
14606                 case 'm':
14607                         method = optarg;
14608                         break;
14609 
14610                 case '?':
14611                         goto usage;
14612 
14613                 default:
14614                         bad_error("getopt", ret);
14615                 }
14616         }
14617 
14618         argc -= optind;
14619         if ((do_service && do_instance) ||
14620             (isunset && argc != 1) ||
14621             (!isunset && argc != 2))
14622                 goto usage;
14623 
14624         name = argv[optind];
14625         if (!isunset)
14626                 value = argv[optind + 1];
14627 
14628         if (cur_snap != NULL) {
14629                 semerr(emsg_cant_modify_snapshots);
14630                 ret = -1;
14631                 goto out;
14632         }
14633 
14634         if (cur_inst == NULL && cur_svc == NULL) {
14635                 semerr(emsg_entity_not_selected);
14636                 ret = -1;
14637                 goto out;
14638         }
14639 
14640         if (do_instance && cur_inst == NULL) {
14641                 semerr(gettext("No instance is selected.\n"));
14642                 ret = -1;
14643                 goto out;
14644         }
14645 
14646         if (do_service && cur_svc == NULL) {
14647                 semerr(gettext("No service is selected.\n"));
14648                 ret = -1;
14649                 goto out;
14650         }
14651 
14652         if (method == NULL) {
14653                 if (do_instance || do_service) {
14654                         method = "method_context";
14655                         if (!isunset) {
14656                                 ret = addpg("method_context",
14657                                     SCF_GROUP_FRAMEWORK);
14658                                 if (ret != 0)
14659                                         goto out;
14660                         }
14661                 } else {
14662                         int in_instance;
14663                         method = start_method_name(&in_instance);
14664                         if (method == NULL) {
14665                                 semerr(gettext(
14666                                     "Couldn't find start method; please "
14667                                     "specify a method with '-m'.\n"));
14668                                 ret = -1;
14669                                 goto out;
14670                         }
14671                         if (!in_instance)
14672                                 cur_inst = NULL;
14673                 }
14674         } else {
14675                 scf_propertygroup_t *pg;
14676                 size_t bufsz;
14677                 char *buf;
14678                 int ret;
14679 
14680                 if ((pg = scf_pg_create(g_hndl)) == NULL)
14681                         scfdie();
14682 
14683                 if (cur_inst != NULL)
14684                         ret = scf_instance_get_pg(cur_inst, method, pg);
14685                 else
14686                         ret = scf_service_get_pg(cur_svc, method, pg);
14687 
14688                 if (ret != 0) {
14689                         scf_pg_destroy(pg);
14690                         switch (scf_error()) {
14691                         case SCF_ERROR_NOT_FOUND:
14692                                 semerr(gettext("Couldn't find the method "
14693                                     "\"%s\".\n"), method);
14694                                 goto out;
14695 
14696                         case SCF_ERROR_INVALID_ARGUMENT:
14697                                 semerr(gettext("Invalid method name \"%s\".\n"),
14698                                     method);
14699                                 goto out;
14700 
14701                         default:
14702                                 scfdie();
14703                         }
14704                 }
14705 
14706                 bufsz = strlen(SCF_GROUP_METHOD) + 1;
14707                 buf = safe_malloc(bufsz);
14708 
14709                 if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14710                     strcmp(buf, SCF_GROUP_METHOD) != 0) {
14711                         semerr(gettext("Property group \"%s\" is not of type "
14712                             "\"method\".\n"), method);
14713                         ret = -1;
14714                         free(buf);
14715                         scf_pg_destroy(pg);
14716                         goto out;
14717                 }
14718 
14719                 free(buf);
14720                 scf_pg_destroy(pg);
14721         }
14722 
14723         prop = uu_msprintf("%s/environment", method);
14724         pattern = uu_msprintf("%s=*", name);
14725 
14726         if (prop == NULL || pattern == NULL)
14727                 uu_die(gettext("Out of memory.\n"));
14728 
14729         ret = lscf_delpropvalue(prop, pattern, !isunset);
14730 
14731         if (ret == 0 && !isunset) {
14732                 uu_free(pattern);
14733                 uu_free(prop);
14734                 prop = uu_msprintf("%s/environment", method);
14735                 pattern = uu_msprintf("%s=%s", name, value);
14736                 if (prop == NULL || pattern == NULL)
14737                         uu_die(gettext("Out of memory.\n"));
14738                 ret = lscf_addpropvalue(prop, "astring:", pattern);
14739         }
14740         uu_free(pattern);
14741         uu_free(prop);
14742 
14743 out:
14744         cur_inst = saved_cur_inst;
14745 
14746         free(argv);
14747         return (ret);
14748 usage:
14749         ret = -2;
14750         goto out;
14751 }
14752 
14753 /*
14754  * Snapshot commands
14755  */
14756 
14757 void
14758 lscf_listsnap()
14759 {
14760         scf_snapshot_t *snap;
14761         scf_iter_t *iter;
14762         char *nb;
14763         int r;
14764 
14765         lscf_prep_hndl();
14766 
14767         if (cur_inst == NULL) {
14768                 semerr(gettext("Instance not selected.\n"));
14769                 return;
14770         }
14771 
14772         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14773             (iter = scf_iter_create(g_hndl)) == NULL)
14774                 scfdie();
14775 
14776         if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
14777                 scfdie();
14778 
14779         nb = safe_malloc(max_scf_name_len + 1);
14780 
14781         while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
14782                 if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
14783                         scfdie();
14784 
14785                 (void) puts(nb);
14786         }
14787         if (r < 0)
14788                 scfdie();
14789 
14790         free(nb);
14791         scf_iter_destroy(iter);
14792         scf_snapshot_destroy(snap);
14793 }
14794 
14795 void
14796 lscf_selectsnap(const char *name)
14797 {
14798         scf_snapshot_t *snap;
14799         scf_snaplevel_t *level;
14800 
14801         lscf_prep_hndl();
14802 
14803         if (cur_inst == NULL) {
14804                 semerr(gettext("Instance not selected.\n"));
14805                 return;
14806         }
14807 
14808         if (cur_snap != NULL) {
14809                 if (name != NULL) {
14810                         char *cur_snap_name;
14811                         boolean_t nochange;
14812 
14813                         cur_snap_name = safe_malloc(max_scf_name_len + 1);
14814 
14815                         if (scf_snapshot_get_name(cur_snap, cur_snap_name,
14816                             max_scf_name_len + 1) < 0)
14817                                 scfdie();
14818 
14819                         nochange = strcmp(name, cur_snap_name) == 0;
14820 
14821                         free(cur_snap_name);
14822 
14823                         if (nochange)
14824                                 return;
14825                 }
14826 
14827                 unselect_cursnap();
14828         }
14829 
14830         if (name == NULL)
14831                 return;
14832 
14833         if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14834             (level = scf_snaplevel_create(g_hndl)) == NULL)
14835                 scfdie();
14836 
14837         if (scf_instance_get_snapshot(cur_inst, name, snap) !=
14838             SCF_SUCCESS) {
14839                 switch (scf_error()) {
14840                 case SCF_ERROR_INVALID_ARGUMENT:
14841                         semerr(gettext("Invalid name \"%s\".\n"), name);
14842                         break;
14843 
14844                 case SCF_ERROR_NOT_FOUND:
14845                         semerr(gettext("No such snapshot \"%s\".\n"), name);
14846                         break;
14847 
14848                 default:
14849                         scfdie();
14850                 }
14851 
14852                 scf_snaplevel_destroy(level);
14853                 scf_snapshot_destroy(snap);
14854                 return;
14855         }
14856 
14857         /* Load the snaplevels into our list. */
14858         cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
14859         if (cur_levels == NULL)
14860                 uu_die(gettext("Could not create list: %s\n"),
14861                     uu_strerror(uu_error()));
14862 
14863         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14864                 if (scf_error() != SCF_ERROR_NOT_FOUND)
14865                         scfdie();
14866 
14867                 semerr(gettext("Snapshot has no snaplevels.\n"));
14868 
14869                 scf_snaplevel_destroy(level);
14870                 scf_snapshot_destroy(snap);
14871                 return;
14872         }
14873 
14874         cur_snap = snap;
14875 
14876         for (;;) {
14877                 cur_elt = safe_malloc(sizeof (*cur_elt));
14878                 uu_list_node_init(cur_elt, &cur_elt->list_node,
14879                     snaplevel_pool);
14880                 cur_elt->sl = level;
14881                 if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
14882                         uu_die(gettext("libuutil error: %s\n"),
14883                             uu_strerror(uu_error()));
14884 
14885                 level = scf_snaplevel_create(g_hndl);
14886                 if (level == NULL)
14887                         scfdie();
14888 
14889                 if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
14890                     level) != SCF_SUCCESS) {
14891                         if (scf_error() != SCF_ERROR_NOT_FOUND)
14892                                 scfdie();
14893 
14894                         scf_snaplevel_destroy(level);
14895                         break;
14896                 }
14897         }
14898 
14899         cur_elt = uu_list_last(cur_levels);
14900         cur_level = cur_elt->sl;
14901 }
14902 
14903 /*
14904  * Copies the properties & values in src to dst.  Assumes src won't change.
14905  * Returns -1 if permission is denied, -2 if another transaction interrupts,
14906  * and 0 on success.
14907  *
14908  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
14909  * property, if it is copied and has type boolean.  (See comment in
14910  * lscf_revert()).
14911  */
14912 static int
14913 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
14914     uint8_t enabled)
14915 {
14916         scf_transaction_t *tx;
14917         scf_iter_t *iter, *viter;
14918         scf_property_t *prop;
14919         scf_value_t *v;
14920         char *nbuf;
14921         int r;
14922 
14923         tx = scf_transaction_create(g_hndl);
14924         if (tx == NULL)
14925                 scfdie();
14926 
14927         if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
14928                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14929                         scfdie();
14930 
14931                 scf_transaction_destroy(tx);
14932 
14933                 return (-1);
14934         }
14935 
14936         if ((iter = scf_iter_create(g_hndl)) == NULL ||
14937             (prop = scf_property_create(g_hndl)) == NULL ||
14938             (viter = scf_iter_create(g_hndl)) == NULL)
14939                 scfdie();
14940 
14941         nbuf = safe_malloc(max_scf_name_len + 1);
14942 
14943         if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
14944                 scfdie();
14945 
14946         for (;;) {
14947                 scf_transaction_entry_t *e;
14948                 scf_type_t ty;
14949 
14950                 r = scf_iter_next_property(iter, prop);
14951                 if (r == -1)
14952                         scfdie();
14953                 if (r == 0)
14954                         break;
14955 
14956                 e = scf_entry_create(g_hndl);
14957                 if (e == NULL)
14958                         scfdie();
14959 
14960                 if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14961                         scfdie();
14962 
14963                 if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14964                         scfdie();
14965 
14966                 if (scf_transaction_property_new(tx, e, nbuf,
14967                     ty) != SCF_SUCCESS)
14968                         scfdie();
14969 
14970                 if ((enabled == 0 || enabled == 1) &&
14971                     strcmp(nbuf, scf_property_enabled) == 0 &&
14972                     ty == SCF_TYPE_BOOLEAN) {
14973                         v = scf_value_create(g_hndl);
14974                         if (v == NULL)
14975                                 scfdie();
14976 
14977                         scf_value_set_boolean(v, enabled);
14978 
14979                         if (scf_entry_add_value(e, v) != 0)
14980                                 scfdie();
14981                 } else {
14982                         if (scf_iter_property_values(viter, prop) != 0)
14983                                 scfdie();
14984 
14985                         for (;;) {
14986                                 v = scf_value_create(g_hndl);
14987                                 if (v == NULL)
14988                                         scfdie();
14989 
14990                                 r = scf_iter_next_value(viter, v);
14991                                 if (r == -1)
14992                                         scfdie();
14993                                 if (r == 0) {
14994                                         scf_value_destroy(v);
14995                                         break;
14996                                 }
14997 
14998                                 if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14999                                         scfdie();
15000                         }
15001                 }
15002         }
15003 
15004         free(nbuf);
15005         scf_iter_destroy(viter);
15006         scf_property_destroy(prop);
15007         scf_iter_destroy(iter);
15008 
15009         r = scf_transaction_commit(tx);
15010         if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15011                 scfdie();
15012 
15013         scf_transaction_destroy_children(tx);
15014         scf_transaction_destroy(tx);
15015 
15016         switch (r) {
15017         case 1:         return (0);
15018         case 0:         return (-2);
15019         case -1:        return (-1);
15020 
15021         default:
15022                 abort();
15023         }
15024 
15025         /* NOTREACHED */
15026 }
15027 
15028 void
15029 lscf_revert(const char *snapname)
15030 {
15031         scf_snapshot_t *snap, *prev;
15032         scf_snaplevel_t *level, *nlevel;
15033         scf_iter_t *iter;
15034         scf_propertygroup_t *pg, *npg;
15035         scf_property_t *prop;
15036         scf_value_t *val;
15037         char *nbuf, *tbuf;
15038         uint8_t enabled;
15039 
15040         lscf_prep_hndl();
15041 
15042         if (cur_inst == NULL) {
15043                 semerr(gettext("Instance not selected.\n"));
15044                 return;
15045         }
15046 
15047         if (snapname != NULL) {
15048                 snap = scf_snapshot_create(g_hndl);
15049                 if (snap == NULL)
15050                         scfdie();
15051 
15052                 if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15053                     SCF_SUCCESS) {
15054                         switch (scf_error()) {
15055                         case SCF_ERROR_INVALID_ARGUMENT:
15056                                 semerr(gettext("Invalid snapshot name "
15057                                     "\"%s\".\n"), snapname);
15058                                 break;
15059 
15060                         case SCF_ERROR_NOT_FOUND:
15061                                 semerr(gettext("No such snapshot.\n"));
15062                                 break;
15063 
15064                         default:
15065                                 scfdie();
15066                         }
15067 
15068                         scf_snapshot_destroy(snap);
15069                         return;
15070                 }
15071         } else {
15072                 if (cur_snap != NULL) {
15073                         snap = cur_snap;
15074                 } else {
15075                         semerr(gettext("No snapshot selected.\n"));
15076                         return;
15077                 }
15078         }
15079 
15080         if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15081             (level = scf_snaplevel_create(g_hndl)) == NULL ||
15082             (iter = scf_iter_create(g_hndl)) == NULL ||
15083             (pg = scf_pg_create(g_hndl)) == NULL ||
15084             (npg = scf_pg_create(g_hndl)) == NULL ||
15085             (prop = scf_property_create(g_hndl)) == NULL ||
15086             (val = scf_value_create(g_hndl)) == NULL)
15087                 scfdie();
15088 
15089         nbuf = safe_malloc(max_scf_name_len + 1);
15090         tbuf = safe_malloc(max_scf_pg_type_len + 1);
15091 
15092         /* Take the "previous" snapshot before we blow away the properties. */
15093         if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15094                 if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15095                         scfdie();
15096         } else {
15097                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15098                         scfdie();
15099 
15100                 if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15101                         scfdie();
15102         }
15103 
15104         /* Save general/enabled, since we're probably going to replace it. */
15105         enabled = 2;
15106         if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15107             scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15108             scf_property_get_value(prop, val) == 0)
15109                 (void) scf_value_get_boolean(val, &enabled);
15110 
15111         if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15112                 if (scf_error() != SCF_ERROR_NOT_FOUND)
15113                         scfdie();
15114 
15115                 goto out;
15116         }
15117 
15118         for (;;) {
15119                 boolean_t isinst;
15120                 uint32_t flags;
15121                 int r;
15122 
15123                 /* Clear the properties from the corresponding entity. */
15124                 isinst = snaplevel_is_instance(level);
15125 
15126                 if (!isinst)
15127                         r = scf_iter_service_pgs(iter, cur_svc);
15128                 else
15129                         r = scf_iter_instance_pgs(iter, cur_inst);
15130                 if (r != SCF_SUCCESS)
15131                         scfdie();
15132 
15133                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15134                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15135                                 scfdie();
15136 
15137                         /* Skip nonpersistent pgs. */
15138                         if (flags & SCF_PG_FLAG_NONPERSISTENT)
15139                                 continue;
15140 
15141                         if (scf_pg_delete(pg) != SCF_SUCCESS) {
15142                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15143                                         scfdie();
15144 
15145                                 semerr(emsg_permission_denied);
15146                                 goto out;
15147                         }
15148                 }
15149                 if (r == -1)
15150                         scfdie();
15151 
15152                 /* Copy the properties to the corresponding entity. */
15153                 if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15154                         scfdie();
15155 
15156                 while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15157                         if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15158                                 scfdie();
15159 
15160                         if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15161                             0)
15162                                 scfdie();
15163 
15164                         if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15165                                 scfdie();
15166 
15167                         if (!isinst)
15168                                 r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15169                                     flags, npg);
15170                         else
15171                                 r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15172                                     flags, npg);
15173                         if (r != SCF_SUCCESS) {
15174                                 if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15175                                         scfdie();
15176 
15177                                 semerr(emsg_permission_denied);
15178                                 goto out;
15179                         }
15180 
15181                         if ((enabled == 0 || enabled == 1) &&
15182                             strcmp(nbuf, scf_pg_general) == 0)
15183                                 r = pg_copy(pg, npg, enabled);
15184                         else
15185                                 r = pg_copy(pg, npg, 2);
15186 
15187                         switch (r) {
15188                         case 0:
15189                                 break;
15190 
15191                         case -1:
15192                                 semerr(emsg_permission_denied);
15193                                 goto out;
15194 
15195                         case -2:
15196                                 semerr(gettext(
15197                                     "Interrupted by another change.\n"));
15198                                 goto out;
15199 
15200                         default:
15201                                 abort();
15202                         }
15203                 }
15204                 if (r == -1)
15205                         scfdie();
15206 
15207                 /* Get next level. */
15208                 nlevel = scf_snaplevel_create(g_hndl);
15209                 if (nlevel == NULL)
15210                         scfdie();
15211 
15212                 if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15213                     SCF_SUCCESS) {
15214                         if (scf_error() != SCF_ERROR_NOT_FOUND)
15215                                 scfdie();
15216 
15217                         scf_snaplevel_destroy(nlevel);
15218                         break;
15219                 }
15220 
15221                 scf_snaplevel_destroy(level);
15222                 level = nlevel;
15223         }
15224 
15225         if (snapname == NULL) {
15226                 lscf_selectsnap(NULL);
15227                 snap = NULL;            /* cur_snap has been destroyed */
15228         }
15229 
15230 out:
15231         free(tbuf);
15232         free(nbuf);
15233         scf_value_destroy(val);
15234         scf_property_destroy(prop);
15235         scf_pg_destroy(npg);
15236         scf_pg_destroy(pg);
15237         scf_iter_destroy(iter);
15238         scf_snaplevel_destroy(level);
15239         scf_snapshot_destroy(prev);
15240         if (snap != cur_snap)
15241                 scf_snapshot_destroy(snap);
15242 }
15243 
15244 void
15245 lscf_refresh(void)
15246 {
15247         ssize_t fmrilen;
15248         size_t bufsz;
15249         char *fmribuf;
15250         int r;
15251 
15252         lscf_prep_hndl();
15253 
15254         if (cur_inst == NULL) {
15255                 semerr(gettext("Instance not selected.\n"));
15256                 return;
15257         }
15258 
15259         bufsz = max_scf_fmri_len + 1;
15260         fmribuf = safe_malloc(bufsz);
15261         fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15262         if (fmrilen < 0) {
15263                 free(fmribuf);
15264                 if (scf_error() != SCF_ERROR_DELETED)
15265                         scfdie();
15266                 scf_instance_destroy(cur_inst);
15267                 cur_inst = NULL;
15268                 warn(emsg_deleted);
15269                 return;
15270         }
15271         assert(fmrilen < bufsz);
15272 
15273         r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15274         switch (r) {
15275         case 0:
15276                 break;
15277 
15278         case ECONNABORTED:
15279                 warn(gettext("Could not refresh %s "
15280                     "(repository connection broken).\n"), fmribuf);
15281                 break;
15282 
15283         case ECANCELED:
15284                 warn(emsg_deleted);
15285                 break;
15286 
15287         case EPERM:
15288                 warn(gettext("Could not refresh %s "
15289                     "(permission denied).\n"), fmribuf);
15290                 break;
15291 
15292         case ENOSPC:
15293                 warn(gettext("Could not refresh %s "
15294                     "(repository server out of resources).\n"),
15295                     fmribuf);
15296                 break;
15297 
15298         case EACCES:
15299         default:
15300                 bad_error("refresh_entity", scf_error());
15301         }
15302 
15303         free(fmribuf);
15304 }
15305 
15306 /*
15307  * describe [-v] [-t] [pg/prop]
15308  */
15309 int
15310 lscf_describe(uu_list_t *args, int hasargs)
15311 {
15312         int ret = 0;
15313         size_t i;
15314         int argc;
15315         char **argv = NULL;
15316         string_list_t *slp;
15317         int do_verbose = 0;
15318         int do_templates = 0;
15319         char *pattern = NULL;
15320 
15321         lscf_prep_hndl();
15322 
15323         if (hasargs != 0)  {
15324                 argc = uu_list_numnodes(args);
15325                 if (argc < 1)
15326                         goto usage;
15327 
15328                 argv = calloc(argc + 1, sizeof (char *));
15329                 if (argv == NULL)
15330                         uu_die(gettext("Out of memory.\n"));
15331 
15332                 for (slp = uu_list_first(args), i = 0;
15333                     slp != NULL;
15334                     slp = uu_list_next(args, slp), ++i)
15335                         argv[i] = slp->str;
15336 
15337                 argv[i] = NULL;
15338 
15339                 /*
15340                  * We start optind = 0 because our list of arguments
15341                  * starts at argv[0]
15342                  */
15343                 optind = 0;
15344                 opterr = 0;
15345                 for (;;) {
15346                         ret = getopt(argc, argv, "vt");
15347                         if (ret == -1)
15348                                 break;
15349 
15350                         switch (ret) {
15351                         case 'v':
15352                                 do_verbose = 1;
15353                                 break;
15354 
15355                         case 't':
15356                                 do_templates = 1;
15357                                 break;
15358 
15359                         case '?':
15360                                 goto usage;
15361 
15362                         default:
15363                                 bad_error("getopt", ret);
15364                         }
15365                 }
15366 
15367                 pattern = argv[optind];
15368         }
15369 
15370         if (cur_inst == NULL && cur_svc == NULL) {
15371                 semerr(emsg_entity_not_selected);
15372                 ret = -1;
15373                 goto out;
15374         }
15375 
15376         /*
15377          * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15378          * output if their last parameter is set to 2.  Less information is
15379          * produced if the parameter is set to 1.
15380          */
15381         if (pattern == NULL) {
15382                 if (do_verbose == 1)
15383                         list_entity_tmpl(2);
15384                 else
15385                         list_entity_tmpl(1);
15386         }
15387 
15388         if (do_templates == 0) {
15389                 if (do_verbose == 1)
15390                         listprop(pattern, 0, 2);
15391                 else
15392                         listprop(pattern, 0, 1);
15393         } else {
15394                 if (do_verbose == 1)
15395                         listtmpl(pattern, 2);
15396                 else
15397                         listtmpl(pattern, 1);
15398         }
15399 
15400         ret = 0;
15401 out:
15402         if (argv != NULL)
15403                 free(argv);
15404         return (ret);
15405 usage:
15406         ret = -2;
15407         goto out;
15408 }
15409 
15410 #define PARAM_ACTIVE    ((const char *) "active")
15411 #define PARAM_INACTIVE  ((const char *) "inactive")
15412 #define PARAM_SMTP_TO   ((const char *) "to")
15413 
15414 /*
15415  * tokenize()
15416  * Breaks down the string according to the tokens passed.
15417  * Caller is responsible for freeing array of pointers returned.
15418  * Returns NULL on failure
15419  */
15420 char **
15421 tokenize(char *str, const char *sep)
15422 {
15423         char *token, *lasts;
15424         char **buf;
15425         int n = 0;      /* number of elements */
15426         int size = 8;   /* size of the array (initial) */
15427 
15428         buf = safe_malloc(size * sizeof (char *));
15429 
15430         for (token = strtok_r(str, sep, &lasts); token != NULL;
15431             token = strtok_r(NULL, sep, &lasts), ++n) {
15432                 if (n + 1 >= size) {
15433                         size *= 2;
15434                         if ((buf = realloc(buf, size * sizeof (char *))) ==
15435                             NULL) {
15436                                 uu_die(gettext("Out of memory"));
15437                         }
15438                 }
15439                 buf[n] = token;
15440         }
15441         /* NULL terminate the pointer array */
15442         buf[n] = NULL;
15443 
15444         return (buf);
15445 }
15446 
15447 int32_t
15448 check_tokens(char **p)
15449 {
15450         int32_t smf = 0;
15451         int32_t fma = 0;
15452 
15453         while (*p) {
15454                 int32_t t = string_to_tset(*p);
15455 
15456                 if (t == 0) {
15457                         if (is_fma_token(*p) == 0)
15458                                 return (INVALID_TOKENS);
15459                         fma = 1; /* this token is an fma event */
15460                 } else {
15461                         smf |= t;
15462                 }
15463 
15464                 if (smf != 0 && fma == 1)
15465                         return (MIXED_TOKENS);
15466                 ++p;
15467         }
15468 
15469         if (smf > 0)
15470                 return (smf);
15471         else if (fma == 1)
15472                 return (FMA_TOKENS);
15473 
15474         return (INVALID_TOKENS);
15475 }
15476 
15477 static int
15478 get_selection_str(char *fmri, size_t sz)
15479 {
15480         if (g_hndl == NULL) {
15481                 semerr(emsg_entity_not_selected);
15482                 return (-1);
15483         } else if (cur_level != NULL) {
15484                 semerr(emsg_invalid_for_snapshot);
15485                 return (-1);
15486         } else {
15487                 lscf_get_selection_str(fmri, sz);
15488         }
15489 
15490         return (0);
15491 }
15492 
15493 void
15494 lscf_delnotify(const char *set, int global)
15495 {
15496         char *str = strdup(set);
15497         char **pgs;
15498         char **p;
15499         int32_t tset;
15500         char *fmri = NULL;
15501 
15502         if (str == NULL)
15503                 uu_die(gettext("Out of memory.\n"));
15504 
15505         pgs = tokenize(str, ",");
15506 
15507         if ((tset = check_tokens(pgs)) > 0) {
15508                 size_t sz = max_scf_fmri_len + 1;
15509 
15510                 fmri = safe_malloc(sz);
15511                 if (global) {
15512                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15513                 } else if (get_selection_str(fmri, sz) != 0) {
15514                         goto out;
15515                 }
15516 
15517                 if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15518                     tset) != SCF_SUCCESS) {
15519                         uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15520                             scf_strerror(scf_error()));
15521                 }
15522         } else if (tset == FMA_TOKENS) {
15523                 if (global) {
15524                         semerr(gettext("Can't use option '-g' with FMA event "
15525                             "definitions\n"));
15526                         goto out;
15527                 }
15528 
15529                 for (p = pgs; *p; ++p) {
15530                         if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15531                             SCF_SUCCESS) {
15532                                 uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15533                                     scf_strerror(scf_error()));
15534                                 goto out;
15535                         }
15536                 }
15537         } else if (tset == MIXED_TOKENS) {
15538                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15539                 goto out;
15540         } else {
15541                 uu_die(gettext("Invalid input.\n"));
15542         }
15543 
15544 out:
15545         free(fmri);
15546         free(pgs);
15547         free(str);
15548 }
15549 
15550 void
15551 lscf_listnotify(const char *set, int global)
15552 {
15553         char *str = safe_strdup(set);
15554         char **pgs;
15555         char **p;
15556         int32_t tset;
15557         nvlist_t *nvl;
15558         char *fmri = NULL;
15559 
15560         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15561                 uu_die(gettext("Out of memory.\n"));
15562 
15563         pgs = tokenize(str, ",");
15564 
15565         if ((tset = check_tokens(pgs)) > 0) {
15566                 size_t sz = max_scf_fmri_len + 1;
15567 
15568                 fmri = safe_malloc(sz);
15569                 if (global) {
15570                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15571                 } else if (get_selection_str(fmri, sz) != 0) {
15572                         goto out;
15573                 }
15574 
15575                 if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15576                     SCF_SUCCESS) {
15577                         if (scf_error() != SCF_ERROR_NOT_FOUND &&
15578                             scf_error() != SCF_ERROR_DELETED)
15579                                 uu_warn(gettext(
15580                                     "Failed listnotify: %s\n"),
15581                                     scf_strerror(scf_error()));
15582                         goto out;
15583                 }
15584 
15585                 listnotify_print(nvl, NULL);
15586         } else if (tset == FMA_TOKENS) {
15587                 if (global) {
15588                         semerr(gettext("Can't use option '-g' with FMA event "
15589                             "definitions\n"));
15590                         goto out;
15591                 }
15592 
15593                 for (p = pgs; *p; ++p) {
15594                         if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15595                             SCF_SUCCESS) {
15596                                 /*
15597                                  * if the preferences have just been deleted
15598                                  * or does not exist, just skip.
15599                                  */
15600                                 if (scf_error() == SCF_ERROR_NOT_FOUND ||
15601                                     scf_error() == SCF_ERROR_DELETED)
15602                                         continue;
15603                                 uu_warn(gettext(
15604                                     "Failed listnotify: %s\n"),
15605                                     scf_strerror(scf_error()));
15606                                 goto out;
15607                         }
15608                         listnotify_print(nvl, re_tag(*p));
15609                 }
15610         } else if (tset == MIXED_TOKENS) {
15611                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15612                 goto out;
15613         } else {
15614                 semerr(gettext("Invalid input.\n"));
15615         }
15616 
15617 out:
15618         nvlist_free(nvl);
15619         free(fmri);
15620         free(pgs);
15621         free(str);
15622 }
15623 
15624 static char *
15625 strip_quotes_and_blanks(char *s)
15626 {
15627         char *start = s;
15628         char *end = strrchr(s, '\"');
15629 
15630         if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15631                 start = s + 1;
15632                 while (isblank(*start))
15633                         start++;
15634                 while (isblank(*(end - 1)) && end > start) {
15635                         end--;
15636                 }
15637                 *end = '\0';
15638         }
15639 
15640         return (start);
15641 }
15642 
15643 static int
15644 set_active(nvlist_t *mech, const char *hier_part)
15645 {
15646         boolean_t b;
15647 
15648         if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15649                 b = B_TRUE;
15650         } else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15651                 b = B_FALSE;
15652         } else {
15653                 return (-1);
15654         }
15655 
15656         if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15657                 uu_die(gettext("Out of memory.\n"));
15658 
15659         return (0);
15660 }
15661 
15662 static int
15663 add_snmp_params(nvlist_t *mech, char *hier_part)
15664 {
15665         return (set_active(mech, hier_part));
15666 }
15667 
15668 static int
15669 add_syslog_params(nvlist_t *mech, char *hier_part)
15670 {
15671         return (set_active(mech, hier_part));
15672 }
15673 
15674 /*
15675  * add_mailto_paramas()
15676  * parse the hier_part of mailto URI
15677  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15678  * or mailto:{[active]|inactive}
15679  */
15680 static int
15681 add_mailto_params(nvlist_t *mech, char *hier_part)
15682 {
15683         const char *tok = "?&";
15684         char *p;
15685         char *lasts;
15686         char *param;
15687         char *val;
15688 
15689         /*
15690          * If the notification parametes are in the form of
15691          *
15692          *   malito:{[active]|inactive}
15693          *
15694          * we set the property accordingly and return.
15695          * Otherwise, we make the notification type active and
15696          * process the hier_part.
15697          */
15698         if (set_active(mech, hier_part) == 0)
15699                 return (0);
15700         else if (set_active(mech, PARAM_ACTIVE) != 0)
15701                 return (-1);
15702 
15703         if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15704                 /*
15705                  * sanity check: we only get here if hier_part = "", but
15706                  * that's handled by set_active
15707                  */
15708                 uu_die("strtok_r");
15709         }
15710 
15711         if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15712                 uu_die(gettext("Out of memory.\n"));
15713 
15714         while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
15715                 if ((param = strtok_r(p, "=", &val)) != NULL)
15716                         if (nvlist_add_string(mech, param, val) != 0)
15717                                 uu_die(gettext("Out of memory.\n"));
15718 
15719         return (0);
15720 }
15721 
15722 static int
15723 uri_split(char *uri, char **scheme, char **hier_part)
15724 {
15725         int r = -1;
15726 
15727         if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
15728             *hier_part == NULL) {
15729                 semerr(gettext("'%s' is not an URI\n"), uri);
15730                 return (r);
15731         }
15732 
15733         if ((r = check_uri_scheme(*scheme)) < 0) {
15734                 semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
15735                 return (r);
15736         }
15737 
15738         return (r);
15739 }
15740 
15741 static int
15742 process_uri(nvlist_t *params, char *uri)
15743 {
15744         char *scheme;
15745         char *hier_part;
15746         nvlist_t *mech;
15747         int index;
15748         int r;
15749 
15750         if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
15751                 return (-1);
15752 
15753         if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
15754                 uu_die(gettext("Out of memory.\n"));
15755 
15756         switch (index) {
15757         case 0:
15758                 /* error messages displayed by called function */
15759                 r = add_mailto_params(mech, hier_part);
15760                 break;
15761 
15762         case 1:
15763                 if ((r = add_snmp_params(mech, hier_part)) != 0)
15764                         semerr(gettext("Not valid parameters: '%s'\n"),
15765                             hier_part);
15766                 break;
15767 
15768         case 2:
15769                 if ((r = add_syslog_params(mech, hier_part)) != 0)
15770                         semerr(gettext("Not valid parameters: '%s'\n"),
15771                             hier_part);
15772                 break;
15773 
15774         default:
15775                 r = -1;
15776         }
15777 
15778         if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
15779             mech) != 0)
15780                 uu_die(gettext("Out of memory.\n"));
15781 
15782         nvlist_free(mech);
15783         return (r);
15784 }
15785 
15786 static int
15787 set_params(nvlist_t *params, char **p)
15788 {
15789         char *uri;
15790 
15791         if (p == NULL)
15792                 /* sanity check */
15793                 uu_die("set_params");
15794 
15795         while (*p) {
15796                 uri = strip_quotes_and_blanks(*p);
15797                 if (process_uri(params, uri) != 0)
15798                         return (-1);
15799 
15800                 ++p;
15801         }
15802 
15803         return (0);
15804 }
15805 
15806 static int
15807 setnotify(const char *e, char **p, int global)
15808 {
15809         char *str = safe_strdup(e);
15810         char **events;
15811         int32_t tset;
15812         int r = -1;
15813         nvlist_t *nvl, *params;
15814         char *fmri = NULL;
15815 
15816         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
15817             nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
15818             nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
15819             SCF_NOTIFY_PARAMS_VERSION) != 0)
15820                 uu_die(gettext("Out of memory.\n"));
15821 
15822         events = tokenize(str, ",");
15823 
15824         if ((tset = check_tokens(events)) > 0) {
15825                 /* SMF state transitions parameters */
15826                 size_t sz = max_scf_fmri_len + 1;
15827 
15828                 fmri = safe_malloc(sz);
15829                 if (global) {
15830                         (void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15831                 } else if (get_selection_str(fmri, sz) != 0) {
15832                         goto out;
15833                 }
15834 
15835                 if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
15836                     nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
15837                         uu_die(gettext("Out of memory.\n"));
15838 
15839                 if ((r = set_params(params, p)) == 0) {
15840                         if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
15841                             params) != 0)
15842                                 uu_die(gettext("Out of memory.\n"));
15843 
15844                         if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
15845                             nvl) != SCF_SUCCESS) {
15846                                 r = -1;
15847                                 uu_warn(gettext(
15848                                     "Failed smf_notify_set_params(3SCF): %s\n"),
15849                                     scf_strerror(scf_error()));
15850                         }
15851                 }
15852         } else if (tset == FMA_TOKENS) {
15853                 /* FMA event parameters */
15854                 if (global) {
15855                         semerr(gettext("Can't use option '-g' with FMA event "
15856                             "definitions\n"));
15857                         goto out;
15858                 }
15859 
15860                 if ((r = set_params(params, p)) != 0)
15861                         goto out;
15862 
15863                 if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
15864                         uu_die(gettext("Out of memory.\n"));
15865 
15866                 while (*events) {
15867                         if (smf_notify_set_params(de_tag(*events), nvl) !=
15868                             SCF_SUCCESS)
15869                                 uu_warn(gettext(
15870                                     "Failed smf_notify_set_params(3SCF) for "
15871                                     "event %s: %s\n"), *events,
15872                                     scf_strerror(scf_error()));
15873                         events++;
15874                 }
15875         } else if (tset == MIXED_TOKENS) {
15876                 semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15877         } else {
15878                 /* Sanity check */
15879                 uu_die(gettext("Invalid input.\n"));
15880         }
15881 
15882 out:
15883         nvlist_free(nvl);
15884         nvlist_free(params);
15885         free(fmri);
15886         free(str);
15887 
15888         return (r);
15889 }
15890 
15891 int
15892 lscf_setnotify(uu_list_t *args)
15893 {
15894         int argc;
15895         char **argv = NULL;
15896         string_list_t *slp;
15897         int global;
15898         char *events;
15899         char **p;
15900         int i;
15901         int ret;
15902 
15903         if ((argc = uu_list_numnodes(args)) < 2)
15904                 goto usage;
15905 
15906         argv = calloc(argc + 1, sizeof (char *));
15907         if (argv == NULL)
15908                 uu_die(gettext("Out of memory.\n"));
15909 
15910         for (slp = uu_list_first(args), i = 0;
15911             slp != NULL;
15912             slp = uu_list_next(args, slp), ++i)
15913                 argv[i] = slp->str;
15914 
15915         argv[i] = NULL;
15916 
15917         if (strcmp(argv[0], "-g") == 0) {
15918                 global = 1;
15919                 events = argv[1];
15920                 p = argv + 2;
15921         } else {
15922                 global = 0;
15923                 events = argv[0];
15924                 p = argv + 1;
15925         }
15926 
15927         ret = setnotify(events, p, global);
15928 
15929 out:
15930         free(argv);
15931         return (ret);
15932 
15933 usage:
15934         ret = -2;
15935         goto out;
15936 }
15937 
15938 /*
15939  * Creates a list of instance name strings associated with a service. If
15940  * wohandcrafted flag is set, get only instances that have a last-import
15941  * snapshot, instances that were imported via svccfg.
15942  */
15943 static uu_list_t *
15944 create_instance_list(scf_service_t *svc, int wohandcrafted)
15945 {
15946         scf_snapshot_t  *snap = NULL;
15947         scf_instance_t  *inst;
15948         scf_iter_t      *inst_iter;
15949         uu_list_t       *instances;
15950         char            *instname;
15951         int             r;
15952 
15953         inst_iter = scf_iter_create(g_hndl);
15954         inst = scf_instance_create(g_hndl);
15955         if (inst_iter == NULL || inst == NULL) {
15956                 uu_warn(gettext("Could not create instance or iterator\n"));
15957                 scfdie();
15958         }
15959 
15960         if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
15961                 return (instances);
15962 
15963         if (scf_iter_service_instances(inst_iter, svc) != 0) {
15964                 switch (scf_error()) {
15965                 case SCF_ERROR_CONNECTION_BROKEN:
15966                 case SCF_ERROR_DELETED:
15967                         uu_list_destroy(instances);
15968                         instances = NULL;
15969                         goto out;
15970 
15971                 case SCF_ERROR_HANDLE_MISMATCH:
15972                 case SCF_ERROR_NOT_BOUND:
15973                 case SCF_ERROR_NOT_SET:
15974                 default:
15975                         bad_error("scf_iter_service_instances", scf_error());
15976                 }
15977         }
15978 
15979         instname = safe_malloc(max_scf_name_len + 1);
15980         while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
15981                 if (r == -1) {
15982                         (void) uu_warn(gettext("Unable to iterate through "
15983                             "instances to create instance list : %s\n"),
15984                             scf_strerror(scf_error()));
15985 
15986                         uu_list_destroy(instances);
15987                         instances = NULL;
15988                         goto out;
15989                 }
15990 
15991                 /*
15992                  * If the instance does not have a last-import snapshot
15993                  * then do not add it to the list as it is a hand-crafted
15994                  * instance that should not be managed.
15995                  */
15996                 if (wohandcrafted) {
15997                         if (snap == NULL &&
15998                             (snap = scf_snapshot_create(g_hndl)) == NULL) {
15999                                 uu_warn(gettext("Unable to create snapshot "
16000                                     "entity\n"));
16001                                 scfdie();
16002                         }
16003 
16004                         if (scf_instance_get_snapshot(inst,
16005                             snap_lastimport, snap) != 0) {
16006                                 switch (scf_error()) {
16007                                 case SCF_ERROR_NOT_FOUND :
16008                                 case SCF_ERROR_DELETED:
16009                                         continue;
16010 
16011                                 case SCF_ERROR_CONNECTION_BROKEN:
16012                                         uu_list_destroy(instances);
16013                                         instances = NULL;
16014                                         goto out;
16015 
16016                                 case SCF_ERROR_HANDLE_MISMATCH:
16017                                 case SCF_ERROR_NOT_BOUND:
16018                                 case SCF_ERROR_NOT_SET:
16019                                 default:
16020                                         bad_error("scf_iter_service_instances",
16021                                             scf_error());
16022                                 }
16023                         }
16024                 }
16025 
16026                 if (scf_instance_get_name(inst, instname,
16027                     max_scf_name_len + 1) < 0) {
16028                         switch (scf_error()) {
16029                         case SCF_ERROR_NOT_FOUND :
16030                                 continue;
16031 
16032                         case SCF_ERROR_CONNECTION_BROKEN:
16033                         case SCF_ERROR_DELETED:
16034                                 uu_list_destroy(instances);
16035                                 instances = NULL;
16036                                 goto out;
16037 
16038                         case SCF_ERROR_HANDLE_MISMATCH:
16039                         case SCF_ERROR_NOT_BOUND:
16040                         case SCF_ERROR_NOT_SET:
16041                         default:
16042                                 bad_error("scf_iter_service_instances",
16043                                     scf_error());
16044                         }
16045                 }
16046 
16047                 add_string(instances, instname);
16048         }
16049 
16050 out:
16051         if (snap)
16052                 scf_snapshot_destroy(snap);
16053 
16054         scf_instance_destroy(inst);
16055         scf_iter_destroy(inst_iter);
16056         free(instname);
16057         return (instances);
16058 }
16059 
16060 /*
16061  * disable an instance but wait for the instance to
16062  * move out of the running state.
16063  *
16064  * Returns 0 : if the instance did not disable
16065  * Returns non-zero : if the instance disabled.
16066  *
16067  */
16068 static int
16069 disable_instance(scf_instance_t *instance)
16070 {
16071         char    *fmribuf;
16072         int     enabled = 10000;
16073 
16074         if (inst_is_running(instance)) {
16075                 fmribuf = safe_malloc(max_scf_name_len + 1);
16076                 if (scf_instance_to_fmri(instance, fmribuf,
16077                     max_scf_name_len + 1) < 0) {
16078                         free(fmribuf);
16079                         return (0);
16080                 }
16081 
16082                 /*
16083                  * If the instance cannot be disabled then return
16084                  * failure to disable and let the caller decide
16085                  * if that is of importance.
16086                  */
16087                 if (smf_disable_instance(fmribuf, 0) != 0) {
16088                         free(fmribuf);
16089                         return (0);
16090                 }
16091 
16092                 while (enabled) {
16093                         if (!inst_is_running(instance))
16094                                 break;
16095 
16096                         (void) poll(NULL, 0, 5);
16097                         enabled = enabled - 5;
16098                 }
16099 
16100                 free(fmribuf);
16101         }
16102 
16103         return (enabled);
16104 }
16105 
16106 /*
16107  * Function to compare two service_manifest structures.
16108  */
16109 /* ARGSUSED2 */
16110 static int
16111 service_manifest_compare(const void *left, const void *right, void *unused)
16112 {
16113         service_manifest_t *l = (service_manifest_t *)left;
16114         service_manifest_t *r = (service_manifest_t *)right;
16115         int rc;
16116 
16117         rc = strcmp(l->servicename, r->servicename);
16118 
16119         return (rc);
16120 }
16121 
16122 /*
16123  * Look for the provided service in the service to manifest
16124  * tree.  If the service exists, and a manifest was provided
16125  * then add the manifest to that service.  If the service
16126  * does not exist, then add the service and manifest to the
16127  * list.
16128  *
16129  * If the manifest is NULL, return the element if found.  If
16130  * the service is not found return NULL.
16131  */
16132 service_manifest_t *
16133 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16134 {
16135         service_manifest_t      elem;
16136         service_manifest_t      *fnelem;
16137         uu_avl_index_t          marker;
16138 
16139         elem.servicename = svnbuf;
16140         fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16141 
16142         if (mfst) {
16143                 if (fnelem) {
16144                         add_string(fnelem->mfstlist, strdup(mfst));
16145                 } else {
16146                         fnelem = safe_malloc(sizeof (*fnelem));
16147                         fnelem->servicename = safe_strdup(svnbuf);
16148                         if ((fnelem->mfstlist =
16149                             uu_list_create(string_pool, NULL, 0)) == NULL)
16150                                 uu_die(gettext("Could not create property "
16151                                     "list: %s\n"), uu_strerror(uu_error()));
16152 
16153                         add_string(fnelem->mfstlist, safe_strdup(mfst));
16154 
16155                         uu_avl_insert(service_manifest_tree, fnelem, marker);
16156                 }
16157         }
16158 
16159         return (fnelem);
16160 }
16161 
16162 /*
16163  * Create the service to manifest avl tree.
16164  *
16165  * Walk each of the manifests currently installed in the supported
16166  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16167  * each of the manifests, inventory the services and add them to
16168  * the tree.
16169  *
16170  * Code that calls this function should make sure fileystem/minimal is online,
16171  * /var is available, since this function walks the /var/svc/manifest directory.
16172  */
16173 static void
16174 create_manifest_tree(void)
16175 {
16176         manifest_info_t **entry;
16177         manifest_info_t **manifests;
16178         uu_list_walk_t  *svcs;
16179         bundle_t        *b;
16180         entity_t        *mfsvc;
16181         char            *dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16182         int             c, status;
16183 
16184         if (service_manifest_pool)
16185                 return;
16186 
16187         /*
16188          * Create the list pool for the service manifest list
16189          */
16190         service_manifest_pool = uu_avl_pool_create("service_manifest",
16191             sizeof (service_manifest_t),
16192             offsetof(service_manifest_t, svcmfst_node),
16193             service_manifest_compare, UU_DEFAULT);
16194         if (service_manifest_pool == NULL)
16195                 uu_die(gettext("service_manifest pool creation failed: %s\n"),
16196                     uu_strerror(uu_error()));
16197 
16198         /*
16199          * Create the list
16200          */
16201         service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16202             UU_DEFAULT);
16203         if (service_manifest_tree == NULL)
16204                 uu_die(gettext("service_manifest tree creation failed: %s\n"),
16205                     uu_strerror(uu_error()));
16206 
16207         /*
16208          * Walk the manifests adding the service(s) from each manifest.
16209          *
16210          * If a service already exists add the manifest to the manifest
16211          * list for that service.  This covers the case of a service that
16212          * is supported by multiple manifest files.
16213          */
16214         for (c = 0; dirs[c]; c++) {
16215                 status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16216                 if (status < 0) {
16217                         uu_warn(gettext("file tree walk of %s encountered "
16218                             "error %s\n"), dirs[c], strerror(errno));
16219 
16220                         uu_avl_destroy(service_manifest_tree);
16221                         service_manifest_tree = NULL;
16222                         return;
16223                 }
16224 
16225                 /*
16226                  * If a manifest that was in the list is not found
16227                  * then skip and go to the next manifest file.
16228                  */
16229                 if (manifests != NULL) {
16230                         for (entry = manifests; *entry != NULL; entry++) {
16231                                 b = internal_bundle_new();
16232                                 if (lxml_get_bundle_file(b, (*entry)->mi_path,
16233                                     SVCCFG_OP_IMPORT) != 0) {
16234                                         internal_bundle_free(b);
16235                                         continue;
16236                                 }
16237 
16238                                 svcs = uu_list_walk_start(b->sc_bundle_services,
16239                                     0);
16240                                 if (svcs == NULL) {
16241                                         internal_bundle_free(b);
16242                                         continue;
16243                                 }
16244 
16245                                 while ((mfsvc = uu_list_walk_next(svcs)) !=
16246                                     NULL) {
16247                                         /* Add manifest to service */
16248                                         (void) find_add_svc_mfst(mfsvc->sc_name,
16249                                             (*entry)->mi_path);
16250                                 }
16251 
16252                                 uu_list_walk_end(svcs);
16253                                 internal_bundle_free(b);
16254                         }
16255 
16256                         free_manifest_array(manifests);
16257                 }
16258         }
16259 }
16260 
16261 /*
16262  * Check the manifest history file to see
16263  * if the service was ever installed from
16264  * one of the supported directories.
16265  *
16266  * Return Values :
16267  *      -1 - if there's error reading manifest history file
16268  *       1 - if the service is not found
16269  *       0 - if the service is found
16270  */
16271 static int
16272 check_mfst_history(const char *svcname)
16273 {
16274         struct stat     st;
16275         caddr_t         mfsthist_start;
16276         char            *svnbuf;
16277         int             fd;
16278         int             r = 1;
16279 
16280         fd = open(MFSTHISTFILE, O_RDONLY);
16281         if (fd == -1) {
16282                 uu_warn(gettext("Unable to open the history file\n"));
16283                 return (-1);
16284         }
16285 
16286         if (fstat(fd, &st) == -1) {
16287                 uu_warn(gettext("Unable to stat the history file\n"));
16288                 return (-1);
16289         }
16290 
16291         mfsthist_start = mmap(0, st.st_size, PROT_READ,
16292             MAP_PRIVATE, fd, 0);
16293 
16294         (void) close(fd);
16295         if (mfsthist_start == MAP_FAILED ||
16296             *(mfsthist_start + st.st_size) != '\0') {
16297                 (void) munmap(mfsthist_start, st.st_size);
16298                 return (-1);
16299         }
16300 
16301         /*
16302          * The manifest history file is a space delimited list
16303          * of service and instance to manifest linkage.  Adding
16304          * a space to the end of the service name so to get only
16305          * the service that is being searched for.
16306          */
16307         svnbuf = uu_msprintf("%s ", svcname);
16308         if (svnbuf == NULL)
16309                 uu_die(gettext("Out of memory"));
16310 
16311         if (strstr(mfsthist_start, svnbuf) != NULL)
16312                 r = 0;
16313 
16314         (void) munmap(mfsthist_start, st.st_size);
16315         uu_free(svnbuf);
16316         return (r);
16317 }
16318 
16319 /*
16320  * Take down each of the instances in the service
16321  * and remove them, then delete the service.
16322  */
16323 static void
16324 teardown_service(scf_service_t *svc, const char *svnbuf)
16325 {
16326         scf_instance_t  *instance;
16327         scf_iter_t      *iter;
16328         int             r;
16329 
16330         safe_printf(gettext("Delete service %s as there are no "
16331             "supporting manifests\n"), svnbuf);
16332 
16333         instance = scf_instance_create(g_hndl);
16334         iter = scf_iter_create(g_hndl);
16335         if (iter == NULL || instance == NULL) {
16336                 uu_warn(gettext("Unable to create supporting entities to "
16337                     "teardown the service\n"));
16338                 uu_warn(gettext("scf error is : %s\n"),
16339                     scf_strerror(scf_error()));
16340                 scfdie();
16341         }
16342 
16343         if (scf_iter_service_instances(iter, svc) != 0) {
16344                 switch (scf_error()) {
16345                 case SCF_ERROR_CONNECTION_BROKEN:
16346                 case SCF_ERROR_DELETED:
16347                         goto out;
16348 
16349                 case SCF_ERROR_HANDLE_MISMATCH:
16350                 case SCF_ERROR_NOT_BOUND:
16351                 case SCF_ERROR_NOT_SET:
16352                 default:
16353                         bad_error("scf_iter_service_instances",
16354                             scf_error());
16355                 }
16356         }
16357 
16358         while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16359                 if (r == -1) {
16360                         uu_warn(gettext("Error - %s\n"),
16361                             scf_strerror(scf_error()));
16362                         goto out;
16363                 }
16364 
16365                 (void) disable_instance(instance);
16366         }
16367 
16368         /*
16369          * Delete the service... forcing the deletion in case
16370          * any of the instances did not disable.
16371          */
16372         (void) lscf_service_delete(svc, 1);
16373 out:
16374         scf_instance_destroy(instance);
16375         scf_iter_destroy(iter);
16376 }
16377 
16378 /*
16379  * Get the list of instances supported by the manifest
16380  * file.
16381  *
16382  * Return 0 if there are no instances.
16383  *
16384  * Return -1 if there are errors attempting to collect instances.
16385  *
16386  * Return the count of instances found if there are no errors.
16387  *
16388  */
16389 static int
16390 check_instance_support(char *mfstfile, const char *svcname,
16391     uu_list_t *instances)
16392 {
16393         uu_list_walk_t  *svcs, *insts;
16394         uu_list_t       *ilist;
16395         bundle_t        *b;
16396         entity_t        *mfsvc, *mfinst;
16397         const char      *svcn;
16398         int             rminstcnt = 0;
16399 
16400 
16401         b = internal_bundle_new();
16402 
16403         if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16404                 /*
16405                  * Unable to process the manifest file for
16406                  * instance support, so just return as
16407                  * don't want to remove instances that could
16408                  * not be accounted for that might exist here.
16409                  */
16410                 internal_bundle_free(b);
16411                 return (0);
16412         }
16413 
16414         svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16415         if (svcs == NULL) {
16416                 internal_bundle_free(b);
16417                 return (0);
16418         }
16419 
16420         svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16421             (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16422 
16423         while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16424                 if (strcmp(mfsvc->sc_name, svcn) == 0)
16425                         break;
16426         }
16427         uu_list_walk_end(svcs);
16428 
16429         if (mfsvc == NULL) {
16430                 internal_bundle_free(b);
16431                 return (-1);
16432         }
16433 
16434         ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16435         if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16436                 internal_bundle_free(b);
16437                 return (0);
16438         }
16439 
16440         while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16441                 /*
16442                  * Remove the instance from the instances list.
16443                  * The unaccounted for instances will be removed
16444                  * from the service once all manifests are
16445                  * processed.
16446                  */
16447                 (void) remove_string(instances,
16448                     mfinst->sc_name);
16449                 rminstcnt++;
16450         }
16451 
16452         uu_list_walk_end(insts);
16453         internal_bundle_free(b);
16454 
16455         return (rminstcnt);
16456 }
16457 
16458 /*
16459  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16460  * 'false' to indicate there's no manifest file(s) found for the service.
16461  */
16462 static void
16463 svc_add_no_support(scf_service_t *svc)
16464 {
16465         char    *pname;
16466 
16467         /* Add no support */
16468         cur_svc = svc;
16469         if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16470                 return;
16471 
16472         pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16473         if (pname == NULL)
16474                 uu_die(gettext("Out of memory.\n"));
16475 
16476         (void) lscf_addpropvalue(pname, "boolean:", "0");
16477 
16478         uu_free(pname);
16479         cur_svc = NULL;
16480 }
16481 
16482 /*
16483  * This function handles all upgrade scenarios for a service that doesn't have
16484  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16485  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16486  * manifest(s) mapping. Manifests under supported directories are inventoried
16487  * and a property is added for each file that delivers configuration to the
16488  * service.  A service that has no corresponding manifest files (deleted) are
16489  * removed from repository.
16490  *
16491  * Unsupported services:
16492  *
16493  * A service is considered unsupported if there is no corresponding manifest
16494  * in the supported directories for that service and the service isn't in the
16495  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16496  * services and instances that were delivered by Solaris before the introduction
16497  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16498  * the path to the manifest file that defined the service or instance.
16499  *
16500  * Another type of unsupported services is 'handcrafted' services,
16501  * programmatically created services or services created by dependent entries
16502  * in other manifests. A handcrafted service is identified by its lack of any
16503  * instance containing last-import snapshot which is created during svccfg
16504  * import.
16505  *
16506  * This function sets a flag for unsupported services by setting services'
16507  * SCF_PG_MANIFESTFILES/support property to false.
16508  */
16509 static void
16510 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16511 {
16512         service_manifest_t      *elem;
16513         uu_list_walk_t          *mfwalk;
16514         string_list_t           *mfile;
16515         uu_list_t               *instances;
16516         const char              *sname;
16517         char                    *pname;
16518         int                     r;
16519 
16520         /*
16521          * Since there's no guarantee manifests under /var are available during
16522          * early import, don't perform any upgrade during early import.
16523          */
16524         if (IGNORE_VAR)
16525                 return;
16526 
16527         if (service_manifest_tree == NULL) {
16528                 create_manifest_tree();
16529         }
16530 
16531         /*
16532          * Find service's supporting manifest(s) after
16533          * stripping off the svc:/ prefix that is part
16534          * of the fmri that is not used in the service
16535          * manifest bundle list.
16536          */
16537         sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16538             strlen(SCF_FMRI_SERVICE_PREFIX);
16539         elem = find_add_svc_mfst(sname, NULL);
16540         if (elem == NULL) {
16541 
16542                 /*
16543                  * A handcrafted service, one that has no instance containing
16544                  * last-import snapshot, should get unsupported flag.
16545                  */
16546                 instances = create_instance_list(svc, 1);
16547                 if (instances == NULL) {
16548                         uu_warn(gettext("Unable to create instance list %s\n"),
16549                             svcname);
16550                         return;
16551                 }
16552 
16553                 if (uu_list_numnodes(instances) == 0) {
16554                         svc_add_no_support(svc);
16555                         return;
16556                 }
16557 
16558                 /*
16559                  * If the service is in the history file, and its supporting
16560                  * manifests are not found, we can safely delete the service
16561                  * because its manifests are removed from the system.
16562                  *
16563                  * Services not found in the history file are not delivered by
16564                  * Solaris and/or delivered outside supported directories, set
16565                  * unsupported flag for these services.
16566                  */
16567                 r = check_mfst_history(svcname);
16568                 if (r == -1)
16569                         return;
16570 
16571                 if (r) {
16572                         /* Set unsupported flag for service  */
16573                         svc_add_no_support(svc);
16574                 } else {
16575                         /* Delete the service */
16576                         teardown_service(svc, svcname);
16577                 }
16578 
16579                 return;
16580         }
16581 
16582         /*
16583          * Walk through the list of manifests and add them
16584          * to the service.
16585          *
16586          * Create a manifestfiles pg and add the property.
16587          */
16588         mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16589         if (mfwalk == NULL)
16590                 return;
16591 
16592         cur_svc = svc;
16593         r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16594         if (r != 0) {
16595                 cur_svc = NULL;
16596                 return;
16597         }
16598 
16599         while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16600                 pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16601                     mhash_filename_to_propname(mfile->str, 0));
16602                 if (pname == NULL)
16603                         uu_die(gettext("Out of memory.\n"));
16604 
16605                 (void) lscf_addpropvalue(pname, "astring:", mfile->str);
16606                 uu_free(pname);
16607         }
16608         uu_list_walk_end(mfwalk);
16609 
16610         cur_svc = NULL;
16611 }
16612 
16613 /*
16614  * Take a service and process the manifest file entires to see if
16615  * there is continued support for the service and instances.  If
16616  * not cleanup as appropriate.
16617  *
16618  * If a service does not have a manifest files entry flag it for
16619  * upgrade and return.
16620  *
16621  * For each manifestfiles property check if the manifest file is
16622  * under the supported /lib/svc/manifest or /var/svc/manifest path
16623  * and if not then return immediately as this service is not supported
16624  * by the cleanup mechanism and should be ignored.
16625  *
16626  * For each manifest file that is supported, check to see if the
16627  * file exists.  If not then remove the manifest file property
16628  * from the service and the smf/manifest hash table.  If the manifest
16629  * file exists then verify that it supports the instances that are
16630  * part of the service.
16631  *
16632  * Once all manifest files have been accounted for remove any instances
16633  * that are no longer supported in the service.
16634  *
16635  * Return values :
16636  * 0 - Successfully processed the service
16637  * non-zero - failed to process the service
16638  *
16639  * On most errors, will just return to wait and get the next service,
16640  * unless in case of unable to create the needed structures which is
16641  * most likely a fatal error that is not going to be recoverable.
16642  */
16643 int
16644 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16645 {
16646         struct mpg_mfile        *mpntov;
16647         struct mpg_mfile        **mpvarry = NULL;
16648         scf_service_t           *svc;
16649         scf_propertygroup_t     *mpg;
16650         scf_property_t          *mp;
16651         scf_value_t             *mv;
16652         scf_iter_t              *mi;
16653         scf_instance_t          *instance;
16654         uu_list_walk_t          *insts;
16655         uu_list_t               *instances = NULL;
16656         boolean_t               activity = (boolean_t)act;
16657         char                    *mpnbuf;
16658         char                    *mpvbuf;
16659         char                    *pgpropbuf;
16660         int                     mfstcnt, rminstct, instct, mfstmax;
16661         int                     index;
16662         int                     r = 0;
16663 
16664         assert(g_hndl != NULL);
16665         assert(wip->svc != NULL);
16666         assert(wip->fmri != NULL);
16667 
16668         svc = wip->svc;
16669 
16670         mpg = scf_pg_create(g_hndl);
16671         mp = scf_property_create(g_hndl);
16672         mi = scf_iter_create(g_hndl);
16673         mv = scf_value_create(g_hndl);
16674         instance = scf_instance_create(g_hndl);
16675 
16676         if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16677             instance == NULL) {
16678                 uu_warn(gettext("Unable to create the supporting entities\n"));
16679                 uu_warn(gettext("scf error is : %s\n"),
16680                     scf_strerror(scf_error()));
16681                 scfdie();
16682         }
16683 
16684         /*
16685          * Get the manifestfiles property group to be parsed for
16686          * files existence.
16687          */
16688         if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16689                 switch (scf_error()) {
16690                 case SCF_ERROR_NOT_FOUND:
16691                         upgrade_svc_mfst_connection(svc, wip->fmri);
16692                         break;
16693                 case SCF_ERROR_DELETED:
16694                 case SCF_ERROR_CONNECTION_BROKEN:
16695                         goto out;
16696 
16697                 case SCF_ERROR_HANDLE_MISMATCH:
16698                 case SCF_ERROR_NOT_BOUND:
16699                 case SCF_ERROR_NOT_SET:
16700                 default:
16701                         bad_error("scf_iter_pg_properties",
16702                             scf_error());
16703                 }
16704 
16705                 goto out;
16706         }
16707 
16708         /*
16709          * Iterate through each of the manifestfiles properties
16710          * to determine what manifestfiles are available.
16711          *
16712          * If a manifest file is supported then increment the
16713          * count and therefore the service is safe.
16714          */
16715         if (scf_iter_pg_properties(mi, mpg) != 0) {
16716                 switch (scf_error()) {
16717                 case SCF_ERROR_DELETED:
16718                 case SCF_ERROR_CONNECTION_BROKEN:
16719                         goto out;
16720 
16721                 case SCF_ERROR_HANDLE_MISMATCH:
16722                 case SCF_ERROR_NOT_BOUND:
16723                 case SCF_ERROR_NOT_SET:
16724                 default:
16725                         bad_error("scf_iter_pg_properties",
16726                             scf_error());
16727                 }
16728         }
16729 
16730         mfstcnt = 0;
16731         mfstmax = MFSTFILE_MAX;
16732         mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
16733         while ((r = scf_iter_next_property(mi, mp)) != 0) {
16734                 if (r == -1)
16735                         bad_error(gettext("Unable to iterate through "
16736                             "manifestfiles properties : %s"),
16737                             scf_error());
16738 
16739                 mpntov = safe_malloc(sizeof (struct mpg_mfile));
16740                 mpnbuf = safe_malloc(max_scf_name_len + 1);
16741                 mpvbuf = safe_malloc(max_scf_value_len + 1);
16742                 mpntov->mpg = mpnbuf;
16743                 mpntov->mfile = mpvbuf;
16744                 mpntov->access = 1;
16745                 if (scf_property_get_name(mp, mpnbuf,
16746                     max_scf_name_len + 1) < 0) {
16747                         uu_warn(gettext("Unable to get manifest file "
16748                             "property : %s\n"),
16749                             scf_strerror(scf_error()));
16750 
16751                         switch (scf_error()) {
16752                         case SCF_ERROR_DELETED:
16753                         case SCF_ERROR_CONNECTION_BROKEN:
16754                                 r = scferror2errno(scf_error());
16755                                 goto out_free;
16756 
16757                         case SCF_ERROR_HANDLE_MISMATCH:
16758                         case SCF_ERROR_NOT_BOUND:
16759                         case SCF_ERROR_NOT_SET:
16760                         default:
16761                                 bad_error("scf_iter_pg_properties",
16762                                     scf_error());
16763                         }
16764                 }
16765 
16766                 /*
16767                  * The support property is a boolean value that indicates
16768                  * if the service is supported for manifest file deletion.
16769                  * Currently at this time there is no code that sets this
16770                  * value to true.  So while we could just let this be caught
16771                  * by the support check below, in the future this by be set
16772                  * to true and require processing.  So for that, go ahead
16773                  * and check here, and just return if false.  Otherwise,
16774                  * fall through expecting that other support checks will
16775                  * handle the entries.
16776                  */
16777                 if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
16778                         uint8_t support;
16779 
16780                         if (scf_property_get_value(mp, mv) != 0 ||
16781                             scf_value_get_boolean(mv, &support) != 0) {
16782                                 uu_warn(gettext("Unable to get the manifest "
16783                                     "support value: %s\n"),
16784                                     scf_strerror(scf_error()));
16785 
16786                                 switch (scf_error()) {
16787                                 case SCF_ERROR_DELETED:
16788                                 case SCF_ERROR_CONNECTION_BROKEN:
16789                                         r = scferror2errno(scf_error());
16790                                         goto out_free;
16791 
16792                                 case SCF_ERROR_HANDLE_MISMATCH:
16793                                 case SCF_ERROR_NOT_BOUND:
16794                                 case SCF_ERROR_NOT_SET:
16795                                 default:
16796                                         bad_error("scf_iter_pg_properties",
16797                                             scf_error());
16798                                 }
16799                         }
16800 
16801                         if (support == B_FALSE)
16802                                 goto out_free;
16803                 }
16804 
16805                 /*
16806                  * Anything with a manifest outside of the supported
16807                  * directories, immediately bail out because that makes
16808                  * this service non-supported.  We don't even want
16809                  * to do instance processing in this case because the
16810                  * instances could be part of the non-supported manifest.
16811                  */
16812                 if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
16813                         /*
16814                          * Manifest is not in /lib/svc, so we need to
16815                          * consider the /var/svc case.
16816                          */
16817                         if (strncmp(mpnbuf, VARSVC_PR,
16818                             strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
16819                                 /*
16820                                  * Either the manifest is not in /var/svc or
16821                                  * /var is not yet mounted.  We ignore the
16822                                  * manifest either because it is not in a
16823                                  * standard location or because we cannot
16824                                  * currently access the manifest.
16825                                  */
16826                                 goto out_free;
16827                         }
16828                 }
16829 
16830                 /*
16831                  * Get the value to of the manifest file for this entry
16832                  * for access verification and instance support
16833                  * verification if it still exists.
16834                  *
16835                  * During Early Manifest Import if the manifest is in
16836                  * /var/svc then it may not yet be available for checking
16837                  * so we must determine if /var/svc is available.  If not
16838                  * then defer until Late Manifest Import to cleanup.
16839                  */
16840                 if (scf_property_get_value(mp, mv) != 0) {
16841                         uu_warn(gettext("Unable to get the manifest file "
16842                             "value: %s\n"),
16843                             scf_strerror(scf_error()));
16844 
16845                         switch (scf_error()) {
16846                         case SCF_ERROR_DELETED:
16847                         case SCF_ERROR_CONNECTION_BROKEN:
16848                                 r = scferror2errno(scf_error());
16849                                 goto out_free;
16850 
16851                         case SCF_ERROR_HANDLE_MISMATCH:
16852                         case SCF_ERROR_NOT_BOUND:
16853                         case SCF_ERROR_NOT_SET:
16854                         default:
16855                                 bad_error("scf_property_get_value",
16856                                     scf_error());
16857                         }
16858                 }
16859 
16860                 if (scf_value_get_astring(mv, mpvbuf,
16861                     max_scf_value_len + 1) < 0) {
16862                         uu_warn(gettext("Unable to get the manifest "
16863                             "file : %s\n"),
16864                             scf_strerror(scf_error()));
16865 
16866                         switch (scf_error()) {
16867                         case SCF_ERROR_DELETED:
16868                         case SCF_ERROR_CONNECTION_BROKEN:
16869                                 r = scferror2errno(scf_error());
16870                                 goto out_free;
16871 
16872                         case SCF_ERROR_HANDLE_MISMATCH:
16873                         case SCF_ERROR_NOT_BOUND:
16874                         case SCF_ERROR_NOT_SET:
16875                         default:
16876                                 bad_error("scf_value_get_astring",
16877                                     scf_error());
16878                         }
16879                 }
16880 
16881                 mpvarry[mfstcnt] = mpntov;
16882                 mfstcnt++;
16883 
16884                 /*
16885                  * Check for the need to reallocate array
16886                  */
16887                 if (mfstcnt >= (mfstmax - 1)) {
16888                         struct mpg_mfile **newmpvarry;
16889 
16890                         mfstmax = mfstmax * 2;
16891                         newmpvarry = realloc(mpvarry,
16892                             sizeof (struct mpg_mfile *) * mfstmax);
16893 
16894                         if (newmpvarry == NULL)
16895                                 goto out_free;
16896 
16897                         mpvarry = newmpvarry;
16898                 }
16899 
16900                 mpvarry[mfstcnt] = NULL;
16901         }
16902 
16903         for (index = 0; mpvarry[index]; index++) {
16904                 mpntov = mpvarry[index];
16905 
16906                 /*
16907                  * Check to see if the manifestfile is accessable, if so hand
16908                  * this service and manifestfile off to be processed for
16909                  * instance support.
16910                  */
16911                 mpnbuf = mpntov->mpg;
16912                 mpvbuf = mpntov->mfile;
16913                 if (access(mpvbuf, F_OK) != 0) {
16914                         mpntov->access = 0;
16915                         activity++;
16916                         mfstcnt--;
16917                         /* Remove the entry from the service */
16918                         cur_svc = svc;
16919                         pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16920                             mpnbuf);
16921                         if (pgpropbuf == NULL)
16922                                 uu_die(gettext("Out of memory.\n"));
16923 
16924                         lscf_delprop(pgpropbuf);
16925                         cur_svc = NULL;
16926 
16927                         uu_free(pgpropbuf);
16928                 }
16929         }
16930 
16931         /*
16932          * If mfstcnt is 0, none of the manifests that supported the service
16933          * existed so remove the service.
16934          */
16935         if (mfstcnt == 0) {
16936                 teardown_service(svc, wip->fmri);
16937 
16938                 goto out_free;
16939         }
16940 
16941         if (activity) {
16942                 int     nosvcsupport = 0;
16943 
16944                 /*
16945                  * If the list of service instances is NULL then
16946                  * create the list.
16947                  */
16948                 instances = create_instance_list(svc, 1);
16949                 if (instances == NULL) {
16950                         uu_warn(gettext("Unable to create instance list %s\n"),
16951                             wip->fmri);
16952                         goto out_free;
16953                 }
16954 
16955                 rminstct = uu_list_numnodes(instances);
16956                 instct = rminstct;
16957 
16958                 for (index = 0; mpvarry[index]; index++) {
16959                         mpntov = mpvarry[index];
16960                         if (mpntov->access == 0)
16961                                 continue;
16962 
16963                         mpnbuf = mpntov->mpg;
16964                         mpvbuf = mpntov->mfile;
16965                         r = check_instance_support(mpvbuf, wip->fmri,
16966                             instances);
16967                         if (r == -1) {
16968                                 nosvcsupport++;
16969                         } else {
16970                                 rminstct -= r;
16971                         }
16972                 }
16973 
16974                 if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
16975                         teardown_service(svc, wip->fmri);
16976 
16977                         goto out_free;
16978                 }
16979         }
16980 
16981         /*
16982          * If there are instances left on the instance list, then
16983          * we must remove them.
16984          */
16985         if (instances != NULL && uu_list_numnodes(instances)) {
16986                 string_list_t *sp;
16987 
16988                 insts = uu_list_walk_start(instances, 0);
16989                 while ((sp = uu_list_walk_next(insts)) != NULL) {
16990                         /*
16991                          * Remove the instance from the instances list.
16992                          */
16993                         safe_printf(gettext("Delete instance %s from "
16994                             "service %s\n"), sp->str, wip->fmri);
16995                         if (scf_service_get_instance(svc, sp->str,
16996                             instance) != SCF_SUCCESS) {
16997                                 (void) uu_warn("scf_error - %s\n",
16998                                     scf_strerror(scf_error()));
16999 
17000                                 continue;
17001                         }
17002 
17003                         (void) disable_instance(instance);
17004 
17005                         (void) lscf_instance_delete(instance, 1);
17006                 }
17007                 scf_instance_destroy(instance);
17008                 uu_list_walk_end(insts);
17009         }
17010 
17011 out_free:
17012         if (mpvarry) {
17013                 struct mpg_mfile *fmpntov;
17014 
17015                 for (index = 0; mpvarry[index]; index++) {
17016                         fmpntov  = mpvarry[index];
17017                         if (fmpntov->mpg == mpnbuf)
17018                                 mpnbuf = NULL;
17019                         free(fmpntov->mpg);
17020 
17021                         if (fmpntov->mfile == mpvbuf)
17022                                 mpvbuf = NULL;
17023                         free(fmpntov->mfile);
17024 
17025                         if (fmpntov == mpntov)
17026                                 mpntov = NULL;
17027                         free(fmpntov);
17028                 }
17029                 if (mpnbuf)
17030                         free(mpnbuf);
17031                 if (mpvbuf)
17032                         free(mpvbuf);
17033                 if (mpntov)
17034                         free(mpntov);
17035 
17036                 free(mpvarry);
17037         }
17038 out:
17039         scf_pg_destroy(mpg);
17040         scf_property_destroy(mp);
17041         scf_iter_destroy(mi);
17042         scf_value_destroy(mv);
17043 
17044         return (0);
17045 }
17046 
17047 /*
17048  * Take the service and search for the manifestfiles property
17049  * in each of the property groups.  If the manifest file
17050  * associated with the property does not exist then remove
17051  * the property group.
17052  */
17053 int
17054 lscf_hash_cleanup()
17055 {
17056         scf_service_t           *svc;
17057         scf_scope_t             *scope;
17058         scf_propertygroup_t     *pg;
17059         scf_property_t          *prop;
17060         scf_value_t             *val;
17061         scf_iter_t              *iter;
17062         char                    *pgname = NULL;
17063         char                    *mfile = NULL;
17064         int                     r;
17065 
17066         svc = scf_service_create(g_hndl);
17067         scope = scf_scope_create(g_hndl);
17068         pg = scf_pg_create(g_hndl);
17069         prop = scf_property_create(g_hndl);
17070         val = scf_value_create(g_hndl);
17071         iter = scf_iter_create(g_hndl);
17072         if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17073             svc == NULL || scope == NULL) {
17074                 uu_warn(gettext("Unable to create a property group, or "
17075                     "property\n"));
17076                 uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17077                     "pg is not NULL");
17078                 uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17079                     "prop is not NULL");
17080                 uu_warn("%s\n", val == NULL ? "val is NULL" :
17081                     "val is not NULL");
17082                 uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17083                     "iter is not NULL");
17084                 uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17085                     "svc is not NULL");
17086                 uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17087                     "scope is not NULL");
17088                 uu_warn(gettext("scf error is : %s\n"),
17089                     scf_strerror(scf_error()));
17090                 scfdie();
17091         }
17092 
17093         if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17094                 switch (scf_error()) {
17095                 case SCF_ERROR_CONNECTION_BROKEN:
17096                 case SCF_ERROR_NOT_FOUND:
17097                         goto out;
17098 
17099                 case SCF_ERROR_HANDLE_MISMATCH:
17100                 case SCF_ERROR_NOT_BOUND:
17101                 case SCF_ERROR_INVALID_ARGUMENT:
17102                 default:
17103                         bad_error("scf_handle_get_scope", scf_error());
17104                 }
17105         }
17106 
17107         if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17108                 uu_warn(gettext("Unable to process the hash service, %s\n"),
17109                     HASH_SVC);
17110                 goto out;
17111         }
17112 
17113         pgname = safe_malloc(max_scf_name_len + 1);
17114         mfile = safe_malloc(max_scf_value_len + 1);
17115 
17116         if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17117                 uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17118                     scf_strerror(scf_error()));
17119                 goto out;
17120         }
17121 
17122         while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17123                 if (r == -1)
17124                         goto out;
17125 
17126                 if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17127                         switch (scf_error()) {
17128                         case SCF_ERROR_DELETED:
17129                                 return (ENODEV);
17130 
17131                         case SCF_ERROR_CONNECTION_BROKEN:
17132                                 return (ECONNABORTED);
17133 
17134                         case SCF_ERROR_NOT_SET:
17135                         case SCF_ERROR_NOT_BOUND:
17136                         default:
17137                                 bad_error("scf_pg_get_name", scf_error());
17138                         }
17139                 }
17140                 if (IGNORE_VAR) {
17141                         if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17142                                 continue;
17143                 }
17144 
17145                 /*
17146                  * If unable to get the property continue as this is an
17147                  * entry that has no location to check against.
17148                  */
17149                 if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17150                         continue;
17151                 }
17152 
17153                 if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17154                         uu_warn(gettext("Unable to get value from %s\n"),
17155                             pgname);
17156 
17157                         switch (scf_error()) {
17158                         case SCF_ERROR_DELETED:
17159                         case SCF_ERROR_CONSTRAINT_VIOLATED:
17160                         case SCF_ERROR_NOT_FOUND:
17161                         case SCF_ERROR_NOT_SET:
17162                                 continue;
17163 
17164                         case SCF_ERROR_CONNECTION_BROKEN:
17165                                 r = scferror2errno(scf_error());
17166                                 goto out;
17167 
17168                         case SCF_ERROR_HANDLE_MISMATCH:
17169                         case SCF_ERROR_NOT_BOUND:
17170                         default:
17171                                 bad_error("scf_property_get_value",
17172                                     scf_error());
17173                         }
17174                 }
17175 
17176                 if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17177                     == -1) {
17178                         uu_warn(gettext("Unable to get astring from %s : %s\n"),
17179                             pgname, scf_strerror(scf_error()));
17180 
17181                         switch (scf_error()) {
17182                         case SCF_ERROR_NOT_SET:
17183                         case SCF_ERROR_TYPE_MISMATCH:
17184                                 continue;
17185 
17186                         default:
17187                                 bad_error("scf_value_get_astring", scf_error());
17188                         }
17189                 }
17190 
17191                 if (access(mfile, F_OK) == 0)
17192                         continue;
17193 
17194                 (void) scf_pg_delete(pg);
17195         }
17196 
17197 out:
17198         scf_scope_destroy(scope);
17199         scf_service_destroy(svc);
17200         scf_pg_destroy(pg);
17201         scf_property_destroy(prop);
17202         scf_value_destroy(val);
17203         scf_iter_destroy(iter);
17204         free(pgname);
17205         free(mfile);
17206 
17207         return (0);
17208 }
17209 
17210 #ifndef NATIVE_BUILD
17211 /* ARGSUSED */
17212 CPL_MATCH_FN(complete_select)
17213 {
17214         const char *arg0, *arg1, *arg1end;
17215         int word_start, err = 0, r;
17216         size_t len;
17217         char *buf;
17218 
17219         lscf_prep_hndl();
17220 
17221         arg0 = line + strspn(line, " \t");
17222         assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17223 
17224         arg1 = arg0 + sizeof ("select") - 1;
17225         arg1 += strspn(arg1, " \t");
17226         word_start = arg1 - line;
17227 
17228         arg1end = arg1 + strcspn(arg1, " \t");
17229         if (arg1end < line + word_end)
17230                 return (0);
17231 
17232         len = line + word_end - arg1;
17233 
17234         buf = safe_malloc(max_scf_name_len + 1);
17235 
17236         if (cur_snap != NULL) {
17237                 return (0);
17238         } else if (cur_inst != NULL) {
17239                 return (0);
17240         } else if (cur_svc != NULL) {
17241                 scf_instance_t *inst;
17242                 scf_iter_t *iter;
17243 
17244                 if ((inst = scf_instance_create(g_hndl)) == NULL ||
17245                     (iter = scf_iter_create(g_hndl)) == NULL)
17246                         scfdie();
17247 
17248                 if (scf_iter_service_instances(iter, cur_svc) != 0)
17249                         scfdie();
17250 
17251                 for (;;) {
17252                         r = scf_iter_next_instance(iter, inst);
17253                         if (r == 0)
17254                                 break;
17255                         if (r != 1)
17256                                 scfdie();
17257 
17258                         if (scf_instance_get_name(inst, buf,
17259                             max_scf_name_len + 1) < 0)
17260                                 scfdie();
17261 
17262                         if (strncmp(buf, arg1, len) == 0) {
17263                                 err = cpl_add_completion(cpl, line, word_start,
17264                                     word_end, buf + len, "", " ");
17265                                 if (err != 0)
17266                                         break;
17267                         }
17268                 }
17269 
17270                 scf_iter_destroy(iter);
17271                 scf_instance_destroy(inst);
17272 
17273                 return (err);
17274         } else {
17275                 scf_service_t *svc;
17276                 scf_iter_t *iter;
17277 
17278                 assert(cur_scope != NULL);
17279 
17280                 if ((svc = scf_service_create(g_hndl)) == NULL ||
17281                     (iter = scf_iter_create(g_hndl)) == NULL)
17282                         scfdie();
17283 
17284                 if (scf_iter_scope_services(iter, cur_scope) != 0)
17285                         scfdie();
17286 
17287                 for (;;) {
17288                         r = scf_iter_next_service(iter, svc);
17289                         if (r == 0)
17290                                 break;
17291                         if (r != 1)
17292                                 scfdie();
17293 
17294                         if (scf_service_get_name(svc, buf,
17295                             max_scf_name_len + 1) < 0)
17296                                 scfdie();
17297 
17298                         if (strncmp(buf, arg1, len) == 0) {
17299                                 err = cpl_add_completion(cpl, line, word_start,
17300                                     word_end, buf + len, "", " ");
17301                                 if (err != 0)
17302                                         break;
17303                         }
17304                 }
17305 
17306                 scf_iter_destroy(iter);
17307                 scf_service_destroy(svc);
17308 
17309                 return (err);
17310         }
17311 }
17312 
17313 /* ARGSUSED */
17314 CPL_MATCH_FN(complete_command)
17315 {
17316         uint32_t scope = 0;
17317 
17318         if (cur_snap != NULL)
17319                 scope = CS_SNAP;
17320         else if (cur_inst != NULL)
17321                 scope = CS_INST;
17322         else if (cur_svc != NULL)
17323                 scope = CS_SVC;
17324         else
17325                 scope = CS_SCOPE;
17326 
17327         return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17328 }
17329 #endif  /* NATIVE_BUILD */