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