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