xref: /illumos-gate/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision 8a2b682e57a046b828f37bcde1776f131ef4629f)
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 2019 Joyent, Inc.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  * Copyright 2017 RackTop Systems.
27  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
28  */
29 
30 
31 #include <alloca.h>
32 #include <assert.h>
33 #include <ctype.h>
34 #include <door.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <fnmatch.h>
38 #include <inttypes.h>
39 #include <libintl.h>
40 #include <libnvpair.h>
41 #include <libscf.h>
42 #include <libscf_priv.h>
43 #include <libtecla.h>
44 #include <libuutil.h>
45 #include <limits.h>
46 #include <locale.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <time.h>
51 #include <unistd.h>
52 #include <wait.h>
53 #include <poll.h>
54 
55 #include <libxml/tree.h>
56 
57 #include <sys/param.h>
58 
59 #include <sys/stat.h>
60 #include <sys/mman.h>
61 
62 #include "svccfg.h"
63 #include "notify_params.h"
64 #include "manifest_hash.h"
65 #include "manifest_find.h"
66 
67 /* The colon namespaces in each entity (each followed by a newline). */
68 #define	COLON_NAMESPACES	":properties\n"
69 
70 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
71 
72 /* These are characters which the lexer requires to be in double-quotes. */
73 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
74 
75 #define	HASH_SIZE		16
76 #define	HASH_PG_TYPE		"framework"
77 #define	HASH_PG_FLAGS		0
78 #define	HASH_PROP		"md5sum"
79 
80 /*
81  * Indentation used in the output of the describe subcommand.
82  */
83 #define	TMPL_VALUE_INDENT	"  "
84 #define	TMPL_INDENT		"    "
85 #define	TMPL_INDENT_2X		"        "
86 #define	TMPL_CHOICE_INDENT	"      "
87 
88 /*
89  * Directory locations for manifests
90  */
91 #define	VARSVC_DIR		"/var/svc/manifest"
92 #define	LIBSVC_DIR		"/lib/svc/manifest"
93 #define	VARSVC_PR		"var_svc_manifest"
94 #define	LIBSVC_PR		"lib_svc_manifest"
95 #define	MFSTFILEPR		"manifestfile"
96 
97 #define	SUPPORTPROP		"support"
98 
99 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
100 
101 #define	MFSTFILE_MAX		16
102 
103 /*
104  * These are the classes of elements which may appear as children of service
105  * or instance elements in XML manifests.
106  */
107 struct entity_elts {
108 	xmlNodePtr	create_default_instance;
109 	xmlNodePtr	single_instance;
110 	xmlNodePtr	restarter;
111 	xmlNodePtr	dependencies;
112 	xmlNodePtr	dependents;
113 	xmlNodePtr	method_context;
114 	xmlNodePtr	exec_methods;
115 	xmlNodePtr	notify_params;
116 	xmlNodePtr	property_groups;
117 	xmlNodePtr	instances;
118 	xmlNodePtr	stability;
119 	xmlNodePtr	template;
120 };
121 
122 /*
123  * Likewise for property_group elements.
124  */
125 struct pg_elts {
126 	xmlNodePtr	stability;
127 	xmlNodePtr	propvals;
128 	xmlNodePtr	properties;
129 };
130 
131 /*
132  * Likewise for template elements.
133  */
134 struct template_elts {
135 	xmlNodePtr	common_name;
136 	xmlNodePtr	description;
137 	xmlNodePtr	documentation;
138 };
139 
140 /*
141  * Likewise for type (for notification parameters) elements.
142  */
143 struct params_elts {
144 	xmlNodePtr	paramval;
145 	xmlNodePtr	parameter;
146 };
147 
148 /*
149  * This structure is for snaplevel lists.  They are convenient because libscf
150  * only allows traversing snaplevels in one direction.
151  */
152 struct snaplevel {
153 	uu_list_node_t	list_node;
154 	scf_snaplevel_t	*sl;
155 };
156 
157 /*
158  * This is used for communication between lscf_service_export and
159  * export_callback.
160  */
161 struct export_args {
162 	const char	*filename;
163 	int		flags;
164 };
165 
166 /*
167  * The service_manifest structure is used by the upgrade process
168  * to create a list of service to manifest linkages from the manifests
169  * in a set of given directories.
170  */
171 typedef struct service_manifest {
172 	const char	*servicename;
173 	uu_list_t	*mfstlist;
174 	size_t	mfstlist_sz;
175 
176 	uu_avl_node_t	svcmfst_node;
177 } service_manifest_t;
178 
179 /*
180  * Structure to track the manifest file property group
181  * and the manifest file associated with that property
182  * group.  Also, a flag to keep the access once it has
183  * been checked.
184  */
185 struct mpg_mfile {
186 	char	*mpg;
187 	char	*mfile;
188 	int	access;
189 };
190 
191 const char * const scf_pg_general = SCF_PG_GENERAL;
192 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
193 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
194 const char * const scf_property_external = "external";
195 
196 const char * const snap_initial = "initial";
197 const char * const snap_lastimport = "last-import";
198 const char * const snap_previous = "previous";
199 const char * const snap_running = "running";
200 
201 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
202 
203 ssize_t max_scf_fmri_len;
204 ssize_t max_scf_name_len;
205 ssize_t max_scf_pg_type_len;
206 ssize_t max_scf_value_len;
207 static size_t max_scf_len;
208 
209 static scf_scope_t *cur_scope;
210 static scf_service_t *cur_svc = NULL;
211 static scf_instance_t *cur_inst = NULL;
212 static scf_snapshot_t *cur_snap = NULL;
213 static scf_snaplevel_t *cur_level = NULL;
214 
215 static uu_list_pool_t *snaplevel_pool;
216 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
217 static uu_list_t *cur_levels;
218 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
219 
220 static FILE *tempfile = NULL;
221 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
222 
223 static const char *emsg_entity_not_selected;
224 static const char *emsg_permission_denied;
225 static const char *emsg_create_xml;
226 static const char *emsg_cant_modify_snapshots;
227 static const char *emsg_invalid_for_snapshot;
228 static const char *emsg_read_only;
229 static const char *emsg_deleted;
230 static const char *emsg_invalid_pg_name;
231 static const char *emsg_invalid_prop_name;
232 static const char *emsg_no_such_pg;
233 static const char *emsg_fmri_invalid_pg_name;
234 static const char *emsg_fmri_invalid_pg_name_type;
235 static const char *emsg_pg_added;
236 static const char *emsg_pg_changed;
237 static const char *emsg_pg_deleted;
238 static const char *emsg_pg_mod_perm;
239 static const char *emsg_pg_add_perm;
240 static const char *emsg_pg_del_perm;
241 static const char *emsg_snap_perm;
242 static const char *emsg_dpt_dangling;
243 static const char *emsg_dpt_no_dep;
244 
245 static int li_only = 0;
246 static int no_refresh = 0;
247 
248 /* how long in ns we should wait between checks for a pg */
249 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
250 
251 /* import globals, to minimize allocations */
252 static scf_scope_t *imp_scope = NULL;
253 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
254 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
255 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
256 static scf_snapshot_t *imp_rsnap = NULL;
257 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
258 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
259 static scf_property_t *imp_prop = NULL;
260 static scf_iter_t *imp_iter = NULL;
261 static scf_iter_t *imp_rpg_iter = NULL;
262 static scf_iter_t *imp_up_iter = NULL;
263 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
264 static char *imp_str = NULL;
265 static size_t imp_str_sz;
266 static char *imp_tsname = NULL;
267 static char *imp_fe1 = NULL;		/* for fmri_equal() */
268 static char *imp_fe2 = NULL;
269 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
270 
271 /* upgrade_dependents() globals */
272 static scf_instance_t *ud_inst = NULL;
273 static scf_snaplevel_t *ud_snpl = NULL;
274 static scf_propertygroup_t *ud_pg = NULL;
275 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
276 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
277 static int ud_run_dpts_pg_set = 0;
278 static scf_property_t *ud_prop = NULL;
279 static scf_property_t *ud_dpt_prop = NULL;
280 static scf_value_t *ud_val = NULL;
281 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
282 static scf_transaction_t *ud_tx = NULL;
283 static char *ud_ctarg = NULL;
284 static char *ud_oldtarg = NULL;
285 static char *ud_name = NULL;
286 
287 /* export globals */
288 static scf_instance_t *exp_inst;
289 static scf_propertygroup_t *exp_pg;
290 static scf_property_t *exp_prop;
291 static scf_value_t *exp_val;
292 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
293 static char *exp_str;
294 static size_t exp_str_sz;
295 
296 /* cleanup globals */
297 static uu_avl_pool_t *service_manifest_pool = NULL;
298 static uu_avl_t *service_manifest_tree = NULL;
299 
300 static void scfdie_lineno(int lineno) __NORETURN;
301 
302 static char *start_method_names[] = {
303 	"start",
304 	"inetd_start",
305 	NULL
306 };
307 
308 static struct uri_scheme {
309 	const char *scheme;
310 	const char *protocol;
311 } uri_scheme[] = {
312 	{ "mailto", "smtp" },
313 	{ "snmp", "snmp" },
314 	{ "syslog", "syslog" },
315 	{ NULL, NULL }
316 };
317 #define	URI_SCHEME_NUM ((sizeof (uri_scheme) / \
318     sizeof (struct uri_scheme)) - 1)
319 
320 static int
321 check_uri_scheme(const char *scheme)
322 {
323 	int i;
324 
325 	for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
326 		if (strcmp(scheme, uri_scheme[i].scheme) == 0)
327 			return (i);
328 	}
329 
330 	return (-1);
331 }
332 
333 static int
334 check_uri_protocol(const char *p)
335 {
336 	int i;
337 
338 	for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
339 		if (strcmp(p, uri_scheme[i].protocol) == 0)
340 			return (i);
341 	}
342 
343 	return (-1);
344 }
345 
346 /*
347  * For unexpected libscf errors.
348  */
349 #ifdef NDEBUG
350 
351 static void scfdie(void) __NORETURN;
352 
353 static void
354 scfdie(void)
355 {
356 	scf_error_t err = scf_error();
357 
358 	if (err == SCF_ERROR_CONNECTION_BROKEN)
359 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
360 
361 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
362 	    scf_strerror(err));
363 }
364 
365 #else
366 
367 #define	scfdie()	scfdie_lineno(__LINE__)
368 
369 static void
370 scfdie_lineno(int lineno)
371 {
372 	scf_error_t err = scf_error();
373 
374 	if (err == SCF_ERROR_CONNECTION_BROKEN)
375 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
376 
377 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
378 	    ": %s.\n"), lineno, scf_strerror(err));
379 }
380 
381 #endif
382 
383 static void
384 scfwarn(void)
385 {
386 	warn(gettext("Unexpected libscf error: %s.\n"),
387 	    scf_strerror(scf_error()));
388 }
389 
390 /*
391  * Clear a field of a structure.
392  */
393 static int
394 clear_int(void *a, void *b)
395 {
396 	/* LINTED */
397 	*(int *)((char *)a + (size_t)b) = 0;
398 
399 	return (UU_WALK_NEXT);
400 }
401 
402 static int
403 scferror2errno(scf_error_t err)
404 {
405 	switch (err) {
406 	case SCF_ERROR_BACKEND_ACCESS:
407 		return (EACCES);
408 
409 	case SCF_ERROR_BACKEND_READONLY:
410 		return (EROFS);
411 
412 	case SCF_ERROR_CONNECTION_BROKEN:
413 		return (ECONNABORTED);
414 
415 	case SCF_ERROR_CONSTRAINT_VIOLATED:
416 	case SCF_ERROR_INVALID_ARGUMENT:
417 		return (EINVAL);
418 
419 	case SCF_ERROR_DELETED:
420 		return (ECANCELED);
421 
422 	case SCF_ERROR_EXISTS:
423 		return (EEXIST);
424 
425 	case SCF_ERROR_NO_MEMORY:
426 		return (ENOMEM);
427 
428 	case SCF_ERROR_NO_RESOURCES:
429 		return (ENOSPC);
430 
431 	case SCF_ERROR_NOT_FOUND:
432 		return (ENOENT);
433 
434 	case SCF_ERROR_PERMISSION_DENIED:
435 		return (EPERM);
436 
437 	default:
438 #ifndef NDEBUG
439 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
440 		    __FILE__, __LINE__, err);
441 #else
442 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
443 #endif
444 		abort();
445 		/* NOTREACHED */
446 	}
447 }
448 
449 static int
450 entity_get_pg(void *ent, int issvc, const char *name,
451     scf_propertygroup_t *pg)
452 {
453 	if (issvc)
454 		return (scf_service_get_pg(ent, name, pg));
455 	else
456 		return (scf_instance_get_pg(ent, name, pg));
457 }
458 
459 static void
460 entity_destroy(void *ent, int issvc)
461 {
462 	if (issvc)
463 		scf_service_destroy(ent);
464 	else
465 		scf_instance_destroy(ent);
466 }
467 
468 static int
469 get_pg(const char *pg_name, scf_propertygroup_t *pg)
470 {
471 	int ret;
472 
473 	if (cur_level != NULL)
474 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
475 	else if (cur_inst != NULL)
476 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
477 	else
478 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
479 
480 	return (ret);
481 }
482 
483 /*
484  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
485  * snaplevel.  Otherwise find the instance snaplevel.
486  *
487  * Returns
488  *   0 - success
489  *   ECONNABORTED - repository connection broken
490  *   ECANCELED - instance containing snap was deleted
491  *   ENOENT - snap has no snaplevels
492  *	    - requested snaplevel not found
493  */
494 static int
495 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
496 {
497 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
498 		switch (scf_error()) {
499 		case SCF_ERROR_CONNECTION_BROKEN:
500 		case SCF_ERROR_DELETED:
501 		case SCF_ERROR_NOT_FOUND:
502 			return (scferror2errno(scf_error()));
503 
504 		case SCF_ERROR_HANDLE_MISMATCH:
505 		case SCF_ERROR_NOT_BOUND:
506 		case SCF_ERROR_NOT_SET:
507 		default:
508 			bad_error("scf_snapshot_get_base_snaplevel",
509 			    scf_error());
510 		}
511 	}
512 
513 	for (;;) {
514 		ssize_t ssz;
515 
516 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
517 		if (ssz >= 0) {
518 			if (!get_svc)
519 				return (0);
520 		} else {
521 			switch (scf_error()) {
522 			case SCF_ERROR_CONSTRAINT_VIOLATED:
523 				if (get_svc)
524 					return (0);
525 				break;
526 
527 			case SCF_ERROR_DELETED:
528 			case SCF_ERROR_CONNECTION_BROKEN:
529 				return (scferror2errno(scf_error()));
530 
531 			case SCF_ERROR_NOT_SET:
532 			case SCF_ERROR_NOT_BOUND:
533 			default:
534 				bad_error("scf_snaplevel_get_instance_name",
535 				    scf_error());
536 			}
537 		}
538 
539 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
540 			switch (scf_error()) {
541 			case SCF_ERROR_NOT_FOUND:
542 			case SCF_ERROR_CONNECTION_BROKEN:
543 			case SCF_ERROR_DELETED:
544 				return (scferror2errno(scf_error()));
545 
546 			case SCF_ERROR_HANDLE_MISMATCH:
547 			case SCF_ERROR_NOT_BOUND:
548 			case SCF_ERROR_NOT_SET:
549 			case SCF_ERROR_INVALID_ARGUMENT:
550 			default:
551 				bad_error("scf_snaplevel_get_next_snaplevel",
552 				    scf_error());
553 			}
554 		}
555 	}
556 }
557 
558 /*
559  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
560  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
561  * the property group named name in it.  If it doesn't have a running
562  * snapshot, set pg to the instance's current property group named name.
563  *
564  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
565  * its instances.  If one has a running snapshot with a service snaplevel, set
566  * pg to the property group named name in it.  If no such snaplevel could be
567  * found, set pg to the service's current property group named name.
568  *
569  * iter, inst, snap, and snpl are required scratch objects.
570  *
571  * Returns
572  *   0 - success
573  *   ECONNABORTED - repository connection broken
574  *   ECANCELED - ent was deleted
575  *   ENOENT - no such property group
576  *   EINVAL - name is an invalid property group name
577  *   EBADF - found running snapshot is missing a snaplevel
578  */
579 static int
580 entity_get_running_pg(void *ent, int issvc, const char *name,
581     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
582     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
583 {
584 	int r;
585 
586 	if (issvc) {
587 		/* Search for an instance with a running snapshot. */
588 		if (scf_iter_service_instances(iter, ent) != 0) {
589 			switch (scf_error()) {
590 			case SCF_ERROR_DELETED:
591 			case SCF_ERROR_CONNECTION_BROKEN:
592 				return (scferror2errno(scf_error()));
593 
594 			case SCF_ERROR_NOT_SET:
595 			case SCF_ERROR_NOT_BOUND:
596 			case SCF_ERROR_HANDLE_MISMATCH:
597 			default:
598 				bad_error("scf_iter_service_instances",
599 				    scf_error());
600 			}
601 		}
602 
603 		for (;;) {
604 			r = scf_iter_next_instance(iter, inst);
605 			if (r == 0) {
606 				if (scf_service_get_pg(ent, name, pg) == 0)
607 					return (0);
608 
609 				switch (scf_error()) {
610 				case SCF_ERROR_DELETED:
611 				case SCF_ERROR_NOT_FOUND:
612 				case SCF_ERROR_INVALID_ARGUMENT:
613 				case SCF_ERROR_CONNECTION_BROKEN:
614 					return (scferror2errno(scf_error()));
615 
616 				case SCF_ERROR_NOT_BOUND:
617 				case SCF_ERROR_HANDLE_MISMATCH:
618 				case SCF_ERROR_NOT_SET:
619 				default:
620 					bad_error("scf_service_get_pg",
621 					    scf_error());
622 				}
623 			}
624 			if (r != 1) {
625 				switch (scf_error()) {
626 				case SCF_ERROR_DELETED:
627 				case SCF_ERROR_CONNECTION_BROKEN:
628 					return (scferror2errno(scf_error()));
629 
630 				case SCF_ERROR_INVALID_ARGUMENT:
631 				case SCF_ERROR_NOT_SET:
632 				case SCF_ERROR_NOT_BOUND:
633 				case SCF_ERROR_HANDLE_MISMATCH:
634 				default:
635 					bad_error("scf_iter_next_instance",
636 					    scf_error());
637 				}
638 			}
639 
640 			if (scf_instance_get_snapshot(inst, snap_running,
641 			    snap) == 0)
642 				break;
643 
644 			switch (scf_error()) {
645 			case SCF_ERROR_NOT_FOUND:
646 			case SCF_ERROR_DELETED:
647 				continue;
648 
649 			case SCF_ERROR_CONNECTION_BROKEN:
650 				return (ECONNABORTED);
651 
652 			case SCF_ERROR_HANDLE_MISMATCH:
653 			case SCF_ERROR_INVALID_ARGUMENT:
654 			case SCF_ERROR_NOT_SET:
655 			case SCF_ERROR_NOT_BOUND:
656 			default:
657 				bad_error("scf_instance_get_snapshot",
658 				    scf_error());
659 			}
660 		}
661 	} else {
662 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
663 			switch (scf_error()) {
664 			case SCF_ERROR_NOT_FOUND:
665 				break;
666 
667 			case SCF_ERROR_DELETED:
668 			case SCF_ERROR_CONNECTION_BROKEN:
669 				return (scferror2errno(scf_error()));
670 
671 			case SCF_ERROR_NOT_BOUND:
672 			case SCF_ERROR_HANDLE_MISMATCH:
673 			case SCF_ERROR_INVALID_ARGUMENT:
674 			case SCF_ERROR_NOT_SET:
675 			default:
676 				bad_error("scf_instance_get_snapshot",
677 				    scf_error());
678 			}
679 
680 			if (scf_instance_get_pg(ent, name, pg) == 0)
681 				return (0);
682 
683 			switch (scf_error()) {
684 			case SCF_ERROR_DELETED:
685 			case SCF_ERROR_NOT_FOUND:
686 			case SCF_ERROR_INVALID_ARGUMENT:
687 			case SCF_ERROR_CONNECTION_BROKEN:
688 				return (scferror2errno(scf_error()));
689 
690 			case SCF_ERROR_NOT_BOUND:
691 			case SCF_ERROR_HANDLE_MISMATCH:
692 			case SCF_ERROR_NOT_SET:
693 			default:
694 				bad_error("scf_instance_get_pg", scf_error());
695 			}
696 		}
697 	}
698 
699 	r = get_snaplevel(snap, issvc, snpl);
700 	switch (r) {
701 	case 0:
702 		break;
703 
704 	case ECONNABORTED:
705 	case ECANCELED:
706 		return (r);
707 
708 	case ENOENT:
709 		return (EBADF);
710 
711 	default:
712 		bad_error("get_snaplevel", r);
713 	}
714 
715 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
716 		return (0);
717 
718 	switch (scf_error()) {
719 	case SCF_ERROR_DELETED:
720 	case SCF_ERROR_INVALID_ARGUMENT:
721 	case SCF_ERROR_CONNECTION_BROKEN:
722 	case SCF_ERROR_NOT_FOUND:
723 		return (scferror2errno(scf_error()));
724 
725 	case SCF_ERROR_NOT_BOUND:
726 	case SCF_ERROR_HANDLE_MISMATCH:
727 	case SCF_ERROR_NOT_SET:
728 	default:
729 		bad_error("scf_snaplevel_get_pg", scf_error());
730 		/* NOTREACHED */
731 	}
732 }
733 
734 /*
735  * To be registered with atexit().
736  */
737 static void
738 remove_tempfile(void)
739 {
740 	int ret;
741 
742 	if (tempfile != NULL) {
743 		if (fclose(tempfile) == EOF)
744 			(void) warn(gettext("Could not close temporary file"));
745 		tempfile = NULL;
746 	}
747 
748 	if (tempfilename[0] != '\0') {
749 		do {
750 			ret = remove(tempfilename);
751 		} while (ret == -1 && errno == EINTR);
752 		if (ret == -1)
753 			warn(gettext("Could not remove temporary file"));
754 		tempfilename[0] = '\0';
755 	}
756 }
757 
758 /*
759  * Launch private svc.configd(1M) for manipulating alternate repositories.
760  */
761 static void
762 start_private_repository(engine_state_t *est)
763 {
764 	int fd, stat;
765 	struct door_info info;
766 	pid_t pid;
767 
768 	/*
769 	 * 1.  Create a temporary file for the door.
770 	 */
771 	if (est->sc_repo_doorname != NULL)
772 		free((void *)est->sc_repo_doorname);
773 
774 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
775 	if (est->sc_repo_doorname == NULL)
776 		uu_die(gettext("Could not acquire temporary filename"));
777 
778 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
779 	if (fd < 0)
780 		uu_die(gettext("Could not create temporary file for "
781 		    "repository server"));
782 
783 	(void) close(fd);
784 
785 	/*
786 	 * 2.  Launch a configd with that door, using the specified
787 	 * repository.
788 	 */
789 	if ((est->sc_repo_pid = fork()) == 0) {
790 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
791 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
792 		    NULL);
793 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
794 	} else if (est->sc_repo_pid == -1)
795 		uu_die(gettext("Attempt to fork failed"));
796 
797 	do {
798 		pid = waitpid(est->sc_repo_pid, &stat, 0);
799 	} while (pid == -1 && errno == EINTR);
800 
801 	if (pid == -1)
802 		uu_die(gettext("Could not waitpid() for repository server"));
803 
804 	if (!WIFEXITED(stat)) {
805 		uu_die(gettext("Repository server failed (status %d).\n"),
806 		    stat);
807 	} else if (WEXITSTATUS(stat) != 0) {
808 		uu_die(gettext("Repository server failed (exit %d).\n"),
809 		    WEXITSTATUS(stat));
810 	}
811 
812 	/*
813 	 * See if it was successful by checking if the door is a door.
814 	 */
815 
816 	fd = open(est->sc_repo_doorname, O_RDWR);
817 	if (fd < 0)
818 		uu_die(gettext("Could not open door \"%s\""),
819 		    est->sc_repo_doorname);
820 
821 	if (door_info(fd, &info) < 0)
822 		uu_die(gettext("Unexpected door_info() error"));
823 
824 	if (close(fd) == -1)
825 		warn(gettext("Could not close repository door"),
826 		    strerror(errno));
827 
828 	est->sc_repo_pid = info.di_target;
829 }
830 
831 void
832 lscf_cleanup(void)
833 {
834 	/*
835 	 * In the case where we've launched a private svc.configd(1M)
836 	 * instance, we must terminate our child and remove the temporary
837 	 * rendezvous point.
838 	 */
839 	if (est->sc_repo_pid > 0) {
840 		(void) kill(est->sc_repo_pid, SIGTERM);
841 		(void) waitpid(est->sc_repo_pid, NULL, 0);
842 		(void) unlink(est->sc_repo_doorname);
843 
844 		est->sc_repo_pid = 0;
845 	}
846 }
847 
848 void
849 unselect_cursnap(void)
850 {
851 	void *cookie;
852 
853 	cur_level = NULL;
854 
855 	cookie = NULL;
856 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
857 		scf_snaplevel_destroy(cur_elt->sl);
858 		free(cur_elt);
859 	}
860 
861 	scf_snapshot_destroy(cur_snap);
862 	cur_snap = NULL;
863 }
864 
865 void
866 lscf_prep_hndl(void)
867 {
868 	if (g_hndl != NULL)
869 		return;
870 
871 	g_hndl = scf_handle_create(SCF_VERSION);
872 	if (g_hndl == NULL)
873 		scfdie();
874 
875 	if (est->sc_repo_filename != NULL)
876 		start_private_repository(est);
877 
878 	if (est->sc_repo_doorname != NULL) {
879 		scf_value_t *repo_value;
880 		int ret;
881 
882 		repo_value = scf_value_create(g_hndl);
883 		if (repo_value == NULL)
884 			scfdie();
885 
886 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
887 		assert(ret == SCF_SUCCESS);
888 
889 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
890 		    SCF_SUCCESS)
891 			scfdie();
892 
893 		scf_value_destroy(repo_value);
894 	}
895 
896 	if (scf_handle_bind(g_hndl) != 0)
897 		uu_die(gettext("Could not connect to repository server: %s.\n"),
898 		    scf_strerror(scf_error()));
899 
900 	cur_scope = scf_scope_create(g_hndl);
901 	if (cur_scope == NULL)
902 		scfdie();
903 
904 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
905 		scfdie();
906 }
907 
908 static void
909 repository_teardown(void)
910 {
911 	if (g_hndl != NULL) {
912 		if (cur_snap != NULL)
913 			unselect_cursnap();
914 		scf_instance_destroy(cur_inst);
915 		scf_service_destroy(cur_svc);
916 		scf_scope_destroy(cur_scope);
917 		scf_handle_destroy(g_hndl);
918 		cur_inst = NULL;
919 		cur_svc = NULL;
920 		cur_scope = NULL;
921 		g_hndl = NULL;
922 		lscf_cleanup();
923 	}
924 }
925 
926 void
927 lscf_set_repository(const char *repfile, int force)
928 {
929 	repository_teardown();
930 
931 	if (est->sc_repo_filename != NULL) {
932 		free((void *)est->sc_repo_filename);
933 		est->sc_repo_filename = NULL;
934 	}
935 
936 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
937 		/*
938 		 * Repository file does not exist
939 		 * or has no read permission.
940 		 */
941 		warn(gettext("Cannot access \"%s\": %s\n"),
942 		    repfile, strerror(errno));
943 	} else {
944 		est->sc_repo_filename = safe_strdup(repfile);
945 	}
946 
947 	lscf_prep_hndl();
948 }
949 
950 void
951 lscf_init()
952 {
953 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
954 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
955 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
956 	    0 ||
957 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
958 		scfdie();
959 
960 	max_scf_len = max_scf_fmri_len;
961 	if (max_scf_name_len > max_scf_len)
962 		max_scf_len = max_scf_name_len;
963 	if (max_scf_pg_type_len > max_scf_len)
964 		max_scf_len = max_scf_pg_type_len;
965 	/*
966 	 * When a value of type opaque is represented as a string, the
967 	 * string contains 2 characters for every byte of data.  That is
968 	 * because the string contains the hex representation of the opaque
969 	 * value.
970 	 */
971 	if (2 * max_scf_value_len > max_scf_len)
972 		max_scf_len = 2 * max_scf_value_len;
973 
974 	if (atexit(remove_tempfile) != 0)
975 		uu_die(gettext("Could not register atexit() function"));
976 
977 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
978 	emsg_permission_denied = gettext("Permission denied.\n");
979 	emsg_create_xml = gettext("Could not create XML node.\n");
980 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
981 	emsg_invalid_for_snapshot =
982 	    gettext("Invalid operation on a snapshot.\n");
983 	emsg_read_only = gettext("Backend read-only.\n");
984 	emsg_deleted = gettext("Current selection has been deleted.\n");
985 	emsg_invalid_pg_name =
986 	    gettext("Invalid property group name \"%s\".\n");
987 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
988 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
989 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
990 	    "with invalid name \"%s\".\n");
991 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
992 	    "group with invalid name \"%s\" or type \"%s\".\n");
993 	emsg_pg_added = gettext("%s changed unexpectedly "
994 	    "(property group \"%s\" added).\n");
995 	emsg_pg_changed = gettext("%s changed unexpectedly "
996 	    "(property group \"%s\" changed).\n");
997 	emsg_pg_deleted = gettext("%s changed unexpectedly "
998 	    "(property group \"%s\" or an ancestor was deleted).\n");
999 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
1000 	    "in %s (permission denied).\n");
1001 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1002 	    "in %s (permission denied).\n");
1003 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1004 	    "in %s (permission denied).\n");
1005 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1006 	    "(permission denied).\n");
1007 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1008 	    "new dependent \"%s\" because it already exists).  Warning: The "
1009 	    "current dependent's target (%s) does not exist.\n");
1010 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1011 	    "dependent \"%s\" because it already exists).  Warning: The "
1012 	    "current dependent's target (%s) does not have a dependency named "
1013 	    "\"%s\" as expected.\n");
1014 
1015 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1016 	    offsetof(string_list_t, node), NULL, 0);
1017 	snaplevel_pool = uu_list_pool_create("snaplevels",
1018 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1019 	    NULL, 0);
1020 }
1021 
1022 
1023 static const char *
1024 prop_to_typestr(const scf_property_t *prop)
1025 {
1026 	scf_type_t ty;
1027 
1028 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1029 		scfdie();
1030 
1031 	return (scf_type_to_string(ty));
1032 }
1033 
1034 static scf_type_t
1035 string_to_type(const char *type)
1036 {
1037 	size_t len = strlen(type);
1038 	char *buf;
1039 
1040 	if (len == 0 || type[len - 1] != ':')
1041 		return (SCF_TYPE_INVALID);
1042 
1043 	buf = (char *)alloca(len + 1);
1044 	(void) strlcpy(buf, type, len + 1);
1045 	buf[len - 1] = 0;
1046 
1047 	return (scf_string_to_type(buf));
1048 }
1049 
1050 static scf_value_t *
1051 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1052 {
1053 	scf_value_t *v;
1054 	char *dup, *nstr;
1055 	size_t len;
1056 
1057 	v = scf_value_create(g_hndl);
1058 	if (v == NULL)
1059 		scfdie();
1060 
1061 	len = strlen(str);
1062 	if (require_quotes &&
1063 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1064 		semerr(gettext("Multiple string values or string values "
1065 		    "with spaces must be quoted with '\"'.\n"));
1066 		scf_value_destroy(v);
1067 		return (NULL);
1068 	}
1069 
1070 	nstr = dup = safe_strdup(str);
1071 	if (dup[0] == '\"') {
1072 		/*
1073 		 * Strip out the first and the last quote.
1074 		 */
1075 		dup[len - 1] = '\0';
1076 		nstr = dup + 1;
1077 	}
1078 
1079 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1080 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1081 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1082 		    scf_type_to_string(ty), nstr);
1083 		scf_value_destroy(v);
1084 		v = NULL;
1085 	}
1086 	free(dup);
1087 	return (v);
1088 }
1089 
1090 /*
1091  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1092  * Optionally append a comment prefix ('#') to newlines ('\n').
1093  */
1094 static int
1095 quote_and_print(const char *str, FILE *strm, int commentnl)
1096 {
1097 	const char *cp;
1098 
1099 	for (cp = str; *cp != '\0'; ++cp) {
1100 		if (*cp == '"' || *cp == '\\')
1101 			(void) putc('\\', strm);
1102 
1103 		(void) putc(*cp, strm);
1104 
1105 		if (commentnl && *cp == '\n') {
1106 			(void) putc('#', strm);
1107 		}
1108 	}
1109 
1110 	return (ferror(strm));
1111 }
1112 
1113 /*
1114  * These wrappers around lowlevel functions provide consistent error checking
1115  * and warnings.
1116  */
1117 static int
1118 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1119 {
1120 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1121 		return (0);
1122 
1123 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1124 		scfdie();
1125 
1126 	if (g_verbose) {
1127 		ssize_t len;
1128 		char *fmri;
1129 
1130 		len = scf_pg_to_fmri(pg, NULL, 0);
1131 		if (len < 0)
1132 			scfdie();
1133 
1134 		fmri = safe_malloc(len + 1);
1135 
1136 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1137 			scfdie();
1138 
1139 		warn(gettext("Expected property %s of property group %s is "
1140 		    "missing.\n"), propname, fmri);
1141 
1142 		free(fmri);
1143 	}
1144 
1145 	return (-1);
1146 }
1147 
1148 static int
1149 prop_check_type(scf_property_t *prop, scf_type_t ty)
1150 {
1151 	scf_type_t pty;
1152 
1153 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1154 		scfdie();
1155 
1156 	if (ty == pty)
1157 		return (0);
1158 
1159 	if (g_verbose) {
1160 		ssize_t len;
1161 		char *fmri;
1162 		const char *tystr;
1163 
1164 		len = scf_property_to_fmri(prop, NULL, 0);
1165 		if (len < 0)
1166 			scfdie();
1167 
1168 		fmri = safe_malloc(len + 1);
1169 
1170 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1171 			scfdie();
1172 
1173 		tystr = scf_type_to_string(ty);
1174 		if (tystr == NULL)
1175 			tystr = "?";
1176 
1177 		warn(gettext("Property %s is not of expected type %s.\n"),
1178 		    fmri, tystr);
1179 
1180 		free(fmri);
1181 	}
1182 
1183 	return (-1);
1184 }
1185 
1186 static int
1187 prop_get_val(scf_property_t *prop, scf_value_t *val)
1188 {
1189 	scf_error_t err;
1190 
1191 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1192 		return (0);
1193 
1194 	err = scf_error();
1195 
1196 	if (err != SCF_ERROR_NOT_FOUND &&
1197 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1198 	    err != SCF_ERROR_PERMISSION_DENIED)
1199 		scfdie();
1200 
1201 	if (g_verbose) {
1202 		ssize_t len;
1203 		char *fmri, *emsg;
1204 
1205 		len = scf_property_to_fmri(prop, NULL, 0);
1206 		if (len < 0)
1207 			scfdie();
1208 
1209 		fmri = safe_malloc(len + 1);
1210 
1211 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1212 			scfdie();
1213 
1214 		if (err == SCF_ERROR_NOT_FOUND)
1215 			emsg = gettext("Property %s has no values; expected "
1216 			    "one.\n");
1217 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1218 			emsg = gettext("Property %s has multiple values; "
1219 			    "expected one.\n");
1220 		else
1221 			emsg = gettext("No permission to read property %s.\n");
1222 
1223 		warn(emsg, fmri);
1224 
1225 		free(fmri);
1226 	}
1227 
1228 	return (-1);
1229 }
1230 
1231 
1232 static boolean_t
1233 snaplevel_is_instance(const scf_snaplevel_t *level)
1234 {
1235 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1236 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1237 			scfdie();
1238 		return (0);
1239 	} else {
1240 		return (1);
1241 	}
1242 }
1243 
1244 /*
1245  * Decode FMRI into a service or instance, and put the result in *ep.  If
1246  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1247  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1248  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1249  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1250  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1251  * whether *ep is a service.
1252  */
1253 static scf_error_t
1254 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1255 {
1256 	char *fmri_copy;
1257 	const char *sstr, *istr, *pgstr;
1258 	scf_service_t *svc;
1259 	scf_instance_t *inst;
1260 
1261 	fmri_copy = strdup(fmri);
1262 	if (fmri_copy == NULL)
1263 		return (SCF_ERROR_NO_MEMORY);
1264 
1265 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1266 	    SCF_SUCCESS) {
1267 		free(fmri_copy);
1268 		return (SCF_ERROR_INVALID_ARGUMENT);
1269 	}
1270 
1271 	free(fmri_copy);
1272 
1273 	if (sstr == NULL || pgstr != NULL)
1274 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1275 
1276 	if (istr == NULL) {
1277 		svc = scf_service_create(h);
1278 		if (svc == NULL)
1279 			return (SCF_ERROR_NO_MEMORY);
1280 
1281 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1282 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1283 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1284 				scfdie();
1285 
1286 			return (SCF_ERROR_NOT_FOUND);
1287 		}
1288 
1289 		*ep = svc;
1290 		*isservice = 1;
1291 	} else {
1292 		inst = scf_instance_create(h);
1293 		if (inst == NULL)
1294 			return (SCF_ERROR_NO_MEMORY);
1295 
1296 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1297 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1298 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1299 				scfdie();
1300 
1301 			return (SCF_ERROR_NOT_FOUND);
1302 		}
1303 
1304 		*ep = inst;
1305 		*isservice = 0;
1306 	}
1307 
1308 	return (SCF_ERROR_NONE);
1309 }
1310 
1311 /*
1312  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1313  * *ep, and set or clear *isservicep if it is a service or an instance.
1314  * Returns
1315  *   SCF_ERROR_NONE - success
1316  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1317  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1318  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1319  *   SCF_ERROR_NOT_FOUND - no such scope
1320  *   SCF_ERROR_PERMISSION_DENIED
1321  *   SCF_ERROR_BACKEND_READONLY
1322  *   SCF_ERROR_BACKEND_ACCESS
1323  */
1324 static scf_error_t
1325 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1326 {
1327 	char *fmri_copy;
1328 	const char *scstr, *sstr, *istr, *pgstr;
1329 	scf_scope_t *scope = NULL;
1330 	scf_service_t *svc = NULL;
1331 	scf_instance_t *inst = NULL;
1332 	scf_error_t scfe;
1333 
1334 	fmri_copy = safe_strdup(fmri);
1335 
1336 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1337 	    0) {
1338 		free(fmri_copy);
1339 		return (SCF_ERROR_INVALID_ARGUMENT);
1340 	}
1341 
1342 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1343 		free(fmri_copy);
1344 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1345 	}
1346 
1347 	*ep = NULL;
1348 
1349 	if ((scope = scf_scope_create(h)) == NULL ||
1350 	    (svc = scf_service_create(h)) == NULL ||
1351 	    (inst = scf_instance_create(h)) == NULL) {
1352 		scfe = SCF_ERROR_NO_MEMORY;
1353 		goto out;
1354 	}
1355 
1356 get_scope:
1357 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1358 		switch (scf_error()) {
1359 		case SCF_ERROR_CONNECTION_BROKEN:
1360 			scfdie();
1361 			/* NOTREACHED */
1362 
1363 		case SCF_ERROR_NOT_FOUND:
1364 			scfe = SCF_ERROR_NOT_FOUND;
1365 			goto out;
1366 
1367 		case SCF_ERROR_HANDLE_MISMATCH:
1368 		case SCF_ERROR_NOT_BOUND:
1369 		case SCF_ERROR_INVALID_ARGUMENT:
1370 		default:
1371 			bad_error("scf_handle_get_scope", scf_error());
1372 		}
1373 	}
1374 
1375 get_svc:
1376 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1377 		switch (scf_error()) {
1378 		case SCF_ERROR_CONNECTION_BROKEN:
1379 			scfdie();
1380 			/* NOTREACHED */
1381 
1382 		case SCF_ERROR_DELETED:
1383 			goto get_scope;
1384 
1385 		case SCF_ERROR_NOT_FOUND:
1386 			break;
1387 
1388 		case SCF_ERROR_HANDLE_MISMATCH:
1389 		case SCF_ERROR_INVALID_ARGUMENT:
1390 		case SCF_ERROR_NOT_BOUND:
1391 		case SCF_ERROR_NOT_SET:
1392 		default:
1393 			bad_error("scf_scope_get_service", scf_error());
1394 		}
1395 
1396 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1397 			switch (scf_error()) {
1398 			case SCF_ERROR_CONNECTION_BROKEN:
1399 				scfdie();
1400 				/* NOTREACHED */
1401 
1402 			case SCF_ERROR_DELETED:
1403 				goto get_scope;
1404 
1405 			case SCF_ERROR_PERMISSION_DENIED:
1406 			case SCF_ERROR_BACKEND_READONLY:
1407 			case SCF_ERROR_BACKEND_ACCESS:
1408 				scfe = scf_error();
1409 				goto out;
1410 
1411 			case SCF_ERROR_HANDLE_MISMATCH:
1412 			case SCF_ERROR_INVALID_ARGUMENT:
1413 			case SCF_ERROR_NOT_BOUND:
1414 			case SCF_ERROR_NOT_SET:
1415 			default:
1416 				bad_error("scf_scope_get_service", scf_error());
1417 			}
1418 		}
1419 	}
1420 
1421 	if (istr == NULL) {
1422 		scfe = SCF_ERROR_NONE;
1423 		*ep = svc;
1424 		*isservicep = 1;
1425 		goto out;
1426 	}
1427 
1428 get_inst:
1429 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1430 		switch (scf_error()) {
1431 		case SCF_ERROR_CONNECTION_BROKEN:
1432 			scfdie();
1433 			/* NOTREACHED */
1434 
1435 		case SCF_ERROR_DELETED:
1436 			goto get_svc;
1437 
1438 		case SCF_ERROR_NOT_FOUND:
1439 			break;
1440 
1441 		case SCF_ERROR_HANDLE_MISMATCH:
1442 		case SCF_ERROR_INVALID_ARGUMENT:
1443 		case SCF_ERROR_NOT_BOUND:
1444 		case SCF_ERROR_NOT_SET:
1445 		default:
1446 			bad_error("scf_service_get_instance", scf_error());
1447 		}
1448 
1449 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1450 			switch (scf_error()) {
1451 			case SCF_ERROR_CONNECTION_BROKEN:
1452 				scfdie();
1453 				/* NOTREACHED */
1454 
1455 			case SCF_ERROR_DELETED:
1456 				goto get_svc;
1457 
1458 			case SCF_ERROR_PERMISSION_DENIED:
1459 			case SCF_ERROR_BACKEND_READONLY:
1460 			case SCF_ERROR_BACKEND_ACCESS:
1461 				scfe = scf_error();
1462 				goto out;
1463 
1464 			case SCF_ERROR_HANDLE_MISMATCH:
1465 			case SCF_ERROR_INVALID_ARGUMENT:
1466 			case SCF_ERROR_NOT_BOUND:
1467 			case SCF_ERROR_NOT_SET:
1468 			default:
1469 				bad_error("scf_service_add_instance",
1470 				    scf_error());
1471 			}
1472 		}
1473 	}
1474 
1475 	scfe = SCF_ERROR_NONE;
1476 	*ep = inst;
1477 	*isservicep = 0;
1478 
1479 out:
1480 	if (*ep != inst)
1481 		scf_instance_destroy(inst);
1482 	if (*ep != svc)
1483 		scf_service_destroy(svc);
1484 	scf_scope_destroy(scope);
1485 	free(fmri_copy);
1486 	return (scfe);
1487 }
1488 
1489 /*
1490  * Create or update a snapshot of inst.  snap is a required scratch object.
1491  *
1492  * Returns
1493  *   0 - success
1494  *   ECONNABORTED - repository connection broken
1495  *   EPERM - permission denied
1496  *   ENOSPC - configd is out of resources
1497  *   ECANCELED - inst was deleted
1498  *   -1 - unknown libscf error (message printed)
1499  */
1500 static int
1501 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1502 {
1503 again:
1504 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1505 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1506 			switch (scf_error()) {
1507 			case SCF_ERROR_CONNECTION_BROKEN:
1508 			case SCF_ERROR_PERMISSION_DENIED:
1509 			case SCF_ERROR_NO_RESOURCES:
1510 				return (scferror2errno(scf_error()));
1511 
1512 			case SCF_ERROR_NOT_SET:
1513 			case SCF_ERROR_INVALID_ARGUMENT:
1514 			default:
1515 				bad_error("_scf_snapshot_take_attach",
1516 				    scf_error());
1517 			}
1518 		}
1519 	} else {
1520 		switch (scf_error()) {
1521 		case SCF_ERROR_NOT_FOUND:
1522 			break;
1523 
1524 		case SCF_ERROR_DELETED:
1525 		case SCF_ERROR_CONNECTION_BROKEN:
1526 			return (scferror2errno(scf_error()));
1527 
1528 		case SCF_ERROR_HANDLE_MISMATCH:
1529 		case SCF_ERROR_NOT_BOUND:
1530 		case SCF_ERROR_INVALID_ARGUMENT:
1531 		case SCF_ERROR_NOT_SET:
1532 		default:
1533 			bad_error("scf_instance_get_snapshot", scf_error());
1534 		}
1535 
1536 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1537 			switch (scf_error()) {
1538 			case SCF_ERROR_EXISTS:
1539 				goto again;
1540 
1541 			case SCF_ERROR_CONNECTION_BROKEN:
1542 			case SCF_ERROR_NO_RESOURCES:
1543 			case SCF_ERROR_PERMISSION_DENIED:
1544 				return (scferror2errno(scf_error()));
1545 
1546 			default:
1547 				scfwarn();
1548 				return (-1);
1549 
1550 			case SCF_ERROR_NOT_SET:
1551 			case SCF_ERROR_INTERNAL:
1552 			case SCF_ERROR_INVALID_ARGUMENT:
1553 			case SCF_ERROR_HANDLE_MISMATCH:
1554 				bad_error("_scf_snapshot_take_new",
1555 				    scf_error());
1556 			}
1557 		}
1558 	}
1559 
1560 	return (0);
1561 }
1562 
1563 static int
1564 refresh_running_snapshot(void *entity)
1565 {
1566 	scf_snapshot_t *snap;
1567 	int r;
1568 
1569 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1570 		scfdie();
1571 	r = take_snap(entity, snap_running, snap);
1572 	scf_snapshot_destroy(snap);
1573 
1574 	return (r);
1575 }
1576 
1577 /*
1578  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1579  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1580  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1581  * for scratch space.  Returns
1582  *   0 - success
1583  *   ECONNABORTED - repository connection broken
1584  *   ECANCELED - entity was deleted
1585  *   EACCES - backend denied access
1586  *   EPERM - permission denied
1587  *   ENOSPC - repository server out of resources
1588  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1589  */
1590 static int
1591 refresh_entity(int isservice, void *entity, const char *fmri,
1592     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1593 {
1594 	scf_error_t scfe;
1595 	int r;
1596 
1597 	if (!isservice) {
1598 		/*
1599 		 * Let restarter handles refreshing and making new running
1600 		 * snapshot only if operating on a live repository and not
1601 		 * running in early import.
1602 		 */
1603 		if (est->sc_repo_filename == NULL &&
1604 		    est->sc_repo_doorname == NULL &&
1605 		    est->sc_in_emi == 0) {
1606 			if (_smf_refresh_instance_i(entity) == 0) {
1607 				if (g_verbose)
1608 					warn(gettext("Refreshed %s.\n"), fmri);
1609 				return (0);
1610 			}
1611 
1612 			switch (scf_error()) {
1613 			case SCF_ERROR_BACKEND_ACCESS:
1614 				return (EACCES);
1615 
1616 			case SCF_ERROR_PERMISSION_DENIED:
1617 				return (EPERM);
1618 
1619 			default:
1620 				return (-1);
1621 			}
1622 		} else {
1623 			r = refresh_running_snapshot(entity);
1624 			switch (r) {
1625 			case 0:
1626 				break;
1627 
1628 			case ECONNABORTED:
1629 			case ECANCELED:
1630 			case EPERM:
1631 			case ENOSPC:
1632 				break;
1633 
1634 			default:
1635 				bad_error("refresh_running_snapshot",
1636 				    scf_error());
1637 			}
1638 
1639 			return (r);
1640 		}
1641 	}
1642 
1643 	if (scf_iter_service_instances(iter, entity) != 0) {
1644 		switch (scf_error()) {
1645 		case SCF_ERROR_CONNECTION_BROKEN:
1646 			return (ECONNABORTED);
1647 
1648 		case SCF_ERROR_DELETED:
1649 			return (ECANCELED);
1650 
1651 		case SCF_ERROR_HANDLE_MISMATCH:
1652 		case SCF_ERROR_NOT_BOUND:
1653 		case SCF_ERROR_NOT_SET:
1654 		default:
1655 			bad_error("scf_iter_service_instances", scf_error());
1656 		}
1657 	}
1658 
1659 	for (;;) {
1660 		r = scf_iter_next_instance(iter, inst);
1661 		if (r == 0)
1662 			break;
1663 		if (r != 1) {
1664 			switch (scf_error()) {
1665 			case SCF_ERROR_CONNECTION_BROKEN:
1666 				return (ECONNABORTED);
1667 
1668 			case SCF_ERROR_DELETED:
1669 				return (ECANCELED);
1670 
1671 			case SCF_ERROR_HANDLE_MISMATCH:
1672 			case SCF_ERROR_NOT_BOUND:
1673 			case SCF_ERROR_NOT_SET:
1674 			case SCF_ERROR_INVALID_ARGUMENT:
1675 			default:
1676 				bad_error("scf_iter_next_instance",
1677 				    scf_error());
1678 			}
1679 		}
1680 
1681 		/*
1682 		 * Similarly, just take a new running snapshot if operating on
1683 		 * a non-live repository or running during early import.
1684 		 */
1685 		if (est->sc_repo_filename != NULL ||
1686 		    est->sc_repo_doorname != NULL ||
1687 		    est->sc_in_emi == 1) {
1688 			r = refresh_running_snapshot(inst);
1689 			switch (r) {
1690 			case 0:
1691 				continue;
1692 
1693 			case ECONNABORTED:
1694 			case ECANCELED:
1695 			case EPERM:
1696 			case ENOSPC:
1697 				break;
1698 			default:
1699 				bad_error("refresh_running_snapshot",
1700 				    scf_error());
1701 			}
1702 
1703 			return (r);
1704 
1705 		}
1706 
1707 		if (_smf_refresh_instance_i(inst) == 0) {
1708 			if (g_verbose) {
1709 				if (scf_instance_get_name(inst, name_buf,
1710 				    max_scf_name_len + 1) < 0)
1711 					(void) strcpy(name_buf, "?");
1712 
1713 				warn(gettext("Refreshed %s:%s.\n"),
1714 				    fmri, name_buf);
1715 			}
1716 		} else {
1717 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1718 			    g_verbose) {
1719 				scfe = scf_error();
1720 
1721 				if (scf_instance_to_fmri(inst, name_buf,
1722 				    max_scf_name_len + 1) < 0)
1723 					(void) strcpy(name_buf, "?");
1724 
1725 				warn(gettext(
1726 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1727 				    name_buf, scf_strerror(scfe));
1728 			}
1729 		}
1730 	}
1731 
1732 	return (0);
1733 }
1734 
1735 static void
1736 private_refresh(void)
1737 {
1738 	scf_instance_t *pinst = NULL;
1739 	scf_iter_t *piter = NULL;
1740 	ssize_t fmrilen;
1741 	size_t bufsz;
1742 	char *fmribuf;
1743 	void *ent;
1744 	int issvc;
1745 	int r;
1746 
1747 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1748 		return;
1749 
1750 	assert(cur_svc != NULL);
1751 
1752 	bufsz = max_scf_fmri_len + 1;
1753 	fmribuf = safe_malloc(bufsz);
1754 	if (cur_inst) {
1755 		issvc = 0;
1756 		ent = cur_inst;
1757 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1758 	} else {
1759 		issvc = 1;
1760 		ent = cur_svc;
1761 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1762 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1763 			scfdie();
1764 
1765 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1766 			scfdie();
1767 	}
1768 	if (fmrilen < 0) {
1769 		free(fmribuf);
1770 		if (scf_error() != SCF_ERROR_DELETED)
1771 			scfdie();
1772 
1773 		warn(emsg_deleted);
1774 		return;
1775 	}
1776 	assert(fmrilen < bufsz);
1777 
1778 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1779 	switch (r) {
1780 	case 0:
1781 		break;
1782 
1783 	case ECONNABORTED:
1784 		warn(gettext("Could not refresh %s "
1785 		    "(repository connection broken).\n"), fmribuf);
1786 		break;
1787 
1788 	case ECANCELED:
1789 		warn(emsg_deleted);
1790 		break;
1791 
1792 	case EPERM:
1793 		warn(gettext("Could not refresh %s "
1794 		    "(permission denied).\n"), fmribuf);
1795 		break;
1796 
1797 	case ENOSPC:
1798 		warn(gettext("Could not refresh %s "
1799 		    "(repository server out of resources).\n"),
1800 		    fmribuf);
1801 		break;
1802 
1803 	case EACCES:
1804 	default:
1805 		bad_error("refresh_entity", scf_error());
1806 	}
1807 
1808 	if (issvc) {
1809 		scf_instance_destroy(pinst);
1810 		scf_iter_destroy(piter);
1811 	}
1812 
1813 	free(fmribuf);
1814 }
1815 
1816 
1817 static int
1818 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1819 {
1820 	cbp->sc_err = scferror2errno(err);
1821 	return (UU_WALK_ERROR);
1822 }
1823 
1824 static int
1825 stash_scferror(scf_callback_t *cbp)
1826 {
1827 	return (stash_scferror_err(cbp, scf_error()));
1828 }
1829 
1830 static int select_inst(const char *);
1831 static int select_svc(const char *);
1832 
1833 /*
1834  * Take a property that does not have a type and check to see if a type
1835  * exists or can be gleened from the current data.  Set the type.
1836  *
1837  * Check the current level (instance) and then check the higher level
1838  * (service).  This could be the case for adding a new property to
1839  * the instance that's going to "override" a service level property.
1840  *
1841  * For a property :
1842  * 1. Take the type from an existing property
1843  * 2. Take the type from a template entry
1844  *
1845  * If the type can not be found, then leave the type as is, and let the import
1846  * report the problem of the missing type.
1847  */
1848 static int
1849 find_current_prop_type(void *p, void *g)
1850 {
1851 	property_t *prop = p;
1852 	scf_callback_t *lcb = g;
1853 	pgroup_t *pg = NULL;
1854 
1855 	const char *fmri = NULL;
1856 	char *lfmri = NULL;
1857 	char *cur_selection = NULL;
1858 
1859 	scf_propertygroup_t *sc_pg = NULL;
1860 	scf_property_t *sc_prop = NULL;
1861 	scf_pg_tmpl_t *t_pg = NULL;
1862 	scf_prop_tmpl_t *t_prop = NULL;
1863 	scf_type_t prop_type;
1864 
1865 	value_t *vp;
1866 	int issvc = lcb->sc_service;
1867 	int r = UU_WALK_ERROR;
1868 
1869 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1870 		return (UU_WALK_NEXT);
1871 
1872 	t_prop = scf_tmpl_prop_create(g_hndl);
1873 	sc_prop = scf_property_create(g_hndl);
1874 	if (sc_prop == NULL || t_prop == NULL) {
1875 		warn(gettext("Unable to create the property to attempt and "
1876 		    "find a missing type.\n"));
1877 
1878 		scf_property_destroy(sc_prop);
1879 		scf_tmpl_prop_destroy(t_prop);
1880 
1881 		return (UU_WALK_ERROR);
1882 	}
1883 
1884 	if (lcb->sc_flags == 1) {
1885 		pg = lcb->sc_parent;
1886 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1887 		fmri = pg->sc_parent->sc_fmri;
1888 retry_pg:
1889 		if (cur_svc && cur_selection == NULL) {
1890 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1891 			lscf_get_selection_str(cur_selection,
1892 			    max_scf_fmri_len + 1);
1893 
1894 			if (strcmp(cur_selection, fmri) != 0) {
1895 				lscf_select(fmri);
1896 			} else {
1897 				free(cur_selection);
1898 				cur_selection = NULL;
1899 			}
1900 		} else {
1901 			lscf_select(fmri);
1902 		}
1903 
1904 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1905 			warn(gettext("Unable to create property group to "
1906 			    "find a missing property type.\n"));
1907 
1908 			goto out;
1909 		}
1910 
1911 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1912 			/*
1913 			 * If this is the sc_pg from the parent
1914 			 * let the caller clean up the sc_pg,
1915 			 * and just throw it away in this case.
1916 			 */
1917 			if (sc_pg != lcb->sc_parent)
1918 				scf_pg_destroy(sc_pg);
1919 
1920 			sc_pg = NULL;
1921 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1922 				warn(gettext("Unable to create template "
1923 				    "property group to find a property "
1924 				    "type.\n"));
1925 
1926 				goto out;
1927 			}
1928 
1929 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1930 			    pg->sc_pgroup_name, NULL, t_pg,
1931 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1932 				/*
1933 				 * if instance get service and jump back
1934 				 */
1935 				scf_tmpl_pg_destroy(t_pg);
1936 				t_pg = NULL;
1937 				if (issvc == 0) {
1938 					entity_t *e = pg->sc_parent->sc_parent;
1939 
1940 					fmri = e->sc_fmri;
1941 					issvc = 1;
1942 					goto retry_pg;
1943 				} else {
1944 					goto out;
1945 				}
1946 			}
1947 		}
1948 	} else {
1949 		sc_pg = lcb->sc_parent;
1950 	}
1951 
1952 	/*
1953 	 * Attempt to get the type from an existing property.  If the property
1954 	 * cannot be found then attempt to get the type from a template entry
1955 	 * for the property.
1956 	 *
1957 	 * Finally, if at the instance level look at the service level.
1958 	 */
1959 	if (sc_pg != NULL &&
1960 	    pg_get_prop(sc_pg, prop->sc_property_name,
1961 	    sc_prop) == SCF_SUCCESS &&
1962 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1963 		prop->sc_value_type = prop_type;
1964 
1965 		/*
1966 		 * Found a type, update the value types and validate
1967 		 * the actual value against this type.
1968 		 */
1969 		for (vp = uu_list_first(prop->sc_property_values);
1970 		    vp != NULL;
1971 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1972 			vp->sc_type = prop->sc_value_type;
1973 			lxml_store_value(vp, 0, NULL);
1974 		}
1975 
1976 		r = UU_WALK_NEXT;
1977 		goto out;
1978 	}
1979 
1980 	/*
1981 	 * If we get here with t_pg set to NULL then we had to have
1982 	 * gotten an sc_pg but that sc_pg did not have the property
1983 	 * we are looking for.   So if the t_pg is not null look up
1984 	 * the template entry for the property.
1985 	 *
1986 	 * If the t_pg is null then need to attempt to get a matching
1987 	 * template entry for the sc_pg, and see if there is a property
1988 	 * entry for that template entry.
1989 	 */
1990 do_tmpl :
1991 	if (t_pg != NULL &&
1992 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1993 	    t_prop, 0) == SCF_SUCCESS) {
1994 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1995 			prop->sc_value_type = prop_type;
1996 
1997 			/*
1998 			 * Found a type, update the value types and validate
1999 			 * the actual value against this type.
2000 			 */
2001 			for (vp = uu_list_first(prop->sc_property_values);
2002 			    vp != NULL;
2003 			    vp = uu_list_next(prop->sc_property_values, vp)) {
2004 				vp->sc_type = prop->sc_value_type;
2005 				lxml_store_value(vp, 0, NULL);
2006 			}
2007 
2008 			r = UU_WALK_NEXT;
2009 			goto out;
2010 		}
2011 	} else {
2012 		if (t_pg == NULL && sc_pg) {
2013 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2014 				warn(gettext("Unable to create template "
2015 				    "property group to find a property "
2016 				    "type.\n"));
2017 
2018 				goto out;
2019 			}
2020 
2021 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2022 				scf_tmpl_pg_destroy(t_pg);
2023 				t_pg = NULL;
2024 			} else {
2025 				goto do_tmpl;
2026 			}
2027 		}
2028 	}
2029 
2030 	if (issvc == 0) {
2031 		scf_instance_t *i;
2032 		scf_service_t *s;
2033 
2034 		issvc = 1;
2035 		if (lcb->sc_flags == 1) {
2036 			entity_t *e = pg->sc_parent->sc_parent;
2037 
2038 			fmri = e->sc_fmri;
2039 			goto retry_pg;
2040 		}
2041 
2042 		/*
2043 		 * because lcb->sc_flags was not set then this means
2044 		 * the pg was not used and can be used here.
2045 		 */
2046 		if ((pg = internal_pgroup_new()) == NULL) {
2047 			warn(gettext("Could not create internal property group "
2048 			    "to find a missing type."));
2049 
2050 			goto out;
2051 		}
2052 
2053 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2054 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2055 		    max_scf_name_len + 1) < 0)
2056 				goto out;
2057 
2058 		i = scf_instance_create(g_hndl);
2059 		s = scf_service_create(g_hndl);
2060 		if (i == NULL || s == NULL ||
2061 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2062 			warn(gettext("Could not get a service for the instance "
2063 			    "to find a missing type."));
2064 
2065 			goto out;
2066 		}
2067 
2068 		/*
2069 		 * Check to see truly at the instance level.
2070 		 */
2071 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2072 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2073 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2074 			goto out;
2075 		else
2076 			fmri = (const char *)lfmri;
2077 
2078 		goto retry_pg;
2079 	}
2080 
2081 out :
2082 	if (sc_pg != lcb->sc_parent) {
2083 		scf_pg_destroy(sc_pg);
2084 	}
2085 
2086 	/*
2087 	 * If this is true then the pg was allocated
2088 	 * here, and the name was set so need to free
2089 	 * the name and the pg.
2090 	 */
2091 	if (pg != NULL && pg != lcb->sc_parent) {
2092 		free((char *)pg->sc_pgroup_name);
2093 		internal_pgroup_free(pg);
2094 	}
2095 
2096 	if (cur_selection) {
2097 		lscf_select(cur_selection);
2098 		free(cur_selection);
2099 	}
2100 
2101 	scf_tmpl_pg_destroy(t_pg);
2102 	scf_tmpl_prop_destroy(t_prop);
2103 	scf_property_destroy(sc_prop);
2104 
2105 	if (r != UU_WALK_NEXT)
2106 		warn(gettext("Could not find property type for \"%s\" "
2107 		    "from \"%s\"\n"), prop->sc_property_name,
2108 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2109 
2110 	free(lfmri);
2111 
2112 	return (r);
2113 }
2114 
2115 /*
2116  * Take a property group that does not have a type and check to see if a type
2117  * exists or can be gleened from the current data.  Set the type.
2118  *
2119  * Check the current level (instance) and then check the higher level
2120  * (service).  This could be the case for adding a new property to
2121  * the instance that's going to "override" a service level property.
2122  *
2123  * For a property group
2124  * 1. Take the type from an existing property group
2125  * 2. Take the type from a template entry
2126  *
2127  * If the type can not be found, then leave the type as is, and let the import
2128  * report the problem of the missing type.
2129  */
2130 static int
2131 find_current_pg_type(void *p, void *sori)
2132 {
2133 	entity_t *si = sori;
2134 	pgroup_t *pg = p;
2135 
2136 	const char *ofmri, *fmri;
2137 	char *cur_selection = NULL;
2138 	char *pg_type = NULL;
2139 
2140 	scf_propertygroup_t *sc_pg = NULL;
2141 	scf_pg_tmpl_t *t_pg = NULL;
2142 
2143 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2144 	int r = UU_WALK_ERROR;
2145 
2146 	ofmri = fmri = si->sc_fmri;
2147 	if (pg->sc_pgroup_type != NULL) {
2148 		r = UU_WALK_NEXT;
2149 
2150 		goto out;
2151 	}
2152 
2153 	sc_pg = scf_pg_create(g_hndl);
2154 	if (sc_pg == NULL) {
2155 		warn(gettext("Unable to create property group to attempt "
2156 		    "and find a missing type.\n"));
2157 
2158 		return (UU_WALK_ERROR);
2159 	}
2160 
2161 	/*
2162 	 * Using get_pg() requires that the cur_svc/cur_inst be
2163 	 * via lscf_select.  Need to preserve the current selection
2164 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2165 	 */
2166 	if (cur_svc) {
2167 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2168 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2169 	}
2170 
2171 	/*
2172 	 * If the property group exists get the type, and set
2173 	 * the pgroup_t type of that type.
2174 	 *
2175 	 * If not the check for a template pg_pattern entry
2176 	 * and take the type from that.
2177 	 */
2178 retry_svc:
2179 	lscf_select(fmri);
2180 
2181 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2182 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2183 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2184 		    max_scf_pg_type_len + 1) != -1) {
2185 			pg->sc_pgroup_type = pg_type;
2186 
2187 			r = UU_WALK_NEXT;
2188 			goto out;
2189 		} else {
2190 			free(pg_type);
2191 		}
2192 	} else {
2193 		if ((t_pg == NULL) &&
2194 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2195 			goto out;
2196 
2197 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2198 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2199 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2200 			pg->sc_pgroup_type = pg_type;
2201 
2202 			r = UU_WALK_NEXT;
2203 			goto out;
2204 		}
2205 	}
2206 
2207 	/*
2208 	 * If type is not found at the instance level then attempt to
2209 	 * find the type at the service level.
2210 	 */
2211 	if (!issvc) {
2212 		si = si->sc_parent;
2213 		fmri = si->sc_fmri;
2214 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2215 		goto retry_svc;
2216 	}
2217 
2218 out :
2219 	if (cur_selection) {
2220 		lscf_select(cur_selection);
2221 		free(cur_selection);
2222 	}
2223 
2224 	/*
2225 	 * Now walk the properties of the property group to make sure that
2226 	 * all properties have the correct type and values are valid for
2227 	 * those types.
2228 	 */
2229 	if (r == UU_WALK_NEXT) {
2230 		scf_callback_t cb;
2231 
2232 		cb.sc_service = issvc;
2233 		cb.sc_source_fmri = ofmri;
2234 		if (sc_pg != NULL) {
2235 			cb.sc_parent = sc_pg;
2236 			cb.sc_flags = 0;
2237 		} else {
2238 			cb.sc_parent = pg;
2239 			cb.sc_flags = 1;
2240 		}
2241 
2242 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2243 		    &cb, UU_DEFAULT) != 0) {
2244 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2245 				bad_error("uu_list_walk", uu_error());
2246 
2247 			r = UU_WALK_ERROR;
2248 		}
2249 	} else {
2250 		warn(gettext("Could not find property group type for "
2251 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2252 	}
2253 
2254 	scf_tmpl_pg_destroy(t_pg);
2255 	scf_pg_destroy(sc_pg);
2256 
2257 	return (r);
2258 }
2259 
2260 /*
2261  * Import.  These functions import a bundle into the repository.
2262  */
2263 
2264 /*
2265  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2266  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2267  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2268  * lcbdata->sc_err to
2269  *   ENOMEM - out of memory
2270  *   ECONNABORTED - repository connection broken
2271  *   ECANCELED - sc_trans's property group was deleted
2272  *   EINVAL - p's name is invalid (error printed)
2273  *	    - p has an invalid value (error printed)
2274  */
2275 static int
2276 lscf_property_import(void *v, void *pvt)
2277 {
2278 	property_t *p = v;
2279 	scf_callback_t *lcbdata = pvt;
2280 	value_t *vp;
2281 	scf_transaction_t *trans = lcbdata->sc_trans;
2282 	scf_transaction_entry_t *entr;
2283 	scf_value_t *val;
2284 	scf_type_t tp;
2285 
2286 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2287 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2288 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2289 		lcbdata->sc_enable = p;
2290 		return (UU_WALK_NEXT);
2291 	}
2292 
2293 	entr = scf_entry_create(lcbdata->sc_handle);
2294 	if (entr == NULL) {
2295 		switch (scf_error()) {
2296 		case SCF_ERROR_NO_MEMORY:
2297 			return (stash_scferror(lcbdata));
2298 
2299 		case SCF_ERROR_INVALID_ARGUMENT:
2300 		default:
2301 			bad_error("scf_entry_create", scf_error());
2302 		}
2303 	}
2304 
2305 	tp = p->sc_value_type;
2306 
2307 	if (scf_transaction_property_new(trans, entr,
2308 	    p->sc_property_name, tp) != 0) {
2309 		switch (scf_error()) {
2310 		case SCF_ERROR_INVALID_ARGUMENT:
2311 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2312 			scf_entry_destroy(entr);
2313 			return (stash_scferror(lcbdata));
2314 
2315 		case SCF_ERROR_EXISTS:
2316 			break;
2317 
2318 		case SCF_ERROR_DELETED:
2319 		case SCF_ERROR_CONNECTION_BROKEN:
2320 			scf_entry_destroy(entr);
2321 			return (stash_scferror(lcbdata));
2322 
2323 		case SCF_ERROR_NOT_BOUND:
2324 		case SCF_ERROR_HANDLE_MISMATCH:
2325 		case SCF_ERROR_NOT_SET:
2326 		default:
2327 			bad_error("scf_transaction_property_new", scf_error());
2328 		}
2329 
2330 		if (scf_transaction_property_change_type(trans, entr,
2331 		    p->sc_property_name, tp) != 0) {
2332 			switch (scf_error()) {
2333 			case SCF_ERROR_DELETED:
2334 			case SCF_ERROR_CONNECTION_BROKEN:
2335 				scf_entry_destroy(entr);
2336 				return (stash_scferror(lcbdata));
2337 
2338 			case SCF_ERROR_INVALID_ARGUMENT:
2339 				semerr(emsg_invalid_prop_name,
2340 				    p->sc_property_name);
2341 				scf_entry_destroy(entr);
2342 				return (stash_scferror(lcbdata));
2343 
2344 			case SCF_ERROR_NOT_FOUND:
2345 			case SCF_ERROR_NOT_SET:
2346 			case SCF_ERROR_HANDLE_MISMATCH:
2347 			case SCF_ERROR_NOT_BOUND:
2348 			default:
2349 				bad_error(
2350 				    "scf_transaction_property_change_type",
2351 				    scf_error());
2352 			}
2353 		}
2354 	}
2355 
2356 	for (vp = uu_list_first(p->sc_property_values);
2357 	    vp != NULL;
2358 	    vp = uu_list_next(p->sc_property_values, vp)) {
2359 		val = scf_value_create(g_hndl);
2360 		if (val == NULL) {
2361 			switch (scf_error()) {
2362 			case SCF_ERROR_NO_MEMORY:
2363 				return (stash_scferror(lcbdata));
2364 
2365 			case SCF_ERROR_INVALID_ARGUMENT:
2366 			default:
2367 				bad_error("scf_value_create", scf_error());
2368 			}
2369 		}
2370 
2371 		switch (tp) {
2372 		case SCF_TYPE_BOOLEAN:
2373 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2374 			break;
2375 		case SCF_TYPE_COUNT:
2376 			scf_value_set_count(val, vp->sc_u.sc_count);
2377 			break;
2378 		case SCF_TYPE_INTEGER:
2379 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2380 			break;
2381 		default:
2382 			assert(vp->sc_u.sc_string != NULL);
2383 			if (scf_value_set_from_string(val, tp,
2384 			    vp->sc_u.sc_string) != 0) {
2385 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2386 					bad_error("scf_value_set_from_string",
2387 					    scf_error());
2388 
2389 				warn(gettext("Value \"%s\" is not a valid "
2390 				    "%s.\n"), vp->sc_u.sc_string,
2391 				    scf_type_to_string(tp));
2392 				scf_value_destroy(val);
2393 				return (stash_scferror(lcbdata));
2394 			}
2395 			break;
2396 		}
2397 
2398 		if (scf_entry_add_value(entr, val) != 0)
2399 			bad_error("scf_entry_add_value", scf_error());
2400 	}
2401 
2402 	return (UU_WALK_NEXT);
2403 }
2404 
2405 /*
2406  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2407  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2408  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2409  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2410  * lcbdata->sc_err to
2411  *   ECONNABORTED - repository connection broken
2412  *   ENOMEM - out of memory
2413  *   ENOSPC - svc.configd is out of resources
2414  *   ECANCELED - sc_parent was deleted
2415  *   EPERM - could not create property group (permission denied) (error printed)
2416  *	   - could not modify property group (permission denied) (error printed)
2417  *	   - could not delete property group (permission denied) (error	printed)
2418  *   EROFS - could not create property group (repository is read-only)
2419  *	   - could not delete property group (repository is read-only)
2420  *   EACCES - could not create property group (backend access denied)
2421  *	    - could not delete property group (backend access denied)
2422  *   EEXIST - could not create property group (already exists)
2423  *   EINVAL - invalid property group name (error printed)
2424  *	    - invalid property name (error printed)
2425  *	    - invalid value (error printed)
2426  *   EBUSY - new property group deleted (error printed)
2427  *	   - new property group changed (error printed)
2428  *	   - property group added (error printed)
2429  *	   - property group deleted (error printed)
2430  */
2431 static int
2432 entity_pgroup_import(void *v, void *pvt)
2433 {
2434 	pgroup_t *p = v;
2435 	scf_callback_t cbdata;
2436 	scf_callback_t *lcbdata = pvt;
2437 	void *ent = lcbdata->sc_parent;
2438 	int issvc = lcbdata->sc_service;
2439 	int r;
2440 
2441 	const char * const pg_changed = gettext("%s changed unexpectedly "
2442 	    "(new property group \"%s\" changed).\n");
2443 
2444 	/* Never import deleted property groups. */
2445 	if (p->sc_pgroup_delete) {
2446 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2447 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2448 			goto delete_pg;
2449 		}
2450 		return (UU_WALK_NEXT);
2451 	}
2452 
2453 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2454 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2455 		lcbdata->sc_general = p;
2456 		return (UU_WALK_NEXT);
2457 	}
2458 
2459 add_pg:
2460 	if (issvc)
2461 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2462 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2463 	else
2464 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2465 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2466 	if (r != 0) {
2467 		switch (scf_error()) {
2468 		case SCF_ERROR_DELETED:
2469 		case SCF_ERROR_CONNECTION_BROKEN:
2470 		case SCF_ERROR_BACKEND_READONLY:
2471 		case SCF_ERROR_BACKEND_ACCESS:
2472 		case SCF_ERROR_NO_RESOURCES:
2473 			return (stash_scferror(lcbdata));
2474 
2475 		case SCF_ERROR_EXISTS:
2476 			if (lcbdata->sc_flags & SCI_FORCE)
2477 				break;
2478 			return (stash_scferror(lcbdata));
2479 
2480 		case SCF_ERROR_INVALID_ARGUMENT:
2481 			warn(emsg_fmri_invalid_pg_name_type,
2482 			    lcbdata->sc_source_fmri,
2483 			    p->sc_pgroup_name, p->sc_pgroup_type);
2484 			return (stash_scferror(lcbdata));
2485 
2486 		case SCF_ERROR_PERMISSION_DENIED:
2487 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2488 			    lcbdata->sc_target_fmri);
2489 			return (stash_scferror(lcbdata));
2490 
2491 		case SCF_ERROR_NOT_BOUND:
2492 		case SCF_ERROR_HANDLE_MISMATCH:
2493 		case SCF_ERROR_NOT_SET:
2494 		default:
2495 			bad_error("scf_service_add_pg", scf_error());
2496 		}
2497 
2498 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2499 			switch (scf_error()) {
2500 			case SCF_ERROR_CONNECTION_BROKEN:
2501 			case SCF_ERROR_DELETED:
2502 				return (stash_scferror(lcbdata));
2503 
2504 			case SCF_ERROR_INVALID_ARGUMENT:
2505 				warn(emsg_fmri_invalid_pg_name,
2506 				    lcbdata->sc_source_fmri,
2507 				    p->sc_pgroup_name);
2508 				return (stash_scferror(lcbdata));
2509 
2510 			case SCF_ERROR_NOT_FOUND:
2511 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2512 				    p->sc_pgroup_name);
2513 				lcbdata->sc_err = EBUSY;
2514 				return (UU_WALK_ERROR);
2515 
2516 			case SCF_ERROR_NOT_BOUND:
2517 			case SCF_ERROR_HANDLE_MISMATCH:
2518 			case SCF_ERROR_NOT_SET:
2519 			default:
2520 				bad_error("entity_get_pg", scf_error());
2521 			}
2522 		}
2523 
2524 		if (lcbdata->sc_flags & SCI_KEEP)
2525 			goto props;
2526 
2527 delete_pg:
2528 		if (scf_pg_delete(imp_pg) != 0) {
2529 			switch (scf_error()) {
2530 			case SCF_ERROR_DELETED:
2531 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2532 				    p->sc_pgroup_name);
2533 				lcbdata->sc_err = EBUSY;
2534 				return (UU_WALK_ERROR);
2535 
2536 			case SCF_ERROR_PERMISSION_DENIED:
2537 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2538 				    lcbdata->sc_target_fmri);
2539 				return (stash_scferror(lcbdata));
2540 
2541 			case SCF_ERROR_BACKEND_READONLY:
2542 			case SCF_ERROR_BACKEND_ACCESS:
2543 			case SCF_ERROR_CONNECTION_BROKEN:
2544 				return (stash_scferror(lcbdata));
2545 
2546 			case SCF_ERROR_NOT_SET:
2547 			default:
2548 				bad_error("scf_pg_delete", scf_error());
2549 			}
2550 		}
2551 
2552 		if (p->sc_pgroup_delete)
2553 			return (UU_WALK_NEXT);
2554 
2555 		goto add_pg;
2556 	}
2557 
2558 props:
2559 
2560 	/*
2561 	 * Add properties to property group, if any.
2562 	 */
2563 	cbdata.sc_handle = lcbdata->sc_handle;
2564 	cbdata.sc_parent = imp_pg;
2565 	cbdata.sc_flags = lcbdata->sc_flags;
2566 	cbdata.sc_trans = imp_tx;
2567 	cbdata.sc_enable = NULL;
2568 
2569 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2570 		switch (scf_error()) {
2571 		case SCF_ERROR_BACKEND_ACCESS:
2572 		case SCF_ERROR_BACKEND_READONLY:
2573 		case SCF_ERROR_CONNECTION_BROKEN:
2574 			return (stash_scferror(lcbdata));
2575 
2576 		case SCF_ERROR_DELETED:
2577 			warn(pg_changed, lcbdata->sc_target_fmri,
2578 			    p->sc_pgroup_name);
2579 			lcbdata->sc_err = EBUSY;
2580 			return (UU_WALK_ERROR);
2581 
2582 		case SCF_ERROR_PERMISSION_DENIED:
2583 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2584 			    lcbdata->sc_target_fmri);
2585 			return (stash_scferror(lcbdata));
2586 
2587 		case SCF_ERROR_NOT_BOUND:
2588 		case SCF_ERROR_NOT_SET:
2589 		case SCF_ERROR_IN_USE:
2590 		case SCF_ERROR_HANDLE_MISMATCH:
2591 		default:
2592 			bad_error("scf_transaction_start", scf_error());
2593 		}
2594 	}
2595 
2596 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2597 	    UU_DEFAULT) != 0) {
2598 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2599 			bad_error("uu_list_walk", uu_error());
2600 		scf_transaction_reset(imp_tx);
2601 
2602 		lcbdata->sc_err = cbdata.sc_err;
2603 		if (cbdata.sc_err == ECANCELED) {
2604 			warn(pg_changed, lcbdata->sc_target_fmri,
2605 			    p->sc_pgroup_name);
2606 			lcbdata->sc_err = EBUSY;
2607 		}
2608 		return (UU_WALK_ERROR);
2609 	}
2610 
2611 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2612 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2613 
2614 		/*
2615 		 * take the snapshot running snapshot then
2616 		 * import the stored general/enable property
2617 		 */
2618 		r = take_snap(ent, snap_running, imp_rsnap);
2619 		switch (r) {
2620 		case 0:
2621 			break;
2622 
2623 		case ECONNABORTED:
2624 			warn(gettext("Could not take %s snapshot on import "
2625 			    "(repository connection broken).\n"),
2626 			    snap_running);
2627 			lcbdata->sc_err = r;
2628 			return (UU_WALK_ERROR);
2629 		case ECANCELED:
2630 			warn(emsg_deleted);
2631 			lcbdata->sc_err = r;
2632 			return (UU_WALK_ERROR);
2633 
2634 		case EPERM:
2635 			warn(gettext("Could not take %s snapshot "
2636 			    "(permission denied).\n"), snap_running);
2637 			lcbdata->sc_err = r;
2638 			return (UU_WALK_ERROR);
2639 
2640 		case ENOSPC:
2641 			warn(gettext("Could not take %s snapshot"
2642 			    "(repository server out of resources).\n"),
2643 			    snap_running);
2644 			lcbdata->sc_err = r;
2645 			return (UU_WALK_ERROR);
2646 
2647 		default:
2648 			bad_error("take_snap", r);
2649 		}
2650 
2651 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2652 		if (r != UU_WALK_NEXT) {
2653 			if (r != UU_WALK_ERROR)
2654 				bad_error("lscf_property_import", r);
2655 			return (EINVAL);
2656 		}
2657 	}
2658 
2659 	r = scf_transaction_commit(imp_tx);
2660 	switch (r) {
2661 	case 1:
2662 		r = UU_WALK_NEXT;
2663 		break;
2664 
2665 	case 0:
2666 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2667 		lcbdata->sc_err = EBUSY;
2668 		r = UU_WALK_ERROR;
2669 		break;
2670 
2671 	case -1:
2672 		switch (scf_error()) {
2673 		case SCF_ERROR_BACKEND_READONLY:
2674 		case SCF_ERROR_BACKEND_ACCESS:
2675 		case SCF_ERROR_CONNECTION_BROKEN:
2676 		case SCF_ERROR_NO_RESOURCES:
2677 			r = stash_scferror(lcbdata);
2678 			break;
2679 
2680 		case SCF_ERROR_DELETED:
2681 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2682 			    p->sc_pgroup_name);
2683 			lcbdata->sc_err = EBUSY;
2684 			r = UU_WALK_ERROR;
2685 			break;
2686 
2687 		case SCF_ERROR_PERMISSION_DENIED:
2688 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2689 			    lcbdata->sc_target_fmri);
2690 			r = stash_scferror(lcbdata);
2691 			break;
2692 
2693 		case SCF_ERROR_NOT_SET:
2694 		case SCF_ERROR_INVALID_ARGUMENT:
2695 		case SCF_ERROR_NOT_BOUND:
2696 		default:
2697 			bad_error("scf_transaction_commit", scf_error());
2698 		}
2699 		break;
2700 
2701 	default:
2702 		bad_error("scf_transaction_commit", r);
2703 	}
2704 
2705 	scf_transaction_destroy_children(imp_tx);
2706 
2707 	return (r);
2708 }
2709 
2710 /*
2711  * Returns
2712  *   0 - success
2713  *   ECONNABORTED - repository connection broken
2714  *   ENOMEM - out of memory
2715  *   ENOSPC - svc.configd is out of resources
2716  *   ECANCELED - inst was deleted
2717  *   EPERM - could not create property group (permission denied) (error printed)
2718  *	   - could not modify property group (permission denied) (error printed)
2719  *   EROFS - could not create property group (repository is read-only)
2720  *   EACCES - could not create property group (backend access denied)
2721  *   EEXIST - could not create property group (already exists)
2722  *   EINVAL - invalid property group name (error printed)
2723  *	    - invalid property name (error printed)
2724  *	    - invalid value (error printed)
2725  *   EBUSY - new property group changed (error printed)
2726  */
2727 static int
2728 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2729     const entity_t *isvc, int flags)
2730 {
2731 	scf_callback_t cbdata;
2732 
2733 	cbdata.sc_handle = scf_service_handle(svc);
2734 	cbdata.sc_parent = svc;
2735 	cbdata.sc_service = 1;
2736 	cbdata.sc_general = 0;
2737 	cbdata.sc_enable = 0;
2738 	cbdata.sc_flags = flags;
2739 	cbdata.sc_source_fmri = isvc->sc_fmri;
2740 	cbdata.sc_target_fmri = target_fmri;
2741 
2742 	/*
2743 	 * If the op is set, then add the flag to the callback
2744 	 * flags for later use.
2745 	 */
2746 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2747 		switch (isvc->sc_op) {
2748 		case SVCCFG_OP_IMPORT :
2749 			cbdata.sc_flags |= SCI_OP_IMPORT;
2750 			break;
2751 		case SVCCFG_OP_APPLY :
2752 			cbdata.sc_flags |= SCI_OP_APPLY;
2753 			break;
2754 		case SVCCFG_OP_RESTORE :
2755 			cbdata.sc_flags |= SCI_OP_RESTORE;
2756 			break;
2757 		default :
2758 			uu_die(gettext("lscf_import_service_pgs : "
2759 			    "Unknown op stored in the service entity\n"));
2760 
2761 		}
2762 	}
2763 
2764 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2765 	    UU_DEFAULT) != 0) {
2766 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2767 			bad_error("uu_list_walk", uu_error());
2768 
2769 		return (cbdata.sc_err);
2770 	}
2771 
2772 	return (0);
2773 }
2774 
2775 /*
2776  * Returns
2777  *   0 - success
2778  *   ECONNABORTED - repository connection broken
2779  *   ENOMEM - out of memory
2780  *   ENOSPC - svc.configd is out of resources
2781  *   ECANCELED - inst was deleted
2782  *   EPERM - could not create property group (permission denied) (error printed)
2783  *	   - could not modify property group (permission denied) (error printed)
2784  *   EROFS - could not create property group (repository is read-only)
2785  *   EACCES - could not create property group (backend access denied)
2786  *   EEXIST - could not create property group (already exists)
2787  *   EINVAL - invalid property group name (error printed)
2788  *	    - invalid property name (error printed)
2789  *	    - invalid value (error printed)
2790  *   EBUSY - new property group changed (error printed)
2791  */
2792 static int
2793 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2794     const entity_t *iinst, int flags)
2795 {
2796 	scf_callback_t cbdata;
2797 
2798 	cbdata.sc_handle = scf_instance_handle(inst);
2799 	cbdata.sc_parent = inst;
2800 	cbdata.sc_service = 0;
2801 	cbdata.sc_general = NULL;
2802 	cbdata.sc_enable = NULL;
2803 	cbdata.sc_flags = flags;
2804 	cbdata.sc_source_fmri = iinst->sc_fmri;
2805 	cbdata.sc_target_fmri = target_fmri;
2806 
2807 	/*
2808 	 * If the op is set, then add the flag to the callback
2809 	 * flags for later use.
2810 	 */
2811 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2812 		switch (iinst->sc_op) {
2813 		case SVCCFG_OP_IMPORT :
2814 			cbdata.sc_flags |= SCI_OP_IMPORT;
2815 			break;
2816 		case SVCCFG_OP_APPLY :
2817 			cbdata.sc_flags |= SCI_OP_APPLY;
2818 			break;
2819 		case SVCCFG_OP_RESTORE :
2820 			cbdata.sc_flags |= SCI_OP_RESTORE;
2821 			break;
2822 		default :
2823 			uu_die(gettext("lscf_import_instance_pgs : "
2824 			    "Unknown op stored in the instance entity\n"));
2825 		}
2826 	}
2827 
2828 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2829 	    UU_DEFAULT) != 0) {
2830 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2831 			bad_error("uu_list_walk", uu_error());
2832 
2833 		return (cbdata.sc_err);
2834 	}
2835 
2836 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2837 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2838 		/*
2839 		 * If importing with the SCI_NOENABLED flag then
2840 		 * skip the delay, but if not then add the delay
2841 		 * of the enable property.
2842 		 */
2843 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2844 			cbdata.sc_flags |= SCI_DELAYENABLE;
2845 		}
2846 
2847 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2848 		    != UU_WALK_NEXT)
2849 			return (cbdata.sc_err);
2850 	}
2851 
2852 	return (0);
2853 }
2854 
2855 /*
2856  * Report the reasons why we can't upgrade pg2 to pg1.
2857  */
2858 static void
2859 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2860     int new)
2861 {
2862 	property_t *p1, *p2;
2863 
2864 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2865 
2866 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2867 		return;
2868 
2869 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2870 	    p1 != NULL;
2871 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2872 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2873 		if (p2 != NULL) {
2874 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2875 			    new);
2876 			continue;
2877 		}
2878 
2879 		if (new)
2880 			warn(gettext("Conflict upgrading %s (new property "
2881 			    "group \"%s\" is missing property \"%s\").\n"),
2882 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2883 		else
2884 			warn(gettext("Conflict upgrading %s (property "
2885 			    "\"%s/%s\" is missing).\n"), fmri,
2886 			    pg1->sc_pgroup_name, p1->sc_property_name);
2887 	}
2888 
2889 	/*
2890 	 * Since pg1 should be from the manifest, any properties in pg2 which
2891 	 * aren't in pg1 shouldn't be reported as conflicts.
2892 	 */
2893 }
2894 
2895 /*
2896  * Add transaction entries to tx which will upgrade cur's pg according to old
2897  * & new.
2898  *
2899  * Returns
2900  *   0 - success
2901  *   EINVAL - new has a property with an invalid name or value (message emitted)
2902  *   ENOMEM - out of memory
2903  */
2904 static int
2905 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2906     pgroup_t *cur, int speak, const char *fmri)
2907 {
2908 	property_t *p, *new_p, *cur_p;
2909 	scf_transaction_entry_t *e;
2910 	int r;
2911 	int is_general;
2912 	int is_protected;
2913 
2914 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2915 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2916 		bad_error("uu_list_walk", uu_error());
2917 
2918 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2919 
2920 	for (p = uu_list_first(old->sc_pgroup_props);
2921 	    p != NULL;
2922 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2923 		/* p is a property in the old property group. */
2924 
2925 		/* Protect live properties. */
2926 		is_protected = 0;
2927 		if (is_general) {
2928 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2929 			    0 ||
2930 			    strcmp(p->sc_property_name,
2931 			    SCF_PROPERTY_RESTARTER) == 0)
2932 				is_protected = 1;
2933 		}
2934 
2935 		/* Look for the same property in the new properties. */
2936 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2937 		if (new_p != NULL) {
2938 			new_p->sc_seen = 1;
2939 
2940 			/*
2941 			 * If the new property is the same as the old, don't do
2942 			 * anything (leave any user customizations).
2943 			 */
2944 			if (prop_equal(p, new_p, NULL, NULL, 0))
2945 				continue;
2946 
2947 			if (new_p->sc_property_override)
2948 				goto upgrade;
2949 		}
2950 
2951 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2952 		if (cur_p == NULL) {
2953 			/*
2954 			 * p has been deleted from the repository.  If we were
2955 			 * going to delete it anyway, do nothing.  Otherwise
2956 			 * report a conflict.
2957 			 */
2958 			if (new_p == NULL)
2959 				continue;
2960 
2961 			if (is_protected)
2962 				continue;
2963 
2964 			warn(gettext("Conflict upgrading %s "
2965 			    "(property \"%s/%s\" is missing).\n"), fmri,
2966 			    old->sc_pgroup_name, p->sc_property_name);
2967 			continue;
2968 		}
2969 
2970 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2971 			/*
2972 			 * Conflict.  Don't warn if the property is already the
2973 			 * way we want it, though.
2974 			 */
2975 			if (is_protected)
2976 				continue;
2977 
2978 			if (new_p == NULL)
2979 				(void) prop_equal(p, cur_p, fmri,
2980 				    old->sc_pgroup_name, 0);
2981 			else
2982 				(void) prop_equal(cur_p, new_p, fmri,
2983 				    old->sc_pgroup_name, 0);
2984 			continue;
2985 		}
2986 
2987 		if (is_protected) {
2988 			if (speak)
2989 				warn(gettext("%s: Refusing to upgrade "
2990 				    "\"%s/%s\" (live property).\n"), fmri,
2991 				    old->sc_pgroup_name, p->sc_property_name);
2992 			continue;
2993 		}
2994 
2995 upgrade:
2996 		/* p hasn't been customized in the repository.  Upgrade it. */
2997 		if (new_p == NULL) {
2998 			/* p was deleted.  Delete from cur if unchanged. */
2999 			if (speak)
3000 				warn(gettext(
3001 				    "%s: Deleting property \"%s/%s\".\n"),
3002 				    fmri, old->sc_pgroup_name,
3003 				    p->sc_property_name);
3004 
3005 			e = scf_entry_create(g_hndl);
3006 			if (e == NULL)
3007 				return (ENOMEM);
3008 
3009 			if (scf_transaction_property_delete(tx, e,
3010 			    p->sc_property_name) != 0) {
3011 				switch (scf_error()) {
3012 				case SCF_ERROR_DELETED:
3013 					scf_entry_destroy(e);
3014 					return (ECANCELED);
3015 
3016 				case SCF_ERROR_CONNECTION_BROKEN:
3017 					scf_entry_destroy(e);
3018 					return (ECONNABORTED);
3019 
3020 				case SCF_ERROR_NOT_FOUND:
3021 					/*
3022 					 * This can happen if cur is from the
3023 					 * running snapshot (and it differs
3024 					 * from the live properties).
3025 					 */
3026 					scf_entry_destroy(e);
3027 					break;
3028 
3029 				case SCF_ERROR_HANDLE_MISMATCH:
3030 				case SCF_ERROR_NOT_BOUND:
3031 				case SCF_ERROR_NOT_SET:
3032 				case SCF_ERROR_INVALID_ARGUMENT:
3033 				default:
3034 					bad_error(
3035 					    "scf_transaction_property_delete",
3036 					    scf_error());
3037 				}
3038 			}
3039 		} else {
3040 			scf_callback_t ctx;
3041 
3042 			if (speak)
3043 				warn(gettext(
3044 				    "%s: Upgrading property \"%s/%s\".\n"),
3045 				    fmri, old->sc_pgroup_name,
3046 				    p->sc_property_name);
3047 
3048 			ctx.sc_handle = g_hndl;
3049 			ctx.sc_trans = tx;
3050 			ctx.sc_flags = 0;
3051 
3052 			r = lscf_property_import(new_p, &ctx);
3053 			if (r != UU_WALK_NEXT) {
3054 				if (r != UU_WALK_ERROR)
3055 					bad_error("lscf_property_import", r);
3056 				return (EINVAL);
3057 			}
3058 		}
3059 	}
3060 
3061 	/* Go over the properties which were added. */
3062 	for (new_p = uu_list_first(new->sc_pgroup_props);
3063 	    new_p != NULL;
3064 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3065 		if (new_p->sc_seen)
3066 			continue;
3067 
3068 		/* This is a new property. */
3069 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3070 		if (cur_p == NULL) {
3071 			scf_callback_t ctx;
3072 
3073 			ctx.sc_handle = g_hndl;
3074 			ctx.sc_trans = tx;
3075 			ctx.sc_flags = 0;
3076 
3077 			r = lscf_property_import(new_p, &ctx);
3078 			if (r != UU_WALK_NEXT) {
3079 				if (r != UU_WALK_ERROR)
3080 					bad_error("lscf_property_import", r);
3081 				return (EINVAL);
3082 			}
3083 			continue;
3084 		}
3085 
3086 		/*
3087 		 * Report a conflict if the new property differs from the
3088 		 * current one.  Unless it's general/enabled, since that's
3089 		 * never in the last-import snapshot.
3090 		 */
3091 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3092 		    0 &&
3093 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3094 			continue;
3095 
3096 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3097 	}
3098 
3099 	return (0);
3100 }
3101 
3102 /*
3103  * Upgrade pg according to old & new.
3104  *
3105  * Returns
3106  *   0 - success
3107  *   ECONNABORTED - repository connection broken
3108  *   ENOMEM - out of memory
3109  *   ENOSPC - svc.configd is out of resources
3110  *   ECANCELED - pg was deleted
3111  *   EPERM - couldn't modify pg (permission denied)
3112  *   EROFS - couldn't modify pg (backend read-only)
3113  *   EACCES - couldn't modify pg (backend access denied)
3114  *   EINVAL - new has a property with invalid name or value (error printed)
3115  *   EBUSY - pg changed unexpectedly
3116  */
3117 static int
3118 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3119     pgroup_t *new, int speak, const char *fmri)
3120 {
3121 	int r;
3122 
3123 	if (scf_transaction_start(imp_tx, pg) != 0) {
3124 		switch (scf_error()) {
3125 		case SCF_ERROR_CONNECTION_BROKEN:
3126 		case SCF_ERROR_DELETED:
3127 		case SCF_ERROR_PERMISSION_DENIED:
3128 		case SCF_ERROR_BACKEND_READONLY:
3129 		case SCF_ERROR_BACKEND_ACCESS:
3130 			return (scferror2errno(scf_error()));
3131 
3132 		case SCF_ERROR_HANDLE_MISMATCH:
3133 		case SCF_ERROR_IN_USE:
3134 		case SCF_ERROR_NOT_BOUND:
3135 		case SCF_ERROR_NOT_SET:
3136 		default:
3137 			bad_error("scf_transaction_start", scf_error());
3138 		}
3139 	}
3140 
3141 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3142 	switch (r) {
3143 	case 0:
3144 		break;
3145 
3146 	case EINVAL:
3147 	case ENOMEM:
3148 		scf_transaction_destroy_children(imp_tx);
3149 		return (r);
3150 
3151 	default:
3152 		bad_error("add_upgrade_entries", r);
3153 	}
3154 
3155 	r = scf_transaction_commit(imp_tx);
3156 
3157 	scf_transaction_destroy_children(imp_tx);
3158 
3159 	switch (r) {
3160 	case 1:
3161 		break;
3162 
3163 	case 0:
3164 		return (EBUSY);
3165 
3166 	case -1:
3167 		switch (scf_error()) {
3168 		case SCF_ERROR_CONNECTION_BROKEN:
3169 		case SCF_ERROR_NO_RESOURCES:
3170 		case SCF_ERROR_PERMISSION_DENIED:
3171 		case SCF_ERROR_BACKEND_READONLY:
3172 		case SCF_ERROR_BACKEND_ACCESS:
3173 		case SCF_ERROR_DELETED:
3174 			return (scferror2errno(scf_error()));
3175 
3176 		case SCF_ERROR_NOT_BOUND:
3177 		case SCF_ERROR_INVALID_ARGUMENT:
3178 		case SCF_ERROR_NOT_SET:
3179 		default:
3180 			bad_error("scf_transaction_commit", scf_error());
3181 		}
3182 
3183 	default:
3184 		bad_error("scf_transaction_commit", r);
3185 	}
3186 
3187 	return (0);
3188 }
3189 
3190 /*
3191  * Compares two entity FMRIs.  Returns
3192  *
3193  *   1 - equal
3194  *   0 - not equal
3195  *   -1 - f1 is invalid or not an entity
3196  *   -2 - f2 is invalid or not an entity
3197  */
3198 static int
3199 fmri_equal(const char *f1, const char *f2)
3200 {
3201 	int r;
3202 	const char *s1, *i1, *pg1;
3203 	const char *s2, *i2, *pg2;
3204 
3205 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3206 		return (-1);
3207 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3208 		return (-1);
3209 
3210 	if (s1 == NULL || pg1 != NULL)
3211 		return (-1);
3212 
3213 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3214 		return (-2);
3215 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3216 		return (-2);
3217 
3218 	if (s2 == NULL || pg2 != NULL)
3219 		return (-2);
3220 
3221 	r = strcmp(s1, s2);
3222 	if (r != 0)
3223 		return (0);
3224 
3225 	if (i1 == NULL && i2 == NULL)
3226 		return (1);
3227 
3228 	if (i1 == NULL || i2 == NULL)
3229 		return (0);
3230 
3231 	return (strcmp(i1, i2) == 0);
3232 }
3233 
3234 /*
3235  * Import a dependent by creating a dependency property group in the dependent
3236  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3237  * dependents pg, and add an entry to create a new property for this
3238  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3239  *
3240  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3241  * lcbdata->sc_err to
3242  *   ECONNABORTED - repository connection broken
3243  *   ENOMEM - out of memory
3244  *   ENOSPC - configd is out of resources
3245  *   EINVAL - target is invalid (error printed)
3246  *	    - target is not an entity (error printed)
3247  *	    - dependent has invalid name (error printed)
3248  *	    - invalid property name (error printed)
3249  *	    - invalid value (error printed)
3250  *	    - scope of target does not exist (error printed)
3251  *   EPERM - couldn't create target (permission denied) (error printed)
3252  *	   - couldn't create dependency pg (permission denied) (error printed)
3253  *	   - couldn't modify dependency pg (permission denied) (error printed)
3254  *   EROFS - couldn't create target (repository read-only)
3255  *	   - couldn't create dependency pg (repository read-only)
3256  *   EACCES - couldn't create target (backend access denied)
3257  *	    - couldn't create dependency pg (backend access denied)
3258  *   ECANCELED - sc_trans's pg was deleted
3259  *   EALREADY - property for dependent already exists in sc_trans's pg
3260  *   EEXIST - dependency pg already exists in target (error printed)
3261  *   EBUSY - target deleted (error printed)
3262  *         - property group changed during import (error printed)
3263  */
3264 static int
3265 lscf_dependent_import(void *a1, void *pvt)
3266 {
3267 	pgroup_t *pgrp = a1;
3268 	scf_callback_t *lcbdata = pvt;
3269 
3270 	int isservice;
3271 	int ret;
3272 	scf_transaction_entry_t *e;
3273 	scf_value_t *val;
3274 	scf_callback_t dependent_cbdata;
3275 	scf_error_t scfe;
3276 
3277 	/*
3278 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3279 	 * it's invalid, we fail before modifying the repository.
3280 	 */
3281 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3282 	    &dependent_cbdata.sc_parent, &isservice);
3283 	switch (scfe) {
3284 	case SCF_ERROR_NONE:
3285 		break;
3286 
3287 	case SCF_ERROR_NO_MEMORY:
3288 		return (stash_scferror_err(lcbdata, scfe));
3289 
3290 	case SCF_ERROR_INVALID_ARGUMENT:
3291 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3292 		    "invalid.\n"), pgrp->sc_pgroup_name);
3293 		return (stash_scferror_err(lcbdata, scfe));
3294 
3295 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3296 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3297 		    "specifies neither a service nor an instance.\n"),
3298 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3299 		return (stash_scferror_err(lcbdata, scfe));
3300 
3301 	case SCF_ERROR_NOT_FOUND:
3302 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3303 		    &dependent_cbdata.sc_parent, &isservice);
3304 		switch (scfe) {
3305 		case SCF_ERROR_NONE:
3306 			break;
3307 
3308 		case SCF_ERROR_NO_MEMORY:
3309 		case SCF_ERROR_BACKEND_READONLY:
3310 		case SCF_ERROR_BACKEND_ACCESS:
3311 			return (stash_scferror_err(lcbdata, scfe));
3312 
3313 		case SCF_ERROR_NOT_FOUND:
3314 			semerr(gettext("The scope in FMRI \"%s\" for the "
3315 			    "\"%s\" dependent does not exist.\n"),
3316 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3317 			lcbdata->sc_err = EINVAL;
3318 			return (UU_WALK_ERROR);
3319 
3320 		case SCF_ERROR_PERMISSION_DENIED:
3321 			warn(gettext(
3322 			    "Could not create %s (permission denied).\n"),
3323 			    pgrp->sc_pgroup_fmri);
3324 			return (stash_scferror_err(lcbdata, scfe));
3325 
3326 		case SCF_ERROR_INVALID_ARGUMENT:
3327 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3328 		default:
3329 			bad_error("create_entity", scfe);
3330 		}
3331 		break;
3332 
3333 	default:
3334 		bad_error("fmri_to_entity", scfe);
3335 	}
3336 
3337 	if (lcbdata->sc_trans != NULL) {
3338 		e = scf_entry_create(lcbdata->sc_handle);
3339 		if (e == NULL) {
3340 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3341 				bad_error("scf_entry_create", scf_error());
3342 
3343 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3344 			return (stash_scferror(lcbdata));
3345 		}
3346 
3347 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3348 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3349 			switch (scf_error()) {
3350 			case SCF_ERROR_INVALID_ARGUMENT:
3351 				warn(gettext("Dependent of %s has invalid name "
3352 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3353 				    pgrp->sc_pgroup_name);
3354 				/* FALLTHROUGH */
3355 
3356 			case SCF_ERROR_DELETED:
3357 			case SCF_ERROR_CONNECTION_BROKEN:
3358 				scf_entry_destroy(e);
3359 				entity_destroy(dependent_cbdata.sc_parent,
3360 				    isservice);
3361 				return (stash_scferror(lcbdata));
3362 
3363 			case SCF_ERROR_EXISTS:
3364 				scf_entry_destroy(e);
3365 				entity_destroy(dependent_cbdata.sc_parent,
3366 				    isservice);
3367 				lcbdata->sc_err = EALREADY;
3368 				return (UU_WALK_ERROR);
3369 
3370 			case SCF_ERROR_NOT_BOUND:
3371 			case SCF_ERROR_HANDLE_MISMATCH:
3372 			case SCF_ERROR_NOT_SET:
3373 			default:
3374 				bad_error("scf_transaction_property_new",
3375 				    scf_error());
3376 			}
3377 		}
3378 
3379 		val = scf_value_create(lcbdata->sc_handle);
3380 		if (val == NULL) {
3381 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3382 				bad_error("scf_value_create", scf_error());
3383 
3384 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3385 			return (stash_scferror(lcbdata));
3386 		}
3387 
3388 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3389 		    pgrp->sc_pgroup_fmri) != 0)
3390 			/* invalid should have been caught above */
3391 			bad_error("scf_value_set_from_string", scf_error());
3392 
3393 		if (scf_entry_add_value(e, val) != 0)
3394 			bad_error("scf_entry_add_value", scf_error());
3395 	}
3396 
3397 	/* Add the property group to the target entity. */
3398 
3399 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3400 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3401 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3402 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3403 
3404 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3405 
3406 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3407 
3408 	if (ret == UU_WALK_NEXT)
3409 		return (ret);
3410 
3411 	if (ret != UU_WALK_ERROR)
3412 		bad_error("entity_pgroup_import", ret);
3413 
3414 	switch (dependent_cbdata.sc_err) {
3415 	case ECANCELED:
3416 		warn(gettext("%s deleted unexpectedly.\n"),
3417 		    pgrp->sc_pgroup_fmri);
3418 		lcbdata->sc_err = EBUSY;
3419 		break;
3420 
3421 	case EEXIST:
3422 		warn(gettext("Could not create \"%s\" dependency in %s "
3423 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3424 		    pgrp->sc_pgroup_fmri);
3425 		/* FALLTHROUGH */
3426 
3427 	default:
3428 		lcbdata->sc_err = dependent_cbdata.sc_err;
3429 	}
3430 
3431 	return (UU_WALK_ERROR);
3432 }
3433 
3434 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3435     const scf_snaplevel_t *, scf_transaction_t *);
3436 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3437     const pgroup_t *);
3438 
3439 /*
3440  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3441  * the current dependent targets from running (the snaplevel of a running
3442  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3443  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3444  * dependent targets and dependency properties from li_dpts_pg (the
3445  * "dependents" property group in snpl) and snpl (the snaplevel which
3446  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3447  * snpl doesn't have a "dependents" property group, and any dependents in ient
3448  * are new.
3449  *
3450  * Returns
3451  *   0 - success
3452  *   ECONNABORTED - repository connection broken
3453  *   ENOMEM - out of memory
3454  *   ENOSPC - configd is out of resources
3455  *   ECANCELED - ent was deleted
3456  *   ENODEV - the entity containing li_dpts_pg was deleted
3457  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3458  *	   - couldn't upgrade dependent (permission denied) (error printed)
3459  *	   - couldn't create dependent (permission denied) (error printed)
3460  *   EROFS - could not modify dependents pg (repository read-only)
3461  *	   - couldn't upgrade dependent (repository read-only)
3462  *	   - couldn't create dependent (repository read-only)
3463  *   EACCES - could not modify dependents pg (backend access denied)
3464  *	    - could not upgrade dependent (backend access denied)
3465  *	    - could not create dependent (backend access denied)
3466  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3467  *	   - dependent target deleted (error printed)
3468  *	   - dependent pg changed (error printed)
3469  *   EINVAL - new dependent is invalid (error printed)
3470  *   EBADF - snpl is corrupt (error printed)
3471  *	   - snpl has corrupt pg (error printed)
3472  *	   - dependency pg in target is corrupt (error printed)
3473  *	   - target has corrupt snapshot (error printed)
3474  *   EEXIST - dependency pg already existed in target service (error printed)
3475  */
3476 static int
3477 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3478     const scf_snaplevel_t *snpl, const entity_t *ient,
3479     const scf_snaplevel_t *running, void *ent)
3480 {
3481 	pgroup_t *new_dpt_pgroup;
3482 	scf_callback_t cbdata;
3483 	int r, unseen, tx_started = 0;
3484 	int have_cur_depts;
3485 
3486 	const char * const dependents = "dependents";
3487 
3488 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3489 
3490 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3491 		/* Nothing to do. */
3492 		return (0);
3493 
3494 	/* Fetch the current version of the "dependents" property group. */
3495 	have_cur_depts = 1;
3496 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3497 		switch (scf_error()) {
3498 		case SCF_ERROR_NOT_FOUND:
3499 			break;
3500 
3501 		case SCF_ERROR_DELETED:
3502 		case SCF_ERROR_CONNECTION_BROKEN:
3503 			return (scferror2errno(scf_error()));
3504 
3505 		case SCF_ERROR_NOT_SET:
3506 		case SCF_ERROR_INVALID_ARGUMENT:
3507 		case SCF_ERROR_HANDLE_MISMATCH:
3508 		case SCF_ERROR_NOT_BOUND:
3509 		default:
3510 			bad_error("entity_get_pg", scf_error());
3511 		}
3512 
3513 		have_cur_depts = 0;
3514 	}
3515 
3516 	/* Fetch the running version of the "dependents" property group. */
3517 	ud_run_dpts_pg_set = 0;
3518 	if (running != NULL)
3519 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3520 	else
3521 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3522 	if (r == 0) {
3523 		ud_run_dpts_pg_set = 1;
3524 	} else {
3525 		switch (scf_error()) {
3526 		case SCF_ERROR_NOT_FOUND:
3527 			break;
3528 
3529 		case SCF_ERROR_DELETED:
3530 		case SCF_ERROR_CONNECTION_BROKEN:
3531 			return (scferror2errno(scf_error()));
3532 
3533 		case SCF_ERROR_NOT_SET:
3534 		case SCF_ERROR_INVALID_ARGUMENT:
3535 		case SCF_ERROR_HANDLE_MISMATCH:
3536 		case SCF_ERROR_NOT_BOUND:
3537 		default:
3538 			bad_error(running ? "scf_snaplevel_get_pg" :
3539 			    "entity_get_pg", scf_error());
3540 		}
3541 	}
3542 
3543 	/*
3544 	 * Clear the seen fields of the dependents, so we can tell which ones
3545 	 * are new.
3546 	 */
3547 	if (uu_list_walk(ient->sc_dependents, clear_int,
3548 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3549 		bad_error("uu_list_walk", uu_error());
3550 
3551 	if (li_dpts_pg != NULL) {
3552 		/*
3553 		 * Each property in li_dpts_pg represents a dependent tag in
3554 		 * the old manifest.  For each, call upgrade_dependent(),
3555 		 * which will change ud_cur_depts_pg or dependencies in other
3556 		 * services as appropriate.  Note (a) that changes to
3557 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3558 		 * made en masse, and (b) it's ok if the entity doesn't have
3559 		 * a current version of the "dependents" property group,
3560 		 * because we'll just consider all dependents as customized
3561 		 * (by being deleted).
3562 		 */
3563 
3564 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3565 			switch (scf_error()) {
3566 			case SCF_ERROR_DELETED:
3567 				return (ENODEV);
3568 
3569 			case SCF_ERROR_CONNECTION_BROKEN:
3570 				return (ECONNABORTED);
3571 
3572 			case SCF_ERROR_HANDLE_MISMATCH:
3573 			case SCF_ERROR_NOT_BOUND:
3574 			case SCF_ERROR_NOT_SET:
3575 			default:
3576 				bad_error("scf_iter_pg_properties",
3577 				    scf_error());
3578 			}
3579 		}
3580 
3581 		if (have_cur_depts &&
3582 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3583 			switch (scf_error()) {
3584 			case SCF_ERROR_BACKEND_ACCESS:
3585 			case SCF_ERROR_BACKEND_READONLY:
3586 			case SCF_ERROR_CONNECTION_BROKEN:
3587 				return (scferror2errno(scf_error()));
3588 
3589 			case SCF_ERROR_DELETED:
3590 				warn(emsg_pg_deleted, ient->sc_fmri,
3591 				    dependents);
3592 				return (EBUSY);
3593 
3594 			case SCF_ERROR_PERMISSION_DENIED:
3595 				warn(emsg_pg_mod_perm, dependents,
3596 				    ient->sc_fmri);
3597 				return (scferror2errno(scf_error()));
3598 
3599 			case SCF_ERROR_HANDLE_MISMATCH:
3600 			case SCF_ERROR_IN_USE:
3601 			case SCF_ERROR_NOT_BOUND:
3602 			case SCF_ERROR_NOT_SET:
3603 			default:
3604 				bad_error("scf_transaction_start", scf_error());
3605 			}
3606 		}
3607 		tx_started = have_cur_depts;
3608 
3609 		for (;;) {
3610 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3611 			if (r == 0)
3612 				break;
3613 			if (r == 1) {
3614 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3615 				    tx_started ? ud_tx : NULL);
3616 				switch (r) {
3617 				case 0:
3618 					continue;
3619 
3620 				case ECONNABORTED:
3621 				case ENOMEM:
3622 				case ENOSPC:
3623 				case EBADF:
3624 				case EBUSY:
3625 				case EINVAL:
3626 				case EPERM:
3627 				case EROFS:
3628 				case EACCES:
3629 				case EEXIST:
3630 					break;
3631 
3632 				case ECANCELED:
3633 					r = ENODEV;
3634 					break;
3635 
3636 				default:
3637 					bad_error("upgrade_dependent", r);
3638 				}
3639 
3640 				if (tx_started)
3641 					scf_transaction_destroy_children(ud_tx);
3642 				return (r);
3643 			}
3644 			if (r != -1)
3645 				bad_error("scf_iter_next_property", r);
3646 
3647 			switch (scf_error()) {
3648 			case SCF_ERROR_DELETED:
3649 				r = ENODEV;
3650 				break;
3651 
3652 			case SCF_ERROR_CONNECTION_BROKEN:
3653 				r = ECONNABORTED;
3654 				break;
3655 
3656 			case SCF_ERROR_NOT_SET:
3657 			case SCF_ERROR_INVALID_ARGUMENT:
3658 			case SCF_ERROR_NOT_BOUND:
3659 			case SCF_ERROR_HANDLE_MISMATCH:
3660 			default:
3661 				bad_error("scf_iter_next_property",
3662 				    scf_error());
3663 			}
3664 
3665 			if (tx_started)
3666 				scf_transaction_destroy_children(ud_tx);
3667 			return (r);
3668 		}
3669 	}
3670 
3671 	/* import unseen dependents */
3672 	unseen = 0;
3673 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3674 	    new_dpt_pgroup != NULL;
3675 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3676 	    new_dpt_pgroup)) {
3677 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3678 			unseen = 1;
3679 			break;
3680 		}
3681 	}
3682 
3683 	/* If there are none, exit early. */
3684 	if (unseen == 0)
3685 		goto commit;
3686 
3687 	/* Set up for lscf_dependent_import() */
3688 	cbdata.sc_handle = g_hndl;
3689 	cbdata.sc_parent = ent;
3690 	cbdata.sc_service = issvc;
3691 	cbdata.sc_flags = 0;
3692 
3693 	if (!have_cur_depts) {
3694 		/*
3695 		 * We have new dependents to import, so we need a "dependents"
3696 		 * property group.
3697 		 */
3698 		if (issvc)
3699 			r = scf_service_add_pg(ent, dependents,
3700 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3701 		else
3702 			r = scf_instance_add_pg(ent, dependents,
3703 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3704 		if (r != 0) {
3705 			switch (scf_error()) {
3706 			case SCF_ERROR_DELETED:
3707 			case SCF_ERROR_CONNECTION_BROKEN:
3708 			case SCF_ERROR_BACKEND_READONLY:
3709 			case SCF_ERROR_BACKEND_ACCESS:
3710 			case SCF_ERROR_NO_RESOURCES:
3711 				return (scferror2errno(scf_error()));
3712 
3713 			case SCF_ERROR_EXISTS:
3714 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3715 				return (EBUSY);
3716 
3717 			case SCF_ERROR_PERMISSION_DENIED:
3718 				warn(emsg_pg_add_perm, dependents,
3719 				    ient->sc_fmri);
3720 				return (scferror2errno(scf_error()));
3721 
3722 			case SCF_ERROR_NOT_BOUND:
3723 			case SCF_ERROR_HANDLE_MISMATCH:
3724 			case SCF_ERROR_INVALID_ARGUMENT:
3725 			case SCF_ERROR_NOT_SET:
3726 			default:
3727 				bad_error("scf_service_add_pg", scf_error());
3728 			}
3729 		}
3730 	}
3731 
3732 	cbdata.sc_trans = ud_tx;
3733 
3734 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3735 		switch (scf_error()) {
3736 		case SCF_ERROR_CONNECTION_BROKEN:
3737 		case SCF_ERROR_BACKEND_ACCESS:
3738 		case SCF_ERROR_BACKEND_READONLY:
3739 			return (scferror2errno(scf_error()));
3740 
3741 		case SCF_ERROR_DELETED:
3742 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3743 			return (EBUSY);
3744 
3745 		case SCF_ERROR_PERMISSION_DENIED:
3746 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3747 			return (scferror2errno(scf_error()));
3748 
3749 		case SCF_ERROR_HANDLE_MISMATCH:
3750 		case SCF_ERROR_IN_USE:
3751 		case SCF_ERROR_NOT_BOUND:
3752 		case SCF_ERROR_NOT_SET:
3753 		default:
3754 			bad_error("scf_transaction_start", scf_error());
3755 		}
3756 	}
3757 	tx_started = 1;
3758 
3759 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3760 	    new_dpt_pgroup != NULL;
3761 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3762 	    new_dpt_pgroup)) {
3763 		if (new_dpt_pgroup->sc_pgroup_seen)
3764 			continue;
3765 
3766 		if (ud_run_dpts_pg_set) {
3767 			/*
3768 			 * If the dependent is already there, then we have
3769 			 * a conflict.
3770 			 */
3771 			if (scf_pg_get_property(ud_run_dpts_pg,
3772 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3773 				r = handle_dependent_conflict(ient, ud_prop,
3774 				    new_dpt_pgroup);
3775 				switch (r) {
3776 				case 0:
3777 					continue;
3778 
3779 				case ECONNABORTED:
3780 				case ENOMEM:
3781 				case EBUSY:
3782 				case EBADF:
3783 				case EINVAL:
3784 					scf_transaction_destroy_children(ud_tx);
3785 					return (r);
3786 
3787 				default:
3788 					bad_error("handle_dependent_conflict",
3789 					    r);
3790 				}
3791 			} else {
3792 				switch (scf_error()) {
3793 				case SCF_ERROR_NOT_FOUND:
3794 					break;
3795 
3796 				case SCF_ERROR_INVALID_ARGUMENT:
3797 					warn(emsg_fmri_invalid_pg_name,
3798 					    ient->sc_fmri,
3799 					    new_dpt_pgroup->sc_pgroup_name);
3800 					scf_transaction_destroy_children(ud_tx);
3801 					return (EINVAL);
3802 
3803 				case SCF_ERROR_DELETED:
3804 					warn(emsg_pg_deleted, ient->sc_fmri,
3805 					    new_dpt_pgroup->sc_pgroup_name);
3806 					scf_transaction_destroy_children(ud_tx);
3807 					return (EBUSY);
3808 
3809 				case SCF_ERROR_CONNECTION_BROKEN:
3810 					scf_transaction_destroy_children(ud_tx);
3811 					return (ECONNABORTED);
3812 
3813 				case SCF_ERROR_NOT_BOUND:
3814 				case SCF_ERROR_HANDLE_MISMATCH:
3815 				case SCF_ERROR_NOT_SET:
3816 				default:
3817 					bad_error("scf_pg_get_property",
3818 					    scf_error());
3819 				}
3820 			}
3821 		}
3822 
3823 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3824 		if (r != UU_WALK_NEXT) {
3825 			if (r != UU_WALK_ERROR)
3826 				bad_error("lscf_dependent_import", r);
3827 
3828 			if (cbdata.sc_err == EALREADY) {
3829 				/* Collisions were handled preemptively. */
3830 				bad_error("lscf_dependent_import",
3831 				    cbdata.sc_err);
3832 			}
3833 
3834 			scf_transaction_destroy_children(ud_tx);
3835 			return (cbdata.sc_err);
3836 		}
3837 	}
3838 
3839 commit:
3840 	if (!tx_started)
3841 		return (0);
3842 
3843 	r = scf_transaction_commit(ud_tx);
3844 
3845 	scf_transaction_destroy_children(ud_tx);
3846 
3847 	switch (r) {
3848 	case 1:
3849 		return (0);
3850 
3851 	case 0:
3852 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3853 		return (EBUSY);
3854 
3855 	case -1:
3856 		break;
3857 
3858 	default:
3859 		bad_error("scf_transaction_commit", r);
3860 	}
3861 
3862 	switch (scf_error()) {
3863 	case SCF_ERROR_CONNECTION_BROKEN:
3864 	case SCF_ERROR_BACKEND_READONLY:
3865 	case SCF_ERROR_BACKEND_ACCESS:
3866 	case SCF_ERROR_NO_RESOURCES:
3867 		return (scferror2errno(scf_error()));
3868 
3869 	case SCF_ERROR_DELETED:
3870 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3871 		return (EBUSY);
3872 
3873 	case SCF_ERROR_PERMISSION_DENIED:
3874 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3875 		return (scferror2errno(scf_error()));
3876 
3877 	case SCF_ERROR_NOT_BOUND:
3878 	case SCF_ERROR_INVALID_ARGUMENT:
3879 	case SCF_ERROR_NOT_SET:
3880 	default:
3881 		bad_error("scf_transaction_destroy", scf_error());
3882 		/* NOTREACHED */
3883 	}
3884 }
3885 
3886 /*
3887  * Used to add the manifests to the list of currently supported manifests.
3888  * We can modify the existing manifest list removing entries if the files
3889  * don't exist.
3890  *
3891  * Get the old list and the new file name
3892  * If the new file name is in the list return
3893  * If not then add the file to the list.
3894  * As we process the list check to see if the files in the old list exist
3895  *	if not then remove the file from the list.
3896  * Commit the list of manifest file names.
3897  *
3898  */
3899 static int
3900 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3901     const scf_snaplevel_t *running, void *ent)
3902 {
3903 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3904 	scf_property_t *ud_prop = NULL;
3905 	scf_iter_t *ud_prop_iter;
3906 	scf_value_t *fname_value;
3907 	scf_callback_t cbdata;
3908 	pgroup_t *mfst_pgroup;
3909 	property_t *mfst_prop;
3910 	property_t *old_prop;
3911 	char *pname;
3912 	char *fval;
3913 	char *old_pname;
3914 	char *old_fval;
3915 	int no_upgrade_pg;
3916 	int mfst_seen;
3917 	int r;
3918 
3919 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3920 
3921 	/*
3922 	 * This should always be the service base on the code
3923 	 * path, and the fact that the manifests pg is a service
3924 	 * level property group only.
3925 	 */
3926 	ud_mfsts_pg = scf_pg_create(g_hndl);
3927 	ud_prop = scf_property_create(g_hndl);
3928 	ud_prop_iter = scf_iter_create(g_hndl);
3929 	fname_value = scf_value_create(g_hndl);
3930 
3931 	/* Fetch the "manifests" property group */
3932 	no_upgrade_pg = 0;
3933 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3934 	    ud_mfsts_pg);
3935 	if (r != 0) {
3936 		switch (scf_error()) {
3937 		case SCF_ERROR_NOT_FOUND:
3938 			no_upgrade_pg = 1;
3939 			break;
3940 
3941 		case SCF_ERROR_DELETED:
3942 		case SCF_ERROR_CONNECTION_BROKEN:
3943 			return (scferror2errno(scf_error()));
3944 
3945 		case SCF_ERROR_NOT_SET:
3946 		case SCF_ERROR_INVALID_ARGUMENT:
3947 		case SCF_ERROR_HANDLE_MISMATCH:
3948 		case SCF_ERROR_NOT_BOUND:
3949 		default:
3950 			bad_error(running ? "scf_snaplevel_get_pg" :
3951 			    "entity_get_pg", scf_error());
3952 		}
3953 	}
3954 
3955 	if (no_upgrade_pg) {
3956 		cbdata.sc_handle = g_hndl;
3957 		cbdata.sc_parent = ent;
3958 		cbdata.sc_service = issvc;
3959 		cbdata.sc_flags = SCI_FORCE;
3960 		cbdata.sc_source_fmri = ient->sc_fmri;
3961 		cbdata.sc_target_fmri = ient->sc_fmri;
3962 
3963 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3964 			return (cbdata.sc_err);
3965 
3966 		return (0);
3967 	}
3968 
3969 	/* Fetch the new manifests property group */
3970 	mfst_pgroup = internal_pgroup_find_or_create(ient,
3971 	    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3972 	assert(mfst_pgroup != NULL);
3973 
3974 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3975 	    SCF_SUCCESS)
3976 		return (-1);
3977 
3978 	if ((pname = malloc(MAXPATHLEN)) == NULL)
3979 		return (ENOMEM);
3980 	if ((fval = malloc(MAXPATHLEN)) == NULL) {
3981 		free(pname);
3982 		return (ENOMEM);
3983 	}
3984 
3985 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3986 		mfst_seen = 0;
3987 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3988 			continue;
3989 
3990 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3991 		    mfst_prop != NULL;
3992 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3993 		    mfst_prop)) {
3994 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3995 				mfst_seen = 1;
3996 			}
3997 		}
3998 
3999 		/*
4000 		 * If the manifest is not seen then add it to the new mfst
4001 		 * property list to get proccessed into the repo.
4002 		 */
4003 		if (mfst_seen == 0) {
4004 			/*
4005 			 * If we cannot get the value then there is no
4006 			 * reason to attempt to attach the value to
4007 			 * the property group
4008 			 */
4009 			if (prop_get_val(ud_prop, fname_value) == 0 &&
4010 			    scf_value_get_astring(fname_value, fval,
4011 			    MAXPATHLEN) != -1)  {
4012 				old_pname = safe_strdup(pname);
4013 				old_fval = safe_strdup(fval);
4014 				old_prop = internal_property_create(old_pname,
4015 				    SCF_TYPE_ASTRING, 1, old_fval);
4016 
4017 				/*
4018 				 * Already checked to see if the property exists
4019 				 * in the group, and it does not.
4020 				 */
4021 				(void) internal_attach_property(mfst_pgroup,
4022 				    old_prop);
4023 			}
4024 		}
4025 	}
4026 	free(pname);
4027 	free(fval);
4028 
4029 	cbdata.sc_handle = g_hndl;
4030 	cbdata.sc_parent = ent;
4031 	cbdata.sc_service = issvc;
4032 	cbdata.sc_flags = SCI_FORCE;
4033 	cbdata.sc_source_fmri = ient->sc_fmri;
4034 	cbdata.sc_target_fmri = ient->sc_fmri;
4035 
4036 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4037 		return (cbdata.sc_err);
4038 
4039 	return (r);
4040 }
4041 
4042 /*
4043  * prop is taken to be a property in the "dependents" property group of snpl,
4044  * which is taken to be the snaplevel of a last-import snapshot corresponding
4045  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4046  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4047  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4048  * of the entity ient represents (possibly in the running snapshot).  If it
4049  * needs to be changed, an entry will be added to tx, if not NULL.
4050  *
4051  * Returns
4052  *   0 - success
4053  *   ECONNABORTED - repository connection broken
4054  *   ENOMEM - out of memory
4055  *   ENOSPC - configd was out of resources
4056  *   ECANCELED - snpl's entity was deleted
4057  *   EINVAL - dependent target is invalid (error printed)
4058  *	    - dependent is invalid (error printed)
4059  *   EBADF - snpl is corrupt (error printed)
4060  *	   - snpl has corrupt pg (error printed)
4061  *	   - dependency pg in target is corrupt (error printed)
4062  *	   - running snapshot in dependent is missing snaplevel (error printed)
4063  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4064  *	   - couldn't create dependent (permission denied) (error printed)
4065  *	   - couldn't modify dependent pg (permission denied) (error printed)
4066  *   EROFS - couldn't delete dependency pg (repository read-only)
4067  *	   - couldn't create dependent (repository read-only)
4068  *   EACCES - couldn't delete dependency pg (backend access denied)
4069  *	    - couldn't create dependent (backend access denied)
4070  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4071  *	   - tx's pg was deleted (error printed)
4072  *	   - dependent pg was changed or deleted (error printed)
4073  *   EEXIST - dependency pg already exists in new target (error printed)
4074  */
4075 static int
4076 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4077     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4078 {
4079 	pgroup_t pgrp;
4080 	scf_type_t ty;
4081 	pgroup_t *new_dpt_pgroup;
4082 	pgroup_t *old_dpt_pgroup = NULL;
4083 	pgroup_t *current_pg;
4084 	pgroup_t *dpt;
4085 	scf_callback_t cbdata;
4086 	int tissvc;
4087 	void *target_ent;
4088 	scf_error_t serr;
4089 	int r;
4090 	scf_transaction_entry_t *ent;
4091 
4092 	const char * const cf_inval = gettext("Conflict upgrading %s "
4093 	    "(dependent \"%s\" has invalid dependents property).\n");
4094 	const char * const cf_missing = gettext("Conflict upgrading %s "
4095 	    "(dependent \"%s\" is missing).\n");
4096 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4097 	    "(dependent \"%s\" has new dependency property group).\n");
4098 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4099 	    "(dependent \"%s\" has new target).\n");
4100 	const char * const li_corrupt =
4101 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4102 	const char * const upgrading =
4103 	    gettext("%s: Upgrading dependent \"%s\".\n");
4104 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4105 	    "corrupt (missing snaplevel).\n");
4106 
4107 	if (scf_property_type(prop, &ty) != 0) {
4108 		switch (scf_error()) {
4109 		case SCF_ERROR_DELETED:
4110 		case SCF_ERROR_CONNECTION_BROKEN:
4111 			return (scferror2errno(scf_error()));
4112 
4113 		case SCF_ERROR_NOT_BOUND:
4114 		case SCF_ERROR_NOT_SET:
4115 		default:
4116 			bad_error("scf_property_type", scf_error());
4117 		}
4118 	}
4119 
4120 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4121 		warn(li_corrupt, ient->sc_fmri);
4122 		return (EBADF);
4123 	}
4124 
4125 	/*
4126 	 * prop represents a dependent in the old manifest.  It is named after
4127 	 * the dependent.
4128 	 */
4129 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4130 		switch (scf_error()) {
4131 		case SCF_ERROR_DELETED:
4132 		case SCF_ERROR_CONNECTION_BROKEN:
4133 			return (scferror2errno(scf_error()));
4134 
4135 		case SCF_ERROR_NOT_BOUND:
4136 		case SCF_ERROR_NOT_SET:
4137 		default:
4138 			bad_error("scf_property_get_name", scf_error());
4139 		}
4140 	}
4141 
4142 	/* See if it's in the new manifest. */
4143 	pgrp.sc_pgroup_name = ud_name;
4144 	new_dpt_pgroup =
4145 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4146 
4147 	/* If it's not, delete it... if it hasn't been customized. */
4148 	if (new_dpt_pgroup == NULL) {
4149 		if (!ud_run_dpts_pg_set)
4150 			return (0);
4151 
4152 		if (scf_property_get_value(prop, ud_val) != 0) {
4153 			switch (scf_error()) {
4154 			case SCF_ERROR_NOT_FOUND:
4155 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4156 				warn(li_corrupt, ient->sc_fmri);
4157 				return (EBADF);
4158 
4159 			case SCF_ERROR_DELETED:
4160 			case SCF_ERROR_CONNECTION_BROKEN:
4161 				return (scferror2errno(scf_error()));
4162 
4163 			case SCF_ERROR_HANDLE_MISMATCH:
4164 			case SCF_ERROR_NOT_BOUND:
4165 			case SCF_ERROR_NOT_SET:
4166 			case SCF_ERROR_PERMISSION_DENIED:
4167 			default:
4168 				bad_error("scf_property_get_value",
4169 				    scf_error());
4170 			}
4171 		}
4172 
4173 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4174 		    max_scf_value_len + 1) < 0)
4175 			bad_error("scf_value_get_as_string", scf_error());
4176 
4177 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4178 		    0) {
4179 			switch (scf_error()) {
4180 			case SCF_ERROR_NOT_FOUND:
4181 				return (0);
4182 
4183 			case SCF_ERROR_CONNECTION_BROKEN:
4184 				return (scferror2errno(scf_error()));
4185 
4186 			case SCF_ERROR_DELETED:
4187 				warn(emsg_pg_deleted, ient->sc_fmri,
4188 				    "dependents");
4189 				return (EBUSY);
4190 
4191 			case SCF_ERROR_INVALID_ARGUMENT:
4192 			case SCF_ERROR_NOT_BOUND:
4193 			case SCF_ERROR_HANDLE_MISMATCH:
4194 			case SCF_ERROR_NOT_SET:
4195 			default:
4196 				bad_error("scf_pg_get_property", scf_error());
4197 			}
4198 		}
4199 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4200 			switch (scf_error()) {
4201 			case SCF_ERROR_NOT_FOUND:
4202 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4203 				warn(cf_inval, ient->sc_fmri, ud_name);
4204 				return (0);
4205 
4206 			case SCF_ERROR_DELETED:
4207 			case SCF_ERROR_CONNECTION_BROKEN:
4208 				return (scferror2errno(scf_error()));
4209 
4210 			case SCF_ERROR_HANDLE_MISMATCH:
4211 			case SCF_ERROR_NOT_BOUND:
4212 			case SCF_ERROR_NOT_SET:
4213 			case SCF_ERROR_PERMISSION_DENIED:
4214 			default:
4215 				bad_error("scf_property_get_value",
4216 				    scf_error());
4217 			}
4218 		}
4219 
4220 		ty = scf_value_type(ud_val);
4221 		assert(ty != SCF_TYPE_INVALID);
4222 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4223 			warn(cf_inval, ient->sc_fmri, ud_name);
4224 			return (0);
4225 		}
4226 
4227 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4228 		    max_scf_value_len + 1) < 0)
4229 			bad_error("scf_value_get_as_string", scf_error());
4230 
4231 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4232 		switch (r) {
4233 		case 1:
4234 			break;
4235 
4236 		case 0:
4237 		case -1:	/* warn? */
4238 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4239 			return (0);
4240 
4241 		case -2:
4242 			warn(li_corrupt, ient->sc_fmri);
4243 			return (EBADF);
4244 
4245 		default:
4246 			bad_error("fmri_equal", r);
4247 		}
4248 
4249 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4250 			switch (scf_error()) {
4251 			case SCF_ERROR_NOT_FOUND:
4252 				warn(li_corrupt, ient->sc_fmri);
4253 				return (EBADF);
4254 
4255 			case SCF_ERROR_DELETED:
4256 			case SCF_ERROR_CONNECTION_BROKEN:
4257 				return (scferror2errno(scf_error()));
4258 
4259 			case SCF_ERROR_NOT_BOUND:
4260 			case SCF_ERROR_HANDLE_MISMATCH:
4261 			case SCF_ERROR_INVALID_ARGUMENT:
4262 			case SCF_ERROR_NOT_SET:
4263 			default:
4264 				bad_error("scf_snaplevel_get_pg", scf_error());
4265 			}
4266 		}
4267 
4268 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4269 		    snap_lastimport);
4270 		switch (r) {
4271 		case 0:
4272 			break;
4273 
4274 		case ECANCELED:
4275 		case ECONNABORTED:
4276 		case ENOMEM:
4277 		case EBADF:
4278 			return (r);
4279 
4280 		case EACCES:
4281 		default:
4282 			bad_error("load_pg", r);
4283 		}
4284 
4285 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4286 		switch (serr) {
4287 		case SCF_ERROR_NONE:
4288 			break;
4289 
4290 		case SCF_ERROR_NO_MEMORY:
4291 			internal_pgroup_free(old_dpt_pgroup);
4292 			return (ENOMEM);
4293 
4294 		case SCF_ERROR_NOT_FOUND:
4295 			internal_pgroup_free(old_dpt_pgroup);
4296 			goto delprop;
4297 
4298 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4299 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4300 		default:
4301 			bad_error("fmri_to_entity", serr);
4302 		}
4303 
4304 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4305 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4306 		switch (r) {
4307 		case 0:
4308 			break;
4309 
4310 		case ECONNABORTED:
4311 			internal_pgroup_free(old_dpt_pgroup);
4312 			return (r);
4313 
4314 		case ECANCELED:
4315 		case ENOENT:
4316 			internal_pgroup_free(old_dpt_pgroup);
4317 			goto delprop;
4318 
4319 		case EBADF:
4320 			warn(r_no_lvl, ud_ctarg);
4321 			internal_pgroup_free(old_dpt_pgroup);
4322 			return (r);
4323 
4324 		case EINVAL:
4325 		default:
4326 			bad_error("entity_get_running_pg", r);
4327 		}
4328 
4329 		/* load it */
4330 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4331 		switch (r) {
4332 		case 0:
4333 			break;
4334 
4335 		case ECANCELED:
4336 			internal_pgroup_free(old_dpt_pgroup);
4337 			goto delprop;
4338 
4339 		case ECONNABORTED:
4340 		case ENOMEM:
4341 		case EBADF:
4342 			internal_pgroup_free(old_dpt_pgroup);
4343 			return (r);
4344 
4345 		case EACCES:
4346 		default:
4347 			bad_error("load_pg", r);
4348 		}
4349 
4350 		/* compare property groups */
4351 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4352 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4353 			internal_pgroup_free(old_dpt_pgroup);
4354 			internal_pgroup_free(current_pg);
4355 			return (0);
4356 		}
4357 
4358 		internal_pgroup_free(old_dpt_pgroup);
4359 		internal_pgroup_free(current_pg);
4360 
4361 		if (g_verbose)
4362 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4363 			    ient->sc_fmri, ud_name);
4364 
4365 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4366 			switch (scf_error()) {
4367 			case SCF_ERROR_NOT_FOUND:
4368 			case SCF_ERROR_DELETED:
4369 				internal_pgroup_free(old_dpt_pgroup);
4370 				goto delprop;
4371 
4372 			case SCF_ERROR_CONNECTION_BROKEN:
4373 				internal_pgroup_free(old_dpt_pgroup);
4374 				return (ECONNABORTED);
4375 
4376 			case SCF_ERROR_NOT_SET:
4377 			case SCF_ERROR_INVALID_ARGUMENT:
4378 			case SCF_ERROR_HANDLE_MISMATCH:
4379 			case SCF_ERROR_NOT_BOUND:
4380 			default:
4381 				bad_error("entity_get_pg", scf_error());
4382 			}
4383 		}
4384 
4385 		if (scf_pg_delete(ud_pg) != 0) {
4386 			switch (scf_error()) {
4387 			case SCF_ERROR_DELETED:
4388 				break;
4389 
4390 			case SCF_ERROR_CONNECTION_BROKEN:
4391 			case SCF_ERROR_BACKEND_READONLY:
4392 			case SCF_ERROR_BACKEND_ACCESS:
4393 				return (scferror2errno(scf_error()));
4394 
4395 			case SCF_ERROR_PERMISSION_DENIED:
4396 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4397 				return (scferror2errno(scf_error()));
4398 
4399 			case SCF_ERROR_NOT_SET:
4400 			default:
4401 				bad_error("scf_pg_delete", scf_error());
4402 			}
4403 		}
4404 
4405 		/*
4406 		 * This service was changed, so it must be refreshed.  But
4407 		 * since it's not mentioned in the new manifest, we have to
4408 		 * record its FMRI here for use later.  We record the name
4409 		 * & the entity (via sc_parent) in case we need to print error
4410 		 * messages during the refresh.
4411 		 */
4412 		dpt = internal_pgroup_new();
4413 		if (dpt == NULL)
4414 			return (ENOMEM);
4415 		dpt->sc_pgroup_name = strdup(ud_name);
4416 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4417 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4418 			return (ENOMEM);
4419 		dpt->sc_parent = (entity_t *)ient;
4420 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4421 			uu_die(gettext("libuutil error: %s\n"),
4422 			    uu_strerror(uu_error()));
4423 
4424 delprop:
4425 		if (tx == NULL)
4426 			return (0);
4427 
4428 		ent = scf_entry_create(g_hndl);
4429 		if (ent == NULL)
4430 			return (ENOMEM);
4431 
4432 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4433 			scf_entry_destroy(ent);
4434 			switch (scf_error()) {
4435 			case SCF_ERROR_DELETED:
4436 				warn(emsg_pg_deleted, ient->sc_fmri,
4437 				    "dependents");
4438 				return (EBUSY);
4439 
4440 			case SCF_ERROR_CONNECTION_BROKEN:
4441 				return (scferror2errno(scf_error()));
4442 
4443 			case SCF_ERROR_NOT_FOUND:
4444 				break;
4445 
4446 			case SCF_ERROR_HANDLE_MISMATCH:
4447 			case SCF_ERROR_NOT_BOUND:
4448 			case SCF_ERROR_INVALID_ARGUMENT:
4449 			case SCF_ERROR_NOT_SET:
4450 			default:
4451 				bad_error("scf_transaction_property_delete",
4452 				    scf_error());
4453 			}
4454 		}
4455 
4456 		return (0);
4457 	}
4458 
4459 	new_dpt_pgroup->sc_pgroup_seen = 1;
4460 
4461 	/*
4462 	 * Decide whether the dependent has changed in the manifest.
4463 	 */
4464 	/* Compare the target. */
4465 	if (scf_property_get_value(prop, ud_val) != 0) {
4466 		switch (scf_error()) {
4467 		case SCF_ERROR_NOT_FOUND:
4468 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4469 			warn(li_corrupt, ient->sc_fmri);
4470 			return (EBADF);
4471 
4472 		case SCF_ERROR_DELETED:
4473 		case SCF_ERROR_CONNECTION_BROKEN:
4474 			return (scferror2errno(scf_error()));
4475 
4476 		case SCF_ERROR_HANDLE_MISMATCH:
4477 		case SCF_ERROR_NOT_BOUND:
4478 		case SCF_ERROR_NOT_SET:
4479 		case SCF_ERROR_PERMISSION_DENIED:
4480 		default:
4481 			bad_error("scf_property_get_value", scf_error());
4482 		}
4483 	}
4484 
4485 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4486 	    0)
4487 		bad_error("scf_value_get_as_string", scf_error());
4488 
4489 	/*
4490 	 * If the fmri's are not equal then the old fmri will need to
4491 	 * be refreshed to ensure that the changes are properly updated
4492 	 * in that service.
4493 	 */
4494 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4495 	switch (r) {
4496 	case 0:
4497 		dpt = internal_pgroup_new();
4498 		if (dpt == NULL)
4499 			return (ENOMEM);
4500 		dpt->sc_pgroup_name = strdup(ud_name);
4501 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4502 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4503 			return (ENOMEM);
4504 		dpt->sc_parent = (entity_t *)ient;
4505 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4506 			uu_die(gettext("libuutil error: %s\n"),
4507 			    uu_strerror(uu_error()));
4508 		break;
4509 
4510 	case 1:
4511 		/* Compare the dependency pgs. */
4512 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4513 			switch (scf_error()) {
4514 			case SCF_ERROR_NOT_FOUND:
4515 				warn(li_corrupt, ient->sc_fmri);
4516 				return (EBADF);
4517 
4518 			case SCF_ERROR_DELETED:
4519 			case SCF_ERROR_CONNECTION_BROKEN:
4520 				return (scferror2errno(scf_error()));
4521 
4522 			case SCF_ERROR_NOT_BOUND:
4523 			case SCF_ERROR_HANDLE_MISMATCH:
4524 			case SCF_ERROR_INVALID_ARGUMENT:
4525 			case SCF_ERROR_NOT_SET:
4526 			default:
4527 				bad_error("scf_snaplevel_get_pg", scf_error());
4528 			}
4529 		}
4530 
4531 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4532 		    snap_lastimport);
4533 		switch (r) {
4534 		case 0:
4535 			break;
4536 
4537 		case ECANCELED:
4538 		case ECONNABORTED:
4539 		case ENOMEM:
4540 		case EBADF:
4541 			return (r);
4542 
4543 		case EACCES:
4544 		default:
4545 			bad_error("load_pg", r);
4546 		}
4547 
4548 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4549 			/* no change, leave customizations */
4550 			internal_pgroup_free(old_dpt_pgroup);
4551 			return (0);
4552 		}
4553 		break;
4554 
4555 	case -1:
4556 		warn(li_corrupt, ient->sc_fmri);
4557 		return (EBADF);
4558 
4559 	case -2:
4560 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4561 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4562 		return (EINVAL);
4563 
4564 	default:
4565 		bad_error("fmri_equal", r);
4566 	}
4567 
4568 	/*
4569 	 * The dependent has changed in the manifest.  Upgrade the current
4570 	 * properties if they haven't been customized.
4571 	 */
4572 
4573 	/*
4574 	 * If new_dpt_pgroup->sc_override, then act as though the property
4575 	 * group hasn't been customized.
4576 	 */
4577 	if (new_dpt_pgroup->sc_pgroup_override) {
4578 		(void) strcpy(ud_ctarg, ud_oldtarg);
4579 		goto nocust;
4580 	}
4581 
4582 	if (!ud_run_dpts_pg_set) {
4583 		warn(cf_missing, ient->sc_fmri, ud_name);
4584 		r = 0;
4585 		goto out;
4586 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4587 		switch (scf_error()) {
4588 		case SCF_ERROR_NOT_FOUND:
4589 			warn(cf_missing, ient->sc_fmri, ud_name);
4590 			r = 0;
4591 			goto out;
4592 
4593 		case SCF_ERROR_CONNECTION_BROKEN:
4594 			r = scferror2errno(scf_error());
4595 			goto out;
4596 
4597 		case SCF_ERROR_DELETED:
4598 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4599 			r = EBUSY;
4600 			goto out;
4601 
4602 		case SCF_ERROR_INVALID_ARGUMENT:
4603 		case SCF_ERROR_NOT_BOUND:
4604 		case SCF_ERROR_HANDLE_MISMATCH:
4605 		case SCF_ERROR_NOT_SET:
4606 		default:
4607 			bad_error("scf_pg_get_property", scf_error());
4608 		}
4609 	}
4610 
4611 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4612 		switch (scf_error()) {
4613 		case SCF_ERROR_NOT_FOUND:
4614 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4615 			warn(cf_inval, ient->sc_fmri, ud_name);
4616 			r = 0;
4617 			goto out;
4618 
4619 		case SCF_ERROR_DELETED:
4620 		case SCF_ERROR_CONNECTION_BROKEN:
4621 			r = scferror2errno(scf_error());
4622 			goto out;
4623 
4624 		case SCF_ERROR_HANDLE_MISMATCH:
4625 		case SCF_ERROR_NOT_BOUND:
4626 		case SCF_ERROR_NOT_SET:
4627 		case SCF_ERROR_PERMISSION_DENIED:
4628 		default:
4629 			bad_error("scf_property_get_value", scf_error());
4630 		}
4631 	}
4632 
4633 	ty = scf_value_type(ud_val);
4634 	assert(ty != SCF_TYPE_INVALID);
4635 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4636 		warn(cf_inval, ient->sc_fmri, ud_name);
4637 		r = 0;
4638 		goto out;
4639 	}
4640 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4641 	    0)
4642 		bad_error("scf_value_get_as_string", scf_error());
4643 
4644 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4645 	if (r == -1) {
4646 		warn(cf_inval, ient->sc_fmri, ud_name);
4647 		r = 0;
4648 		goto out;
4649 	} else if (r == -2) {
4650 		warn(li_corrupt, ient->sc_fmri);
4651 		r = EBADF;
4652 		goto out;
4653 	} else if (r == 0) {
4654 		/*
4655 		 * Target has been changed.  Only abort now if it's been
4656 		 * changed to something other than what's in the manifest.
4657 		 */
4658 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4659 		if (r == -1) {
4660 			warn(cf_inval, ient->sc_fmri, ud_name);
4661 			r = 0;
4662 			goto out;
4663 		} else if (r == 0) {
4664 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4665 			r = 0;
4666 			goto out;
4667 		} else if (r != 1) {
4668 			/* invalid sc_pgroup_fmri caught above */
4669 			bad_error("fmri_equal", r);
4670 		}
4671 
4672 		/*
4673 		 * Fetch the current dependency pg.  If it's what the manifest
4674 		 * says, then no problem.
4675 		 */
4676 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4677 		switch (serr) {
4678 		case SCF_ERROR_NONE:
4679 			break;
4680 
4681 		case SCF_ERROR_NOT_FOUND:
4682 			warn(cf_missing, ient->sc_fmri, ud_name);
4683 			r = 0;
4684 			goto out;
4685 
4686 		case SCF_ERROR_NO_MEMORY:
4687 			r = ENOMEM;
4688 			goto out;
4689 
4690 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4691 		case SCF_ERROR_INVALID_ARGUMENT:
4692 		default:
4693 			bad_error("fmri_to_entity", serr);
4694 		}
4695 
4696 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4697 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4698 		switch (r) {
4699 		case 0:
4700 			break;
4701 
4702 		case ECONNABORTED:
4703 			goto out;
4704 
4705 		case ECANCELED:
4706 		case ENOENT:
4707 			warn(cf_missing, ient->sc_fmri, ud_name);
4708 			r = 0;
4709 			goto out;
4710 
4711 		case EBADF:
4712 			warn(r_no_lvl, ud_ctarg);
4713 			goto out;
4714 
4715 		case EINVAL:
4716 		default:
4717 			bad_error("entity_get_running_pg", r);
4718 		}
4719 
4720 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4721 		switch (r) {
4722 		case 0:
4723 			break;
4724 
4725 		case ECANCELED:
4726 			warn(cf_missing, ient->sc_fmri, ud_name);
4727 			r = 0;
4728 			goto out;
4729 
4730 		case ECONNABORTED:
4731 		case ENOMEM:
4732 		case EBADF:
4733 			goto out;
4734 
4735 		case EACCES:
4736 		default:
4737 			bad_error("load_pg", r);
4738 		}
4739 
4740 		if (!pg_equal(current_pg, new_dpt_pgroup))
4741 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4742 		internal_pgroup_free(current_pg);
4743 		r = 0;
4744 		goto out;
4745 	} else if (r != 1) {
4746 		bad_error("fmri_equal", r);
4747 	}
4748 
4749 nocust:
4750 	/*
4751 	 * Target has not been customized.  Check the dependency property
4752 	 * group.
4753 	 */
4754 
4755 	if (old_dpt_pgroup == NULL) {
4756 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4757 		    ud_pg) != 0) {
4758 			switch (scf_error()) {
4759 			case SCF_ERROR_NOT_FOUND:
4760 				warn(li_corrupt, ient->sc_fmri);
4761 				return (EBADF);
4762 
4763 			case SCF_ERROR_DELETED:
4764 			case SCF_ERROR_CONNECTION_BROKEN:
4765 				return (scferror2errno(scf_error()));
4766 
4767 			case SCF_ERROR_NOT_BOUND:
4768 			case SCF_ERROR_HANDLE_MISMATCH:
4769 			case SCF_ERROR_INVALID_ARGUMENT:
4770 			case SCF_ERROR_NOT_SET:
4771 			default:
4772 				bad_error("scf_snaplevel_get_pg", scf_error());
4773 			}
4774 		}
4775 
4776 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4777 		    snap_lastimport);
4778 		switch (r) {
4779 		case 0:
4780 			break;
4781 
4782 		case ECANCELED:
4783 		case ECONNABORTED:
4784 		case ENOMEM:
4785 		case EBADF:
4786 			return (r);
4787 
4788 		case EACCES:
4789 		default:
4790 			bad_error("load_pg", r);
4791 		}
4792 	}
4793 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4794 	switch (serr) {
4795 	case SCF_ERROR_NONE:
4796 		break;
4797 
4798 	case SCF_ERROR_NOT_FOUND:
4799 		warn(cf_missing, ient->sc_fmri, ud_name);
4800 		r = 0;
4801 		goto out;
4802 
4803 	case SCF_ERROR_NO_MEMORY:
4804 		r = ENOMEM;
4805 		goto out;
4806 
4807 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4808 	case SCF_ERROR_INVALID_ARGUMENT:
4809 	default:
4810 		bad_error("fmri_to_entity", serr);
4811 	}
4812 
4813 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4814 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4815 	switch (r) {
4816 	case 0:
4817 		break;
4818 
4819 	case ECONNABORTED:
4820 		goto out;
4821 
4822 	case ECANCELED:
4823 	case ENOENT:
4824 		warn(cf_missing, ient->sc_fmri, ud_name);
4825 		r = 0;
4826 		goto out;
4827 
4828 	case EBADF:
4829 		warn(r_no_lvl, ud_ctarg);
4830 		goto out;
4831 
4832 	case EINVAL:
4833 	default:
4834 		bad_error("entity_get_running_pg", r);
4835 	}
4836 
4837 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4838 	switch (r) {
4839 	case 0:
4840 		break;
4841 
4842 	case ECANCELED:
4843 		warn(cf_missing, ient->sc_fmri, ud_name);
4844 		goto out;
4845 
4846 	case ECONNABORTED:
4847 	case ENOMEM:
4848 	case EBADF:
4849 		goto out;
4850 
4851 	case EACCES:
4852 	default:
4853 		bad_error("load_pg", r);
4854 	}
4855 
4856 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4857 		if (!pg_equal(current_pg, new_dpt_pgroup))
4858 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4859 		internal_pgroup_free(current_pg);
4860 		r = 0;
4861 		goto out;
4862 	}
4863 
4864 	/* Uncustomized.  Upgrade. */
4865 
4866 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4867 	switch (r) {
4868 	case 1:
4869 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4870 			/* Already upgraded. */
4871 			internal_pgroup_free(current_pg);
4872 			r = 0;
4873 			goto out;
4874 		}
4875 
4876 		internal_pgroup_free(current_pg);
4877 
4878 		/* upgrade current_pg */
4879 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4880 			switch (scf_error()) {
4881 			case SCF_ERROR_CONNECTION_BROKEN:
4882 				r = scferror2errno(scf_error());
4883 				goto out;
4884 
4885 			case SCF_ERROR_DELETED:
4886 				warn(cf_missing, ient->sc_fmri, ud_name);
4887 				r = 0;
4888 				goto out;
4889 
4890 			case SCF_ERROR_NOT_FOUND:
4891 				break;
4892 
4893 			case SCF_ERROR_INVALID_ARGUMENT:
4894 			case SCF_ERROR_NOT_BOUND:
4895 			case SCF_ERROR_NOT_SET:
4896 			case SCF_ERROR_HANDLE_MISMATCH:
4897 			default:
4898 				bad_error("entity_get_pg", scf_error());
4899 			}
4900 
4901 			if (tissvc)
4902 				r = scf_service_add_pg(target_ent, ud_name,
4903 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4904 			else
4905 				r = scf_instance_add_pg(target_ent, ud_name,
4906 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4907 			if (r != 0) {
4908 				switch (scf_error()) {
4909 				case SCF_ERROR_CONNECTION_BROKEN:
4910 				case SCF_ERROR_NO_RESOURCES:
4911 				case SCF_ERROR_BACKEND_READONLY:
4912 				case SCF_ERROR_BACKEND_ACCESS:
4913 					r = scferror2errno(scf_error());
4914 					goto out;
4915 
4916 				case SCF_ERROR_DELETED:
4917 					warn(cf_missing, ient->sc_fmri,
4918 					    ud_name);
4919 					r = 0;
4920 					goto out;
4921 
4922 				case SCF_ERROR_PERMISSION_DENIED:
4923 					warn(emsg_pg_deleted, ud_ctarg,
4924 					    ud_name);
4925 					r = EPERM;
4926 					goto out;
4927 
4928 				case SCF_ERROR_EXISTS:
4929 					warn(emsg_pg_added, ud_ctarg, ud_name);
4930 					r = EBUSY;
4931 					goto out;
4932 
4933 				case SCF_ERROR_NOT_BOUND:
4934 				case SCF_ERROR_HANDLE_MISMATCH:
4935 				case SCF_ERROR_INVALID_ARGUMENT:
4936 				case SCF_ERROR_NOT_SET:
4937 				default:
4938 					bad_error("entity_add_pg", scf_error());
4939 				}
4940 			}
4941 		}
4942 
4943 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4944 		switch (r) {
4945 		case 0:
4946 			break;
4947 
4948 		case ECANCELED:
4949 			warn(cf_missing, ient->sc_fmri, ud_name);
4950 			goto out;
4951 
4952 		case ECONNABORTED:
4953 		case ENOMEM:
4954 		case EBADF:
4955 			goto out;
4956 
4957 		case EACCES:
4958 		default:
4959 			bad_error("load_pg", r);
4960 		}
4961 
4962 		if (g_verbose)
4963 			warn(upgrading, ient->sc_fmri, ud_name);
4964 
4965 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4966 		    new_dpt_pgroup, 0, ient->sc_fmri);
4967 		switch (r) {
4968 		case 0:
4969 			break;
4970 
4971 		case ECANCELED:
4972 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4973 			r = EBUSY;
4974 			goto out;
4975 
4976 		case EPERM:
4977 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4978 			goto out;
4979 
4980 		case EBUSY:
4981 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4982 			goto out;
4983 
4984 		case ECONNABORTED:
4985 		case ENOMEM:
4986 		case ENOSPC:
4987 		case EROFS:
4988 		case EACCES:
4989 		case EINVAL:
4990 			goto out;
4991 
4992 		default:
4993 			bad_error("upgrade_pg", r);
4994 		}
4995 		break;
4996 
4997 	case 0: {
4998 		scf_transaction_entry_t *ent;
4999 		scf_value_t *val;
5000 
5001 		internal_pgroup_free(current_pg);
5002 
5003 		/* delete old pg */
5004 		if (g_verbose)
5005 			warn(upgrading, ient->sc_fmri, ud_name);
5006 
5007 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5008 			switch (scf_error()) {
5009 			case SCF_ERROR_CONNECTION_BROKEN:
5010 				r = scferror2errno(scf_error());
5011 				goto out;
5012 
5013 			case SCF_ERROR_DELETED:
5014 				warn(cf_missing, ient->sc_fmri, ud_name);
5015 				r = 0;
5016 				goto out;
5017 
5018 			case SCF_ERROR_NOT_FOUND:
5019 				break;
5020 
5021 			case SCF_ERROR_INVALID_ARGUMENT:
5022 			case SCF_ERROR_NOT_BOUND:
5023 			case SCF_ERROR_NOT_SET:
5024 			case SCF_ERROR_HANDLE_MISMATCH:
5025 			default:
5026 				bad_error("entity_get_pg", scf_error());
5027 			}
5028 		} else if (scf_pg_delete(ud_pg) != 0) {
5029 			switch (scf_error()) {
5030 			case SCF_ERROR_DELETED:
5031 				break;
5032 
5033 			case SCF_ERROR_CONNECTION_BROKEN:
5034 			case SCF_ERROR_BACKEND_READONLY:
5035 			case SCF_ERROR_BACKEND_ACCESS:
5036 				r = scferror2errno(scf_error());
5037 				goto out;
5038 
5039 			case SCF_ERROR_PERMISSION_DENIED:
5040 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5041 				r = scferror2errno(scf_error());
5042 				goto out;
5043 
5044 			case SCF_ERROR_NOT_SET:
5045 			default:
5046 				bad_error("scf_pg_delete", scf_error());
5047 			}
5048 		}
5049 
5050 		/* import new one */
5051 		cbdata.sc_handle = g_hndl;
5052 		cbdata.sc_trans = NULL;		/* handled below */
5053 		cbdata.sc_flags = 0;
5054 
5055 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5056 		if (r != UU_WALK_NEXT) {
5057 			if (r != UU_WALK_ERROR)
5058 				bad_error("lscf_dependent_import", r);
5059 
5060 			r = cbdata.sc_err;
5061 			goto out;
5062 		}
5063 
5064 		if (tx == NULL)
5065 			break;
5066 
5067 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5068 		    (val = scf_value_create(g_hndl)) == NULL) {
5069 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5070 				return (ENOMEM);
5071 
5072 			bad_error("scf_entry_create", scf_error());
5073 		}
5074 
5075 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5076 		    SCF_TYPE_FMRI) != 0) {
5077 			switch (scf_error()) {
5078 			case SCF_ERROR_CONNECTION_BROKEN:
5079 				r = scferror2errno(scf_error());
5080 				goto out;
5081 
5082 			case SCF_ERROR_DELETED:
5083 				warn(emsg_pg_deleted, ient->sc_fmri,
5084 				    "dependents");
5085 				r = EBUSY;
5086 				goto out;
5087 
5088 			case SCF_ERROR_NOT_FOUND:
5089 				break;
5090 
5091 			case SCF_ERROR_NOT_BOUND:
5092 			case SCF_ERROR_HANDLE_MISMATCH:
5093 			case SCF_ERROR_INVALID_ARGUMENT:
5094 			case SCF_ERROR_NOT_SET:
5095 			default:
5096 				bad_error("scf_transaction_property_"
5097 				    "change_type", scf_error());
5098 			}
5099 
5100 			if (scf_transaction_property_new(tx, ent, ud_name,
5101 			    SCF_TYPE_FMRI) != 0) {
5102 				switch (scf_error()) {
5103 				case SCF_ERROR_CONNECTION_BROKEN:
5104 					r = scferror2errno(scf_error());
5105 					goto out;
5106 
5107 				case SCF_ERROR_DELETED:
5108 					warn(emsg_pg_deleted, ient->sc_fmri,
5109 					    "dependents");
5110 					r = EBUSY;
5111 					goto out;
5112 
5113 				case SCF_ERROR_EXISTS:
5114 					warn(emsg_pg_changed, ient->sc_fmri,
5115 					    "dependents");
5116 					r = EBUSY;
5117 					goto out;
5118 
5119 				case SCF_ERROR_INVALID_ARGUMENT:
5120 				case SCF_ERROR_HANDLE_MISMATCH:
5121 				case SCF_ERROR_NOT_BOUND:
5122 				case SCF_ERROR_NOT_SET:
5123 				default:
5124 					bad_error("scf_transaction_property_"
5125 					    "new", scf_error());
5126 				}
5127 			}
5128 		}
5129 
5130 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5131 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5132 			/* invalid sc_pgroup_fmri caught above */
5133 			bad_error("scf_value_set_from_string",
5134 			    scf_error());
5135 
5136 		if (scf_entry_add_value(ent, val) != 0)
5137 			bad_error("scf_entry_add_value", scf_error());
5138 		break;
5139 	}
5140 
5141 	case -2:
5142 		warn(li_corrupt, ient->sc_fmri);
5143 		internal_pgroup_free(current_pg);
5144 		r = EBADF;
5145 		goto out;
5146 
5147 	case -1:
5148 	default:
5149 		/* invalid sc_pgroup_fmri caught above */
5150 		bad_error("fmri_equal", r);
5151 	}
5152 
5153 	r = 0;
5154 
5155 out:
5156 	if (old_dpt_pgroup != NULL)
5157 		internal_pgroup_free(old_dpt_pgroup);
5158 
5159 	return (r);
5160 }
5161 
5162 /*
5163  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5164  * would import it, except it seems to exist in the service anyway.  Compare
5165  * the existent dependent with the one we would import, and report any
5166  * differences (if there are none, be silent).  prop is the property which
5167  * represents the existent dependent (in the dependents property group) in the
5168  * entity corresponding to ient.
5169  *
5170  * Returns
5171  *   0 - success (Sort of.  At least, we can continue importing.)
5172  *   ECONNABORTED - repository connection broken
5173  *   EBUSY - ancestor of prop was deleted (error printed)
5174  *   ENOMEM - out of memory
5175  *   EBADF - corrupt property group (error printed)
5176  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5177  */
5178 static int
5179 handle_dependent_conflict(const entity_t * const ient,
5180     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5181 {
5182 	int r;
5183 	scf_type_t ty;
5184 	scf_error_t scfe;
5185 	void *tptr;
5186 	int tissvc;
5187 	pgroup_t *pgroup;
5188 
5189 	if (scf_property_get_value(prop, ud_val) != 0) {
5190 		switch (scf_error()) {
5191 		case SCF_ERROR_CONNECTION_BROKEN:
5192 			return (scferror2errno(scf_error()));
5193 
5194 		case SCF_ERROR_DELETED:
5195 			warn(emsg_pg_deleted, ient->sc_fmri,
5196 			    new_dpt_pgroup->sc_pgroup_name);
5197 			return (EBUSY);
5198 
5199 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5200 		case SCF_ERROR_NOT_FOUND:
5201 			warn(gettext("Conflict upgrading %s (not importing "
5202 			    "dependent \"%s\" because it already exists.)  "
5203 			    "Warning: The \"%s/%2$s\" property has more or "
5204 			    "fewer than one value)).\n"), ient->sc_fmri,
5205 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5206 			return (0);
5207 
5208 		case SCF_ERROR_HANDLE_MISMATCH:
5209 		case SCF_ERROR_NOT_BOUND:
5210 		case SCF_ERROR_NOT_SET:
5211 		case SCF_ERROR_PERMISSION_DENIED:
5212 		default:
5213 			bad_error("scf_property_get_value",
5214 			    scf_error());
5215 		}
5216 	}
5217 
5218 	ty = scf_value_type(ud_val);
5219 	assert(ty != SCF_TYPE_INVALID);
5220 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5221 		warn(gettext("Conflict upgrading %s (not importing dependent "
5222 		    "\"%s\" because it already exists).  Warning: The "
5223 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5224 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5225 		    scf_type_to_string(ty), "dependents");
5226 		return (0);
5227 	}
5228 
5229 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5230 	    0)
5231 		bad_error("scf_value_get_as_string", scf_error());
5232 
5233 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5234 	switch (r) {
5235 	case 0:
5236 		warn(gettext("Conflict upgrading %s (not importing dependent "
5237 		    "\"%s\" (target \"%s\") because it already exists with "
5238 		    "target \"%s\").\n"), ient->sc_fmri,
5239 		    new_dpt_pgroup->sc_pgroup_name,
5240 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5241 		return (0);
5242 
5243 	case 1:
5244 		break;
5245 
5246 	case -1:
5247 		warn(gettext("Conflict upgrading %s (not importing dependent "
5248 		    "\"%s\" because it already exists).  Warning: The current "
5249 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5250 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5251 		return (0);
5252 
5253 	case -2:
5254 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5255 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5256 		    new_dpt_pgroup->sc_pgroup_fmri);
5257 		return (EINVAL);
5258 
5259 	default:
5260 		bad_error("fmri_equal", r);
5261 	}
5262 
5263 	/* compare dependency pgs in target */
5264 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5265 	switch (scfe) {
5266 	case SCF_ERROR_NONE:
5267 		break;
5268 
5269 	case SCF_ERROR_NO_MEMORY:
5270 		return (ENOMEM);
5271 
5272 	case SCF_ERROR_NOT_FOUND:
5273 		warn(emsg_dpt_dangling, ient->sc_fmri,
5274 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5275 		return (0);
5276 
5277 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5278 	case SCF_ERROR_INVALID_ARGUMENT:
5279 	default:
5280 		bad_error("fmri_to_entity", scfe);
5281 	}
5282 
5283 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5284 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5285 	switch (r) {
5286 	case 0:
5287 		break;
5288 
5289 	case ECONNABORTED:
5290 		return (r);
5291 
5292 	case ECANCELED:
5293 		warn(emsg_dpt_dangling, ient->sc_fmri,
5294 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5295 		return (0);
5296 
5297 	case EBADF:
5298 		if (tissvc)
5299 			warn(gettext("%s has an instance with a \"%s\" "
5300 			    "snapshot which is missing a snaplevel.\n"),
5301 			    ud_ctarg, "running");
5302 		else
5303 			warn(gettext("%s has a \"%s\" snapshot which is "
5304 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5305 		/* FALLTHROUGH */
5306 
5307 	case ENOENT:
5308 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5309 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5310 		    new_dpt_pgroup->sc_pgroup_name);
5311 		return (0);
5312 
5313 	case EINVAL:
5314 	default:
5315 		bad_error("entity_get_running_pg", r);
5316 	}
5317 
5318 	pgroup = internal_pgroup_new();
5319 	if (pgroup == NULL)
5320 		return (ENOMEM);
5321 
5322 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5323 	switch (r) {
5324 	case 0:
5325 		break;
5326 
5327 	case ECONNABORTED:
5328 	case EBADF:
5329 	case ENOMEM:
5330 		internal_pgroup_free(pgroup);
5331 		return (r);
5332 
5333 	case ECANCELED:
5334 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5335 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5336 		    new_dpt_pgroup->sc_pgroup_name);
5337 		internal_pgroup_free(pgroup);
5338 		return (0);
5339 
5340 	case EACCES:
5341 	default:
5342 		bad_error("load_pg", r);
5343 	}
5344 
5345 	/* report differences */
5346 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5347 	internal_pgroup_free(pgroup);
5348 	return (0);
5349 }
5350 
5351 /*
5352  * lipg is a property group in the last-import snapshot of ent, which is an
5353  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5354  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5355  * in ents's property groups, compare and upgrade ent appropriately.
5356  *
5357  * Returns
5358  *   0 - success
5359  *   ECONNABORTED - repository connection broken
5360  *   ENOMEM - out of memory
5361  *   ENOSPC - configd is out of resources
5362  *   EINVAL - ient has invalid dependent (error printed)
5363  *	    - ient has invalid pgroup_t (error printed)
5364  *   ECANCELED - ent has been deleted
5365  *   ENODEV - entity containing lipg has been deleted
5366  *	    - entity containing running has been deleted
5367  *   EPERM - could not delete pg (permission denied) (error printed)
5368  *	   - couldn't upgrade dependents (permission denied) (error printed)
5369  *	   - couldn't import pg (permission denied) (error printed)
5370  *	   - couldn't upgrade pg (permission denied) (error printed)
5371  *   EROFS - could not delete pg (repository read-only)
5372  *	   - couldn't upgrade dependents (repository read-only)
5373  *	   - couldn't import pg (repository read-only)
5374  *	   - couldn't upgrade pg (repository read-only)
5375  *   EACCES - could not delete pg (backend access denied)
5376  *	    - couldn't upgrade dependents (backend access denied)
5377  *	    - couldn't import pg (backend access denied)
5378  *	    - couldn't upgrade pg (backend access denied)
5379  *	    - couldn't read property (backend access denied)
5380  *   EBUSY - property group was added (error printed)
5381  *	   - property group was deleted (error printed)
5382  *	   - property group changed (error printed)
5383  *	   - "dependents" pg was added, changed, or deleted (error printed)
5384  *	   - dependent target deleted (error printed)
5385  *	   - dependent pg changed (error printed)
5386  *   EBADF - imp_snpl is corrupt (error printed)
5387  *	   - ent has bad pg (error printed)
5388  *   EEXIST - dependent collision in target service (error printed)
5389  */
5390 static int
5391 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5392     const scf_snaplevel_t *running)
5393 {
5394 	int r;
5395 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5396 	scf_callback_t cbdata;
5397 
5398 	const char * const cf_pg_missing =
5399 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5400 	const char * const deleting =
5401 	    gettext("%s: Deleting property group \"%s\".\n");
5402 
5403 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5404 
5405 	/* Skip dependent property groups. */
5406 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5407 		switch (scf_error()) {
5408 		case SCF_ERROR_DELETED:
5409 			return (ENODEV);
5410 
5411 		case SCF_ERROR_CONNECTION_BROKEN:
5412 			return (ECONNABORTED);
5413 
5414 		case SCF_ERROR_NOT_SET:
5415 		case SCF_ERROR_NOT_BOUND:
5416 		default:
5417 			bad_error("scf_pg_get_type", scf_error());
5418 		}
5419 	}
5420 
5421 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5422 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5423 			return (0);
5424 
5425 		switch (scf_error()) {
5426 		case SCF_ERROR_NOT_FOUND:
5427 			break;
5428 
5429 		case SCF_ERROR_CONNECTION_BROKEN:
5430 			return (ECONNABORTED);
5431 
5432 		case SCF_ERROR_DELETED:
5433 			return (ENODEV);
5434 
5435 		case SCF_ERROR_INVALID_ARGUMENT:
5436 		case SCF_ERROR_NOT_BOUND:
5437 		case SCF_ERROR_HANDLE_MISMATCH:
5438 		case SCF_ERROR_NOT_SET:
5439 		default:
5440 			bad_error("scf_pg_get_property", scf_error());
5441 		}
5442 	}
5443 
5444 	/* lookup pg in new properties */
5445 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5446 		switch (scf_error()) {
5447 		case SCF_ERROR_DELETED:
5448 			return (ENODEV);
5449 
5450 		case SCF_ERROR_CONNECTION_BROKEN:
5451 			return (ECONNABORTED);
5452 
5453 		case SCF_ERROR_NOT_SET:
5454 		case SCF_ERROR_NOT_BOUND:
5455 		default:
5456 			bad_error("scf_pg_get_name", scf_error());
5457 		}
5458 	}
5459 
5460 	pgrp.sc_pgroup_name = imp_str;
5461 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5462 
5463 	if (mpg != NULL)
5464 		mpg->sc_pgroup_seen = 1;
5465 
5466 	/* Special handling for dependents */
5467 	if (strcmp(imp_str, "dependents") == 0)
5468 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5469 
5470 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5471 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5472 
5473 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5474 		/* property group was deleted from manifest */
5475 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5476 			switch (scf_error()) {
5477 			case SCF_ERROR_NOT_FOUND:
5478 				return (0);
5479 
5480 			case SCF_ERROR_DELETED:
5481 			case SCF_ERROR_CONNECTION_BROKEN:
5482 				return (scferror2errno(scf_error()));
5483 
5484 			case SCF_ERROR_INVALID_ARGUMENT:
5485 			case SCF_ERROR_HANDLE_MISMATCH:
5486 			case SCF_ERROR_NOT_BOUND:
5487 			case SCF_ERROR_NOT_SET:
5488 			default:
5489 				bad_error("entity_get_pg", scf_error());
5490 			}
5491 		}
5492 
5493 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5494 			if (g_verbose)
5495 				warn(deleting, ient->sc_fmri, imp_str);
5496 			if (scf_pg_delete(imp_pg2) == 0)
5497 				return (0);
5498 
5499 			switch (scf_error()) {
5500 			case SCF_ERROR_DELETED:
5501 				return (0);
5502 
5503 			case SCF_ERROR_CONNECTION_BROKEN:
5504 			case SCF_ERROR_BACKEND_READONLY:
5505 			case SCF_ERROR_BACKEND_ACCESS:
5506 				return (scferror2errno(scf_error()));
5507 
5508 			case SCF_ERROR_PERMISSION_DENIED:
5509 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5510 				return (scferror2errno(scf_error()));
5511 
5512 			case SCF_ERROR_NOT_SET:
5513 			default:
5514 				bad_error("scf_pg_delete", scf_error());
5515 			}
5516 		}
5517 
5518 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5519 		switch (r) {
5520 		case 0:
5521 			break;
5522 
5523 		case ECANCELED:
5524 			return (ENODEV);
5525 
5526 		case ECONNABORTED:
5527 		case ENOMEM:
5528 		case EBADF:
5529 		case EACCES:
5530 			return (r);
5531 
5532 		default:
5533 			bad_error("load_pg", r);
5534 		}
5535 
5536 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5537 		switch (r) {
5538 		case 0:
5539 			break;
5540 
5541 		case ECANCELED:
5542 		case ECONNABORTED:
5543 		case ENOMEM:
5544 		case EBADF:
5545 		case EACCES:
5546 			internal_pgroup_free(lipg_i);
5547 			return (r);
5548 
5549 		default:
5550 			bad_error("load_pg", r);
5551 		}
5552 
5553 		if (pg_equal(lipg_i, curpg_i)) {
5554 			if (g_verbose)
5555 				warn(deleting, ient->sc_fmri, imp_str);
5556 			if (scf_pg_delete(imp_pg2) != 0) {
5557 				switch (scf_error()) {
5558 				case SCF_ERROR_DELETED:
5559 					break;
5560 
5561 				case SCF_ERROR_CONNECTION_BROKEN:
5562 					internal_pgroup_free(lipg_i);
5563 					internal_pgroup_free(curpg_i);
5564 					return (ECONNABORTED);
5565 
5566 				case SCF_ERROR_NOT_SET:
5567 				case SCF_ERROR_NOT_BOUND:
5568 				default:
5569 					bad_error("scf_pg_delete", scf_error());
5570 				}
5571 			}
5572 		} else {
5573 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5574 		}
5575 
5576 		internal_pgroup_free(lipg_i);
5577 		internal_pgroup_free(curpg_i);
5578 
5579 		return (0);
5580 	}
5581 
5582 	/*
5583 	 * Only dependent pgs can have override set, and we skipped those
5584 	 * above.
5585 	 */
5586 	assert(!mpg->sc_pgroup_override);
5587 
5588 	/* compare */
5589 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5590 	switch (r) {
5591 	case 0:
5592 		break;
5593 
5594 	case ECANCELED:
5595 		return (ENODEV);
5596 
5597 	case ECONNABORTED:
5598 	case EBADF:
5599 	case ENOMEM:
5600 	case EACCES:
5601 		return (r);
5602 
5603 	default:
5604 		bad_error("load_pg", r);
5605 	}
5606 
5607 	if (pg_equal(mpg, lipg_i)) {
5608 		/* The manifest pg has not changed.  Move on. */
5609 		r = 0;
5610 		goto out;
5611 	}
5612 
5613 	/* upgrade current properties according to lipg & mpg */
5614 	if (running != NULL)
5615 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5616 	else
5617 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5618 	if (r != 0) {
5619 		switch (scf_error()) {
5620 		case SCF_ERROR_CONNECTION_BROKEN:
5621 			r = scferror2errno(scf_error());
5622 			goto out;
5623 
5624 		case SCF_ERROR_DELETED:
5625 			if (running != NULL)
5626 				r = ENODEV;
5627 			else
5628 				r = ECANCELED;
5629 			goto out;
5630 
5631 		case SCF_ERROR_NOT_FOUND:
5632 			break;
5633 
5634 		case SCF_ERROR_INVALID_ARGUMENT:
5635 		case SCF_ERROR_HANDLE_MISMATCH:
5636 		case SCF_ERROR_NOT_BOUND:
5637 		case SCF_ERROR_NOT_SET:
5638 		default:
5639 			bad_error("entity_get_pg", scf_error());
5640 		}
5641 
5642 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5643 
5644 		r = 0;
5645 		goto out;
5646 	}
5647 
5648 	r = load_pg_attrs(imp_pg2, &curpg_i);
5649 	switch (r) {
5650 	case 0:
5651 		break;
5652 
5653 	case ECANCELED:
5654 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5655 		r = 0;
5656 		goto out;
5657 
5658 	case ECONNABORTED:
5659 	case ENOMEM:
5660 		goto out;
5661 
5662 	default:
5663 		bad_error("load_pg_attrs", r);
5664 	}
5665 
5666 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5667 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5668 		internal_pgroup_free(curpg_i);
5669 		r = 0;
5670 		goto out;
5671 	}
5672 
5673 	internal_pgroup_free(curpg_i);
5674 
5675 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5676 	switch (r) {
5677 	case 0:
5678 		break;
5679 
5680 	case ECANCELED:
5681 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5682 		r = 0;
5683 		goto out;
5684 
5685 	case ECONNABORTED:
5686 	case EBADF:
5687 	case ENOMEM:
5688 	case EACCES:
5689 		goto out;
5690 
5691 	default:
5692 		bad_error("load_pg", r);
5693 	}
5694 
5695 	if (pg_equal(lipg_i, curpg_i) &&
5696 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5697 		int do_delete = 1;
5698 
5699 		if (g_verbose)
5700 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5701 			    ient->sc_fmri, mpg->sc_pgroup_name);
5702 
5703 		internal_pgroup_free(curpg_i);
5704 
5705 		if (running != NULL &&
5706 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5707 			switch (scf_error()) {
5708 			case SCF_ERROR_DELETED:
5709 				r = ECANCELED;
5710 				goto out;
5711 
5712 			case SCF_ERROR_NOT_FOUND:
5713 				do_delete = 0;
5714 				break;
5715 
5716 			case SCF_ERROR_CONNECTION_BROKEN:
5717 				r = scferror2errno(scf_error());
5718 				goto out;
5719 
5720 			case SCF_ERROR_HANDLE_MISMATCH:
5721 			case SCF_ERROR_INVALID_ARGUMENT:
5722 			case SCF_ERROR_NOT_SET:
5723 			case SCF_ERROR_NOT_BOUND:
5724 			default:
5725 				bad_error("entity_get_pg", scf_error());
5726 			}
5727 		}
5728 
5729 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5730 			switch (scf_error()) {
5731 			case SCF_ERROR_DELETED:
5732 				break;
5733 
5734 			case SCF_ERROR_CONNECTION_BROKEN:
5735 			case SCF_ERROR_BACKEND_READONLY:
5736 			case SCF_ERROR_BACKEND_ACCESS:
5737 				r = scferror2errno(scf_error());
5738 				goto out;
5739 
5740 			case SCF_ERROR_PERMISSION_DENIED:
5741 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5742 				    ient->sc_fmri);
5743 				r = scferror2errno(scf_error());
5744 				goto out;
5745 
5746 			case SCF_ERROR_NOT_SET:
5747 			case SCF_ERROR_NOT_BOUND:
5748 			default:
5749 				bad_error("scf_pg_delete", scf_error());
5750 			}
5751 		}
5752 
5753 		cbdata.sc_handle = g_hndl;
5754 		cbdata.sc_parent = ent;
5755 		cbdata.sc_service = issvc;
5756 		cbdata.sc_flags = 0;
5757 		cbdata.sc_source_fmri = ient->sc_fmri;
5758 		cbdata.sc_target_fmri = ient->sc_fmri;
5759 
5760 		r = entity_pgroup_import(mpg, &cbdata);
5761 		switch (r) {
5762 		case UU_WALK_NEXT:
5763 			r = 0;
5764 			goto out;
5765 
5766 		case UU_WALK_ERROR:
5767 			if (cbdata.sc_err == EEXIST) {
5768 				warn(emsg_pg_added, ient->sc_fmri,
5769 				    mpg->sc_pgroup_name);
5770 				r = EBUSY;
5771 			} else {
5772 				r = cbdata.sc_err;
5773 			}
5774 			goto out;
5775 
5776 		default:
5777 			bad_error("entity_pgroup_import", r);
5778 		}
5779 	}
5780 
5781 	if (running != NULL &&
5782 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5783 		switch (scf_error()) {
5784 		case SCF_ERROR_CONNECTION_BROKEN:
5785 		case SCF_ERROR_DELETED:
5786 			r = scferror2errno(scf_error());
5787 			goto out;
5788 
5789 		case SCF_ERROR_NOT_FOUND:
5790 			break;
5791 
5792 		case SCF_ERROR_HANDLE_MISMATCH:
5793 		case SCF_ERROR_INVALID_ARGUMENT:
5794 		case SCF_ERROR_NOT_SET:
5795 		case SCF_ERROR_NOT_BOUND:
5796 		default:
5797 			bad_error("entity_get_pg", scf_error());
5798 		}
5799 
5800 		cbdata.sc_handle = g_hndl;
5801 		cbdata.sc_parent = ent;
5802 		cbdata.sc_service = issvc;
5803 		cbdata.sc_flags = SCI_FORCE;
5804 		cbdata.sc_source_fmri = ient->sc_fmri;
5805 		cbdata.sc_target_fmri = ient->sc_fmri;
5806 
5807 		r = entity_pgroup_import(mpg, &cbdata);
5808 		switch (r) {
5809 		case UU_WALK_NEXT:
5810 			r = 0;
5811 			goto out;
5812 
5813 		case UU_WALK_ERROR:
5814 			if (cbdata.sc_err == EEXIST) {
5815 				warn(emsg_pg_added, ient->sc_fmri,
5816 				    mpg->sc_pgroup_name);
5817 				r = EBUSY;
5818 			} else {
5819 				r = cbdata.sc_err;
5820 			}
5821 			goto out;
5822 
5823 		default:
5824 			bad_error("entity_pgroup_import", r);
5825 		}
5826 	}
5827 
5828 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5829 	internal_pgroup_free(curpg_i);
5830 	switch (r) {
5831 	case 0:
5832 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5833 		break;
5834 
5835 	case ECANCELED:
5836 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5837 		r = EBUSY;
5838 		break;
5839 
5840 	case EPERM:
5841 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5842 		break;
5843 
5844 	case EBUSY:
5845 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5846 		break;
5847 
5848 	case ECONNABORTED:
5849 	case ENOMEM:
5850 	case ENOSPC:
5851 	case EROFS:
5852 	case EACCES:
5853 	case EINVAL:
5854 		break;
5855 
5856 	default:
5857 		bad_error("upgrade_pg", r);
5858 	}
5859 
5860 out:
5861 	internal_pgroup_free(lipg_i);
5862 	return (r);
5863 }
5864 
5865 /*
5866  * Upgrade the properties of ent according to snpl & ient.
5867  *
5868  * Returns
5869  *   0 - success
5870  *   ECONNABORTED - repository connection broken
5871  *   ENOMEM - out of memory
5872  *   ENOSPC - configd is out of resources
5873  *   ECANCELED - ent was deleted
5874  *   ENODEV - entity containing snpl was deleted
5875  *	    - entity containing running was deleted
5876  *   EBADF - imp_snpl is corrupt (error printed)
5877  *	   - ent has corrupt pg (error printed)
5878  *	   - dependent has corrupt pg (error printed)
5879  *	   - dependent target has a corrupt snapshot (error printed)
5880  *   EBUSY - pg was added, changed, or deleted (error printed)
5881  *	   - dependent target was deleted (error printed)
5882  *	   - dependent pg changed (error printed)
5883  *   EINVAL - invalid property group name (error printed)
5884  *	    - invalid property name (error printed)
5885  *	    - invalid value (error printed)
5886  *	    - ient has invalid pgroup or dependent (error printed)
5887  *   EPERM - could not create property group (permission denied) (error printed)
5888  *	   - could not modify property group (permission denied) (error printed)
5889  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5890  *   EROFS - could not create property group (repository read-only)
5891  *	   - couldn't delete, upgrade, or import pg or dependent
5892  *   EACCES - could not create property group (backend access denied)
5893  *	    - couldn't delete, upgrade, or import pg or dependent
5894  *   EEXIST - dependent collision in target service (error printed)
5895  */
5896 static int
5897 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5898     entity_t *ient)
5899 {
5900 	pgroup_t *pg, *rpg;
5901 	int r;
5902 	uu_list_t *pgs = ient->sc_pgroups;
5903 
5904 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5905 
5906 	/* clear sc_sceen for pgs */
5907 	if (uu_list_walk(pgs, clear_int,
5908 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5909 		bad_error("uu_list_walk", uu_error());
5910 
5911 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5912 		switch (scf_error()) {
5913 		case SCF_ERROR_DELETED:
5914 			return (ENODEV);
5915 
5916 		case SCF_ERROR_CONNECTION_BROKEN:
5917 			return (ECONNABORTED);
5918 
5919 		case SCF_ERROR_NOT_SET:
5920 		case SCF_ERROR_NOT_BOUND:
5921 		case SCF_ERROR_HANDLE_MISMATCH:
5922 		default:
5923 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5924 		}
5925 	}
5926 
5927 	for (;;) {
5928 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5929 		if (r == 0)
5930 			break;
5931 		if (r == 1) {
5932 			r = process_old_pg(imp_pg, ient, ent, running);
5933 			switch (r) {
5934 			case 0:
5935 				break;
5936 
5937 			case ECONNABORTED:
5938 			case ENOMEM:
5939 			case ENOSPC:
5940 			case ECANCELED:
5941 			case ENODEV:
5942 			case EPERM:
5943 			case EROFS:
5944 			case EACCES:
5945 			case EBADF:
5946 			case EBUSY:
5947 			case EINVAL:
5948 			case EEXIST:
5949 				return (r);
5950 
5951 			default:
5952 				bad_error("process_old_pg", r);
5953 			}
5954 			continue;
5955 		}
5956 		if (r != -1)
5957 			bad_error("scf_iter_next_pg", r);
5958 
5959 		switch (scf_error()) {
5960 		case SCF_ERROR_DELETED:
5961 			return (ENODEV);
5962 
5963 		case SCF_ERROR_CONNECTION_BROKEN:
5964 			return (ECONNABORTED);
5965 
5966 		case SCF_ERROR_HANDLE_MISMATCH:
5967 		case SCF_ERROR_NOT_BOUND:
5968 		case SCF_ERROR_NOT_SET:
5969 		case SCF_ERROR_INVALID_ARGUMENT:
5970 		default:
5971 			bad_error("scf_iter_next_pg", scf_error());
5972 		}
5973 	}
5974 
5975 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5976 		if (pg->sc_pgroup_seen)
5977 			continue;
5978 
5979 		/* pg is new */
5980 
5981 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5982 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5983 			    ent);
5984 			switch (r) {
5985 			case 0:
5986 				break;
5987 
5988 			case ECONNABORTED:
5989 			case ENOMEM:
5990 			case ENOSPC:
5991 			case ECANCELED:
5992 			case ENODEV:
5993 			case EBADF:
5994 			case EBUSY:
5995 			case EINVAL:
5996 			case EPERM:
5997 			case EROFS:
5998 			case EACCES:
5999 			case EEXIST:
6000 				return (r);
6001 
6002 			default:
6003 				bad_error("upgrade_dependents", r);
6004 			}
6005 			continue;
6006 		}
6007 
6008 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6009 			r = upgrade_manifestfiles(pg, ient, running, ent);
6010 			switch (r) {
6011 			case 0:
6012 				break;
6013 
6014 			case ECONNABORTED:
6015 			case ENOMEM:
6016 			case ENOSPC:
6017 			case ECANCELED:
6018 			case ENODEV:
6019 			case EBADF:
6020 			case EBUSY:
6021 			case EINVAL:
6022 			case EPERM:
6023 			case EROFS:
6024 			case EACCES:
6025 			case EEXIST:
6026 				return (r);
6027 
6028 			default:
6029 				bad_error("upgrade_manifestfiles", r);
6030 			}
6031 			continue;
6032 		}
6033 
6034 		if (running != NULL) {
6035 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6036 			    imp_pg);
6037 		} else {
6038 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6039 			    imp_pg);
6040 		}
6041 		if (r != 0) {
6042 			scf_callback_t cbdata;
6043 
6044 			switch (scf_error()) {
6045 			case SCF_ERROR_NOT_FOUND:
6046 				break;
6047 
6048 			case SCF_ERROR_CONNECTION_BROKEN:
6049 				return (scferror2errno(scf_error()));
6050 
6051 			case SCF_ERROR_DELETED:
6052 				if (running != NULL)
6053 					return (ENODEV);
6054 				else
6055 					return (scferror2errno(scf_error()));
6056 
6057 			case SCF_ERROR_INVALID_ARGUMENT:
6058 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6059 				    pg->sc_pgroup_name);
6060 				return (EINVAL);
6061 
6062 			case SCF_ERROR_NOT_SET:
6063 			case SCF_ERROR_HANDLE_MISMATCH:
6064 			case SCF_ERROR_NOT_BOUND:
6065 			default:
6066 				bad_error("entity_get_pg", scf_error());
6067 			}
6068 
6069 			/* User doesn't have pg, so import it. */
6070 
6071 			cbdata.sc_handle = g_hndl;
6072 			cbdata.sc_parent = ent;
6073 			cbdata.sc_service = issvc;
6074 			cbdata.sc_flags = SCI_FORCE;
6075 			cbdata.sc_source_fmri = ient->sc_fmri;
6076 			cbdata.sc_target_fmri = ient->sc_fmri;
6077 
6078 			r = entity_pgroup_import(pg, &cbdata);
6079 			switch (r) {
6080 			case UU_WALK_NEXT:
6081 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6082 				continue;
6083 
6084 			case UU_WALK_ERROR:
6085 				if (cbdata.sc_err == EEXIST) {
6086 					warn(emsg_pg_added, ient->sc_fmri,
6087 					    pg->sc_pgroup_name);
6088 					return (EBUSY);
6089 				}
6090 				return (cbdata.sc_err);
6091 
6092 			default:
6093 				bad_error("entity_pgroup_import", r);
6094 			}
6095 		}
6096 
6097 		/* report differences between pg & current */
6098 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6099 		switch (r) {
6100 		case 0:
6101 			break;
6102 
6103 		case ECANCELED:
6104 			warn(emsg_pg_deleted, ient->sc_fmri,
6105 			    pg->sc_pgroup_name);
6106 			return (EBUSY);
6107 
6108 		case ECONNABORTED:
6109 		case EBADF:
6110 		case ENOMEM:
6111 		case EACCES:
6112 			return (r);
6113 
6114 		default:
6115 			bad_error("load_pg", r);
6116 		}
6117 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6118 		internal_pgroup_free(rpg);
6119 		rpg = NULL;
6120 	}
6121 
6122 	return (0);
6123 }
6124 
6125 /*
6126  * Import an instance.  If it doesn't exist, create it.  If it has
6127  * a last-import snapshot, upgrade its properties.  Finish by updating its
6128  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6129  * could have been created for a dependent tag in another manifest.  Import the
6130  * new properties.  If there's a conflict, don't override, like now?
6131  *
6132  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6133  * lcbdata->sc_err to
6134  *   ECONNABORTED - repository connection broken
6135  *   ENOMEM - out of memory
6136  *   ENOSPC - svc.configd is out of resources
6137  *   EEXIST - dependency collision in dependent service (error printed)
6138  *   EPERM - couldn't create temporary instance (permission denied)
6139  *	   - couldn't import into temporary instance (permission denied)
6140  *	   - couldn't take snapshot (permission denied)
6141  *	   - couldn't upgrade properties (permission denied)
6142  *	   - couldn't import properties (permission denied)
6143  *	   - couldn't import dependents (permission denied)
6144  *   EROFS - couldn't create temporary instance (repository read-only)
6145  *	   - couldn't import into temporary instance (repository read-only)
6146  *	   - couldn't upgrade properties (repository read-only)
6147  *	   - couldn't import properties (repository read-only)
6148  *	   - couldn't import dependents (repository read-only)
6149  *   EACCES - couldn't create temporary instance (backend access denied)
6150  *	    - couldn't import into temporary instance (backend access denied)
6151  *	    - couldn't upgrade properties (backend access denied)
6152  *	    - couldn't import properties (backend access denied)
6153  *	    - couldn't import dependents (backend access denied)
6154  *   EINVAL - invalid instance name (error printed)
6155  *	    - invalid pgroup_t's (error printed)
6156  *	    - invalid dependents (error printed)
6157  *   EBUSY - temporary service deleted (error printed)
6158  *	   - temporary instance deleted (error printed)
6159  *	   - temporary instance changed (error printed)
6160  *	   - temporary instance already exists (error printed)
6161  *	   - instance deleted (error printed)
6162  *   EBADF - instance has corrupt last-import snapshot (error printed)
6163  *	   - instance is corrupt (error printed)
6164  *	   - dependent has corrupt pg (error printed)
6165  *	   - dependent target has a corrupt snapshot (error printed)
6166  *   -1 - unknown libscf error (error printed)
6167  */
6168 static int
6169 lscf_instance_import(void *v, void *pvt)
6170 {
6171 	entity_t *inst = v;
6172 	scf_callback_t ctx;
6173 	scf_callback_t *lcbdata = pvt;
6174 	scf_service_t *rsvc = lcbdata->sc_parent;
6175 	int r;
6176 	scf_snaplevel_t *running;
6177 	int flags = lcbdata->sc_flags;
6178 
6179 	const char * const emsg_tdel =
6180 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6181 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6182 	    "changed unexpectedly.\n");
6183 	const char * const emsg_del = gettext("%s changed unexpectedly "
6184 	    "(instance \"%s\" was deleted.)\n");
6185 	const char * const emsg_badsnap = gettext(
6186 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6187 
6188 	/*
6189 	 * prepare last-import snapshot:
6190 	 * create temporary instance (service was precreated)
6191 	 * populate with properties from bundle
6192 	 * take snapshot
6193 	 */
6194 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6195 		switch (scf_error()) {
6196 		case SCF_ERROR_CONNECTION_BROKEN:
6197 		case SCF_ERROR_NO_RESOURCES:
6198 		case SCF_ERROR_BACKEND_READONLY:
6199 		case SCF_ERROR_BACKEND_ACCESS:
6200 			return (stash_scferror(lcbdata));
6201 
6202 		case SCF_ERROR_EXISTS:
6203 			warn(gettext("Temporary service svc:/%s "
6204 			    "changed unexpectedly (instance \"%s\" added).\n"),
6205 			    imp_tsname, inst->sc_name);
6206 			lcbdata->sc_err = EBUSY;
6207 			return (UU_WALK_ERROR);
6208 
6209 		case SCF_ERROR_DELETED:
6210 			warn(gettext("Temporary service svc:/%s "
6211 			    "was deleted unexpectedly.\n"), imp_tsname);
6212 			lcbdata->sc_err = EBUSY;
6213 			return (UU_WALK_ERROR);
6214 
6215 		case SCF_ERROR_INVALID_ARGUMENT:
6216 			warn(gettext("Invalid instance name \"%s\".\n"),
6217 			    inst->sc_name);
6218 			return (stash_scferror(lcbdata));
6219 
6220 		case SCF_ERROR_PERMISSION_DENIED:
6221 			warn(gettext("Could not create temporary instance "
6222 			    "\"%s\" in svc:/%s (permission denied).\n"),
6223 			    inst->sc_name, imp_tsname);
6224 			return (stash_scferror(lcbdata));
6225 
6226 		case SCF_ERROR_HANDLE_MISMATCH:
6227 		case SCF_ERROR_NOT_BOUND:
6228 		case SCF_ERROR_NOT_SET:
6229 		default:
6230 			bad_error("scf_service_add_instance", scf_error());
6231 		}
6232 	}
6233 
6234 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6235 	    inst->sc_name);
6236 	if (r < 0)
6237 		bad_error("snprintf", errno);
6238 
6239 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6240 	    lcbdata->sc_flags | SCI_NOENABLED);
6241 	switch (r) {
6242 	case 0:
6243 		break;
6244 
6245 	case ECANCELED:
6246 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6247 		lcbdata->sc_err = EBUSY;
6248 		r = UU_WALK_ERROR;
6249 		goto deltemp;
6250 
6251 	case EEXIST:
6252 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6253 		lcbdata->sc_err = EBUSY;
6254 		r = UU_WALK_ERROR;
6255 		goto deltemp;
6256 
6257 	case ECONNABORTED:
6258 		goto connaborted;
6259 
6260 	case ENOMEM:
6261 	case ENOSPC:
6262 	case EPERM:
6263 	case EROFS:
6264 	case EACCES:
6265 	case EINVAL:
6266 	case EBUSY:
6267 		lcbdata->sc_err = r;
6268 		r = UU_WALK_ERROR;
6269 		goto deltemp;
6270 
6271 	default:
6272 		bad_error("lscf_import_instance_pgs", r);
6273 	}
6274 
6275 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6276 	    inst->sc_name);
6277 	if (r < 0)
6278 		bad_error("snprintf", errno);
6279 
6280 	ctx.sc_handle = lcbdata->sc_handle;
6281 	ctx.sc_parent = imp_tinst;
6282 	ctx.sc_service = 0;
6283 	ctx.sc_source_fmri = inst->sc_fmri;
6284 	ctx.sc_target_fmri = imp_str;
6285 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6286 	    UU_DEFAULT) != 0) {
6287 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6288 			bad_error("uu_list_walk", uu_error());
6289 
6290 		switch (ctx.sc_err) {
6291 		case ECONNABORTED:
6292 			goto connaborted;
6293 
6294 		case ECANCELED:
6295 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6296 			lcbdata->sc_err = EBUSY;
6297 			break;
6298 
6299 		case EEXIST:
6300 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6301 			lcbdata->sc_err = EBUSY;
6302 			break;
6303 
6304 		default:
6305 			lcbdata->sc_err = ctx.sc_err;
6306 		}
6307 		r = UU_WALK_ERROR;
6308 		goto deltemp;
6309 	}
6310 
6311 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6312 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6313 		switch (scf_error()) {
6314 		case SCF_ERROR_CONNECTION_BROKEN:
6315 			goto connaborted;
6316 
6317 		case SCF_ERROR_NO_RESOURCES:
6318 			r = stash_scferror(lcbdata);
6319 			goto deltemp;
6320 
6321 		case SCF_ERROR_EXISTS:
6322 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6323 			lcbdata->sc_err = EBUSY;
6324 			r = UU_WALK_ERROR;
6325 			goto deltemp;
6326 
6327 		case SCF_ERROR_PERMISSION_DENIED:
6328 			warn(gettext("Could not take \"%s\" snapshot of %s "
6329 			    "(permission denied).\n"), snap_lastimport,
6330 			    imp_str);
6331 			r = stash_scferror(lcbdata);
6332 			goto deltemp;
6333 
6334 		default:
6335 			scfwarn();
6336 			lcbdata->sc_err = -1;
6337 			r = UU_WALK_ERROR;
6338 			goto deltemp;
6339 
6340 		case SCF_ERROR_HANDLE_MISMATCH:
6341 		case SCF_ERROR_INVALID_ARGUMENT:
6342 		case SCF_ERROR_NOT_SET:
6343 			bad_error("_scf_snapshot_take_new_named", scf_error());
6344 		}
6345 	}
6346 
6347 	if (lcbdata->sc_flags & SCI_FRESH)
6348 		goto fresh;
6349 
6350 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6351 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6352 		    imp_lisnap) != 0) {
6353 			switch (scf_error()) {
6354 			case SCF_ERROR_DELETED:
6355 				warn(emsg_del, inst->sc_parent->sc_fmri,
6356 				    inst->sc_name);
6357 				lcbdata->sc_err = EBUSY;
6358 				r = UU_WALK_ERROR;
6359 				goto deltemp;
6360 
6361 			case SCF_ERROR_NOT_FOUND:
6362 				flags |= SCI_FORCE;
6363 				goto nosnap;
6364 
6365 			case SCF_ERROR_CONNECTION_BROKEN:
6366 				goto connaborted;
6367 
6368 			case SCF_ERROR_INVALID_ARGUMENT:
6369 			case SCF_ERROR_HANDLE_MISMATCH:
6370 			case SCF_ERROR_NOT_BOUND:
6371 			case SCF_ERROR_NOT_SET:
6372 			default:
6373 				bad_error("scf_instance_get_snapshot",
6374 				    scf_error());
6375 			}
6376 		}
6377 
6378 		/* upgrade */
6379 
6380 		/*
6381 		 * compare new properties with last-import properties
6382 		 * upgrade current properties
6383 		 */
6384 		/* clear sc_sceen for pgs */
6385 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6386 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6387 		    0)
6388 			bad_error("uu_list_walk", uu_error());
6389 
6390 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6391 		switch (r) {
6392 		case 0:
6393 			break;
6394 
6395 		case ECONNABORTED:
6396 			goto connaborted;
6397 
6398 		case ECANCELED:
6399 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6400 			lcbdata->sc_err = EBUSY;
6401 			r = UU_WALK_ERROR;
6402 			goto deltemp;
6403 
6404 		case ENOENT:
6405 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6406 			lcbdata->sc_err = EBADF;
6407 			r = UU_WALK_ERROR;
6408 			goto deltemp;
6409 
6410 		default:
6411 			bad_error("get_snaplevel", r);
6412 		}
6413 
6414 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6415 		    imp_rsnap) != 0) {
6416 			switch (scf_error()) {
6417 			case SCF_ERROR_DELETED:
6418 				warn(emsg_del, inst->sc_parent->sc_fmri,
6419 				    inst->sc_name);
6420 				lcbdata->sc_err = EBUSY;
6421 				r = UU_WALK_ERROR;
6422 				goto deltemp;
6423 
6424 			case SCF_ERROR_NOT_FOUND:
6425 				break;
6426 
6427 			case SCF_ERROR_CONNECTION_BROKEN:
6428 				goto connaborted;
6429 
6430 			case SCF_ERROR_INVALID_ARGUMENT:
6431 			case SCF_ERROR_HANDLE_MISMATCH:
6432 			case SCF_ERROR_NOT_BOUND:
6433 			case SCF_ERROR_NOT_SET:
6434 			default:
6435 				bad_error("scf_instance_get_snapshot",
6436 				    scf_error());
6437 			}
6438 
6439 			running = NULL;
6440 		} else {
6441 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6442 			switch (r) {
6443 			case 0:
6444 				running = imp_rsnpl;
6445 				break;
6446 
6447 			case ECONNABORTED:
6448 				goto connaborted;
6449 
6450 			case ECANCELED:
6451 				warn(emsg_del, inst->sc_parent->sc_fmri,
6452 				    inst->sc_name);
6453 				lcbdata->sc_err = EBUSY;
6454 				r = UU_WALK_ERROR;
6455 				goto deltemp;
6456 
6457 			case ENOENT:
6458 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6459 				lcbdata->sc_err = EBADF;
6460 				r = UU_WALK_ERROR;
6461 				goto deltemp;
6462 
6463 			default:
6464 				bad_error("get_snaplevel", r);
6465 			}
6466 		}
6467 
6468 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6469 		switch (r) {
6470 		case 0:
6471 			break;
6472 
6473 		case ECANCELED:
6474 		case ENODEV:
6475 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6476 			lcbdata->sc_err = EBUSY;
6477 			r = UU_WALK_ERROR;
6478 			goto deltemp;
6479 
6480 		case ECONNABORTED:
6481 			goto connaborted;
6482 
6483 		case ENOMEM:
6484 		case ENOSPC:
6485 		case EBADF:
6486 		case EBUSY:
6487 		case EINVAL:
6488 		case EPERM:
6489 		case EROFS:
6490 		case EACCES:
6491 		case EEXIST:
6492 			lcbdata->sc_err = r;
6493 			r = UU_WALK_ERROR;
6494 			goto deltemp;
6495 
6496 		default:
6497 			bad_error("upgrade_props", r);
6498 		}
6499 
6500 		inst->sc_import_state = IMPORT_PROP_DONE;
6501 	} else {
6502 		switch (scf_error()) {
6503 		case SCF_ERROR_CONNECTION_BROKEN:
6504 			goto connaborted;
6505 
6506 		case SCF_ERROR_NOT_FOUND:
6507 			break;
6508 
6509 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6510 		case SCF_ERROR_HANDLE_MISMATCH:
6511 		case SCF_ERROR_NOT_BOUND:
6512 		case SCF_ERROR_NOT_SET:
6513 		default:
6514 			bad_error("scf_service_get_instance", scf_error());
6515 		}
6516 
6517 fresh:
6518 		/* create instance */
6519 		if (scf_service_add_instance(rsvc, inst->sc_name,
6520 		    imp_inst) != 0) {
6521 			switch (scf_error()) {
6522 			case SCF_ERROR_CONNECTION_BROKEN:
6523 				goto connaborted;
6524 
6525 			case SCF_ERROR_NO_RESOURCES:
6526 			case SCF_ERROR_BACKEND_READONLY:
6527 			case SCF_ERROR_BACKEND_ACCESS:
6528 				r = stash_scferror(lcbdata);
6529 				goto deltemp;
6530 
6531 			case SCF_ERROR_EXISTS:
6532 				warn(gettext("%s changed unexpectedly "
6533 				    "(instance \"%s\" added).\n"),
6534 				    inst->sc_parent->sc_fmri, inst->sc_name);
6535 				lcbdata->sc_err = EBUSY;
6536 				r = UU_WALK_ERROR;
6537 				goto deltemp;
6538 
6539 			case SCF_ERROR_PERMISSION_DENIED:
6540 				warn(gettext("Could not create \"%s\" instance "
6541 				    "in %s (permission denied).\n"),
6542 				    inst->sc_name, inst->sc_parent->sc_fmri);
6543 				r = stash_scferror(lcbdata);
6544 				goto deltemp;
6545 
6546 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6547 			case SCF_ERROR_HANDLE_MISMATCH:
6548 			case SCF_ERROR_NOT_BOUND:
6549 			case SCF_ERROR_NOT_SET:
6550 			default:
6551 				bad_error("scf_service_add_instance",
6552 				    scf_error());
6553 			}
6554 		}
6555 
6556 nosnap:
6557 		/*
6558 		 * Create a last-import snapshot to serve as an attachment
6559 		 * point for the real one from the temporary instance.  Since
6560 		 * the contents is irrelevant, take it now, while the instance
6561 		 * is empty, to minimize svc.configd's work.
6562 		 */
6563 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6564 		    imp_lisnap) != 0) {
6565 			switch (scf_error()) {
6566 			case SCF_ERROR_CONNECTION_BROKEN:
6567 				goto connaborted;
6568 
6569 			case SCF_ERROR_NO_RESOURCES:
6570 				r = stash_scferror(lcbdata);
6571 				goto deltemp;
6572 
6573 			case SCF_ERROR_EXISTS:
6574 				warn(gettext("%s changed unexpectedly "
6575 				    "(snapshot \"%s\" added).\n"),
6576 				    inst->sc_fmri, snap_lastimport);
6577 				lcbdata->sc_err = EBUSY;
6578 				r = UU_WALK_ERROR;
6579 				goto deltemp;
6580 
6581 			case SCF_ERROR_PERMISSION_DENIED:
6582 				warn(gettext("Could not take \"%s\" snapshot "
6583 				    "of %s (permission denied).\n"),
6584 				    snap_lastimport, inst->sc_fmri);
6585 				r = stash_scferror(lcbdata);
6586 				goto deltemp;
6587 
6588 			default:
6589 				scfwarn();
6590 				lcbdata->sc_err = -1;
6591 				r = UU_WALK_ERROR;
6592 				goto deltemp;
6593 
6594 			case SCF_ERROR_NOT_SET:
6595 			case SCF_ERROR_INTERNAL:
6596 			case SCF_ERROR_INVALID_ARGUMENT:
6597 			case SCF_ERROR_HANDLE_MISMATCH:
6598 				bad_error("_scf_snapshot_take_new",
6599 				    scf_error());
6600 			}
6601 		}
6602 
6603 		if (li_only)
6604 			goto lionly;
6605 
6606 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6607 
6608 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6609 		    flags);
6610 		switch (r) {
6611 		case 0:
6612 			break;
6613 
6614 		case ECONNABORTED:
6615 			goto connaborted;
6616 
6617 		case ECANCELED:
6618 			warn(gettext("%s changed unexpectedly "
6619 			    "(instance \"%s\" deleted).\n"),
6620 			    inst->sc_parent->sc_fmri, inst->sc_name);
6621 			lcbdata->sc_err = EBUSY;
6622 			r = UU_WALK_ERROR;
6623 			goto deltemp;
6624 
6625 		case EEXIST:
6626 			warn(gettext("%s changed unexpectedly "
6627 			    "(property group added).\n"), inst->sc_fmri);
6628 			lcbdata->sc_err = EBUSY;
6629 			r = UU_WALK_ERROR;
6630 			goto deltemp;
6631 
6632 		default:
6633 			lcbdata->sc_err = r;
6634 			r = UU_WALK_ERROR;
6635 			goto deltemp;
6636 
6637 		case EINVAL:	/* caught above */
6638 			bad_error("lscf_import_instance_pgs", r);
6639 		}
6640 
6641 		ctx.sc_parent = imp_inst;
6642 		ctx.sc_service = 0;
6643 		ctx.sc_trans = NULL;
6644 		ctx.sc_flags = 0;
6645 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6646 		    &ctx, UU_DEFAULT) != 0) {
6647 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6648 				bad_error("uu_list_walk", uu_error());
6649 
6650 			if (ctx.sc_err == ECONNABORTED)
6651 				goto connaborted;
6652 			lcbdata->sc_err = ctx.sc_err;
6653 			r = UU_WALK_ERROR;
6654 			goto deltemp;
6655 		}
6656 
6657 		inst->sc_import_state = IMPORT_PROP_DONE;
6658 
6659 		if (g_verbose)
6660 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6661 			    snap_initial, inst->sc_fmri);
6662 		r = take_snap(imp_inst, snap_initial, imp_snap);
6663 		switch (r) {
6664 		case 0:
6665 			break;
6666 
6667 		case ECONNABORTED:
6668 			goto connaborted;
6669 
6670 		case ENOSPC:
6671 		case -1:
6672 			lcbdata->sc_err = r;
6673 			r = UU_WALK_ERROR;
6674 			goto deltemp;
6675 
6676 		case ECANCELED:
6677 			warn(gettext("%s changed unexpectedly "
6678 			    "(instance %s deleted).\n"),
6679 			    inst->sc_parent->sc_fmri, inst->sc_name);
6680 			lcbdata->sc_err = r;
6681 			r = UU_WALK_ERROR;
6682 			goto deltemp;
6683 
6684 		case EPERM:
6685 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6686 			lcbdata->sc_err = r;
6687 			r = UU_WALK_ERROR;
6688 			goto deltemp;
6689 
6690 		default:
6691 			bad_error("take_snap", r);
6692 		}
6693 	}
6694 
6695 lionly:
6696 	if (lcbdata->sc_flags & SCI_NOSNAP)
6697 		goto deltemp;
6698 
6699 	/* transfer snapshot from temporary instance */
6700 	if (g_verbose)
6701 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6702 		    snap_lastimport, inst->sc_fmri);
6703 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6704 		switch (scf_error()) {
6705 		case SCF_ERROR_CONNECTION_BROKEN:
6706 			goto connaborted;
6707 
6708 		case SCF_ERROR_NO_RESOURCES:
6709 			r = stash_scferror(lcbdata);
6710 			goto deltemp;
6711 
6712 		case SCF_ERROR_PERMISSION_DENIED:
6713 			warn(gettext("Could not take \"%s\" snapshot for %s "
6714 			    "(permission denied).\n"), snap_lastimport,
6715 			    inst->sc_fmri);
6716 			r = stash_scferror(lcbdata);
6717 			goto deltemp;
6718 
6719 		case SCF_ERROR_NOT_SET:
6720 		case SCF_ERROR_HANDLE_MISMATCH:
6721 		default:
6722 			bad_error("_scf_snapshot_attach", scf_error());
6723 		}
6724 	}
6725 
6726 	inst->sc_import_state = IMPORT_COMPLETE;
6727 
6728 	r = UU_WALK_NEXT;
6729 
6730 deltemp:
6731 	/* delete temporary instance */
6732 	if (scf_instance_delete(imp_tinst) != 0) {
6733 		switch (scf_error()) {
6734 		case SCF_ERROR_DELETED:
6735 			break;
6736 
6737 		case SCF_ERROR_CONNECTION_BROKEN:
6738 			goto connaborted;
6739 
6740 		case SCF_ERROR_NOT_SET:
6741 		case SCF_ERROR_NOT_BOUND:
6742 		default:
6743 			bad_error("scf_instance_delete", scf_error());
6744 		}
6745 	}
6746 
6747 	return (r);
6748 
6749 connaborted:
6750 	warn(gettext("Could not delete svc:/%s:%s "
6751 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6752 	lcbdata->sc_err = ECONNABORTED;
6753 	return (UU_WALK_ERROR);
6754 }
6755 
6756 /*
6757  * When an instance is imported we end up telling configd about it. Once we tell
6758  * configd about these changes, startd eventually notices. If this is a new
6759  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6760  * property group. However, many of the other tools expect that this property
6761  * group exists and has certain values.
6762  *
6763  * These values are added asynchronously by startd. We should not return from
6764  * this routine until we can verify that the property group we need is there.
6765  *
6766  * Before we go ahead and verify this, we have to ask ourselves an important
6767  * question: Is the early manifest service currently running?  Because if it is
6768  * running and it has invoked us, then the service will never get a restarter
6769  * property because svc.startd is blocked on EMI finishing before it lets itself
6770  * fully connect to svc.configd. Of course, this means that this race condition
6771  * is in fact impossible to 100% eliminate.
6772  *
6773  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6774  * the state of the EMI instance. If it is online it bails out and makes sure
6775  * that it doesn't run again. In this case, we're going to do something similar,
6776  * only if the state is online, then we're going to actually verify. EMI always
6777  * has to be present, but it can be explicitly disabled to reduce the amount of
6778  * damage it can cause. If EMI has been disabled then we no longer have to worry
6779  * about the implicit race condition and can go ahead and check things. If EMI
6780  * is in some state that isn't online or disabled and isn't runinng, then we
6781  * assume that things are rather bad and we're not going to get in your way,
6782  * even if the rest of SMF does.
6783  *
6784  * Returns 0 on success or returns an errno.
6785  */
6786 #ifndef NATIVE_BUILD
6787 static int
6788 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6789 {
6790 	int ret, err;
6791 	struct timespec ts;
6792 	char *emi_state;
6793 
6794 	/*
6795 	 * smf_get_state does not distinguish between its different failure
6796 	 * modes: memory allocation failures, SMF internal failures, and a lack
6797 	 * of EMI entirely because it's been removed. In these cases, we're
6798 	 * going to be conservative and opt to say that if we don't know, better
6799 	 * to not block import or falsely warn to the user.
6800 	 */
6801 	if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6802 		return (0);
6803 	}
6804 
6805 	/*
6806 	 * As per the block comment for this function check the state of EMI
6807 	 */
6808 	if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6809 	    strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6810 		warn(gettext("Not validating instance %s:%s because EMI's "
6811 		    "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6812 		free(emi_state);
6813 		return (0);
6814 	}
6815 
6816 	free(emi_state);
6817 
6818 	/*
6819 	 * First we have to get the property.
6820 	 */
6821 	if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6822 		ret = scf_error();
6823 		warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6824 		return (ret);
6825 	}
6826 
6827 	/*
6828 	 * We should always be able to get the instance. It should already
6829 	 * exist because we just created it or got it. There probably is a
6830 	 * slim chance that someone may have come in and deleted it though from
6831 	 * under us.
6832 	 */
6833 	if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6834 	    != 0) {
6835 		ret = scf_error();
6836 		warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6837 		switch (ret) {
6838 		case SCF_ERROR_DELETED:
6839 			err = ENODEV;
6840 			break;
6841 		case SCF_ERROR_CONNECTION_BROKEN:
6842 			warn(gettext("Lost repository connection\n"));
6843 			err = ECONNABORTED;
6844 			break;
6845 		case SCF_ERROR_NOT_FOUND:
6846 			warn(gettext("Instance \"%s\" disappeared out from "
6847 			    "under us.\n"), inst->sc_name);
6848 			err = ENOENT;
6849 			break;
6850 		default:
6851 			bad_error("scf_service_get_instance", ret);
6852 		}
6853 
6854 		return (err);
6855 	}
6856 
6857 	/*
6858 	 * An astute observer may want to use _scf_wait_pg which would notify us
6859 	 * of a property group change, unfortunately that does not work if the
6860 	 * property group in question does not exist. So instead we have to
6861 	 * manually poll and ask smf the best way to get to it.
6862 	 */
6863 	while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6864 	    != SCF_SUCCESS) {
6865 		ret = scf_error();
6866 		if (ret != SCF_ERROR_NOT_FOUND) {
6867 			warn(gettext("Failed to get restarter property "
6868 			    "group for instance: %s\n"), inst->sc_name);
6869 			switch (ret) {
6870 			case SCF_ERROR_DELETED:
6871 				err = ENODEV;
6872 				break;
6873 			case SCF_ERROR_CONNECTION_BROKEN:
6874 				warn(gettext("Lost repository connection\n"));
6875 				err = ECONNABORTED;
6876 				break;
6877 			default:
6878 				bad_error("scf_service_get_instance", ret);
6879 			}
6880 
6881 			return (err);
6882 		}
6883 
6884 		ts.tv_sec = pg_timeout / NANOSEC;
6885 		ts.tv_nsec = pg_timeout % NANOSEC;
6886 
6887 		(void) nanosleep(&ts, NULL);
6888 	}
6889 
6890 	/*
6891 	 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6892 	 * So in addition to the property group being present, we need to wait
6893 	 * for the property to be there in some form.
6894 	 *
6895 	 * Note that a property group is a frozen snapshot in time. To properly
6896 	 * get beyond this, you have to refresh the property group each time.
6897 	 */
6898 	while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6899 	    imp_prop)) != 0) {
6900 
6901 		ret = scf_error();
6902 		if (ret != SCF_ERROR_NOT_FOUND) {
6903 			warn(gettext("Failed to get property %s from the "
6904 			    "restarter property group of instance %s\n"),
6905 			    SCF_PROPERTY_STATE, inst->sc_name);
6906 			switch (ret) {
6907 			case SCF_ERROR_CONNECTION_BROKEN:
6908 				warn(gettext("Lost repository connection\n"));
6909 				err = ECONNABORTED;
6910 				break;
6911 			case SCF_ERROR_DELETED:
6912 				err = ENODEV;
6913 				break;
6914 			default:
6915 				bad_error("scf_pg_get_property", ret);
6916 			}
6917 
6918 			return (err);
6919 		}
6920 
6921 		ts.tv_sec = pg_timeout / NANOSEC;
6922 		ts.tv_nsec = pg_timeout % NANOSEC;
6923 
6924 		(void) nanosleep(&ts, NULL);
6925 
6926 		ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6927 		if (ret != SCF_SUCCESS) {
6928 			warn(gettext("Failed to get restarter property "
6929 			    "group for instance: %s\n"), inst->sc_name);
6930 			switch (ret) {
6931 			case SCF_ERROR_DELETED:
6932 				err = ENODEV;
6933 				break;
6934 			case SCF_ERROR_CONNECTION_BROKEN:
6935 				warn(gettext("Lost repository connection\n"));
6936 				err = ECONNABORTED;
6937 				break;
6938 			default:
6939 				bad_error("scf_service_get_instance", ret);
6940 			}
6941 
6942 			return (err);
6943 		}
6944 	}
6945 
6946 	/*
6947 	 * We don't have to free the property groups or other values that we got
6948 	 * because we stored them in global variables that are allocated and
6949 	 * freed by the routines that call into these functions. Unless of
6950 	 * course the rest of the code here that we are basing this on is
6951 	 * mistaken.
6952 	 */
6953 	return (0);
6954 }
6955 #endif
6956 
6957 /*
6958  * If the service is missing, create it, import its properties, and import the
6959  * instances.  Since the service is brand new, it should be empty, and if we
6960  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6961  *
6962  * If the service exists, we want to upgrade its properties and import the
6963  * instances.  Upgrade requires a last-import snapshot, though, which are
6964  * children of instances, so first we'll have to go through the instances
6965  * looking for a last-import snapshot.  If we don't find one then we'll just
6966  * override-import the service properties (but don't delete existing
6967  * properties: another service might have declared us as a dependent).  Before
6968  * we change anything, though, we want to take the previous snapshots.  We
6969  * also give lscf_instance_import() a leg up on taking last-import snapshots
6970  * by importing the manifest's service properties into a temporary service.
6971  *
6972  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6973  * sets lcbdata->sc_err to
6974  *   ECONNABORTED - repository connection broken
6975  *   ENOMEM - out of memory
6976  *   ENOSPC - svc.configd is out of resources
6977  *   EPERM - couldn't create temporary service (error printed)
6978  *	   - couldn't import into temp service (error printed)
6979  *	   - couldn't create service (error printed)
6980  *	   - couldn't import dependent (error printed)
6981  *	   - couldn't take snapshot (error printed)
6982  *	   - couldn't create instance (error printed)
6983  *	   - couldn't create, modify, or delete pg (error printed)
6984  *	   - couldn't create, modify, or delete dependent (error printed)
6985  *	   - couldn't import instance (error printed)
6986  *   EROFS - couldn't create temporary service (repository read-only)
6987  *	   - couldn't import into temporary service (repository read-only)
6988  *	   - couldn't create service (repository read-only)
6989  *	   - couldn't import dependent (repository read-only)
6990  *	   - couldn't create instance (repository read-only)
6991  *	   - couldn't create, modify, or delete pg or dependent
6992  *	   - couldn't import instance (repository read-only)
6993  *   EACCES - couldn't create temporary service (backend access denied)
6994  *	    - couldn't import into temporary service (backend access denied)
6995  *	    - couldn't create service (backend access denied)
6996  *	    - couldn't import dependent (backend access denied)
6997  *	    - couldn't create instance (backend access denied)
6998  *	    - couldn't create, modify, or delete pg or dependent
6999  *	    - couldn't import instance (backend access denied)
7000  *   EINVAL - service name is invalid (error printed)
7001  *	    - service name is too long (error printed)
7002  *	    - s has invalid pgroup (error printed)
7003  *	    - s has invalid dependent (error printed)
7004  *	    - instance name is invalid (error printed)
7005  *	    - instance entity_t is invalid (error printed)
7006  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7007  *	    - couldn't import dependent (dependency pg already exists) (printed)
7008  *	    - dependency collision in dependent service (error printed)
7009  *   EBUSY - temporary service deleted (error printed)
7010  *	   - property group added to temporary service (error printed)
7011  *	   - new property group changed or was deleted (error printed)
7012  *	   - service was added unexpectedly (error printed)
7013  *	   - service was deleted unexpectedly (error printed)
7014  *	   - property group added to new service (error printed)
7015  *	   - instance added unexpectedly (error printed)
7016  *	   - instance deleted unexpectedly (error printed)
7017  *	   - dependent service deleted unexpectedly (error printed)
7018  *	   - pg was added, changed, or deleted (error printed)
7019  *	   - dependent pg changed (error printed)
7020  *	   - temporary instance added, changed, or deleted (error printed)
7021  *   EBADF - a last-import snapshot is corrupt (error printed)
7022  *	   - the service is corrupt (error printed)
7023  *	   - a dependent is corrupt (error printed)
7024  *	   - an instance is corrupt (error printed)
7025  *	   - an instance has a corrupt last-import snapshot (error printed)
7026  *	   - dependent target has a corrupt snapshot (error printed)
7027  *   -1 - unknown libscf error (error printed)
7028  */
7029 static int
7030 lscf_service_import(void *v, void *pvt)
7031 {
7032 	entity_t *s = v;
7033 	scf_callback_t cbdata;
7034 	scf_callback_t *lcbdata = pvt;
7035 	scf_scope_t *scope = lcbdata->sc_parent;
7036 	entity_t *inst, linst;
7037 	int r;
7038 	int fresh = 0;
7039 	scf_snaplevel_t *running;
7040 	int have_ge = 0;
7041 	boolean_t retried = B_FALSE;
7042 
7043 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
7044 	    "was deleted unexpectedly.\n");
7045 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7046 	    "changed unexpectedly (property group added).\n");
7047 	const char * const s_deleted =
7048 	    gettext("%s was deleted unexpectedly.\n");
7049 	const char * const i_deleted =
7050 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7051 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7052 	    "is corrupt (missing service snaplevel).\n");
7053 	const char * const s_mfile_upd =
7054 	    gettext("Unable to update the manifest file connection "
7055 	    "for %s\n");
7056 
7057 	li_only = 0;
7058 	/* Validate the service name */
7059 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7060 		switch (scf_error()) {
7061 		case SCF_ERROR_CONNECTION_BROKEN:
7062 			return (stash_scferror(lcbdata));
7063 
7064 		case SCF_ERROR_INVALID_ARGUMENT:
7065 			warn(gettext("\"%s\" is an invalid service name.  "
7066 			    "Cannot import.\n"), s->sc_name);
7067 			return (stash_scferror(lcbdata));
7068 
7069 		case SCF_ERROR_NOT_FOUND:
7070 			break;
7071 
7072 		case SCF_ERROR_HANDLE_MISMATCH:
7073 		case SCF_ERROR_NOT_BOUND:
7074 		case SCF_ERROR_NOT_SET:
7075 		default:
7076 			bad_error("scf_scope_get_service", scf_error());
7077 		}
7078 	}
7079 
7080 	/* create temporary service */
7081 	/*
7082 	 * the size of the buffer was reduced to max_scf_name_len to prevent
7083 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
7084 	 * should be restored to its original value (max_scf_name_len +1)
7085 	 */
7086 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7087 	if (r < 0)
7088 		bad_error("snprintf", errno);
7089 	if (r > max_scf_name_len) {
7090 		warn(gettext(
7091 		    "Service name \"%s\" is too long.  Cannot import.\n"),
7092 		    s->sc_name);
7093 		lcbdata->sc_err = EINVAL;
7094 		return (UU_WALK_ERROR);
7095 	}
7096 
7097 retry:
7098 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7099 		switch (scf_error()) {
7100 		case SCF_ERROR_CONNECTION_BROKEN:
7101 		case SCF_ERROR_NO_RESOURCES:
7102 		case SCF_ERROR_BACKEND_READONLY:
7103 		case SCF_ERROR_BACKEND_ACCESS:
7104 			return (stash_scferror(lcbdata));
7105 
7106 		case SCF_ERROR_EXISTS:
7107 			if (!retried) {
7108 				lscf_delete(imp_tsname, 0);
7109 				retried = B_TRUE;
7110 				goto retry;
7111 			}
7112 			warn(gettext(
7113 			    "Temporary service \"%s\" must be deleted before "
7114 			    "this manifest can be imported.\n"), imp_tsname);
7115 			return (stash_scferror(lcbdata));
7116 
7117 		case SCF_ERROR_PERMISSION_DENIED:
7118 			warn(gettext("Could not create temporary service "
7119 			    "\"%s\" (permission denied).\n"), imp_tsname);
7120 			return (stash_scferror(lcbdata));
7121 
7122 		case SCF_ERROR_INVALID_ARGUMENT:
7123 		case SCF_ERROR_HANDLE_MISMATCH:
7124 		case SCF_ERROR_NOT_BOUND:
7125 		case SCF_ERROR_NOT_SET:
7126 		default:
7127 			bad_error("scf_scope_add_service", scf_error());
7128 		}
7129 	}
7130 
7131 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7132 	if (r < 0)
7133 		bad_error("snprintf", errno);
7134 
7135 	cbdata.sc_handle = lcbdata->sc_handle;
7136 	cbdata.sc_parent = imp_tsvc;
7137 	cbdata.sc_service = 1;
7138 	cbdata.sc_source_fmri = s->sc_fmri;
7139 	cbdata.sc_target_fmri = imp_str;
7140 	cbdata.sc_flags = 0;
7141 
7142 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7143 	    UU_DEFAULT) != 0) {
7144 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7145 			bad_error("uu_list_walk", uu_error());
7146 
7147 		lcbdata->sc_err = cbdata.sc_err;
7148 		switch (cbdata.sc_err) {
7149 		case ECONNABORTED:
7150 			goto connaborted;
7151 
7152 		case ECANCELED:
7153 			warn(ts_deleted, imp_tsname);
7154 			lcbdata->sc_err = EBUSY;
7155 			return (UU_WALK_ERROR);
7156 
7157 		case EEXIST:
7158 			warn(ts_pg_added, imp_tsname);
7159 			lcbdata->sc_err = EBUSY;
7160 			return (UU_WALK_ERROR);
7161 		}
7162 
7163 		r = UU_WALK_ERROR;
7164 		goto deltemp;
7165 	}
7166 
7167 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7168 	    UU_DEFAULT) != 0) {
7169 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7170 			bad_error("uu_list_walk", uu_error());
7171 
7172 		lcbdata->sc_err = cbdata.sc_err;
7173 		switch (cbdata.sc_err) {
7174 		case ECONNABORTED:
7175 			goto connaborted;
7176 
7177 		case ECANCELED:
7178 			warn(ts_deleted, imp_tsname);
7179 			lcbdata->sc_err = EBUSY;
7180 			return (UU_WALK_ERROR);
7181 
7182 		case EEXIST:
7183 			warn(ts_pg_added, imp_tsname);
7184 			lcbdata->sc_err = EBUSY;
7185 			return (UU_WALK_ERROR);
7186 		}
7187 
7188 		r = UU_WALK_ERROR;
7189 		goto deltemp;
7190 	}
7191 
7192 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7193 		switch (scf_error()) {
7194 		case SCF_ERROR_NOT_FOUND:
7195 			break;
7196 
7197 		case SCF_ERROR_CONNECTION_BROKEN:
7198 			goto connaborted;
7199 
7200 		case SCF_ERROR_INVALID_ARGUMENT:
7201 		case SCF_ERROR_HANDLE_MISMATCH:
7202 		case SCF_ERROR_NOT_BOUND:
7203 		case SCF_ERROR_NOT_SET:
7204 		default:
7205 			bad_error("scf_scope_get_service", scf_error());
7206 		}
7207 
7208 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7209 			switch (scf_error()) {
7210 			case SCF_ERROR_CONNECTION_BROKEN:
7211 				goto connaborted;
7212 
7213 			case SCF_ERROR_NO_RESOURCES:
7214 			case SCF_ERROR_BACKEND_READONLY:
7215 			case SCF_ERROR_BACKEND_ACCESS:
7216 				r = stash_scferror(lcbdata);
7217 				goto deltemp;
7218 
7219 			case SCF_ERROR_EXISTS:
7220 				warn(gettext("Scope \"%s\" changed unexpectedly"
7221 				    " (service \"%s\" added).\n"),
7222 				    SCF_SCOPE_LOCAL, s->sc_name);
7223 				lcbdata->sc_err = EBUSY;
7224 				goto deltemp;
7225 
7226 			case SCF_ERROR_PERMISSION_DENIED:
7227 				warn(gettext("Could not create service \"%s\" "
7228 				    "(permission denied).\n"), s->sc_name);
7229 				goto deltemp;
7230 
7231 			case SCF_ERROR_INVALID_ARGUMENT:
7232 			case SCF_ERROR_HANDLE_MISMATCH:
7233 			case SCF_ERROR_NOT_BOUND:
7234 			case SCF_ERROR_NOT_SET:
7235 			default:
7236 				bad_error("scf_scope_add_service", scf_error());
7237 			}
7238 		}
7239 
7240 		s->sc_import_state = IMPORT_PROP_BEGUN;
7241 
7242 		/* import service properties */
7243 		cbdata.sc_handle = lcbdata->sc_handle;
7244 		cbdata.sc_parent = imp_svc;
7245 		cbdata.sc_service = 1;
7246 		cbdata.sc_flags = lcbdata->sc_flags;
7247 		cbdata.sc_source_fmri = s->sc_fmri;
7248 		cbdata.sc_target_fmri = s->sc_fmri;
7249 
7250 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7251 		    &cbdata, UU_DEFAULT) != 0) {
7252 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7253 				bad_error("uu_list_walk", uu_error());
7254 
7255 			lcbdata->sc_err = cbdata.sc_err;
7256 			switch (cbdata.sc_err) {
7257 			case ECONNABORTED:
7258 				goto connaborted;
7259 
7260 			case ECANCELED:
7261 				warn(s_deleted, s->sc_fmri);
7262 				lcbdata->sc_err = EBUSY;
7263 				return (UU_WALK_ERROR);
7264 
7265 			case EEXIST:
7266 				warn(gettext("%s changed unexpectedly "
7267 				    "(property group added).\n"), s->sc_fmri);
7268 				lcbdata->sc_err = EBUSY;
7269 				return (UU_WALK_ERROR);
7270 
7271 			case EINVAL:
7272 				/* caught above */
7273 				bad_error("entity_pgroup_import",
7274 				    cbdata.sc_err);
7275 			}
7276 
7277 			r = UU_WALK_ERROR;
7278 			goto deltemp;
7279 		}
7280 
7281 		cbdata.sc_trans = NULL;
7282 		cbdata.sc_flags = 0;
7283 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7284 		    &cbdata, UU_DEFAULT) != 0) {
7285 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7286 				bad_error("uu_list_walk", uu_error());
7287 
7288 			lcbdata->sc_err = cbdata.sc_err;
7289 			if (cbdata.sc_err == ECONNABORTED)
7290 				goto connaborted;
7291 			r = UU_WALK_ERROR;
7292 			goto deltemp;
7293 		}
7294 
7295 		s->sc_import_state = IMPORT_PROP_DONE;
7296 
7297 		/*
7298 		 * This is a new service, so we can't take previous snapshots
7299 		 * or upgrade service properties.
7300 		 */
7301 		fresh = 1;
7302 		goto instances;
7303 	}
7304 
7305 	/* Clear sc_seen for the instances. */
7306 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7307 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7308 		bad_error("uu_list_walk", uu_error());
7309 
7310 	/*
7311 	 * Take previous snapshots for all instances.  Even for ones not
7312 	 * mentioned in the bundle, since we might change their service
7313 	 * properties.
7314 	 */
7315 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7316 		switch (scf_error()) {
7317 		case SCF_ERROR_CONNECTION_BROKEN:
7318 			goto connaborted;
7319 
7320 		case SCF_ERROR_DELETED:
7321 			warn(s_deleted, s->sc_fmri);
7322 			lcbdata->sc_err = EBUSY;
7323 			r = UU_WALK_ERROR;
7324 			goto deltemp;
7325 
7326 		case SCF_ERROR_HANDLE_MISMATCH:
7327 		case SCF_ERROR_NOT_BOUND:
7328 		case SCF_ERROR_NOT_SET:
7329 		default:
7330 			bad_error("scf_iter_service_instances", scf_error());
7331 		}
7332 	}
7333 
7334 	for (;;) {
7335 		r = scf_iter_next_instance(imp_iter, imp_inst);
7336 		if (r == 0)
7337 			break;
7338 		if (r != 1) {
7339 			switch (scf_error()) {
7340 			case SCF_ERROR_DELETED:
7341 				warn(s_deleted, s->sc_fmri);
7342 				lcbdata->sc_err = EBUSY;
7343 				r = UU_WALK_ERROR;
7344 				goto deltemp;
7345 
7346 			case SCF_ERROR_CONNECTION_BROKEN:
7347 				goto connaborted;
7348 
7349 			case SCF_ERROR_NOT_BOUND:
7350 			case SCF_ERROR_HANDLE_MISMATCH:
7351 			case SCF_ERROR_INVALID_ARGUMENT:
7352 			case SCF_ERROR_NOT_SET:
7353 			default:
7354 				bad_error("scf_iter_next_instance",
7355 				    scf_error());
7356 			}
7357 		}
7358 
7359 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7360 			switch (scf_error()) {
7361 			case SCF_ERROR_DELETED:
7362 				continue;
7363 
7364 			case SCF_ERROR_CONNECTION_BROKEN:
7365 				goto connaborted;
7366 
7367 			case SCF_ERROR_NOT_SET:
7368 			case SCF_ERROR_NOT_BOUND:
7369 			default:
7370 				bad_error("scf_instance_get_name", scf_error());
7371 			}
7372 		}
7373 
7374 		if (g_verbose)
7375 			warn(gettext(
7376 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7377 			    snap_previous, s->sc_name, imp_str);
7378 
7379 		r = take_snap(imp_inst, snap_previous, imp_snap);
7380 		switch (r) {
7381 		case 0:
7382 			break;
7383 
7384 		case ECANCELED:
7385 			continue;
7386 
7387 		case ECONNABORTED:
7388 			goto connaborted;
7389 
7390 		case EPERM:
7391 			warn(gettext("Could not take \"%s\" snapshot of "
7392 			    "svc:/%s:%s (permission denied).\n"),
7393 			    snap_previous, s->sc_name, imp_str);
7394 			lcbdata->sc_err = r;
7395 			return (UU_WALK_ERROR);
7396 
7397 		case ENOSPC:
7398 		case -1:
7399 			lcbdata->sc_err = r;
7400 			r = UU_WALK_ERROR;
7401 			goto deltemp;
7402 
7403 		default:
7404 			bad_error("take_snap", r);
7405 		}
7406 
7407 		linst.sc_name = imp_str;
7408 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7409 		    &linst, NULL, NULL);
7410 		if (inst != NULL) {
7411 			inst->sc_import_state = IMPORT_PREVIOUS;
7412 			inst->sc_seen = 1;
7413 		}
7414 	}
7415 
7416 	/*
7417 	 * Create the new instances and take previous snapshots of
7418 	 * them.  This is not necessary, but it maximizes data preservation.
7419 	 */
7420 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7421 	    inst != NULL;
7422 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7423 	    inst)) {
7424 		if (inst->sc_seen)
7425 			continue;
7426 
7427 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7428 		    imp_inst) != 0) {
7429 			switch (scf_error()) {
7430 			case SCF_ERROR_CONNECTION_BROKEN:
7431 				goto connaborted;
7432 
7433 			case SCF_ERROR_BACKEND_READONLY:
7434 			case SCF_ERROR_BACKEND_ACCESS:
7435 			case SCF_ERROR_NO_RESOURCES:
7436 				r = stash_scferror(lcbdata);
7437 				goto deltemp;
7438 
7439 			case SCF_ERROR_EXISTS:
7440 				warn(gettext("%s changed unexpectedly "
7441 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7442 				    inst->sc_name);
7443 				lcbdata->sc_err = EBUSY;
7444 				r = UU_WALK_ERROR;
7445 				goto deltemp;
7446 
7447 			case SCF_ERROR_INVALID_ARGUMENT:
7448 				warn(gettext("Service \"%s\" has instance with "
7449 				    "invalid name \"%s\".\n"), s->sc_name,
7450 				    inst->sc_name);
7451 				r = stash_scferror(lcbdata);
7452 				goto deltemp;
7453 
7454 			case SCF_ERROR_PERMISSION_DENIED:
7455 				warn(gettext("Could not create instance \"%s\" "
7456 				    "in %s (permission denied).\n"),
7457 				    inst->sc_name, s->sc_fmri);
7458 				r = stash_scferror(lcbdata);
7459 				goto deltemp;
7460 
7461 			case SCF_ERROR_HANDLE_MISMATCH:
7462 			case SCF_ERROR_NOT_BOUND:
7463 			case SCF_ERROR_NOT_SET:
7464 			default:
7465 				bad_error("scf_service_add_instance",
7466 				    scf_error());
7467 			}
7468 		}
7469 
7470 		if (g_verbose)
7471 			warn(gettext("Taking \"%s\" snapshot for "
7472 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7473 		r = take_snap(imp_inst, snap_previous, imp_snap);
7474 		switch (r) {
7475 		case 0:
7476 			break;
7477 
7478 		case ECANCELED:
7479 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7480 			lcbdata->sc_err = EBUSY;
7481 			r = UU_WALK_ERROR;
7482 			goto deltemp;
7483 
7484 		case ECONNABORTED:
7485 			goto connaborted;
7486 
7487 		case EPERM:
7488 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7489 			lcbdata->sc_err = r;
7490 			r = UU_WALK_ERROR;
7491 			goto deltemp;
7492 
7493 		case ENOSPC:
7494 		case -1:
7495 			r = UU_WALK_ERROR;
7496 			goto deltemp;
7497 
7498 		default:
7499 			bad_error("take_snap", r);
7500 		}
7501 	}
7502 
7503 	s->sc_import_state = IMPORT_PREVIOUS;
7504 
7505 	/*
7506 	 * Upgrade service properties, if we can find a last-import snapshot.
7507 	 * Any will do because we don't support different service properties
7508 	 * in different manifests, so all snaplevels of the service in all of
7509 	 * the last-import snapshots of the instances should be the same.
7510 	 */
7511 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7512 		switch (scf_error()) {
7513 		case SCF_ERROR_CONNECTION_BROKEN:
7514 			goto connaborted;
7515 
7516 		case SCF_ERROR_DELETED:
7517 			warn(s_deleted, s->sc_fmri);
7518 			lcbdata->sc_err = EBUSY;
7519 			r = UU_WALK_ERROR;
7520 			goto deltemp;
7521 
7522 		case SCF_ERROR_HANDLE_MISMATCH:
7523 		case SCF_ERROR_NOT_BOUND:
7524 		case SCF_ERROR_NOT_SET:
7525 		default:
7526 			bad_error("scf_iter_service_instances", scf_error());
7527 		}
7528 	}
7529 
7530 	for (;;) {
7531 		r = scf_iter_next_instance(imp_iter, imp_inst);
7532 		if (r == -1) {
7533 			switch (scf_error()) {
7534 			case SCF_ERROR_DELETED:
7535 				warn(s_deleted, s->sc_fmri);
7536 				lcbdata->sc_err = EBUSY;
7537 				r = UU_WALK_ERROR;
7538 				goto deltemp;
7539 
7540 			case SCF_ERROR_CONNECTION_BROKEN:
7541 				goto connaborted;
7542 
7543 			case SCF_ERROR_NOT_BOUND:
7544 			case SCF_ERROR_HANDLE_MISMATCH:
7545 			case SCF_ERROR_INVALID_ARGUMENT:
7546 			case SCF_ERROR_NOT_SET:
7547 			default:
7548 				bad_error("scf_iter_next_instance",
7549 				    scf_error());
7550 			}
7551 		}
7552 
7553 		if (r == 0) {
7554 			/*
7555 			 * Didn't find any last-import snapshots.  Override-
7556 			 * import the properties.  Unless one of the instances
7557 			 * has a general/enabled property, in which case we're
7558 			 * probably running a last-import-capable svccfg for
7559 			 * the first time, and we should only take the
7560 			 * last-import snapshot.
7561 			 */
7562 			if (have_ge) {
7563 				pgroup_t *mfpg;
7564 				scf_callback_t mfcbdata;
7565 
7566 				li_only = 1;
7567 				no_refresh = 1;
7568 				/*
7569 				 * Need to go ahead and import the manifestfiles
7570 				 * pg if it exists. If the last-import snapshot
7571 				 * upgrade code is ever removed this code can
7572 				 * be removed as well.
7573 				 */
7574 				mfpg = internal_pgroup_find(s,
7575 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7576 
7577 				if (mfpg) {
7578 					mfcbdata.sc_handle = g_hndl;
7579 					mfcbdata.sc_parent = imp_svc;
7580 					mfcbdata.sc_service = 1;
7581 					mfcbdata.sc_flags = SCI_FORCE;
7582 					mfcbdata.sc_source_fmri = s->sc_fmri;
7583 					mfcbdata.sc_target_fmri = s->sc_fmri;
7584 					if (entity_pgroup_import(mfpg,
7585 					    &mfcbdata) != UU_WALK_NEXT) {
7586 						warn(s_mfile_upd, s->sc_fmri);
7587 						r = UU_WALK_ERROR;
7588 						goto deltemp;
7589 					}
7590 				}
7591 				break;
7592 			}
7593 
7594 			s->sc_import_state = IMPORT_PROP_BEGUN;
7595 
7596 			cbdata.sc_handle = g_hndl;
7597 			cbdata.sc_parent = imp_svc;
7598 			cbdata.sc_service = 1;
7599 			cbdata.sc_flags = SCI_FORCE;
7600 			cbdata.sc_source_fmri = s->sc_fmri;
7601 			cbdata.sc_target_fmri = s->sc_fmri;
7602 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7603 			    &cbdata, UU_DEFAULT) != 0) {
7604 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7605 					bad_error("uu_list_walk", uu_error());
7606 				lcbdata->sc_err = cbdata.sc_err;
7607 				switch (cbdata.sc_err) {
7608 				case ECONNABORTED:
7609 					goto connaborted;
7610 
7611 				case ECANCELED:
7612 					warn(s_deleted, s->sc_fmri);
7613 					lcbdata->sc_err = EBUSY;
7614 					break;
7615 
7616 				case EINVAL:	/* caught above */
7617 				case EEXIST:
7618 					bad_error("entity_pgroup_import",
7619 					    cbdata.sc_err);
7620 				}
7621 
7622 				r = UU_WALK_ERROR;
7623 				goto deltemp;
7624 			}
7625 
7626 			cbdata.sc_trans = NULL;
7627 			cbdata.sc_flags = 0;
7628 			if (uu_list_walk(s->sc_dependents,
7629 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7630 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7631 					bad_error("uu_list_walk", uu_error());
7632 				lcbdata->sc_err = cbdata.sc_err;
7633 				if (cbdata.sc_err == ECONNABORTED)
7634 					goto connaborted;
7635 				r = UU_WALK_ERROR;
7636 				goto deltemp;
7637 			}
7638 			break;
7639 		}
7640 
7641 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7642 		    imp_snap) != 0) {
7643 			switch (scf_error()) {
7644 			case SCF_ERROR_DELETED:
7645 				continue;
7646 
7647 			case SCF_ERROR_NOT_FOUND:
7648 				break;
7649 
7650 			case SCF_ERROR_CONNECTION_BROKEN:
7651 				goto connaborted;
7652 
7653 			case SCF_ERROR_HANDLE_MISMATCH:
7654 			case SCF_ERROR_NOT_BOUND:
7655 			case SCF_ERROR_INVALID_ARGUMENT:
7656 			case SCF_ERROR_NOT_SET:
7657 			default:
7658 				bad_error("scf_instance_get_snapshot",
7659 				    scf_error());
7660 			}
7661 
7662 			if (have_ge)
7663 				continue;
7664 
7665 			/*
7666 			 * Check for a general/enabled property.  This is how
7667 			 * we tell whether to import if there turn out to be
7668 			 * no last-import snapshots.
7669 			 */
7670 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7671 			    imp_pg) == 0) {
7672 				if (scf_pg_get_property(imp_pg,
7673 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7674 					have_ge = 1;
7675 				} else {
7676 					switch (scf_error()) {
7677 					case SCF_ERROR_DELETED:
7678 					case SCF_ERROR_NOT_FOUND:
7679 						continue;
7680 
7681 					case SCF_ERROR_INVALID_ARGUMENT:
7682 					case SCF_ERROR_HANDLE_MISMATCH:
7683 					case SCF_ERROR_CONNECTION_BROKEN:
7684 					case SCF_ERROR_NOT_BOUND:
7685 					case SCF_ERROR_NOT_SET:
7686 					default:
7687 						bad_error("scf_pg_get_property",
7688 						    scf_error());
7689 					}
7690 				}
7691 			} else {
7692 				switch (scf_error()) {
7693 				case SCF_ERROR_DELETED:
7694 				case SCF_ERROR_NOT_FOUND:
7695 					continue;
7696 
7697 				case SCF_ERROR_CONNECTION_BROKEN:
7698 					goto connaborted;
7699 
7700 				case SCF_ERROR_NOT_BOUND:
7701 				case SCF_ERROR_NOT_SET:
7702 				case SCF_ERROR_INVALID_ARGUMENT:
7703 				case SCF_ERROR_HANDLE_MISMATCH:
7704 				default:
7705 					bad_error("scf_instance_get_pg",
7706 					    scf_error());
7707 				}
7708 			}
7709 			continue;
7710 		}
7711 
7712 		/* find service snaplevel */
7713 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7714 		switch (r) {
7715 		case 0:
7716 			break;
7717 
7718 		case ECONNABORTED:
7719 			goto connaborted;
7720 
7721 		case ECANCELED:
7722 			continue;
7723 
7724 		case ENOENT:
7725 			if (scf_instance_get_name(imp_inst, imp_str,
7726 			    imp_str_sz) < 0)
7727 				(void) strcpy(imp_str, "?");
7728 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7729 			lcbdata->sc_err = EBADF;
7730 			r = UU_WALK_ERROR;
7731 			goto deltemp;
7732 
7733 		default:
7734 			bad_error("get_snaplevel", r);
7735 		}
7736 
7737 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7738 		    imp_rsnap) != 0) {
7739 			switch (scf_error()) {
7740 			case SCF_ERROR_DELETED:
7741 				continue;
7742 
7743 			case SCF_ERROR_NOT_FOUND:
7744 				break;
7745 
7746 			case SCF_ERROR_CONNECTION_BROKEN:
7747 				goto connaborted;
7748 
7749 			case SCF_ERROR_INVALID_ARGUMENT:
7750 			case SCF_ERROR_HANDLE_MISMATCH:
7751 			case SCF_ERROR_NOT_BOUND:
7752 			case SCF_ERROR_NOT_SET:
7753 			default:
7754 				bad_error("scf_instance_get_snapshot",
7755 				    scf_error());
7756 			}
7757 			running = NULL;
7758 		} else {
7759 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7760 			switch (r) {
7761 			case 0:
7762 				running = imp_rsnpl;
7763 				break;
7764 
7765 			case ECONNABORTED:
7766 				goto connaborted;
7767 
7768 			case ECANCELED:
7769 				continue;
7770 
7771 			case ENOENT:
7772 				if (scf_instance_get_name(imp_inst, imp_str,
7773 				    imp_str_sz) < 0)
7774 					(void) strcpy(imp_str, "?");
7775 				warn(badsnap, snap_running, s->sc_name,
7776 				    imp_str);
7777 				lcbdata->sc_err = EBADF;
7778 				r = UU_WALK_ERROR;
7779 				goto deltemp;
7780 
7781 			default:
7782 				bad_error("get_snaplevel", r);
7783 			}
7784 		}
7785 
7786 		if (g_verbose) {
7787 			if (scf_instance_get_name(imp_inst, imp_str,
7788 			    imp_str_sz) < 0)
7789 				(void) strcpy(imp_str, "?");
7790 			warn(gettext("Upgrading properties of %s according to "
7791 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7792 		}
7793 
7794 		/* upgrade service properties */
7795 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7796 		if (r == 0)
7797 			break;
7798 
7799 		switch (r) {
7800 		case ECONNABORTED:
7801 			goto connaborted;
7802 
7803 		case ECANCELED:
7804 			warn(s_deleted, s->sc_fmri);
7805 			lcbdata->sc_err = EBUSY;
7806 			break;
7807 
7808 		case ENODEV:
7809 			if (scf_instance_get_name(imp_inst, imp_str,
7810 			    imp_str_sz) < 0)
7811 				(void) strcpy(imp_str, "?");
7812 			warn(i_deleted, s->sc_fmri, imp_str);
7813 			lcbdata->sc_err = EBUSY;
7814 			break;
7815 
7816 		default:
7817 			lcbdata->sc_err = r;
7818 		}
7819 
7820 		r = UU_WALK_ERROR;
7821 		goto deltemp;
7822 	}
7823 
7824 	s->sc_import_state = IMPORT_PROP_DONE;
7825 
7826 instances:
7827 	/* import instances */
7828 	cbdata.sc_handle = lcbdata->sc_handle;
7829 	cbdata.sc_parent = imp_svc;
7830 	cbdata.sc_service = 1;
7831 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7832 	cbdata.sc_general = NULL;
7833 
7834 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7835 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7836 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7837 			bad_error("uu_list_walk", uu_error());
7838 
7839 		lcbdata->sc_err = cbdata.sc_err;
7840 		if (cbdata.sc_err == ECONNABORTED)
7841 			goto connaborted;
7842 		r = UU_WALK_ERROR;
7843 		goto deltemp;
7844 	}
7845 
7846 	s->sc_import_state = IMPORT_COMPLETE;
7847 	r = UU_WALK_NEXT;
7848 
7849 deltemp:
7850 	/* delete temporary service */
7851 	if (scf_service_delete(imp_tsvc) != 0) {
7852 		switch (scf_error()) {
7853 		case SCF_ERROR_DELETED:
7854 			break;
7855 
7856 		case SCF_ERROR_CONNECTION_BROKEN:
7857 			goto connaborted;
7858 
7859 		case SCF_ERROR_EXISTS:
7860 			warn(gettext(
7861 			    "Could not delete svc:/%s (instances exist).\n"),
7862 			    imp_tsname);
7863 			break;
7864 
7865 		case SCF_ERROR_NOT_SET:
7866 		case SCF_ERROR_NOT_BOUND:
7867 		default:
7868 			bad_error("scf_service_delete", scf_error());
7869 		}
7870 	}
7871 
7872 	return (r);
7873 
7874 connaborted:
7875 	warn(gettext("Could not delete svc:/%s "
7876 	    "(repository connection broken).\n"), imp_tsname);
7877 	lcbdata->sc_err = ECONNABORTED;
7878 	return (UU_WALK_ERROR);
7879 }
7880 
7881 static const char *
7882 import_progress(int st)
7883 {
7884 	switch (st) {
7885 	case 0:
7886 		return (gettext("not reached."));
7887 
7888 	case IMPORT_PREVIOUS:
7889 		return (gettext("previous snapshot taken."));
7890 
7891 	case IMPORT_PROP_BEGUN:
7892 		return (gettext("some properties imported."));
7893 
7894 	case IMPORT_PROP_DONE:
7895 		return (gettext("properties imported."));
7896 
7897 	case IMPORT_COMPLETE:
7898 		return (gettext("imported."));
7899 
7900 	case IMPORT_REFRESHED:
7901 		return (gettext("refresh requested."));
7902 
7903 	default:
7904 #ifndef NDEBUG
7905 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7906 		    __FILE__, __LINE__, st);
7907 #endif
7908 		abort();
7909 		/* NOTREACHED */
7910 	}
7911 }
7912 
7913 /*
7914  * Returns
7915  *   0 - success
7916  *     - fmri wasn't found (error printed)
7917  *     - entity was deleted (error printed)
7918  *     - backend denied access (error printed)
7919  *   ENOMEM - out of memory (error printed)
7920  *   ECONNABORTED - repository connection broken (error printed)
7921  *   EPERM - permission denied (error printed)
7922  *   -1 - unknown libscf error (error printed)
7923  */
7924 static int
7925 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7926 {
7927 	scf_error_t serr;
7928 	void *ent;
7929 	int issvc;
7930 	int r;
7931 
7932 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7933 	const char *dpt_deleted = gettext("Could not refresh %s "
7934 	    "(dependent \"%s\" of %s) (deleted).\n");
7935 
7936 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7937 	switch (serr) {
7938 	case SCF_ERROR_NONE:
7939 		break;
7940 
7941 	case SCF_ERROR_NO_MEMORY:
7942 		if (name == NULL)
7943 			warn(gettext("Could not refresh %s (out of memory).\n"),
7944 			    fmri);
7945 		else
7946 			warn(gettext("Could not refresh %s "
7947 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7948 			    fmri, name, d_fmri);
7949 		return (ENOMEM);
7950 
7951 	case SCF_ERROR_NOT_FOUND:
7952 		if (name == NULL)
7953 			warn(deleted, fmri);
7954 		else
7955 			warn(dpt_deleted, fmri, name, d_fmri);
7956 		return (0);
7957 
7958 	case SCF_ERROR_INVALID_ARGUMENT:
7959 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7960 	default:
7961 		bad_error("fmri_to_entity", serr);
7962 	}
7963 
7964 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7965 	switch (r) {
7966 	case 0:
7967 		break;
7968 
7969 	case ECONNABORTED:
7970 		if (name != NULL)
7971 			warn(gettext("Could not refresh %s "
7972 			    "(dependent \"%s\" of %s) "
7973 			    "(repository connection broken).\n"), fmri, name,
7974 			    d_fmri);
7975 		return (r);
7976 
7977 	case ECANCELED:
7978 		if (name == NULL)
7979 			warn(deleted, fmri);
7980 		else
7981 			warn(dpt_deleted, fmri, name, d_fmri);
7982 		return (0);
7983 
7984 	case EACCES:
7985 		if (!g_verbose)
7986 			return (0);
7987 		if (name == NULL)
7988 			warn(gettext("Could not refresh %s "
7989 			    "(backend access denied).\n"), fmri);
7990 		else
7991 			warn(gettext("Could not refresh %s "
7992 			    "(dependent \"%s\" of %s) "
7993 			    "(backend access denied).\n"), fmri, name, d_fmri);
7994 		return (0);
7995 
7996 	case EPERM:
7997 		if (name == NULL)
7998 			warn(gettext("Could not refresh %s "
7999 			    "(permission denied).\n"), fmri);
8000 		else
8001 			warn(gettext("Could not refresh %s "
8002 			    "(dependent \"%s\" of %s) "
8003 			    "(permission denied).\n"), fmri, name, d_fmri);
8004 		return (r);
8005 
8006 	case ENOSPC:
8007 		if (name == NULL)
8008 			warn(gettext("Could not refresh %s "
8009 			    "(repository server out of resources).\n"),
8010 			    fmri);
8011 		else
8012 			warn(gettext("Could not refresh %s "
8013 			    "(dependent \"%s\" of %s) "
8014 			    "(repository server out of resources).\n"),
8015 			    fmri, name, d_fmri);
8016 		return (r);
8017 
8018 	case -1:
8019 		scfwarn();
8020 		return (r);
8021 
8022 	default:
8023 		bad_error("refresh_entity", r);
8024 	}
8025 
8026 	if (issvc)
8027 		scf_service_destroy(ent);
8028 	else
8029 		scf_instance_destroy(ent);
8030 
8031 	return (0);
8032 }
8033 
8034 static int
8035 alloc_imp_globals()
8036 {
8037 	int r;
8038 
8039 	const char * const emsg_nomem = gettext("Out of memory.\n");
8040 	const char * const emsg_nores =
8041 	    gettext("svc.configd is out of resources.\n");
8042 
8043 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8044 	    max_scf_name_len : max_scf_fmri_len) + 1;
8045 
8046 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8047 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
8048 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8049 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8050 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8051 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8052 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8053 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8054 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8055 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8056 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8057 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8058 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8059 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
8060 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8061 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8062 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8063 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8064 	    (imp_str = malloc(imp_str_sz)) == NULL ||
8065 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8066 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8067 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8068 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8069 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8070 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8071 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8072 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8073 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8074 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
8075 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8076 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
8077 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8078 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8079 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8080 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8081 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8082 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8083 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
8084 			warn(emsg_nores);
8085 		else
8086 			warn(emsg_nomem);
8087 
8088 		return (-1);
8089 	}
8090 
8091 	r = load_init();
8092 	switch (r) {
8093 	case 0:
8094 		break;
8095 
8096 	case ENOMEM:
8097 		warn(emsg_nomem);
8098 		return (-1);
8099 
8100 	default:
8101 		bad_error("load_init", r);
8102 	}
8103 
8104 	return (0);
8105 }
8106 
8107 static void
8108 free_imp_globals()
8109 {
8110 	pgroup_t *old_dpt;
8111 	void *cookie;
8112 
8113 	load_fini();
8114 
8115 	free(ud_ctarg);
8116 	free(ud_oldtarg);
8117 	free(ud_name);
8118 	ud_ctarg = ud_oldtarg = ud_name = NULL;
8119 
8120 	scf_transaction_destroy(ud_tx);
8121 	ud_tx = NULL;
8122 	scf_iter_destroy(ud_iter);
8123 	scf_iter_destroy(ud_iter2);
8124 	ud_iter = ud_iter2 = NULL;
8125 	scf_value_destroy(ud_val);
8126 	ud_val = NULL;
8127 	scf_property_destroy(ud_prop);
8128 	scf_property_destroy(ud_dpt_prop);
8129 	ud_prop = ud_dpt_prop = NULL;
8130 	scf_pg_destroy(ud_pg);
8131 	scf_pg_destroy(ud_cur_depts_pg);
8132 	scf_pg_destroy(ud_run_dpts_pg);
8133 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8134 	scf_snaplevel_destroy(ud_snpl);
8135 	ud_snpl = NULL;
8136 	scf_instance_destroy(ud_inst);
8137 	ud_inst = NULL;
8138 
8139 	free(imp_str);
8140 	free(imp_tsname);
8141 	free(imp_fe1);
8142 	free(imp_fe2);
8143 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8144 
8145 	cookie = NULL;
8146 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8147 	    NULL) {
8148 		free((char *)old_dpt->sc_pgroup_name);
8149 		free((char *)old_dpt->sc_pgroup_fmri);
8150 		internal_pgroup_free(old_dpt);
8151 	}
8152 	uu_list_destroy(imp_deleted_dpts);
8153 
8154 	scf_transaction_destroy(imp_tx);
8155 	imp_tx = NULL;
8156 	scf_iter_destroy(imp_iter);
8157 	scf_iter_destroy(imp_rpg_iter);
8158 	scf_iter_destroy(imp_up_iter);
8159 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8160 	scf_property_destroy(imp_prop);
8161 	imp_prop = NULL;
8162 	scf_pg_destroy(imp_pg);
8163 	scf_pg_destroy(imp_pg2);
8164 	imp_pg = imp_pg2 = NULL;
8165 	scf_snaplevel_destroy(imp_snpl);
8166 	scf_snaplevel_destroy(imp_rsnpl);
8167 	imp_snpl = imp_rsnpl = NULL;
8168 	scf_snapshot_destroy(imp_snap);
8169 	scf_snapshot_destroy(imp_lisnap);
8170 	scf_snapshot_destroy(imp_tlisnap);
8171 	scf_snapshot_destroy(imp_rsnap);
8172 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8173 	scf_instance_destroy(imp_inst);
8174 	scf_instance_destroy(imp_tinst);
8175 	imp_inst = imp_tinst = NULL;
8176 	scf_service_destroy(imp_svc);
8177 	scf_service_destroy(imp_tsvc);
8178 	imp_svc = imp_tsvc = NULL;
8179 	scf_scope_destroy(imp_scope);
8180 	imp_scope = NULL;
8181 
8182 	load_fini();
8183 }
8184 
8185 int
8186 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8187 {
8188 	scf_callback_t cbdata;
8189 	int result = 0;
8190 	entity_t *svc, *inst;
8191 	uu_list_t *insts;
8192 	int r;
8193 	pgroup_t *old_dpt;
8194 	int annotation_set = 0;
8195 
8196 	const char * const emsg_nomem = gettext("Out of memory.\n");
8197 	const char * const emsg_nores =
8198 	    gettext("svc.configd is out of resources.\n");
8199 
8200 	lscf_prep_hndl();
8201 
8202 	if (alloc_imp_globals())
8203 		goto out;
8204 
8205 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8206 		switch (scf_error()) {
8207 		case SCF_ERROR_CONNECTION_BROKEN:
8208 			warn(gettext("Repository connection broken.\n"));
8209 			repository_teardown();
8210 			result = -1;
8211 			goto out;
8212 
8213 		case SCF_ERROR_NOT_FOUND:
8214 		case SCF_ERROR_INVALID_ARGUMENT:
8215 		case SCF_ERROR_NOT_BOUND:
8216 		case SCF_ERROR_HANDLE_MISMATCH:
8217 		default:
8218 			bad_error("scf_handle_get_scope", scf_error());
8219 		}
8220 	}
8221 
8222 	/* Set up the auditing annotation. */
8223 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8224 		annotation_set = 1;
8225 	} else {
8226 		switch (scf_error()) {
8227 		case SCF_ERROR_CONNECTION_BROKEN:
8228 			warn(gettext("Repository connection broken.\n"));
8229 			repository_teardown();
8230 			result = -1;
8231 			goto out;
8232 
8233 		case SCF_ERROR_INVALID_ARGUMENT:
8234 		case SCF_ERROR_NOT_BOUND:
8235 		case SCF_ERROR_NO_RESOURCES:
8236 		case SCF_ERROR_INTERNAL:
8237 			bad_error("_scf_set_annotation", scf_error());
8238 			/* NOTREACHED */
8239 
8240 		default:
8241 			/*
8242 			 * Do not terminate import because of inability to
8243 			 * generate annotation audit event.
8244 			 */
8245 			warn(gettext("_scf_set_annotation() unexpectedly "
8246 			    "failed with return code of %d\n"), scf_error());
8247 			break;
8248 		}
8249 	}
8250 
8251 	/*
8252 	 * Clear the sc_import_state's of all services & instances so we can
8253 	 * report how far we got if we fail.
8254 	 */
8255 	for (svc = uu_list_first(bndl->sc_bundle_services);
8256 	    svc != NULL;
8257 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8258 		svc->sc_import_state = 0;
8259 
8260 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8261 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8262 		    UU_DEFAULT) != 0)
8263 			bad_error("uu_list_walk", uu_error());
8264 	}
8265 
8266 	cbdata.sc_handle = g_hndl;
8267 	cbdata.sc_parent = imp_scope;
8268 	cbdata.sc_flags = flags;
8269 	cbdata.sc_general = NULL;
8270 
8271 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8272 	    &cbdata, UU_DEFAULT) == 0) {
8273 		char *eptr;
8274 		/* Success.  Refresh everything. */
8275 
8276 		if (flags & SCI_NOREFRESH || no_refresh) {
8277 			no_refresh = 0;
8278 			result = 0;
8279 			goto out;
8280 		}
8281 
8282 		for (svc = uu_list_first(bndl->sc_bundle_services);
8283 		    svc != NULL;
8284 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8285 			pgroup_t *dpt;
8286 
8287 			insts = svc->sc_u.sc_service.sc_service_instances;
8288 
8289 			for (inst = uu_list_first(insts);
8290 			    inst != NULL;
8291 			    inst = uu_list_next(insts, inst)) {
8292 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8293 				switch (r) {
8294 				case 0:
8295 					break;
8296 
8297 				case ENOMEM:
8298 				case ECONNABORTED:
8299 				case EPERM:
8300 				case -1:
8301 					goto progress;
8302 
8303 				default:
8304 					bad_error("imp_refresh_fmri", r);
8305 				}
8306 
8307 				inst->sc_import_state = IMPORT_REFRESHED;
8308 
8309 				for (dpt = uu_list_first(inst->sc_dependents);
8310 				    dpt != NULL;
8311 				    dpt = uu_list_next(inst->sc_dependents,
8312 				    dpt))
8313 					if (imp_refresh_fmri(
8314 					    dpt->sc_pgroup_fmri,
8315 					    dpt->sc_pgroup_name,
8316 					    inst->sc_fmri) != 0)
8317 						goto progress;
8318 			}
8319 
8320 			for (dpt = uu_list_first(svc->sc_dependents);
8321 			    dpt != NULL;
8322 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8323 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8324 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8325 					goto progress;
8326 		}
8327 
8328 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8329 		    old_dpt != NULL;
8330 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8331 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8332 			    old_dpt->sc_pgroup_name,
8333 			    old_dpt->sc_parent->sc_fmri) != 0)
8334 				goto progress;
8335 
8336 		result = 0;
8337 
8338 		/*
8339 		 * This snippet of code assumes that we are running svccfg as we
8340 		 * normally do -- witih svc.startd running. Of course, that is
8341 		 * not actually the case all the time because we also use a
8342 		 * varient of svc.configd and svccfg which are only meant to
8343 		 * run during the build process. During this time we have no
8344 		 * svc.startd, so this check would hang the build process.
8345 		 *
8346 		 * However, we've also given other consolidations, a bit of a
8347 		 * means to tie themselves into a knot. They're not properly
8348 		 * using the native build equivalents, but they've been getting
8349 		 * away with it anyways. Therefore, if we've found that
8350 		 * SVCCFG_REPOSITORY is set indicating that a separate configd
8351 		 * should be spun up, then we have to assume it's not using a
8352 		 * startd and we should not do this check.
8353 		 */
8354 #ifndef NATIVE_BUILD
8355 		/*
8356 		 * Verify that the restarter group is preset
8357 		 */
8358 		eptr = getenv("SVCCFG_REPOSITORY");
8359 		for (svc = uu_list_first(bndl->sc_bundle_services);
8360 		    svc != NULL && eptr == NULL;
8361 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8362 
8363 			insts = svc->sc_u.sc_service.sc_service_instances;
8364 
8365 			for (inst = uu_list_first(insts);
8366 			    inst != NULL;
8367 			    inst = uu_list_next(insts, inst)) {
8368 				if (lscf_instance_verify(imp_scope, svc,
8369 				    inst) != 0)
8370 					goto progress;
8371 			}
8372 		}
8373 #endif
8374 		goto out;
8375 
8376 	}
8377 
8378 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8379 		bad_error("uu_list_walk", uu_error());
8380 
8381 printerr:
8382 	/* If the error hasn't been printed yet, do so here. */
8383 	switch (cbdata.sc_err) {
8384 	case ECONNABORTED:
8385 		warn(gettext("Repository connection broken.\n"));
8386 		break;
8387 
8388 	case ENOMEM:
8389 		warn(emsg_nomem);
8390 		break;
8391 
8392 	case ENOSPC:
8393 		warn(emsg_nores);
8394 		break;
8395 
8396 	case EROFS:
8397 		warn(gettext("Repository is read-only.\n"));
8398 		break;
8399 
8400 	case EACCES:
8401 		warn(gettext("Repository backend denied access.\n"));
8402 		break;
8403 
8404 	case EPERM:
8405 	case EINVAL:
8406 	case EEXIST:
8407 	case EBUSY:
8408 	case EBADF:
8409 	case -1:
8410 		break;
8411 
8412 	default:
8413 		bad_error("lscf_service_import", cbdata.sc_err);
8414 	}
8415 
8416 progress:
8417 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8418 
8419 	for (svc = uu_list_first(bndl->sc_bundle_services);
8420 	    svc != NULL;
8421 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8422 		insts = svc->sc_u.sc_service.sc_service_instances;
8423 
8424 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8425 		    import_progress(svc->sc_import_state));
8426 
8427 		for (inst = uu_list_first(insts);
8428 		    inst != NULL;
8429 		    inst = uu_list_next(insts, inst))
8430 			warn(gettext("    Instance \"%s\": %s\n"),
8431 			    inst->sc_name,
8432 			    import_progress(inst->sc_import_state));
8433 	}
8434 
8435 	if (cbdata.sc_err == ECONNABORTED)
8436 		repository_teardown();
8437 
8438 
8439 	result = -1;
8440 
8441 out:
8442 	if (annotation_set != 0) {
8443 		/* Turn off annotation.  It is no longer needed. */
8444 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8445 	}
8446 
8447 	free_imp_globals();
8448 
8449 	return (result);
8450 }
8451 
8452 /*
8453  * _lscf_import_err() summarize the error handling returned by
8454  * lscf_import_{instance | service}_pgs
8455  * Return values are:
8456  * IMPORT_NEXT
8457  * IMPORT_OUT
8458  * IMPORT_BAD
8459  */
8460 
8461 #define	IMPORT_BAD	-1
8462 #define	IMPORT_NEXT	0
8463 #define	IMPORT_OUT	1
8464 
8465 static int
8466 _lscf_import_err(int err, const char *fmri)
8467 {
8468 	switch (err) {
8469 	case 0:
8470 		if (g_verbose)
8471 			warn(gettext("%s updated.\n"), fmri);
8472 		return (IMPORT_NEXT);
8473 
8474 	case ECONNABORTED:
8475 		warn(gettext("Could not update %s "
8476 		    "(repository connection broken).\n"), fmri);
8477 		return (IMPORT_OUT);
8478 
8479 	case ENOMEM:
8480 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8481 		return (IMPORT_OUT);
8482 
8483 	case ENOSPC:
8484 		warn(gettext("Could not update %s "
8485 		    "(repository server out of resources).\n"), fmri);
8486 		return (IMPORT_OUT);
8487 
8488 	case ECANCELED:
8489 		warn(gettext(
8490 		    "Could not update %s (deleted).\n"), fmri);
8491 		return (IMPORT_NEXT);
8492 
8493 	case EPERM:
8494 	case EINVAL:
8495 	case EBUSY:
8496 		return (IMPORT_NEXT);
8497 
8498 	case EROFS:
8499 		warn(gettext("Could not update %s (repository read-only).\n"),
8500 		    fmri);
8501 		return (IMPORT_OUT);
8502 
8503 	case EACCES:
8504 		warn(gettext("Could not update %s "
8505 		    "(backend access denied).\n"), fmri);
8506 		return (IMPORT_NEXT);
8507 
8508 	case EEXIST:
8509 	default:
8510 		return (IMPORT_BAD);
8511 	}
8512 
8513 	/*NOTREACHED*/
8514 }
8515 
8516 /*
8517  * The global imp_svc and imp_inst should be set by the caller in the
8518  * check to make sure the service and instance exist that the apply is
8519  * working on.
8520  */
8521 static int
8522 lscf_dependent_apply(void *dpg, void *e)
8523 {
8524 	scf_callback_t cb;
8525 	pgroup_t *dpt_pgroup = dpg;
8526 	pgroup_t *deldpt;
8527 	entity_t *ent = e;
8528 	int tissvc;
8529 	void *sc_ent, *tent;
8530 	scf_error_t serr;
8531 	int r;
8532 
8533 	const char * const dependents = "dependents";
8534 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8535 
8536 	if (issvc)
8537 		sc_ent = imp_svc;
8538 	else
8539 		sc_ent = imp_inst;
8540 
8541 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8542 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8543 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8544 	    imp_prop) != 0) {
8545 		switch (scf_error()) {
8546 		case SCF_ERROR_NOT_FOUND:
8547 		case SCF_ERROR_DELETED:
8548 			break;
8549 
8550 		case SCF_ERROR_CONNECTION_BROKEN:
8551 		case SCF_ERROR_NOT_SET:
8552 		case SCF_ERROR_INVALID_ARGUMENT:
8553 		case SCF_ERROR_HANDLE_MISMATCH:
8554 		case SCF_ERROR_NOT_BOUND:
8555 		default:
8556 			bad_error("entity_get_pg", scf_error());
8557 		}
8558 	} else {
8559 		/*
8560 		 * Found the dependents/<wip dep> so check to
8561 		 * see if the service is different.  If so
8562 		 * store the service for later refresh, and
8563 		 * delete the wip dependency from the service
8564 		 */
8565 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8566 			switch (scf_error()) {
8567 				case SCF_ERROR_DELETED:
8568 					break;
8569 
8570 				case SCF_ERROR_CONNECTION_BROKEN:
8571 				case SCF_ERROR_NOT_SET:
8572 				case SCF_ERROR_INVALID_ARGUMENT:
8573 				case SCF_ERROR_HANDLE_MISMATCH:
8574 				case SCF_ERROR_NOT_BOUND:
8575 				default:
8576 					bad_error("scf_property_get_value",
8577 					    scf_error());
8578 			}
8579 		}
8580 
8581 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8582 		    max_scf_value_len + 1) < 0)
8583 			bad_error("scf_value_get_as_string", scf_error());
8584 
8585 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8586 		switch (r) {
8587 		case 1:
8588 			break;
8589 		case 0:
8590 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8591 			    &tissvc)) != SCF_ERROR_NONE) {
8592 				if (serr == SCF_ERROR_NOT_FOUND) {
8593 					break;
8594 				} else {
8595 					bad_error("fmri_to_entity", serr);
8596 				}
8597 			}
8598 
8599 			if (entity_get_pg(tent, tissvc,
8600 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8601 				serr = scf_error();
8602 				if (serr == SCF_ERROR_NOT_FOUND ||
8603 				    serr == SCF_ERROR_DELETED) {
8604 					break;
8605 				} else {
8606 					bad_error("entity_get_pg", scf_error());
8607 				}
8608 			}
8609 
8610 			if (scf_pg_delete(imp_pg) != 0) {
8611 				serr = scf_error();
8612 				if (serr == SCF_ERROR_NOT_FOUND ||
8613 				    serr == SCF_ERROR_DELETED) {
8614 					break;
8615 				} else {
8616 					bad_error("scf_pg_delete", scf_error());
8617 				}
8618 			}
8619 
8620 			deldpt = internal_pgroup_new();
8621 			if (deldpt == NULL)
8622 				return (ENOMEM);
8623 			deldpt->sc_pgroup_name =
8624 			    strdup(dpt_pgroup->sc_pgroup_name);
8625 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8626 			if (deldpt->sc_pgroup_name == NULL ||
8627 			    deldpt->sc_pgroup_fmri == NULL)
8628 				return (ENOMEM);
8629 			deldpt->sc_parent = (entity_t *)ent;
8630 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8631 			    deldpt) != 0)
8632 				uu_die(gettext("libuutil error: %s\n"),
8633 				    uu_strerror(uu_error()));
8634 
8635 			break;
8636 		default:
8637 			bad_error("fmri_equal", r);
8638 		}
8639 	}
8640 
8641 	cb.sc_handle = g_hndl;
8642 	cb.sc_parent = ent;
8643 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8644 	cb.sc_source_fmri = ent->sc_fmri;
8645 	cb.sc_target_fmri = ent->sc_fmri;
8646 	cb.sc_trans = NULL;
8647 	cb.sc_flags = SCI_FORCE;
8648 
8649 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8650 		return (UU_WALK_ERROR);
8651 
8652 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8653 	switch (r) {
8654 	case 0:
8655 		break;
8656 
8657 	case ENOMEM:
8658 	case ECONNABORTED:
8659 	case EPERM:
8660 	case -1:
8661 		warn(gettext("Unable to refresh \"%s\"\n"),
8662 		    dpt_pgroup->sc_pgroup_fmri);
8663 		return (UU_WALK_ERROR);
8664 
8665 	default:
8666 		bad_error("imp_refresh_fmri", r);
8667 	}
8668 
8669 	return (UU_WALK_NEXT);
8670 }
8671 
8672 /*
8673  * Returns
8674  *   0 - success
8675  *   -1 - lscf_import_instance_pgs() failed.
8676  */
8677 int
8678 lscf_bundle_apply(bundle_t *bndl, const char *file)
8679 {
8680 	pgroup_t *old_dpt;
8681 	entity_t *svc, *inst;
8682 	int annotation_set = 0;
8683 	int ret = 0;
8684 	int r = 0;
8685 
8686 	lscf_prep_hndl();
8687 
8688 	if ((ret = alloc_imp_globals()))
8689 		goto out;
8690 
8691 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8692 		scfdie();
8693 
8694 	/*
8695 	 * Set the strings to be used for the security audit annotation
8696 	 * event.
8697 	 */
8698 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8699 		annotation_set = 1;
8700 	} else {
8701 		switch (scf_error()) {
8702 		case SCF_ERROR_CONNECTION_BROKEN:
8703 			warn(gettext("Repository connection broken.\n"));
8704 			goto out;
8705 
8706 		case SCF_ERROR_INVALID_ARGUMENT:
8707 		case SCF_ERROR_NOT_BOUND:
8708 		case SCF_ERROR_NO_RESOURCES:
8709 		case SCF_ERROR_INTERNAL:
8710 			bad_error("_scf_set_annotation", scf_error());
8711 			/* NOTREACHED */
8712 
8713 		default:
8714 			/*
8715 			 * Do not abort apply operation because of
8716 			 * inability to create annotation audit event.
8717 			 */
8718 			warn(gettext("_scf_set_annotation() unexpectedly "
8719 			    "failed with return code of %d\n"), scf_error());
8720 			break;
8721 		}
8722 	}
8723 
8724 	for (svc = uu_list_first(bndl->sc_bundle_services);
8725 	    svc != NULL;
8726 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8727 		int refresh = 0;
8728 
8729 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8730 		    imp_svc) != 0) {
8731 			switch (scf_error()) {
8732 			case SCF_ERROR_NOT_FOUND:
8733 				if (g_verbose)
8734 					warn(gettext("Ignoring nonexistent "
8735 					    "service %s.\n"), svc->sc_name);
8736 				continue;
8737 
8738 			default:
8739 				scfdie();
8740 			}
8741 		}
8742 
8743 		/*
8744 		 * If there were missing types in the profile, then need to
8745 		 * attempt to find the types.
8746 		 */
8747 		if (svc->sc_miss_type) {
8748 			if (uu_list_numnodes(svc->sc_pgroups) &&
8749 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8750 			    svc, UU_DEFAULT) != 0) {
8751 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8752 					bad_error("uu_list_walk", uu_error());
8753 
8754 				ret = -1;
8755 				continue;
8756 			}
8757 
8758 			for (inst = uu_list_first(
8759 			    svc->sc_u.sc_service.sc_service_instances);
8760 			    inst != NULL;
8761 			    inst = uu_list_next(
8762 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8763 				/*
8764 				 * If the instance doesn't exist just
8765 				 * skip to the next instance and let the
8766 				 * import note the missing instance.
8767 				 */
8768 				if (scf_service_get_instance(imp_svc,
8769 				    inst->sc_name, imp_inst) != 0)
8770 					continue;
8771 
8772 				if (uu_list_walk(inst->sc_pgroups,
8773 				    find_current_pg_type, inst,
8774 				    UU_DEFAULT) != 0) {
8775 					if (uu_error() !=
8776 					    UU_ERROR_CALLBACK_FAILED)
8777 						bad_error("uu_list_walk",
8778 						    uu_error());
8779 
8780 					ret = -1;
8781 					inst->sc_miss_type = B_TRUE;
8782 				}
8783 			}
8784 		}
8785 
8786 		/*
8787 		 * if we have pgs in the profile, we need to refresh ALL
8788 		 * instances of the service
8789 		 */
8790 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8791 			refresh = 1;
8792 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8793 			    SCI_FORCE | SCI_KEEP);
8794 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8795 			case IMPORT_NEXT:
8796 				break;
8797 
8798 			case IMPORT_OUT:
8799 				goto out;
8800 
8801 			case IMPORT_BAD:
8802 			default:
8803 				bad_error("lscf_import_service_pgs", r);
8804 			}
8805 		}
8806 
8807 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8808 			uu_list_walk(svc->sc_dependents,
8809 			    lscf_dependent_apply, svc, UU_DEFAULT);
8810 		}
8811 
8812 		for (inst = uu_list_first(
8813 		    svc->sc_u.sc_service.sc_service_instances);
8814 		    inst != NULL;
8815 		    inst = uu_list_next(
8816 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8817 			/*
8818 			 * This instance still has missing types
8819 			 * so skip it.
8820 			 */
8821 			if (inst->sc_miss_type) {
8822 				if (g_verbose)
8823 					warn(gettext("Ignoring instance "
8824 					    "%s:%s with missing types\n"),
8825 					    inst->sc_parent->sc_name,
8826 					    inst->sc_name);
8827 
8828 				continue;
8829 			}
8830 
8831 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8832 			    imp_inst) != 0) {
8833 				switch (scf_error()) {
8834 				case SCF_ERROR_NOT_FOUND:
8835 					if (g_verbose)
8836 						warn(gettext("Ignoring "
8837 						    "nonexistant instance "
8838 						    "%s:%s.\n"),
8839 						    inst->sc_parent->sc_name,
8840 						    inst->sc_name);
8841 					continue;
8842 
8843 				default:
8844 					scfdie();
8845 				}
8846 			}
8847 
8848 			/*
8849 			 * If the instance does not have a general/enabled
8850 			 * property and no last-import snapshot then the
8851 			 * instance is not a fully installed instance and
8852 			 * should not have a profile applied to it.
8853 			 *
8854 			 * This could happen if a service/instance declares
8855 			 * a dependent on behalf of another service/instance.
8856 			 *
8857 			 */
8858 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8859 			    imp_snap) != 0) {
8860 				if (scf_instance_get_pg(imp_inst,
8861 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8862 				    scf_pg_get_property(imp_pg,
8863 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8864 					if (g_verbose)
8865 						warn(gettext("Ignoreing "
8866 						    "partial instance "
8867 						    "%s:%s.\n"),
8868 						    inst->sc_parent->sc_name,
8869 						    inst->sc_name);
8870 					continue;
8871 				}
8872 			}
8873 
8874 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8875 			    inst, SCI_FORCE | SCI_KEEP);
8876 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8877 			case IMPORT_NEXT:
8878 				break;
8879 
8880 			case IMPORT_OUT:
8881 				goto out;
8882 
8883 			case IMPORT_BAD:
8884 			default:
8885 				bad_error("lscf_import_instance_pgs", r);
8886 			}
8887 
8888 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8889 				uu_list_walk(inst->sc_dependents,
8890 				    lscf_dependent_apply, inst, UU_DEFAULT);
8891 			}
8892 
8893 			/* refresh only if there is no pgs in the service */
8894 			if (refresh == 0)
8895 				(void) refresh_entity(0, imp_inst,
8896 				    inst->sc_fmri, NULL, NULL, NULL);
8897 		}
8898 
8899 		if (refresh == 1) {
8900 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8901 
8902 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8903 			    imp_inst, imp_iter, name_buf);
8904 			free(name_buf);
8905 		}
8906 
8907 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8908 		    old_dpt != NULL;
8909 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8910 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8911 			    old_dpt->sc_pgroup_name,
8912 			    old_dpt->sc_parent->sc_fmri) != 0) {
8913 				warn(gettext("Unable to refresh \"%s\"\n"),
8914 				    old_dpt->sc_pgroup_fmri);
8915 			}
8916 		}
8917 	}
8918 
8919 out:
8920 	if (annotation_set) {
8921 		/* Remove security audit annotation strings. */
8922 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8923 	}
8924 
8925 	free_imp_globals();
8926 	return (ret);
8927 }
8928 
8929 
8930 /*
8931  * Export.  These functions create and output an XML tree of a service
8932  * description from the repository.  This is largely the inverse of
8933  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8934  *
8935  * - We must include any properties which are not represented specifically by
8936  *   a service manifest, e.g., properties created by an admin post-import.  To
8937  *   do so we'll iterate through all properties and deal with each
8938  *   apropriately.
8939  *
8940  * - Children of services and instances must must be in the order set by the
8941  *   DTD, but we iterate over the properties in undefined order.  The elements
8942  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8943  *   number of classes of them, however, we'll keep the classes separate and
8944  *   assemble them in order.
8945  */
8946 
8947 /*
8948  * Convenience function to handle xmlSetProp errors (and type casting).
8949  */
8950 static void
8951 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8952 {
8953 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8954 		uu_die(gettext("Could not set XML property.\n"));
8955 }
8956 
8957 /*
8958  * Convenience function to set an XML attribute to the single value of an
8959  * astring property.  If the value happens to be the default, don't set the
8960  * attribute.  "dval" should be the default value supplied by the DTD, or
8961  * NULL for no default.
8962  */
8963 static int
8964 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8965     const char *name, const char *dval)
8966 {
8967 	scf_value_t *val;
8968 	ssize_t len;
8969 	char *str;
8970 
8971 	val = scf_value_create(g_hndl);
8972 	if (val == NULL)
8973 		scfdie();
8974 
8975 	if (prop_get_val(prop, val) != 0) {
8976 		scf_value_destroy(val);
8977 		return (-1);
8978 	}
8979 
8980 	len = scf_value_get_as_string(val, NULL, 0);
8981 	if (len < 0)
8982 		scfdie();
8983 
8984 	str = safe_malloc(len + 1);
8985 
8986 	if (scf_value_get_as_string(val, str, len + 1) < 0)
8987 		scfdie();
8988 
8989 	scf_value_destroy(val);
8990 
8991 	if (dval == NULL || strcmp(str, dval) != 0)
8992 		safe_setprop(n, name, str);
8993 
8994 	free(str);
8995 
8996 	return (0);
8997 }
8998 
8999 /*
9000  * As above, but the attribute is always set.
9001  */
9002 static int
9003 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9004 {
9005 	return (set_attr_from_prop_default(prop, n, name, NULL));
9006 }
9007 
9008 /*
9009  * Dump the given document onto f, with "'s replaced by ''s.
9010  */
9011 static int
9012 write_service_bundle(xmlDocPtr doc, FILE *f)
9013 {
9014 	xmlChar *mem;
9015 	int sz, i;
9016 
9017 	mem = NULL;
9018 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9019 
9020 	if (mem == NULL) {
9021 		semerr(gettext("Could not dump XML tree.\n"));
9022 		return (-1);
9023 	}
9024 
9025 	/*
9026 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
9027 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9028 	 * &apos; code?!
9029 	 */
9030 	for (i = 0; i < sz; ++i) {
9031 		char c = (char)mem[i];
9032 
9033 		if (c == '"')
9034 			(void) fputc('\'', f);
9035 		else if (c == '\'')
9036 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9037 		else
9038 			(void) fputc(c, f);
9039 	}
9040 
9041 	return (0);
9042 }
9043 
9044 /*
9045  * Create the DOM elements in elts necessary to (generically) represent prop
9046  * (i.e., a property or propval element).  If the name of the property is
9047  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9048  */
9049 static void
9050 export_property(scf_property_t *prop, const char *name_arg,
9051     struct pg_elts *elts, int flags)
9052 {
9053 	const char *type;
9054 	scf_error_t err = 0;
9055 	xmlNodePtr pnode, lnode;
9056 	char *lnname;
9057 	int ret;
9058 
9059 	/* name */
9060 	if (name_arg != NULL) {
9061 		(void) strcpy(exp_str, name_arg);
9062 	} else {
9063 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9064 			scfdie();
9065 	}
9066 
9067 	/* type */
9068 	type = prop_to_typestr(prop);
9069 	if (type == NULL)
9070 		uu_die(gettext("Can't export property %s: unknown type.\n"),
9071 		    exp_str);
9072 
9073 	/* If we're exporting values, and there's just one, export it here. */
9074 	if (!(flags & SCE_ALL_VALUES))
9075 		goto empty;
9076 
9077 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9078 		xmlNodePtr n;
9079 
9080 		/* Single value, so use propval */
9081 		n = xmlNewNode(NULL, (xmlChar *)"propval");
9082 		if (n == NULL)
9083 			uu_die(emsg_create_xml);
9084 
9085 		safe_setprop(n, name_attr, exp_str);
9086 		safe_setprop(n, type_attr, type);
9087 
9088 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9089 			scfdie();
9090 		safe_setprop(n, value_attr, exp_str);
9091 
9092 		if (elts->propvals == NULL)
9093 			elts->propvals = n;
9094 		else
9095 			(void) xmlAddSibling(elts->propvals, n);
9096 
9097 		return;
9098 	}
9099 
9100 	err = scf_error();
9101 
9102 	if (err == SCF_ERROR_PERMISSION_DENIED) {
9103 		semerr(emsg_permission_denied);
9104 		return;
9105 	}
9106 
9107 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9108 	    err != SCF_ERROR_NOT_FOUND &&
9109 	    err != SCF_ERROR_PERMISSION_DENIED)
9110 		scfdie();
9111 
9112 empty:
9113 	/* Multiple (or no) values, so use property */
9114 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
9115 	if (pnode == NULL)
9116 		uu_die(emsg_create_xml);
9117 
9118 	safe_setprop(pnode, name_attr, exp_str);
9119 	safe_setprop(pnode, type_attr, type);
9120 
9121 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9122 		lnname = uu_msprintf("%s_list", type);
9123 		if (lnname == NULL)
9124 			uu_die(gettext("Could not create string"));
9125 
9126 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9127 		if (lnode == NULL)
9128 			uu_die(emsg_create_xml);
9129 
9130 		uu_free(lnname);
9131 
9132 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9133 			scfdie();
9134 
9135 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9136 		    1) {
9137 			xmlNodePtr vn;
9138 
9139 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9140 			    NULL);
9141 			if (vn == NULL)
9142 				uu_die(emsg_create_xml);
9143 
9144 			if (scf_value_get_as_string(exp_val, exp_str,
9145 			    exp_str_sz) < 0)
9146 				scfdie();
9147 			safe_setprop(vn, value_attr, exp_str);
9148 		}
9149 		if (ret != 0)
9150 			scfdie();
9151 	}
9152 
9153 	if (elts->properties == NULL)
9154 		elts->properties = pnode;
9155 	else
9156 		(void) xmlAddSibling(elts->properties, pnode);
9157 }
9158 
9159 /*
9160  * Add a property_group element for this property group to elts.
9161  */
9162 static void
9163 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9164 {
9165 	xmlNodePtr n;
9166 	struct pg_elts elts;
9167 	int ret;
9168 	boolean_t read_protected;
9169 
9170 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
9171 
9172 	/* name */
9173 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9174 		scfdie();
9175 	safe_setprop(n, name_attr, exp_str);
9176 
9177 	/* type */
9178 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9179 		scfdie();
9180 	safe_setprop(n, type_attr, exp_str);
9181 
9182 	/* properties */
9183 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9184 		scfdie();
9185 
9186 	(void) memset(&elts, 0, sizeof (elts));
9187 
9188 	/*
9189 	 * If this property group is not read protected, we always want to
9190 	 * output all the values.  Otherwise, we only output the values if the
9191 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9192 	 */
9193 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9194 		scfdie();
9195 
9196 	if (!read_protected)
9197 		flags |= SCE_ALL_VALUES;
9198 
9199 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9200 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9201 			scfdie();
9202 
9203 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9204 			xmlNodePtr m;
9205 
9206 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9207 			if (m == NULL)
9208 				uu_die(emsg_create_xml);
9209 
9210 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9211 				elts.stability = m;
9212 				continue;
9213 			}
9214 
9215 			xmlFreeNode(m);
9216 		}
9217 
9218 		export_property(exp_prop, NULL, &elts, flags);
9219 	}
9220 	if (ret == -1)
9221 		scfdie();
9222 
9223 	(void) xmlAddChild(n, elts.stability);
9224 	(void) xmlAddChildList(n, elts.propvals);
9225 	(void) xmlAddChildList(n, elts.properties);
9226 
9227 	if (eelts->property_groups == NULL)
9228 		eelts->property_groups = n;
9229 	else
9230 		(void) xmlAddSibling(eelts->property_groups, n);
9231 }
9232 
9233 /*
9234  * Create an XML node representing the dependency described by the given
9235  * property group and put it in eelts.  Unless the dependency is not valid, in
9236  * which case create a generic property_group element which represents it and
9237  * put it in eelts.
9238  */
9239 static void
9240 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9241 {
9242 	xmlNodePtr n;
9243 	int err = 0, ret;
9244 	struct pg_elts elts;
9245 
9246 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
9247 	if (n == NULL)
9248 		uu_die(emsg_create_xml);
9249 
9250 	/*
9251 	 * If the external flag is present, skip this dependency because it
9252 	 * should have been created by another manifest.
9253 	 */
9254 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9255 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9256 		    prop_get_val(exp_prop, exp_val) == 0) {
9257 			uint8_t b;
9258 
9259 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9260 				scfdie();
9261 
9262 			if (b)
9263 				return;
9264 		}
9265 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
9266 		scfdie();
9267 
9268 	/* Get the required attributes. */
9269 
9270 	/* name */
9271 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9272 		scfdie();
9273 	safe_setprop(n, name_attr, exp_str);
9274 
9275 	/* grouping */
9276 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9277 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9278 		err = 1;
9279 
9280 	/* restart_on */
9281 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9282 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9283 		err = 1;
9284 
9285 	/* type */
9286 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9287 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9288 		err = 1;
9289 
9290 	/*
9291 	 * entities: Not required, but if we create no children, it will be
9292 	 * created as empty on import, so fail if it's missing.
9293 	 */
9294 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9295 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9296 		scf_iter_t *eiter;
9297 		int ret2;
9298 
9299 		eiter = scf_iter_create(g_hndl);
9300 		if (eiter == NULL)
9301 			scfdie();
9302 
9303 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9304 			scfdie();
9305 
9306 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9307 			xmlNodePtr ch;
9308 
9309 			if (scf_value_get_astring(exp_val, exp_str,
9310 			    exp_str_sz) < 0)
9311 				scfdie();
9312 
9313 			/*
9314 			 * service_fmri's must be first, so we can add them
9315 			 * here.
9316 			 */
9317 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9318 			    NULL);
9319 			if (ch == NULL)
9320 				uu_die(emsg_create_xml);
9321 
9322 			safe_setprop(ch, value_attr, exp_str);
9323 		}
9324 		if (ret2 == -1)
9325 			scfdie();
9326 
9327 		scf_iter_destroy(eiter);
9328 	} else
9329 		err = 1;
9330 
9331 	if (err) {
9332 		xmlFreeNode(n);
9333 
9334 		export_pg(pg, eelts, SCE_ALL_VALUES);
9335 
9336 		return;
9337 	}
9338 
9339 	/* Iterate through the properties & handle each. */
9340 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9341 		scfdie();
9342 
9343 	(void) memset(&elts, 0, sizeof (elts));
9344 
9345 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9346 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9347 			scfdie();
9348 
9349 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9350 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9351 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9352 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9353 			continue;
9354 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9355 			xmlNodePtr m;
9356 
9357 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9358 			if (m == NULL)
9359 				uu_die(emsg_create_xml);
9360 
9361 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9362 				elts.stability = m;
9363 				continue;
9364 			}
9365 
9366 			xmlFreeNode(m);
9367 		}
9368 
9369 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9370 	}
9371 	if (ret == -1)
9372 		scfdie();
9373 
9374 	(void) xmlAddChild(n, elts.stability);
9375 	(void) xmlAddChildList(n, elts.propvals);
9376 	(void) xmlAddChildList(n, elts.properties);
9377 
9378 	if (eelts->dependencies == NULL)
9379 		eelts->dependencies = n;
9380 	else
9381 		(void) xmlAddSibling(eelts->dependencies, n);
9382 }
9383 
9384 static xmlNodePtr
9385 export_method_environment(scf_propertygroup_t *pg)
9386 {
9387 	xmlNodePtr env;
9388 	int ret;
9389 	int children = 0;
9390 
9391 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9392 		return (NULL);
9393 
9394 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9395 	if (env == NULL)
9396 		uu_die(emsg_create_xml);
9397 
9398 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9399 		scfdie();
9400 
9401 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9402 		scfdie();
9403 
9404 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9405 		xmlNodePtr ev;
9406 		char *cp;
9407 
9408 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9409 			scfdie();
9410 
9411 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9412 			warn(gettext("Invalid environment variable \"%s\".\n"),
9413 			    exp_str);
9414 			continue;
9415 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9416 			warn(gettext("Invalid environment variable \"%s\"; "
9417 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9418 			continue;
9419 		}
9420 
9421 		*cp = '\0';
9422 		cp++;
9423 
9424 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9425 		if (ev == NULL)
9426 			uu_die(emsg_create_xml);
9427 
9428 		safe_setprop(ev, name_attr, exp_str);
9429 		safe_setprop(ev, value_attr, cp);
9430 		children++;
9431 	}
9432 
9433 	if (ret != 0)
9434 		scfdie();
9435 
9436 	if (children == 0) {
9437 		xmlFreeNode(env);
9438 		return (NULL);
9439 	}
9440 
9441 	return (env);
9442 }
9443 
9444 /*
9445  * As above, but for a method property group.
9446  */
9447 static void
9448 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9449 {
9450 	xmlNodePtr n, env;
9451 	char *str;
9452 	int err = 0, nonenv, ret;
9453 	uint8_t use_profile;
9454 	struct pg_elts elts;
9455 	xmlNodePtr ctxt = NULL;
9456 
9457 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9458 
9459 	/* Get the required attributes. */
9460 
9461 	/* name */
9462 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9463 		scfdie();
9464 	safe_setprop(n, name_attr, exp_str);
9465 
9466 	/* type */
9467 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9468 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9469 		err = 1;
9470 
9471 	/* exec */
9472 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9473 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9474 		err = 1;
9475 
9476 	/* timeout */
9477 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9478 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9479 	    prop_get_val(exp_prop, exp_val) == 0) {
9480 		uint64_t c;
9481 
9482 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9483 			scfdie();
9484 
9485 		str = uu_msprintf("%llu", c);
9486 		if (str == NULL)
9487 			uu_die(gettext("Could not create string"));
9488 
9489 		safe_setprop(n, "timeout_seconds", str);
9490 		free(str);
9491 	} else
9492 		err = 1;
9493 
9494 	if (err) {
9495 		xmlFreeNode(n);
9496 
9497 		export_pg(pg, eelts, SCE_ALL_VALUES);
9498 
9499 		return;
9500 	}
9501 
9502 
9503 	/*
9504 	 * If we're going to have a method_context child, we need to know
9505 	 * before we iterate through the properties.  Since method_context's
9506 	 * are optional, we don't want to complain about any properties
9507 	 * missing if none of them are there.  Thus we can't use the
9508 	 * convenience functions.
9509 	 */
9510 	nonenv =
9511 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9512 	    SCF_SUCCESS ||
9513 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9514 	    SCF_SUCCESS ||
9515 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9516 	    SCF_SUCCESS ||
9517 	    scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9518 	    SCF_SUCCESS ||
9519 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9520 	    SCF_SUCCESS;
9521 
9522 	if (nonenv) {
9523 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9524 		if (ctxt == NULL)
9525 			uu_die(emsg_create_xml);
9526 
9527 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9528 		    0 &&
9529 		    set_attr_from_prop_default(exp_prop, ctxt,
9530 		    "working_directory", ":default") != 0)
9531 			err = 1;
9532 
9533 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9534 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9535 		    ":default") != 0)
9536 			err = 1;
9537 
9538 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9539 		    0 &&
9540 		    set_attr_from_prop_default(exp_prop, ctxt,
9541 		    "resource_pool", ":default") != 0)
9542 			err = 1;
9543 
9544 		if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9545 		    set_attr_from_prop_default(exp_prop, ctxt,
9546 		    "security_flags", ":default") != 0)
9547 			err = 1;
9548 
9549 		/*
9550 		 * We only want to complain about profile or credential
9551 		 * properties if we will use them.  To determine that we must
9552 		 * examine USE_PROFILE.
9553 		 */
9554 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9555 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9556 		    prop_get_val(exp_prop, exp_val) == 0) {
9557 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9558 			    SCF_SUCCESS) {
9559 				scfdie();
9560 			}
9561 
9562 			if (use_profile) {
9563 				xmlNodePtr prof;
9564 
9565 				prof = xmlNewChild(ctxt, NULL,
9566 				    (xmlChar *)"method_profile", NULL);
9567 				if (prof == NULL)
9568 					uu_die(emsg_create_xml);
9569 
9570 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9571 				    exp_prop) != 0 ||
9572 				    set_attr_from_prop(exp_prop, prof,
9573 				    name_attr) != 0)
9574 					err = 1;
9575 			} else {
9576 				xmlNodePtr cred;
9577 
9578 				cred = xmlNewChild(ctxt, NULL,
9579 				    (xmlChar *)"method_credential", NULL);
9580 				if (cred == NULL)
9581 					uu_die(emsg_create_xml);
9582 
9583 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9584 				    exp_prop) != 0 ||
9585 				    set_attr_from_prop(exp_prop, cred,
9586 				    "user") != 0) {
9587 					err = 1;
9588 				}
9589 
9590 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9591 				    exp_prop) == 0 &&
9592 				    set_attr_from_prop_default(exp_prop, cred,
9593 				    "group", ":default") != 0)
9594 					err = 1;
9595 
9596 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9597 				    exp_prop) == 0 &&
9598 				    set_attr_from_prop_default(exp_prop, cred,
9599 				    "supp_groups", ":default") != 0)
9600 					err = 1;
9601 
9602 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9603 				    exp_prop) == 0 &&
9604 				    set_attr_from_prop_default(exp_prop, cred,
9605 				    "privileges", ":default") != 0)
9606 					err = 1;
9607 
9608 				if (pg_get_prop(pg,
9609 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9610 				    exp_prop) == 0 &&
9611 				    set_attr_from_prop_default(exp_prop, cred,
9612 				    "limit_privileges", ":default") != 0)
9613 					err = 1;
9614 			}
9615 		}
9616 	}
9617 
9618 	if ((env = export_method_environment(pg)) != NULL) {
9619 		if (ctxt == NULL) {
9620 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9621 			if (ctxt == NULL)
9622 				uu_die(emsg_create_xml);
9623 		}
9624 		(void) xmlAddChild(ctxt, env);
9625 	}
9626 
9627 	if (env != NULL || (nonenv && err == 0))
9628 		(void) xmlAddChild(n, ctxt);
9629 	else
9630 		xmlFreeNode(ctxt);
9631 
9632 	nonenv = (err == 0);
9633 
9634 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9635 		scfdie();
9636 
9637 	(void) memset(&elts, 0, sizeof (elts));
9638 
9639 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9640 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9641 			scfdie();
9642 
9643 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9644 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9645 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9646 			continue;
9647 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9648 			xmlNodePtr m;
9649 
9650 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9651 			if (m == NULL)
9652 				uu_die(emsg_create_xml);
9653 
9654 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9655 				elts.stability = m;
9656 				continue;
9657 			}
9658 
9659 			xmlFreeNode(m);
9660 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9661 		    0 ||
9662 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9663 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9664 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9665 			if (nonenv)
9666 				continue;
9667 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9668 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9669 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9670 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9671 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9672 		    strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9673 			if (nonenv && !use_profile)
9674 				continue;
9675 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9676 			if (nonenv && use_profile)
9677 				continue;
9678 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9679 			if (env != NULL)
9680 				continue;
9681 		}
9682 
9683 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9684 	}
9685 	if (ret == -1)
9686 		scfdie();
9687 
9688 	(void) xmlAddChild(n, elts.stability);
9689 	(void) xmlAddChildList(n, elts.propvals);
9690 	(void) xmlAddChildList(n, elts.properties);
9691 
9692 	if (eelts->exec_methods == NULL)
9693 		eelts->exec_methods = n;
9694 	else
9695 		(void) xmlAddSibling(eelts->exec_methods, n);
9696 }
9697 
9698 static void
9699 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9700     struct entity_elts *eelts)
9701 {
9702 	xmlNodePtr pgnode;
9703 
9704 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9705 	if (pgnode == NULL)
9706 		uu_die(emsg_create_xml);
9707 
9708 	safe_setprop(pgnode, name_attr, name);
9709 	safe_setprop(pgnode, type_attr, type);
9710 
9711 	(void) xmlAddChildList(pgnode, elts->propvals);
9712 	(void) xmlAddChildList(pgnode, elts->properties);
9713 
9714 	if (eelts->property_groups == NULL)
9715 		eelts->property_groups = pgnode;
9716 	else
9717 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9718 }
9719 
9720 /*
9721  * Process the general property group for a service.  This is the one with the
9722  * goodies.
9723  */
9724 static void
9725 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9726 {
9727 	struct pg_elts elts;
9728 	int ret;
9729 
9730 	/*
9731 	 * In case there are properties which don't correspond to child
9732 	 * entities of the service entity, we'll set up a pg_elts structure to
9733 	 * put them in.
9734 	 */
9735 	(void) memset(&elts, 0, sizeof (elts));
9736 
9737 	/* Walk the properties, looking for special ones. */
9738 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9739 		scfdie();
9740 
9741 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9742 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9743 			scfdie();
9744 
9745 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9746 			/*
9747 			 * Unimplemented and obsolete, but we still process it
9748 			 * for compatibility purposes.
9749 			 */
9750 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9751 			    prop_get_val(exp_prop, exp_val) == 0) {
9752 				uint8_t b;
9753 
9754 				if (scf_value_get_boolean(exp_val, &b) !=
9755 				    SCF_SUCCESS)
9756 					scfdie();
9757 
9758 				if (b) {
9759 					selts->single_instance =
9760 					    xmlNewNode(NULL,
9761 					    (xmlChar *)"single_instance");
9762 					if (selts->single_instance == NULL)
9763 						uu_die(emsg_create_xml);
9764 				}
9765 
9766 				continue;
9767 			}
9768 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9769 			xmlNodePtr rnode, sfnode;
9770 
9771 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9772 			if (rnode == NULL)
9773 				uu_die(emsg_create_xml);
9774 
9775 			sfnode = xmlNewChild(rnode, NULL,
9776 			    (xmlChar *)"service_fmri", NULL);
9777 			if (sfnode == NULL)
9778 				uu_die(emsg_create_xml);
9779 
9780 			if (set_attr_from_prop(exp_prop, sfnode,
9781 			    value_attr) == 0) {
9782 				selts->restarter = rnode;
9783 				continue;
9784 			}
9785 
9786 			xmlFreeNode(rnode);
9787 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9788 		    0) {
9789 			xmlNodePtr s;
9790 
9791 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9792 			if (s == NULL)
9793 				uu_die(emsg_create_xml);
9794 
9795 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9796 				selts->stability = s;
9797 				continue;
9798 			}
9799 
9800 			xmlFreeNode(s);
9801 		}
9802 
9803 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9804 	}
9805 	if (ret == -1)
9806 		scfdie();
9807 
9808 	if (elts.propvals != NULL || elts.properties != NULL)
9809 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9810 		    selts);
9811 }
9812 
9813 static void
9814 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9815 {
9816 	xmlNodePtr n, prof, cred, env;
9817 	uint8_t use_profile;
9818 	int ret, err = 0;
9819 
9820 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9821 
9822 	env = export_method_environment(pg);
9823 
9824 	/* Need to know whether we'll use a profile or not. */
9825 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9826 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9827 	    prop_get_val(exp_prop, exp_val) == 0) {
9828 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9829 			scfdie();
9830 
9831 		if (use_profile)
9832 			prof =
9833 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9834 			    NULL);
9835 		else
9836 			cred =
9837 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9838 			    NULL);
9839 	}
9840 
9841 	if (env != NULL)
9842 		(void) xmlAddChild(n, env);
9843 
9844 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9845 		scfdie();
9846 
9847 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9848 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9849 			scfdie();
9850 
9851 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9852 			if (set_attr_from_prop(exp_prop, n,
9853 			    "working_directory") != 0)
9854 				err = 1;
9855 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9856 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9857 				err = 1;
9858 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9859 			if (set_attr_from_prop(exp_prop, n,
9860 			    "resource_pool") != 0)
9861 				err = 1;
9862 		} else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9863 			if (set_attr_from_prop(exp_prop, n,
9864 			    "security_flags") != 0)
9865 				err = 1;
9866 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9867 			/* EMPTY */
9868 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9869 			if (use_profile ||
9870 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9871 				err = 1;
9872 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9873 			if (use_profile ||
9874 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9875 				err = 1;
9876 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9877 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9878 			    "supp_groups") != 0)
9879 				err = 1;
9880 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9881 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9882 			    "privileges") != 0)
9883 				err = 1;
9884 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9885 		    0) {
9886 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9887 			    "limit_privileges") != 0)
9888 				err = 1;
9889 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9890 			if (!use_profile || set_attr_from_prop(exp_prop,
9891 			    prof, name_attr) != 0)
9892 				err = 1;
9893 		} else {
9894 			/* Can't have generic properties in method_context's */
9895 			err = 1;
9896 		}
9897 	}
9898 	if (ret == -1)
9899 		scfdie();
9900 
9901 	if (err && env == NULL) {
9902 		xmlFreeNode(n);
9903 		export_pg(pg, elts, SCE_ALL_VALUES);
9904 		return;
9905 	}
9906 
9907 	elts->method_context = n;
9908 }
9909 
9910 /*
9911  * Given a dependency property group in the tfmri entity (target fmri), return
9912  * a dependent element which represents it.
9913  */
9914 static xmlNodePtr
9915 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9916 {
9917 	uint8_t b;
9918 	xmlNodePtr n, sf;
9919 	int err = 0, ret;
9920 	struct pg_elts pgelts;
9921 
9922 	/*
9923 	 * If external isn't set to true then exporting the service will
9924 	 * export this as a normal dependency, so we should stop to avoid
9925 	 * duplication.
9926 	 */
9927 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9928 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9929 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9930 		if (g_verbose) {
9931 			warn(gettext("Dependent \"%s\" cannot be exported "
9932 			    "properly because the \"%s\" property of the "
9933 			    "\"%s\" dependency of %s is not set to true.\n"),
9934 			    name, scf_property_external, name, tfmri);
9935 		}
9936 
9937 		return (NULL);
9938 	}
9939 
9940 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9941 	if (n == NULL)
9942 		uu_die(emsg_create_xml);
9943 
9944 	safe_setprop(n, name_attr, name);
9945 
9946 	/* Get the required attributes */
9947 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9948 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9949 		err = 1;
9950 
9951 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9952 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9953 		err = 1;
9954 
9955 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9956 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9957 	    prop_get_val(exp_prop, exp_val) == 0) {
9958 		/* EMPTY */
9959 	} else
9960 		err = 1;
9961 
9962 	if (err) {
9963 		xmlFreeNode(n);
9964 		return (NULL);
9965 	}
9966 
9967 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9968 	if (sf == NULL)
9969 		uu_die(emsg_create_xml);
9970 
9971 	safe_setprop(sf, value_attr, tfmri);
9972 
9973 	/*
9974 	 * Now add elements for the other properties.
9975 	 */
9976 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9977 		scfdie();
9978 
9979 	(void) memset(&pgelts, 0, sizeof (pgelts));
9980 
9981 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9982 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9983 			scfdie();
9984 
9985 		if (strcmp(exp_str, scf_property_external) == 0 ||
9986 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9987 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9988 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9989 			continue;
9990 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9991 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9992 			    prop_get_val(exp_prop, exp_val) == 0) {
9993 				char type[sizeof ("service") + 1];
9994 
9995 				if (scf_value_get_astring(exp_val, type,
9996 				    sizeof (type)) < 0)
9997 					scfdie();
9998 
9999 				if (strcmp(type, "service") == 0)
10000 					continue;
10001 			}
10002 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10003 			xmlNodePtr s;
10004 
10005 			s = xmlNewNode(NULL, (xmlChar *)"stability");
10006 			if (s == NULL)
10007 				uu_die(emsg_create_xml);
10008 
10009 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10010 				pgelts.stability = s;
10011 				continue;
10012 			}
10013 
10014 			xmlFreeNode(s);
10015 		}
10016 
10017 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10018 	}
10019 	if (ret == -1)
10020 		scfdie();
10021 
10022 	(void) xmlAddChild(n, pgelts.stability);
10023 	(void) xmlAddChildList(n, pgelts.propvals);
10024 	(void) xmlAddChildList(n, pgelts.properties);
10025 
10026 	return (n);
10027 }
10028 
10029 static void
10030 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10031 {
10032 	scf_propertygroup_t *opg;
10033 	scf_iter_t *iter;
10034 	char *type, *fmri;
10035 	int ret;
10036 	struct pg_elts pgelts;
10037 	xmlNodePtr n;
10038 	scf_error_t serr;
10039 
10040 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
10041 	    (iter = scf_iter_create(g_hndl)) == NULL)
10042 		scfdie();
10043 
10044 	/* Can't use exp_prop_iter due to export_dependent(). */
10045 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10046 		scfdie();
10047 
10048 	type = safe_malloc(max_scf_pg_type_len + 1);
10049 
10050 	/* Get an extra byte so we can tell if values are too long. */
10051 	fmri = safe_malloc(max_scf_fmri_len + 2);
10052 
10053 	(void) memset(&pgelts, 0, sizeof (pgelts));
10054 
10055 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10056 		void *entity;
10057 		int isservice;
10058 		scf_type_t ty;
10059 
10060 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10061 			scfdie();
10062 
10063 		if ((ty != SCF_TYPE_ASTRING &&
10064 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10065 		    prop_get_val(exp_prop, exp_val) != 0) {
10066 			export_property(exp_prop, NULL, &pgelts,
10067 			    SCE_ALL_VALUES);
10068 			continue;
10069 		}
10070 
10071 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10072 			scfdie();
10073 
10074 		if (scf_value_get_astring(exp_val, fmri,
10075 		    max_scf_fmri_len + 2) < 0)
10076 			scfdie();
10077 
10078 		/* Look for a dependency group in the target fmri. */
10079 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10080 		switch (serr) {
10081 		case SCF_ERROR_NONE:
10082 			break;
10083 
10084 		case SCF_ERROR_NO_MEMORY:
10085 			uu_die(gettext("Out of memory.\n"));
10086 			/* NOTREACHED */
10087 
10088 		case SCF_ERROR_INVALID_ARGUMENT:
10089 			if (g_verbose) {
10090 				if (scf_property_to_fmri(exp_prop, fmri,
10091 				    max_scf_fmri_len + 2) < 0)
10092 					scfdie();
10093 
10094 				warn(gettext("The value of %s is not a valid "
10095 				    "FMRI.\n"), fmri);
10096 			}
10097 
10098 			export_property(exp_prop, exp_str, &pgelts,
10099 			    SCE_ALL_VALUES);
10100 			continue;
10101 
10102 		case SCF_ERROR_CONSTRAINT_VIOLATED:
10103 			if (g_verbose) {
10104 				if (scf_property_to_fmri(exp_prop, fmri,
10105 				    max_scf_fmri_len + 2) < 0)
10106 					scfdie();
10107 
10108 				warn(gettext("The value of %s does not specify "
10109 				    "a service or an instance.\n"), fmri);
10110 			}
10111 
10112 			export_property(exp_prop, exp_str, &pgelts,
10113 			    SCE_ALL_VALUES);
10114 			continue;
10115 
10116 		case SCF_ERROR_NOT_FOUND:
10117 			if (g_verbose) {
10118 				if (scf_property_to_fmri(exp_prop, fmri,
10119 				    max_scf_fmri_len + 2) < 0)
10120 					scfdie();
10121 
10122 				warn(gettext("The entity specified by %s does "
10123 				    "not exist.\n"), fmri);
10124 			}
10125 
10126 			export_property(exp_prop, exp_str, &pgelts,
10127 			    SCE_ALL_VALUES);
10128 			continue;
10129 
10130 		default:
10131 #ifndef NDEBUG
10132 			(void) fprintf(stderr, "%s:%d: %s() failed with "
10133 			    "unexpected error %d.\n", __FILE__, __LINE__,
10134 			    "fmri_to_entity", serr);
10135 #endif
10136 			abort();
10137 		}
10138 
10139 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10140 			if (scf_error() != SCF_ERROR_NOT_FOUND)
10141 				scfdie();
10142 
10143 			warn(gettext("Entity %s is missing dependency property "
10144 			    "group %s.\n"), fmri, exp_str);
10145 
10146 			export_property(exp_prop, NULL, &pgelts,
10147 			    SCE_ALL_VALUES);
10148 			continue;
10149 		}
10150 
10151 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10152 			scfdie();
10153 
10154 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10155 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10156 				scfdie();
10157 
10158 			warn(gettext("Property group %s is not of "
10159 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10160 
10161 			export_property(exp_prop, NULL, &pgelts,
10162 			    SCE_ALL_VALUES);
10163 			continue;
10164 		}
10165 
10166 		n = export_dependent(opg, exp_str, fmri);
10167 		if (n == NULL) {
10168 			export_property(exp_prop, exp_str, &pgelts,
10169 			    SCE_ALL_VALUES);
10170 		} else {
10171 			if (eelts->dependents == NULL)
10172 				eelts->dependents = n;
10173 			else
10174 				(void) xmlAddSibling(eelts->dependents,
10175 				    n);
10176 		}
10177 	}
10178 	if (ret == -1)
10179 		scfdie();
10180 
10181 	free(fmri);
10182 	free(type);
10183 
10184 	scf_iter_destroy(iter);
10185 	scf_pg_destroy(opg);
10186 
10187 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10188 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10189 		    eelts);
10190 }
10191 
10192 static void
10193 make_node(xmlNodePtr *nodep, const char *name)
10194 {
10195 	if (*nodep == NULL) {
10196 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
10197 		if (*nodep == NULL)
10198 			uu_die(emsg_create_xml);
10199 	}
10200 }
10201 
10202 static xmlNodePtr
10203 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10204 {
10205 	int ret;
10206 	xmlNodePtr parent = NULL;
10207 	xmlNodePtr loctext = NULL;
10208 
10209 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10210 		scfdie();
10211 
10212 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10213 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10214 		    prop_get_val(exp_prop, exp_val) != 0)
10215 			continue;
10216 
10217 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10218 			scfdie();
10219 
10220 		make_node(&parent, parname);
10221 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10222 		    (xmlChar *)exp_str);
10223 		if (loctext == NULL)
10224 			uu_die(emsg_create_xml);
10225 
10226 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10227 			scfdie();
10228 
10229 		safe_setprop(loctext, "xml:lang", exp_str);
10230 	}
10231 
10232 	if (ret == -1)
10233 		scfdie();
10234 
10235 	return (parent);
10236 }
10237 
10238 static xmlNodePtr
10239 export_tm_manpage(scf_propertygroup_t *pg)
10240 {
10241 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10242 	if (manpage == NULL)
10243 		uu_die(emsg_create_xml);
10244 
10245 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10246 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10247 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10248 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10249 		xmlFreeNode(manpage);
10250 		return (NULL);
10251 	}
10252 
10253 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10254 		(void) set_attr_from_prop_default(exp_prop,
10255 		    manpage, "manpath", ":default");
10256 
10257 	return (manpage);
10258 }
10259 
10260 static xmlNodePtr
10261 export_tm_doc_link(scf_propertygroup_t *pg)
10262 {
10263 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10264 	if (doc_link == NULL)
10265 		uu_die(emsg_create_xml);
10266 
10267 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10268 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10269 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10270 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10271 		xmlFreeNode(doc_link);
10272 		return (NULL);
10273 	}
10274 	return (doc_link);
10275 }
10276 
10277 /*
10278  * Process template information for a service or instances.
10279  */
10280 static void
10281 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10282     struct template_elts *telts)
10283 {
10284 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10285 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10286 	xmlNodePtr child = NULL;
10287 
10288 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10289 		scfdie();
10290 
10291 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10292 		telts->common_name = export_tm_loctext(pg, "common_name");
10293 		if (telts->common_name == NULL)
10294 			export_pg(pg, elts, SCE_ALL_VALUES);
10295 		return;
10296 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10297 		telts->description = export_tm_loctext(pg, "description");
10298 		if (telts->description == NULL)
10299 			export_pg(pg, elts, SCE_ALL_VALUES);
10300 		return;
10301 	}
10302 
10303 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10304 		child = export_tm_manpage(pg);
10305 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10306 		child = export_tm_doc_link(pg);
10307 	}
10308 
10309 	if (child != NULL) {
10310 		make_node(&telts->documentation, "documentation");
10311 		(void) xmlAddChild(telts->documentation, child);
10312 	} else {
10313 		export_pg(pg, elts, SCE_ALL_VALUES);
10314 	}
10315 }
10316 
10317 /*
10318  * Process parameter and paramval elements
10319  */
10320 static void
10321 export_parameter(scf_property_t *prop, const char *name,
10322     struct params_elts *elts)
10323 {
10324 	xmlNodePtr param;
10325 	scf_error_t err = 0;
10326 	int ret;
10327 
10328 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10329 		if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10330 			uu_die(emsg_create_xml);
10331 
10332 		safe_setprop(param, name_attr, name);
10333 
10334 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10335 			scfdie();
10336 		safe_setprop(param, value_attr, exp_str);
10337 
10338 		if (elts->paramval == NULL)
10339 			elts->paramval = param;
10340 		else
10341 			(void) xmlAddSibling(elts->paramval, param);
10342 
10343 		return;
10344 	}
10345 
10346 	err = scf_error();
10347 
10348 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10349 	    err != SCF_ERROR_NOT_FOUND)
10350 		scfdie();
10351 
10352 	if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10353 		uu_die(emsg_create_xml);
10354 
10355 	safe_setprop(param, name_attr, name);
10356 
10357 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10358 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10359 			scfdie();
10360 
10361 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10362 		    1) {
10363 			xmlNodePtr vn;
10364 
10365 			if ((vn = xmlNewChild(param, NULL,
10366 			    (xmlChar *)"value_node", NULL)) == NULL)
10367 				uu_die(emsg_create_xml);
10368 
10369 			if (scf_value_get_as_string(exp_val, exp_str,
10370 			    exp_str_sz) < 0)
10371 				scfdie();
10372 
10373 			safe_setprop(vn, value_attr, exp_str);
10374 		}
10375 		if (ret != 0)
10376 			scfdie();
10377 	}
10378 
10379 	if (elts->parameter == NULL)
10380 		elts->parameter = param;
10381 	else
10382 		(void) xmlAddSibling(elts->parameter, param);
10383 }
10384 
10385 /*
10386  * Process notification parameters for a service or instance
10387  */
10388 static void
10389 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10390 {
10391 	xmlNodePtr n, event, *type;
10392 	struct params_elts *eelts;
10393 	int ret, err, i;
10394 	char *s;
10395 
10396 	n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10397 	event = xmlNewNode(NULL, (xmlChar *)"event");
10398 	if (n == NULL || event == NULL)
10399 		uu_die(emsg_create_xml);
10400 
10401 	/* event value */
10402 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10403 		scfdie();
10404 	/* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10405 	if ((s = strchr(exp_str, ',')) != NULL)
10406 		*s = '\0';
10407 	safe_setprop(event, value_attr, exp_str);
10408 
10409 	(void) xmlAddChild(n, event);
10410 
10411 	if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10412 	    (eelts = calloc(URI_SCHEME_NUM,
10413 	    sizeof (struct params_elts))) == NULL)
10414 		uu_die(gettext("Out of memory.\n"));
10415 
10416 	err = 0;
10417 
10418 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10419 		scfdie();
10420 
10421 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10422 		char *t, *p;
10423 
10424 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10425 			scfdie();
10426 
10427 		if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10428 			/*
10429 			 * this is not a well formed notification parameters
10430 			 * element, we should export as regular pg
10431 			 */
10432 			err = 1;
10433 			break;
10434 		}
10435 
10436 		if ((i = check_uri_protocol(t)) < 0) {
10437 			err = 1;
10438 			break;
10439 		}
10440 
10441 		if (type[i] == NULL) {
10442 			if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10443 			    NULL)
10444 				uu_die(emsg_create_xml);
10445 
10446 			safe_setprop(type[i], name_attr, t);
10447 		}
10448 		if (strcmp(p, active_attr) == 0) {
10449 			if (set_attr_from_prop(exp_prop, type[i],
10450 			    active_attr) != 0) {
10451 				err = 1;
10452 				break;
10453 			}
10454 			continue;
10455 		}
10456 		/*
10457 		 * We export the parameter
10458 		 */
10459 		export_parameter(exp_prop, p, &eelts[i]);
10460 	}
10461 
10462 	if (ret == -1)
10463 		scfdie();
10464 
10465 	if (err == 1) {
10466 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10467 			xmlFree(type[i]);
10468 		free(type);
10469 
10470 		export_pg(pg, elts, SCE_ALL_VALUES);
10471 
10472 		return;
10473 	} else {
10474 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10475 			if (type[i] != NULL) {
10476 				(void) xmlAddChildList(type[i],
10477 				    eelts[i].paramval);
10478 				(void) xmlAddChildList(type[i],
10479 				    eelts[i].parameter);
10480 				(void) xmlAddSibling(event, type[i]);
10481 			}
10482 	}
10483 	free(type);
10484 
10485 	if (elts->notify_params == NULL)
10486 		elts->notify_params = n;
10487 	else
10488 		(void) xmlAddSibling(elts->notify_params, n);
10489 }
10490 
10491 /*
10492  * Process the general property group for an instance.
10493  */
10494 static void
10495 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10496     struct entity_elts *elts)
10497 {
10498 	uint8_t enabled;
10499 	struct pg_elts pgelts;
10500 	int ret;
10501 
10502 	/* enabled */
10503 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10504 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10505 	    prop_get_val(exp_prop, exp_val) == 0) {
10506 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10507 			scfdie();
10508 	} else {
10509 		enabled = 0;
10510 	}
10511 
10512 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10513 
10514 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10515 		scfdie();
10516 
10517 	(void) memset(&pgelts, 0, sizeof (pgelts));
10518 
10519 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10520 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10521 			scfdie();
10522 
10523 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10524 			continue;
10525 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10526 			xmlNodePtr rnode, sfnode;
10527 
10528 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10529 			if (rnode == NULL)
10530 				uu_die(emsg_create_xml);
10531 
10532 			sfnode = xmlNewChild(rnode, NULL,
10533 			    (xmlChar *)"service_fmri", NULL);
10534 			if (sfnode == NULL)
10535 				uu_die(emsg_create_xml);
10536 
10537 			if (set_attr_from_prop(exp_prop, sfnode,
10538 			    value_attr) == 0) {
10539 				elts->restarter = rnode;
10540 				continue;
10541 			}
10542 
10543 			xmlFreeNode(rnode);
10544 		}
10545 
10546 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10547 	}
10548 	if (ret == -1)
10549 		scfdie();
10550 
10551 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10552 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10553 		    elts);
10554 }
10555 
10556 /*
10557  * Put an instance element for the given instance into selts.
10558  */
10559 static void
10560 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10561 {
10562 	xmlNodePtr n;
10563 	boolean_t isdefault;
10564 	struct entity_elts elts;
10565 	struct template_elts template_elts;
10566 	int ret;
10567 
10568 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10569 	if (n == NULL)
10570 		uu_die(emsg_create_xml);
10571 
10572 	/* name */
10573 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10574 		scfdie();
10575 	safe_setprop(n, name_attr, exp_str);
10576 	isdefault = strcmp(exp_str, "default") == 0;
10577 
10578 	/* check existance of general pg (since general/enabled is required) */
10579 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10580 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10581 			scfdie();
10582 
10583 		if (g_verbose) {
10584 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10585 				scfdie();
10586 
10587 			warn(gettext("Instance %s has no general property "
10588 			    "group; it will be marked disabled.\n"), exp_str);
10589 		}
10590 
10591 		safe_setprop(n, enabled_attr, false);
10592 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10593 	    strcmp(exp_str, scf_group_framework) != 0) {
10594 		if (g_verbose) {
10595 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10596 				scfdie();
10597 
10598 			warn(gettext("Property group %s is not of type "
10599 			    "framework; the instance will be marked "
10600 			    "disabled.\n"), exp_str);
10601 		}
10602 
10603 		safe_setprop(n, enabled_attr, false);
10604 	}
10605 
10606 	/* property groups */
10607 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10608 		scfdie();
10609 
10610 	(void) memset(&elts, 0, sizeof (elts));
10611 	(void) memset(&template_elts, 0, sizeof (template_elts));
10612 
10613 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10614 		uint32_t pgflags;
10615 
10616 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10617 			scfdie();
10618 
10619 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10620 			continue;
10621 
10622 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10623 			scfdie();
10624 
10625 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10626 			export_dependency(exp_pg, &elts);
10627 			continue;
10628 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10629 			export_method(exp_pg, &elts);
10630 			continue;
10631 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10632 			if (scf_pg_get_name(exp_pg, exp_str,
10633 			    max_scf_name_len + 1) < 0)
10634 				scfdie();
10635 
10636 			if (strcmp(exp_str, scf_pg_general) == 0) {
10637 				export_inst_general(exp_pg, n, &elts);
10638 				continue;
10639 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10640 			    0) {
10641 				export_method_context(exp_pg, &elts);
10642 				continue;
10643 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10644 				export_dependents(exp_pg, &elts);
10645 				continue;
10646 			}
10647 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10648 			export_template(exp_pg, &elts, &template_elts);
10649 			continue;
10650 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10651 			export_notify_params(exp_pg, &elts);
10652 			continue;
10653 		}
10654 
10655 		/* Ordinary pg. */
10656 		export_pg(exp_pg, &elts, flags);
10657 	}
10658 	if (ret == -1)
10659 		scfdie();
10660 
10661 	if (template_elts.common_name != NULL) {
10662 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10663 		(void) xmlAddChild(elts.template, template_elts.common_name);
10664 		(void) xmlAddChild(elts.template, template_elts.description);
10665 		(void) xmlAddChild(elts.template, template_elts.documentation);
10666 	} else {
10667 		xmlFreeNode(template_elts.description);
10668 		xmlFreeNode(template_elts.documentation);
10669 	}
10670 
10671 	if (isdefault && elts.restarter == NULL &&
10672 	    elts.dependencies == NULL && elts.method_context == NULL &&
10673 	    elts.exec_methods == NULL && elts.notify_params == NULL &&
10674 	    elts.property_groups == NULL && elts.template == NULL) {
10675 		xmlChar *eval;
10676 
10677 		/* This is a default instance */
10678 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10679 
10680 		xmlFreeNode(n);
10681 
10682 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10683 		if (n == NULL)
10684 			uu_die(emsg_create_xml);
10685 
10686 		safe_setprop(n, enabled_attr, (char *)eval);
10687 		xmlFree(eval);
10688 
10689 		selts->create_default_instance = n;
10690 	} else {
10691 		/* Assemble the children in order. */
10692 		(void) xmlAddChild(n, elts.restarter);
10693 		(void) xmlAddChildList(n, elts.dependencies);
10694 		(void) xmlAddChildList(n, elts.dependents);
10695 		(void) xmlAddChild(n, elts.method_context);
10696 		(void) xmlAddChildList(n, elts.exec_methods);
10697 		(void) xmlAddChildList(n, elts.notify_params);
10698 		(void) xmlAddChildList(n, elts.property_groups);
10699 		(void) xmlAddChild(n, elts.template);
10700 
10701 		if (selts->instances == NULL)
10702 			selts->instances = n;
10703 		else
10704 			(void) xmlAddSibling(selts->instances, n);
10705 	}
10706 }
10707 
10708 /*
10709  * Return a service element for the given service.
10710  */
10711 static xmlNodePtr
10712 export_service(scf_service_t *svc, int flags)
10713 {
10714 	xmlNodePtr snode;
10715 	struct entity_elts elts;
10716 	struct template_elts template_elts;
10717 	int ret;
10718 
10719 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10720 	if (snode == NULL)
10721 		uu_die(emsg_create_xml);
10722 
10723 	/* Get & set name attribute */
10724 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10725 		scfdie();
10726 	safe_setprop(snode, name_attr, exp_str);
10727 
10728 	safe_setprop(snode, type_attr, "service");
10729 	safe_setprop(snode, "version", "0");
10730 
10731 	/* Acquire child elements. */
10732 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10733 		scfdie();
10734 
10735 	(void) memset(&elts, 0, sizeof (elts));
10736 	(void) memset(&template_elts, 0, sizeof (template_elts));
10737 
10738 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10739 		uint32_t pgflags;
10740 
10741 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10742 			scfdie();
10743 
10744 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10745 			continue;
10746 
10747 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10748 			scfdie();
10749 
10750 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10751 			export_dependency(exp_pg, &elts);
10752 			continue;
10753 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10754 			export_method(exp_pg, &elts);
10755 			continue;
10756 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10757 			if (scf_pg_get_name(exp_pg, exp_str,
10758 			    max_scf_name_len + 1) < 0)
10759 				scfdie();
10760 
10761 			if (strcmp(exp_str, scf_pg_general) == 0) {
10762 				export_svc_general(exp_pg, &elts);
10763 				continue;
10764 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10765 			    0) {
10766 				export_method_context(exp_pg, &elts);
10767 				continue;
10768 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10769 				export_dependents(exp_pg, &elts);
10770 				continue;
10771 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10772 				continue;
10773 			}
10774 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10775 			export_template(exp_pg, &elts, &template_elts);
10776 			continue;
10777 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10778 			export_notify_params(exp_pg, &elts);
10779 			continue;
10780 		}
10781 
10782 		export_pg(exp_pg, &elts, flags);
10783 	}
10784 	if (ret == -1)
10785 		scfdie();
10786 
10787 	if (template_elts.common_name != NULL) {
10788 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10789 		(void) xmlAddChild(elts.template, template_elts.common_name);
10790 		(void) xmlAddChild(elts.template, template_elts.description);
10791 		(void) xmlAddChild(elts.template, template_elts.documentation);
10792 	} else {
10793 		xmlFreeNode(template_elts.description);
10794 		xmlFreeNode(template_elts.documentation);
10795 	}
10796 
10797 	/* Iterate instances */
10798 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10799 		scfdie();
10800 
10801 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10802 		export_instance(exp_inst, &elts, flags);
10803 	if (ret == -1)
10804 		scfdie();
10805 
10806 	/* Now add all of the accumulated elements in order. */
10807 	(void) xmlAddChild(snode, elts.create_default_instance);
10808 	(void) xmlAddChild(snode, elts.single_instance);
10809 	(void) xmlAddChild(snode, elts.restarter);
10810 	(void) xmlAddChildList(snode, elts.dependencies);
10811 	(void) xmlAddChildList(snode, elts.dependents);
10812 	(void) xmlAddChild(snode, elts.method_context);
10813 	(void) xmlAddChildList(snode, elts.exec_methods);
10814 	(void) xmlAddChildList(snode, elts.notify_params);
10815 	(void) xmlAddChildList(snode, elts.property_groups);
10816 	(void) xmlAddChildList(snode, elts.instances);
10817 	(void) xmlAddChild(snode, elts.stability);
10818 	(void) xmlAddChild(snode, elts.template);
10819 
10820 	return (snode);
10821 }
10822 
10823 static int
10824 export_callback(void *data, scf_walkinfo_t *wip)
10825 {
10826 	FILE *f;
10827 	xmlDocPtr doc;
10828 	xmlNodePtr sb;
10829 	int result;
10830 	struct export_args *argsp = (struct export_args *)data;
10831 
10832 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10833 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10834 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10835 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10836 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10837 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10838 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10839 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10840 		scfdie();
10841 
10842 	exp_str_sz = max_scf_len + 1;
10843 	exp_str = safe_malloc(exp_str_sz);
10844 
10845 	if (argsp->filename != NULL) {
10846 		errno = 0;
10847 		f = fopen(argsp->filename, "wb");
10848 		if (f == NULL) {
10849 			if (errno == 0)
10850 				uu_die(gettext("Could not open \"%s\": no free "
10851 				    "stdio streams.\n"), argsp->filename);
10852 			else
10853 				uu_die(gettext("Could not open \"%s\""),
10854 				    argsp->filename);
10855 		}
10856 	} else
10857 		f = stdout;
10858 
10859 	doc = xmlNewDoc((xmlChar *)"1.0");
10860 	if (doc == NULL)
10861 		uu_die(gettext("Could not create XML document.\n"));
10862 
10863 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10864 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10865 		uu_die(emsg_create_xml);
10866 
10867 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10868 	if (sb == NULL)
10869 		uu_die(emsg_create_xml);
10870 	safe_setprop(sb, type_attr, "manifest");
10871 	safe_setprop(sb, name_attr, "export");
10872 	(void) xmlAddSibling(doc->children, sb);
10873 
10874 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10875 
10876 	result = write_service_bundle(doc, f);
10877 
10878 	free(exp_str);
10879 	scf_iter_destroy(exp_val_iter);
10880 	scf_iter_destroy(exp_prop_iter);
10881 	scf_iter_destroy(exp_pg_iter);
10882 	scf_iter_destroy(exp_inst_iter);
10883 	scf_value_destroy(exp_val);
10884 	scf_property_destroy(exp_prop);
10885 	scf_pg_destroy(exp_pg);
10886 	scf_instance_destroy(exp_inst);
10887 
10888 	xmlFreeDoc(doc);
10889 
10890 	if (f != stdout)
10891 		(void) fclose(f);
10892 
10893 	return (result);
10894 }
10895 
10896 /*
10897  * Get the service named by fmri, build an XML tree which represents it, and
10898  * dump it into filename (or stdout if filename is NULL).
10899  */
10900 int
10901 lscf_service_export(char *fmri, const char *filename, int flags)
10902 {
10903 	struct export_args args;
10904 	char *fmridup;
10905 	const char *scope, *svc, *inst;
10906 	size_t cblen = 3 * max_scf_name_len;
10907 	char *canonbuf = alloca(cblen);
10908 	int ret, err;
10909 
10910 	lscf_prep_hndl();
10911 
10912 	bzero(&args, sizeof (args));
10913 	args.filename = filename;
10914 	args.flags = flags;
10915 
10916 	/*
10917 	 * If some poor user has passed an exact instance FMRI, of the sort
10918 	 * one might cut and paste from svcs(1) or an error message, warn
10919 	 * and chop off the instance instead of failing.
10920 	 */
10921 	fmridup = alloca(strlen(fmri) + 1);
10922 	(void) strcpy(fmridup, fmri);
10923 	if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10924 	    sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10925 	    scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10926 	    inst != NULL) {
10927 		(void) strlcpy(canonbuf, "svc:/", cblen);
10928 		if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10929 			(void) strlcat(canonbuf, "/", cblen);
10930 			(void) strlcat(canonbuf, scope, cblen);
10931 		}
10932 		(void) strlcat(canonbuf, svc, cblen);
10933 		fmri = canonbuf;
10934 
10935 		warn(gettext("Only services may be exported; ignoring "
10936 		    "instance portion of argument.\n"));
10937 	}
10938 
10939 	err = 0;
10940 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10941 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10942 	    &args, &err, semerr)) != 0) {
10943 		if (ret != -1)
10944 			semerr(gettext("Failed to walk instances: %s\n"),
10945 			    scf_strerror(ret));
10946 		return (-1);
10947 	}
10948 
10949 	/*
10950 	 * Error message has already been printed.
10951 	 */
10952 	if (err != 0)
10953 		return (-1);
10954 
10955 	return (0);
10956 }
10957 
10958 
10959 /*
10960  * Archive
10961  */
10962 
10963 static xmlNodePtr
10964 make_archive(int flags)
10965 {
10966 	xmlNodePtr sb;
10967 	scf_scope_t *scope;
10968 	scf_service_t *svc;
10969 	scf_iter_t *iter;
10970 	int r;
10971 
10972 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10973 	    (svc = scf_service_create(g_hndl)) == NULL ||
10974 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10975 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10976 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10977 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10978 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10979 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10980 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10981 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10982 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10983 		scfdie();
10984 
10985 	exp_str_sz = max_scf_len + 1;
10986 	exp_str = safe_malloc(exp_str_sz);
10987 
10988 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10989 	if (sb == NULL)
10990 		uu_die(emsg_create_xml);
10991 	safe_setprop(sb, type_attr, "archive");
10992 	safe_setprop(sb, name_attr, "none");
10993 
10994 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10995 		scfdie();
10996 	if (scf_iter_scope_services(iter, scope) != 0)
10997 		scfdie();
10998 
10999 	for (;;) {
11000 		r = scf_iter_next_service(iter, svc);
11001 		if (r == 0)
11002 			break;
11003 		if (r != 1)
11004 			scfdie();
11005 
11006 		if (scf_service_get_name(svc, exp_str,
11007 		    max_scf_name_len + 1) < 0)
11008 			scfdie();
11009 
11010 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11011 			continue;
11012 
11013 		(void) xmlAddChild(sb, export_service(svc, flags));
11014 	}
11015 
11016 	free(exp_str);
11017 
11018 	scf_iter_destroy(exp_val_iter);
11019 	scf_iter_destroy(exp_prop_iter);
11020 	scf_iter_destroy(exp_pg_iter);
11021 	scf_iter_destroy(exp_inst_iter);
11022 	scf_value_destroy(exp_val);
11023 	scf_property_destroy(exp_prop);
11024 	scf_pg_destroy(exp_pg);
11025 	scf_instance_destroy(exp_inst);
11026 	scf_iter_destroy(iter);
11027 	scf_service_destroy(svc);
11028 	scf_scope_destroy(scope);
11029 
11030 	return (sb);
11031 }
11032 
11033 int
11034 lscf_archive(const char *filename, int flags)
11035 {
11036 	FILE *f;
11037 	xmlDocPtr doc;
11038 	int result;
11039 
11040 	lscf_prep_hndl();
11041 
11042 	if (filename != NULL) {
11043 		errno = 0;
11044 		f = fopen(filename, "wb");
11045 		if (f == NULL) {
11046 			if (errno == 0)
11047 				uu_die(gettext("Could not open \"%s\": no free "
11048 				    "stdio streams.\n"), filename);
11049 			else
11050 				uu_die(gettext("Could not open \"%s\""),
11051 				    filename);
11052 		}
11053 	} else
11054 		f = stdout;
11055 
11056 	doc = xmlNewDoc((xmlChar *)"1.0");
11057 	if (doc == NULL)
11058 		uu_die(gettext("Could not create XML document.\n"));
11059 
11060 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11061 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11062 		uu_die(emsg_create_xml);
11063 
11064 	(void) xmlAddSibling(doc->children, make_archive(flags));
11065 
11066 	result = write_service_bundle(doc, f);
11067 
11068 	xmlFreeDoc(doc);
11069 
11070 	if (f != stdout)
11071 		(void) fclose(f);
11072 
11073 	return (result);
11074 }
11075 
11076 
11077 /*
11078  * "Extract" a profile.
11079  */
11080 int
11081 lscf_profile_extract(const char *filename)
11082 {
11083 	FILE *f;
11084 	xmlDocPtr doc;
11085 	xmlNodePtr sb, snode, inode;
11086 	scf_scope_t *scope;
11087 	scf_service_t *svc;
11088 	scf_instance_t *inst;
11089 	scf_propertygroup_t *pg;
11090 	scf_property_t *prop;
11091 	scf_value_t *val;
11092 	scf_iter_t *siter, *iiter;
11093 	int r, s;
11094 	char *namebuf;
11095 	uint8_t b;
11096 	int result;
11097 
11098 	lscf_prep_hndl();
11099 
11100 	if (filename != NULL) {
11101 		errno = 0;
11102 		f = fopen(filename, "wb");
11103 		if (f == NULL) {
11104 			if (errno == 0)
11105 				uu_die(gettext("Could not open \"%s\": no "
11106 				    "free stdio streams.\n"), filename);
11107 			else
11108 				uu_die(gettext("Could not open \"%s\""),
11109 				    filename);
11110 		}
11111 	} else
11112 		f = stdout;
11113 
11114 	doc = xmlNewDoc((xmlChar *)"1.0");
11115 	if (doc == NULL)
11116 		uu_die(gettext("Could not create XML document.\n"));
11117 
11118 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11119 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11120 		uu_die(emsg_create_xml);
11121 
11122 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11123 	if (sb == NULL)
11124 		uu_die(emsg_create_xml);
11125 	safe_setprop(sb, type_attr, "profile");
11126 	safe_setprop(sb, name_attr, "extract");
11127 	(void) xmlAddSibling(doc->children, sb);
11128 
11129 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
11130 	    (svc = scf_service_create(g_hndl)) == NULL ||
11131 	    (inst = scf_instance_create(g_hndl)) == NULL ||
11132 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11133 	    (prop = scf_property_create(g_hndl)) == NULL ||
11134 	    (val = scf_value_create(g_hndl)) == NULL ||
11135 	    (siter = scf_iter_create(g_hndl)) == NULL ||
11136 	    (iiter = scf_iter_create(g_hndl)) == NULL)
11137 		scfdie();
11138 
11139 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11140 		scfdie();
11141 
11142 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11143 		scfdie();
11144 
11145 	namebuf = safe_malloc(max_scf_name_len + 1);
11146 
11147 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
11148 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11149 			scfdie();
11150 
11151 		snode = xmlNewNode(NULL, (xmlChar *)"service");
11152 		if (snode == NULL)
11153 			uu_die(emsg_create_xml);
11154 
11155 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11156 		    0)
11157 			scfdie();
11158 
11159 		safe_setprop(snode, name_attr, namebuf);
11160 
11161 		safe_setprop(snode, type_attr, "service");
11162 		safe_setprop(snode, "version", "0");
11163 
11164 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11165 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11166 			    SCF_SUCCESS) {
11167 				if (scf_error() != SCF_ERROR_NOT_FOUND)
11168 					scfdie();
11169 
11170 				if (g_verbose) {
11171 					ssize_t len;
11172 					char *fmri;
11173 
11174 					len =
11175 					    scf_instance_to_fmri(inst, NULL, 0);
11176 					if (len < 0)
11177 						scfdie();
11178 
11179 					fmri = safe_malloc(len + 1);
11180 
11181 					if (scf_instance_to_fmri(inst, fmri,
11182 					    len + 1) < 0)
11183 						scfdie();
11184 
11185 					warn("Instance %s has no \"%s\" "
11186 					    "property group.\n", fmri,
11187 					    scf_pg_general);
11188 
11189 					free(fmri);
11190 				}
11191 
11192 				continue;
11193 			}
11194 
11195 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11196 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11197 			    prop_get_val(prop, val) != 0)
11198 				continue;
11199 
11200 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11201 			    NULL);
11202 			if (inode == NULL)
11203 				uu_die(emsg_create_xml);
11204 
11205 			if (scf_instance_get_name(inst, namebuf,
11206 			    max_scf_name_len + 1) < 0)
11207 				scfdie();
11208 
11209 			safe_setprop(inode, name_attr, namebuf);
11210 
11211 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11212 				scfdie();
11213 
11214 			safe_setprop(inode, enabled_attr, b ? true : false);
11215 		}
11216 		if (s < 0)
11217 			scfdie();
11218 
11219 		if (snode->children != NULL)
11220 			(void) xmlAddChild(sb, snode);
11221 		else
11222 			xmlFreeNode(snode);
11223 	}
11224 	if (r < 0)
11225 		scfdie();
11226 
11227 	free(namebuf);
11228 
11229 	result = write_service_bundle(doc, f);
11230 
11231 	xmlFreeDoc(doc);
11232 
11233 	if (f != stdout)
11234 		(void) fclose(f);
11235 
11236 	return (result);
11237 }
11238 
11239 
11240 /*
11241  * Entity manipulation commands
11242  */
11243 
11244 /*
11245  * Entity selection.  If no entity is selected, then the current scope is in
11246  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11247  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11248  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11249  * cur_inst will be non-NULL.
11250  */
11251 
11252 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11253 static int
11254 select_inst(const char *name)
11255 {
11256 	scf_instance_t *inst;
11257 	scf_error_t err;
11258 
11259 	assert(cur_svc != NULL);
11260 
11261 	inst = scf_instance_create(g_hndl);
11262 	if (inst == NULL)
11263 		scfdie();
11264 
11265 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11266 		cur_inst = inst;
11267 		return (0);
11268 	}
11269 
11270 	err = scf_error();
11271 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11272 		scfdie();
11273 
11274 	scf_instance_destroy(inst);
11275 	return (1);
11276 }
11277 
11278 /* Returns as above. */
11279 static int
11280 select_svc(const char *name)
11281 {
11282 	scf_service_t *svc;
11283 	scf_error_t err;
11284 
11285 	assert(cur_scope != NULL);
11286 
11287 	svc = scf_service_create(g_hndl);
11288 	if (svc == NULL)
11289 		scfdie();
11290 
11291 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11292 		cur_svc = svc;
11293 		return (0);
11294 	}
11295 
11296 	err = scf_error();
11297 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11298 		scfdie();
11299 
11300 	scf_service_destroy(svc);
11301 	return (1);
11302 }
11303 
11304 /* ARGSUSED */
11305 static int
11306 select_callback(void *unused, scf_walkinfo_t *wip)
11307 {
11308 	scf_instance_t *inst;
11309 	scf_service_t *svc;
11310 	scf_scope_t *scope;
11311 
11312 	if (wip->inst != NULL) {
11313 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11314 		    (svc = scf_service_create(g_hndl)) == NULL ||
11315 		    (inst = scf_instance_create(g_hndl)) == NULL)
11316 			scfdie();
11317 
11318 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11319 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11320 			scfdie();
11321 	} else {
11322 		assert(wip->svc != NULL);
11323 
11324 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11325 		    (svc = scf_service_create(g_hndl)) == NULL)
11326 			scfdie();
11327 
11328 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11329 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11330 			scfdie();
11331 
11332 		inst = NULL;
11333 	}
11334 
11335 	/* Clear out the current selection */
11336 	assert(cur_scope != NULL);
11337 	scf_scope_destroy(cur_scope);
11338 	scf_service_destroy(cur_svc);
11339 	scf_instance_destroy(cur_inst);
11340 
11341 	cur_scope = scope;
11342 	cur_svc = svc;
11343 	cur_inst = inst;
11344 
11345 	return (0);
11346 }
11347 
11348 static int
11349 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11350 {
11351 	char **fmri = fmri_p;
11352 
11353 	*fmri = strdup(wip->fmri);
11354 	if (*fmri == NULL)
11355 		uu_die(gettext("Out of memory.\n"));
11356 
11357 	return (0);
11358 }
11359 
11360 /*
11361  * validate [fmri]
11362  * Perform the validation of an FMRI instance.
11363  */
11364 void
11365 lscf_validate_fmri(const char *fmri)
11366 {
11367 	int ret = 0;
11368 	size_t inst_sz;
11369 	char *inst_fmri = NULL;
11370 	scf_tmpl_errors_t *errs = NULL;
11371 	char *snapbuf = NULL;
11372 
11373 	lscf_prep_hndl();
11374 
11375 	if (fmri == NULL) {
11376 		inst_sz = max_scf_fmri_len + 1;
11377 		inst_fmri = safe_malloc(inst_sz);
11378 
11379 		if (cur_snap != NULL) {
11380 			snapbuf = safe_malloc(max_scf_name_len + 1);
11381 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11382 			    max_scf_name_len + 1) < 0)
11383 				scfdie();
11384 		}
11385 		if (cur_inst == NULL) {
11386 			semerr(gettext("No instance selected\n"));
11387 			goto cleanup;
11388 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11389 		    inst_sz) >= inst_sz) {
11390 			/* sanity check. Should never get here */
11391 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11392 			    __FILE__, __LINE__);
11393 		}
11394 	} else {
11395 		scf_error_t scf_err;
11396 		int err = 0;
11397 
11398 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11399 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11400 			uu_warn("Failed to walk instances: %s\n",
11401 			    scf_strerror(scf_err));
11402 			goto cleanup;
11403 		}
11404 		if (err != 0) {
11405 			/* error message displayed by scf_walk_fmri */
11406 			goto cleanup;
11407 		}
11408 	}
11409 
11410 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11411 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11412 	if (ret == -1) {
11413 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11414 			warn(gettext("Template data for %s is invalid. "
11415 			    "Consider reverting to a previous snapshot or "
11416 			    "restoring original configuration.\n"), inst_fmri);
11417 		} else {
11418 			uu_warn("%s: %s\n",
11419 			    gettext("Error validating the instance"),
11420 			    scf_strerror(scf_error()));
11421 		}
11422 	} else if (ret == 1 && errs != NULL) {
11423 		scf_tmpl_error_t *err = NULL;
11424 		char *msg;
11425 		size_t len = 256;	/* initial error buffer size */
11426 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11427 		    SCF_TMPL_STRERROR_HUMAN : 0;
11428 
11429 		msg = safe_malloc(len);
11430 
11431 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11432 			int ret;
11433 
11434 			if ((ret = scf_tmpl_strerror(err, msg, len,
11435 			    flag)) >= len) {
11436 				len = ret + 1;
11437 				msg = realloc(msg, len);
11438 				if (msg == NULL)
11439 					uu_die(gettext(
11440 					    "Out of memory.\n"));
11441 				(void) scf_tmpl_strerror(err, msg, len,
11442 				    flag);
11443 			}
11444 			(void) fprintf(stderr, "%s\n", msg);
11445 		}
11446 		if (msg != NULL)
11447 			free(msg);
11448 	}
11449 	if (errs != NULL)
11450 		scf_tmpl_errors_destroy(errs);
11451 
11452 cleanup:
11453 	free(inst_fmri);
11454 	free(snapbuf);
11455 }
11456 
11457 static void
11458 lscf_validate_file(const char *filename)
11459 {
11460 	tmpl_errors_t *errs;
11461 
11462 	bundle_t *b = internal_bundle_new();
11463 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11464 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11465 			tmpl_errors_print(stderr, errs, "");
11466 			semerr(gettext("Validation failed.\n"));
11467 		}
11468 		tmpl_errors_destroy(errs);
11469 	}
11470 	(void) internal_bundle_free(b);
11471 }
11472 
11473 /*
11474  * validate [fmri|file]
11475  */
11476 void
11477 lscf_validate(const char *arg)
11478 {
11479 	const char *str;
11480 
11481 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11482 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11483 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11484 		lscf_validate_file(str);
11485 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11486 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11487 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11488 		lscf_validate_fmri(str);
11489 	} else if (access(arg, R_OK | F_OK) == 0) {
11490 		lscf_validate_file(arg);
11491 	} else {
11492 		lscf_validate_fmri(arg);
11493 	}
11494 }
11495 
11496 void
11497 lscf_select(const char *fmri)
11498 {
11499 	int ret, err;
11500 
11501 	lscf_prep_hndl();
11502 
11503 	if (cur_snap != NULL) {
11504 		struct snaplevel *elt;
11505 		char *buf;
11506 
11507 		/* Error unless name is that of the next level. */
11508 		elt = uu_list_next(cur_levels, cur_elt);
11509 		if (elt == NULL) {
11510 			semerr(gettext("No children.\n"));
11511 			return;
11512 		}
11513 
11514 		buf = safe_malloc(max_scf_name_len + 1);
11515 
11516 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11517 		    max_scf_name_len + 1) < 0)
11518 			scfdie();
11519 
11520 		if (strcmp(buf, fmri) != 0) {
11521 			semerr(gettext("No such child.\n"));
11522 			free(buf);
11523 			return;
11524 		}
11525 
11526 		free(buf);
11527 
11528 		cur_elt = elt;
11529 		cur_level = elt->sl;
11530 		return;
11531 	}
11532 
11533 	/*
11534 	 * Special case for 'svc:', which takes the user to the scope level.
11535 	 */
11536 	if (strcmp(fmri, "svc:") == 0) {
11537 		scf_instance_destroy(cur_inst);
11538 		scf_service_destroy(cur_svc);
11539 		cur_inst = NULL;
11540 		cur_svc = NULL;
11541 		return;
11542 	}
11543 
11544 	/*
11545 	 * Special case for ':properties'.  This appears as part of 'list' but
11546 	 * can't be selected.  Give a more helpful error message in this case.
11547 	 */
11548 	if (strcmp(fmri, ":properties") == 0) {
11549 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11550 		    "to list properties.\n"));
11551 		return;
11552 	}
11553 
11554 	/*
11555 	 * First try the argument as relative to the current selection.
11556 	 */
11557 	if (cur_inst != NULL) {
11558 		/* EMPTY */;
11559 	} else if (cur_svc != NULL) {
11560 		if (select_inst(fmri) != 1)
11561 			return;
11562 	} else {
11563 		if (select_svc(fmri) != 1)
11564 			return;
11565 	}
11566 
11567 	err = 0;
11568 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11569 	    select_callback, NULL, &err, semerr)) != 0) {
11570 		semerr(gettext("Failed to walk instances: %s\n"),
11571 		    scf_strerror(ret));
11572 	}
11573 }
11574 
11575 void
11576 lscf_unselect(void)
11577 {
11578 	lscf_prep_hndl();
11579 
11580 	if (cur_snap != NULL) {
11581 		struct snaplevel *elt;
11582 
11583 		elt = uu_list_prev(cur_levels, cur_elt);
11584 		if (elt == NULL) {
11585 			semerr(gettext("No parent levels.\n"));
11586 		} else {
11587 			cur_elt = elt;
11588 			cur_level = elt->sl;
11589 		}
11590 	} else if (cur_inst != NULL) {
11591 		scf_instance_destroy(cur_inst);
11592 		cur_inst = NULL;
11593 	} else if (cur_svc != NULL) {
11594 		scf_service_destroy(cur_svc);
11595 		cur_svc = NULL;
11596 	} else {
11597 		semerr(gettext("Cannot unselect at scope level.\n"));
11598 	}
11599 }
11600 
11601 /*
11602  * Return the FMRI of the current selection, for the prompt.
11603  */
11604 void
11605 lscf_get_selection_str(char *buf, size_t bufsz)
11606 {
11607 	char *cp;
11608 	ssize_t fmrilen, szret;
11609 	boolean_t deleted = B_FALSE;
11610 
11611 	if (g_hndl == NULL) {
11612 		(void) strlcpy(buf, "svc:", bufsz);
11613 		return;
11614 	}
11615 
11616 	if (cur_level != NULL) {
11617 		assert(cur_snap != NULL);
11618 
11619 		/* [ snapshot ] FMRI [: instance ] */
11620 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11621 		    + 2 + max_scf_name_len + 1 + 1);
11622 
11623 		buf[0] = '[';
11624 
11625 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11626 		    max_scf_name_len + 1);
11627 		if (szret < 0) {
11628 			if (scf_error() != SCF_ERROR_DELETED)
11629 				scfdie();
11630 
11631 			goto snap_deleted;
11632 		}
11633 
11634 		(void) strcat(buf, "]svc:/");
11635 
11636 		cp = strchr(buf, '\0');
11637 
11638 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11639 		    max_scf_name_len + 1);
11640 		if (szret < 0) {
11641 			if (scf_error() != SCF_ERROR_DELETED)
11642 				scfdie();
11643 
11644 			goto snap_deleted;
11645 		}
11646 
11647 		cp = strchr(cp, '\0');
11648 
11649 		if (snaplevel_is_instance(cur_level)) {
11650 			*cp++ = ':';
11651 
11652 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11653 			    max_scf_name_len + 1) < 0) {
11654 				if (scf_error() != SCF_ERROR_DELETED)
11655 					scfdie();
11656 
11657 				goto snap_deleted;
11658 			}
11659 		} else {
11660 			*cp++ = '[';
11661 			*cp++ = ':';
11662 
11663 			if (scf_instance_get_name(cur_inst, cp,
11664 			    max_scf_name_len + 1) < 0) {
11665 				if (scf_error() != SCF_ERROR_DELETED)
11666 					scfdie();
11667 
11668 				goto snap_deleted;
11669 			}
11670 
11671 			(void) strcat(buf, "]");
11672 		}
11673 
11674 		return;
11675 
11676 snap_deleted:
11677 		deleted = B_TRUE;
11678 		free(buf);
11679 		unselect_cursnap();
11680 	}
11681 
11682 	assert(cur_snap == NULL);
11683 
11684 	if (cur_inst != NULL) {
11685 		assert(cur_svc != NULL);
11686 		assert(cur_scope != NULL);
11687 
11688 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11689 		if (fmrilen >= 0) {
11690 			assert(fmrilen < bufsz);
11691 			if (deleted)
11692 				warn(emsg_deleted);
11693 			return;
11694 		}
11695 
11696 		if (scf_error() != SCF_ERROR_DELETED)
11697 			scfdie();
11698 
11699 		deleted = B_TRUE;
11700 
11701 		scf_instance_destroy(cur_inst);
11702 		cur_inst = NULL;
11703 	}
11704 
11705 	if (cur_svc != NULL) {
11706 		assert(cur_scope != NULL);
11707 
11708 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11709 		if (szret >= 0) {
11710 			assert(szret < bufsz);
11711 			if (deleted)
11712 				warn(emsg_deleted);
11713 			return;
11714 		}
11715 
11716 		if (scf_error() != SCF_ERROR_DELETED)
11717 			scfdie();
11718 
11719 		deleted = B_TRUE;
11720 		scf_service_destroy(cur_svc);
11721 		cur_svc = NULL;
11722 	}
11723 
11724 	assert(cur_scope != NULL);
11725 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11726 
11727 	if (fmrilen < 0)
11728 		scfdie();
11729 
11730 	assert(fmrilen < bufsz);
11731 	if (deleted)
11732 		warn(emsg_deleted);
11733 }
11734 
11735 /*
11736  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11737  * :statistics) are listed for the current selection.
11738  */
11739 void
11740 lscf_list(const char *pattern)
11741 {
11742 	scf_iter_t *iter;
11743 	char *buf;
11744 	int ret;
11745 
11746 	lscf_prep_hndl();
11747 
11748 	if (cur_level != NULL) {
11749 		struct snaplevel *elt;
11750 
11751 		(void) fputs(COLON_NAMESPACES, stdout);
11752 
11753 		elt = uu_list_next(cur_levels, cur_elt);
11754 		if (elt == NULL)
11755 			return;
11756 
11757 		/*
11758 		 * For now, we know that the next level is an instance.  But
11759 		 * if we ever have multiple scopes, this could be complicated.
11760 		 */
11761 		buf = safe_malloc(max_scf_name_len + 1);
11762 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11763 		    max_scf_name_len + 1) >= 0) {
11764 			(void) puts(buf);
11765 		} else {
11766 			if (scf_error() != SCF_ERROR_DELETED)
11767 				scfdie();
11768 		}
11769 
11770 		free(buf);
11771 
11772 		return;
11773 	}
11774 
11775 	if (cur_inst != NULL) {
11776 		(void) fputs(COLON_NAMESPACES, stdout);
11777 		return;
11778 	}
11779 
11780 	iter = scf_iter_create(g_hndl);
11781 	if (iter == NULL)
11782 		scfdie();
11783 
11784 	buf = safe_malloc(max_scf_name_len + 1);
11785 
11786 	if (cur_svc != NULL) {
11787 		/* List the instances in this service. */
11788 		scf_instance_t *inst;
11789 
11790 		inst = scf_instance_create(g_hndl);
11791 		if (inst == NULL)
11792 			scfdie();
11793 
11794 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11795 			safe_printf(COLON_NAMESPACES);
11796 
11797 			for (;;) {
11798 				ret = scf_iter_next_instance(iter, inst);
11799 				if (ret == 0)
11800 					break;
11801 				if (ret != 1) {
11802 					if (scf_error() != SCF_ERROR_DELETED)
11803 						scfdie();
11804 
11805 					break;
11806 				}
11807 
11808 				if (scf_instance_get_name(inst, buf,
11809 				    max_scf_name_len + 1) >= 0) {
11810 					if (pattern == NULL ||
11811 					    fnmatch(pattern, buf, 0) == 0)
11812 						(void) puts(buf);
11813 				} else {
11814 					if (scf_error() != SCF_ERROR_DELETED)
11815 						scfdie();
11816 				}
11817 			}
11818 		} else {
11819 			if (scf_error() != SCF_ERROR_DELETED)
11820 				scfdie();
11821 		}
11822 
11823 		scf_instance_destroy(inst);
11824 	} else {
11825 		/* List the services in this scope. */
11826 		scf_service_t *svc;
11827 
11828 		assert(cur_scope != NULL);
11829 
11830 		svc = scf_service_create(g_hndl);
11831 		if (svc == NULL)
11832 			scfdie();
11833 
11834 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11835 			scfdie();
11836 
11837 		for (;;) {
11838 			ret = scf_iter_next_service(iter, svc);
11839 			if (ret == 0)
11840 				break;
11841 			if (ret != 1)
11842 				scfdie();
11843 
11844 			if (scf_service_get_name(svc, buf,
11845 			    max_scf_name_len + 1) >= 0) {
11846 				if (pattern == NULL ||
11847 				    fnmatch(pattern, buf, 0) == 0)
11848 					safe_printf("%s\n", buf);
11849 			} else {
11850 				if (scf_error() != SCF_ERROR_DELETED)
11851 					scfdie();
11852 			}
11853 		}
11854 
11855 		scf_service_destroy(svc);
11856 	}
11857 
11858 	free(buf);
11859 	scf_iter_destroy(iter);
11860 }
11861 
11862 /*
11863  * Entity addition.  Creates an empty entity in the current selection.
11864  */
11865 void
11866 lscf_add(const char *name)
11867 {
11868 	lscf_prep_hndl();
11869 
11870 	if (cur_snap != NULL) {
11871 		semerr(emsg_cant_modify_snapshots);
11872 	} else if (cur_inst != NULL) {
11873 		semerr(gettext("Cannot add entities to an instance.\n"));
11874 	} else if (cur_svc != NULL) {
11875 
11876 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11877 		    SCF_SUCCESS) {
11878 			switch (scf_error()) {
11879 			case SCF_ERROR_INVALID_ARGUMENT:
11880 				semerr(gettext("Invalid name.\n"));
11881 				break;
11882 
11883 			case SCF_ERROR_EXISTS:
11884 				semerr(gettext("Instance already exists.\n"));
11885 				break;
11886 
11887 			case SCF_ERROR_PERMISSION_DENIED:
11888 				semerr(emsg_permission_denied);
11889 				break;
11890 
11891 			default:
11892 				scfdie();
11893 			}
11894 		}
11895 	} else {
11896 		assert(cur_scope != NULL);
11897 
11898 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11899 		    SCF_SUCCESS) {
11900 			switch (scf_error()) {
11901 			case SCF_ERROR_INVALID_ARGUMENT:
11902 				semerr(gettext("Invalid name.\n"));
11903 				break;
11904 
11905 			case SCF_ERROR_EXISTS:
11906 				semerr(gettext("Service already exists.\n"));
11907 				break;
11908 
11909 			case SCF_ERROR_PERMISSION_DENIED:
11910 				semerr(emsg_permission_denied);
11911 				break;
11912 
11913 			case SCF_ERROR_BACKEND_READONLY:
11914 				semerr(emsg_read_only);
11915 				break;
11916 
11917 			default:
11918 				scfdie();
11919 			}
11920 		}
11921 	}
11922 }
11923 
11924 /* return 1 if the entity has no persistent pgs, else return 0 */
11925 static int
11926 entity_has_no_pgs(void *ent, int isservice)
11927 {
11928 	scf_iter_t *iter = NULL;
11929 	scf_propertygroup_t *pg = NULL;
11930 	uint32_t flags;
11931 	int err;
11932 	int ret = 1;
11933 
11934 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11935 	    (pg = scf_pg_create(g_hndl)) == NULL)
11936 		scfdie();
11937 
11938 	if (isservice) {
11939 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11940 			scfdie();
11941 	} else {
11942 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11943 			scfdie();
11944 	}
11945 
11946 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11947 		if (scf_pg_get_flags(pg, &flags) != 0)
11948 			scfdie();
11949 
11950 		/* skip nonpersistent pgs */
11951 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11952 			continue;
11953 
11954 		ret = 0;
11955 		break;
11956 	}
11957 
11958 	if (err == -1)
11959 		scfdie();
11960 
11961 	scf_pg_destroy(pg);
11962 	scf_iter_destroy(iter);
11963 
11964 	return (ret);
11965 }
11966 
11967 /* return 1 if the service has no instances, else return 0 */
11968 static int
11969 svc_has_no_insts(scf_service_t *svc)
11970 {
11971 	scf_instance_t *inst;
11972 	scf_iter_t *iter;
11973 	int r;
11974 	int ret = 1;
11975 
11976 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11977 	    (iter = scf_iter_create(g_hndl)) == NULL)
11978 		scfdie();
11979 
11980 	if (scf_iter_service_instances(iter, svc) != 0)
11981 		scfdie();
11982 
11983 	r = scf_iter_next_instance(iter, inst);
11984 	if (r == 1) {
11985 		ret = 0;
11986 	} else if (r == 0) {
11987 		ret = 1;
11988 	} else if (r == -1) {
11989 		scfdie();
11990 	} else {
11991 		bad_error("scf_iter_next_instance", r);
11992 	}
11993 
11994 	scf_iter_destroy(iter);
11995 	scf_instance_destroy(inst);
11996 
11997 	return (ret);
11998 }
11999 
12000 /*
12001  * Entity deletion.
12002  */
12003 
12004 /*
12005  * Delete the property group <fmri>/:properties/<name>.  Returns
12006  * SCF_ERROR_NONE on success (or if the entity is not found),
12007  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12008  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12009  * denied.
12010  */
12011 static scf_error_t
12012 delete_dependency_pg(const char *fmri, const char *name)
12013 {
12014 	void *entity = NULL;
12015 	int isservice;
12016 	scf_propertygroup_t *pg = NULL;
12017 	scf_error_t result;
12018 	char *pgty;
12019 	scf_service_t *svc = NULL;
12020 	scf_instance_t *inst = NULL;
12021 	scf_iter_t *iter = NULL;
12022 	char *name_buf = NULL;
12023 
12024 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12025 	switch (result) {
12026 	case SCF_ERROR_NONE:
12027 		break;
12028 
12029 	case SCF_ERROR_NO_MEMORY:
12030 		uu_die(gettext("Out of memory.\n"));
12031 		/* NOTREACHED */
12032 
12033 	case SCF_ERROR_INVALID_ARGUMENT:
12034 	case SCF_ERROR_CONSTRAINT_VIOLATED:
12035 		return (SCF_ERROR_INVALID_ARGUMENT);
12036 
12037 	case SCF_ERROR_NOT_FOUND:
12038 		result = SCF_ERROR_NONE;
12039 		goto out;
12040 
12041 	default:
12042 		bad_error("fmri_to_entity", result);
12043 	}
12044 
12045 	pg = scf_pg_create(g_hndl);
12046 	if (pg == NULL)
12047 		scfdie();
12048 
12049 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
12050 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12051 			scfdie();
12052 
12053 		result = SCF_ERROR_NONE;
12054 		goto out;
12055 	}
12056 
12057 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12058 
12059 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12060 		scfdie();
12061 
12062 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12063 		result = SCF_ERROR_TYPE_MISMATCH;
12064 		free(pgty);
12065 		goto out;
12066 	}
12067 
12068 	free(pgty);
12069 
12070 	if (scf_pg_delete(pg) != 0) {
12071 		result = scf_error();
12072 		if (result != SCF_ERROR_PERMISSION_DENIED)
12073 			scfdie();
12074 		goto out;
12075 	}
12076 
12077 	/*
12078 	 * We have to handle the case where we've just deleted the last
12079 	 * property group of a "dummy" entity (instance or service).
12080 	 * A "dummy" entity is an entity only present to hold an
12081 	 * external dependency.
12082 	 * So, in the case we deleted the last property group then we
12083 	 * can also delete the entity. If the entity is an instance then
12084 	 * we must verify if this was the last instance for the service
12085 	 * and if it is, we can also delete the service if it doesn't
12086 	 * have any property group either.
12087 	 */
12088 
12089 	result = SCF_ERROR_NONE;
12090 
12091 	if (isservice) {
12092 		svc = (scf_service_t *)entity;
12093 
12094 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
12095 		    (iter = scf_iter_create(g_hndl)) == NULL)
12096 			scfdie();
12097 
12098 		name_buf = safe_malloc(max_scf_name_len + 1);
12099 	} else {
12100 		inst = (scf_instance_t *)entity;
12101 	}
12102 
12103 	/*
12104 	 * If the entity is an instance and we've just deleted its last
12105 	 * property group then we should delete it.
12106 	 */
12107 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
12108 		/* find the service before deleting the inst. - needed later */
12109 		if ((svc = scf_service_create(g_hndl)) == NULL)
12110 			scfdie();
12111 
12112 		if (scf_instance_get_parent(inst, svc) != 0)
12113 			scfdie();
12114 
12115 		/* delete the instance */
12116 		if (scf_instance_delete(inst) != 0) {
12117 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12118 				scfdie();
12119 
12120 			result = SCF_ERROR_PERMISSION_DENIED;
12121 			goto out;
12122 		}
12123 		/* no need to refresh the instance */
12124 		inst = NULL;
12125 	}
12126 
12127 	/*
12128 	 * If the service has no more instances and pgs or we just deleted the
12129 	 * last instance and the service doesn't have anymore propery groups
12130 	 * then the service should be deleted.
12131 	 */
12132 	if (svc != NULL &&
12133 	    svc_has_no_insts(svc) &&
12134 	    entity_has_no_pgs((void *)svc, 1)) {
12135 		if (scf_service_delete(svc) == 0) {
12136 			if (isservice) {
12137 				/* no need to refresh the service */
12138 				svc = NULL;
12139 			}
12140 
12141 			goto out;
12142 		}
12143 
12144 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12145 			scfdie();
12146 
12147 		result = SCF_ERROR_PERMISSION_DENIED;
12148 	}
12149 
12150 	/* if the entity has not been deleted, refresh it */
12151 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12152 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
12153 		    name_buf);
12154 	}
12155 
12156 out:
12157 	if (isservice && (inst != NULL && iter != NULL)) {
12158 		free(name_buf);
12159 		scf_iter_destroy(iter);
12160 		scf_instance_destroy(inst);
12161 	}
12162 
12163 	if (!isservice && svc != NULL) {
12164 		scf_service_destroy(svc);
12165 	}
12166 
12167 	scf_pg_destroy(pg);
12168 	if (entity != NULL)
12169 		entity_destroy(entity, isservice);
12170 
12171 	return (result);
12172 }
12173 
12174 static int
12175 delete_dependents(scf_propertygroup_t *pg)
12176 {
12177 	char *pgty, *name, *fmri;
12178 	scf_property_t *prop;
12179 	scf_value_t *val;
12180 	scf_iter_t *iter;
12181 	int r;
12182 	scf_error_t err;
12183 
12184 	/* Verify that the pg has the correct type. */
12185 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12186 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12187 		scfdie();
12188 
12189 	if (strcmp(pgty, scf_group_framework) != 0) {
12190 		if (g_verbose) {
12191 			fmri = safe_malloc(max_scf_fmri_len + 1);
12192 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12193 				scfdie();
12194 
12195 			warn(gettext("Property group %s is not of expected "
12196 			    "type %s.\n"), fmri, scf_group_framework);
12197 
12198 			free(fmri);
12199 		}
12200 
12201 		free(pgty);
12202 		return (-1);
12203 	}
12204 
12205 	free(pgty);
12206 
12207 	/* map delete_dependency_pg onto the properties. */
12208 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12209 	    (val = scf_value_create(g_hndl)) == NULL ||
12210 	    (iter = scf_iter_create(g_hndl)) == NULL)
12211 		scfdie();
12212 
12213 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12214 		scfdie();
12215 
12216 	name = safe_malloc(max_scf_name_len + 1);
12217 	fmri = safe_malloc(max_scf_fmri_len + 2);
12218 
12219 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
12220 		scf_type_t ty;
12221 
12222 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12223 			scfdie();
12224 
12225 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12226 			scfdie();
12227 
12228 		if ((ty != SCF_TYPE_ASTRING &&
12229 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12230 		    prop_get_val(prop, val) != 0)
12231 			continue;
12232 
12233 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12234 			scfdie();
12235 
12236 		err = delete_dependency_pg(fmri, name);
12237 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12238 			if (scf_property_to_fmri(prop, fmri,
12239 			    max_scf_fmri_len + 2) < 0)
12240 				scfdie();
12241 
12242 			warn(gettext("Value of %s is not a valid FMRI.\n"),
12243 			    fmri);
12244 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12245 			warn(gettext("Property group \"%s\" of entity \"%s\" "
12246 			    "does not have dependency type.\n"), name, fmri);
12247 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12248 			warn(gettext("Could not delete property group \"%s\" "
12249 			    "of entity \"%s\" (permission denied).\n"), name,
12250 			    fmri);
12251 		}
12252 	}
12253 	if (r == -1)
12254 		scfdie();
12255 
12256 	scf_value_destroy(val);
12257 	scf_property_destroy(prop);
12258 
12259 	return (0);
12260 }
12261 
12262 /*
12263  * Returns 1 if the instance may be running, and 0 otherwise.
12264  */
12265 static int
12266 inst_is_running(scf_instance_t *inst)
12267 {
12268 	scf_propertygroup_t *pg;
12269 	scf_property_t *prop;
12270 	scf_value_t *val;
12271 	char buf[MAX_SCF_STATE_STRING_SZ];
12272 	int ret = 0;
12273 	ssize_t szret;
12274 
12275 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12276 	    (prop = scf_property_create(g_hndl)) == NULL ||
12277 	    (val = scf_value_create(g_hndl)) == NULL)
12278 		scfdie();
12279 
12280 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12281 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12282 			scfdie();
12283 		goto out;
12284 	}
12285 
12286 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12287 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12288 	    prop_get_val(prop, val) != 0)
12289 		goto out;
12290 
12291 	szret = scf_value_get_astring(val, buf, sizeof (buf));
12292 	assert(szret >= 0);
12293 
12294 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12295 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12296 
12297 out:
12298 	scf_value_destroy(val);
12299 	scf_property_destroy(prop);
12300 	scf_pg_destroy(pg);
12301 	return (ret);
12302 }
12303 
12304 static uint8_t
12305 pg_is_external_dependency(scf_propertygroup_t *pg)
12306 {
12307 	char *type;
12308 	scf_value_t *val;
12309 	scf_property_t *prop;
12310 	uint8_t b = B_FALSE;
12311 
12312 	type = safe_malloc(max_scf_pg_type_len + 1);
12313 
12314 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12315 		scfdie();
12316 
12317 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12318 	    (val = scf_value_create(g_hndl)) == NULL)
12319 		scfdie();
12320 
12321 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12322 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12323 			if (scf_property_get_value(prop, val) != 0)
12324 				scfdie();
12325 			if (scf_value_get_boolean(val, &b) != 0)
12326 				scfdie();
12327 		}
12328 	}
12329 
12330 	free(type);
12331 	(void) scf_value_destroy(val);
12332 	(void) scf_property_destroy(prop);
12333 
12334 	return (b);
12335 }
12336 
12337 #define	DELETE_FAILURE			-1
12338 #define	DELETE_SUCCESS_NOEXTDEPS	0
12339 #define	DELETE_SUCCESS_EXTDEPS		1
12340 
12341 /*
12342  * lscf_instance_delete() deletes an instance.  Before calling
12343  * scf_instance_delete(), though, we make sure the instance isn't
12344  * running and delete dependencies in other entities which the instance
12345  * declared as "dependents".  If there are dependencies which were
12346  * created for other entities, then instead of deleting the instance we
12347  * make it "empty" by deleting all other property groups and all
12348  * snapshots.
12349  *
12350  * lscf_instance_delete() verifies that there is no external dependency pgs
12351  * before suppressing the instance. If there is, then we must not remove them
12352  * now in case the instance is re-created otherwise the dependencies would be
12353  * lost. The external dependency pgs will be removed if the dependencies are
12354  * removed.
12355  *
12356  * Returns:
12357  *  DELETE_FAILURE		on failure
12358  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12359  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12360  */
12361 static int
12362 lscf_instance_delete(scf_instance_t *inst, int force)
12363 {
12364 	scf_propertygroup_t *pg;
12365 	scf_snapshot_t *snap;
12366 	scf_iter_t *iter;
12367 	int err;
12368 	int external = 0;
12369 
12370 	/* If we're not forcing and the instance is running, refuse. */
12371 	if (!force && inst_is_running(inst)) {
12372 		char *fmri;
12373 
12374 		fmri = safe_malloc(max_scf_fmri_len + 1);
12375 
12376 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12377 			scfdie();
12378 
12379 		semerr(gettext("Instance %s may be running.  "
12380 		    "Use delete -f if it is not.\n"), fmri);
12381 
12382 		free(fmri);
12383 		return (DELETE_FAILURE);
12384 	}
12385 
12386 	pg = scf_pg_create(g_hndl);
12387 	if (pg == NULL)
12388 		scfdie();
12389 
12390 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12391 		(void) delete_dependents(pg);
12392 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12393 		scfdie();
12394 
12395 	scf_pg_destroy(pg);
12396 
12397 	/*
12398 	 * If the instance has some external dependencies then we must
12399 	 * keep them in case the instance is reimported otherwise the
12400 	 * dependencies would be lost on reimport.
12401 	 */
12402 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12403 	    (pg = scf_pg_create(g_hndl)) == NULL)
12404 		scfdie();
12405 
12406 	if (scf_iter_instance_pgs(iter, inst) < 0)
12407 		scfdie();
12408 
12409 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12410 		if (pg_is_external_dependency(pg)) {
12411 			external = 1;
12412 			continue;
12413 		}
12414 
12415 		if (scf_pg_delete(pg) != 0) {
12416 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12417 				scfdie();
12418 			else {
12419 				semerr(emsg_permission_denied);
12420 
12421 				(void) scf_iter_destroy(iter);
12422 				(void) scf_pg_destroy(pg);
12423 				return (DELETE_FAILURE);
12424 			}
12425 		}
12426 	}
12427 
12428 	if (err == -1)
12429 		scfdie();
12430 
12431 	(void) scf_iter_destroy(iter);
12432 	(void) scf_pg_destroy(pg);
12433 
12434 	if (external) {
12435 		/*
12436 		 * All the pgs have been deleted for the instance except
12437 		 * the ones holding the external dependencies.
12438 		 * For the job to be complete, we must also delete the
12439 		 * snapshots associated with the instance.
12440 		 */
12441 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12442 		    NULL)
12443 			scfdie();
12444 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12445 			scfdie();
12446 
12447 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12448 			scfdie();
12449 
12450 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12451 			if (_scf_snapshot_delete(snap) != 0) {
12452 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12453 					scfdie();
12454 
12455 				semerr(emsg_permission_denied);
12456 
12457 				(void) scf_iter_destroy(iter);
12458 				(void) scf_snapshot_destroy(snap);
12459 				return (DELETE_FAILURE);
12460 			}
12461 		}
12462 
12463 		if (err == -1)
12464 			scfdie();
12465 
12466 		(void) scf_iter_destroy(iter);
12467 		(void) scf_snapshot_destroy(snap);
12468 		return (DELETE_SUCCESS_EXTDEPS);
12469 	}
12470 
12471 	if (scf_instance_delete(inst) != 0) {
12472 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12473 			scfdie();
12474 
12475 		semerr(emsg_permission_denied);
12476 
12477 		return (DELETE_FAILURE);
12478 	}
12479 
12480 	return (DELETE_SUCCESS_NOEXTDEPS);
12481 }
12482 
12483 /*
12484  * lscf_service_delete() deletes a service.  Before calling
12485  * scf_service_delete(), though, we call lscf_instance_delete() for
12486  * each of the instances and delete dependencies in other entities
12487  * which were created as "dependents" of this service.  If there are
12488  * dependencies which were created for other entities, then we delete
12489  * all other property groups in the service and leave it as "empty".
12490  *
12491  * lscf_service_delete() verifies that there is no external dependency
12492  * pgs at the instance & service level before suppressing the service.
12493  * If there is, then we must not remove them now in case the service
12494  * is re-imported otherwise the dependencies would be lost. The external
12495  * dependency pgs will be removed if the dependencies are removed.
12496  *
12497  * Returns:
12498  *   DELETE_FAILURE		on failure
12499  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12500  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12501  */
12502 static int
12503 lscf_service_delete(scf_service_t *svc, int force)
12504 {
12505 	int r;
12506 	scf_instance_t *inst;
12507 	scf_propertygroup_t *pg;
12508 	scf_iter_t *iter;
12509 	int ret;
12510 	int external = 0;
12511 
12512 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12513 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12514 	    (iter = scf_iter_create(g_hndl)) == NULL)
12515 		scfdie();
12516 
12517 	if (scf_iter_service_instances(iter, svc) != 0)
12518 		scfdie();
12519 
12520 	for (r = scf_iter_next_instance(iter, inst);
12521 	    r == 1;
12522 	    r = scf_iter_next_instance(iter, inst)) {
12523 
12524 		ret = lscf_instance_delete(inst, force);
12525 		if (ret == DELETE_FAILURE) {
12526 			scf_iter_destroy(iter);
12527 			scf_pg_destroy(pg);
12528 			scf_instance_destroy(inst);
12529 			return (DELETE_FAILURE);
12530 		}
12531 
12532 		/*
12533 		 * Record the fact that there is some external dependencies
12534 		 * at the instance level.
12535 		 */
12536 		if (ret == DELETE_SUCCESS_EXTDEPS)
12537 			external |= 1;
12538 	}
12539 
12540 	if (r != 0)
12541 		scfdie();
12542 
12543 	/* Delete dependency property groups in dependent services. */
12544 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12545 		(void) delete_dependents(pg);
12546 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12547 		scfdie();
12548 
12549 	scf_iter_destroy(iter);
12550 	scf_pg_destroy(pg);
12551 	scf_instance_destroy(inst);
12552 
12553 	/*
12554 	 * If the service has some external dependencies then we don't
12555 	 * want to remove them in case the service is re-imported.
12556 	 */
12557 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12558 	    (iter = scf_iter_create(g_hndl)) == NULL)
12559 		scfdie();
12560 
12561 	if (scf_iter_service_pgs(iter, svc) < 0)
12562 		scfdie();
12563 
12564 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12565 		if (pg_is_external_dependency(pg)) {
12566 			external |= 2;
12567 			continue;
12568 		}
12569 
12570 		if (scf_pg_delete(pg) != 0) {
12571 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12572 				scfdie();
12573 			else {
12574 				semerr(emsg_permission_denied);
12575 
12576 				(void) scf_iter_destroy(iter);
12577 				(void) scf_pg_destroy(pg);
12578 				return (DELETE_FAILURE);
12579 			}
12580 		}
12581 	}
12582 
12583 	if (r == -1)
12584 		scfdie();
12585 
12586 	(void) scf_iter_destroy(iter);
12587 	(void) scf_pg_destroy(pg);
12588 
12589 	if (external != 0)
12590 		return (DELETE_SUCCESS_EXTDEPS);
12591 
12592 	if (scf_service_delete(svc) == 0)
12593 		return (DELETE_SUCCESS_NOEXTDEPS);
12594 
12595 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12596 		scfdie();
12597 
12598 	semerr(emsg_permission_denied);
12599 	return (DELETE_FAILURE);
12600 }
12601 
12602 static int
12603 delete_callback(void *data, scf_walkinfo_t *wip)
12604 {
12605 	int force = (int)data;
12606 
12607 	if (wip->inst != NULL)
12608 		(void) lscf_instance_delete(wip->inst, force);
12609 	else
12610 		(void) lscf_service_delete(wip->svc, force);
12611 
12612 	return (0);
12613 }
12614 
12615 void
12616 lscf_delete(const char *fmri, int force)
12617 {
12618 	scf_service_t *svc;
12619 	scf_instance_t *inst;
12620 	int ret;
12621 
12622 	lscf_prep_hndl();
12623 
12624 	if (cur_snap != NULL) {
12625 		if (!snaplevel_is_instance(cur_level)) {
12626 			char *buf;
12627 
12628 			buf = safe_malloc(max_scf_name_len + 1);
12629 			if (scf_instance_get_name(cur_inst, buf,
12630 			    max_scf_name_len + 1) >= 0) {
12631 				if (strcmp(buf, fmri) == 0) {
12632 					semerr(emsg_cant_modify_snapshots);
12633 					free(buf);
12634 					return;
12635 				}
12636 			} else if (scf_error() != SCF_ERROR_DELETED) {
12637 				scfdie();
12638 			}
12639 			free(buf);
12640 		}
12641 	} else if (cur_inst != NULL) {
12642 		/* EMPTY */;
12643 	} else if (cur_svc != NULL) {
12644 		inst = scf_instance_create(g_hndl);
12645 		if (inst == NULL)
12646 			scfdie();
12647 
12648 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12649 		    SCF_SUCCESS) {
12650 			(void) lscf_instance_delete(inst, force);
12651 			scf_instance_destroy(inst);
12652 			return;
12653 		}
12654 
12655 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12656 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12657 			scfdie();
12658 
12659 		scf_instance_destroy(inst);
12660 	} else {
12661 		assert(cur_scope != NULL);
12662 
12663 		svc = scf_service_create(g_hndl);
12664 		if (svc == NULL)
12665 			scfdie();
12666 
12667 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12668 		    SCF_SUCCESS) {
12669 			(void) lscf_service_delete(svc, force);
12670 			scf_service_destroy(svc);
12671 			return;
12672 		}
12673 
12674 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12675 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12676 			scfdie();
12677 
12678 		scf_service_destroy(svc);
12679 	}
12680 
12681 	/*
12682 	 * Match FMRI to entity.
12683 	 */
12684 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12685 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12686 		semerr(gettext("Failed to walk instances: %s\n"),
12687 		    scf_strerror(ret));
12688 	}
12689 }
12690 
12691 
12692 
12693 /*
12694  * :properties commands.  These all end with "pg" or "prop" and generally
12695  * operate on the currently selected entity.
12696  */
12697 
12698 /*
12699  * Property listing.  List the property groups, properties, their types and
12700  * their values for the currently selected entity.
12701  */
12702 static void
12703 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12704 {
12705 	char *buf;
12706 	uint32_t flags;
12707 
12708 	buf = safe_malloc(max_scf_pg_type_len + 1);
12709 
12710 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12711 		scfdie();
12712 
12713 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12714 		scfdie();
12715 
12716 	safe_printf("%-*s  %s", namewidth, name, buf);
12717 
12718 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12719 		safe_printf("\tNONPERSISTENT");
12720 
12721 	safe_printf("\n");
12722 
12723 	free(buf);
12724 }
12725 
12726 static boolean_t
12727 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12728 {
12729 	if (scf_property_get_value(prop, val) == 0) {
12730 		return (B_FALSE);
12731 	} else {
12732 		switch (scf_error()) {
12733 		case SCF_ERROR_NOT_FOUND:
12734 			return (B_FALSE);
12735 		case SCF_ERROR_PERMISSION_DENIED:
12736 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12737 			return (B_TRUE);
12738 		default:
12739 			scfdie();
12740 			/*NOTREACHED*/
12741 		}
12742 	}
12743 }
12744 
12745 static void
12746 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12747 {
12748 	scf_iter_t *iter;
12749 	scf_value_t *val;
12750 	const char *type;
12751 	int multiple_strings = 0;
12752 	int ret;
12753 
12754 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12755 	    (val = scf_value_create(g_hndl)) == NULL)
12756 		scfdie();
12757 
12758 	type = prop_to_typestr(prop);
12759 	assert(type != NULL);
12760 
12761 	safe_printf("%-*s  %-7s ", len, name, type);
12762 
12763 	if (prop_has_multiple_values(prop, val) &&
12764 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12765 	    scf_value_type(val) == SCF_TYPE_USTRING))
12766 		multiple_strings = 1;
12767 
12768 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12769 		scfdie();
12770 
12771 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12772 		char *buf;
12773 		ssize_t vlen, szret;
12774 
12775 		vlen = scf_value_get_as_string(val, NULL, 0);
12776 		if (vlen < 0)
12777 			scfdie();
12778 
12779 		buf = safe_malloc(vlen + 1);
12780 
12781 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12782 		if (szret < 0)
12783 			scfdie();
12784 		assert(szret <= vlen);
12785 
12786 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12787 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12788 			safe_printf(" \"");
12789 			(void) quote_and_print(buf, stdout, 0);
12790 			(void) putchar('"');
12791 			if (ferror(stdout)) {
12792 				(void) putchar('\n');
12793 				uu_die(gettext("Error writing to stdout.\n"));
12794 			}
12795 		} else {
12796 			safe_printf(" %s", buf);
12797 		}
12798 
12799 		free(buf);
12800 	}
12801 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12802 		scfdie();
12803 
12804 	if (putchar('\n') != '\n')
12805 		uu_die(gettext("Could not output newline"));
12806 }
12807 
12808 /*
12809  * Outputs template property group info for the describe subcommand.
12810  * If 'templates' == 2, verbose output is printed in the format expected
12811  * for describe -v, which includes all templates fields.  If pg is
12812  * not NULL, we're describing the template data, not an existing property
12813  * group, and formatting should be appropriate for describe -t.
12814  */
12815 static void
12816 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12817 {
12818 	char *buf;
12819 	uint8_t required;
12820 	scf_property_t *stability_prop;
12821 	scf_value_t *stability_val;
12822 
12823 	if (templates == 0)
12824 		return;
12825 
12826 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12827 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12828 		scfdie();
12829 
12830 	if (templates == 2 && pg != NULL) {
12831 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12832 		    stability_prop) == 0) {
12833 			if (prop_check_type(stability_prop,
12834 			    SCF_TYPE_ASTRING) == 0 &&
12835 			    prop_get_val(stability_prop, stability_val) == 0) {
12836 				char *stability;
12837 
12838 				stability = safe_malloc(max_scf_value_len + 1);
12839 
12840 				if (scf_value_get_astring(stability_val,
12841 				    stability, max_scf_value_len + 1) == -1 &&
12842 				    scf_error() != SCF_ERROR_NOT_FOUND)
12843 					scfdie();
12844 
12845 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12846 				    gettext("stability"), stability);
12847 
12848 				free(stability);
12849 			}
12850 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12851 			scfdie();
12852 	}
12853 
12854 	scf_property_destroy(stability_prop);
12855 	scf_value_destroy(stability_val);
12856 
12857 	if (pgt == NULL)
12858 		return;
12859 
12860 	if (pg == NULL || templates == 2) {
12861 		/* print type info only if scf_tmpl_pg_name succeeds */
12862 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12863 			if (pg != NULL)
12864 				safe_printf("%s", TMPL_INDENT);
12865 			safe_printf("%s: ", gettext("name"));
12866 			safe_printf("%s\n", buf);
12867 			free(buf);
12868 		}
12869 
12870 		/* print type info only if scf_tmpl_pg_type succeeds */
12871 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12872 			if (pg != NULL)
12873 				safe_printf("%s", TMPL_INDENT);
12874 			safe_printf("%s: ", gettext("type"));
12875 			safe_printf("%s\n", buf);
12876 			free(buf);
12877 		}
12878 	}
12879 
12880 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12881 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12882 		    required ? "true" : "false");
12883 
12884 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12885 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12886 		    buf);
12887 		free(buf);
12888 	}
12889 
12890 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12891 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12892 		    buf);
12893 		free(buf);
12894 	}
12895 
12896 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12897 		if (templates == 2)
12898 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12899 			    gettext("description"), buf);
12900 		else
12901 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12902 		free(buf);
12903 	}
12904 
12905 }
12906 
12907 /*
12908  * With as_value set to true, indent as appropriate for the value level.
12909  * If false, indent to appropriate level for inclusion in constraint
12910  * or choice printout.
12911  */
12912 static void
12913 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12914     int as_value)
12915 {
12916 	char *buf;
12917 
12918 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12919 		if (as_value == 0)
12920 			safe_printf("%s", TMPL_CHOICE_INDENT);
12921 		else
12922 			safe_printf("%s", TMPL_INDENT);
12923 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12924 		free(buf);
12925 	}
12926 
12927 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12928 		if (as_value == 0)
12929 			safe_printf("%s", TMPL_CHOICE_INDENT);
12930 		else
12931 			safe_printf("%s", TMPL_INDENT);
12932 		safe_printf("%s: %s\n", gettext("value description"), buf);
12933 		free(buf);
12934 	}
12935 }
12936 
12937 static void
12938 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12939 {
12940 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12941 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12942 	safe_printf("%s\n", val_buf);
12943 
12944 	print_template_value_details(prt, val_buf, 1);
12945 }
12946 
12947 static void
12948 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12949 {
12950 	int i, printed = 0;
12951 	scf_values_t values;
12952 	scf_count_ranges_t c_ranges;
12953 	scf_int_ranges_t i_ranges;
12954 
12955 	printed = 0;
12956 	i = 0;
12957 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12958 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12959 		    gettext("value constraints"));
12960 		printed++;
12961 		for (i = 0; i < values.value_count; ++i) {
12962 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12963 			    gettext("value name"), values.values_as_strings[i]);
12964 			if (verbose == 1)
12965 				print_template_value_details(prt,
12966 				    values.values_as_strings[i], 0);
12967 		}
12968 
12969 		scf_values_destroy(&values);
12970 	}
12971 
12972 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12973 		if (printed++ == 0)
12974 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12975 			    gettext("value constraints"));
12976 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12977 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12978 			    gettext("range"), c_ranges.scr_min[i],
12979 			    c_ranges.scr_max[i]);
12980 		}
12981 		scf_count_ranges_destroy(&c_ranges);
12982 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12983 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12984 		if (printed++ == 0)
12985 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12986 			    gettext("value constraints"));
12987 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12988 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12989 			    gettext("range"), i_ranges.sir_min[i],
12990 			    i_ranges.sir_max[i]);
12991 		}
12992 		scf_int_ranges_destroy(&i_ranges);
12993 	}
12994 }
12995 
12996 static void
12997 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12998 {
12999 	int i = 0, printed = 0;
13000 	scf_values_t values;
13001 	scf_count_ranges_t c_ranges;
13002 	scf_int_ranges_t i_ranges;
13003 
13004 	printed = 0;
13005 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13006 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13007 		    gettext("value constraints"));
13008 		printed++;
13009 		for (i = 0; i < values.value_count; i++) {
13010 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13011 			    gettext("value name"), values.values_as_strings[i]);
13012 			if (verbose == 1)
13013 				print_template_value_details(prt,
13014 				    values.values_as_strings[i], 0);
13015 		}
13016 
13017 		scf_values_destroy(&values);
13018 	}
13019 
13020 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13021 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13022 			if (printed++ == 0)
13023 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13024 				    gettext("value choices"));
13025 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13026 			    gettext("range"), c_ranges.scr_min[i],
13027 			    c_ranges.scr_max[i]);
13028 		}
13029 		scf_count_ranges_destroy(&c_ranges);
13030 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13031 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13032 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13033 			if (printed++ == 0)
13034 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13035 				    gettext("value choices"));
13036 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13037 			    gettext("range"), i_ranges.sir_min[i],
13038 			    i_ranges.sir_max[i]);
13039 		}
13040 		scf_int_ranges_destroy(&i_ranges);
13041 	}
13042 }
13043 
13044 static void
13045 list_values_by_template(scf_prop_tmpl_t *prt)
13046 {
13047 	print_template_constraints(prt, 1);
13048 	print_template_choices(prt, 1);
13049 }
13050 
13051 static void
13052 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13053 {
13054 	char *val_buf;
13055 	scf_iter_t *iter;
13056 	scf_value_t *val;
13057 	int ret;
13058 
13059 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13060 	    (val = scf_value_create(g_hndl)) == NULL)
13061 		scfdie();
13062 
13063 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13064 		scfdie();
13065 
13066 	val_buf = safe_malloc(max_scf_value_len + 1);
13067 
13068 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13069 		if (scf_value_get_as_string(val, val_buf,
13070 		    max_scf_value_len + 1) < 0)
13071 			scfdie();
13072 
13073 		print_template_value(prt, val_buf);
13074 	}
13075 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13076 		scfdie();
13077 	free(val_buf);
13078 
13079 	print_template_constraints(prt, 0);
13080 	print_template_choices(prt, 0);
13081 
13082 }
13083 
13084 /*
13085  * Outputs property info for the describe subcommand
13086  * Verbose output if templates == 2, -v option of svccfg describe
13087  * Displays template data if prop is not NULL, -t option of svccfg describe
13088  */
13089 static void
13090 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13091 {
13092 	char *buf;
13093 	uint8_t u_buf;
13094 	int i;
13095 	uint64_t min, max;
13096 	scf_values_t values;
13097 
13098 	if (prt == NULL || templates == 0)
13099 		return;
13100 
13101 	if (prop == NULL) {
13102 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13103 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
13104 			safe_printf("%s\n", buf);
13105 			free(buf);
13106 		} else
13107 			safe_printf("(%s)\n", gettext("any"));
13108 	}
13109 
13110 	if (prop == NULL || templates == 2) {
13111 		if (prop != NULL)
13112 			safe_printf("%s", TMPL_INDENT);
13113 		else
13114 			safe_printf("%s", TMPL_VALUE_INDENT);
13115 		safe_printf("%s: ", gettext("type"));
13116 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13117 			safe_printf("%s\n", buf);
13118 			free(buf);
13119 		} else
13120 			safe_printf("(%s)\n", gettext("any"));
13121 	}
13122 
13123 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13124 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13125 		    u_buf ? "true" : "false");
13126 
13127 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13128 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13129 		    buf);
13130 		free(buf);
13131 	}
13132 
13133 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13134 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13135 		    buf);
13136 		free(buf);
13137 	}
13138 
13139 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13140 		safe_printf("%s%s\n", TMPL_INDENT, buf);
13141 		free(buf);
13142 	}
13143 
13144 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13145 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13146 		    scf_tmpl_visibility_to_string(u_buf));
13147 
13148 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13149 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13150 		    gettext("minimum number of values"), min);
13151 		if (max == ULLONG_MAX) {
13152 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13153 			    gettext("maximum number of values"),
13154 			    gettext("unlimited"));
13155 		} else {
13156 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13157 			    gettext("maximum number of values"), max);
13158 		}
13159 	}
13160 
13161 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13162 		for (i = 0; i < values.value_count; i++) {
13163 			if (i == 0) {
13164 				safe_printf("%s%s:", TMPL_INDENT,
13165 				    gettext("internal separators"));
13166 			}
13167 			safe_printf(" \"%s\"", values.values_as_strings[i]);
13168 		}
13169 		safe_printf("\n");
13170 	}
13171 
13172 	if (templates != 2)
13173 		return;
13174 
13175 	if (prop != NULL)
13176 		list_values_tmpl(prt, prop);
13177 	else
13178 		list_values_by_template(prt);
13179 }
13180 
13181 static char *
13182 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13183 {
13184 	char *rv;
13185 
13186 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
13187 	if (rv == NULL) {
13188 		switch (scf_error()) {
13189 		case SCF_ERROR_NOT_FOUND:
13190 			break;
13191 		default:
13192 			scfdie();
13193 		}
13194 	}
13195 	return (rv);
13196 }
13197 
13198 static void
13199 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13200 {
13201 	size_t doc_len;
13202 	size_t man_len;
13203 	char *pg_name;
13204 	char *text = NULL;
13205 	int rv;
13206 
13207 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13208 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13209 	pg_name = safe_malloc(max_scf_name_len + 1);
13210 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13211 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13212 			scfdie();
13213 		}
13214 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13215 			/* Display doc_link and and uri */
13216 			safe_printf("%s%s:\n", TMPL_INDENT,
13217 			    gettext("doc_link"));
13218 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13219 			if (text != NULL) {
13220 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13221 				    TMPL_INDENT, gettext("name"), text);
13222 				uu_free(text);
13223 			}
13224 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
13225 			if (text != NULL) {
13226 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13227 				    gettext("uri"), text);
13228 				uu_free(text);
13229 			}
13230 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13231 		    man_len) == 0) {
13232 			/* Display manpage title, section and path */
13233 			safe_printf("%s%s:\n", TMPL_INDENT,
13234 			    gettext("manpage"));
13235 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13236 			if (text != NULL) {
13237 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13238 				    TMPL_INDENT, gettext("title"), text);
13239 				uu_free(text);
13240 			}
13241 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13242 			if (text != NULL) {
13243 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13244 				    TMPL_INDENT, gettext("section"), text);
13245 				uu_free(text);
13246 			}
13247 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13248 			if (text != NULL) {
13249 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13250 				    TMPL_INDENT, gettext("manpath"), text);
13251 				uu_free(text);
13252 			}
13253 		}
13254 	}
13255 	if (rv == -1)
13256 		scfdie();
13257 
13258 done:
13259 	free(pg_name);
13260 }
13261 
13262 static void
13263 list_entity_tmpl(int templates)
13264 {
13265 	char *common_name = NULL;
13266 	char *description = NULL;
13267 	char *locale = NULL;
13268 	scf_iter_t *iter;
13269 	scf_propertygroup_t *pg;
13270 	scf_property_t *prop;
13271 	int r;
13272 	scf_value_t *val;
13273 
13274 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13275 	    (prop = scf_property_create(g_hndl)) == NULL ||
13276 	    (val = scf_value_create(g_hndl)) == NULL ||
13277 	    (iter = scf_iter_create(g_hndl)) == NULL)
13278 		scfdie();
13279 
13280 	locale = setlocale(LC_MESSAGES, NULL);
13281 
13282 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13283 		common_name = safe_malloc(max_scf_value_len + 1);
13284 
13285 		/* Try both the current locale and the "C" locale. */
13286 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
13287 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
13288 		    scf_pg_get_property(pg, "C", prop) == 0)) {
13289 			if (prop_get_val(prop, val) == 0 &&
13290 			    scf_value_get_ustring(val, common_name,
13291 			    max_scf_value_len + 1) != -1) {
13292 				safe_printf("%s%s: %s\n", TMPL_INDENT,
13293 				    gettext("common name"), common_name);
13294 			}
13295 		}
13296 	}
13297 
13298 	/*
13299 	 * Do description, manpages, and doc links if templates == 2.
13300 	 */
13301 	if (templates == 2) {
13302 		/* Get the description. */
13303 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13304 			description = safe_malloc(max_scf_value_len + 1);
13305 
13306 			/* Try both the current locale and the "C" locale. */
13307 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
13308 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
13309 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13310 				if (prop_get_val(prop, val) == 0 &&
13311 				    scf_value_get_ustring(val, description,
13312 				    max_scf_value_len + 1) != -1) {
13313 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13314 					    gettext("description"),
13315 					    description);
13316 				}
13317 			}
13318 		}
13319 
13320 		/* Process doc_link & manpage elements. */
13321 		if (cur_level != NULL) {
13322 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13323 			    SCF_GROUP_TEMPLATE);
13324 		} else if (cur_inst != NULL) {
13325 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13326 			    SCF_GROUP_TEMPLATE);
13327 		} else {
13328 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13329 			    SCF_GROUP_TEMPLATE);
13330 		}
13331 		if (r == 0) {
13332 			display_documentation(iter, pg);
13333 		}
13334 	}
13335 
13336 	free(common_name);
13337 	free(description);
13338 	scf_pg_destroy(pg);
13339 	scf_property_destroy(prop);
13340 	scf_value_destroy(val);
13341 	scf_iter_destroy(iter);
13342 }
13343 
13344 static void
13345 listtmpl(const char *pattern, int templates)
13346 {
13347 	scf_pg_tmpl_t *pgt;
13348 	scf_prop_tmpl_t *prt;
13349 	char *snapbuf = NULL;
13350 	char *fmribuf;
13351 	char *pg_name = NULL, *prop_name = NULL;
13352 	ssize_t prop_name_size;
13353 	char *qual_prop_name;
13354 	char *search_name;
13355 	int listed = 0;
13356 
13357 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13358 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13359 		scfdie();
13360 
13361 	fmribuf = safe_malloc(max_scf_name_len + 1);
13362 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13363 
13364 	if (cur_snap != NULL) {
13365 		snapbuf = safe_malloc(max_scf_name_len + 1);
13366 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13367 		    max_scf_name_len + 1) < 0)
13368 			scfdie();
13369 	}
13370 
13371 	if (cur_inst != NULL) {
13372 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13373 		    max_scf_name_len + 1) < 0)
13374 			scfdie();
13375 	} else if (cur_svc != NULL) {
13376 		if (scf_service_to_fmri(cur_svc, fmribuf,
13377 		    max_scf_name_len + 1) < 0)
13378 			scfdie();
13379 	} else
13380 		abort();
13381 
13382 	/* If pattern is specified, we want to list only those items. */
13383 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13384 		listed = 0;
13385 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13386 		    fnmatch(pattern, pg_name, 0) == 0)) {
13387 			list_pg_tmpl(pgt, NULL, templates);
13388 			listed++;
13389 		}
13390 
13391 		scf_tmpl_prop_reset(prt);
13392 
13393 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13394 			search_name = NULL;
13395 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13396 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13397 				if (snprintf(qual_prop_name,
13398 				    max_scf_name_len + 1, "%s/%s",
13399 				    pg_name, prop_name) >=
13400 				    max_scf_name_len + 1) {
13401 					prop_name_size = -1;
13402 				} else {
13403 					search_name = qual_prop_name;
13404 				}
13405 			}
13406 			if (listed > 0 || pattern == NULL ||
13407 			    (prop_name_size > 0 &&
13408 			    fnmatch(pattern, search_name,
13409 			    FNM_PATHNAME) == 0))
13410 				list_prop_tmpl(prt, NULL, templates);
13411 			if (prop_name != NULL) {
13412 				free(prop_name);
13413 				prop_name = NULL;
13414 			}
13415 		}
13416 		if (pg_name != NULL) {
13417 			free(pg_name);
13418 			pg_name = NULL;
13419 		}
13420 	}
13421 
13422 	scf_tmpl_prop_destroy(prt);
13423 	scf_tmpl_pg_destroy(pgt);
13424 	free(snapbuf);
13425 	free(fmribuf);
13426 	free(qual_prop_name);
13427 }
13428 
13429 static void
13430 listprop(const char *pattern, int only_pgs, int templates)
13431 {
13432 	scf_propertygroup_t *pg;
13433 	scf_property_t *prop;
13434 	scf_iter_t *iter, *piter;
13435 	char *pgnbuf, *prnbuf, *ppnbuf;
13436 	scf_pg_tmpl_t *pgt, *pgtp;
13437 	scf_prop_tmpl_t *prt;
13438 
13439 	void **objects;
13440 	char **names;
13441 	void **tmpls;
13442 	int allocd, i;
13443 
13444 	int ret;
13445 	ssize_t pgnlen, prnlen, szret;
13446 	size_t max_len = 0;
13447 
13448 	if (cur_svc == NULL && cur_inst == NULL) {
13449 		semerr(emsg_entity_not_selected);
13450 		return;
13451 	}
13452 
13453 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13454 	    (prop = scf_property_create(g_hndl)) == NULL ||
13455 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13456 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13457 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13458 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13459 		scfdie();
13460 
13461 	prnbuf = safe_malloc(max_scf_name_len + 1);
13462 
13463 	if (cur_level != NULL)
13464 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13465 	else if (cur_inst != NULL)
13466 		ret = scf_iter_instance_pgs(iter, cur_inst);
13467 	else
13468 		ret = scf_iter_service_pgs(iter, cur_svc);
13469 	if (ret != 0) {
13470 		return;
13471 	}
13472 
13473 	/*
13474 	 * We want to only list items which match pattern, and we want the
13475 	 * second column to line up, so during the first pass we'll save
13476 	 * matching items, their names, and their templates in objects,
13477 	 * names, and tmpls, computing the maximum name length as we go,
13478 	 * and then we'll print them out.
13479 	 *
13480 	 * Note: We always keep an extra slot available so the array can be
13481 	 * NULL-terminated.
13482 	 */
13483 	i = 0;
13484 	allocd = 1;
13485 	objects = safe_malloc(sizeof (*objects));
13486 	names = safe_malloc(sizeof (*names));
13487 	tmpls = safe_malloc(sizeof (*tmpls));
13488 
13489 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13490 		int new_pg = 0;
13491 		int print_props = 0;
13492 		pgtp = NULL;
13493 
13494 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13495 		if (pgnlen < 0)
13496 			scfdie();
13497 
13498 		pgnbuf = safe_malloc(pgnlen + 1);
13499 
13500 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13501 		if (szret < 0)
13502 			scfdie();
13503 		assert(szret <= pgnlen);
13504 
13505 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13506 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13507 				scfdie();
13508 			pgtp = NULL;
13509 		} else {
13510 			pgtp = pgt;
13511 		}
13512 
13513 		if (pattern == NULL ||
13514 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13515 			if (i+1 >= allocd) {
13516 				allocd *= 2;
13517 				objects = realloc(objects,
13518 				    sizeof (*objects) * allocd);
13519 				names =
13520 				    realloc(names, sizeof (*names) * allocd);
13521 				tmpls = realloc(tmpls,
13522 				    sizeof (*tmpls) * allocd);
13523 				if (objects == NULL || names == NULL ||
13524 				    tmpls == NULL)
13525 					uu_die(gettext("Out of memory"));
13526 			}
13527 			objects[i] = pg;
13528 			names[i] = pgnbuf;
13529 
13530 			if (pgtp == NULL)
13531 				tmpls[i] = NULL;
13532 			else
13533 				tmpls[i] = pgt;
13534 
13535 			++i;
13536 
13537 			if (pgnlen > max_len)
13538 				max_len = pgnlen;
13539 
13540 			new_pg = 1;
13541 			print_props = 1;
13542 		}
13543 
13544 		if (only_pgs) {
13545 			if (new_pg) {
13546 				pg = scf_pg_create(g_hndl);
13547 				if (pg == NULL)
13548 					scfdie();
13549 				pgt = scf_tmpl_pg_create(g_hndl);
13550 				if (pgt == NULL)
13551 					scfdie();
13552 			} else
13553 				free(pgnbuf);
13554 
13555 			continue;
13556 		}
13557 
13558 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13559 			scfdie();
13560 
13561 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13562 			prnlen = scf_property_get_name(prop, prnbuf,
13563 			    max_scf_name_len + 1);
13564 			if (prnlen < 0)
13565 				scfdie();
13566 
13567 			/* Will prepend the property group name and a slash. */
13568 			prnlen += pgnlen + 1;
13569 
13570 			ppnbuf = safe_malloc(prnlen + 1);
13571 
13572 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13573 			    prnbuf) < 0)
13574 				uu_die("snprintf");
13575 
13576 			if (pattern == NULL || print_props == 1 ||
13577 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13578 				if (i+1 >= allocd) {
13579 					allocd *= 2;
13580 					objects = realloc(objects,
13581 					    sizeof (*objects) * allocd);
13582 					names = realloc(names,
13583 					    sizeof (*names) * allocd);
13584 					tmpls = realloc(tmpls,
13585 					    sizeof (*tmpls) * allocd);
13586 					if (objects == NULL || names == NULL ||
13587 					    tmpls == NULL)
13588 						uu_die(gettext(
13589 						    "Out of memory"));
13590 				}
13591 
13592 				objects[i] = prop;
13593 				names[i] = ppnbuf;
13594 
13595 				if (pgtp != NULL) {
13596 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13597 					    prt, 0) < 0) {
13598 						if (scf_error() !=
13599 						    SCF_ERROR_NOT_FOUND)
13600 							scfdie();
13601 						tmpls[i] = NULL;
13602 					} else {
13603 						tmpls[i] = prt;
13604 					}
13605 				} else {
13606 					tmpls[i] = NULL;
13607 				}
13608 
13609 				++i;
13610 
13611 				if (prnlen > max_len)
13612 					max_len = prnlen;
13613 
13614 				prop = scf_property_create(g_hndl);
13615 				prt = scf_tmpl_prop_create(g_hndl);
13616 			} else {
13617 				free(ppnbuf);
13618 			}
13619 		}
13620 
13621 		if (new_pg) {
13622 			pg = scf_pg_create(g_hndl);
13623 			if (pg == NULL)
13624 				scfdie();
13625 			pgt = scf_tmpl_pg_create(g_hndl);
13626 			if (pgt == NULL)
13627 				scfdie();
13628 		} else
13629 			free(pgnbuf);
13630 	}
13631 	if (ret != 0)
13632 		scfdie();
13633 
13634 	objects[i] = NULL;
13635 
13636 	scf_pg_destroy(pg);
13637 	scf_tmpl_pg_destroy(pgt);
13638 	scf_property_destroy(prop);
13639 	scf_tmpl_prop_destroy(prt);
13640 
13641 	for (i = 0; objects[i] != NULL; ++i) {
13642 		if (strchr(names[i], '/') == NULL) {
13643 			/* property group */
13644 			pg = (scf_propertygroup_t *)objects[i];
13645 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13646 			list_pg_info(pg, names[i], max_len);
13647 			list_pg_tmpl(pgt, pg, templates);
13648 			free(names[i]);
13649 			scf_pg_destroy(pg);
13650 			if (pgt != NULL)
13651 				scf_tmpl_pg_destroy(pgt);
13652 		} else {
13653 			/* property */
13654 			prop = (scf_property_t *)objects[i];
13655 			prt = (scf_prop_tmpl_t *)tmpls[i];
13656 			list_prop_info(prop, names[i], max_len);
13657 			list_prop_tmpl(prt, prop, templates);
13658 			free(names[i]);
13659 			scf_property_destroy(prop);
13660 			if (prt != NULL)
13661 				scf_tmpl_prop_destroy(prt);
13662 		}
13663 	}
13664 
13665 	free(names);
13666 	free(objects);
13667 	free(tmpls);
13668 }
13669 
13670 void
13671 lscf_listpg(const char *pattern)
13672 {
13673 	lscf_prep_hndl();
13674 
13675 	listprop(pattern, 1, 0);
13676 }
13677 
13678 /*
13679  * Property group and property creation, setting, and deletion.  setprop (and
13680  * its alias, addprop) can either create a property group of a given type, or
13681  * it can create or set a property to a given type and list of values.
13682  */
13683 void
13684 lscf_addpg(const char *name, const char *type, const char *flags)
13685 {
13686 	scf_propertygroup_t *pg;
13687 	int ret;
13688 	uint32_t flgs = 0;
13689 	const char *cp;
13690 
13691 
13692 	lscf_prep_hndl();
13693 
13694 	if (cur_snap != NULL) {
13695 		semerr(emsg_cant_modify_snapshots);
13696 		return;
13697 	}
13698 
13699 	if (cur_inst == NULL && cur_svc == NULL) {
13700 		semerr(emsg_entity_not_selected);
13701 		return;
13702 	}
13703 
13704 	if (flags != NULL) {
13705 		for (cp = flags; *cp != '\0'; ++cp) {
13706 			switch (*cp) {
13707 			case 'P':
13708 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13709 				break;
13710 
13711 			case 'p':
13712 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13713 				break;
13714 
13715 			default:
13716 				semerr(gettext("Invalid property group flag "
13717 				    "%c."), *cp);
13718 				return;
13719 			}
13720 		}
13721 	}
13722 
13723 	pg = scf_pg_create(g_hndl);
13724 	if (pg == NULL)
13725 		scfdie();
13726 
13727 	if (cur_inst != NULL)
13728 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13729 	else
13730 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13731 
13732 	if (ret != SCF_SUCCESS) {
13733 		switch (scf_error()) {
13734 		case SCF_ERROR_INVALID_ARGUMENT:
13735 			semerr(gettext("Name, type, or flags are invalid.\n"));
13736 			break;
13737 
13738 		case SCF_ERROR_EXISTS:
13739 			semerr(gettext("Property group already exists.\n"));
13740 			break;
13741 
13742 		case SCF_ERROR_PERMISSION_DENIED:
13743 			semerr(emsg_permission_denied);
13744 			break;
13745 
13746 		case SCF_ERROR_BACKEND_ACCESS:
13747 			semerr(gettext("Backend refused access.\n"));
13748 			break;
13749 
13750 		default:
13751 			scfdie();
13752 		}
13753 	}
13754 
13755 	scf_pg_destroy(pg);
13756 
13757 	private_refresh();
13758 }
13759 
13760 void
13761 lscf_delpg(char *name)
13762 {
13763 	lscf_prep_hndl();
13764 
13765 	if (cur_snap != NULL) {
13766 		semerr(emsg_cant_modify_snapshots);
13767 		return;
13768 	}
13769 
13770 	if (cur_inst == NULL && cur_svc == NULL) {
13771 		semerr(emsg_entity_not_selected);
13772 		return;
13773 	}
13774 
13775 	if (strchr(name, '/') != NULL) {
13776 		semerr(emsg_invalid_pg_name, name);
13777 		return;
13778 	}
13779 
13780 	lscf_delprop(name);
13781 }
13782 
13783 /*
13784  * scf_delhash() is used to remove the property group related to the
13785  * hash entry for a specific manifest in the repository. pgname will be
13786  * constructed from the location of the manifest file. If deathrow isn't 0,
13787  * manifest file doesn't need to exist (manifest string will be used as
13788  * an absolute path).
13789  */
13790 void
13791 lscf_delhash(char *manifest, int deathrow)
13792 {
13793 	char *pgname;
13794 
13795 	if (cur_snap != NULL ||
13796 	    cur_inst != NULL || cur_svc != NULL) {
13797 		warn(gettext("error, an entity is selected\n"));
13798 		return;
13799 	}
13800 
13801 	/* select smf/manifest */
13802 	lscf_select(HASH_SVC);
13803 	/*
13804 	 * Translate the manifest file name to property name. In the deathrow
13805 	 * case, the manifest file does not need to exist.
13806 	 */
13807 	pgname = mhash_filename_to_propname(manifest,
13808 	    deathrow ? B_TRUE : B_FALSE);
13809 	if (pgname == NULL) {
13810 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13811 		return;
13812 	}
13813 	/* delete the hash property name */
13814 	lscf_delpg(pgname);
13815 }
13816 
13817 void
13818 lscf_listprop(const char *pattern)
13819 {
13820 	lscf_prep_hndl();
13821 
13822 	listprop(pattern, 0, 0);
13823 }
13824 
13825 int
13826 lscf_setprop(const char *pgname, const char *type, const char *value,
13827     const uu_list_t *values)
13828 {
13829 	scf_type_t ty, current_ty;
13830 	scf_service_t *svc;
13831 	scf_propertygroup_t *pg, *parent_pg;
13832 	scf_property_t *prop, *parent_prop;
13833 	scf_pg_tmpl_t *pgt;
13834 	scf_prop_tmpl_t *prt;
13835 	int ret, result = 0;
13836 	scf_transaction_t *tx;
13837 	scf_transaction_entry_t *e;
13838 	scf_value_t *v;
13839 	uu_list_walk_t *walk;
13840 	string_list_t *sp;
13841 	char *propname;
13842 	int req_quotes = 0;
13843 
13844 	lscf_prep_hndl();
13845 
13846 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13847 	    (svc = scf_service_create(g_hndl)) == NULL ||
13848 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13849 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13850 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13851 	    (prop = scf_property_create(g_hndl)) == NULL ||
13852 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13853 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13854 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13855 		scfdie();
13856 
13857 	if (cur_snap != NULL) {
13858 		semerr(emsg_cant_modify_snapshots);
13859 		goto fail;
13860 	}
13861 
13862 	if (cur_inst == NULL && cur_svc == NULL) {
13863 		semerr(emsg_entity_not_selected);
13864 		goto fail;
13865 	}
13866 
13867 	propname = strchr(pgname, '/');
13868 	if (propname == NULL) {
13869 		semerr(gettext("Property names must contain a `/'.\n"));
13870 		goto fail;
13871 	}
13872 
13873 	*propname = '\0';
13874 	++propname;
13875 
13876 	if (type != NULL) {
13877 		ty = string_to_type(type);
13878 		if (ty == SCF_TYPE_INVALID) {
13879 			semerr(gettext("Unknown type \"%s\".\n"), type);
13880 			goto fail;
13881 		}
13882 	}
13883 
13884 	if (cur_inst != NULL)
13885 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13886 	else
13887 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13888 	if (ret != SCF_SUCCESS) {
13889 		switch (scf_error()) {
13890 		case SCF_ERROR_NOT_FOUND:
13891 			semerr(emsg_no_such_pg, pgname);
13892 			goto fail;
13893 
13894 		case SCF_ERROR_INVALID_ARGUMENT:
13895 			semerr(emsg_invalid_pg_name, pgname);
13896 			goto fail;
13897 
13898 		default:
13899 			scfdie();
13900 			break;
13901 		}
13902 	}
13903 
13904 	do {
13905 		if (scf_pg_update(pg) == -1)
13906 			scfdie();
13907 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13908 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13909 				scfdie();
13910 
13911 			semerr(emsg_permission_denied);
13912 			goto fail;
13913 		}
13914 
13915 		ret = scf_pg_get_property(pg, propname, prop);
13916 		if (ret == SCF_SUCCESS) {
13917 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13918 				scfdie();
13919 
13920 			if (type == NULL)
13921 				ty = current_ty;
13922 			if (scf_transaction_property_change_type(tx, e,
13923 			    propname, ty) == -1)
13924 				scfdie();
13925 
13926 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13927 			/* Infer the type, if possible. */
13928 			if (type == NULL) {
13929 				/*
13930 				 * First check if we're an instance and the
13931 				 * property is set on the service.
13932 				 */
13933 				if (cur_inst != NULL &&
13934 				    scf_instance_get_parent(cur_inst,
13935 				    svc) == 0 &&
13936 				    scf_service_get_pg(cur_svc, pgname,
13937 				    parent_pg) == 0 &&
13938 				    scf_pg_get_property(parent_pg, propname,
13939 				    parent_prop) == 0 &&
13940 				    scf_property_type(parent_prop,
13941 				    &current_ty) == 0) {
13942 					ty = current_ty;
13943 
13944 				/* Then check for a type set in a template. */
13945 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13946 				    0) == 0 &&
13947 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13948 				    0) == 0 &&
13949 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13950 					ty = current_ty;
13951 
13952 				/* If type can't be inferred, fail. */
13953 				} else {
13954 					semerr(gettext("Type required for new "
13955 					    "properties.\n"));
13956 					goto fail;
13957 				}
13958 			}
13959 			if (scf_transaction_property_new(tx, e, propname,
13960 			    ty) == -1)
13961 				scfdie();
13962 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13963 			semerr(emsg_invalid_prop_name, propname);
13964 			goto fail;
13965 		} else {
13966 			scfdie();
13967 		}
13968 
13969 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13970 			req_quotes = 1;
13971 
13972 		if (value != NULL) {
13973 			v = string_to_value(value, ty, 0);
13974 
13975 			if (v == NULL)
13976 				goto fail;
13977 
13978 			ret = scf_entry_add_value(e, v);
13979 			assert(ret == SCF_SUCCESS);
13980 		} else {
13981 			assert(values != NULL);
13982 
13983 			walk = uu_list_walk_start((uu_list_t *)values,
13984 			    UU_DEFAULT);
13985 			if (walk == NULL)
13986 				uu_die(gettext("Could not walk list"));
13987 
13988 			for (sp = uu_list_walk_next(walk); sp != NULL;
13989 			    sp = uu_list_walk_next(walk)) {
13990 				v = string_to_value(sp->str, ty, req_quotes);
13991 
13992 				if (v == NULL) {
13993 					scf_entry_destroy_children(e);
13994 					goto fail;
13995 				}
13996 
13997 				ret = scf_entry_add_value(e, v);
13998 				assert(ret == SCF_SUCCESS);
13999 			}
14000 			uu_list_walk_end(walk);
14001 		}
14002 		result = scf_transaction_commit(tx);
14003 
14004 		scf_transaction_reset(tx);
14005 		scf_entry_destroy_children(e);
14006 	} while (result == 0);
14007 
14008 	if (result < 0) {
14009 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14010 			scfdie();
14011 
14012 		semerr(emsg_permission_denied);
14013 		goto fail;
14014 	}
14015 
14016 	ret = 0;
14017 
14018 	private_refresh();
14019 
14020 	goto cleanup;
14021 
14022 fail:
14023 	ret = -1;
14024 
14025 cleanup:
14026 	scf_transaction_destroy(tx);
14027 	scf_entry_destroy(e);
14028 	scf_service_destroy(svc);
14029 	scf_pg_destroy(parent_pg);
14030 	scf_pg_destroy(pg);
14031 	scf_property_destroy(parent_prop);
14032 	scf_property_destroy(prop);
14033 	scf_tmpl_pg_destroy(pgt);
14034 	scf_tmpl_prop_destroy(prt);
14035 
14036 	return (ret);
14037 }
14038 
14039 void
14040 lscf_delprop(char *pgn)
14041 {
14042 	char *slash, *pn;
14043 	scf_propertygroup_t *pg;
14044 	scf_transaction_t *tx;
14045 	scf_transaction_entry_t *e;
14046 	int ret;
14047 
14048 
14049 	lscf_prep_hndl();
14050 
14051 	if (cur_snap != NULL) {
14052 		semerr(emsg_cant_modify_snapshots);
14053 		return;
14054 	}
14055 
14056 	if (cur_inst == NULL && cur_svc == NULL) {
14057 		semerr(emsg_entity_not_selected);
14058 		return;
14059 	}
14060 
14061 	pg = scf_pg_create(g_hndl);
14062 	if (pg == NULL)
14063 		scfdie();
14064 
14065 	slash = strchr(pgn, '/');
14066 	if (slash == NULL) {
14067 		pn = NULL;
14068 	} else {
14069 		*slash = '\0';
14070 		pn = slash + 1;
14071 	}
14072 
14073 	if (cur_inst != NULL)
14074 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
14075 	else
14076 		ret = scf_service_get_pg(cur_svc, pgn, pg);
14077 	if (ret != SCF_SUCCESS) {
14078 		switch (scf_error()) {
14079 		case SCF_ERROR_NOT_FOUND:
14080 			semerr(emsg_no_such_pg, pgn);
14081 			break;
14082 
14083 		case SCF_ERROR_INVALID_ARGUMENT:
14084 			semerr(emsg_invalid_pg_name, pgn);
14085 			break;
14086 
14087 		default:
14088 			scfdie();
14089 		}
14090 
14091 		scf_pg_destroy(pg);
14092 
14093 		return;
14094 	}
14095 
14096 	if (pn == NULL) {
14097 		/* Try to delete the property group. */
14098 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
14099 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14100 				scfdie();
14101 
14102 			semerr(emsg_permission_denied);
14103 		} else {
14104 			private_refresh();
14105 		}
14106 
14107 		scf_pg_destroy(pg);
14108 		return;
14109 	}
14110 
14111 	e = scf_entry_create(g_hndl);
14112 	tx = scf_transaction_create(g_hndl);
14113 
14114 	do {
14115 		if (scf_pg_update(pg) == -1)
14116 			scfdie();
14117 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14118 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14119 				scfdie();
14120 
14121 			semerr(emsg_permission_denied);
14122 			break;
14123 		}
14124 
14125 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14126 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
14127 				semerr(gettext("No such property %s/%s.\n"),
14128 				    pgn, pn);
14129 				break;
14130 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14131 				semerr(emsg_invalid_prop_name, pn);
14132 				break;
14133 			} else {
14134 				scfdie();
14135 			}
14136 		}
14137 
14138 		ret = scf_transaction_commit(tx);
14139 
14140 		if (ret == 0)
14141 			scf_transaction_reset(tx);
14142 	} while (ret == 0);
14143 
14144 	if (ret < 0) {
14145 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14146 			scfdie();
14147 
14148 		semerr(emsg_permission_denied);
14149 	} else {
14150 		private_refresh();
14151 	}
14152 
14153 	scf_transaction_destroy(tx);
14154 	scf_entry_destroy(e);
14155 	scf_pg_destroy(pg);
14156 }
14157 
14158 /*
14159  * Property editing.
14160  */
14161 
14162 static int
14163 write_edit_script(FILE *strm)
14164 {
14165 	char *fmribuf;
14166 	ssize_t fmrilen;
14167 
14168 	scf_propertygroup_t *pg;
14169 	scf_property_t *prop;
14170 	scf_value_t *val;
14171 	scf_type_t ty;
14172 	int ret, result = 0;
14173 	scf_iter_t *iter, *piter, *viter;
14174 	char *buf, *tybuf, *pname;
14175 	const char *emsg_write_error;
14176 
14177 
14178 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14179 
14180 
14181 	/* select fmri */
14182 	if (cur_inst != NULL) {
14183 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14184 		if (fmrilen < 0)
14185 			scfdie();
14186 		fmribuf = safe_malloc(fmrilen + 1);
14187 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14188 			scfdie();
14189 	} else {
14190 		assert(cur_svc != NULL);
14191 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14192 		if (fmrilen < 0)
14193 			scfdie();
14194 		fmribuf = safe_malloc(fmrilen + 1);
14195 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14196 			scfdie();
14197 	}
14198 
14199 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14200 		warn(emsg_write_error, strerror(errno));
14201 		free(fmribuf);
14202 		return (-1);
14203 	}
14204 
14205 	free(fmribuf);
14206 
14207 
14208 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
14209 	    (prop = scf_property_create(g_hndl)) == NULL ||
14210 	    (val = scf_value_create(g_hndl)) == NULL ||
14211 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14212 	    (piter = scf_iter_create(g_hndl)) == NULL ||
14213 	    (viter = scf_iter_create(g_hndl)) == NULL)
14214 		scfdie();
14215 
14216 	buf = safe_malloc(max_scf_name_len + 1);
14217 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
14218 	pname = safe_malloc(max_scf_name_len + 1);
14219 
14220 	if (cur_inst != NULL)
14221 		ret = scf_iter_instance_pgs(iter, cur_inst);
14222 	else
14223 		ret = scf_iter_service_pgs(iter, cur_svc);
14224 	if (ret != SCF_SUCCESS)
14225 		scfdie();
14226 
14227 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14228 		int ret2;
14229 
14230 		/*
14231 		 * # delprop pg
14232 		 * # addpg pg type
14233 		 */
14234 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14235 			scfdie();
14236 
14237 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14238 			scfdie();
14239 
14240 		if (fprintf(strm, "# Property group \"%s\"\n"
14241 		    "# delprop %s\n"
14242 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14243 			warn(emsg_write_error, strerror(errno));
14244 			result = -1;
14245 			goto out;
14246 		}
14247 
14248 		/* # setprop pg/prop = (values) */
14249 
14250 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14251 			scfdie();
14252 
14253 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14254 			int first = 1;
14255 			int ret3;
14256 			int multiple;
14257 			int is_str;
14258 			scf_type_t bty;
14259 
14260 			if (scf_property_get_name(prop, pname,
14261 			    max_scf_name_len + 1) < 0)
14262 				scfdie();
14263 
14264 			if (scf_property_type(prop, &ty) != 0)
14265 				scfdie();
14266 
14267 			multiple = prop_has_multiple_values(prop, val);
14268 
14269 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14270 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
14271 			    < 0) {
14272 				warn(emsg_write_error, strerror(errno));
14273 				result = -1;
14274 				goto out;
14275 			}
14276 
14277 			(void) scf_type_base_type(ty, &bty);
14278 			is_str = (bty == SCF_TYPE_ASTRING);
14279 
14280 			if (scf_iter_property_values(viter, prop) !=
14281 			    SCF_SUCCESS)
14282 				scfdie();
14283 
14284 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14285 				char *buf;
14286 				ssize_t buflen;
14287 
14288 				buflen = scf_value_get_as_string(val, NULL, 0);
14289 				if (buflen < 0)
14290 					scfdie();
14291 
14292 				buf = safe_malloc(buflen + 1);
14293 
14294 				if (scf_value_get_as_string(val, buf,
14295 				    buflen + 1) < 0)
14296 					scfdie();
14297 
14298 				if (first)
14299 					first = 0;
14300 				else {
14301 					if (putc(' ', strm) != ' ') {
14302 						warn(emsg_write_error,
14303 						    strerror(errno));
14304 						result = -1;
14305 						goto out;
14306 					}
14307 				}
14308 
14309 				if ((is_str && multiple) ||
14310 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14311 					(void) putc('"', strm);
14312 					(void) quote_and_print(buf, strm, 1);
14313 					(void) putc('"', strm);
14314 
14315 					if (ferror(strm)) {
14316 						warn(emsg_write_error,
14317 						    strerror(errno));
14318 						result = -1;
14319 						goto out;
14320 					}
14321 				} else {
14322 					if (fprintf(strm, "%s", buf) < 0) {
14323 						warn(emsg_write_error,
14324 						    strerror(errno));
14325 						result = -1;
14326 						goto out;
14327 					}
14328 				}
14329 
14330 				free(buf);
14331 			}
14332 			if (ret3 < 0 &&
14333 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14334 				scfdie();
14335 
14336 			/* Write closing paren if mult-value property */
14337 			if ((multiple && putc(')', strm) == EOF) ||
14338 
14339 			    /* Write final newline */
14340 			    fputc('\n', strm) == EOF) {
14341 				warn(emsg_write_error, strerror(errno));
14342 				result = -1;
14343 				goto out;
14344 			}
14345 		}
14346 		if (ret2 < 0)
14347 			scfdie();
14348 
14349 		if (fputc('\n', strm) == EOF) {
14350 			warn(emsg_write_error, strerror(errno));
14351 			result = -1;
14352 			goto out;
14353 		}
14354 	}
14355 	if (ret < 0)
14356 		scfdie();
14357 
14358 out:
14359 	free(pname);
14360 	free(tybuf);
14361 	free(buf);
14362 	scf_iter_destroy(viter);
14363 	scf_iter_destroy(piter);
14364 	scf_iter_destroy(iter);
14365 	scf_value_destroy(val);
14366 	scf_property_destroy(prop);
14367 	scf_pg_destroy(pg);
14368 
14369 	if (result == 0) {
14370 		if (fflush(strm) != 0) {
14371 			warn(emsg_write_error, strerror(errno));
14372 			return (-1);
14373 		}
14374 	}
14375 
14376 	return (result);
14377 }
14378 
14379 int
14380 lscf_editprop()
14381 {
14382 	char *buf, *editor;
14383 	size_t bufsz;
14384 	int tmpfd;
14385 	char tempname[] = TEMP_FILE_PATTERN;
14386 
14387 	lscf_prep_hndl();
14388 
14389 	if (cur_snap != NULL) {
14390 		semerr(emsg_cant_modify_snapshots);
14391 		return (-1);
14392 	}
14393 
14394 	if (cur_svc == NULL && cur_inst == NULL) {
14395 		semerr(emsg_entity_not_selected);
14396 		return (-1);
14397 	}
14398 
14399 	tmpfd = mkstemp(tempname);
14400 	if (tmpfd == -1) {
14401 		semerr(gettext("Could not create temporary file.\n"));
14402 		return (-1);
14403 	}
14404 
14405 	(void) strcpy(tempfilename, tempname);
14406 
14407 	tempfile = fdopen(tmpfd, "r+");
14408 	if (tempfile == NULL) {
14409 		warn(gettext("Could not create temporary file.\n"));
14410 		if (close(tmpfd) == -1)
14411 			warn(gettext("Could not close temporary file: %s.\n"),
14412 			    strerror(errno));
14413 
14414 		remove_tempfile();
14415 
14416 		return (-1);
14417 	}
14418 
14419 	if (write_edit_script(tempfile) == -1) {
14420 		remove_tempfile();
14421 		return (-1);
14422 	}
14423 
14424 	editor = getenv("EDITOR");
14425 	if (editor == NULL)
14426 		editor = "vi";
14427 
14428 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14429 	buf = safe_malloc(bufsz);
14430 
14431 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14432 		uu_die(gettext("Error creating editor command"));
14433 
14434 	if (system(buf) == -1) {
14435 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14436 		    strerror(errno));
14437 		free(buf);
14438 		remove_tempfile();
14439 		return (-1);
14440 	}
14441 
14442 	free(buf);
14443 
14444 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14445 
14446 	remove_tempfile();
14447 
14448 	return (0);
14449 }
14450 
14451 static void
14452 add_string(uu_list_t *strlist, const char *str)
14453 {
14454 	string_list_t *elem;
14455 	elem = safe_malloc(sizeof (*elem));
14456 	uu_list_node_init(elem, &elem->node, string_pool);
14457 	elem->str = safe_strdup(str);
14458 	if (uu_list_append(strlist, elem) != 0)
14459 		uu_die(gettext("libuutil error: %s\n"),
14460 		    uu_strerror(uu_error()));
14461 }
14462 
14463 static int
14464 remove_string(uu_list_t *strlist, const char *str)
14465 {
14466 	uu_list_walk_t	*elems;
14467 	string_list_t	*sp;
14468 
14469 	/*
14470 	 * Find the element that needs to be removed.
14471 	 */
14472 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14473 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14474 		if (strcmp(sp->str, str) == 0)
14475 			break;
14476 	}
14477 	uu_list_walk_end(elems);
14478 
14479 	/*
14480 	 * Returning 1 here as the value was not found, this
14481 	 * might not be an error.  Leave it to the caller to
14482 	 * decide.
14483 	 */
14484 	if (sp == NULL) {
14485 		return (1);
14486 	}
14487 
14488 	uu_list_remove(strlist, sp);
14489 
14490 	free(sp->str);
14491 	free(sp);
14492 
14493 	return (0);
14494 }
14495 
14496 /*
14497  * Get all property values that don't match the given glob pattern,
14498  * if a pattern is specified.
14499  */
14500 static void
14501 get_prop_values(scf_property_t *prop, uu_list_t *values,
14502     const char *pattern)
14503 {
14504 	scf_iter_t *iter;
14505 	scf_value_t *val;
14506 	int ret;
14507 
14508 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14509 	    (val = scf_value_create(g_hndl)) == NULL)
14510 		scfdie();
14511 
14512 	if (scf_iter_property_values(iter, prop) != 0)
14513 		scfdie();
14514 
14515 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14516 		char *buf;
14517 		ssize_t vlen, szret;
14518 
14519 		vlen = scf_value_get_as_string(val, NULL, 0);
14520 		if (vlen < 0)
14521 			scfdie();
14522 
14523 		buf = safe_malloc(vlen + 1);
14524 
14525 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14526 		if (szret < 0)
14527 			scfdie();
14528 		assert(szret <= vlen);
14529 
14530 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14531 			add_string(values, buf);
14532 
14533 		free(buf);
14534 	}
14535 
14536 	if (ret == -1)
14537 		scfdie();
14538 
14539 	scf_value_destroy(val);
14540 	scf_iter_destroy(iter);
14541 }
14542 
14543 static int
14544 lscf_setpropvalue(const char *pgname, const char *type,
14545     const char *arg, int isadd, int isnotfoundok)
14546 {
14547 	scf_type_t ty;
14548 	scf_propertygroup_t *pg;
14549 	scf_property_t *prop;
14550 	int ret, result = 0;
14551 	scf_transaction_t *tx;
14552 	scf_transaction_entry_t *e;
14553 	scf_value_t *v;
14554 	string_list_t *sp;
14555 	char *propname;
14556 	uu_list_t *values;
14557 	uu_list_walk_t *walk;
14558 	void *cookie = NULL;
14559 	char *pattern = NULL;
14560 
14561 	lscf_prep_hndl();
14562 
14563 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14564 		uu_die(gettext("Could not create property list: %s\n"),
14565 		    uu_strerror(uu_error()));
14566 
14567 	if (!isadd)
14568 		pattern = safe_strdup(arg);
14569 
14570 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14571 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14572 	    (prop = scf_property_create(g_hndl)) == NULL ||
14573 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14574 		scfdie();
14575 
14576 	if (cur_snap != NULL) {
14577 		semerr(emsg_cant_modify_snapshots);
14578 		goto fail;
14579 	}
14580 
14581 	if (cur_inst == NULL && cur_svc == NULL) {
14582 		semerr(emsg_entity_not_selected);
14583 		goto fail;
14584 	}
14585 
14586 	propname = strchr(pgname, '/');
14587 	if (propname == NULL) {
14588 		semerr(gettext("Property names must contain a `/'.\n"));
14589 		goto fail;
14590 	}
14591 
14592 	*propname = '\0';
14593 	++propname;
14594 
14595 	if (type != NULL) {
14596 		ty = string_to_type(type);
14597 		if (ty == SCF_TYPE_INVALID) {
14598 			semerr(gettext("Unknown type \"%s\".\n"), type);
14599 			goto fail;
14600 		}
14601 	}
14602 
14603 	if (cur_inst != NULL)
14604 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14605 	else
14606 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14607 	if (ret != 0) {
14608 		switch (scf_error()) {
14609 		case SCF_ERROR_NOT_FOUND:
14610 			if (isnotfoundok) {
14611 				result = 0;
14612 			} else {
14613 				semerr(emsg_no_such_pg, pgname);
14614 				result = -1;
14615 			}
14616 			goto out;
14617 
14618 		case SCF_ERROR_INVALID_ARGUMENT:
14619 			semerr(emsg_invalid_pg_name, pgname);
14620 			goto fail;
14621 
14622 		default:
14623 			scfdie();
14624 		}
14625 	}
14626 
14627 	do {
14628 		if (scf_pg_update(pg) == -1)
14629 			scfdie();
14630 		if (scf_transaction_start(tx, pg) != 0) {
14631 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14632 				scfdie();
14633 
14634 			semerr(emsg_permission_denied);
14635 			goto fail;
14636 		}
14637 
14638 		ret = scf_pg_get_property(pg, propname, prop);
14639 		if (ret == 0) {
14640 			scf_type_t ptype;
14641 			char *pat = pattern;
14642 
14643 			if (scf_property_type(prop, &ptype) != 0)
14644 				scfdie();
14645 
14646 			if (isadd) {
14647 				if (type != NULL && ptype != ty) {
14648 					semerr(gettext("Property \"%s\" is not "
14649 					    "of type \"%s\".\n"), propname,
14650 					    type);
14651 					goto fail;
14652 				}
14653 
14654 				pat = NULL;
14655 			} else {
14656 				size_t len = strlen(pat);
14657 				if (len > 0 && pat[len - 1] == '\"')
14658 					pat[len - 1] = '\0';
14659 				if (len > 0 && pat[0] == '\"')
14660 					pat++;
14661 			}
14662 
14663 			ty = ptype;
14664 
14665 			get_prop_values(prop, values, pat);
14666 
14667 			if (isadd)
14668 				add_string(values, arg);
14669 
14670 			if (scf_transaction_property_change(tx, e,
14671 			    propname, ty) == -1)
14672 				scfdie();
14673 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14674 			if (isadd) {
14675 				if (type == NULL) {
14676 					semerr(gettext("Type required "
14677 					    "for new properties.\n"));
14678 					goto fail;
14679 				}
14680 
14681 				add_string(values, arg);
14682 
14683 				if (scf_transaction_property_new(tx, e,
14684 				    propname, ty) == -1)
14685 					scfdie();
14686 			} else if (isnotfoundok) {
14687 				result = 0;
14688 				goto out;
14689 			} else {
14690 				semerr(gettext("No such property %s/%s.\n"),
14691 				    pgname, propname);
14692 				result = -1;
14693 				goto out;
14694 			}
14695 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14696 			semerr(emsg_invalid_prop_name, propname);
14697 			goto fail;
14698 		} else {
14699 			scfdie();
14700 		}
14701 
14702 		walk = uu_list_walk_start(values, UU_DEFAULT);
14703 		if (walk == NULL)
14704 			uu_die(gettext("Could not walk property list.\n"));
14705 
14706 		for (sp = uu_list_walk_next(walk); sp != NULL;
14707 		    sp = uu_list_walk_next(walk)) {
14708 			v = string_to_value(sp->str, ty, 0);
14709 
14710 			if (v == NULL) {
14711 				scf_entry_destroy_children(e);
14712 				goto fail;
14713 			}
14714 			ret = scf_entry_add_value(e, v);
14715 			assert(ret == 0);
14716 		}
14717 		uu_list_walk_end(walk);
14718 
14719 		result = scf_transaction_commit(tx);
14720 
14721 		scf_transaction_reset(tx);
14722 		scf_entry_destroy_children(e);
14723 	} while (result == 0);
14724 
14725 	if (result < 0) {
14726 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14727 			scfdie();
14728 
14729 		semerr(emsg_permission_denied);
14730 		goto fail;
14731 	}
14732 
14733 	result = 0;
14734 
14735 	private_refresh();
14736 
14737 out:
14738 	scf_transaction_destroy(tx);
14739 	scf_entry_destroy(e);
14740 	scf_pg_destroy(pg);
14741 	scf_property_destroy(prop);
14742 	free(pattern);
14743 
14744 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14745 		free(sp->str);
14746 		free(sp);
14747 	}
14748 
14749 	uu_list_destroy(values);
14750 
14751 	return (result);
14752 
14753 fail:
14754 	result = -1;
14755 	goto out;
14756 }
14757 
14758 int
14759 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14760 {
14761 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14762 }
14763 
14764 int
14765 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14766 {
14767 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14768 }
14769 
14770 /*
14771  * Look for a standard start method, first in the instance (if any),
14772  * then the service.
14773  */
14774 static const char *
14775 start_method_name(int *in_instance)
14776 {
14777 	scf_propertygroup_t *pg;
14778 	char **p;
14779 	int ret;
14780 	scf_instance_t *inst = cur_inst;
14781 
14782 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14783 		scfdie();
14784 
14785 again:
14786 	for (p = start_method_names; *p != NULL; p++) {
14787 		if (inst != NULL)
14788 			ret = scf_instance_get_pg(inst, *p, pg);
14789 		else
14790 			ret = scf_service_get_pg(cur_svc, *p, pg);
14791 
14792 		if (ret == 0) {
14793 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14794 			char *buf = safe_malloc(bufsz);
14795 
14796 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14797 				free(buf);
14798 				continue;
14799 			}
14800 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14801 				free(buf);
14802 				continue;
14803 			}
14804 
14805 			free(buf);
14806 			*in_instance = (inst != NULL);
14807 			scf_pg_destroy(pg);
14808 			return (*p);
14809 		}
14810 
14811 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14812 			continue;
14813 
14814 		scfdie();
14815 	}
14816 
14817 	if (inst != NULL) {
14818 		inst = NULL;
14819 		goto again;
14820 	}
14821 
14822 	scf_pg_destroy(pg);
14823 	return (NULL);
14824 }
14825 
14826 static int
14827 addpg(const char *name, const char *type)
14828 {
14829 	scf_propertygroup_t *pg;
14830 	int ret;
14831 
14832 	pg = scf_pg_create(g_hndl);
14833 	if (pg == NULL)
14834 		scfdie();
14835 
14836 	if (cur_inst != NULL)
14837 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14838 	else
14839 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14840 
14841 	if (ret != 0) {
14842 		switch (scf_error()) {
14843 		case SCF_ERROR_EXISTS:
14844 			ret = 0;
14845 			break;
14846 
14847 		case SCF_ERROR_PERMISSION_DENIED:
14848 			semerr(emsg_permission_denied);
14849 			break;
14850 
14851 		default:
14852 			scfdie();
14853 		}
14854 	}
14855 
14856 	scf_pg_destroy(pg);
14857 	return (ret);
14858 }
14859 
14860 int
14861 lscf_setenv(uu_list_t *args, int isunset)
14862 {
14863 	int ret = 0;
14864 	size_t i;
14865 	int argc;
14866 	char **argv = NULL;
14867 	string_list_t *slp;
14868 	char *pattern;
14869 	char *prop;
14870 	int do_service = 0;
14871 	int do_instance = 0;
14872 	const char *method = NULL;
14873 	const char *name = NULL;
14874 	const char *value = NULL;
14875 	scf_instance_t *saved_cur_inst = cur_inst;
14876 
14877 	lscf_prep_hndl();
14878 
14879 	argc = uu_list_numnodes(args);
14880 	if (argc < 1)
14881 		goto usage;
14882 
14883 	argv = calloc(argc + 1, sizeof (char *));
14884 	if (argv == NULL)
14885 		uu_die(gettext("Out of memory.\n"));
14886 
14887 	for (slp = uu_list_first(args), i = 0;
14888 	    slp != NULL;
14889 	    slp = uu_list_next(args, slp), ++i)
14890 		argv[i] = slp->str;
14891 
14892 	argv[i] = NULL;
14893 
14894 	opterr = 0;
14895 	optind = 0;
14896 	for (;;) {
14897 		ret = getopt(argc, argv, "sim:");
14898 		if (ret == -1)
14899 			break;
14900 
14901 		switch (ret) {
14902 		case 's':
14903 			do_service = 1;
14904 			cur_inst = NULL;
14905 			break;
14906 
14907 		case 'i':
14908 			do_instance = 1;
14909 			break;
14910 
14911 		case 'm':
14912 			method = optarg;
14913 			break;
14914 
14915 		case '?':
14916 			goto usage;
14917 
14918 		default:
14919 			bad_error("getopt", ret);
14920 		}
14921 	}
14922 
14923 	argc -= optind;
14924 	if ((do_service && do_instance) ||
14925 	    (isunset && argc != 1) ||
14926 	    (!isunset && argc != 2))
14927 		goto usage;
14928 
14929 	name = argv[optind];
14930 	if (!isunset)
14931 		value = argv[optind + 1];
14932 
14933 	if (cur_snap != NULL) {
14934 		semerr(emsg_cant_modify_snapshots);
14935 		ret = -1;
14936 		goto out;
14937 	}
14938 
14939 	if (cur_inst == NULL && cur_svc == NULL) {
14940 		semerr(emsg_entity_not_selected);
14941 		ret = -1;
14942 		goto out;
14943 	}
14944 
14945 	if (do_instance && cur_inst == NULL) {
14946 		semerr(gettext("No instance is selected.\n"));
14947 		ret = -1;
14948 		goto out;
14949 	}
14950 
14951 	if (do_service && cur_svc == NULL) {
14952 		semerr(gettext("No service is selected.\n"));
14953 		ret = -1;
14954 		goto out;
14955 	}
14956 
14957 	if (method == NULL) {
14958 		if (do_instance || do_service) {
14959 			method = "method_context";
14960 			if (!isunset) {
14961 				ret = addpg("method_context",
14962 				    SCF_GROUP_FRAMEWORK);
14963 				if (ret != 0)
14964 					goto out;
14965 			}
14966 		} else {
14967 			int in_instance;
14968 			method = start_method_name(&in_instance);
14969 			if (method == NULL) {
14970 				semerr(gettext(
14971 				    "Couldn't find start method; please "
14972 				    "specify a method with '-m'.\n"));
14973 				ret = -1;
14974 				goto out;
14975 			}
14976 			if (!in_instance)
14977 				cur_inst = NULL;
14978 		}
14979 	} else {
14980 		scf_propertygroup_t *pg;
14981 		size_t bufsz;
14982 		char *buf;
14983 		int ret;
14984 
14985 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14986 			scfdie();
14987 
14988 		if (cur_inst != NULL)
14989 			ret = scf_instance_get_pg(cur_inst, method, pg);
14990 		else
14991 			ret = scf_service_get_pg(cur_svc, method, pg);
14992 
14993 		if (ret != 0) {
14994 			scf_pg_destroy(pg);
14995 			switch (scf_error()) {
14996 			case SCF_ERROR_NOT_FOUND:
14997 				semerr(gettext("Couldn't find the method "
14998 				    "\"%s\".\n"), method);
14999 				goto out;
15000 
15001 			case SCF_ERROR_INVALID_ARGUMENT:
15002 				semerr(gettext("Invalid method name \"%s\".\n"),
15003 				    method);
15004 				goto out;
15005 
15006 			default:
15007 				scfdie();
15008 			}
15009 		}
15010 
15011 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
15012 		buf = safe_malloc(bufsz);
15013 
15014 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15015 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
15016 			semerr(gettext("Property group \"%s\" is not of type "
15017 			    "\"method\".\n"), method);
15018 			ret = -1;
15019 			free(buf);
15020 			scf_pg_destroy(pg);
15021 			goto out;
15022 		}
15023 
15024 		free(buf);
15025 		scf_pg_destroy(pg);
15026 	}
15027 
15028 	prop = uu_msprintf("%s/environment", method);
15029 	pattern = uu_msprintf("%s=*", name);
15030 
15031 	if (prop == NULL || pattern == NULL)
15032 		uu_die(gettext("Out of memory.\n"));
15033 
15034 	ret = lscf_delpropvalue(prop, pattern, !isunset);
15035 
15036 	if (ret == 0 && !isunset) {
15037 		uu_free(pattern);
15038 		uu_free(prop);
15039 		prop = uu_msprintf("%s/environment", method);
15040 		pattern = uu_msprintf("%s=%s", name, value);
15041 		if (prop == NULL || pattern == NULL)
15042 			uu_die(gettext("Out of memory.\n"));
15043 		ret = lscf_addpropvalue(prop, "astring:", pattern);
15044 	}
15045 	uu_free(pattern);
15046 	uu_free(prop);
15047 
15048 out:
15049 	cur_inst = saved_cur_inst;
15050 
15051 	free(argv);
15052 	return (ret);
15053 usage:
15054 	ret = -2;
15055 	goto out;
15056 }
15057 
15058 /*
15059  * Snapshot commands
15060  */
15061 
15062 void
15063 lscf_listsnap()
15064 {
15065 	scf_snapshot_t *snap;
15066 	scf_iter_t *iter;
15067 	char *nb;
15068 	int r;
15069 
15070 	lscf_prep_hndl();
15071 
15072 	if (cur_inst == NULL) {
15073 		semerr(gettext("Instance not selected.\n"));
15074 		return;
15075 	}
15076 
15077 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15078 	    (iter = scf_iter_create(g_hndl)) == NULL)
15079 		scfdie();
15080 
15081 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15082 		scfdie();
15083 
15084 	nb = safe_malloc(max_scf_name_len + 1);
15085 
15086 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15087 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15088 			scfdie();
15089 
15090 		(void) puts(nb);
15091 	}
15092 	if (r < 0)
15093 		scfdie();
15094 
15095 	free(nb);
15096 	scf_iter_destroy(iter);
15097 	scf_snapshot_destroy(snap);
15098 }
15099 
15100 void
15101 lscf_selectsnap(const char *name)
15102 {
15103 	scf_snapshot_t *snap;
15104 	scf_snaplevel_t *level;
15105 
15106 	lscf_prep_hndl();
15107 
15108 	if (cur_inst == NULL) {
15109 		semerr(gettext("Instance not selected.\n"));
15110 		return;
15111 	}
15112 
15113 	if (cur_snap != NULL) {
15114 		if (name != NULL) {
15115 			char *cur_snap_name;
15116 			boolean_t nochange;
15117 
15118 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
15119 
15120 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15121 			    max_scf_name_len + 1) < 0)
15122 				scfdie();
15123 
15124 			nochange = strcmp(name, cur_snap_name) == 0;
15125 
15126 			free(cur_snap_name);
15127 
15128 			if (nochange)
15129 				return;
15130 		}
15131 
15132 		unselect_cursnap();
15133 	}
15134 
15135 	if (name == NULL)
15136 		return;
15137 
15138 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15139 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
15140 		scfdie();
15141 
15142 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15143 	    SCF_SUCCESS) {
15144 		switch (scf_error()) {
15145 		case SCF_ERROR_INVALID_ARGUMENT:
15146 			semerr(gettext("Invalid name \"%s\".\n"), name);
15147 			break;
15148 
15149 		case SCF_ERROR_NOT_FOUND:
15150 			semerr(gettext("No such snapshot \"%s\".\n"), name);
15151 			break;
15152 
15153 		default:
15154 			scfdie();
15155 		}
15156 
15157 		scf_snaplevel_destroy(level);
15158 		scf_snapshot_destroy(snap);
15159 		return;
15160 	}
15161 
15162 	/* Load the snaplevels into our list. */
15163 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15164 	if (cur_levels == NULL)
15165 		uu_die(gettext("Could not create list: %s\n"),
15166 		    uu_strerror(uu_error()));
15167 
15168 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15169 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15170 			scfdie();
15171 
15172 		semerr(gettext("Snapshot has no snaplevels.\n"));
15173 
15174 		scf_snaplevel_destroy(level);
15175 		scf_snapshot_destroy(snap);
15176 		return;
15177 	}
15178 
15179 	cur_snap = snap;
15180 
15181 	for (;;) {
15182 		cur_elt = safe_malloc(sizeof (*cur_elt));
15183 		uu_list_node_init(cur_elt, &cur_elt->list_node,
15184 		    snaplevel_pool);
15185 		cur_elt->sl = level;
15186 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15187 			uu_die(gettext("libuutil error: %s\n"),
15188 			    uu_strerror(uu_error()));
15189 
15190 		level = scf_snaplevel_create(g_hndl);
15191 		if (level == NULL)
15192 			scfdie();
15193 
15194 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15195 		    level) != SCF_SUCCESS) {
15196 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15197 				scfdie();
15198 
15199 			scf_snaplevel_destroy(level);
15200 			break;
15201 		}
15202 	}
15203 
15204 	cur_elt = uu_list_last(cur_levels);
15205 	cur_level = cur_elt->sl;
15206 }
15207 
15208 /*
15209  * Copies the properties & values in src to dst.  Assumes src won't change.
15210  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15211  * and 0 on success.
15212  *
15213  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15214  * property, if it is copied and has type boolean.  (See comment in
15215  * lscf_revert()).
15216  */
15217 static int
15218 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15219     uint8_t enabled)
15220 {
15221 	scf_transaction_t *tx;
15222 	scf_iter_t *iter, *viter;
15223 	scf_property_t *prop;
15224 	scf_value_t *v;
15225 	char *nbuf;
15226 	int r;
15227 
15228 	tx = scf_transaction_create(g_hndl);
15229 	if (tx == NULL)
15230 		scfdie();
15231 
15232 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15233 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15234 			scfdie();
15235 
15236 		scf_transaction_destroy(tx);
15237 
15238 		return (-1);
15239 	}
15240 
15241 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
15242 	    (prop = scf_property_create(g_hndl)) == NULL ||
15243 	    (viter = scf_iter_create(g_hndl)) == NULL)
15244 		scfdie();
15245 
15246 	nbuf = safe_malloc(max_scf_name_len + 1);
15247 
15248 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15249 		scfdie();
15250 
15251 	for (;;) {
15252 		scf_transaction_entry_t *e;
15253 		scf_type_t ty;
15254 
15255 		r = scf_iter_next_property(iter, prop);
15256 		if (r == -1)
15257 			scfdie();
15258 		if (r == 0)
15259 			break;
15260 
15261 		e = scf_entry_create(g_hndl);
15262 		if (e == NULL)
15263 			scfdie();
15264 
15265 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15266 			scfdie();
15267 
15268 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15269 			scfdie();
15270 
15271 		if (scf_transaction_property_new(tx, e, nbuf,
15272 		    ty) != SCF_SUCCESS)
15273 			scfdie();
15274 
15275 		if ((enabled == 0 || enabled == 1) &&
15276 		    strcmp(nbuf, scf_property_enabled) == 0 &&
15277 		    ty == SCF_TYPE_BOOLEAN) {
15278 			v = scf_value_create(g_hndl);
15279 			if (v == NULL)
15280 				scfdie();
15281 
15282 			scf_value_set_boolean(v, enabled);
15283 
15284 			if (scf_entry_add_value(e, v) != 0)
15285 				scfdie();
15286 		} else {
15287 			if (scf_iter_property_values(viter, prop) != 0)
15288 				scfdie();
15289 
15290 			for (;;) {
15291 				v = scf_value_create(g_hndl);
15292 				if (v == NULL)
15293 					scfdie();
15294 
15295 				r = scf_iter_next_value(viter, v);
15296 				if (r == -1)
15297 					scfdie();
15298 				if (r == 0) {
15299 					scf_value_destroy(v);
15300 					break;
15301 				}
15302 
15303 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15304 					scfdie();
15305 			}
15306 		}
15307 	}
15308 
15309 	free(nbuf);
15310 	scf_iter_destroy(viter);
15311 	scf_property_destroy(prop);
15312 	scf_iter_destroy(iter);
15313 
15314 	r = scf_transaction_commit(tx);
15315 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15316 		scfdie();
15317 
15318 	scf_transaction_destroy_children(tx);
15319 	scf_transaction_destroy(tx);
15320 
15321 	switch (r) {
15322 	case 1:		return (0);
15323 	case 0:		return (-2);
15324 	case -1:	return (-1);
15325 
15326 	default:
15327 		abort();
15328 	}
15329 
15330 	/* NOTREACHED */
15331 }
15332 
15333 void
15334 lscf_revert(const char *snapname)
15335 {
15336 	scf_snapshot_t *snap, *prev;
15337 	scf_snaplevel_t *level, *nlevel;
15338 	scf_iter_t *iter;
15339 	scf_propertygroup_t *pg, *npg;
15340 	scf_property_t *prop;
15341 	scf_value_t *val;
15342 	char *nbuf, *tbuf;
15343 	uint8_t enabled;
15344 
15345 	lscf_prep_hndl();
15346 
15347 	if (cur_inst == NULL) {
15348 		semerr(gettext("Instance not selected.\n"));
15349 		return;
15350 	}
15351 
15352 	if (snapname != NULL) {
15353 		snap = scf_snapshot_create(g_hndl);
15354 		if (snap == NULL)
15355 			scfdie();
15356 
15357 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15358 		    SCF_SUCCESS) {
15359 			switch (scf_error()) {
15360 			case SCF_ERROR_INVALID_ARGUMENT:
15361 				semerr(gettext("Invalid snapshot name "
15362 				    "\"%s\".\n"), snapname);
15363 				break;
15364 
15365 			case SCF_ERROR_NOT_FOUND:
15366 				semerr(gettext("No such snapshot.\n"));
15367 				break;
15368 
15369 			default:
15370 				scfdie();
15371 			}
15372 
15373 			scf_snapshot_destroy(snap);
15374 			return;
15375 		}
15376 	} else {
15377 		if (cur_snap != NULL) {
15378 			snap = cur_snap;
15379 		} else {
15380 			semerr(gettext("No snapshot selected.\n"));
15381 			return;
15382 		}
15383 	}
15384 
15385 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15386 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15387 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15388 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15389 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15390 	    (prop = scf_property_create(g_hndl)) == NULL ||
15391 	    (val = scf_value_create(g_hndl)) == NULL)
15392 		scfdie();
15393 
15394 	nbuf = safe_malloc(max_scf_name_len + 1);
15395 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15396 
15397 	/* Take the "previous" snapshot before we blow away the properties. */
15398 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15399 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15400 			scfdie();
15401 	} else {
15402 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15403 			scfdie();
15404 
15405 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15406 			scfdie();
15407 	}
15408 
15409 	/* Save general/enabled, since we're probably going to replace it. */
15410 	enabled = 2;
15411 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15412 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15413 	    scf_property_get_value(prop, val) == 0)
15414 		(void) scf_value_get_boolean(val, &enabled);
15415 
15416 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15417 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15418 			scfdie();
15419 
15420 		goto out;
15421 	}
15422 
15423 	for (;;) {
15424 		boolean_t isinst;
15425 		uint32_t flags;
15426 		int r;
15427 
15428 		/* Clear the properties from the corresponding entity. */
15429 		isinst = snaplevel_is_instance(level);
15430 
15431 		if (!isinst)
15432 			r = scf_iter_service_pgs(iter, cur_svc);
15433 		else
15434 			r = scf_iter_instance_pgs(iter, cur_inst);
15435 		if (r != SCF_SUCCESS)
15436 			scfdie();
15437 
15438 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15439 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15440 				scfdie();
15441 
15442 			/* Skip nonpersistent pgs. */
15443 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15444 				continue;
15445 
15446 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15447 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15448 					scfdie();
15449 
15450 				semerr(emsg_permission_denied);
15451 				goto out;
15452 			}
15453 		}
15454 		if (r == -1)
15455 			scfdie();
15456 
15457 		/* Copy the properties to the corresponding entity. */
15458 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15459 			scfdie();
15460 
15461 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15462 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15463 				scfdie();
15464 
15465 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15466 			    0)
15467 				scfdie();
15468 
15469 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15470 				scfdie();
15471 
15472 			if (!isinst)
15473 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15474 				    flags, npg);
15475 			else
15476 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15477 				    flags, npg);
15478 			if (r != SCF_SUCCESS) {
15479 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15480 					scfdie();
15481 
15482 				semerr(emsg_permission_denied);
15483 				goto out;
15484 			}
15485 
15486 			if ((enabled == 0 || enabled == 1) &&
15487 			    strcmp(nbuf, scf_pg_general) == 0)
15488 				r = pg_copy(pg, npg, enabled);
15489 			else
15490 				r = pg_copy(pg, npg, 2);
15491 
15492 			switch (r) {
15493 			case 0:
15494 				break;
15495 
15496 			case -1:
15497 				semerr(emsg_permission_denied);
15498 				goto out;
15499 
15500 			case -2:
15501 				semerr(gettext(
15502 				    "Interrupted by another change.\n"));
15503 				goto out;
15504 
15505 			default:
15506 				abort();
15507 			}
15508 		}
15509 		if (r == -1)
15510 			scfdie();
15511 
15512 		/* Get next level. */
15513 		nlevel = scf_snaplevel_create(g_hndl);
15514 		if (nlevel == NULL)
15515 			scfdie();
15516 
15517 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15518 		    SCF_SUCCESS) {
15519 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15520 				scfdie();
15521 
15522 			scf_snaplevel_destroy(nlevel);
15523 			break;
15524 		}
15525 
15526 		scf_snaplevel_destroy(level);
15527 		level = nlevel;
15528 	}
15529 
15530 	if (snapname == NULL) {
15531 		lscf_selectsnap(NULL);
15532 		snap = NULL;		/* cur_snap has been destroyed */
15533 	}
15534 
15535 out:
15536 	free(tbuf);
15537 	free(nbuf);
15538 	scf_value_destroy(val);
15539 	scf_property_destroy(prop);
15540 	scf_pg_destroy(npg);
15541 	scf_pg_destroy(pg);
15542 	scf_iter_destroy(iter);
15543 	scf_snaplevel_destroy(level);
15544 	scf_snapshot_destroy(prev);
15545 	if (snap != cur_snap)
15546 		scf_snapshot_destroy(snap);
15547 }
15548 
15549 void
15550 lscf_refresh(void)
15551 {
15552 	ssize_t fmrilen;
15553 	size_t bufsz;
15554 	char *fmribuf;
15555 	int r;
15556 
15557 	lscf_prep_hndl();
15558 
15559 	if (cur_inst == NULL) {
15560 		semerr(gettext("Instance not selected.\n"));
15561 		return;
15562 	}
15563 
15564 	bufsz = max_scf_fmri_len + 1;
15565 	fmribuf = safe_malloc(bufsz);
15566 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15567 	if (fmrilen < 0) {
15568 		free(fmribuf);
15569 		if (scf_error() != SCF_ERROR_DELETED)
15570 			scfdie();
15571 		scf_instance_destroy(cur_inst);
15572 		cur_inst = NULL;
15573 		warn(emsg_deleted);
15574 		return;
15575 	}
15576 	assert(fmrilen < bufsz);
15577 
15578 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15579 	switch (r) {
15580 	case 0:
15581 		break;
15582 
15583 	case ECONNABORTED:
15584 		warn(gettext("Could not refresh %s "
15585 		    "(repository connection broken).\n"), fmribuf);
15586 		break;
15587 
15588 	case ECANCELED:
15589 		warn(emsg_deleted);
15590 		break;
15591 
15592 	case EPERM:
15593 		warn(gettext("Could not refresh %s "
15594 		    "(permission denied).\n"), fmribuf);
15595 		break;
15596 
15597 	case ENOSPC:
15598 		warn(gettext("Could not refresh %s "
15599 		    "(repository server out of resources).\n"),
15600 		    fmribuf);
15601 		break;
15602 
15603 	case EACCES:
15604 	default:
15605 		bad_error("refresh_entity", scf_error());
15606 	}
15607 
15608 	free(fmribuf);
15609 }
15610 
15611 /*
15612  * describe [-v] [-t] [pg/prop]
15613  */
15614 int
15615 lscf_describe(uu_list_t *args, int hasargs)
15616 {
15617 	int ret = 0;
15618 	size_t i;
15619 	int argc;
15620 	char **argv = NULL;
15621 	string_list_t *slp;
15622 	int do_verbose = 0;
15623 	int do_templates = 0;
15624 	char *pattern = NULL;
15625 
15626 	lscf_prep_hndl();
15627 
15628 	if (hasargs != 0)  {
15629 		argc = uu_list_numnodes(args);
15630 		if (argc < 1)
15631 			goto usage;
15632 
15633 		argv = calloc(argc + 1, sizeof (char *));
15634 		if (argv == NULL)
15635 			uu_die(gettext("Out of memory.\n"));
15636 
15637 		for (slp = uu_list_first(args), i = 0;
15638 		    slp != NULL;
15639 		    slp = uu_list_next(args, slp), ++i)
15640 			argv[i] = slp->str;
15641 
15642 		argv[i] = NULL;
15643 
15644 		/*
15645 		 * We start optind = 0 because our list of arguments
15646 		 * starts at argv[0]
15647 		 */
15648 		optind = 0;
15649 		opterr = 0;
15650 		for (;;) {
15651 			ret = getopt(argc, argv, "vt");
15652 			if (ret == -1)
15653 				break;
15654 
15655 			switch (ret) {
15656 			case 'v':
15657 				do_verbose = 1;
15658 				break;
15659 
15660 			case 't':
15661 				do_templates = 1;
15662 				break;
15663 
15664 			case '?':
15665 				goto usage;
15666 
15667 			default:
15668 				bad_error("getopt", ret);
15669 			}
15670 		}
15671 
15672 		pattern = argv[optind];
15673 	}
15674 
15675 	if (cur_inst == NULL && cur_svc == NULL) {
15676 		semerr(emsg_entity_not_selected);
15677 		ret = -1;
15678 		goto out;
15679 	}
15680 
15681 	/*
15682 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15683 	 * output if their last parameter is set to 2.  Less information is
15684 	 * produced if the parameter is set to 1.
15685 	 */
15686 	if (pattern == NULL) {
15687 		if (do_verbose == 1)
15688 			list_entity_tmpl(2);
15689 		else
15690 			list_entity_tmpl(1);
15691 	}
15692 
15693 	if (do_templates == 0) {
15694 		if (do_verbose == 1)
15695 			listprop(pattern, 0, 2);
15696 		else
15697 			listprop(pattern, 0, 1);
15698 	} else {
15699 		if (do_verbose == 1)
15700 			listtmpl(pattern, 2);
15701 		else
15702 			listtmpl(pattern, 1);
15703 	}
15704 
15705 	ret = 0;
15706 out:
15707 	if (argv != NULL)
15708 		free(argv);
15709 	return (ret);
15710 usage:
15711 	ret = -2;
15712 	goto out;
15713 }
15714 
15715 #define	PARAM_ACTIVE	((const char *) "active")
15716 #define	PARAM_INACTIVE	((const char *) "inactive")
15717 #define	PARAM_SMTP_TO	((const char *) "to")
15718 
15719 /*
15720  * tokenize()
15721  * Breaks down the string according to the tokens passed.
15722  * Caller is responsible for freeing array of pointers returned.
15723  * Returns NULL on failure
15724  */
15725 char **
15726 tokenize(char *str, const char *sep)
15727 {
15728 	char *token, *lasts;
15729 	char **buf;
15730 	int n = 0;	/* number of elements */
15731 	int size = 8;	/* size of the array (initial) */
15732 
15733 	buf = safe_malloc(size * sizeof (char *));
15734 
15735 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15736 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15737 		if (n + 1 >= size) {
15738 			size *= 2;
15739 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15740 			    NULL) {
15741 				uu_die(gettext("Out of memory"));
15742 			}
15743 		}
15744 		buf[n] = token;
15745 	}
15746 	/* NULL terminate the pointer array */
15747 	buf[n] = NULL;
15748 
15749 	return (buf);
15750 }
15751 
15752 int32_t
15753 check_tokens(char **p)
15754 {
15755 	int32_t smf = 0;
15756 	int32_t fma = 0;
15757 
15758 	while (*p) {
15759 		int32_t t = string_to_tset(*p);
15760 
15761 		if (t == 0) {
15762 			if (is_fma_token(*p) == 0)
15763 				return (INVALID_TOKENS);
15764 			fma = 1; /* this token is an fma event */
15765 		} else {
15766 			smf |= t;
15767 		}
15768 
15769 		if (smf != 0 && fma == 1)
15770 			return (MIXED_TOKENS);
15771 		++p;
15772 	}
15773 
15774 	if (smf > 0)
15775 		return (smf);
15776 	else if (fma == 1)
15777 		return (FMA_TOKENS);
15778 
15779 	return (INVALID_TOKENS);
15780 }
15781 
15782 static int
15783 get_selection_str(char *fmri, size_t sz)
15784 {
15785 	if (g_hndl == NULL) {
15786 		semerr(emsg_entity_not_selected);
15787 		return (-1);
15788 	} else if (cur_level != NULL) {
15789 		semerr(emsg_invalid_for_snapshot);
15790 		return (-1);
15791 	} else {
15792 		lscf_get_selection_str(fmri, sz);
15793 	}
15794 
15795 	return (0);
15796 }
15797 
15798 void
15799 lscf_delnotify(const char *set, int global)
15800 {
15801 	char *str = strdup(set);
15802 	char **pgs;
15803 	char **p;
15804 	int32_t tset;
15805 	char *fmri = NULL;
15806 
15807 	if (str == NULL)
15808 		uu_die(gettext("Out of memory.\n"));
15809 
15810 	pgs = tokenize(str, ",");
15811 
15812 	if ((tset = check_tokens(pgs)) > 0) {
15813 		size_t sz = max_scf_fmri_len + 1;
15814 
15815 		fmri = safe_malloc(sz);
15816 		if (global) {
15817 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15818 		} else if (get_selection_str(fmri, sz) != 0) {
15819 			goto out;
15820 		}
15821 
15822 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15823 		    tset) != SCF_SUCCESS) {
15824 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15825 			    scf_strerror(scf_error()));
15826 		}
15827 	} else if (tset == FMA_TOKENS) {
15828 		if (global) {
15829 			semerr(gettext("Can't use option '-g' with FMA event "
15830 			    "definitions\n"));
15831 			goto out;
15832 		}
15833 
15834 		for (p = pgs; *p; ++p) {
15835 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15836 			    SCF_SUCCESS) {
15837 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15838 				    scf_strerror(scf_error()));
15839 				goto out;
15840 			}
15841 		}
15842 	} else if (tset == MIXED_TOKENS) {
15843 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15844 		goto out;
15845 	} else {
15846 		uu_die(gettext("Invalid input.\n"));
15847 	}
15848 
15849 out:
15850 	free(fmri);
15851 	free(pgs);
15852 	free(str);
15853 }
15854 
15855 void
15856 lscf_listnotify(const char *set, int global)
15857 {
15858 	char *str = safe_strdup(set);
15859 	char **pgs;
15860 	char **p;
15861 	int32_t tset;
15862 	nvlist_t *nvl;
15863 	char *fmri = NULL;
15864 
15865 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15866 		uu_die(gettext("Out of memory.\n"));
15867 
15868 	pgs = tokenize(str, ",");
15869 
15870 	if ((tset = check_tokens(pgs)) > 0) {
15871 		size_t sz = max_scf_fmri_len + 1;
15872 
15873 		fmri = safe_malloc(sz);
15874 		if (global) {
15875 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15876 		} else if (get_selection_str(fmri, sz) != 0) {
15877 			goto out;
15878 		}
15879 
15880 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15881 		    SCF_SUCCESS) {
15882 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15883 			    scf_error() != SCF_ERROR_DELETED)
15884 				uu_warn(gettext(
15885 				    "Failed listnotify: %s\n"),
15886 				    scf_strerror(scf_error()));
15887 			goto out;
15888 		}
15889 
15890 		listnotify_print(nvl, NULL);
15891 	} else if (tset == FMA_TOKENS) {
15892 		if (global) {
15893 			semerr(gettext("Can't use option '-g' with FMA event "
15894 			    "definitions\n"));
15895 			goto out;
15896 		}
15897 
15898 		for (p = pgs; *p; ++p) {
15899 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15900 			    SCF_SUCCESS) {
15901 				/*
15902 				 * if the preferences have just been deleted
15903 				 * or does not exist, just skip.
15904 				 */
15905 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15906 				    scf_error() == SCF_ERROR_DELETED)
15907 					continue;
15908 				uu_warn(gettext(
15909 				    "Failed listnotify: %s\n"),
15910 				    scf_strerror(scf_error()));
15911 				goto out;
15912 			}
15913 			listnotify_print(nvl, re_tag(*p));
15914 		}
15915 	} else if (tset == MIXED_TOKENS) {
15916 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15917 		goto out;
15918 	} else {
15919 		semerr(gettext("Invalid input.\n"));
15920 	}
15921 
15922 out:
15923 	nvlist_free(nvl);
15924 	free(fmri);
15925 	free(pgs);
15926 	free(str);
15927 }
15928 
15929 static char *
15930 strip_quotes_and_blanks(char *s)
15931 {
15932 	char *start = s;
15933 	char *end = strrchr(s, '\"');
15934 
15935 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15936 		start = s + 1;
15937 		while (isblank(*start))
15938 			start++;
15939 		while (isblank(*(end - 1)) && end > start) {
15940 			end--;
15941 		}
15942 		*end = '\0';
15943 	}
15944 
15945 	return (start);
15946 }
15947 
15948 static int
15949 set_active(nvlist_t *mech, const char *hier_part)
15950 {
15951 	boolean_t b;
15952 
15953 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15954 		b = B_TRUE;
15955 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15956 		b = B_FALSE;
15957 	} else {
15958 		return (-1);
15959 	}
15960 
15961 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15962 		uu_die(gettext("Out of memory.\n"));
15963 
15964 	return (0);
15965 }
15966 
15967 static int
15968 add_snmp_params(nvlist_t *mech, char *hier_part)
15969 {
15970 	return (set_active(mech, hier_part));
15971 }
15972 
15973 static int
15974 add_syslog_params(nvlist_t *mech, char *hier_part)
15975 {
15976 	return (set_active(mech, hier_part));
15977 }
15978 
15979 /*
15980  * add_mailto_paramas()
15981  * parse the hier_part of mailto URI
15982  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15983  * or mailto:{[active]|inactive}
15984  */
15985 static int
15986 add_mailto_params(nvlist_t *mech, char *hier_part)
15987 {
15988 	const char *tok = "?&";
15989 	char *p;
15990 	char *lasts;
15991 	char *param;
15992 	char *val;
15993 
15994 	/*
15995 	 * If the notification parametes are in the form of
15996 	 *
15997 	 *   malito:{[active]|inactive}
15998 	 *
15999 	 * we set the property accordingly and return.
16000 	 * Otherwise, we make the notification type active and
16001 	 * process the hier_part.
16002 	 */
16003 	if (set_active(mech, hier_part) == 0)
16004 		return (0);
16005 	else if (set_active(mech, PARAM_ACTIVE) != 0)
16006 		return (-1);
16007 
16008 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16009 		/*
16010 		 * sanity check: we only get here if hier_part = "", but
16011 		 * that's handled by set_active
16012 		 */
16013 		uu_die("strtok_r");
16014 	}
16015 
16016 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16017 		uu_die(gettext("Out of memory.\n"));
16018 
16019 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16020 		if ((param = strtok_r(p, "=", &val)) != NULL)
16021 			if (nvlist_add_string(mech, param, val) != 0)
16022 				uu_die(gettext("Out of memory.\n"));
16023 
16024 	return (0);
16025 }
16026 
16027 static int
16028 uri_split(char *uri, char **scheme, char **hier_part)
16029 {
16030 	int r = -1;
16031 
16032 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16033 	    *hier_part == NULL) {
16034 		semerr(gettext("'%s' is not an URI\n"), uri);
16035 		return (r);
16036 	}
16037 
16038 	if ((r = check_uri_scheme(*scheme)) < 0) {
16039 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16040 		return (r);
16041 	}
16042 
16043 	return (r);
16044 }
16045 
16046 static int
16047 process_uri(nvlist_t *params, char *uri)
16048 {
16049 	char *scheme;
16050 	char *hier_part;
16051 	nvlist_t *mech;
16052 	int index;
16053 	int r;
16054 
16055 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16056 		return (-1);
16057 
16058 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16059 		uu_die(gettext("Out of memory.\n"));
16060 
16061 	switch (index) {
16062 	case 0:
16063 		/* error messages displayed by called function */
16064 		r = add_mailto_params(mech, hier_part);
16065 		break;
16066 
16067 	case 1:
16068 		if ((r = add_snmp_params(mech, hier_part)) != 0)
16069 			semerr(gettext("Not valid parameters: '%s'\n"),
16070 			    hier_part);
16071 		break;
16072 
16073 	case 2:
16074 		if ((r = add_syslog_params(mech, hier_part)) != 0)
16075 			semerr(gettext("Not valid parameters: '%s'\n"),
16076 			    hier_part);
16077 		break;
16078 
16079 	default:
16080 		r = -1;
16081 	}
16082 
16083 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16084 	    mech) != 0)
16085 		uu_die(gettext("Out of memory.\n"));
16086 
16087 	nvlist_free(mech);
16088 	return (r);
16089 }
16090 
16091 static int
16092 set_params(nvlist_t *params, char **p)
16093 {
16094 	char *uri;
16095 
16096 	if (p == NULL)
16097 		/* sanity check */
16098 		uu_die("set_params");
16099 
16100 	while (*p) {
16101 		uri = strip_quotes_and_blanks(*p);
16102 		if (process_uri(params, uri) != 0)
16103 			return (-1);
16104 
16105 		++p;
16106 	}
16107 
16108 	return (0);
16109 }
16110 
16111 static int
16112 setnotify(const char *e, char **p, int global)
16113 {
16114 	char *str = safe_strdup(e);
16115 	char **events;
16116 	int32_t tset;
16117 	int r = -1;
16118 	nvlist_t *nvl, *params;
16119 	char *fmri = NULL;
16120 
16121 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16122 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16123 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16124 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
16125 		uu_die(gettext("Out of memory.\n"));
16126 
16127 	events = tokenize(str, ",");
16128 
16129 	if ((tset = check_tokens(events)) > 0) {
16130 		/* SMF state transitions parameters */
16131 		size_t sz = max_scf_fmri_len + 1;
16132 
16133 		fmri = safe_malloc(sz);
16134 		if (global) {
16135 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16136 		} else if (get_selection_str(fmri, sz) != 0) {
16137 			goto out;
16138 		}
16139 
16140 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16141 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16142 			uu_die(gettext("Out of memory.\n"));
16143 
16144 		if ((r = set_params(params, p)) == 0) {
16145 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16146 			    params) != 0)
16147 				uu_die(gettext("Out of memory.\n"));
16148 
16149 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16150 			    nvl) != SCF_SUCCESS) {
16151 				r = -1;
16152 				uu_warn(gettext(
16153 				    "Failed smf_notify_set_params(3SCF): %s\n"),
16154 				    scf_strerror(scf_error()));
16155 			}
16156 		}
16157 	} else if (tset == FMA_TOKENS) {
16158 		/* FMA event parameters */
16159 		if (global) {
16160 			semerr(gettext("Can't use option '-g' with FMA event "
16161 			    "definitions\n"));
16162 			goto out;
16163 		}
16164 
16165 		if ((r = set_params(params, p)) != 0)
16166 			goto out;
16167 
16168 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16169 			uu_die(gettext("Out of memory.\n"));
16170 
16171 		while (*events) {
16172 			if (smf_notify_set_params(de_tag(*events), nvl) !=
16173 			    SCF_SUCCESS)
16174 				uu_warn(gettext(
16175 				    "Failed smf_notify_set_params(3SCF) for "
16176 				    "event %s: %s\n"), *events,
16177 				    scf_strerror(scf_error()));
16178 			events++;
16179 		}
16180 	} else if (tset == MIXED_TOKENS) {
16181 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16182 	} else {
16183 		/* Sanity check */
16184 		uu_die(gettext("Invalid input.\n"));
16185 	}
16186 
16187 out:
16188 	nvlist_free(nvl);
16189 	nvlist_free(params);
16190 	free(fmri);
16191 	free(str);
16192 
16193 	return (r);
16194 }
16195 
16196 int
16197 lscf_setnotify(uu_list_t *args)
16198 {
16199 	int argc;
16200 	char **argv = NULL;
16201 	string_list_t *slp;
16202 	int global;
16203 	char *events;
16204 	char **p;
16205 	int i;
16206 	int ret;
16207 
16208 	if ((argc = uu_list_numnodes(args)) < 2)
16209 		goto usage;
16210 
16211 	argv = calloc(argc + 1, sizeof (char *));
16212 	if (argv == NULL)
16213 		uu_die(gettext("Out of memory.\n"));
16214 
16215 	for (slp = uu_list_first(args), i = 0;
16216 	    slp != NULL;
16217 	    slp = uu_list_next(args, slp), ++i)
16218 		argv[i] = slp->str;
16219 
16220 	argv[i] = NULL;
16221 
16222 	if (strcmp(argv[0], "-g") == 0) {
16223 		global = 1;
16224 		events = argv[1];
16225 		p = argv + 2;
16226 	} else {
16227 		global = 0;
16228 		events = argv[0];
16229 		p = argv + 1;
16230 	}
16231 
16232 	ret = setnotify(events, p, global);
16233 
16234 out:
16235 	free(argv);
16236 	return (ret);
16237 
16238 usage:
16239 	ret = -2;
16240 	goto out;
16241 }
16242 
16243 /*
16244  * Creates a list of instance name strings associated with a service. If
16245  * wohandcrafted flag is set, get only instances that have a last-import
16246  * snapshot, instances that were imported via svccfg.
16247  */
16248 static uu_list_t *
16249 create_instance_list(scf_service_t *svc, int wohandcrafted)
16250 {
16251 	scf_snapshot_t  *snap = NULL;
16252 	scf_instance_t  *inst;
16253 	scf_iter_t	*inst_iter;
16254 	uu_list_t	*instances;
16255 	char		*instname;
16256 	int		r;
16257 
16258 	inst_iter = scf_iter_create(g_hndl);
16259 	inst = scf_instance_create(g_hndl);
16260 	if (inst_iter == NULL || inst == NULL) {
16261 		uu_warn(gettext("Could not create instance or iterator\n"));
16262 		scfdie();
16263 	}
16264 
16265 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16266 		return (instances);
16267 
16268 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
16269 		switch (scf_error()) {
16270 		case SCF_ERROR_CONNECTION_BROKEN:
16271 		case SCF_ERROR_DELETED:
16272 			uu_list_destroy(instances);
16273 			instances = NULL;
16274 			goto out;
16275 
16276 		case SCF_ERROR_HANDLE_MISMATCH:
16277 		case SCF_ERROR_NOT_BOUND:
16278 		case SCF_ERROR_NOT_SET:
16279 		default:
16280 			bad_error("scf_iter_service_instances", scf_error());
16281 		}
16282 	}
16283 
16284 	instname = safe_malloc(max_scf_name_len + 1);
16285 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16286 		if (r == -1) {
16287 			(void) uu_warn(gettext("Unable to iterate through "
16288 			    "instances to create instance list : %s\n"),
16289 			    scf_strerror(scf_error()));
16290 
16291 			uu_list_destroy(instances);
16292 			instances = NULL;
16293 			goto out;
16294 		}
16295 
16296 		/*
16297 		 * If the instance does not have a last-import snapshot
16298 		 * then do not add it to the list as it is a hand-crafted
16299 		 * instance that should not be managed.
16300 		 */
16301 		if (wohandcrafted) {
16302 			if (snap == NULL &&
16303 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
16304 				uu_warn(gettext("Unable to create snapshot "
16305 				    "entity\n"));
16306 				scfdie();
16307 			}
16308 
16309 			if (scf_instance_get_snapshot(inst,
16310 			    snap_lastimport, snap) != 0) {
16311 				switch (scf_error()) {
16312 				case SCF_ERROR_NOT_FOUND :
16313 				case SCF_ERROR_DELETED:
16314 					continue;
16315 
16316 				case SCF_ERROR_CONNECTION_BROKEN:
16317 					uu_list_destroy(instances);
16318 					instances = NULL;
16319 					goto out;
16320 
16321 				case SCF_ERROR_HANDLE_MISMATCH:
16322 				case SCF_ERROR_NOT_BOUND:
16323 				case SCF_ERROR_NOT_SET:
16324 				default:
16325 					bad_error("scf_iter_service_instances",
16326 					    scf_error());
16327 				}
16328 			}
16329 		}
16330 
16331 		if (scf_instance_get_name(inst, instname,
16332 		    max_scf_name_len + 1) < 0) {
16333 			switch (scf_error()) {
16334 			case SCF_ERROR_NOT_FOUND :
16335 				continue;
16336 
16337 			case SCF_ERROR_CONNECTION_BROKEN:
16338 			case SCF_ERROR_DELETED:
16339 				uu_list_destroy(instances);
16340 				instances = NULL;
16341 				goto out;
16342 
16343 			case SCF_ERROR_HANDLE_MISMATCH:
16344 			case SCF_ERROR_NOT_BOUND:
16345 			case SCF_ERROR_NOT_SET:
16346 			default:
16347 				bad_error("scf_iter_service_instances",
16348 				    scf_error());
16349 			}
16350 		}
16351 
16352 		add_string(instances, instname);
16353 	}
16354 
16355 out:
16356 	if (snap)
16357 		scf_snapshot_destroy(snap);
16358 
16359 	scf_instance_destroy(inst);
16360 	scf_iter_destroy(inst_iter);
16361 	free(instname);
16362 	return (instances);
16363 }
16364 
16365 /*
16366  * disable an instance but wait for the instance to
16367  * move out of the running state.
16368  *
16369  * Returns 0 : if the instance did not disable
16370  * Returns non-zero : if the instance disabled.
16371  *
16372  */
16373 static int
16374 disable_instance(scf_instance_t *instance)
16375 {
16376 	char	*fmribuf;
16377 	int	enabled = 10000;
16378 
16379 	if (inst_is_running(instance)) {
16380 		fmribuf = safe_malloc(max_scf_name_len + 1);
16381 		if (scf_instance_to_fmri(instance, fmribuf,
16382 		    max_scf_name_len + 1) < 0) {
16383 			free(fmribuf);
16384 			return (0);
16385 		}
16386 
16387 		/*
16388 		 * If the instance cannot be disabled then return
16389 		 * failure to disable and let the caller decide
16390 		 * if that is of importance.
16391 		 */
16392 		if (smf_disable_instance(fmribuf, 0) != 0) {
16393 			free(fmribuf);
16394 			return (0);
16395 		}
16396 
16397 		while (enabled) {
16398 			if (!inst_is_running(instance))
16399 				break;
16400 
16401 			(void) poll(NULL, 0, 5);
16402 			enabled = enabled - 5;
16403 		}
16404 
16405 		free(fmribuf);
16406 	}
16407 
16408 	return (enabled);
16409 }
16410 
16411 /*
16412  * Function to compare two service_manifest structures.
16413  */
16414 /* ARGSUSED2 */
16415 static int
16416 service_manifest_compare(const void *left, const void *right, void *unused)
16417 {
16418 	service_manifest_t *l = (service_manifest_t *)left;
16419 	service_manifest_t *r = (service_manifest_t *)right;
16420 	int rc;
16421 
16422 	rc = strcmp(l->servicename, r->servicename);
16423 
16424 	return (rc);
16425 }
16426 
16427 /*
16428  * Look for the provided service in the service to manifest
16429  * tree.  If the service exists, and a manifest was provided
16430  * then add the manifest to that service.  If the service
16431  * does not exist, then add the service and manifest to the
16432  * list.
16433  *
16434  * If the manifest is NULL, return the element if found.  If
16435  * the service is not found return NULL.
16436  */
16437 service_manifest_t *
16438 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16439 {
16440 	service_manifest_t	elem;
16441 	service_manifest_t	*fnelem;
16442 	uu_avl_index_t		marker;
16443 
16444 	elem.servicename = svnbuf;
16445 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16446 
16447 	if (mfst) {
16448 		if (fnelem) {
16449 			add_string(fnelem->mfstlist, strdup(mfst));
16450 		} else {
16451 			fnelem = safe_malloc(sizeof (*fnelem));
16452 			fnelem->servicename = safe_strdup(svnbuf);
16453 			if ((fnelem->mfstlist =
16454 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16455 				uu_die(gettext("Could not create property "
16456 				    "list: %s\n"), uu_strerror(uu_error()));
16457 
16458 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16459 
16460 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16461 		}
16462 	}
16463 
16464 	return (fnelem);
16465 }
16466 
16467 /*
16468  * Create the service to manifest avl tree.
16469  *
16470  * Walk each of the manifests currently installed in the supported
16471  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16472  * each of the manifests, inventory the services and add them to
16473  * the tree.
16474  *
16475  * Code that calls this function should make sure fileystem/minimal is online,
16476  * /var is available, since this function walks the /var/svc/manifest directory.
16477  */
16478 static void
16479 create_manifest_tree(void)
16480 {
16481 	manifest_info_t **entry;
16482 	manifest_info_t **manifests;
16483 	uu_list_walk_t	*svcs;
16484 	bundle_t	*b;
16485 	entity_t	*mfsvc;
16486 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16487 	int		c, status;
16488 
16489 	if (service_manifest_pool)
16490 		return;
16491 
16492 	/*
16493 	 * Create the list pool for the service manifest list
16494 	 */
16495 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16496 	    sizeof (service_manifest_t),
16497 	    offsetof(service_manifest_t, svcmfst_node),
16498 	    service_manifest_compare, UU_DEFAULT);
16499 	if (service_manifest_pool == NULL)
16500 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16501 		    uu_strerror(uu_error()));
16502 
16503 	/*
16504 	 * Create the list
16505 	 */
16506 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16507 	    UU_DEFAULT);
16508 	if (service_manifest_tree == NULL)
16509 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16510 		    uu_strerror(uu_error()));
16511 
16512 	/*
16513 	 * Walk the manifests adding the service(s) from each manifest.
16514 	 *
16515 	 * If a service already exists add the manifest to the manifest
16516 	 * list for that service.  This covers the case of a service that
16517 	 * is supported by multiple manifest files.
16518 	 */
16519 	for (c = 0; dirs[c]; c++) {
16520 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16521 		if (status < 0) {
16522 			uu_warn(gettext("file tree walk of %s encountered "
16523 			    "error %s\n"), dirs[c], strerror(errno));
16524 
16525 			uu_avl_destroy(service_manifest_tree);
16526 			service_manifest_tree = NULL;
16527 			return;
16528 		}
16529 
16530 		/*
16531 		 * If a manifest that was in the list is not found
16532 		 * then skip and go to the next manifest file.
16533 		 */
16534 		if (manifests != NULL) {
16535 			for (entry = manifests; *entry != NULL; entry++) {
16536 				b = internal_bundle_new();
16537 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16538 				    SVCCFG_OP_IMPORT) != 0) {
16539 					internal_bundle_free(b);
16540 					continue;
16541 				}
16542 
16543 				svcs = uu_list_walk_start(b->sc_bundle_services,
16544 				    0);
16545 				if (svcs == NULL) {
16546 					internal_bundle_free(b);
16547 					continue;
16548 				}
16549 
16550 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16551 				    NULL) {
16552 					/* Add manifest to service */
16553 					(void) find_add_svc_mfst(mfsvc->sc_name,
16554 					    (*entry)->mi_path);
16555 				}
16556 
16557 				uu_list_walk_end(svcs);
16558 				internal_bundle_free(b);
16559 			}
16560 
16561 			free_manifest_array(manifests);
16562 		}
16563 	}
16564 }
16565 
16566 /*
16567  * Check the manifest history file to see
16568  * if the service was ever installed from
16569  * one of the supported directories.
16570  *
16571  * Return Values :
16572  *	-1 - if there's error reading manifest history file
16573  *	 1 - if the service is not found
16574  *	 0 - if the service is found
16575  */
16576 static int
16577 check_mfst_history(const char *svcname)
16578 {
16579 	struct stat	st;
16580 	caddr_t		mfsthist_start;
16581 	char		*svnbuf;
16582 	int		fd;
16583 	int		r = 1;
16584 
16585 	fd = open(MFSTHISTFILE, O_RDONLY);
16586 	if (fd == -1) {
16587 		uu_warn(gettext("Unable to open the history file\n"));
16588 		return (-1);
16589 	}
16590 
16591 	if (fstat(fd, &st) == -1) {
16592 		uu_warn(gettext("Unable to stat the history file\n"));
16593 		return (-1);
16594 	}
16595 
16596 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16597 	    MAP_PRIVATE, fd, 0);
16598 
16599 	(void) close(fd);
16600 	if (mfsthist_start == MAP_FAILED ||
16601 	    *(mfsthist_start + st.st_size) != '\0') {
16602 		(void) munmap(mfsthist_start, st.st_size);
16603 		return (-1);
16604 	}
16605 
16606 	/*
16607 	 * The manifest history file is a space delimited list
16608 	 * of service and instance to manifest linkage.  Adding
16609 	 * a space to the end of the service name so to get only
16610 	 * the service that is being searched for.
16611 	 */
16612 	svnbuf = uu_msprintf("%s ", svcname);
16613 	if (svnbuf == NULL)
16614 		uu_die(gettext("Out of memory"));
16615 
16616 	if (strstr(mfsthist_start, svnbuf) != NULL)
16617 		r = 0;
16618 
16619 	(void) munmap(mfsthist_start, st.st_size);
16620 	uu_free(svnbuf);
16621 	return (r);
16622 }
16623 
16624 /*
16625  * Take down each of the instances in the service
16626  * and remove them, then delete the service.
16627  */
16628 static void
16629 teardown_service(scf_service_t *svc, const char *svnbuf)
16630 {
16631 	scf_instance_t	*instance;
16632 	scf_iter_t	*iter;
16633 	int		r;
16634 
16635 	safe_printf(gettext("Delete service %s as there are no "
16636 	    "supporting manifests\n"), svnbuf);
16637 
16638 	instance = scf_instance_create(g_hndl);
16639 	iter = scf_iter_create(g_hndl);
16640 	if (iter == NULL || instance == NULL) {
16641 		uu_warn(gettext("Unable to create supporting entities to "
16642 		    "teardown the service\n"));
16643 		uu_warn(gettext("scf error is : %s\n"),
16644 		    scf_strerror(scf_error()));
16645 		scfdie();
16646 	}
16647 
16648 	if (scf_iter_service_instances(iter, svc) != 0) {
16649 		switch (scf_error()) {
16650 		case SCF_ERROR_CONNECTION_BROKEN:
16651 		case SCF_ERROR_DELETED:
16652 			goto out;
16653 
16654 		case SCF_ERROR_HANDLE_MISMATCH:
16655 		case SCF_ERROR_NOT_BOUND:
16656 		case SCF_ERROR_NOT_SET:
16657 		default:
16658 			bad_error("scf_iter_service_instances",
16659 			    scf_error());
16660 		}
16661 	}
16662 
16663 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16664 		if (r == -1) {
16665 			uu_warn(gettext("Error - %s\n"),
16666 			    scf_strerror(scf_error()));
16667 			goto out;
16668 		}
16669 
16670 		(void) disable_instance(instance);
16671 	}
16672 
16673 	/*
16674 	 * Delete the service... forcing the deletion in case
16675 	 * any of the instances did not disable.
16676 	 */
16677 	(void) lscf_service_delete(svc, 1);
16678 out:
16679 	scf_instance_destroy(instance);
16680 	scf_iter_destroy(iter);
16681 }
16682 
16683 /*
16684  * Get the list of instances supported by the manifest
16685  * file.
16686  *
16687  * Return 0 if there are no instances.
16688  *
16689  * Return -1 if there are errors attempting to collect instances.
16690  *
16691  * Return the count of instances found if there are no errors.
16692  *
16693  */
16694 static int
16695 check_instance_support(char *mfstfile, const char *svcname,
16696     uu_list_t *instances)
16697 {
16698 	uu_list_walk_t	*svcs, *insts;
16699 	uu_list_t	*ilist;
16700 	bundle_t	*b;
16701 	entity_t	*mfsvc, *mfinst;
16702 	const char	*svcn;
16703 	int		rminstcnt = 0;
16704 
16705 
16706 	b = internal_bundle_new();
16707 
16708 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16709 		/*
16710 		 * Unable to process the manifest file for
16711 		 * instance support, so just return as
16712 		 * don't want to remove instances that could
16713 		 * not be accounted for that might exist here.
16714 		 */
16715 		internal_bundle_free(b);
16716 		return (0);
16717 	}
16718 
16719 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16720 	if (svcs == NULL) {
16721 		internal_bundle_free(b);
16722 		return (0);
16723 	}
16724 
16725 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16726 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16727 
16728 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16729 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16730 			break;
16731 	}
16732 	uu_list_walk_end(svcs);
16733 
16734 	if (mfsvc == NULL) {
16735 		internal_bundle_free(b);
16736 		return (-1);
16737 	}
16738 
16739 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16740 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16741 		internal_bundle_free(b);
16742 		return (0);
16743 	}
16744 
16745 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16746 		/*
16747 		 * Remove the instance from the instances list.
16748 		 * The unaccounted for instances will be removed
16749 		 * from the service once all manifests are
16750 		 * processed.
16751 		 */
16752 		(void) remove_string(instances,
16753 		    mfinst->sc_name);
16754 		rminstcnt++;
16755 	}
16756 
16757 	uu_list_walk_end(insts);
16758 	internal_bundle_free(b);
16759 
16760 	return (rminstcnt);
16761 }
16762 
16763 /*
16764  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16765  * 'false' to indicate there's no manifest file(s) found for the service.
16766  */
16767 static void
16768 svc_add_no_support(scf_service_t *svc)
16769 {
16770 	char	*pname;
16771 
16772 	/* Add no support */
16773 	cur_svc = svc;
16774 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16775 		return;
16776 
16777 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16778 	if (pname == NULL)
16779 		uu_die(gettext("Out of memory.\n"));
16780 
16781 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16782 
16783 	uu_free(pname);
16784 	cur_svc = NULL;
16785 }
16786 
16787 /*
16788  * This function handles all upgrade scenarios for a service that doesn't have
16789  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16790  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16791  * manifest(s) mapping. Manifests under supported directories are inventoried
16792  * and a property is added for each file that delivers configuration to the
16793  * service.  A service that has no corresponding manifest files (deleted) are
16794  * removed from repository.
16795  *
16796  * Unsupported services:
16797  *
16798  * A service is considered unsupported if there is no corresponding manifest
16799  * in the supported directories for that service and the service isn't in the
16800  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16801  * services and instances that were delivered by Solaris before the introduction
16802  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16803  * the path to the manifest file that defined the service or instance.
16804  *
16805  * Another type of unsupported services is 'handcrafted' services,
16806  * programmatically created services or services created by dependent entries
16807  * in other manifests. A handcrafted service is identified by its lack of any
16808  * instance containing last-import snapshot which is created during svccfg
16809  * import.
16810  *
16811  * This function sets a flag for unsupported services by setting services'
16812  * SCF_PG_MANIFESTFILES/support property to false.
16813  */
16814 static void
16815 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16816 {
16817 	service_manifest_t	*elem;
16818 	uu_list_walk_t		*mfwalk;
16819 	string_list_t		*mfile;
16820 	uu_list_t		*instances;
16821 	const char		*sname;
16822 	char			*pname;
16823 	int			r;
16824 
16825 	/*
16826 	 * Since there's no guarantee manifests under /var are available during
16827 	 * early import, don't perform any upgrade during early import.
16828 	 */
16829 	if (IGNORE_VAR)
16830 		return;
16831 
16832 	if (service_manifest_tree == NULL) {
16833 		create_manifest_tree();
16834 	}
16835 
16836 	/*
16837 	 * Find service's supporting manifest(s) after
16838 	 * stripping off the svc:/ prefix that is part
16839 	 * of the fmri that is not used in the service
16840 	 * manifest bundle list.
16841 	 */
16842 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16843 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16844 	elem = find_add_svc_mfst(sname, NULL);
16845 	if (elem == NULL) {
16846 
16847 		/*
16848 		 * A handcrafted service, one that has no instance containing
16849 		 * last-import snapshot, should get unsupported flag.
16850 		 */
16851 		instances = create_instance_list(svc, 1);
16852 		if (instances == NULL) {
16853 			uu_warn(gettext("Unable to create instance list %s\n"),
16854 			    svcname);
16855 			return;
16856 		}
16857 
16858 		if (uu_list_numnodes(instances) == 0) {
16859 			svc_add_no_support(svc);
16860 			return;
16861 		}
16862 
16863 		/*
16864 		 * If the service is in the history file, and its supporting
16865 		 * manifests are not found, we can safely delete the service
16866 		 * because its manifests are removed from the system.
16867 		 *
16868 		 * Services not found in the history file are not delivered by
16869 		 * Solaris and/or delivered outside supported directories, set
16870 		 * unsupported flag for these services.
16871 		 */
16872 		r = check_mfst_history(svcname);
16873 		if (r == -1)
16874 			return;
16875 
16876 		if (r) {
16877 			/* Set unsupported flag for service  */
16878 			svc_add_no_support(svc);
16879 		} else {
16880 			/* Delete the service */
16881 			teardown_service(svc, svcname);
16882 		}
16883 
16884 		return;
16885 	}
16886 
16887 	/*
16888 	 * Walk through the list of manifests and add them
16889 	 * to the service.
16890 	 *
16891 	 * Create a manifestfiles pg and add the property.
16892 	 */
16893 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16894 	if (mfwalk == NULL)
16895 		return;
16896 
16897 	cur_svc = svc;
16898 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16899 	if (r != 0) {
16900 		cur_svc = NULL;
16901 		return;
16902 	}
16903 
16904 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16905 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16906 		    mhash_filename_to_propname(mfile->str, 0));
16907 		if (pname == NULL)
16908 			uu_die(gettext("Out of memory.\n"));
16909 
16910 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16911 		uu_free(pname);
16912 	}
16913 	uu_list_walk_end(mfwalk);
16914 
16915 	cur_svc = NULL;
16916 }
16917 
16918 /*
16919  * Take a service and process the manifest file entires to see if
16920  * there is continued support for the service and instances.  If
16921  * not cleanup as appropriate.
16922  *
16923  * If a service does not have a manifest files entry flag it for
16924  * upgrade and return.
16925  *
16926  * For each manifestfiles property check if the manifest file is
16927  * under the supported /lib/svc/manifest or /var/svc/manifest path
16928  * and if not then return immediately as this service is not supported
16929  * by the cleanup mechanism and should be ignored.
16930  *
16931  * For each manifest file that is supported, check to see if the
16932  * file exists.  If not then remove the manifest file property
16933  * from the service and the smf/manifest hash table.  If the manifest
16934  * file exists then verify that it supports the instances that are
16935  * part of the service.
16936  *
16937  * Once all manifest files have been accounted for remove any instances
16938  * that are no longer supported in the service.
16939  *
16940  * Return values :
16941  * 0 - Successfully processed the service
16942  * non-zero - failed to process the service
16943  *
16944  * On most errors, will just return to wait and get the next service,
16945  * unless in case of unable to create the needed structures which is
16946  * most likely a fatal error that is not going to be recoverable.
16947  */
16948 int
16949 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16950 {
16951 	struct mpg_mfile	*mpntov = NULL;
16952 	struct mpg_mfile	**mpvarry = NULL;
16953 	scf_service_t		*svc;
16954 	scf_propertygroup_t	*mpg;
16955 	scf_property_t		*mp;
16956 	scf_value_t		*mv;
16957 	scf_iter_t		*mi;
16958 	scf_instance_t		*instance;
16959 	uu_list_walk_t		*insts;
16960 	uu_list_t		*instances = NULL;
16961 	boolean_t		activity = (boolean_t)act;
16962 	char			*mpnbuf = NULL;
16963 	char			*mpvbuf = NULL;
16964 	char			*pgpropbuf;
16965 	int			mfstcnt, rminstct, instct, mfstmax;
16966 	int			index;
16967 	int			r = 0;
16968 
16969 	assert(g_hndl != NULL);
16970 	assert(wip->svc != NULL);
16971 	assert(wip->fmri != NULL);
16972 
16973 	svc = wip->svc;
16974 
16975 	mpg = scf_pg_create(g_hndl);
16976 	mp = scf_property_create(g_hndl);
16977 	mi = scf_iter_create(g_hndl);
16978 	mv = scf_value_create(g_hndl);
16979 	instance = scf_instance_create(g_hndl);
16980 
16981 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16982 	    instance == NULL) {
16983 		uu_warn(gettext("Unable to create the supporting entities\n"));
16984 		uu_warn(gettext("scf error is : %s\n"),
16985 		    scf_strerror(scf_error()));
16986 		scfdie();
16987 	}
16988 
16989 	/*
16990 	 * Get the manifestfiles property group to be parsed for
16991 	 * files existence.
16992 	 */
16993 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16994 		switch (scf_error()) {
16995 		case SCF_ERROR_NOT_FOUND:
16996 			upgrade_svc_mfst_connection(svc, wip->fmri);
16997 			break;
16998 		case SCF_ERROR_DELETED:
16999 		case SCF_ERROR_CONNECTION_BROKEN:
17000 			goto out;
17001 
17002 		case SCF_ERROR_HANDLE_MISMATCH:
17003 		case SCF_ERROR_NOT_BOUND:
17004 		case SCF_ERROR_NOT_SET:
17005 		default:
17006 			bad_error("scf_iter_pg_properties",
17007 			    scf_error());
17008 		}
17009 
17010 		goto out;
17011 	}
17012 
17013 	/*
17014 	 * Iterate through each of the manifestfiles properties
17015 	 * to determine what manifestfiles are available.
17016 	 *
17017 	 * If a manifest file is supported then increment the
17018 	 * count and therefore the service is safe.
17019 	 */
17020 	if (scf_iter_pg_properties(mi, mpg) != 0) {
17021 		switch (scf_error()) {
17022 		case SCF_ERROR_DELETED:
17023 		case SCF_ERROR_CONNECTION_BROKEN:
17024 			goto out;
17025 
17026 		case SCF_ERROR_HANDLE_MISMATCH:
17027 		case SCF_ERROR_NOT_BOUND:
17028 		case SCF_ERROR_NOT_SET:
17029 		default:
17030 			bad_error("scf_iter_pg_properties",
17031 			    scf_error());
17032 		}
17033 	}
17034 
17035 	mfstcnt = 0;
17036 	mfstmax = MFSTFILE_MAX;
17037 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17038 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
17039 		if (r == -1)
17040 			bad_error(gettext("Unable to iterate through "
17041 			    "manifestfiles properties : %s"),
17042 			    scf_error());
17043 
17044 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
17045 		mpnbuf = safe_malloc(max_scf_name_len + 1);
17046 		mpvbuf = safe_malloc(max_scf_value_len + 1);
17047 		mpntov->mpg = mpnbuf;
17048 		mpntov->mfile = mpvbuf;
17049 		mpntov->access = 1;
17050 		if (scf_property_get_name(mp, mpnbuf,
17051 		    max_scf_name_len + 1) < 0) {
17052 			uu_warn(gettext("Unable to get manifest file "
17053 			    "property : %s\n"),
17054 			    scf_strerror(scf_error()));
17055 
17056 			switch (scf_error()) {
17057 			case SCF_ERROR_DELETED:
17058 			case SCF_ERROR_CONNECTION_BROKEN:
17059 				r = scferror2errno(scf_error());
17060 				goto out_free;
17061 
17062 			case SCF_ERROR_HANDLE_MISMATCH:
17063 			case SCF_ERROR_NOT_BOUND:
17064 			case SCF_ERROR_NOT_SET:
17065 			default:
17066 				bad_error("scf_iter_pg_properties",
17067 				    scf_error());
17068 			}
17069 		}
17070 
17071 		/*
17072 		 * The support property is a boolean value that indicates
17073 		 * if the service is supported for manifest file deletion.
17074 		 * Currently at this time there is no code that sets this
17075 		 * value to true.  So while we could just let this be caught
17076 		 * by the support check below, in the future this by be set
17077 		 * to true and require processing.  So for that, go ahead
17078 		 * and check here, and just return if false.  Otherwise,
17079 		 * fall through expecting that other support checks will
17080 		 * handle the entries.
17081 		 */
17082 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17083 			uint8_t	support;
17084 
17085 			if (scf_property_get_value(mp, mv) != 0 ||
17086 			    scf_value_get_boolean(mv, &support) != 0) {
17087 				uu_warn(gettext("Unable to get the manifest "
17088 				    "support value: %s\n"),
17089 				    scf_strerror(scf_error()));
17090 
17091 				switch (scf_error()) {
17092 				case SCF_ERROR_DELETED:
17093 				case SCF_ERROR_CONNECTION_BROKEN:
17094 					r = scferror2errno(scf_error());
17095 					goto out_free;
17096 
17097 				case SCF_ERROR_HANDLE_MISMATCH:
17098 				case SCF_ERROR_NOT_BOUND:
17099 				case SCF_ERROR_NOT_SET:
17100 				default:
17101 					bad_error("scf_iter_pg_properties",
17102 					    scf_error());
17103 				}
17104 			}
17105 
17106 			if (support == B_FALSE)
17107 				goto out_free;
17108 		}
17109 
17110 		/*
17111 		 * Anything with a manifest outside of the supported
17112 		 * directories, immediately bail out because that makes
17113 		 * this service non-supported.  We don't even want
17114 		 * to do instance processing in this case because the
17115 		 * instances could be part of the non-supported manifest.
17116 		 */
17117 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17118 			/*
17119 			 * Manifest is not in /lib/svc, so we need to
17120 			 * consider the /var/svc case.
17121 			 */
17122 			if (strncmp(mpnbuf, VARSVC_PR,
17123 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17124 				/*
17125 				 * Either the manifest is not in /var/svc or
17126 				 * /var is not yet mounted.  We ignore the
17127 				 * manifest either because it is not in a
17128 				 * standard location or because we cannot
17129 				 * currently access the manifest.
17130 				 */
17131 				goto out_free;
17132 			}
17133 		}
17134 
17135 		/*
17136 		 * Get the value to of the manifest file for this entry
17137 		 * for access verification and instance support
17138 		 * verification if it still exists.
17139 		 *
17140 		 * During Early Manifest Import if the manifest is in
17141 		 * /var/svc then it may not yet be available for checking
17142 		 * so we must determine if /var/svc is available.  If not
17143 		 * then defer until Late Manifest Import to cleanup.
17144 		 */
17145 		if (scf_property_get_value(mp, mv) != 0) {
17146 			uu_warn(gettext("Unable to get the manifest file "
17147 			    "value: %s\n"),
17148 			    scf_strerror(scf_error()));
17149 
17150 			switch (scf_error()) {
17151 			case SCF_ERROR_DELETED:
17152 			case SCF_ERROR_CONNECTION_BROKEN:
17153 				r = scferror2errno(scf_error());
17154 				goto out_free;
17155 
17156 			case SCF_ERROR_HANDLE_MISMATCH:
17157 			case SCF_ERROR_NOT_BOUND:
17158 			case SCF_ERROR_NOT_SET:
17159 			default:
17160 				bad_error("scf_property_get_value",
17161 				    scf_error());
17162 			}
17163 		}
17164 
17165 		if (scf_value_get_astring(mv, mpvbuf,
17166 		    max_scf_value_len + 1) < 0) {
17167 			uu_warn(gettext("Unable to get the manifest "
17168 			    "file : %s\n"),
17169 			    scf_strerror(scf_error()));
17170 
17171 			switch (scf_error()) {
17172 			case SCF_ERROR_DELETED:
17173 			case SCF_ERROR_CONNECTION_BROKEN:
17174 				r = scferror2errno(scf_error());
17175 				goto out_free;
17176 
17177 			case SCF_ERROR_HANDLE_MISMATCH:
17178 			case SCF_ERROR_NOT_BOUND:
17179 			case SCF_ERROR_NOT_SET:
17180 			default:
17181 				bad_error("scf_value_get_astring",
17182 				    scf_error());
17183 			}
17184 		}
17185 
17186 		mpvarry[mfstcnt] = mpntov;
17187 		mfstcnt++;
17188 
17189 		/*
17190 		 * Check for the need to reallocate array
17191 		 */
17192 		if (mfstcnt >= (mfstmax - 1)) {
17193 			struct mpg_mfile **newmpvarry;
17194 
17195 			mfstmax = mfstmax * 2;
17196 			newmpvarry = realloc(mpvarry,
17197 			    sizeof (struct mpg_mfile *) * mfstmax);
17198 
17199 			if (newmpvarry == NULL)
17200 				goto out_free;
17201 
17202 			mpvarry = newmpvarry;
17203 		}
17204 
17205 		mpvarry[mfstcnt] = NULL;
17206 	}
17207 
17208 	for (index = 0; mpvarry[index]; index++) {
17209 		mpntov = mpvarry[index];
17210 
17211 		/*
17212 		 * Check to see if the manifestfile is accessable, if so hand
17213 		 * this service and manifestfile off to be processed for
17214 		 * instance support.
17215 		 */
17216 		mpnbuf = mpntov->mpg;
17217 		mpvbuf = mpntov->mfile;
17218 		if (access(mpvbuf, F_OK) != 0) {
17219 			mpntov->access = 0;
17220 			activity++;
17221 			mfstcnt--;
17222 			/* Remove the entry from the service */
17223 			cur_svc = svc;
17224 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17225 			    mpnbuf);
17226 			if (pgpropbuf == NULL)
17227 				uu_die(gettext("Out of memory.\n"));
17228 
17229 			lscf_delprop(pgpropbuf);
17230 			cur_svc = NULL;
17231 
17232 			uu_free(pgpropbuf);
17233 		}
17234 	}
17235 
17236 	/*
17237 	 * If mfstcnt is 0, none of the manifests that supported the service
17238 	 * existed so remove the service.
17239 	 */
17240 	if (mfstcnt == 0) {
17241 		teardown_service(svc, wip->fmri);
17242 
17243 		goto out_free;
17244 	}
17245 
17246 	if (activity) {
17247 		int	nosvcsupport = 0;
17248 
17249 		/*
17250 		 * If the list of service instances is NULL then
17251 		 * create the list.
17252 		 */
17253 		instances = create_instance_list(svc, 1);
17254 		if (instances == NULL) {
17255 			uu_warn(gettext("Unable to create instance list %s\n"),
17256 			    wip->fmri);
17257 			goto out_free;
17258 		}
17259 
17260 		rminstct = uu_list_numnodes(instances);
17261 		instct = rminstct;
17262 
17263 		for (index = 0; mpvarry[index]; index++) {
17264 			mpntov = mpvarry[index];
17265 			if (mpntov->access == 0)
17266 				continue;
17267 
17268 			mpnbuf = mpntov->mpg;
17269 			mpvbuf = mpntov->mfile;
17270 			r = check_instance_support(mpvbuf, wip->fmri,
17271 			    instances);
17272 			if (r == -1) {
17273 				nosvcsupport++;
17274 			} else {
17275 				rminstct -= r;
17276 			}
17277 		}
17278 
17279 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17280 			teardown_service(svc, wip->fmri);
17281 
17282 			goto out_free;
17283 		}
17284 	}
17285 
17286 	/*
17287 	 * If there are instances left on the instance list, then
17288 	 * we must remove them.
17289 	 */
17290 	if (instances != NULL && uu_list_numnodes(instances)) {
17291 		string_list_t *sp;
17292 
17293 		insts = uu_list_walk_start(instances, 0);
17294 		while ((sp = uu_list_walk_next(insts)) != NULL) {
17295 			/*
17296 			 * Remove the instance from the instances list.
17297 			 */
17298 			safe_printf(gettext("Delete instance %s from "
17299 			    "service %s\n"), sp->str, wip->fmri);
17300 			if (scf_service_get_instance(svc, sp->str,
17301 			    instance) != SCF_SUCCESS) {
17302 				(void) uu_warn("scf_error - %s\n",
17303 				    scf_strerror(scf_error()));
17304 
17305 				continue;
17306 			}
17307 
17308 			(void) disable_instance(instance);
17309 
17310 			(void) lscf_instance_delete(instance, 1);
17311 		}
17312 		scf_instance_destroy(instance);
17313 		uu_list_walk_end(insts);
17314 	}
17315 
17316 out_free:
17317 	if (mpvarry) {
17318 		struct mpg_mfile *fmpntov;
17319 
17320 		for (index = 0; mpvarry[index]; index++) {
17321 			fmpntov  = mpvarry[index];
17322 			if (fmpntov->mpg == mpnbuf)
17323 				mpnbuf = NULL;
17324 			free(fmpntov->mpg);
17325 
17326 			if (fmpntov->mfile == mpvbuf)
17327 				mpvbuf = NULL;
17328 			free(fmpntov->mfile);
17329 
17330 			if (fmpntov == mpntov)
17331 				mpntov = NULL;
17332 			free(fmpntov);
17333 		}
17334 		if (mpnbuf)
17335 			free(mpnbuf);
17336 		if (mpvbuf)
17337 			free(mpvbuf);
17338 		if (mpntov)
17339 			free(mpntov);
17340 
17341 		free(mpvarry);
17342 	}
17343 out:
17344 	scf_pg_destroy(mpg);
17345 	scf_property_destroy(mp);
17346 	scf_iter_destroy(mi);
17347 	scf_value_destroy(mv);
17348 
17349 	return (0);
17350 }
17351 
17352 /*
17353  * Take the service and search for the manifestfiles property
17354  * in each of the property groups.  If the manifest file
17355  * associated with the property does not exist then remove
17356  * the property group.
17357  */
17358 int
17359 lscf_hash_cleanup()
17360 {
17361 	scf_service_t		*svc;
17362 	scf_scope_t		*scope;
17363 	scf_propertygroup_t	*pg;
17364 	scf_property_t		*prop;
17365 	scf_value_t		*val;
17366 	scf_iter_t		*iter;
17367 	char			*pgname = NULL;
17368 	char			*mfile = NULL;
17369 	int			r;
17370 
17371 	svc = scf_service_create(g_hndl);
17372 	scope = scf_scope_create(g_hndl);
17373 	pg = scf_pg_create(g_hndl);
17374 	prop = scf_property_create(g_hndl);
17375 	val = scf_value_create(g_hndl);
17376 	iter = scf_iter_create(g_hndl);
17377 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17378 	    svc == NULL || scope == NULL) {
17379 		uu_warn(gettext("Unable to create a property group, or "
17380 		    "property\n"));
17381 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17382 		    "pg is not NULL");
17383 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17384 		    "prop is not NULL");
17385 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17386 		    "val is not NULL");
17387 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17388 		    "iter is not NULL");
17389 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17390 		    "svc is not NULL");
17391 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17392 		    "scope is not NULL");
17393 		uu_warn(gettext("scf error is : %s\n"),
17394 		    scf_strerror(scf_error()));
17395 		scfdie();
17396 	}
17397 
17398 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17399 		switch (scf_error()) {
17400 		case SCF_ERROR_CONNECTION_BROKEN:
17401 		case SCF_ERROR_NOT_FOUND:
17402 			goto out;
17403 
17404 		case SCF_ERROR_HANDLE_MISMATCH:
17405 		case SCF_ERROR_NOT_BOUND:
17406 		case SCF_ERROR_INVALID_ARGUMENT:
17407 		default:
17408 			bad_error("scf_handle_get_scope", scf_error());
17409 		}
17410 	}
17411 
17412 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17413 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17414 		    HASH_SVC);
17415 		goto out;
17416 	}
17417 
17418 	pgname = safe_malloc(max_scf_name_len + 1);
17419 	mfile = safe_malloc(max_scf_value_len + 1);
17420 
17421 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17422 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17423 		    scf_strerror(scf_error()));
17424 		goto out;
17425 	}
17426 
17427 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17428 		if (r == -1)
17429 			goto out;
17430 
17431 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17432 			switch (scf_error()) {
17433 			case SCF_ERROR_DELETED:
17434 				return (ENODEV);
17435 
17436 			case SCF_ERROR_CONNECTION_BROKEN:
17437 				return (ECONNABORTED);
17438 
17439 			case SCF_ERROR_NOT_SET:
17440 			case SCF_ERROR_NOT_BOUND:
17441 			default:
17442 				bad_error("scf_pg_get_name", scf_error());
17443 			}
17444 		}
17445 		if (IGNORE_VAR) {
17446 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17447 				continue;
17448 		}
17449 
17450 		/*
17451 		 * If unable to get the property continue as this is an
17452 		 * entry that has no location to check against.
17453 		 */
17454 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17455 			continue;
17456 		}
17457 
17458 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17459 			uu_warn(gettext("Unable to get value from %s\n"),
17460 			    pgname);
17461 
17462 			switch (scf_error()) {
17463 			case SCF_ERROR_DELETED:
17464 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17465 			case SCF_ERROR_NOT_FOUND:
17466 			case SCF_ERROR_NOT_SET:
17467 				continue;
17468 
17469 			case SCF_ERROR_CONNECTION_BROKEN:
17470 				r = scferror2errno(scf_error());
17471 				goto out;
17472 
17473 			case SCF_ERROR_HANDLE_MISMATCH:
17474 			case SCF_ERROR_NOT_BOUND:
17475 			default:
17476 				bad_error("scf_property_get_value",
17477 				    scf_error());
17478 			}
17479 		}
17480 
17481 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17482 		    == -1) {
17483 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17484 			    pgname, scf_strerror(scf_error()));
17485 
17486 			switch (scf_error()) {
17487 			case SCF_ERROR_NOT_SET:
17488 			case SCF_ERROR_TYPE_MISMATCH:
17489 				continue;
17490 
17491 			default:
17492 				bad_error("scf_value_get_astring", scf_error());
17493 			}
17494 		}
17495 
17496 		if (access(mfile, F_OK) == 0)
17497 			continue;
17498 
17499 		(void) scf_pg_delete(pg);
17500 	}
17501 
17502 out:
17503 	scf_scope_destroy(scope);
17504 	scf_service_destroy(svc);
17505 	scf_pg_destroy(pg);
17506 	scf_property_destroy(prop);
17507 	scf_value_destroy(val);
17508 	scf_iter_destroy(iter);
17509 	free(pgname);
17510 	free(mfile);
17511 
17512 	return (0);
17513 }
17514 
17515 #ifndef NATIVE_BUILD
17516 /* ARGSUSED */
17517 CPL_MATCH_FN(complete_select)
17518 {
17519 	const char *arg0, *arg1, *arg1end;
17520 	int word_start, err = 0, r;
17521 	size_t len;
17522 	char *buf;
17523 
17524 	lscf_prep_hndl();
17525 
17526 	arg0 = line + strspn(line, " \t");
17527 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17528 
17529 	arg1 = arg0 + sizeof ("select") - 1;
17530 	arg1 += strspn(arg1, " \t");
17531 	word_start = arg1 - line;
17532 
17533 	arg1end = arg1 + strcspn(arg1, " \t");
17534 	if (arg1end < line + word_end)
17535 		return (0);
17536 
17537 	len = line + word_end - arg1;
17538 
17539 	buf = safe_malloc(max_scf_name_len + 1);
17540 
17541 	if (cur_snap != NULL) {
17542 		return (0);
17543 	} else if (cur_inst != NULL) {
17544 		return (0);
17545 	} else if (cur_svc != NULL) {
17546 		scf_instance_t *inst;
17547 		scf_iter_t *iter;
17548 
17549 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17550 		    (iter = scf_iter_create(g_hndl)) == NULL)
17551 			scfdie();
17552 
17553 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17554 			scfdie();
17555 
17556 		for (;;) {
17557 			r = scf_iter_next_instance(iter, inst);
17558 			if (r == 0)
17559 				break;
17560 			if (r != 1)
17561 				scfdie();
17562 
17563 			if (scf_instance_get_name(inst, buf,
17564 			    max_scf_name_len + 1) < 0)
17565 				scfdie();
17566 
17567 			if (strncmp(buf, arg1, len) == 0) {
17568 				err = cpl_add_completion(cpl, line, word_start,
17569 				    word_end, buf + len, "", " ");
17570 				if (err != 0)
17571 					break;
17572 			}
17573 		}
17574 
17575 		scf_iter_destroy(iter);
17576 		scf_instance_destroy(inst);
17577 
17578 		return (err);
17579 	} else {
17580 		scf_service_t *svc;
17581 		scf_iter_t *iter;
17582 
17583 		assert(cur_scope != NULL);
17584 
17585 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17586 		    (iter = scf_iter_create(g_hndl)) == NULL)
17587 			scfdie();
17588 
17589 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17590 			scfdie();
17591 
17592 		for (;;) {
17593 			r = scf_iter_next_service(iter, svc);
17594 			if (r == 0)
17595 				break;
17596 			if (r != 1)
17597 				scfdie();
17598 
17599 			if (scf_service_get_name(svc, buf,
17600 			    max_scf_name_len + 1) < 0)
17601 				scfdie();
17602 
17603 			if (strncmp(buf, arg1, len) == 0) {
17604 				err = cpl_add_completion(cpl, line, word_start,
17605 				    word_end, buf + len, "", " ");
17606 				if (err != 0)
17607 					break;
17608 			}
17609 		}
17610 
17611 		scf_iter_destroy(iter);
17612 		scf_service_destroy(svc);
17613 
17614 		return (err);
17615 	}
17616 }
17617 
17618 /* ARGSUSED */
17619 CPL_MATCH_FN(complete_command)
17620 {
17621 	uint32_t scope = 0;
17622 
17623 	if (cur_snap != NULL)
17624 		scope = CS_SNAP;
17625 	else if (cur_inst != NULL)
17626 		scope = CS_INST;
17627 	else if (cur_svc != NULL)
17628 		scope = CS_SVC;
17629 	else
17630 		scope = CS_SCOPE;
17631 
17632 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17633 }
17634 #endif	/* NATIVE_BUILD */
17635