xref: /titanic_51/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision 188eaed9d5f14c73dfba1cd0dabaa430bdfd4a9a)
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  */
25 
26 
27 #include <alloca.h>
28 #include <assert.h>
29 #include <ctype.h>
30 #include <door.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <fnmatch.h>
34 #include <inttypes.h>
35 #include <libintl.h>
36 #include <libscf.h>
37 #include <libscf_priv.h>
38 #include <libtecla.h>
39 #include <libuutil.h>
40 #include <limits.h>
41 #include <locale.h>
42 #include <stdarg.h>
43 #include <string.h>
44 #include <strings.h>
45 #include <unistd.h>
46 #include <wait.h>
47 #include <poll.h>
48 
49 #include <libxml/tree.h>
50 
51 #include <sys/param.h>
52 
53 #include <sys/stat.h>
54 #include <sys/mman.h>
55 
56 #include "svccfg.h"
57 #include "manifest_hash.h"
58 #include "manifest_find.h"
59 
60 /* The colon namespaces in each entity (each followed by a newline). */
61 #define	COLON_NAMESPACES	":properties\n"
62 
63 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
64 
65 /* These are characters which the lexer requires to be in double-quotes. */
66 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
67 
68 #define	HASH_SIZE		16
69 #define	HASH_PG_TYPE		"framework"
70 #define	HASH_PG_FLAGS		0
71 #define	HASH_PROP		"md5sum"
72 
73 /*
74  * Indentation used in the output of the describe subcommand.
75  */
76 #define	TMPL_VALUE_INDENT	"  "
77 #define	TMPL_INDENT		"    "
78 #define	TMPL_INDENT_2X		"        "
79 #define	TMPL_CHOICE_INDENT	"      "
80 
81 /*
82  * Directory locations for manifests
83  */
84 #define	VARSVC_DIR		"/var/svc/manifest"
85 #define	LIBSVC_DIR		"/lib/svc/manifest"
86 #define	VARSVC_PR		"var_svc_manifest"
87 #define	LIBSVC_PR		"lib_svc_manifest"
88 #define	MFSTFILEPR		"manifestfile"
89 
90 #define	SUPPORTPROP		"support"
91 
92 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
93 
94 #define	MFSTFILE_MAX		16
95 
96 /*
97  * These are the classes of elements which may appear as children of service
98  * or instance elements in XML manifests.
99  */
100 struct entity_elts {
101 	xmlNodePtr	create_default_instance;
102 	xmlNodePtr	single_instance;
103 	xmlNodePtr	restarter;
104 	xmlNodePtr	dependencies;
105 	xmlNodePtr	dependents;
106 	xmlNodePtr	method_context;
107 	xmlNodePtr	exec_methods;
108 	xmlNodePtr	property_groups;
109 	xmlNodePtr	instances;
110 	xmlNodePtr	stability;
111 	xmlNodePtr	template;
112 };
113 
114 /*
115  * Likewise for property_group elements.
116  */
117 struct pg_elts {
118 	xmlNodePtr	stability;
119 	xmlNodePtr	propvals;
120 	xmlNodePtr	properties;
121 };
122 
123 /*
124  * Likewise for template elements.
125  */
126 struct template_elts {
127 	xmlNodePtr	common_name;
128 	xmlNodePtr	description;
129 	xmlNodePtr	documentation;
130 };
131 
132 /*
133  * This structure is for snaplevel lists.  They are convenient because libscf
134  * only allows traversing snaplevels in one direction.
135  */
136 struct snaplevel {
137 	uu_list_node_t	list_node;
138 	scf_snaplevel_t	*sl;
139 };
140 
141 /*
142  * This is used for communication between lscf_service_export and
143  * export_callback.
144  */
145 struct export_args {
146 	const char	*filename;
147 	int 		flags;
148 };
149 
150 /*
151  * The service_manifest structure is used by the upgrade process
152  * to create a list of service to manifest linkages from the manifests
153  * in a set of given directories.
154  */
155 typedef struct service_manifest {
156 	const char 	*servicename;
157 	uu_list_t	*mfstlist;
158 	size_t	mfstlist_sz;
159 
160 	uu_avl_node_t	svcmfst_node;
161 } service_manifest_t;
162 
163 /*
164  * Structure to track the manifest file property group
165  * and the manifest file associated with that property
166  * group.  Also, a flag to keep the access once it has
167  * been checked.
168  */
169 struct mpg_mfile {
170 	char	*mpg;
171 	char	*mfile;
172 	int	access;
173 };
174 
175 const char * const scf_pg_general = SCF_PG_GENERAL;
176 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
177 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
178 const char * const scf_property_external = "external";
179 
180 const char * const snap_initial = "initial";
181 const char * const snap_lastimport = "last-import";
182 const char * const snap_previous = "previous";
183 const char * const snap_running = "running";
184 
185 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
186 
187 ssize_t max_scf_fmri_len;
188 ssize_t max_scf_name_len;
189 ssize_t max_scf_pg_type_len;
190 ssize_t max_scf_value_len;
191 static size_t max_scf_len;
192 
193 static scf_scope_t *cur_scope;
194 static scf_service_t *cur_svc = NULL;
195 static scf_instance_t *cur_inst = NULL;
196 static scf_snapshot_t *cur_snap = NULL;
197 static scf_snaplevel_t *cur_level = NULL;
198 
199 static uu_list_pool_t *snaplevel_pool;
200 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
201 static uu_list_t *cur_levels;
202 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
203 
204 static FILE *tempfile = NULL;
205 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
206 
207 static const char *emsg_entity_not_selected;
208 static const char *emsg_permission_denied;
209 static const char *emsg_create_xml;
210 static const char *emsg_cant_modify_snapshots;
211 static const char *emsg_read_only;
212 static const char *emsg_deleted;
213 static const char *emsg_invalid_pg_name;
214 static const char *emsg_invalid_prop_name;
215 static const char *emsg_no_such_pg;
216 static const char *emsg_fmri_invalid_pg_name;
217 static const char *emsg_fmri_invalid_pg_name_type;
218 static const char *emsg_pg_added;
219 static const char *emsg_pg_changed;
220 static const char *emsg_pg_deleted;
221 static const char *emsg_pg_mod_perm;
222 static const char *emsg_pg_add_perm;
223 static const char *emsg_pg_del_perm;
224 static const char *emsg_snap_perm;
225 static const char *emsg_dpt_dangling;
226 static const char *emsg_dpt_no_dep;
227 
228 static int li_only = 0;
229 static int no_refresh = 0;
230 
231 /* import globals, to minimize allocations */
232 static scf_scope_t *imp_scope = NULL;
233 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
234 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
235 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
236 static scf_snapshot_t *imp_rsnap = NULL;
237 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
238 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
239 static scf_property_t *imp_prop = NULL;
240 static scf_iter_t *imp_iter = NULL;
241 static scf_iter_t *imp_rpg_iter = NULL;
242 static scf_iter_t *imp_up_iter = NULL;
243 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
244 static char *imp_str = NULL;
245 static size_t imp_str_sz;
246 static char *imp_tsname = NULL;
247 static char *imp_fe1 = NULL;		/* for fmri_equal() */
248 static char *imp_fe2 = NULL;
249 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
250 
251 /* upgrade_dependents() globals */
252 static scf_instance_t *ud_inst = NULL;
253 static scf_snaplevel_t *ud_snpl = NULL;
254 static scf_propertygroup_t *ud_pg = NULL;
255 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
256 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
257 static int ud_run_dpts_pg_set = 0;
258 static scf_property_t *ud_prop = NULL;
259 static scf_property_t *ud_dpt_prop = NULL;
260 static scf_value_t *ud_val = NULL;
261 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
262 static scf_transaction_t *ud_tx = NULL;
263 static char *ud_ctarg = NULL;
264 static char *ud_oldtarg = NULL;
265 static char *ud_name = NULL;
266 
267 /* export globals */
268 static scf_instance_t *exp_inst;
269 static scf_propertygroup_t *exp_pg;
270 static scf_property_t *exp_prop;
271 static scf_value_t *exp_val;
272 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
273 static char *exp_str;
274 static size_t exp_str_sz;
275 
276 /* cleanup globals */
277 static uu_avl_pool_t *service_manifest_pool = NULL;
278 static uu_avl_t *service_manifest_tree = NULL;
279 
280 static void scfdie_lineno(int lineno) __NORETURN;
281 
282 static char *start_method_names[] = {
283 	"start",
284 	"inetd_start",
285 	NULL
286 };
287 
288 static void
289 safe_printf(const char *fmt, ...)
290 {
291 	va_list va;
292 
293 	va_start(va, fmt);
294 	if (vprintf(fmt, va) < 0)
295 		uu_die(gettext("Error writing to stdout"));
296 	va_end(va);
297 }
298 
299 /*
300  * For unexpected libscf errors.
301  */
302 #ifdef NDEBUG
303 
304 static void scfdie(void) __NORETURN;
305 
306 static void
307 scfdie(void)
308 {
309 	scf_error_t err = scf_error();
310 
311 	if (err == SCF_ERROR_CONNECTION_BROKEN)
312 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
313 
314 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
315 	    scf_strerror(err));
316 }
317 
318 #else
319 
320 #define	scfdie()	scfdie_lineno(__LINE__)
321 
322 static void
323 scfdie_lineno(int lineno)
324 {
325 	scf_error_t err = scf_error();
326 
327 	if (err == SCF_ERROR_CONNECTION_BROKEN)
328 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
329 
330 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
331 	    ": %s.\n"), lineno, scf_strerror(err));
332 }
333 
334 #endif
335 
336 static void
337 scfwarn(void)
338 {
339 	warn(gettext("Unexpected libscf error: %s.\n"),
340 	    scf_strerror(scf_error()));
341 }
342 
343 /*
344  * Clear a field of a structure.
345  */
346 static int
347 clear_int(void *a, void *b)
348 {
349 	/* LINTED */
350 	*(int *)((char *)a + (size_t)b) = 0;
351 
352 	return (UU_WALK_NEXT);
353 }
354 
355 static int
356 scferror2errno(scf_error_t err)
357 {
358 	switch (err) {
359 	case SCF_ERROR_BACKEND_ACCESS:
360 		return (EACCES);
361 
362 	case SCF_ERROR_BACKEND_READONLY:
363 		return (EROFS);
364 
365 	case SCF_ERROR_CONNECTION_BROKEN:
366 		return (ECONNABORTED);
367 
368 	case SCF_ERROR_CONSTRAINT_VIOLATED:
369 	case SCF_ERROR_INVALID_ARGUMENT:
370 		return (EINVAL);
371 
372 	case SCF_ERROR_DELETED:
373 		return (ECANCELED);
374 
375 	case SCF_ERROR_EXISTS:
376 		return (EEXIST);
377 
378 	case SCF_ERROR_NO_MEMORY:
379 		return (ENOMEM);
380 
381 	case SCF_ERROR_NO_RESOURCES:
382 		return (ENOSPC);
383 
384 	case SCF_ERROR_NOT_FOUND:
385 		return (ENOENT);
386 
387 	case SCF_ERROR_PERMISSION_DENIED:
388 		return (EPERM);
389 
390 	default:
391 #ifndef NDEBUG
392 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
393 		    __FILE__, __LINE__, err);
394 #else
395 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
396 #endif
397 		abort();
398 		/* NOTREACHED */
399 	}
400 }
401 
402 static int
403 entity_get_pg(void *ent, int issvc, const char *name,
404     scf_propertygroup_t *pg)
405 {
406 	if (issvc)
407 		return (scf_service_get_pg(ent, name, pg));
408 	else
409 		return (scf_instance_get_pg(ent, name, pg));
410 }
411 
412 static void
413 entity_destroy(void *ent, int issvc)
414 {
415 	if (issvc)
416 		scf_service_destroy(ent);
417 	else
418 		scf_instance_destroy(ent);
419 }
420 
421 static int
422 get_pg(const char *pg_name, scf_propertygroup_t *pg)
423 {
424 	int ret;
425 
426 	if (cur_level != NULL)
427 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
428 	else if (cur_inst != NULL)
429 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
430 	else
431 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
432 
433 	return (ret);
434 }
435 
436 /*
437  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
438  * snaplevel.  Otherwise find the instance snaplevel.
439  *
440  * Returns
441  *   0 - success
442  *   ECONNABORTED - repository connection broken
443  *   ECANCELED - instance containing snap was deleted
444  *   ENOENT - snap has no snaplevels
445  *	    - requested snaplevel not found
446  */
447 static int
448 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
449 {
450 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
451 		switch (scf_error()) {
452 		case SCF_ERROR_CONNECTION_BROKEN:
453 		case SCF_ERROR_DELETED:
454 		case SCF_ERROR_NOT_FOUND:
455 			return (scferror2errno(scf_error()));
456 
457 		case SCF_ERROR_HANDLE_MISMATCH:
458 		case SCF_ERROR_NOT_BOUND:
459 		case SCF_ERROR_NOT_SET:
460 		default:
461 			bad_error("scf_snapshot_get_base_snaplevel",
462 			    scf_error());
463 		}
464 	}
465 
466 	for (;;) {
467 		ssize_t ssz;
468 
469 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
470 		if (ssz >= 0) {
471 			if (!get_svc)
472 				return (0);
473 		} else {
474 			switch (scf_error()) {
475 			case SCF_ERROR_CONSTRAINT_VIOLATED:
476 				if (get_svc)
477 					return (0);
478 				break;
479 
480 			case SCF_ERROR_DELETED:
481 			case SCF_ERROR_CONNECTION_BROKEN:
482 				return (scferror2errno(scf_error()));
483 
484 			case SCF_ERROR_NOT_SET:
485 			case SCF_ERROR_NOT_BOUND:
486 			default:
487 				bad_error("scf_snaplevel_get_instance_name",
488 				    scf_error());
489 			}
490 		}
491 
492 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
493 			switch (scf_error()) {
494 			case SCF_ERROR_NOT_FOUND:
495 			case SCF_ERROR_CONNECTION_BROKEN:
496 			case SCF_ERROR_DELETED:
497 				return (scferror2errno(scf_error()));
498 
499 			case SCF_ERROR_HANDLE_MISMATCH:
500 			case SCF_ERROR_NOT_BOUND:
501 			case SCF_ERROR_NOT_SET:
502 			case SCF_ERROR_INVALID_ARGUMENT:
503 			default:
504 				bad_error("scf_snaplevel_get_next_snaplevel",
505 				    scf_error());
506 			}
507 		}
508 	}
509 }
510 
511 /*
512  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
513  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
514  * the property group named name in it.  If it doesn't have a running
515  * snapshot, set pg to the instance's current property group named name.
516  *
517  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
518  * its instances.  If one has a running snapshot with a service snaplevel, set
519  * pg to the property group named name in it.  If no such snaplevel could be
520  * found, set pg to the service's current property group named name.
521  *
522  * iter, inst, snap, and snpl are required scratch objects.
523  *
524  * Returns
525  *   0 - success
526  *   ECONNABORTED - repository connection broken
527  *   ECANCELED - ent was deleted
528  *   ENOENT - no such property group
529  *   EINVAL - name is an invalid property group name
530  *   EBADF - found running snapshot is missing a snaplevel
531  */
532 static int
533 entity_get_running_pg(void *ent, int issvc, const char *name,
534     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
535     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
536 {
537 	int r;
538 
539 	if (issvc) {
540 		/* Search for an instance with a running snapshot. */
541 		if (scf_iter_service_instances(iter, ent) != 0) {
542 			switch (scf_error()) {
543 			case SCF_ERROR_DELETED:
544 			case SCF_ERROR_CONNECTION_BROKEN:
545 				return (scferror2errno(scf_error()));
546 
547 			case SCF_ERROR_NOT_SET:
548 			case SCF_ERROR_NOT_BOUND:
549 			case SCF_ERROR_HANDLE_MISMATCH:
550 			default:
551 				bad_error("scf_iter_service_instances",
552 				    scf_error());
553 			}
554 		}
555 
556 		for (;;) {
557 			r = scf_iter_next_instance(iter, inst);
558 			if (r == 0) {
559 				if (scf_service_get_pg(ent, name, pg) == 0)
560 					return (0);
561 
562 				switch (scf_error()) {
563 				case SCF_ERROR_DELETED:
564 				case SCF_ERROR_NOT_FOUND:
565 				case SCF_ERROR_INVALID_ARGUMENT:
566 				case SCF_ERROR_CONNECTION_BROKEN:
567 					return (scferror2errno(scf_error()));
568 
569 				case SCF_ERROR_NOT_BOUND:
570 				case SCF_ERROR_HANDLE_MISMATCH:
571 				case SCF_ERROR_NOT_SET:
572 				default:
573 					bad_error("scf_service_get_pg",
574 					    scf_error());
575 				}
576 			}
577 			if (r != 1) {
578 				switch (scf_error()) {
579 				case SCF_ERROR_DELETED:
580 				case SCF_ERROR_CONNECTION_BROKEN:
581 					return (scferror2errno(scf_error()));
582 
583 				case SCF_ERROR_INVALID_ARGUMENT:
584 				case SCF_ERROR_NOT_SET:
585 				case SCF_ERROR_NOT_BOUND:
586 				case SCF_ERROR_HANDLE_MISMATCH:
587 				default:
588 					bad_error("scf_iter_next_instance",
589 					    scf_error());
590 				}
591 			}
592 
593 			if (scf_instance_get_snapshot(inst, snap_running,
594 			    snap) == 0)
595 				break;
596 
597 			switch (scf_error()) {
598 			case SCF_ERROR_NOT_FOUND:
599 			case SCF_ERROR_DELETED:
600 				continue;
601 
602 			case SCF_ERROR_CONNECTION_BROKEN:
603 				return (ECONNABORTED);
604 
605 			case SCF_ERROR_HANDLE_MISMATCH:
606 			case SCF_ERROR_INVALID_ARGUMENT:
607 			case SCF_ERROR_NOT_SET:
608 			case SCF_ERROR_NOT_BOUND:
609 			default:
610 				bad_error("scf_instance_get_snapshot",
611 				    scf_error());
612 			}
613 		}
614 	} else {
615 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
616 			switch (scf_error()) {
617 			case SCF_ERROR_NOT_FOUND:
618 				break;
619 
620 			case SCF_ERROR_DELETED:
621 			case SCF_ERROR_CONNECTION_BROKEN:
622 				return (scferror2errno(scf_error()));
623 
624 			case SCF_ERROR_NOT_BOUND:
625 			case SCF_ERROR_HANDLE_MISMATCH:
626 			case SCF_ERROR_INVALID_ARGUMENT:
627 			case SCF_ERROR_NOT_SET:
628 			default:
629 				bad_error("scf_instance_get_snapshot",
630 				    scf_error());
631 			}
632 
633 			if (scf_instance_get_pg(ent, name, pg) == 0)
634 				return (0);
635 
636 			switch (scf_error()) {
637 			case SCF_ERROR_DELETED:
638 			case SCF_ERROR_NOT_FOUND:
639 			case SCF_ERROR_INVALID_ARGUMENT:
640 			case SCF_ERROR_CONNECTION_BROKEN:
641 				return (scferror2errno(scf_error()));
642 
643 			case SCF_ERROR_NOT_BOUND:
644 			case SCF_ERROR_HANDLE_MISMATCH:
645 			case SCF_ERROR_NOT_SET:
646 			default:
647 				bad_error("scf_instance_get_pg", scf_error());
648 			}
649 		}
650 	}
651 
652 	r = get_snaplevel(snap, issvc, snpl);
653 	switch (r) {
654 	case 0:
655 		break;
656 
657 	case ECONNABORTED:
658 	case ECANCELED:
659 		return (r);
660 
661 	case ENOENT:
662 		return (EBADF);
663 
664 	default:
665 		bad_error("get_snaplevel", r);
666 	}
667 
668 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
669 		return (0);
670 
671 	switch (scf_error()) {
672 	case SCF_ERROR_DELETED:
673 	case SCF_ERROR_INVALID_ARGUMENT:
674 	case SCF_ERROR_CONNECTION_BROKEN:
675 	case SCF_ERROR_NOT_FOUND:
676 		return (scferror2errno(scf_error()));
677 
678 	case SCF_ERROR_NOT_BOUND:
679 	case SCF_ERROR_HANDLE_MISMATCH:
680 	case SCF_ERROR_NOT_SET:
681 	default:
682 		bad_error("scf_snaplevel_get_pg", scf_error());
683 		/* NOTREACHED */
684 	}
685 }
686 
687 /*
688  * To be registered with atexit().
689  */
690 static void
691 remove_tempfile(void)
692 {
693 	int ret;
694 
695 	if (tempfile != NULL) {
696 		if (fclose(tempfile) == EOF)
697 			(void) warn(gettext("Could not close temporary file"));
698 		tempfile = NULL;
699 	}
700 
701 	if (tempfilename[0] != '\0') {
702 		do {
703 			ret = remove(tempfilename);
704 		} while (ret == -1 && errno == EINTR);
705 		if (ret == -1)
706 			warn(gettext("Could not remove temporary file"));
707 		tempfilename[0] = '\0';
708 	}
709 }
710 
711 /*
712  * Launch private svc.configd(1M) for manipulating alternate repositories.
713  */
714 static void
715 start_private_repository(engine_state_t *est)
716 {
717 	int fd, stat;
718 	struct door_info info;
719 	pid_t pid;
720 
721 	/*
722 	 * 1.  Create a temporary file for the door.
723 	 */
724 	if (est->sc_repo_doorname != NULL)
725 		free((void *)est->sc_repo_doorname);
726 
727 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
728 	if (est->sc_repo_doorname == NULL)
729 		uu_die(gettext("Could not acquire temporary filename"));
730 
731 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
732 	if (fd < 0)
733 		uu_die(gettext("Could not create temporary file for "
734 		    "repository server"));
735 
736 	(void) close(fd);
737 
738 	/*
739 	 * 2.  Launch a configd with that door, using the specified
740 	 * repository.
741 	 */
742 	if ((est->sc_repo_pid = fork()) == 0) {
743 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
744 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
745 		    NULL);
746 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
747 	} else if (est->sc_repo_pid == -1)
748 		uu_die(gettext("Attempt to fork failed"));
749 
750 	do {
751 		pid = waitpid(est->sc_repo_pid, &stat, 0);
752 	} while (pid == -1 && errno == EINTR);
753 
754 	if (pid == -1)
755 		uu_die(gettext("Could not waitpid() for repository server"));
756 
757 	if (!WIFEXITED(stat)) {
758 		uu_die(gettext("Repository server failed (status %d).\n"),
759 		    stat);
760 	} else if (WEXITSTATUS(stat) != 0) {
761 		uu_die(gettext("Repository server failed (exit %d).\n"),
762 		    WEXITSTATUS(stat));
763 	}
764 
765 	/*
766 	 * See if it was successful by checking if the door is a door.
767 	 */
768 
769 	fd = open(est->sc_repo_doorname, O_RDWR);
770 	if (fd < 0)
771 		uu_die(gettext("Could not open door \"%s\""),
772 		    est->sc_repo_doorname);
773 
774 	if (door_info(fd, &info) < 0)
775 		uu_die(gettext("Unexpected door_info() error"));
776 
777 	if (close(fd) == -1)
778 		warn(gettext("Could not close repository door"),
779 		    strerror(errno));
780 
781 	est->sc_repo_pid = info.di_target;
782 }
783 
784 void
785 lscf_cleanup(void)
786 {
787 	/*
788 	 * In the case where we've launched a private svc.configd(1M)
789 	 * instance, we must terminate our child and remove the temporary
790 	 * rendezvous point.
791 	 */
792 	if (est->sc_repo_pid > 0) {
793 		(void) kill(est->sc_repo_pid, SIGTERM);
794 		(void) waitpid(est->sc_repo_pid, NULL, 0);
795 		(void) unlink(est->sc_repo_doorname);
796 
797 		est->sc_repo_pid = 0;
798 	}
799 }
800 
801 void
802 unselect_cursnap(void)
803 {
804 	void *cookie;
805 
806 	cur_level = NULL;
807 
808 	cookie = NULL;
809 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
810 		scf_snaplevel_destroy(cur_elt->sl);
811 		free(cur_elt);
812 	}
813 
814 	scf_snapshot_destroy(cur_snap);
815 	cur_snap = NULL;
816 }
817 
818 void
819 lscf_prep_hndl(void)
820 {
821 	if (g_hndl != NULL)
822 		return;
823 
824 	g_hndl = scf_handle_create(SCF_VERSION);
825 	if (g_hndl == NULL)
826 		scfdie();
827 
828 	if (est->sc_repo_filename != NULL)
829 		start_private_repository(est);
830 
831 	if (est->sc_repo_doorname != NULL) {
832 		scf_value_t *repo_value;
833 		int ret;
834 
835 		repo_value = scf_value_create(g_hndl);
836 		if (repo_value == NULL)
837 			scfdie();
838 
839 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
840 		assert(ret == SCF_SUCCESS);
841 
842 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
843 		    SCF_SUCCESS)
844 			scfdie();
845 
846 		scf_value_destroy(repo_value);
847 	}
848 
849 	if (scf_handle_bind(g_hndl) != 0)
850 		uu_die(gettext("Could not connect to repository server: %s.\n"),
851 		    scf_strerror(scf_error()));
852 
853 	cur_scope = scf_scope_create(g_hndl);
854 	if (cur_scope == NULL)
855 		scfdie();
856 
857 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
858 		scfdie();
859 }
860 
861 static void
862 repository_teardown(void)
863 {
864 	if (g_hndl != NULL) {
865 		if (cur_snap != NULL)
866 			unselect_cursnap();
867 		scf_instance_destroy(cur_inst);
868 		scf_service_destroy(cur_svc);
869 		scf_scope_destroy(cur_scope);
870 		scf_handle_destroy(g_hndl);
871 		cur_inst = NULL;
872 		cur_svc = NULL;
873 		cur_scope = NULL;
874 		g_hndl = NULL;
875 		lscf_cleanup();
876 	}
877 }
878 
879 void
880 lscf_set_repository(const char *repfile, int force)
881 {
882 	repository_teardown();
883 
884 	if (est->sc_repo_filename != NULL) {
885 		free((void *)est->sc_repo_filename);
886 		est->sc_repo_filename = NULL;
887 	}
888 
889 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
890 		/*
891 		 * Repository file does not exist
892 		 * or has no read permission.
893 		 */
894 		warn(gettext("Cannot access \"%s\": %s\n"),
895 		    repfile, strerror(errno));
896 	} else {
897 		est->sc_repo_filename = safe_strdup(repfile);
898 	}
899 
900 	lscf_prep_hndl();
901 }
902 
903 void
904 lscf_init()
905 {
906 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
907 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
908 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
909 	    0 ||
910 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
911 		scfdie();
912 
913 	max_scf_len = max_scf_fmri_len;
914 	if (max_scf_name_len > max_scf_len)
915 		max_scf_len = max_scf_name_len;
916 	if (max_scf_pg_type_len > max_scf_len)
917 		max_scf_len = max_scf_pg_type_len;
918 	if (max_scf_value_len > max_scf_len)
919 		max_scf_len = max_scf_value_len;
920 
921 	if (atexit(remove_tempfile) != 0)
922 		uu_die(gettext("Could not register atexit() function"));
923 
924 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
925 	emsg_permission_denied = gettext("Permission denied.\n");
926 	emsg_create_xml = gettext("Could not create XML node.\n");
927 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
928 	emsg_read_only = gettext("Backend read-only.\n");
929 	emsg_deleted = gettext("Current selection has been deleted.\n");
930 	emsg_invalid_pg_name =
931 	    gettext("Invalid property group name \"%s\".\n");
932 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
933 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
934 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
935 	    "with invalid name \"%s\".\n");
936 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
937 	    "group with invalid name \"%s\" or type \"%s\".\n");
938 	emsg_pg_added = gettext("%s changed unexpectedly "
939 	    "(property group \"%s\" added).\n");
940 	emsg_pg_changed = gettext("%s changed unexpectedly "
941 	    "(property group \"%s\" changed).\n");
942 	emsg_pg_deleted = gettext("%s changed unexpectedly "
943 	    "(property group \"%s\" or an ancestor was deleted).\n");
944 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
945 	    "in %s (permission denied).\n");
946 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
947 	    "in %s (permission denied).\n");
948 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
949 	    "in %s (permission denied).\n");
950 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
951 	    "(permission denied).\n");
952 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
953 	    "new dependent \"%s\" because it already exists).  Warning: The "
954 	    "current dependent's target (%s) does not exist.\n");
955 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
956 	    "dependent \"%s\" because it already exists).  Warning: The "
957 	    "current dependent's target (%s) does not have a dependency named "
958 	    "\"%s\" as expected.\n");
959 
960 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
961 	    offsetof(string_list_t, node), NULL, 0);
962 	snaplevel_pool = uu_list_pool_create("snaplevels",
963 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
964 	    NULL, 0);
965 }
966 
967 
968 static const char *
969 prop_to_typestr(const scf_property_t *prop)
970 {
971 	scf_type_t ty;
972 
973 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
974 		scfdie();
975 
976 	return (scf_type_to_string(ty));
977 }
978 
979 static scf_type_t
980 string_to_type(const char *type)
981 {
982 	size_t len = strlen(type);
983 	char *buf;
984 
985 	if (len == 0 || type[len - 1] != ':')
986 		return (SCF_TYPE_INVALID);
987 
988 	buf = (char *)alloca(len + 1);
989 	(void) strlcpy(buf, type, len + 1);
990 	buf[len - 1] = 0;
991 
992 	return (scf_string_to_type(buf));
993 }
994 
995 static scf_value_t *
996 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
997 {
998 	scf_value_t *v;
999 	char *dup, *nstr;
1000 	size_t len;
1001 
1002 	v = scf_value_create(g_hndl);
1003 	if (v == NULL)
1004 		scfdie();
1005 
1006 	len = strlen(str);
1007 	if (require_quotes &&
1008 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1009 		semerr(gettext("Multiple string values or string values "
1010 		    "with spaces must be quoted with '\"'.\n"));
1011 		scf_value_destroy(v);
1012 		return (NULL);
1013 	}
1014 
1015 	nstr = dup = safe_strdup(str);
1016 	if (dup[0] == '\"') {
1017 		/*
1018 		 * Strip out the first and the last quote.
1019 		 */
1020 		dup[len - 1] = '\0';
1021 		nstr = dup + 1;
1022 	}
1023 
1024 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1025 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1026 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1027 		    scf_type_to_string(ty), nstr);
1028 		scf_value_destroy(v);
1029 		v = NULL;
1030 	}
1031 	free(dup);
1032 	return (v);
1033 }
1034 
1035 /*
1036  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1037  * Optionally append a comment prefix ('#') to newlines ('\n').
1038  */
1039 static int
1040 quote_and_print(const char *str, FILE *strm, int commentnl)
1041 {
1042 	const char *cp;
1043 
1044 	for (cp = str; *cp != '\0'; ++cp) {
1045 		if (*cp == '"' || *cp == '\\')
1046 			(void) putc('\\', strm);
1047 
1048 		(void) putc(*cp, strm);
1049 
1050 		if (commentnl && *cp == '\n') {
1051 			(void) putc('#', strm);
1052 		}
1053 	}
1054 
1055 	return (ferror(strm));
1056 }
1057 
1058 /*
1059  * These wrappers around lowlevel functions provide consistent error checking
1060  * and warnings.
1061  */
1062 static int
1063 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1064 {
1065 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1066 		return (0);
1067 
1068 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1069 		scfdie();
1070 
1071 	if (g_verbose) {
1072 		ssize_t len;
1073 		char *fmri;
1074 
1075 		len = scf_pg_to_fmri(pg, NULL, 0);
1076 		if (len < 0)
1077 			scfdie();
1078 
1079 		fmri = safe_malloc(len + 1);
1080 
1081 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1082 			scfdie();
1083 
1084 		warn(gettext("Expected property %s of property group %s is "
1085 		    "missing.\n"), propname, fmri);
1086 
1087 		free(fmri);
1088 	}
1089 
1090 	return (-1);
1091 }
1092 
1093 static int
1094 prop_check_type(scf_property_t *prop, scf_type_t ty)
1095 {
1096 	scf_type_t pty;
1097 
1098 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1099 		scfdie();
1100 
1101 	if (ty == pty)
1102 		return (0);
1103 
1104 	if (g_verbose) {
1105 		ssize_t len;
1106 		char *fmri;
1107 		const char *tystr;
1108 
1109 		len = scf_property_to_fmri(prop, NULL, 0);
1110 		if (len < 0)
1111 			scfdie();
1112 
1113 		fmri = safe_malloc(len + 1);
1114 
1115 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1116 			scfdie();
1117 
1118 		tystr = scf_type_to_string(ty);
1119 		if (tystr == NULL)
1120 			tystr = "?";
1121 
1122 		warn(gettext("Property %s is not of expected type %s.\n"),
1123 		    fmri, tystr);
1124 
1125 		free(fmri);
1126 	}
1127 
1128 	return (-1);
1129 }
1130 
1131 static int
1132 prop_get_val(scf_property_t *prop, scf_value_t *val)
1133 {
1134 	scf_error_t err;
1135 
1136 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1137 		return (0);
1138 
1139 	err = scf_error();
1140 
1141 	if (err != SCF_ERROR_NOT_FOUND &&
1142 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1143 	    err != SCF_ERROR_PERMISSION_DENIED)
1144 		scfdie();
1145 
1146 	if (g_verbose) {
1147 		ssize_t len;
1148 		char *fmri, *emsg;
1149 
1150 		len = scf_property_to_fmri(prop, NULL, 0);
1151 		if (len < 0)
1152 			scfdie();
1153 
1154 		fmri = safe_malloc(len + 1);
1155 
1156 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1157 			scfdie();
1158 
1159 		if (err == SCF_ERROR_NOT_FOUND)
1160 			emsg = gettext("Property %s has no values; expected "
1161 			    "one.\n");
1162 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1163 			emsg = gettext("Property %s has multiple values; "
1164 			    "expected one.\n");
1165 		else
1166 			emsg = gettext("No permission to read property %s.\n");
1167 
1168 		warn(emsg, fmri);
1169 
1170 		free(fmri);
1171 	}
1172 
1173 	return (-1);
1174 }
1175 
1176 
1177 static boolean_t
1178 snaplevel_is_instance(const scf_snaplevel_t *level)
1179 {
1180 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1181 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1182 			scfdie();
1183 		return (0);
1184 	} else {
1185 		return (1);
1186 	}
1187 }
1188 
1189 /*
1190  * Decode FMRI into a service or instance, and put the result in *ep.  If
1191  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1192  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1193  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1194  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1195  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1196  * whether *ep is a service.
1197  */
1198 static scf_error_t
1199 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1200 {
1201 	char *fmri_copy;
1202 	const char *sstr, *istr, *pgstr;
1203 	scf_service_t *svc;
1204 	scf_instance_t *inst;
1205 
1206 	fmri_copy = strdup(fmri);
1207 	if (fmri_copy == NULL)
1208 		return (SCF_ERROR_NO_MEMORY);
1209 
1210 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1211 	    SCF_SUCCESS) {
1212 		free(fmri_copy);
1213 		return (SCF_ERROR_INVALID_ARGUMENT);
1214 	}
1215 
1216 	free(fmri_copy);
1217 
1218 	if (sstr == NULL || pgstr != NULL)
1219 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1220 
1221 	if (istr == NULL) {
1222 		svc = scf_service_create(h);
1223 		if (svc == NULL)
1224 			return (SCF_ERROR_NO_MEMORY);
1225 
1226 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1227 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1228 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1229 				scfdie();
1230 
1231 			return (SCF_ERROR_NOT_FOUND);
1232 		}
1233 
1234 		*ep = svc;
1235 		*isservice = 1;
1236 	} else {
1237 		inst = scf_instance_create(h);
1238 		if (inst == NULL)
1239 			return (SCF_ERROR_NO_MEMORY);
1240 
1241 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1242 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1243 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1244 				scfdie();
1245 
1246 			return (SCF_ERROR_NOT_FOUND);
1247 		}
1248 
1249 		*ep = inst;
1250 		*isservice = 0;
1251 	}
1252 
1253 	return (SCF_ERROR_NONE);
1254 }
1255 
1256 /*
1257  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1258  * *ep, and set or clear *isservicep if it is a service or an instance.
1259  * Returns
1260  *   SCF_ERROR_NONE - success
1261  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1262  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1263  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1264  *   SCF_ERROR_NOT_FOUND - no such scope
1265  *   SCF_ERROR_PERMISSION_DENIED
1266  *   SCF_ERROR_BACKEND_READONLY
1267  *   SCF_ERROR_BACKEND_ACCESS
1268  */
1269 static scf_error_t
1270 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1271 {
1272 	char *fmri_copy;
1273 	const char *scstr, *sstr, *istr, *pgstr;
1274 	scf_scope_t *scope = NULL;
1275 	scf_service_t *svc = NULL;
1276 	scf_instance_t *inst = NULL;
1277 	scf_error_t scfe;
1278 
1279 	fmri_copy = safe_strdup(fmri);
1280 
1281 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1282 	    0) {
1283 		free(fmri_copy);
1284 		return (SCF_ERROR_INVALID_ARGUMENT);
1285 	}
1286 
1287 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1288 		free(fmri_copy);
1289 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1290 	}
1291 
1292 	*ep = NULL;
1293 
1294 	if ((scope = scf_scope_create(h)) == NULL ||
1295 	    (svc = scf_service_create(h)) == NULL ||
1296 	    (inst = scf_instance_create(h)) == NULL) {
1297 		scfe = SCF_ERROR_NO_MEMORY;
1298 		goto out;
1299 	}
1300 
1301 get_scope:
1302 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1303 		switch (scf_error()) {
1304 		case SCF_ERROR_CONNECTION_BROKEN:
1305 			scfdie();
1306 			/* NOTREACHED */
1307 
1308 		case SCF_ERROR_NOT_FOUND:
1309 			scfe = SCF_ERROR_NOT_FOUND;
1310 			goto out;
1311 
1312 		case SCF_ERROR_HANDLE_MISMATCH:
1313 		case SCF_ERROR_NOT_BOUND:
1314 		case SCF_ERROR_INVALID_ARGUMENT:
1315 		default:
1316 			bad_error("scf_handle_get_scope", scf_error());
1317 		}
1318 	}
1319 
1320 get_svc:
1321 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1322 		switch (scf_error()) {
1323 		case SCF_ERROR_CONNECTION_BROKEN:
1324 			scfdie();
1325 			/* NOTREACHED */
1326 
1327 		case SCF_ERROR_DELETED:
1328 			goto get_scope;
1329 
1330 		case SCF_ERROR_NOT_FOUND:
1331 			break;
1332 
1333 		case SCF_ERROR_HANDLE_MISMATCH:
1334 		case SCF_ERROR_INVALID_ARGUMENT:
1335 		case SCF_ERROR_NOT_BOUND:
1336 		case SCF_ERROR_NOT_SET:
1337 		default:
1338 			bad_error("scf_scope_get_service", scf_error());
1339 		}
1340 
1341 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1342 			switch (scf_error()) {
1343 			case SCF_ERROR_CONNECTION_BROKEN:
1344 				scfdie();
1345 				/* NOTREACHED */
1346 
1347 			case SCF_ERROR_DELETED:
1348 				goto get_scope;
1349 
1350 			case SCF_ERROR_PERMISSION_DENIED:
1351 			case SCF_ERROR_BACKEND_READONLY:
1352 			case SCF_ERROR_BACKEND_ACCESS:
1353 				scfe = scf_error();
1354 				goto out;
1355 
1356 			case SCF_ERROR_HANDLE_MISMATCH:
1357 			case SCF_ERROR_INVALID_ARGUMENT:
1358 			case SCF_ERROR_NOT_BOUND:
1359 			case SCF_ERROR_NOT_SET:
1360 			default:
1361 				bad_error("scf_scope_get_service", scf_error());
1362 			}
1363 		}
1364 	}
1365 
1366 	if (istr == NULL) {
1367 		scfe = SCF_ERROR_NONE;
1368 		*ep = svc;
1369 		*isservicep = 1;
1370 		goto out;
1371 	}
1372 
1373 get_inst:
1374 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1375 		switch (scf_error()) {
1376 		case SCF_ERROR_CONNECTION_BROKEN:
1377 			scfdie();
1378 			/* NOTREACHED */
1379 
1380 		case SCF_ERROR_DELETED:
1381 			goto get_svc;
1382 
1383 		case SCF_ERROR_NOT_FOUND:
1384 			break;
1385 
1386 		case SCF_ERROR_HANDLE_MISMATCH:
1387 		case SCF_ERROR_INVALID_ARGUMENT:
1388 		case SCF_ERROR_NOT_BOUND:
1389 		case SCF_ERROR_NOT_SET:
1390 		default:
1391 			bad_error("scf_service_get_instance", scf_error());
1392 		}
1393 
1394 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1395 			switch (scf_error()) {
1396 			case SCF_ERROR_CONNECTION_BROKEN:
1397 				scfdie();
1398 				/* NOTREACHED */
1399 
1400 			case SCF_ERROR_DELETED:
1401 				goto get_svc;
1402 
1403 			case SCF_ERROR_PERMISSION_DENIED:
1404 			case SCF_ERROR_BACKEND_READONLY:
1405 			case SCF_ERROR_BACKEND_ACCESS:
1406 				scfe = scf_error();
1407 				goto out;
1408 
1409 			case SCF_ERROR_HANDLE_MISMATCH:
1410 			case SCF_ERROR_INVALID_ARGUMENT:
1411 			case SCF_ERROR_NOT_BOUND:
1412 			case SCF_ERROR_NOT_SET:
1413 			default:
1414 				bad_error("scf_service_add_instance",
1415 				    scf_error());
1416 			}
1417 		}
1418 	}
1419 
1420 	scfe = SCF_ERROR_NONE;
1421 	*ep = inst;
1422 	*isservicep = 0;
1423 
1424 out:
1425 	if (*ep != inst)
1426 		scf_instance_destroy(inst);
1427 	if (*ep != svc)
1428 		scf_service_destroy(svc);
1429 	scf_scope_destroy(scope);
1430 	free(fmri_copy);
1431 	return (scfe);
1432 }
1433 
1434 /*
1435  * Create or update a snapshot of inst.  snap is a required scratch object.
1436  *
1437  * Returns
1438  *   0 - success
1439  *   ECONNABORTED - repository connection broken
1440  *   EPERM - permission denied
1441  *   ENOSPC - configd is out of resources
1442  *   ECANCELED - inst was deleted
1443  *   -1 - unknown libscf error (message printed)
1444  */
1445 static int
1446 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1447 {
1448 again:
1449 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1450 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1451 			switch (scf_error()) {
1452 			case SCF_ERROR_CONNECTION_BROKEN:
1453 			case SCF_ERROR_PERMISSION_DENIED:
1454 			case SCF_ERROR_NO_RESOURCES:
1455 				return (scferror2errno(scf_error()));
1456 
1457 			case SCF_ERROR_NOT_SET:
1458 			case SCF_ERROR_INVALID_ARGUMENT:
1459 			default:
1460 				bad_error("_scf_snapshot_take_attach",
1461 				    scf_error());
1462 			}
1463 		}
1464 	} else {
1465 		switch (scf_error()) {
1466 		case SCF_ERROR_NOT_FOUND:
1467 			break;
1468 
1469 		case SCF_ERROR_DELETED:
1470 		case SCF_ERROR_CONNECTION_BROKEN:
1471 			return (scferror2errno(scf_error()));
1472 
1473 		case SCF_ERROR_HANDLE_MISMATCH:
1474 		case SCF_ERROR_NOT_BOUND:
1475 		case SCF_ERROR_INVALID_ARGUMENT:
1476 		case SCF_ERROR_NOT_SET:
1477 		default:
1478 			bad_error("scf_instance_get_snapshot", scf_error());
1479 		}
1480 
1481 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1482 			switch (scf_error()) {
1483 			case SCF_ERROR_EXISTS:
1484 				goto again;
1485 
1486 			case SCF_ERROR_CONNECTION_BROKEN:
1487 			case SCF_ERROR_NO_RESOURCES:
1488 			case SCF_ERROR_PERMISSION_DENIED:
1489 				return (scferror2errno(scf_error()));
1490 
1491 			default:
1492 				scfwarn();
1493 				return (-1);
1494 
1495 			case SCF_ERROR_NOT_SET:
1496 			case SCF_ERROR_INTERNAL:
1497 			case SCF_ERROR_INVALID_ARGUMENT:
1498 			case SCF_ERROR_HANDLE_MISMATCH:
1499 				bad_error("_scf_snapshot_take_new",
1500 				    scf_error());
1501 			}
1502 		}
1503 	}
1504 
1505 	return (0);
1506 }
1507 
1508 static int
1509 refresh_running_snapshot(void *entity)
1510 {
1511 	scf_snapshot_t *snap;
1512 	int r;
1513 
1514 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1515 		scfdie();
1516 	r = take_snap(entity, snap_running, snap);
1517 	scf_snapshot_destroy(snap);
1518 
1519 	return (r);
1520 }
1521 
1522 /*
1523  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1524  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1525  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1526  * for scratch space.  Returns
1527  *   0 - success
1528  *   ECONNABORTED - repository connection broken
1529  *   ECANCELED - entity was deleted
1530  *   EACCES - backend denied access
1531  *   EPERM - permission denied
1532  *   ENOSPC - repository server out of resources
1533  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1534  */
1535 static int
1536 refresh_entity(int isservice, void *entity, const char *fmri,
1537     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1538 {
1539 	scf_error_t scfe;
1540 	int r;
1541 
1542 	if (!isservice) {
1543 		/*
1544 		 * Let restarter handles refreshing and making new running
1545 		 * snapshot only if operating on a live repository and not
1546 		 * running in early import.
1547 		 */
1548 		if (est->sc_repo_filename == NULL &&
1549 		    est->sc_repo_doorname == NULL &&
1550 		    est->sc_in_emi == 0) {
1551 			if (_smf_refresh_instance_i(entity) == 0) {
1552 				if (g_verbose)
1553 					warn(gettext("Refreshed %s.\n"), fmri);
1554 				return (0);
1555 			}
1556 
1557 			switch (scf_error()) {
1558 			case SCF_ERROR_BACKEND_ACCESS:
1559 				return (EACCES);
1560 
1561 			case SCF_ERROR_PERMISSION_DENIED:
1562 				return (EPERM);
1563 
1564 			default:
1565 				return (-1);
1566 			}
1567 		} else {
1568 			r = refresh_running_snapshot(entity);
1569 			switch (r) {
1570 			case 0:
1571 				break;
1572 
1573 			case ECONNABORTED:
1574 			case ECANCELED:
1575 			case EPERM:
1576 			case ENOSPC:
1577 				break;
1578 
1579 			default:
1580 				bad_error("refresh_running_snapshot",
1581 				    scf_error());
1582 			}
1583 
1584 			return (r);
1585 		}
1586 	}
1587 
1588 	if (scf_iter_service_instances(iter, entity) != 0) {
1589 		switch (scf_error()) {
1590 		case SCF_ERROR_CONNECTION_BROKEN:
1591 			return (ECONNABORTED);
1592 
1593 		case SCF_ERROR_DELETED:
1594 			return (ECANCELED);
1595 
1596 		case SCF_ERROR_HANDLE_MISMATCH:
1597 		case SCF_ERROR_NOT_BOUND:
1598 		case SCF_ERROR_NOT_SET:
1599 		default:
1600 			bad_error("scf_iter_service_instances", scf_error());
1601 		}
1602 	}
1603 
1604 	for (;;) {
1605 		r = scf_iter_next_instance(iter, inst);
1606 		if (r == 0)
1607 			break;
1608 		if (r != 1) {
1609 			switch (scf_error()) {
1610 			case SCF_ERROR_CONNECTION_BROKEN:
1611 				return (ECONNABORTED);
1612 
1613 			case SCF_ERROR_DELETED:
1614 				return (ECANCELED);
1615 
1616 			case SCF_ERROR_HANDLE_MISMATCH:
1617 			case SCF_ERROR_NOT_BOUND:
1618 			case SCF_ERROR_NOT_SET:
1619 			case SCF_ERROR_INVALID_ARGUMENT:
1620 			default:
1621 				bad_error("scf_iter_next_instance",
1622 				    scf_error());
1623 			}
1624 		}
1625 
1626 		/*
1627 		 * Similarly, just take a new running snapshot if operating on
1628 		 * a non-live repository or running during early import.
1629 		 */
1630 		if (est->sc_repo_filename != NULL ||
1631 		    est->sc_repo_doorname != NULL ||
1632 		    est->sc_in_emi == 1) {
1633 			r = refresh_running_snapshot(inst);
1634 			switch (r) {
1635 			case 0:
1636 				continue;
1637 
1638 			case ECONNABORTED:
1639 			case ECANCELED:
1640 			case EPERM:
1641 			case ENOSPC:
1642 				break;
1643 			default:
1644 				bad_error("refresh_running_snapshot",
1645 				    scf_error());
1646 			}
1647 
1648 			return (r);
1649 
1650 		}
1651 
1652 		if (_smf_refresh_instance_i(inst) == 0) {
1653 			if (g_verbose) {
1654 				if (scf_instance_get_name(inst, name_buf,
1655 				    max_scf_name_len + 1) < 0)
1656 					(void) strcpy(name_buf, "?");
1657 
1658 				warn(gettext("Refreshed %s:%s.\n"),
1659 				    fmri, name_buf);
1660 			}
1661 		} else {
1662 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1663 			    g_verbose) {
1664 				scfe = scf_error();
1665 
1666 				if (scf_instance_to_fmri(inst, name_buf,
1667 				    max_scf_name_len + 1) < 0)
1668 					(void) strcpy(name_buf, "?");
1669 
1670 				warn(gettext(
1671 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1672 				    name_buf, scf_strerror(scfe));
1673 			}
1674 		}
1675 	}
1676 
1677 	return (0);
1678 }
1679 
1680 static void
1681 private_refresh(void)
1682 {
1683 	scf_instance_t *pinst = NULL;
1684 	scf_iter_t *piter = NULL;
1685 	ssize_t fmrilen;
1686 	size_t bufsz;
1687 	char *fmribuf;
1688 	void *ent;
1689 	int issvc;
1690 	int r;
1691 
1692 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1693 		return;
1694 
1695 	assert(cur_svc != NULL);
1696 
1697 	bufsz = max_scf_fmri_len + 1;
1698 	fmribuf = safe_malloc(bufsz);
1699 	if (cur_inst) {
1700 		issvc = 0;
1701 		ent = cur_inst;
1702 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1703 	} else {
1704 		issvc = 1;
1705 		ent = cur_svc;
1706 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1707 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1708 			scfdie();
1709 
1710 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1711 			scfdie();
1712 	}
1713 	if (fmrilen < 0) {
1714 		free(fmribuf);
1715 		if (scf_error() != SCF_ERROR_DELETED)
1716 			scfdie();
1717 
1718 		warn(emsg_deleted);
1719 		return;
1720 	}
1721 	assert(fmrilen < bufsz);
1722 
1723 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1724 	switch (r) {
1725 	case 0:
1726 		break;
1727 
1728 	case ECONNABORTED:
1729 		warn(gettext("Could not refresh %s "
1730 		    "(repository connection broken).\n"), fmribuf);
1731 		break;
1732 
1733 	case ECANCELED:
1734 		warn(emsg_deleted);
1735 		break;
1736 
1737 	case EPERM:
1738 		warn(gettext("Could not refresh %s "
1739 		    "(permission denied).\n"), fmribuf);
1740 		break;
1741 
1742 	case ENOSPC:
1743 		warn(gettext("Could not refresh %s "
1744 		    "(repository server out of resources).\n"),
1745 		    fmribuf);
1746 		break;
1747 
1748 	case EACCES:
1749 	default:
1750 		bad_error("refresh_entity", scf_error());
1751 	}
1752 
1753 	if (issvc) {
1754 		scf_instance_destroy(pinst);
1755 		scf_iter_destroy(piter);
1756 	}
1757 
1758 	free(fmribuf);
1759 }
1760 
1761 
1762 static int
1763 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1764 {
1765 	cbp->sc_err = scferror2errno(err);
1766 	return (UU_WALK_ERROR);
1767 }
1768 
1769 static int
1770 stash_scferror(scf_callback_t *cbp)
1771 {
1772 	return (stash_scferror_err(cbp, scf_error()));
1773 }
1774 
1775 static int select_inst(const char *);
1776 static int select_svc(const char *);
1777 
1778 /*
1779  * Take a property that does not have a type and check to see if a type
1780  * exists or can be gleened from the current data.  Set the type.
1781  *
1782  * Check the current level (instance) and then check the higher level
1783  * (service).  This could be the case for adding a new property to
1784  * the instance that's going to "override" a service level property.
1785  *
1786  * For a property :
1787  * 1. Take the type from an existing property
1788  * 2. Take the type from a template entry
1789  *
1790  * If the type can not be found, then leave the type as is, and let the import
1791  * report the problem of the missing type.
1792  */
1793 static int
1794 find_current_prop_type(void *p, void *g)
1795 {
1796 	property_t *prop = p;
1797 	scf_callback_t *lcb = g;
1798 	pgroup_t *pg = NULL;
1799 
1800 	const char *fmri = NULL;
1801 	char *lfmri = NULL;
1802 	char *cur_selection = NULL;
1803 
1804 	scf_propertygroup_t *sc_pg = NULL;
1805 	scf_property_t *sc_prop = NULL;
1806 	scf_pg_tmpl_t *t_pg = NULL;
1807 	scf_prop_tmpl_t *t_prop = NULL;
1808 	scf_type_t prop_type;
1809 
1810 	value_t *vp;
1811 	int issvc = lcb->sc_service;
1812 	int r = UU_WALK_ERROR;
1813 
1814 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1815 		return (UU_WALK_NEXT);
1816 
1817 	t_prop = scf_tmpl_prop_create(g_hndl);
1818 	sc_prop = scf_property_create(g_hndl);
1819 	if (sc_prop == NULL || t_prop == NULL) {
1820 		warn(gettext("Unable to create the property to attempt and "
1821 		    "find a missing type.\n"));
1822 
1823 		scf_property_destroy(sc_prop);
1824 		scf_tmpl_prop_destroy(t_prop);
1825 
1826 		return (UU_WALK_ERROR);
1827 	}
1828 
1829 	if (lcb->sc_flags == 1) {
1830 		pg = lcb->sc_parent;
1831 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1832 		fmri = pg->sc_parent->sc_fmri;
1833 retry_pg:
1834 		if (cur_svc && cur_selection == NULL) {
1835 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1836 			lscf_get_selection_str(cur_selection,
1837 			    max_scf_fmri_len + 1);
1838 
1839 			if (strcmp(cur_selection, fmri) != 0) {
1840 				lscf_select(fmri);
1841 			} else {
1842 				free(cur_selection);
1843 				cur_selection = NULL;
1844 			}
1845 		} else {
1846 			lscf_select(fmri);
1847 		}
1848 
1849 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1850 			warn(gettext("Unable to create property group to "
1851 			    "find a missing property type.\n"));
1852 
1853 			goto out;
1854 		}
1855 
1856 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1857 			/*
1858 			 * If this is the sc_pg from the parent
1859 			 * let the caller clean up the sc_pg,
1860 			 * and just throw it away in this case.
1861 			 */
1862 			if (sc_pg != lcb->sc_parent)
1863 				scf_pg_destroy(sc_pg);
1864 
1865 			sc_pg = NULL;
1866 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1867 				warn(gettext("Unable to create template "
1868 				    "property group to find a property "
1869 				    "type.\n"));
1870 
1871 				goto out;
1872 			}
1873 
1874 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1875 			    pg->sc_pgroup_name, NULL, t_pg,
1876 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1877 				/*
1878 				 * if instance get service and jump back
1879 				 */
1880 				scf_tmpl_pg_destroy(t_pg);
1881 				t_pg = NULL;
1882 				if (issvc == 0) {
1883 					entity_t *e = pg->sc_parent->sc_parent;
1884 
1885 					fmri = e->sc_fmri;
1886 					issvc = 1;
1887 					goto retry_pg;
1888 				} else {
1889 					goto out;
1890 				}
1891 			}
1892 		}
1893 	} else {
1894 		sc_pg = lcb->sc_parent;
1895 	}
1896 
1897 	/*
1898 	 * Attempt to get the type from an existing property.  If the property
1899 	 * cannot be found then attempt to get the type from a template entry
1900 	 * for the property.
1901 	 *
1902 	 * Finally, if at the instance level look at the service level.
1903 	 */
1904 	if (sc_pg != NULL &&
1905 	    pg_get_prop(sc_pg, prop->sc_property_name,
1906 	    sc_prop) == SCF_SUCCESS &&
1907 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1908 		prop->sc_value_type = prop_type;
1909 
1910 		/*
1911 		 * Found a type, update the value types and validate
1912 		 * the actual value against this type.
1913 		 */
1914 		for (vp = uu_list_first(prop->sc_property_values);
1915 		    vp != NULL;
1916 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1917 			vp->sc_type = prop->sc_value_type;
1918 			lxml_store_value(vp, 0, NULL);
1919 		}
1920 
1921 		r = UU_WALK_NEXT;
1922 		goto out;
1923 	}
1924 
1925 	/*
1926 	 * If we get here with t_pg set to NULL then we had to have
1927 	 * gotten an sc_pg but that sc_pg did not have the property
1928 	 * we are looking for.   So if the t_pg is not null look up
1929 	 * the template entry for the property.
1930 	 *
1931 	 * If the t_pg is null then need to attempt to get a matching
1932 	 * template entry for the sc_pg, and see if there is a property
1933 	 * entry for that template entry.
1934 	 */
1935 do_tmpl :
1936 	if (t_pg != NULL &&
1937 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1938 	    t_prop, 0) == SCF_SUCCESS) {
1939 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1940 			prop->sc_value_type = prop_type;
1941 
1942 			/*
1943 			 * Found a type, update the value types and validate
1944 			 * the actual value against this type.
1945 			 */
1946 			for (vp = uu_list_first(prop->sc_property_values);
1947 			    vp != NULL;
1948 			    vp = uu_list_next(prop->sc_property_values, vp)) {
1949 				vp->sc_type = prop->sc_value_type;
1950 				lxml_store_value(vp, 0, NULL);
1951 			}
1952 
1953 			r = UU_WALK_NEXT;
1954 			goto out;
1955 		}
1956 	} else {
1957 		if (t_pg == NULL && sc_pg) {
1958 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1959 				warn(gettext("Unable to create template "
1960 				    "property group to find a property "
1961 				    "type.\n"));
1962 
1963 				goto out;
1964 			}
1965 
1966 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
1967 				scf_tmpl_pg_destroy(t_pg);
1968 				t_pg = NULL;
1969 			} else {
1970 				goto do_tmpl;
1971 			}
1972 		}
1973 	}
1974 
1975 	if (issvc == 0) {
1976 		scf_instance_t *i;
1977 		scf_service_t *s;
1978 
1979 		issvc = 1;
1980 		if (lcb->sc_flags == 1) {
1981 			entity_t *e = pg->sc_parent->sc_parent;
1982 
1983 			fmri = e->sc_fmri;
1984 			goto retry_pg;
1985 		}
1986 
1987 		/*
1988 		 * because lcb->sc_flags was not set then this means
1989 		 * the pg was not used and can be used here.
1990 		 */
1991 		if ((pg = internal_pgroup_new()) == NULL) {
1992 			warn(gettext("Could not create internal property group "
1993 			    "to find a missing type."));
1994 
1995 			goto out;
1996 		}
1997 
1998 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
1999 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2000 		    max_scf_name_len + 1) < 0)
2001 				goto out;
2002 
2003 		i = scf_instance_create(g_hndl);
2004 		s = scf_service_create(g_hndl);
2005 		if (i == NULL || s == NULL ||
2006 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2007 			warn(gettext("Could not get a service for the instance "
2008 			    "to find a missing type."));
2009 
2010 			goto out;
2011 		}
2012 
2013 		/*
2014 		 * Check to see truly at the instance level.
2015 		 */
2016 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2017 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2018 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2019 			goto out;
2020 		else
2021 			fmri = (const char *)lfmri;
2022 
2023 		goto retry_pg;
2024 	}
2025 
2026 out :
2027 	if (sc_pg != lcb->sc_parent) {
2028 		scf_pg_destroy(sc_pg);
2029 	}
2030 
2031 	/*
2032 	 * If this is true then the pg was allocated
2033 	 * here, and the name was set so need to free
2034 	 * the name and the pg.
2035 	 */
2036 	if (pg != NULL && pg != lcb->sc_parent) {
2037 		free((char *)pg->sc_pgroup_name);
2038 		internal_pgroup_free(pg);
2039 	}
2040 
2041 	if (cur_selection) {
2042 		lscf_select(cur_selection);
2043 		free(cur_selection);
2044 	}
2045 
2046 	scf_tmpl_pg_destroy(t_pg);
2047 	scf_tmpl_prop_destroy(t_prop);
2048 	scf_property_destroy(sc_prop);
2049 
2050 	if (r != UU_WALK_NEXT)
2051 		warn(gettext("Could not find property type for \"%s\" "
2052 		    "from \"%s\"\n"), prop->sc_property_name,
2053 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2054 
2055 	free(lfmri);
2056 
2057 	return (r);
2058 }
2059 
2060 /*
2061  * Take a property group that does not have a type and check to see if a type
2062  * exists or can be gleened from the current data.  Set the type.
2063  *
2064  * Check the current level (instance) and then check the higher level
2065  * (service).  This could be the case for adding a new property to
2066  * the instance that's going to "override" a service level property.
2067  *
2068  * For a property group
2069  * 1. Take the type from an existing property group
2070  * 2. Take the type from a template entry
2071  *
2072  * If the type can not be found, then leave the type as is, and let the import
2073  * report the problem of the missing type.
2074  */
2075 static int
2076 find_current_pg_type(void *p, void *sori)
2077 {
2078 	entity_t *si = sori;
2079 	pgroup_t *pg = p;
2080 
2081 	const char *ofmri, *fmri;
2082 	char *cur_selection = NULL;
2083 	char *pg_type = NULL;
2084 
2085 	scf_propertygroup_t *sc_pg = NULL;
2086 	scf_pg_tmpl_t *t_pg = NULL;
2087 
2088 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2089 	int r = UU_WALK_ERROR;
2090 
2091 	ofmri = fmri = si->sc_fmri;
2092 	if (pg->sc_pgroup_type != NULL) {
2093 		r = UU_WALK_NEXT;
2094 
2095 		goto out;
2096 	}
2097 
2098 	sc_pg = scf_pg_create(g_hndl);
2099 	if (sc_pg == NULL) {
2100 		warn(gettext("Unable to create property group to attempt "
2101 		    "and find a missing type.\n"));
2102 
2103 		return (UU_WALK_ERROR);
2104 	}
2105 
2106 	/*
2107 	 * Using get_pg() requires that the cur_svc/cur_inst be
2108 	 * via lscf_select.  Need to preserve the current selection
2109 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2110 	 */
2111 	if (cur_svc) {
2112 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2113 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2114 	}
2115 
2116 	/*
2117 	 * If the property group exists get the type, and set
2118 	 * the pgroup_t type of that type.
2119 	 *
2120 	 * If not the check for a template pg_pattern entry
2121 	 * and take the type from that.
2122 	 */
2123 retry_svc:
2124 	lscf_select(fmri);
2125 
2126 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2127 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2128 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2129 		    max_scf_pg_type_len + 1) != -1) {
2130 			pg->sc_pgroup_type = pg_type;
2131 
2132 			r = UU_WALK_NEXT;
2133 			goto out;
2134 		} else {
2135 			free(pg_type);
2136 		}
2137 	} else {
2138 		if ((t_pg == NULL) &&
2139 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2140 			goto out;
2141 
2142 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2143 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2144 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2145 			pg->sc_pgroup_type = pg_type;
2146 
2147 			r = UU_WALK_NEXT;
2148 			goto out;
2149 		}
2150 	}
2151 
2152 	/*
2153 	 * If type is not found at the instance level then attempt to
2154 	 * find the type at the service level.
2155 	 */
2156 	if (!issvc) {
2157 		si = si->sc_parent;
2158 		fmri = si->sc_fmri;
2159 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2160 		goto retry_svc;
2161 	}
2162 
2163 out :
2164 	if (cur_selection) {
2165 		lscf_select(cur_selection);
2166 		free(cur_selection);
2167 	}
2168 
2169 	/*
2170 	 * Now walk the properties of the property group to make sure that
2171 	 * all properties have the correct type and values are valid for
2172 	 * those types.
2173 	 */
2174 	if (r == UU_WALK_NEXT) {
2175 		scf_callback_t cb;
2176 
2177 		cb.sc_service = issvc;
2178 		cb.sc_source_fmri = ofmri;
2179 		if (sc_pg != NULL) {
2180 			cb.sc_parent = sc_pg;
2181 			cb.sc_flags = 0;
2182 		} else {
2183 			cb.sc_parent = pg;
2184 			cb.sc_flags = 1;
2185 		}
2186 
2187 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2188 		    &cb, UU_DEFAULT) != 0) {
2189 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2190 				bad_error("uu_list_walk", uu_error());
2191 
2192 			r = UU_WALK_ERROR;
2193 		}
2194 	} else {
2195 		warn(gettext("Could not find property group type for "
2196 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2197 	}
2198 
2199 	scf_tmpl_pg_destroy(t_pg);
2200 	scf_pg_destroy(sc_pg);
2201 
2202 	return (r);
2203 }
2204 
2205 /*
2206  * Import.  These functions import a bundle into the repository.
2207  */
2208 
2209 /*
2210  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2211  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2212  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2213  * lcbdata->sc_err to
2214  *   ENOMEM - out of memory
2215  *   ECONNABORTED - repository connection broken
2216  *   ECANCELED - sc_trans's property group was deleted
2217  *   EINVAL - p's name is invalid (error printed)
2218  *	    - p has an invalid value (error printed)
2219  */
2220 static int
2221 lscf_property_import(void *v, void *pvt)
2222 {
2223 	property_t *p = v;
2224 	scf_callback_t *lcbdata = pvt;
2225 	value_t *vp;
2226 	scf_transaction_t *trans = lcbdata->sc_trans;
2227 	scf_transaction_entry_t *entr;
2228 	scf_value_t *val;
2229 	scf_type_t tp;
2230 
2231 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2232 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2233 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2234 		lcbdata->sc_enable = p;
2235 		return (UU_WALK_NEXT);
2236 	}
2237 
2238 	entr = scf_entry_create(lcbdata->sc_handle);
2239 	if (entr == NULL) {
2240 		switch (scf_error()) {
2241 		case SCF_ERROR_NO_MEMORY:
2242 			return (stash_scferror(lcbdata));
2243 
2244 		case SCF_ERROR_INVALID_ARGUMENT:
2245 		default:
2246 			bad_error("scf_entry_create", scf_error());
2247 		}
2248 	}
2249 
2250 	tp = p->sc_value_type;
2251 
2252 	if (scf_transaction_property_new(trans, entr,
2253 	    p->sc_property_name, tp) != 0) {
2254 		switch (scf_error()) {
2255 		case SCF_ERROR_INVALID_ARGUMENT:
2256 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2257 			scf_entry_destroy(entr);
2258 			return (stash_scferror(lcbdata));
2259 
2260 		case SCF_ERROR_EXISTS:
2261 			break;
2262 
2263 		case SCF_ERROR_DELETED:
2264 		case SCF_ERROR_CONNECTION_BROKEN:
2265 			scf_entry_destroy(entr);
2266 			return (stash_scferror(lcbdata));
2267 
2268 		case SCF_ERROR_NOT_BOUND:
2269 		case SCF_ERROR_HANDLE_MISMATCH:
2270 		case SCF_ERROR_NOT_SET:
2271 		default:
2272 			bad_error("scf_transaction_property_new", scf_error());
2273 		}
2274 
2275 		if (scf_transaction_property_change_type(trans, entr,
2276 		    p->sc_property_name, tp) != 0) {
2277 			switch (scf_error()) {
2278 			case SCF_ERROR_DELETED:
2279 			case SCF_ERROR_CONNECTION_BROKEN:
2280 				scf_entry_destroy(entr);
2281 				return (stash_scferror(lcbdata));
2282 
2283 			case SCF_ERROR_INVALID_ARGUMENT:
2284 				semerr(emsg_invalid_prop_name,
2285 				    p->sc_property_name);
2286 				scf_entry_destroy(entr);
2287 				return (stash_scferror(lcbdata));
2288 
2289 			case SCF_ERROR_NOT_FOUND:
2290 			case SCF_ERROR_NOT_SET:
2291 			case SCF_ERROR_HANDLE_MISMATCH:
2292 			case SCF_ERROR_NOT_BOUND:
2293 			default:
2294 				bad_error(
2295 				    "scf_transaction_property_change_type",
2296 				    scf_error());
2297 			}
2298 		}
2299 	}
2300 
2301 	for (vp = uu_list_first(p->sc_property_values);
2302 	    vp != NULL;
2303 	    vp = uu_list_next(p->sc_property_values, vp)) {
2304 		val = scf_value_create(g_hndl);
2305 		if (val == NULL) {
2306 			switch (scf_error()) {
2307 			case SCF_ERROR_NO_MEMORY:
2308 				return (stash_scferror(lcbdata));
2309 
2310 			case SCF_ERROR_INVALID_ARGUMENT:
2311 			default:
2312 				bad_error("scf_value_create", scf_error());
2313 			}
2314 		}
2315 
2316 		switch (tp) {
2317 		case SCF_TYPE_BOOLEAN:
2318 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2319 			break;
2320 		case SCF_TYPE_COUNT:
2321 			scf_value_set_count(val, vp->sc_u.sc_count);
2322 			break;
2323 		case SCF_TYPE_INTEGER:
2324 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2325 			break;
2326 		default:
2327 			assert(vp->sc_u.sc_string != NULL);
2328 			if (scf_value_set_from_string(val, tp,
2329 			    vp->sc_u.sc_string) != 0) {
2330 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2331 					bad_error("scf_value_set_from_string",
2332 					    scf_error());
2333 
2334 				warn(gettext("Value \"%s\" is not a valid "
2335 				    "%s.\n"), vp->sc_u.sc_string,
2336 				    scf_type_to_string(tp));
2337 				scf_value_destroy(val);
2338 				return (stash_scferror(lcbdata));
2339 			}
2340 			break;
2341 		}
2342 
2343 		if (scf_entry_add_value(entr, val) != 0)
2344 			bad_error("scf_entry_add_value", scf_error());
2345 	}
2346 
2347 	return (UU_WALK_NEXT);
2348 }
2349 
2350 /*
2351  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2352  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2353  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2354  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2355  * lcbdata->sc_err to
2356  *   ECONNABORTED - repository connection broken
2357  *   ENOMEM - out of memory
2358  *   ENOSPC - svc.configd is out of resources
2359  *   ECANCELED - sc_parent was deleted
2360  *   EPERM - could not create property group (permission denied) (error printed)
2361  *	   - could not modify property group (permission denied) (error printed)
2362  *	   - could not delete property group (permission denied) (error	printed)
2363  *   EROFS - could not create property group (repository is read-only)
2364  *	   - could not delete property group (repository is read-only)
2365  *   EACCES - could not create property group (backend access denied)
2366  *	    - could not delete property group (backend access denied)
2367  *   EEXIST - could not create property group (already exists)
2368  *   EINVAL - invalid property group name (error printed)
2369  *	    - invalid property name (error printed)
2370  *	    - invalid value (error printed)
2371  *   EBUSY - new property group deleted (error printed)
2372  *	   - new property group changed (error printed)
2373  *	   - property group added (error printed)
2374  *	   - property group deleted (error printed)
2375  */
2376 static int
2377 entity_pgroup_import(void *v, void *pvt)
2378 {
2379 	pgroup_t *p = v;
2380 	scf_callback_t cbdata;
2381 	scf_callback_t *lcbdata = pvt;
2382 	void *ent = lcbdata->sc_parent;
2383 	int issvc = lcbdata->sc_service;
2384 	int r;
2385 
2386 	const char * const pg_changed = gettext("%s changed unexpectedly "
2387 	    "(new property group \"%s\" changed).\n");
2388 
2389 	/* Never import deleted property groups. */
2390 	if (p->sc_pgroup_delete) {
2391 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2392 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2393 			goto delete_pg;
2394 		}
2395 		return (UU_WALK_NEXT);
2396 	}
2397 
2398 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2399 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2400 		lcbdata->sc_general = p;
2401 		return (UU_WALK_NEXT);
2402 	}
2403 
2404 add_pg:
2405 	if (issvc)
2406 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2407 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2408 	else
2409 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2410 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2411 	if (r != 0) {
2412 		switch (scf_error()) {
2413 		case SCF_ERROR_DELETED:
2414 		case SCF_ERROR_CONNECTION_BROKEN:
2415 		case SCF_ERROR_BACKEND_READONLY:
2416 		case SCF_ERROR_BACKEND_ACCESS:
2417 		case SCF_ERROR_NO_RESOURCES:
2418 			return (stash_scferror(lcbdata));
2419 
2420 		case SCF_ERROR_EXISTS:
2421 			if (lcbdata->sc_flags & SCI_FORCE)
2422 				break;
2423 			return (stash_scferror(lcbdata));
2424 
2425 		case SCF_ERROR_INVALID_ARGUMENT:
2426 			warn(emsg_fmri_invalid_pg_name_type,
2427 			    lcbdata->sc_source_fmri,
2428 			    p->sc_pgroup_name, p->sc_pgroup_type);
2429 			return (stash_scferror(lcbdata));
2430 
2431 		case SCF_ERROR_PERMISSION_DENIED:
2432 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2433 			    lcbdata->sc_target_fmri);
2434 			return (stash_scferror(lcbdata));
2435 
2436 		case SCF_ERROR_NOT_BOUND:
2437 		case SCF_ERROR_HANDLE_MISMATCH:
2438 		case SCF_ERROR_NOT_SET:
2439 		default:
2440 			bad_error("scf_service_add_pg", scf_error());
2441 		}
2442 
2443 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2444 			switch (scf_error()) {
2445 			case SCF_ERROR_CONNECTION_BROKEN:
2446 			case SCF_ERROR_DELETED:
2447 				return (stash_scferror(lcbdata));
2448 
2449 			case SCF_ERROR_INVALID_ARGUMENT:
2450 				warn(emsg_fmri_invalid_pg_name,
2451 				    lcbdata->sc_source_fmri,
2452 				    p->sc_pgroup_name);
2453 				return (stash_scferror(lcbdata));
2454 
2455 			case SCF_ERROR_NOT_FOUND:
2456 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2457 				    p->sc_pgroup_name);
2458 				lcbdata->sc_err = EBUSY;
2459 				return (UU_WALK_ERROR);
2460 
2461 			case SCF_ERROR_NOT_BOUND:
2462 			case SCF_ERROR_HANDLE_MISMATCH:
2463 			case SCF_ERROR_NOT_SET:
2464 			default:
2465 				bad_error("entity_get_pg", scf_error());
2466 			}
2467 		}
2468 
2469 		if (lcbdata->sc_flags & SCI_KEEP)
2470 			goto props;
2471 
2472 delete_pg:
2473 		if (scf_pg_delete(imp_pg) != 0) {
2474 			switch (scf_error()) {
2475 			case SCF_ERROR_DELETED:
2476 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2477 				    p->sc_pgroup_name);
2478 				lcbdata->sc_err = EBUSY;
2479 				return (UU_WALK_ERROR);
2480 
2481 			case SCF_ERROR_PERMISSION_DENIED:
2482 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2483 				    lcbdata->sc_target_fmri);
2484 				return (stash_scferror(lcbdata));
2485 
2486 			case SCF_ERROR_BACKEND_READONLY:
2487 			case SCF_ERROR_BACKEND_ACCESS:
2488 			case SCF_ERROR_CONNECTION_BROKEN:
2489 				return (stash_scferror(lcbdata));
2490 
2491 			case SCF_ERROR_NOT_SET:
2492 			default:
2493 				bad_error("scf_pg_delete", scf_error());
2494 			}
2495 		}
2496 
2497 		if (p->sc_pgroup_delete)
2498 			return (UU_WALK_NEXT);
2499 
2500 		goto add_pg;
2501 	}
2502 
2503 props:
2504 
2505 	/*
2506 	 * Add properties to property group, if any.
2507 	 */
2508 	cbdata.sc_handle = lcbdata->sc_handle;
2509 	cbdata.sc_parent = imp_pg;
2510 	cbdata.sc_flags = lcbdata->sc_flags;
2511 	cbdata.sc_trans = imp_tx;
2512 	cbdata.sc_enable = NULL;
2513 
2514 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2515 		switch (scf_error()) {
2516 		case SCF_ERROR_BACKEND_ACCESS:
2517 		case SCF_ERROR_BACKEND_READONLY:
2518 		case SCF_ERROR_CONNECTION_BROKEN:
2519 			return (stash_scferror(lcbdata));
2520 
2521 		case SCF_ERROR_DELETED:
2522 			warn(pg_changed, lcbdata->sc_target_fmri,
2523 			    p->sc_pgroup_name);
2524 			lcbdata->sc_err = EBUSY;
2525 			return (UU_WALK_ERROR);
2526 
2527 		case SCF_ERROR_PERMISSION_DENIED:
2528 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2529 			    lcbdata->sc_target_fmri);
2530 			return (stash_scferror(lcbdata));
2531 
2532 		case SCF_ERROR_NOT_BOUND:
2533 		case SCF_ERROR_NOT_SET:
2534 		case SCF_ERROR_IN_USE:
2535 		case SCF_ERROR_HANDLE_MISMATCH:
2536 		default:
2537 			bad_error("scf_transaction_start", scf_error());
2538 		}
2539 	}
2540 
2541 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2542 	    UU_DEFAULT) != 0) {
2543 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2544 			bad_error("uu_list_walk", uu_error());
2545 		scf_transaction_reset(imp_tx);
2546 
2547 		lcbdata->sc_err = cbdata.sc_err;
2548 		if (cbdata.sc_err == ECANCELED) {
2549 			warn(pg_changed, lcbdata->sc_target_fmri,
2550 			    p->sc_pgroup_name);
2551 			lcbdata->sc_err = EBUSY;
2552 		}
2553 		return (UU_WALK_ERROR);
2554 	}
2555 
2556 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2557 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2558 
2559 		/*
2560 		 * take the snapshot running snapshot then
2561 		 * import the stored general/enable property
2562 		 */
2563 		r = take_snap(ent, snap_running, imp_rsnap);
2564 		switch (r) {
2565 		case 0:
2566 			break;
2567 
2568 		case ECONNABORTED:
2569 			warn(gettext("Could not take %s snapshot on import "
2570 			    "(repository connection broken).\n"),
2571 			    snap_running);
2572 			lcbdata->sc_err = r;
2573 			return (UU_WALK_ERROR);
2574 		case ECANCELED:
2575 			warn(emsg_deleted);
2576 			lcbdata->sc_err = r;
2577 			return (UU_WALK_ERROR);
2578 
2579 		case EPERM:
2580 			warn(gettext("Could not take %s snapshot "
2581 			    "(permission denied).\n"), snap_running);
2582 			lcbdata->sc_err = r;
2583 			return (UU_WALK_ERROR);
2584 
2585 		case ENOSPC:
2586 			warn(gettext("Could not take %s snapshot"
2587 			    "(repository server out of resources).\n"),
2588 			    snap_running);
2589 			lcbdata->sc_err = r;
2590 			return (UU_WALK_ERROR);
2591 
2592 		default:
2593 			bad_error("take_snap", r);
2594 		}
2595 
2596 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2597 		if (r != UU_WALK_NEXT) {
2598 			if (r != UU_WALK_ERROR)
2599 				bad_error("lscf_property_import", r);
2600 			return (EINVAL);
2601 		}
2602 	}
2603 
2604 	r = scf_transaction_commit(imp_tx);
2605 	switch (r) {
2606 	case 1:
2607 		r = UU_WALK_NEXT;
2608 		break;
2609 
2610 	case 0:
2611 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2612 		lcbdata->sc_err = EBUSY;
2613 		r = UU_WALK_ERROR;
2614 		break;
2615 
2616 	case -1:
2617 		switch (scf_error()) {
2618 		case SCF_ERROR_BACKEND_READONLY:
2619 		case SCF_ERROR_BACKEND_ACCESS:
2620 		case SCF_ERROR_CONNECTION_BROKEN:
2621 		case SCF_ERROR_NO_RESOURCES:
2622 			r = stash_scferror(lcbdata);
2623 			break;
2624 
2625 		case SCF_ERROR_DELETED:
2626 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2627 			    p->sc_pgroup_name);
2628 			lcbdata->sc_err = EBUSY;
2629 			r = UU_WALK_ERROR;
2630 			break;
2631 
2632 		case SCF_ERROR_PERMISSION_DENIED:
2633 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2634 			    lcbdata->sc_target_fmri);
2635 			r = stash_scferror(lcbdata);
2636 			break;
2637 
2638 		case SCF_ERROR_NOT_SET:
2639 		case SCF_ERROR_INVALID_ARGUMENT:
2640 		case SCF_ERROR_NOT_BOUND:
2641 		default:
2642 			bad_error("scf_transaction_commit", scf_error());
2643 		}
2644 		break;
2645 
2646 	default:
2647 		bad_error("scf_transaction_commit", r);
2648 	}
2649 
2650 	scf_transaction_destroy_children(imp_tx);
2651 
2652 	return (r);
2653 }
2654 
2655 /*
2656  * Returns
2657  *   0 - success
2658  *   ECONNABORTED - repository connection broken
2659  *   ENOMEM - out of memory
2660  *   ENOSPC - svc.configd is out of resources
2661  *   ECANCELED - inst was deleted
2662  *   EPERM - could not create property group (permission denied) (error printed)
2663  *	   - could not modify property group (permission denied) (error printed)
2664  *   EROFS - could not create property group (repository is read-only)
2665  *   EACCES - could not create property group (backend access denied)
2666  *   EEXIST - could not create property group (already exists)
2667  *   EINVAL - invalid property group name (error printed)
2668  *	    - invalid property name (error printed)
2669  *	    - invalid value (error printed)
2670  *   EBUSY - new property group changed (error printed)
2671  */
2672 static int
2673 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2674     const entity_t *isvc, int flags)
2675 {
2676 	scf_callback_t cbdata;
2677 
2678 	cbdata.sc_handle = scf_service_handle(svc);
2679 	cbdata.sc_parent = svc;
2680 	cbdata.sc_service = 1;
2681 	cbdata.sc_general = 0;
2682 	cbdata.sc_enable = 0;
2683 	cbdata.sc_flags = flags;
2684 	cbdata.sc_source_fmri = isvc->sc_fmri;
2685 	cbdata.sc_target_fmri = target_fmri;
2686 
2687 	/*
2688 	 * If the op is set, then add the flag to the callback
2689 	 * flags for later use.
2690 	 */
2691 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2692 		switch (isvc->sc_op) {
2693 		case SVCCFG_OP_IMPORT :
2694 			cbdata.sc_flags |= SCI_OP_IMPORT;
2695 			break;
2696 		case SVCCFG_OP_APPLY :
2697 			cbdata.sc_flags |= SCI_OP_APPLY;
2698 			break;
2699 		case SVCCFG_OP_RESTORE :
2700 			cbdata.sc_flags |= SCI_OP_RESTORE;
2701 			break;
2702 		default :
2703 			uu_die(gettext("lscf_import_service_pgs : "
2704 			    "Unknown op stored in the service entity\n"));
2705 
2706 		}
2707 	}
2708 
2709 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2710 	    UU_DEFAULT) != 0) {
2711 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2712 			bad_error("uu_list_walk", uu_error());
2713 
2714 		return (cbdata.sc_err);
2715 	}
2716 
2717 	return (0);
2718 }
2719 
2720 /*
2721  * Returns
2722  *   0 - success
2723  *   ECONNABORTED - repository connection broken
2724  *   ENOMEM - out of memory
2725  *   ENOSPC - svc.configd is out of resources
2726  *   ECANCELED - inst was deleted
2727  *   EPERM - could not create property group (permission denied) (error printed)
2728  *	   - could not modify property group (permission denied) (error printed)
2729  *   EROFS - could not create property group (repository is read-only)
2730  *   EACCES - could not create property group (backend access denied)
2731  *   EEXIST - could not create property group (already exists)
2732  *   EINVAL - invalid property group name (error printed)
2733  *	    - invalid property name (error printed)
2734  *	    - invalid value (error printed)
2735  *   EBUSY - new property group changed (error printed)
2736  */
2737 static int
2738 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2739     const entity_t *iinst, int flags)
2740 {
2741 	scf_callback_t cbdata;
2742 
2743 	cbdata.sc_handle = scf_instance_handle(inst);
2744 	cbdata.sc_parent = inst;
2745 	cbdata.sc_service = 0;
2746 	cbdata.sc_general = NULL;
2747 	cbdata.sc_enable = NULL;
2748 	cbdata.sc_flags = flags;
2749 	cbdata.sc_source_fmri = iinst->sc_fmri;
2750 	cbdata.sc_target_fmri = target_fmri;
2751 
2752 	/*
2753 	 * If the op is set, then add the flag to the callback
2754 	 * flags for later use.
2755 	 */
2756 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2757 		switch (iinst->sc_op) {
2758 		case SVCCFG_OP_IMPORT :
2759 			cbdata.sc_flags |= SCI_OP_IMPORT;
2760 			break;
2761 		case SVCCFG_OP_APPLY :
2762 			cbdata.sc_flags |= SCI_OP_APPLY;
2763 			break;
2764 		case SVCCFG_OP_RESTORE :
2765 			cbdata.sc_flags |= SCI_OP_RESTORE;
2766 			break;
2767 		default :
2768 			uu_die(gettext("lscf_import_instance_pgs : "
2769 			    "Unknown op stored in the instance entity\n"));
2770 		}
2771 	}
2772 
2773 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2774 	    UU_DEFAULT) != 0) {
2775 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2776 			bad_error("uu_list_walk", uu_error());
2777 
2778 		return (cbdata.sc_err);
2779 	}
2780 
2781 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2782 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2783 		/*
2784 		 * If importing with the SCI_NOENABLED flag then
2785 		 * skip the delay, but if not then add the delay
2786 		 * of the enable property.
2787 		 */
2788 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2789 			cbdata.sc_flags |= SCI_DELAYENABLE;
2790 		}
2791 
2792 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2793 		    != UU_WALK_NEXT)
2794 			return (cbdata.sc_err);
2795 	}
2796 
2797 	return (0);
2798 }
2799 
2800 /*
2801  * Report the reasons why we can't upgrade pg2 to pg1.
2802  */
2803 static void
2804 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2805     int new)
2806 {
2807 	property_t *p1, *p2;
2808 
2809 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2810 
2811 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2812 		return;
2813 
2814 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2815 	    p1 != NULL;
2816 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2817 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2818 		if (p2 != NULL) {
2819 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2820 			    new);
2821 			continue;
2822 		}
2823 
2824 		if (new)
2825 			warn(gettext("Conflict upgrading %s (new property "
2826 			    "group \"%s\" is missing property \"%s\").\n"),
2827 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2828 		else
2829 			warn(gettext("Conflict upgrading %s (property "
2830 			    "\"%s/%s\" is missing).\n"), fmri,
2831 			    pg1->sc_pgroup_name, p1->sc_property_name);
2832 	}
2833 
2834 	/*
2835 	 * Since pg1 should be from the manifest, any properties in pg2 which
2836 	 * aren't in pg1 shouldn't be reported as conflicts.
2837 	 */
2838 }
2839 
2840 /*
2841  * Add transaction entries to tx which will upgrade cur's pg according to old
2842  * & new.
2843  *
2844  * Returns
2845  *   0 - success
2846  *   EINVAL - new has a property with an invalid name or value (message emitted)
2847  *   ENOMEM - out of memory
2848  */
2849 static int
2850 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2851     pgroup_t *cur, int speak, const char *fmri)
2852 {
2853 	property_t *p, *new_p, *cur_p;
2854 	scf_transaction_entry_t *e;
2855 	int r;
2856 	int is_general;
2857 	int is_protected;
2858 
2859 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2860 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2861 		bad_error("uu_list_walk", uu_error());
2862 
2863 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2864 
2865 	for (p = uu_list_first(old->sc_pgroup_props);
2866 	    p != NULL;
2867 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2868 		/* p is a property in the old property group. */
2869 
2870 		/* Protect live properties. */
2871 		is_protected = 0;
2872 		if (is_general) {
2873 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2874 			    0 ||
2875 			    strcmp(p->sc_property_name,
2876 			    SCF_PROPERTY_RESTARTER) == 0)
2877 				is_protected = 1;
2878 		}
2879 
2880 		/* Look for the same property in the new properties. */
2881 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2882 		if (new_p != NULL) {
2883 			new_p->sc_seen = 1;
2884 
2885 			/*
2886 			 * If the new property is the same as the old, don't do
2887 			 * anything (leave any user customizations).
2888 			 */
2889 			if (prop_equal(p, new_p, NULL, NULL, 0))
2890 				continue;
2891 
2892 			if (new_p->sc_property_override)
2893 				goto upgrade;
2894 		}
2895 
2896 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2897 		if (cur_p == NULL) {
2898 			/*
2899 			 * p has been deleted from the repository.  If we were
2900 			 * going to delete it anyway, do nothing.  Otherwise
2901 			 * report a conflict.
2902 			 */
2903 			if (new_p == NULL)
2904 				continue;
2905 
2906 			if (is_protected)
2907 				continue;
2908 
2909 			warn(gettext("Conflict upgrading %s "
2910 			    "(property \"%s/%s\" is missing).\n"), fmri,
2911 			    old->sc_pgroup_name, p->sc_property_name);
2912 			continue;
2913 		}
2914 
2915 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2916 			/*
2917 			 * Conflict.  Don't warn if the property is already the
2918 			 * way we want it, though.
2919 			 */
2920 			if (is_protected)
2921 				continue;
2922 
2923 			if (new_p == NULL)
2924 				(void) prop_equal(p, cur_p, fmri,
2925 				    old->sc_pgroup_name, 0);
2926 			else
2927 				(void) prop_equal(cur_p, new_p, fmri,
2928 				    old->sc_pgroup_name, 0);
2929 			continue;
2930 		}
2931 
2932 		if (is_protected) {
2933 			if (speak)
2934 				warn(gettext("%s: Refusing to upgrade "
2935 				    "\"%s/%s\" (live property).\n"), fmri,
2936 				    old->sc_pgroup_name, p->sc_property_name);
2937 			continue;
2938 		}
2939 
2940 upgrade:
2941 		/* p hasn't been customized in the repository.  Upgrade it. */
2942 		if (new_p == NULL) {
2943 			/* p was deleted.  Delete from cur if unchanged. */
2944 			if (speak)
2945 				warn(gettext(
2946 				    "%s: Deleting property \"%s/%s\".\n"),
2947 				    fmri, old->sc_pgroup_name,
2948 				    p->sc_property_name);
2949 
2950 			e = scf_entry_create(g_hndl);
2951 			if (e == NULL)
2952 				return (ENOMEM);
2953 
2954 			if (scf_transaction_property_delete(tx, e,
2955 			    p->sc_property_name) != 0) {
2956 				switch (scf_error()) {
2957 				case SCF_ERROR_DELETED:
2958 					scf_entry_destroy(e);
2959 					return (ECANCELED);
2960 
2961 				case SCF_ERROR_CONNECTION_BROKEN:
2962 					scf_entry_destroy(e);
2963 					return (ECONNABORTED);
2964 
2965 				case SCF_ERROR_NOT_FOUND:
2966 					/*
2967 					 * This can happen if cur is from the
2968 					 * running snapshot (and it differs
2969 					 * from the live properties).
2970 					 */
2971 					scf_entry_destroy(e);
2972 					break;
2973 
2974 				case SCF_ERROR_HANDLE_MISMATCH:
2975 				case SCF_ERROR_NOT_BOUND:
2976 				case SCF_ERROR_NOT_SET:
2977 				case SCF_ERROR_INVALID_ARGUMENT:
2978 				default:
2979 					bad_error(
2980 					    "scf_transaction_property_delete",
2981 					    scf_error());
2982 				}
2983 			}
2984 		} else {
2985 			scf_callback_t ctx;
2986 
2987 			if (speak)
2988 				warn(gettext(
2989 				    "%s: Upgrading property \"%s/%s\".\n"),
2990 				    fmri, old->sc_pgroup_name,
2991 				    p->sc_property_name);
2992 
2993 			ctx.sc_handle = g_hndl;
2994 			ctx.sc_trans = tx;
2995 			ctx.sc_flags = 0;
2996 
2997 			r = lscf_property_import(new_p, &ctx);
2998 			if (r != UU_WALK_NEXT) {
2999 				if (r != UU_WALK_ERROR)
3000 					bad_error("lscf_property_import", r);
3001 				return (EINVAL);
3002 			}
3003 		}
3004 	}
3005 
3006 	/* Go over the properties which were added. */
3007 	for (new_p = uu_list_first(new->sc_pgroup_props);
3008 	    new_p != NULL;
3009 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3010 		if (new_p->sc_seen)
3011 			continue;
3012 
3013 		/* This is a new property. */
3014 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3015 		if (cur_p == NULL) {
3016 			scf_callback_t ctx;
3017 
3018 			ctx.sc_handle = g_hndl;
3019 			ctx.sc_trans = tx;
3020 			ctx.sc_flags = 0;
3021 
3022 			r = lscf_property_import(new_p, &ctx);
3023 			if (r != UU_WALK_NEXT) {
3024 				if (r != UU_WALK_ERROR)
3025 					bad_error("lscf_property_import", r);
3026 				return (EINVAL);
3027 			}
3028 			continue;
3029 		}
3030 
3031 		/*
3032 		 * Report a conflict if the new property differs from the
3033 		 * current one.  Unless it's general/enabled, since that's
3034 		 * never in the last-import snapshot.
3035 		 */
3036 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3037 		    0 &&
3038 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3039 			continue;
3040 
3041 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3042 	}
3043 
3044 	return (0);
3045 }
3046 
3047 /*
3048  * Upgrade pg according to old & new.
3049  *
3050  * Returns
3051  *   0 - success
3052  *   ECONNABORTED - repository connection broken
3053  *   ENOMEM - out of memory
3054  *   ENOSPC - svc.configd is out of resources
3055  *   ECANCELED - pg was deleted
3056  *   EPERM - couldn't modify pg (permission denied)
3057  *   EROFS - couldn't modify pg (backend read-only)
3058  *   EACCES - couldn't modify pg (backend access denied)
3059  *   EINVAL - new has a property with invalid name or value (error printed)
3060  *   EBUSY - pg changed unexpectedly
3061  */
3062 static int
3063 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3064     pgroup_t *new, int speak, const char *fmri)
3065 {
3066 	int r;
3067 
3068 	if (scf_transaction_start(imp_tx, pg) != 0) {
3069 		switch (scf_error()) {
3070 		case SCF_ERROR_CONNECTION_BROKEN:
3071 		case SCF_ERROR_DELETED:
3072 		case SCF_ERROR_PERMISSION_DENIED:
3073 		case SCF_ERROR_BACKEND_READONLY:
3074 		case SCF_ERROR_BACKEND_ACCESS:
3075 			return (scferror2errno(scf_error()));
3076 
3077 		case SCF_ERROR_HANDLE_MISMATCH:
3078 		case SCF_ERROR_IN_USE:
3079 		case SCF_ERROR_NOT_BOUND:
3080 		case SCF_ERROR_NOT_SET:
3081 		default:
3082 			bad_error("scf_transaction_start", scf_error());
3083 		}
3084 	}
3085 
3086 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3087 	switch (r) {
3088 	case 0:
3089 		break;
3090 
3091 	case EINVAL:
3092 	case ENOMEM:
3093 		scf_transaction_destroy_children(imp_tx);
3094 		return (r);
3095 
3096 	default:
3097 		bad_error("add_upgrade_entries", r);
3098 	}
3099 
3100 	r = scf_transaction_commit(imp_tx);
3101 
3102 	scf_transaction_destroy_children(imp_tx);
3103 
3104 	switch (r) {
3105 	case 1:
3106 		break;
3107 
3108 	case 0:
3109 		return (EBUSY);
3110 
3111 	case -1:
3112 		switch (scf_error()) {
3113 		case SCF_ERROR_CONNECTION_BROKEN:
3114 		case SCF_ERROR_NO_RESOURCES:
3115 		case SCF_ERROR_PERMISSION_DENIED:
3116 		case SCF_ERROR_BACKEND_READONLY:
3117 		case SCF_ERROR_BACKEND_ACCESS:
3118 		case SCF_ERROR_DELETED:
3119 			return (scferror2errno(scf_error()));
3120 
3121 		case SCF_ERROR_NOT_BOUND:
3122 		case SCF_ERROR_INVALID_ARGUMENT:
3123 		case SCF_ERROR_NOT_SET:
3124 		default:
3125 			bad_error("scf_transaction_commit", scf_error());
3126 		}
3127 
3128 	default:
3129 		bad_error("scf_transaction_commit", r);
3130 	}
3131 
3132 	return (0);
3133 }
3134 
3135 /*
3136  * Compares two entity FMRIs.  Returns
3137  *
3138  *   1 - equal
3139  *   0 - not equal
3140  *   -1 - f1 is invalid or not an entity
3141  *   -2 - f2 is invalid or not an entity
3142  */
3143 static int
3144 fmri_equal(const char *f1, const char *f2)
3145 {
3146 	int r;
3147 	const char *s1, *i1, *pg1;
3148 	const char *s2, *i2, *pg2;
3149 
3150 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3151 		return (-1);
3152 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3153 		return (-1);
3154 
3155 	if (s1 == NULL || pg1 != NULL)
3156 		return (-1);
3157 
3158 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3159 		return (-2);
3160 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3161 		return (-2);
3162 
3163 	if (s2 == NULL || pg2 != NULL)
3164 		return (-2);
3165 
3166 	r = strcmp(s1, s2);
3167 	if (r != 0)
3168 		return (0);
3169 
3170 	if (i1 == NULL && i2 == NULL)
3171 		return (1);
3172 
3173 	if (i1 == NULL || i2 == NULL)
3174 		return (0);
3175 
3176 	return (strcmp(i1, i2) == 0);
3177 }
3178 
3179 /*
3180  * Import a dependent by creating a dependency property group in the dependent
3181  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3182  * dependents pg, and add an entry to create a new property for this
3183  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3184  *
3185  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3186  * lcbdata->sc_err to
3187  *   ECONNABORTED - repository connection broken
3188  *   ENOMEM - out of memory
3189  *   ENOSPC - configd is out of resources
3190  *   EINVAL - target is invalid (error printed)
3191  *	    - target is not an entity (error printed)
3192  *	    - dependent has invalid name (error printed)
3193  *	    - invalid property name (error printed)
3194  *	    - invalid value (error printed)
3195  *	    - scope of target does not exist (error printed)
3196  *   EPERM - couldn't create target (permission denied) (error printed)
3197  *	   - couldn't create dependency pg (permission denied) (error printed)
3198  *	   - couldn't modify dependency pg (permission denied) (error printed)
3199  *   EROFS - couldn't create target (repository read-only)
3200  *	   - couldn't create dependency pg (repository read-only)
3201  *   EACCES - couldn't create target (backend access denied)
3202  *	    - couldn't create dependency pg (backend access denied)
3203  *   ECANCELED - sc_trans's pg was deleted
3204  *   EALREADY - property for dependent already exists in sc_trans's pg
3205  *   EEXIST - dependency pg already exists in target (error printed)
3206  *   EBUSY - target deleted (error printed)
3207  *         - property group changed during import (error printed)
3208  */
3209 static int
3210 lscf_dependent_import(void *a1, void *pvt)
3211 {
3212 	pgroup_t *pgrp = a1;
3213 	scf_callback_t *lcbdata = pvt;
3214 
3215 	int isservice;
3216 	int ret;
3217 	scf_transaction_entry_t *e;
3218 	scf_value_t *val;
3219 	scf_callback_t dependent_cbdata;
3220 	scf_error_t scfe;
3221 
3222 	/*
3223 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3224 	 * it's invalid, we fail before modifying the repository.
3225 	 */
3226 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3227 	    &dependent_cbdata.sc_parent, &isservice);
3228 	switch (scfe) {
3229 	case SCF_ERROR_NONE:
3230 		break;
3231 
3232 	case SCF_ERROR_NO_MEMORY:
3233 		return (stash_scferror_err(lcbdata, scfe));
3234 
3235 	case SCF_ERROR_INVALID_ARGUMENT:
3236 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3237 		    "invalid.\n"), pgrp->sc_pgroup_name);
3238 		return (stash_scferror_err(lcbdata, scfe));
3239 
3240 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3241 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3242 		    "specifies neither a service nor an instance.\n"),
3243 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3244 		return (stash_scferror_err(lcbdata, scfe));
3245 
3246 	case SCF_ERROR_NOT_FOUND:
3247 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3248 		    &dependent_cbdata.sc_parent, &isservice);
3249 		switch (scfe) {
3250 		case SCF_ERROR_NONE:
3251 			break;
3252 
3253 		case SCF_ERROR_NO_MEMORY:
3254 		case SCF_ERROR_BACKEND_READONLY:
3255 		case SCF_ERROR_BACKEND_ACCESS:
3256 			return (stash_scferror_err(lcbdata, scfe));
3257 
3258 		case SCF_ERROR_NOT_FOUND:
3259 			semerr(gettext("The scope in FMRI \"%s\" for the "
3260 			    "\"%s\" dependent does not exist.\n"),
3261 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3262 			lcbdata->sc_err = EINVAL;
3263 			return (UU_WALK_ERROR);
3264 
3265 		case SCF_ERROR_PERMISSION_DENIED:
3266 			warn(gettext(
3267 			    "Could not create %s (permission denied).\n"),
3268 			    pgrp->sc_pgroup_fmri);
3269 			return (stash_scferror_err(lcbdata, scfe));
3270 
3271 		case SCF_ERROR_INVALID_ARGUMENT:
3272 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3273 		default:
3274 			bad_error("create_entity", scfe);
3275 		}
3276 		break;
3277 
3278 	default:
3279 		bad_error("fmri_to_entity", scfe);
3280 	}
3281 
3282 	if (lcbdata->sc_trans != NULL) {
3283 		e = scf_entry_create(lcbdata->sc_handle);
3284 		if (e == NULL) {
3285 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3286 				bad_error("scf_entry_create", scf_error());
3287 
3288 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3289 			return (stash_scferror(lcbdata));
3290 		}
3291 
3292 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3293 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3294 			switch (scf_error()) {
3295 			case SCF_ERROR_INVALID_ARGUMENT:
3296 				warn(gettext("Dependent of %s has invalid name "
3297 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3298 				    pgrp->sc_pgroup_name);
3299 				/* FALLTHROUGH */
3300 
3301 			case SCF_ERROR_DELETED:
3302 			case SCF_ERROR_CONNECTION_BROKEN:
3303 				scf_entry_destroy(e);
3304 				entity_destroy(dependent_cbdata.sc_parent,
3305 				    isservice);
3306 				return (stash_scferror(lcbdata));
3307 
3308 			case SCF_ERROR_EXISTS:
3309 				scf_entry_destroy(e);
3310 				entity_destroy(dependent_cbdata.sc_parent,
3311 				    isservice);
3312 				lcbdata->sc_err = EALREADY;
3313 				return (UU_WALK_ERROR);
3314 
3315 			case SCF_ERROR_NOT_BOUND:
3316 			case SCF_ERROR_HANDLE_MISMATCH:
3317 			case SCF_ERROR_NOT_SET:
3318 			default:
3319 				bad_error("scf_transaction_property_new",
3320 				    scf_error());
3321 			}
3322 		}
3323 
3324 		val = scf_value_create(lcbdata->sc_handle);
3325 		if (val == NULL) {
3326 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3327 				bad_error("scf_value_create", scf_error());
3328 
3329 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3330 			return (stash_scferror(lcbdata));
3331 		}
3332 
3333 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3334 		    pgrp->sc_pgroup_fmri) != 0)
3335 			/* invalid should have been caught above */
3336 			bad_error("scf_value_set_from_string", scf_error());
3337 
3338 		if (scf_entry_add_value(e, val) != 0)
3339 			bad_error("scf_entry_add_value", scf_error());
3340 	}
3341 
3342 	/* Add the property group to the target entity. */
3343 
3344 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3345 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3346 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3347 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3348 
3349 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3350 
3351 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3352 
3353 	if (ret == UU_WALK_NEXT)
3354 		return (ret);
3355 
3356 	if (ret != UU_WALK_ERROR)
3357 		bad_error("entity_pgroup_import", ret);
3358 
3359 	switch (dependent_cbdata.sc_err) {
3360 	case ECANCELED:
3361 		warn(gettext("%s deleted unexpectedly.\n"),
3362 		    pgrp->sc_pgroup_fmri);
3363 		lcbdata->sc_err = EBUSY;
3364 		break;
3365 
3366 	case EEXIST:
3367 		warn(gettext("Could not create \"%s\" dependency in %s "
3368 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3369 		    pgrp->sc_pgroup_fmri);
3370 		/* FALLTHROUGH */
3371 
3372 	default:
3373 		lcbdata->sc_err = dependent_cbdata.sc_err;
3374 	}
3375 
3376 	return (UU_WALK_ERROR);
3377 }
3378 
3379 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3380     const scf_snaplevel_t *, scf_transaction_t *);
3381 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3382     const pgroup_t *);
3383 
3384 /*
3385  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3386  * the current dependent targets from running (the snaplevel of a running
3387  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3388  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3389  * dependent targets and dependency properties from li_dpts_pg (the
3390  * "dependents" property group in snpl) and snpl (the snaplevel which
3391  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3392  * snpl doesn't have a "dependents" property group, and any dependents in ient
3393  * are new.
3394  *
3395  * Returns
3396  *   0 - success
3397  *   ECONNABORTED - repository connection broken
3398  *   ENOMEM - out of memory
3399  *   ENOSPC - configd is out of resources
3400  *   ECANCELED - ent was deleted
3401  *   ENODEV - the entity containing li_dpts_pg was deleted
3402  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3403  *	   - couldn't upgrade dependent (permission denied) (error printed)
3404  *	   - couldn't create dependent (permission denied) (error printed)
3405  *   EROFS - could not modify dependents pg (repository read-only)
3406  *	   - couldn't upgrade dependent (repository read-only)
3407  *	   - couldn't create dependent (repository read-only)
3408  *   EACCES - could not modify dependents pg (backend access denied)
3409  *	    - could not upgrade dependent (backend access denied)
3410  *	    - could not create dependent (backend access denied)
3411  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3412  *	   - dependent target deleted (error printed)
3413  *	   - dependent pg changed (error printed)
3414  *   EINVAL - new dependent is invalid (error printed)
3415  *   EBADF - snpl is corrupt (error printed)
3416  *	   - snpl has corrupt pg (error printed)
3417  *	   - dependency pg in target is corrupt (error printed)
3418  *	   - target has corrupt snapshot (error printed)
3419  *   EEXIST - dependency pg already existed in target service (error printed)
3420  */
3421 static int
3422 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3423     const scf_snaplevel_t *snpl, const entity_t *ient,
3424     const scf_snaplevel_t *running, void *ent)
3425 {
3426 	pgroup_t *new_dpt_pgroup;
3427 	scf_callback_t cbdata;
3428 	int r, unseen, tx_started = 0;
3429 	int have_cur_depts;
3430 
3431 	const char * const dependents = "dependents";
3432 
3433 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3434 
3435 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3436 		/* Nothing to do. */
3437 		return (0);
3438 
3439 	/* Fetch the current version of the "dependents" property group. */
3440 	have_cur_depts = 1;
3441 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3442 		switch (scf_error()) {
3443 		case SCF_ERROR_NOT_FOUND:
3444 			break;
3445 
3446 		case SCF_ERROR_DELETED:
3447 		case SCF_ERROR_CONNECTION_BROKEN:
3448 			return (scferror2errno(scf_error()));
3449 
3450 		case SCF_ERROR_NOT_SET:
3451 		case SCF_ERROR_INVALID_ARGUMENT:
3452 		case SCF_ERROR_HANDLE_MISMATCH:
3453 		case SCF_ERROR_NOT_BOUND:
3454 		default:
3455 			bad_error("entity_get_pg", scf_error());
3456 		}
3457 
3458 		have_cur_depts = 0;
3459 	}
3460 
3461 	/* Fetch the running version of the "dependents" property group. */
3462 	ud_run_dpts_pg_set = 0;
3463 	if (running != NULL)
3464 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3465 	else
3466 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3467 	if (r == 0) {
3468 		ud_run_dpts_pg_set = 1;
3469 	} else {
3470 		switch (scf_error()) {
3471 		case SCF_ERROR_NOT_FOUND:
3472 			break;
3473 
3474 		case SCF_ERROR_DELETED:
3475 		case SCF_ERROR_CONNECTION_BROKEN:
3476 			return (scferror2errno(scf_error()));
3477 
3478 		case SCF_ERROR_NOT_SET:
3479 		case SCF_ERROR_INVALID_ARGUMENT:
3480 		case SCF_ERROR_HANDLE_MISMATCH:
3481 		case SCF_ERROR_NOT_BOUND:
3482 		default:
3483 			bad_error(running ? "scf_snaplevel_get_pg" :
3484 			    "entity_get_pg", scf_error());
3485 		}
3486 	}
3487 
3488 	/*
3489 	 * Clear the seen fields of the dependents, so we can tell which ones
3490 	 * are new.
3491 	 */
3492 	if (uu_list_walk(ient->sc_dependents, clear_int,
3493 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3494 		bad_error("uu_list_walk", uu_error());
3495 
3496 	if (li_dpts_pg != NULL) {
3497 		/*
3498 		 * Each property in li_dpts_pg represents a dependent tag in
3499 		 * the old manifest.  For each, call upgrade_dependent(),
3500 		 * which will change ud_cur_depts_pg or dependencies in other
3501 		 * services as appropriate.  Note (a) that changes to
3502 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3503 		 * made en masse, and (b) it's ok if the entity doesn't have
3504 		 * a current version of the "dependents" property group,
3505 		 * because we'll just consider all dependents as customized
3506 		 * (by being deleted).
3507 		 */
3508 
3509 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3510 			switch (scf_error()) {
3511 			case SCF_ERROR_DELETED:
3512 				return (ENODEV);
3513 
3514 			case SCF_ERROR_CONNECTION_BROKEN:
3515 				return (ECONNABORTED);
3516 
3517 			case SCF_ERROR_HANDLE_MISMATCH:
3518 			case SCF_ERROR_NOT_BOUND:
3519 			case SCF_ERROR_NOT_SET:
3520 			default:
3521 				bad_error("scf_iter_pg_properties",
3522 				    scf_error());
3523 			}
3524 		}
3525 
3526 		if (have_cur_depts &&
3527 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3528 			switch (scf_error()) {
3529 			case SCF_ERROR_BACKEND_ACCESS:
3530 			case SCF_ERROR_BACKEND_READONLY:
3531 			case SCF_ERROR_CONNECTION_BROKEN:
3532 				return (scferror2errno(scf_error()));
3533 
3534 			case SCF_ERROR_DELETED:
3535 				warn(emsg_pg_deleted, ient->sc_fmri,
3536 				    dependents);
3537 				return (EBUSY);
3538 
3539 			case SCF_ERROR_PERMISSION_DENIED:
3540 				warn(emsg_pg_mod_perm, dependents,
3541 				    ient->sc_fmri);
3542 				return (scferror2errno(scf_error()));
3543 
3544 			case SCF_ERROR_HANDLE_MISMATCH:
3545 			case SCF_ERROR_IN_USE:
3546 			case SCF_ERROR_NOT_BOUND:
3547 			case SCF_ERROR_NOT_SET:
3548 			default:
3549 				bad_error("scf_transaction_start", scf_error());
3550 			}
3551 		}
3552 		tx_started = have_cur_depts;
3553 
3554 		for (;;) {
3555 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3556 			if (r == 0)
3557 				break;
3558 			if (r == 1) {
3559 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3560 				    tx_started ? ud_tx : NULL);
3561 				switch (r) {
3562 				case 0:
3563 					continue;
3564 
3565 				case ECONNABORTED:
3566 				case ENOMEM:
3567 				case ENOSPC:
3568 				case EBADF:
3569 				case EBUSY:
3570 				case EINVAL:
3571 				case EPERM:
3572 				case EROFS:
3573 				case EACCES:
3574 				case EEXIST:
3575 					break;
3576 
3577 				case ECANCELED:
3578 					r = ENODEV;
3579 					break;
3580 
3581 				default:
3582 					bad_error("upgrade_dependent", r);
3583 				}
3584 
3585 				if (tx_started)
3586 					scf_transaction_destroy_children(ud_tx);
3587 				return (r);
3588 			}
3589 			if (r != -1)
3590 				bad_error("scf_iter_next_property", r);
3591 
3592 			switch (scf_error()) {
3593 			case SCF_ERROR_DELETED:
3594 				r = ENODEV;
3595 				break;
3596 
3597 			case SCF_ERROR_CONNECTION_BROKEN:
3598 				r = ECONNABORTED;
3599 				break;
3600 
3601 			case SCF_ERROR_NOT_SET:
3602 			case SCF_ERROR_INVALID_ARGUMENT:
3603 			case SCF_ERROR_NOT_BOUND:
3604 			case SCF_ERROR_HANDLE_MISMATCH:
3605 			default:
3606 				bad_error("scf_iter_next_property",
3607 				    scf_error());
3608 			}
3609 
3610 			if (tx_started)
3611 				scf_transaction_destroy_children(ud_tx);
3612 			return (r);
3613 		}
3614 	}
3615 
3616 	/* import unseen dependents */
3617 	unseen = 0;
3618 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3619 	    new_dpt_pgroup != NULL;
3620 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3621 	    new_dpt_pgroup)) {
3622 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3623 			unseen = 1;
3624 			break;
3625 		}
3626 	}
3627 
3628 	/* If there are none, exit early. */
3629 	if (unseen == 0)
3630 		goto commit;
3631 
3632 	/* Set up for lscf_dependent_import() */
3633 	cbdata.sc_handle = g_hndl;
3634 	cbdata.sc_parent = ent;
3635 	cbdata.sc_service = issvc;
3636 	cbdata.sc_flags = 0;
3637 
3638 	if (!have_cur_depts) {
3639 		/*
3640 		 * We have new dependents to import, so we need a "dependents"
3641 		 * property group.
3642 		 */
3643 		if (issvc)
3644 			r = scf_service_add_pg(ent, dependents,
3645 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3646 		else
3647 			r = scf_instance_add_pg(ent, dependents,
3648 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3649 		if (r != 0) {
3650 			switch (scf_error()) {
3651 			case SCF_ERROR_DELETED:
3652 			case SCF_ERROR_CONNECTION_BROKEN:
3653 			case SCF_ERROR_BACKEND_READONLY:
3654 			case SCF_ERROR_BACKEND_ACCESS:
3655 			case SCF_ERROR_NO_RESOURCES:
3656 				return (scferror2errno(scf_error()));
3657 
3658 			case SCF_ERROR_EXISTS:
3659 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3660 				return (EBUSY);
3661 
3662 			case SCF_ERROR_PERMISSION_DENIED:
3663 				warn(emsg_pg_add_perm, dependents,
3664 				    ient->sc_fmri);
3665 				return (scferror2errno(scf_error()));
3666 
3667 			case SCF_ERROR_NOT_BOUND:
3668 			case SCF_ERROR_HANDLE_MISMATCH:
3669 			case SCF_ERROR_INVALID_ARGUMENT:
3670 			case SCF_ERROR_NOT_SET:
3671 			default:
3672 				bad_error("scf_service_add_pg", scf_error());
3673 			}
3674 		}
3675 	}
3676 
3677 	cbdata.sc_trans = ud_tx;
3678 
3679 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3680 		switch (scf_error()) {
3681 		case SCF_ERROR_CONNECTION_BROKEN:
3682 		case SCF_ERROR_BACKEND_ACCESS:
3683 		case SCF_ERROR_BACKEND_READONLY:
3684 			return (scferror2errno(scf_error()));
3685 
3686 		case SCF_ERROR_DELETED:
3687 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3688 			return (EBUSY);
3689 
3690 		case SCF_ERROR_PERMISSION_DENIED:
3691 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3692 			return (scferror2errno(scf_error()));
3693 
3694 		case SCF_ERROR_HANDLE_MISMATCH:
3695 		case SCF_ERROR_IN_USE:
3696 		case SCF_ERROR_NOT_BOUND:
3697 		case SCF_ERROR_NOT_SET:
3698 		default:
3699 			bad_error("scf_transaction_start", scf_error());
3700 		}
3701 	}
3702 	tx_started = 1;
3703 
3704 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3705 	    new_dpt_pgroup != NULL;
3706 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3707 	    new_dpt_pgroup)) {
3708 		if (new_dpt_pgroup->sc_pgroup_seen)
3709 			continue;
3710 
3711 		if (ud_run_dpts_pg_set) {
3712 			/*
3713 			 * If the dependent is already there, then we have
3714 			 * a conflict.
3715 			 */
3716 			if (scf_pg_get_property(ud_run_dpts_pg,
3717 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3718 				r = handle_dependent_conflict(ient, ud_prop,
3719 				    new_dpt_pgroup);
3720 				switch (r) {
3721 				case 0:
3722 					continue;
3723 
3724 				case ECONNABORTED:
3725 				case ENOMEM:
3726 				case EBUSY:
3727 				case EBADF:
3728 				case EINVAL:
3729 					scf_transaction_destroy_children(ud_tx);
3730 					return (r);
3731 
3732 				default:
3733 					bad_error("handle_dependent_conflict",
3734 					    r);
3735 				}
3736 			} else {
3737 				switch (scf_error()) {
3738 				case SCF_ERROR_NOT_FOUND:
3739 					break;
3740 
3741 				case SCF_ERROR_INVALID_ARGUMENT:
3742 					warn(emsg_fmri_invalid_pg_name,
3743 					    ient->sc_fmri,
3744 					    new_dpt_pgroup->sc_pgroup_name);
3745 					scf_transaction_destroy_children(ud_tx);
3746 					return (EINVAL);
3747 
3748 				case SCF_ERROR_DELETED:
3749 					warn(emsg_pg_deleted, ient->sc_fmri,
3750 					    new_dpt_pgroup->sc_pgroup_name);
3751 					scf_transaction_destroy_children(ud_tx);
3752 					return (EBUSY);
3753 
3754 				case SCF_ERROR_CONNECTION_BROKEN:
3755 					scf_transaction_destroy_children(ud_tx);
3756 					return (ECONNABORTED);
3757 
3758 				case SCF_ERROR_NOT_BOUND:
3759 				case SCF_ERROR_HANDLE_MISMATCH:
3760 				case SCF_ERROR_NOT_SET:
3761 				default:
3762 					bad_error("scf_pg_get_property",
3763 					    scf_error());
3764 				}
3765 			}
3766 		}
3767 
3768 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3769 		if (r != UU_WALK_NEXT) {
3770 			if (r != UU_WALK_ERROR)
3771 				bad_error("lscf_dependent_import", r);
3772 
3773 			if (cbdata.sc_err == EALREADY) {
3774 				/* Collisions were handled preemptively. */
3775 				bad_error("lscf_dependent_import",
3776 				    cbdata.sc_err);
3777 			}
3778 
3779 			scf_transaction_destroy_children(ud_tx);
3780 			return (cbdata.sc_err);
3781 		}
3782 	}
3783 
3784 commit:
3785 	if (!tx_started)
3786 		return (0);
3787 
3788 	r = scf_transaction_commit(ud_tx);
3789 
3790 	scf_transaction_destroy_children(ud_tx);
3791 
3792 	switch (r) {
3793 	case 1:
3794 		return (0);
3795 
3796 	case 0:
3797 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3798 		return (EBUSY);
3799 
3800 	case -1:
3801 		break;
3802 
3803 	default:
3804 		bad_error("scf_transaction_commit", r);
3805 	}
3806 
3807 	switch (scf_error()) {
3808 	case SCF_ERROR_CONNECTION_BROKEN:
3809 	case SCF_ERROR_BACKEND_READONLY:
3810 	case SCF_ERROR_BACKEND_ACCESS:
3811 	case SCF_ERROR_NO_RESOURCES:
3812 		return (scferror2errno(scf_error()));
3813 
3814 	case SCF_ERROR_DELETED:
3815 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3816 		return (EBUSY);
3817 
3818 	case SCF_ERROR_PERMISSION_DENIED:
3819 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3820 		return (scferror2errno(scf_error()));
3821 
3822 	case SCF_ERROR_NOT_BOUND:
3823 	case SCF_ERROR_INVALID_ARGUMENT:
3824 	case SCF_ERROR_NOT_SET:
3825 	default:
3826 		bad_error("scf_transaction_destroy", scf_error());
3827 		/* NOTREACHED */
3828 	}
3829 }
3830 
3831 /*
3832  * Used to add the manifests to the list of currently supported manifests.
3833  * We can modify the existing manifest list removing entries if the files
3834  * don't exist.
3835  *
3836  * Get the old list and the new file name
3837  * If the new file name is in the list return
3838  * If not then add the file to the list.
3839  * As we process the list check to see if the files in the old list exist
3840  * 	if not then remove the file from the list.
3841  * Commit the list of manifest file names.
3842  *
3843  */
3844 static int
3845 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3846     const scf_snaplevel_t *running, void *ent)
3847 {
3848 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3849 	scf_property_t *ud_prop = NULL;
3850 	scf_iter_t *ud_prop_iter;
3851 	scf_value_t *fname_value;
3852 	scf_callback_t cbdata;
3853 	pgroup_t *mfst_pgroup;
3854 	property_t *mfst_prop;
3855 	property_t *old_prop;
3856 	char *pname = malloc(MAXPATHLEN);
3857 	char *fval = NULL;
3858 	char *old_pname;
3859 	char *old_fval;
3860 	int no_upgrade_pg;
3861 	int mfst_seen;
3862 	int r;
3863 
3864 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3865 
3866 	/*
3867 	 * This should always be the service base on the code
3868 	 * path, and the fact that the manifests pg is a service
3869 	 * level property group only.
3870 	 */
3871 	ud_mfsts_pg = scf_pg_create(g_hndl);
3872 	ud_prop = scf_property_create(g_hndl);
3873 	ud_prop_iter = scf_iter_create(g_hndl);
3874 	fname_value = scf_value_create(g_hndl);
3875 
3876 	/* Fetch the "manifests" property group */
3877 	no_upgrade_pg = 0;
3878 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3879 	    ud_mfsts_pg);
3880 	if (r != 0) {
3881 		switch (scf_error()) {
3882 		case SCF_ERROR_NOT_FOUND:
3883 			no_upgrade_pg = 1;
3884 			break;
3885 
3886 		case SCF_ERROR_DELETED:
3887 		case SCF_ERROR_CONNECTION_BROKEN:
3888 			return (scferror2errno(scf_error()));
3889 
3890 		case SCF_ERROR_NOT_SET:
3891 		case SCF_ERROR_INVALID_ARGUMENT:
3892 		case SCF_ERROR_HANDLE_MISMATCH:
3893 		case SCF_ERROR_NOT_BOUND:
3894 		default:
3895 			bad_error(running ? "scf_snaplevel_get_pg" :
3896 			    "entity_get_pg", scf_error());
3897 		}
3898 	}
3899 
3900 	if (no_upgrade_pg) {
3901 		cbdata.sc_handle = g_hndl;
3902 		cbdata.sc_parent = ent;
3903 		cbdata.sc_service = issvc;
3904 		cbdata.sc_flags = SCI_FORCE;
3905 		cbdata.sc_source_fmri = ient->sc_fmri;
3906 		cbdata.sc_target_fmri = ient->sc_fmri;
3907 
3908 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3909 			return (cbdata.sc_err);
3910 
3911 		return (0);
3912 	}
3913 
3914 	/* Fetch the new manifests property group */
3915 	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3916 	    mfst_pgroup != NULL;
3917 	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3918 		if (strcmp(mfst_pgroup->sc_pgroup_name,
3919 		    SCF_PG_MANIFESTFILES) == 0)
3920 			break;
3921 	}
3922 
3923 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3924 	    SCF_SUCCESS)
3925 		return (-1);
3926 
3927 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3928 		mfst_seen = 0;
3929 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3930 			continue;
3931 
3932 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3933 		    mfst_prop != NULL;
3934 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3935 		    mfst_prop)) {
3936 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3937 				mfst_seen = 1;
3938 			}
3939 		}
3940 
3941 		/*
3942 		 * If the manifest is not seen then add it to the new mfst
3943 		 * property list to get proccessed into the repo.
3944 		 */
3945 		if (mfst_seen == 0) {
3946 			if (fval == NULL)
3947 				fval = malloc(MAXPATHLEN);
3948 
3949 			/*
3950 			 * If we cannot get the value then there is no
3951 			 * reason to attempt to attach the value to
3952 			 * the property group
3953 			 */
3954 			if (fval != NULL &&
3955 			    prop_get_val(ud_prop, fname_value) == 0 &&
3956 			    scf_value_get_astring(fname_value, fval,
3957 			    MAXPATHLEN) != -1)  {
3958 				old_pname = safe_strdup(pname);
3959 				old_fval = safe_strdup(fval);
3960 				old_prop = internal_property_create(old_pname,
3961 				    SCF_TYPE_ASTRING, 1, old_fval);
3962 
3963 				/*
3964 				 * Already checked to see if the property exists
3965 				 * in the group, and it does not.
3966 				 */
3967 				(void) internal_attach_property(mfst_pgroup,
3968 				    old_prop);
3969 			}
3970 		}
3971 	}
3972 	free(fval);
3973 
3974 	cbdata.sc_handle = g_hndl;
3975 	cbdata.sc_parent = ent;
3976 	cbdata.sc_service = issvc;
3977 	cbdata.sc_flags = SCI_FORCE;
3978 	cbdata.sc_source_fmri = ient->sc_fmri;
3979 	cbdata.sc_target_fmri = ient->sc_fmri;
3980 
3981 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
3982 		return (cbdata.sc_err);
3983 
3984 	return (r);
3985 }
3986 
3987 /*
3988  * prop is taken to be a property in the "dependents" property group of snpl,
3989  * which is taken to be the snaplevel of a last-import snapshot corresponding
3990  * to ient.  If prop is a valid dependents property, upgrade the dependent it
3991  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
3992  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
3993  * of the entity ient represents (possibly in the running snapshot).  If it
3994  * needs to be changed, an entry will be added to tx, if not NULL.
3995  *
3996  * Returns
3997  *   0 - success
3998  *   ECONNABORTED - repository connection broken
3999  *   ENOMEM - out of memory
4000  *   ENOSPC - configd was out of resources
4001  *   ECANCELED - snpl's entity was deleted
4002  *   EINVAL - dependent target is invalid (error printed)
4003  *	    - dependent is invalid (error printed)
4004  *   EBADF - snpl is corrupt (error printed)
4005  *	   - snpl has corrupt pg (error printed)
4006  *	   - dependency pg in target is corrupt (error printed)
4007  *	   - running snapshot in dependent is missing snaplevel (error printed)
4008  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4009  *	   - couldn't create dependent (permission denied) (error printed)
4010  *	   - couldn't modify dependent pg (permission denied) (error printed)
4011  *   EROFS - couldn't delete dependency pg (repository read-only)
4012  *	   - couldn't create dependent (repository read-only)
4013  *   EACCES - couldn't delete dependency pg (backend access denied)
4014  *	    - couldn't create dependent (backend access denied)
4015  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4016  *	   - tx's pg was deleted (error printed)
4017  *	   - dependent pg was changed or deleted (error printed)
4018  *   EEXIST - dependency pg already exists in new target (error printed)
4019  */
4020 static int
4021 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4022     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4023 {
4024 	pgroup_t pgrp;
4025 	scf_type_t ty;
4026 	pgroup_t *new_dpt_pgroup;
4027 	pgroup_t *old_dpt_pgroup = NULL;
4028 	pgroup_t *current_pg;
4029 	pgroup_t *dpt;
4030 	scf_callback_t cbdata;
4031 	int tissvc;
4032 	void *target_ent;
4033 	scf_error_t serr;
4034 	int r;
4035 	scf_transaction_entry_t *ent;
4036 
4037 	const char * const cf_inval = gettext("Conflict upgrading %s "
4038 	    "(dependent \"%s\" has invalid dependents property).\n");
4039 	const char * const cf_missing = gettext("Conflict upgrading %s "
4040 	    "(dependent \"%s\" is missing).\n");
4041 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4042 	    "(dependent \"%s\" has new dependency property group).\n");
4043 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4044 	    "(dependent \"%s\" has new target).\n");
4045 	const char * const li_corrupt =
4046 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4047 	const char * const upgrading =
4048 	    gettext("%s: Upgrading dependent \"%s\".\n");
4049 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4050 	    "corrupt (missing snaplevel).\n");
4051 
4052 	if (scf_property_type(prop, &ty) != 0) {
4053 		switch (scf_error()) {
4054 		case SCF_ERROR_DELETED:
4055 		case SCF_ERROR_CONNECTION_BROKEN:
4056 			return (scferror2errno(scf_error()));
4057 
4058 		case SCF_ERROR_NOT_BOUND:
4059 		case SCF_ERROR_NOT_SET:
4060 		default:
4061 			bad_error("scf_property_type", scf_error());
4062 		}
4063 	}
4064 
4065 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4066 		warn(li_corrupt, ient->sc_fmri);
4067 		return (EBADF);
4068 	}
4069 
4070 	/*
4071 	 * prop represents a dependent in the old manifest.  It is named after
4072 	 * the dependent.
4073 	 */
4074 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4075 		switch (scf_error()) {
4076 		case SCF_ERROR_DELETED:
4077 		case SCF_ERROR_CONNECTION_BROKEN:
4078 			return (scferror2errno(scf_error()));
4079 
4080 		case SCF_ERROR_NOT_BOUND:
4081 		case SCF_ERROR_NOT_SET:
4082 		default:
4083 			bad_error("scf_property_get_name", scf_error());
4084 		}
4085 	}
4086 
4087 	/* See if it's in the new manifest. */
4088 	pgrp.sc_pgroup_name = ud_name;
4089 	new_dpt_pgroup =
4090 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4091 
4092 	/* If it's not, delete it... if it hasn't been customized. */
4093 	if (new_dpt_pgroup == NULL) {
4094 		if (!ud_run_dpts_pg_set)
4095 			return (0);
4096 
4097 		if (scf_property_get_value(prop, ud_val) != 0) {
4098 			switch (scf_error()) {
4099 			case SCF_ERROR_NOT_FOUND:
4100 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4101 				warn(li_corrupt, ient->sc_fmri);
4102 				return (EBADF);
4103 
4104 			case SCF_ERROR_DELETED:
4105 			case SCF_ERROR_CONNECTION_BROKEN:
4106 				return (scferror2errno(scf_error()));
4107 
4108 			case SCF_ERROR_HANDLE_MISMATCH:
4109 			case SCF_ERROR_NOT_BOUND:
4110 			case SCF_ERROR_NOT_SET:
4111 			case SCF_ERROR_PERMISSION_DENIED:
4112 			default:
4113 				bad_error("scf_property_get_value",
4114 				    scf_error());
4115 			}
4116 		}
4117 
4118 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4119 		    max_scf_value_len + 1) < 0)
4120 			bad_error("scf_value_get_as_string", scf_error());
4121 
4122 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4123 		    0) {
4124 			switch (scf_error()) {
4125 			case SCF_ERROR_NOT_FOUND:
4126 				return (0);
4127 
4128 			case SCF_ERROR_CONNECTION_BROKEN:
4129 				return (scferror2errno(scf_error()));
4130 
4131 			case SCF_ERROR_DELETED:
4132 				warn(emsg_pg_deleted, ient->sc_fmri,
4133 				    "dependents");
4134 				return (EBUSY);
4135 
4136 			case SCF_ERROR_INVALID_ARGUMENT:
4137 			case SCF_ERROR_NOT_BOUND:
4138 			case SCF_ERROR_HANDLE_MISMATCH:
4139 			case SCF_ERROR_NOT_SET:
4140 			default:
4141 				bad_error("scf_pg_get_property", scf_error());
4142 			}
4143 		}
4144 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4145 			switch (scf_error()) {
4146 			case SCF_ERROR_NOT_FOUND:
4147 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4148 				warn(cf_inval, ient->sc_fmri, ud_name);
4149 				return (0);
4150 
4151 			case SCF_ERROR_DELETED:
4152 			case SCF_ERROR_CONNECTION_BROKEN:
4153 				return (scferror2errno(scf_error()));
4154 
4155 			case SCF_ERROR_HANDLE_MISMATCH:
4156 			case SCF_ERROR_NOT_BOUND:
4157 			case SCF_ERROR_NOT_SET:
4158 			case SCF_ERROR_PERMISSION_DENIED:
4159 			default:
4160 				bad_error("scf_property_get_value",
4161 				    scf_error());
4162 			}
4163 		}
4164 
4165 		ty = scf_value_type(ud_val);
4166 		assert(ty != SCF_TYPE_INVALID);
4167 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4168 			warn(cf_inval, ient->sc_fmri, ud_name);
4169 			return (0);
4170 		}
4171 
4172 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4173 		    max_scf_value_len + 1) < 0)
4174 			bad_error("scf_value_get_as_string", scf_error());
4175 
4176 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4177 		switch (r) {
4178 		case 1:
4179 			break;
4180 
4181 		case 0:
4182 		case -1:	/* warn? */
4183 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4184 			return (0);
4185 
4186 		case -2:
4187 			warn(li_corrupt, ient->sc_fmri);
4188 			return (EBADF);
4189 
4190 		default:
4191 			bad_error("fmri_equal", r);
4192 		}
4193 
4194 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4195 			switch (scf_error()) {
4196 			case SCF_ERROR_NOT_FOUND:
4197 				warn(li_corrupt, ient->sc_fmri);
4198 				return (EBADF);
4199 
4200 			case SCF_ERROR_DELETED:
4201 			case SCF_ERROR_CONNECTION_BROKEN:
4202 				return (scferror2errno(scf_error()));
4203 
4204 			case SCF_ERROR_NOT_BOUND:
4205 			case SCF_ERROR_HANDLE_MISMATCH:
4206 			case SCF_ERROR_INVALID_ARGUMENT:
4207 			case SCF_ERROR_NOT_SET:
4208 			default:
4209 				bad_error("scf_snaplevel_get_pg", scf_error());
4210 			}
4211 		}
4212 
4213 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4214 		    snap_lastimport);
4215 		switch (r) {
4216 		case 0:
4217 			break;
4218 
4219 		case ECANCELED:
4220 		case ECONNABORTED:
4221 		case ENOMEM:
4222 		case EBADF:
4223 			return (r);
4224 
4225 		case EACCES:
4226 		default:
4227 			bad_error("load_pg", r);
4228 		}
4229 
4230 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4231 		switch (serr) {
4232 		case SCF_ERROR_NONE:
4233 			break;
4234 
4235 		case SCF_ERROR_NO_MEMORY:
4236 			internal_pgroup_free(old_dpt_pgroup);
4237 			return (ENOMEM);
4238 
4239 		case SCF_ERROR_NOT_FOUND:
4240 			internal_pgroup_free(old_dpt_pgroup);
4241 			goto delprop;
4242 
4243 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4244 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4245 		default:
4246 			bad_error("fmri_to_entity", serr);
4247 		}
4248 
4249 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4250 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4251 		switch (r) {
4252 		case 0:
4253 			break;
4254 
4255 		case ECONNABORTED:
4256 			internal_pgroup_free(old_dpt_pgroup);
4257 			return (r);
4258 
4259 		case ECANCELED:
4260 		case ENOENT:
4261 			internal_pgroup_free(old_dpt_pgroup);
4262 			goto delprop;
4263 
4264 		case EBADF:
4265 			warn(r_no_lvl, ud_ctarg);
4266 			internal_pgroup_free(old_dpt_pgroup);
4267 			return (r);
4268 
4269 		case EINVAL:
4270 		default:
4271 			bad_error("entity_get_running_pg", r);
4272 		}
4273 
4274 		/* load it */
4275 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4276 		switch (r) {
4277 		case 0:
4278 			break;
4279 
4280 		case ECANCELED:
4281 			internal_pgroup_free(old_dpt_pgroup);
4282 			goto delprop;
4283 
4284 		case ECONNABORTED:
4285 		case ENOMEM:
4286 		case EBADF:
4287 			internal_pgroup_free(old_dpt_pgroup);
4288 			return (r);
4289 
4290 		case EACCES:
4291 		default:
4292 			bad_error("load_pg", r);
4293 		}
4294 
4295 		/* compare property groups */
4296 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4297 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4298 			internal_pgroup_free(old_dpt_pgroup);
4299 			internal_pgroup_free(current_pg);
4300 			return (0);
4301 		}
4302 
4303 		internal_pgroup_free(old_dpt_pgroup);
4304 		internal_pgroup_free(current_pg);
4305 
4306 		if (g_verbose)
4307 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4308 			    ient->sc_fmri, ud_name);
4309 
4310 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4311 			switch (scf_error()) {
4312 			case SCF_ERROR_NOT_FOUND:
4313 			case SCF_ERROR_DELETED:
4314 				internal_pgroup_free(old_dpt_pgroup);
4315 				goto delprop;
4316 
4317 			case SCF_ERROR_CONNECTION_BROKEN:
4318 				internal_pgroup_free(old_dpt_pgroup);
4319 				return (ECONNABORTED);
4320 
4321 			case SCF_ERROR_NOT_SET:
4322 			case SCF_ERROR_INVALID_ARGUMENT:
4323 			case SCF_ERROR_HANDLE_MISMATCH:
4324 			case SCF_ERROR_NOT_BOUND:
4325 			default:
4326 				bad_error("entity_get_pg", scf_error());
4327 			}
4328 		}
4329 
4330 		if (scf_pg_delete(ud_pg) != 0) {
4331 			switch (scf_error()) {
4332 			case SCF_ERROR_DELETED:
4333 				break;
4334 
4335 			case SCF_ERROR_CONNECTION_BROKEN:
4336 			case SCF_ERROR_BACKEND_READONLY:
4337 			case SCF_ERROR_BACKEND_ACCESS:
4338 				return (scferror2errno(scf_error()));
4339 
4340 			case SCF_ERROR_PERMISSION_DENIED:
4341 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4342 				return (scferror2errno(scf_error()));
4343 
4344 			case SCF_ERROR_NOT_SET:
4345 			default:
4346 				bad_error("scf_pg_delete", scf_error());
4347 			}
4348 		}
4349 
4350 		/*
4351 		 * This service was changed, so it must be refreshed.  But
4352 		 * since it's not mentioned in the new manifest, we have to
4353 		 * record its FMRI here for use later.  We record the name
4354 		 * & the entity (via sc_parent) in case we need to print error
4355 		 * messages during the refresh.
4356 		 */
4357 		dpt = internal_pgroup_new();
4358 		if (dpt == NULL)
4359 			return (ENOMEM);
4360 		dpt->sc_pgroup_name = strdup(ud_name);
4361 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4362 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4363 			return (ENOMEM);
4364 		dpt->sc_parent = (entity_t *)ient;
4365 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4366 			uu_die(gettext("libuutil error: %s\n"),
4367 			    uu_strerror(uu_error()));
4368 
4369 delprop:
4370 		if (tx == NULL)
4371 			return (0);
4372 
4373 		ent = scf_entry_create(g_hndl);
4374 		if (ent == NULL)
4375 			return (ENOMEM);
4376 
4377 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4378 			scf_entry_destroy(ent);
4379 			switch (scf_error()) {
4380 			case SCF_ERROR_DELETED:
4381 				warn(emsg_pg_deleted, ient->sc_fmri,
4382 				    "dependents");
4383 				return (EBUSY);
4384 
4385 			case SCF_ERROR_CONNECTION_BROKEN:
4386 				return (scferror2errno(scf_error()));
4387 
4388 			case SCF_ERROR_NOT_FOUND:
4389 				break;
4390 
4391 			case SCF_ERROR_HANDLE_MISMATCH:
4392 			case SCF_ERROR_NOT_BOUND:
4393 			case SCF_ERROR_INVALID_ARGUMENT:
4394 			case SCF_ERROR_NOT_SET:
4395 			default:
4396 				bad_error("scf_transaction_property_delete",
4397 				    scf_error());
4398 			}
4399 		}
4400 
4401 		return (0);
4402 	}
4403 
4404 	new_dpt_pgroup->sc_pgroup_seen = 1;
4405 
4406 	/*
4407 	 * Decide whether the dependent has changed in the manifest.
4408 	 */
4409 	/* Compare the target. */
4410 	if (scf_property_get_value(prop, ud_val) != 0) {
4411 		switch (scf_error()) {
4412 		case SCF_ERROR_NOT_FOUND:
4413 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4414 			warn(li_corrupt, ient->sc_fmri);
4415 			return (EBADF);
4416 
4417 		case SCF_ERROR_DELETED:
4418 		case SCF_ERROR_CONNECTION_BROKEN:
4419 			return (scferror2errno(scf_error()));
4420 
4421 		case SCF_ERROR_HANDLE_MISMATCH:
4422 		case SCF_ERROR_NOT_BOUND:
4423 		case SCF_ERROR_NOT_SET:
4424 		case SCF_ERROR_PERMISSION_DENIED:
4425 		default:
4426 			bad_error("scf_property_get_value", scf_error());
4427 		}
4428 	}
4429 
4430 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4431 	    0)
4432 		bad_error("scf_value_get_as_string", scf_error());
4433 
4434 	/*
4435 	 * If the fmri's are not equal then the old fmri will need to
4436 	 * be refreshed to ensure that the changes are properly updated
4437 	 * in that service.
4438 	 */
4439 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4440 	switch (r) {
4441 	case 0:
4442 		dpt = internal_pgroup_new();
4443 		if (dpt == NULL)
4444 			return (ENOMEM);
4445 		dpt->sc_pgroup_name = strdup(ud_name);
4446 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4447 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4448 			return (ENOMEM);
4449 		dpt->sc_parent = (entity_t *)ient;
4450 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4451 			uu_die(gettext("libuutil error: %s\n"),
4452 			    uu_strerror(uu_error()));
4453 		break;
4454 
4455 	case 1:
4456 		/* Compare the dependency pgs. */
4457 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4458 			switch (scf_error()) {
4459 			case SCF_ERROR_NOT_FOUND:
4460 				warn(li_corrupt, ient->sc_fmri);
4461 				return (EBADF);
4462 
4463 			case SCF_ERROR_DELETED:
4464 			case SCF_ERROR_CONNECTION_BROKEN:
4465 				return (scferror2errno(scf_error()));
4466 
4467 			case SCF_ERROR_NOT_BOUND:
4468 			case SCF_ERROR_HANDLE_MISMATCH:
4469 			case SCF_ERROR_INVALID_ARGUMENT:
4470 			case SCF_ERROR_NOT_SET:
4471 			default:
4472 				bad_error("scf_snaplevel_get_pg", scf_error());
4473 			}
4474 		}
4475 
4476 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4477 		    snap_lastimport);
4478 		switch (r) {
4479 		case 0:
4480 			break;
4481 
4482 		case ECANCELED:
4483 		case ECONNABORTED:
4484 		case ENOMEM:
4485 		case EBADF:
4486 			return (r);
4487 
4488 		case EACCES:
4489 		default:
4490 			bad_error("load_pg", r);
4491 		}
4492 
4493 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4494 			/* no change, leave customizations */
4495 			internal_pgroup_free(old_dpt_pgroup);
4496 			return (0);
4497 		}
4498 		break;
4499 
4500 	case -1:
4501 		warn(li_corrupt, ient->sc_fmri);
4502 		return (EBADF);
4503 
4504 	case -2:
4505 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4506 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4507 		return (EINVAL);
4508 
4509 	default:
4510 		bad_error("fmri_equal", r);
4511 	}
4512 
4513 	/*
4514 	 * The dependent has changed in the manifest.  Upgrade the current
4515 	 * properties if they haven't been customized.
4516 	 */
4517 
4518 	/*
4519 	 * If new_dpt_pgroup->sc_override, then act as though the property
4520 	 * group hasn't been customized.
4521 	 */
4522 	if (new_dpt_pgroup->sc_pgroup_override) {
4523 		(void) strcpy(ud_ctarg, ud_oldtarg);
4524 		goto nocust;
4525 	}
4526 
4527 	if (!ud_run_dpts_pg_set) {
4528 		warn(cf_missing, ient->sc_fmri, ud_name);
4529 		r = 0;
4530 		goto out;
4531 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4532 		switch (scf_error()) {
4533 		case SCF_ERROR_NOT_FOUND:
4534 			warn(cf_missing, ient->sc_fmri, ud_name);
4535 			r = 0;
4536 			goto out;
4537 
4538 		case SCF_ERROR_CONNECTION_BROKEN:
4539 			r = scferror2errno(scf_error());
4540 			goto out;
4541 
4542 		case SCF_ERROR_DELETED:
4543 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4544 			r = EBUSY;
4545 			goto out;
4546 
4547 		case SCF_ERROR_INVALID_ARGUMENT:
4548 		case SCF_ERROR_NOT_BOUND:
4549 		case SCF_ERROR_HANDLE_MISMATCH:
4550 		case SCF_ERROR_NOT_SET:
4551 		default:
4552 			bad_error("scf_pg_get_property", scf_error());
4553 		}
4554 	}
4555 
4556 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4557 		switch (scf_error()) {
4558 		case SCF_ERROR_NOT_FOUND:
4559 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4560 			warn(cf_inval, ient->sc_fmri, ud_name);
4561 			r = 0;
4562 			goto out;
4563 
4564 		case SCF_ERROR_DELETED:
4565 		case SCF_ERROR_CONNECTION_BROKEN:
4566 			r = scferror2errno(scf_error());
4567 			goto out;
4568 
4569 		case SCF_ERROR_HANDLE_MISMATCH:
4570 		case SCF_ERROR_NOT_BOUND:
4571 		case SCF_ERROR_NOT_SET:
4572 		case SCF_ERROR_PERMISSION_DENIED:
4573 		default:
4574 			bad_error("scf_property_get_value", scf_error());
4575 		}
4576 	}
4577 
4578 	ty = scf_value_type(ud_val);
4579 	assert(ty != SCF_TYPE_INVALID);
4580 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4581 		warn(cf_inval, ient->sc_fmri, ud_name);
4582 		r = 0;
4583 		goto out;
4584 	}
4585 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4586 	    0)
4587 		bad_error("scf_value_get_as_string", scf_error());
4588 
4589 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4590 	if (r == -1) {
4591 		warn(cf_inval, ient->sc_fmri, ud_name);
4592 		r = 0;
4593 		goto out;
4594 	} else if (r == -2) {
4595 		warn(li_corrupt, ient->sc_fmri);
4596 		r = EBADF;
4597 		goto out;
4598 	} else if (r == 0) {
4599 		/*
4600 		 * Target has been changed.  Only abort now if it's been
4601 		 * changed to something other than what's in the manifest.
4602 		 */
4603 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4604 		if (r == -1) {
4605 			warn(cf_inval, ient->sc_fmri, ud_name);
4606 			r = 0;
4607 			goto out;
4608 		} else if (r == 0) {
4609 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4610 			r = 0;
4611 			goto out;
4612 		} else if (r != 1) {
4613 			/* invalid sc_pgroup_fmri caught above */
4614 			bad_error("fmri_equal", r);
4615 		}
4616 
4617 		/*
4618 		 * Fetch the current dependency pg.  If it's what the manifest
4619 		 * says, then no problem.
4620 		 */
4621 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4622 		switch (serr) {
4623 		case SCF_ERROR_NONE:
4624 			break;
4625 
4626 		case SCF_ERROR_NOT_FOUND:
4627 			warn(cf_missing, ient->sc_fmri, ud_name);
4628 			r = 0;
4629 			goto out;
4630 
4631 		case SCF_ERROR_NO_MEMORY:
4632 			r = ENOMEM;
4633 			goto out;
4634 
4635 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4636 		case SCF_ERROR_INVALID_ARGUMENT:
4637 		default:
4638 			bad_error("fmri_to_entity", serr);
4639 		}
4640 
4641 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4642 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4643 		switch (r) {
4644 		case 0:
4645 			break;
4646 
4647 		case ECONNABORTED:
4648 			goto out;
4649 
4650 		case ECANCELED:
4651 		case ENOENT:
4652 			warn(cf_missing, ient->sc_fmri, ud_name);
4653 			r = 0;
4654 			goto out;
4655 
4656 		case EBADF:
4657 			warn(r_no_lvl, ud_ctarg);
4658 			goto out;
4659 
4660 		case EINVAL:
4661 		default:
4662 			bad_error("entity_get_running_pg", r);
4663 		}
4664 
4665 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4666 		switch (r) {
4667 		case 0:
4668 			break;
4669 
4670 		case ECANCELED:
4671 			warn(cf_missing, ient->sc_fmri, ud_name);
4672 			r = 0;
4673 			goto out;
4674 
4675 		case ECONNABORTED:
4676 		case ENOMEM:
4677 		case EBADF:
4678 			goto out;
4679 
4680 		case EACCES:
4681 		default:
4682 			bad_error("load_pg", r);
4683 		}
4684 
4685 		if (!pg_equal(current_pg, new_dpt_pgroup))
4686 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4687 		internal_pgroup_free(current_pg);
4688 		r = 0;
4689 		goto out;
4690 	} else if (r != 1) {
4691 		bad_error("fmri_equal", r);
4692 	}
4693 
4694 nocust:
4695 	/*
4696 	 * Target has not been customized.  Check the dependency property
4697 	 * group.
4698 	 */
4699 
4700 	if (old_dpt_pgroup == NULL) {
4701 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4702 		    ud_pg) != 0) {
4703 			switch (scf_error()) {
4704 			case SCF_ERROR_NOT_FOUND:
4705 				warn(li_corrupt, ient->sc_fmri);
4706 				return (EBADF);
4707 
4708 			case SCF_ERROR_DELETED:
4709 			case SCF_ERROR_CONNECTION_BROKEN:
4710 				return (scferror2errno(scf_error()));
4711 
4712 			case SCF_ERROR_NOT_BOUND:
4713 			case SCF_ERROR_HANDLE_MISMATCH:
4714 			case SCF_ERROR_INVALID_ARGUMENT:
4715 			case SCF_ERROR_NOT_SET:
4716 			default:
4717 				bad_error("scf_snaplevel_get_pg", scf_error());
4718 			}
4719 		}
4720 
4721 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4722 		    snap_lastimport);
4723 		switch (r) {
4724 		case 0:
4725 			break;
4726 
4727 		case ECANCELED:
4728 		case ECONNABORTED:
4729 		case ENOMEM:
4730 		case EBADF:
4731 			return (r);
4732 
4733 		case EACCES:
4734 		default:
4735 			bad_error("load_pg", r);
4736 		}
4737 	}
4738 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4739 	switch (serr) {
4740 	case SCF_ERROR_NONE:
4741 		break;
4742 
4743 	case SCF_ERROR_NOT_FOUND:
4744 		warn(cf_missing, ient->sc_fmri, ud_name);
4745 		r = 0;
4746 		goto out;
4747 
4748 	case SCF_ERROR_NO_MEMORY:
4749 		r = ENOMEM;
4750 		goto out;
4751 
4752 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4753 	case SCF_ERROR_INVALID_ARGUMENT:
4754 	default:
4755 		bad_error("fmri_to_entity", serr);
4756 	}
4757 
4758 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4759 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4760 	switch (r) {
4761 	case 0:
4762 		break;
4763 
4764 	case ECONNABORTED:
4765 		goto out;
4766 
4767 	case ECANCELED:
4768 	case ENOENT:
4769 		warn(cf_missing, ient->sc_fmri, ud_name);
4770 		r = 0;
4771 		goto out;
4772 
4773 	case EBADF:
4774 		warn(r_no_lvl, ud_ctarg);
4775 		goto out;
4776 
4777 	case EINVAL:
4778 	default:
4779 		bad_error("entity_get_running_pg", r);
4780 	}
4781 
4782 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4783 	switch (r) {
4784 	case 0:
4785 		break;
4786 
4787 	case ECANCELED:
4788 		warn(cf_missing, ient->sc_fmri, ud_name);
4789 		goto out;
4790 
4791 	case ECONNABORTED:
4792 	case ENOMEM:
4793 	case EBADF:
4794 		goto out;
4795 
4796 	case EACCES:
4797 	default:
4798 		bad_error("load_pg", r);
4799 	}
4800 
4801 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4802 		if (!pg_equal(current_pg, new_dpt_pgroup))
4803 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4804 		internal_pgroup_free(current_pg);
4805 		r = 0;
4806 		goto out;
4807 	}
4808 
4809 	/* Uncustomized.  Upgrade. */
4810 
4811 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4812 	switch (r) {
4813 	case 1:
4814 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4815 			/* Already upgraded. */
4816 			internal_pgroup_free(current_pg);
4817 			r = 0;
4818 			goto out;
4819 		}
4820 
4821 		internal_pgroup_free(current_pg);
4822 
4823 		/* upgrade current_pg */
4824 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4825 			switch (scf_error()) {
4826 			case SCF_ERROR_CONNECTION_BROKEN:
4827 				r = scferror2errno(scf_error());
4828 				goto out;
4829 
4830 			case SCF_ERROR_DELETED:
4831 				warn(cf_missing, ient->sc_fmri, ud_name);
4832 				r = 0;
4833 				goto out;
4834 
4835 			case SCF_ERROR_NOT_FOUND:
4836 				break;
4837 
4838 			case SCF_ERROR_INVALID_ARGUMENT:
4839 			case SCF_ERROR_NOT_BOUND:
4840 			case SCF_ERROR_NOT_SET:
4841 			case SCF_ERROR_HANDLE_MISMATCH:
4842 			default:
4843 				bad_error("entity_get_pg", scf_error());
4844 			}
4845 
4846 			if (tissvc)
4847 				r = scf_service_add_pg(target_ent, ud_name,
4848 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4849 			else
4850 				r = scf_instance_add_pg(target_ent, ud_name,
4851 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4852 			if (r != 0) {
4853 				switch (scf_error()) {
4854 				case SCF_ERROR_CONNECTION_BROKEN:
4855 				case SCF_ERROR_NO_RESOURCES:
4856 				case SCF_ERROR_BACKEND_READONLY:
4857 				case SCF_ERROR_BACKEND_ACCESS:
4858 					r = scferror2errno(scf_error());
4859 					goto out;
4860 
4861 				case SCF_ERROR_DELETED:
4862 					warn(cf_missing, ient->sc_fmri,
4863 					    ud_name);
4864 					r = 0;
4865 					goto out;
4866 
4867 				case SCF_ERROR_PERMISSION_DENIED:
4868 					warn(emsg_pg_deleted, ud_ctarg,
4869 					    ud_name);
4870 					r = EPERM;
4871 					goto out;
4872 
4873 				case SCF_ERROR_EXISTS:
4874 					warn(emsg_pg_added, ud_ctarg, ud_name);
4875 					r = EBUSY;
4876 					goto out;
4877 
4878 				case SCF_ERROR_NOT_BOUND:
4879 				case SCF_ERROR_HANDLE_MISMATCH:
4880 				case SCF_ERROR_INVALID_ARGUMENT:
4881 				case SCF_ERROR_NOT_SET:
4882 				default:
4883 					bad_error("entity_add_pg", scf_error());
4884 				}
4885 			}
4886 		}
4887 
4888 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4889 		switch (r) {
4890 		case 0:
4891 			break;
4892 
4893 		case ECANCELED:
4894 			warn(cf_missing, ient->sc_fmri, ud_name);
4895 			goto out;
4896 
4897 		case ECONNABORTED:
4898 		case ENOMEM:
4899 		case EBADF:
4900 			goto out;
4901 
4902 		case EACCES:
4903 		default:
4904 			bad_error("load_pg", r);
4905 		}
4906 
4907 		if (g_verbose)
4908 			warn(upgrading, ient->sc_fmri, ud_name);
4909 
4910 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4911 		    new_dpt_pgroup, 0, ient->sc_fmri);
4912 		switch (r) {
4913 		case 0:
4914 			break;
4915 
4916 		case ECANCELED:
4917 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4918 			r = EBUSY;
4919 			goto out;
4920 
4921 		case EPERM:
4922 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4923 			goto out;
4924 
4925 		case EBUSY:
4926 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4927 			goto out;
4928 
4929 		case ECONNABORTED:
4930 		case ENOMEM:
4931 		case ENOSPC:
4932 		case EROFS:
4933 		case EACCES:
4934 		case EINVAL:
4935 			goto out;
4936 
4937 		default:
4938 			bad_error("upgrade_pg", r);
4939 		}
4940 		break;
4941 
4942 	case 0: {
4943 		scf_transaction_entry_t *ent;
4944 		scf_value_t *val;
4945 
4946 		internal_pgroup_free(current_pg);
4947 
4948 		/* delete old pg */
4949 		if (g_verbose)
4950 			warn(upgrading, ient->sc_fmri, ud_name);
4951 
4952 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4953 			switch (scf_error()) {
4954 			case SCF_ERROR_CONNECTION_BROKEN:
4955 				r = scferror2errno(scf_error());
4956 				goto out;
4957 
4958 			case SCF_ERROR_DELETED:
4959 				warn(cf_missing, ient->sc_fmri, ud_name);
4960 				r = 0;
4961 				goto out;
4962 
4963 			case SCF_ERROR_NOT_FOUND:
4964 				break;
4965 
4966 			case SCF_ERROR_INVALID_ARGUMENT:
4967 			case SCF_ERROR_NOT_BOUND:
4968 			case SCF_ERROR_NOT_SET:
4969 			case SCF_ERROR_HANDLE_MISMATCH:
4970 			default:
4971 				bad_error("entity_get_pg", scf_error());
4972 			}
4973 		} else if (scf_pg_delete(ud_pg) != 0) {
4974 			switch (scf_error()) {
4975 			case SCF_ERROR_DELETED:
4976 				break;
4977 
4978 			case SCF_ERROR_CONNECTION_BROKEN:
4979 			case SCF_ERROR_BACKEND_READONLY:
4980 			case SCF_ERROR_BACKEND_ACCESS:
4981 				r = scferror2errno(scf_error());
4982 				goto out;
4983 
4984 			case SCF_ERROR_PERMISSION_DENIED:
4985 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4986 				r = scferror2errno(scf_error());
4987 				goto out;
4988 
4989 			case SCF_ERROR_NOT_SET:
4990 			default:
4991 				bad_error("scf_pg_delete", scf_error());
4992 			}
4993 		}
4994 
4995 		/* import new one */
4996 		cbdata.sc_handle = g_hndl;
4997 		cbdata.sc_trans = NULL;		/* handled below */
4998 		cbdata.sc_flags = 0;
4999 
5000 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5001 		if (r != UU_WALK_NEXT) {
5002 			if (r != UU_WALK_ERROR)
5003 				bad_error("lscf_dependent_import", r);
5004 
5005 			r = cbdata.sc_err;
5006 			goto out;
5007 		}
5008 
5009 		if (tx == NULL)
5010 			break;
5011 
5012 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5013 		    (val = scf_value_create(g_hndl)) == NULL) {
5014 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5015 				return (ENOMEM);
5016 
5017 			bad_error("scf_entry_create", scf_error());
5018 		}
5019 
5020 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5021 		    SCF_TYPE_FMRI) != 0) {
5022 			switch (scf_error()) {
5023 			case SCF_ERROR_CONNECTION_BROKEN:
5024 				r = scferror2errno(scf_error());
5025 				goto out;
5026 
5027 			case SCF_ERROR_DELETED:
5028 				warn(emsg_pg_deleted, ient->sc_fmri,
5029 				    "dependents");
5030 				r = EBUSY;
5031 				goto out;
5032 
5033 			case SCF_ERROR_NOT_FOUND:
5034 				break;
5035 
5036 			case SCF_ERROR_NOT_BOUND:
5037 			case SCF_ERROR_HANDLE_MISMATCH:
5038 			case SCF_ERROR_INVALID_ARGUMENT:
5039 			case SCF_ERROR_NOT_SET:
5040 			default:
5041 				bad_error("scf_transaction_property_"
5042 				    "change_type", scf_error());
5043 			}
5044 
5045 			if (scf_transaction_property_new(tx, ent, ud_name,
5046 			    SCF_TYPE_FMRI) != 0) {
5047 				switch (scf_error()) {
5048 				case SCF_ERROR_CONNECTION_BROKEN:
5049 					r = scferror2errno(scf_error());
5050 					goto out;
5051 
5052 				case SCF_ERROR_DELETED:
5053 					warn(emsg_pg_deleted, ient->sc_fmri,
5054 					    "dependents");
5055 					r = EBUSY;
5056 					goto out;
5057 
5058 				case SCF_ERROR_EXISTS:
5059 					warn(emsg_pg_changed, ient->sc_fmri,
5060 					    "dependents");
5061 					r = EBUSY;
5062 					goto out;
5063 
5064 				case SCF_ERROR_INVALID_ARGUMENT:
5065 				case SCF_ERROR_HANDLE_MISMATCH:
5066 				case SCF_ERROR_NOT_BOUND:
5067 				case SCF_ERROR_NOT_SET:
5068 				default:
5069 					bad_error("scf_transaction_property_"
5070 					    "new", scf_error());
5071 				}
5072 			}
5073 		}
5074 
5075 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5076 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5077 			/* invalid sc_pgroup_fmri caught above */
5078 			bad_error("scf_value_set_from_string",
5079 			    scf_error());
5080 
5081 		if (scf_entry_add_value(ent, val) != 0)
5082 			bad_error("scf_entry_add_value", scf_error());
5083 		break;
5084 	}
5085 
5086 	case -2:
5087 		warn(li_corrupt, ient->sc_fmri);
5088 		internal_pgroup_free(current_pg);
5089 		r = EBADF;
5090 		goto out;
5091 
5092 	case -1:
5093 	default:
5094 		/* invalid sc_pgroup_fmri caught above */
5095 		bad_error("fmri_equal", r);
5096 	}
5097 
5098 	r = 0;
5099 
5100 out:
5101 	if (old_dpt_pgroup != NULL)
5102 		internal_pgroup_free(old_dpt_pgroup);
5103 
5104 	return (r);
5105 }
5106 
5107 /*
5108  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5109  * would import it, except it seems to exist in the service anyway.  Compare
5110  * the existent dependent with the one we would import, and report any
5111  * differences (if there are none, be silent).  prop is the property which
5112  * represents the existent dependent (in the dependents property group) in the
5113  * entity corresponding to ient.
5114  *
5115  * Returns
5116  *   0 - success (Sort of.  At least, we can continue importing.)
5117  *   ECONNABORTED - repository connection broken
5118  *   EBUSY - ancestor of prop was deleted (error printed)
5119  *   ENOMEM - out of memory
5120  *   EBADF - corrupt property group (error printed)
5121  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5122  */
5123 static int
5124 handle_dependent_conflict(const entity_t * const ient,
5125     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5126 {
5127 	int r;
5128 	scf_type_t ty;
5129 	scf_error_t scfe;
5130 	void *tptr;
5131 	int tissvc;
5132 	pgroup_t *pgroup;
5133 
5134 	if (scf_property_get_value(prop, ud_val) != 0) {
5135 		switch (scf_error()) {
5136 		case SCF_ERROR_CONNECTION_BROKEN:
5137 			return (scferror2errno(scf_error()));
5138 
5139 		case SCF_ERROR_DELETED:
5140 			warn(emsg_pg_deleted, ient->sc_fmri,
5141 			    new_dpt_pgroup->sc_pgroup_name);
5142 			return (EBUSY);
5143 
5144 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5145 		case SCF_ERROR_NOT_FOUND:
5146 			warn(gettext("Conflict upgrading %s (not importing "
5147 			    "dependent \"%s\" because it already exists.)  "
5148 			    "Warning: The \"%s/%2$s\" property has more or "
5149 			    "fewer than one value)).\n"), ient->sc_fmri,
5150 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5151 			return (0);
5152 
5153 		case SCF_ERROR_HANDLE_MISMATCH:
5154 		case SCF_ERROR_NOT_BOUND:
5155 		case SCF_ERROR_NOT_SET:
5156 		case SCF_ERROR_PERMISSION_DENIED:
5157 		default:
5158 			bad_error("scf_property_get_value",
5159 			    scf_error());
5160 		}
5161 	}
5162 
5163 	ty = scf_value_type(ud_val);
5164 	assert(ty != SCF_TYPE_INVALID);
5165 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5166 		warn(gettext("Conflict upgrading %s (not importing dependent "
5167 		    "\"%s\" because it already exists).  Warning: The "
5168 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5169 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5170 		    scf_type_to_string(ty), "dependents");
5171 		return (0);
5172 	}
5173 
5174 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5175 	    0)
5176 		bad_error("scf_value_get_as_string", scf_error());
5177 
5178 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5179 	switch (r) {
5180 	case 0:
5181 		warn(gettext("Conflict upgrading %s (not importing dependent "
5182 		    "\"%s\" (target \"%s\") because it already exists with "
5183 		    "target \"%s\").\n"), ient->sc_fmri,
5184 		    new_dpt_pgroup->sc_pgroup_name,
5185 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5186 		return (0);
5187 
5188 	case 1:
5189 		break;
5190 
5191 	case -1:
5192 		warn(gettext("Conflict upgrading %s (not importing dependent "
5193 		    "\"%s\" because it already exists).  Warning: The current "
5194 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5195 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5196 		return (0);
5197 
5198 	case -2:
5199 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5200 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5201 		    new_dpt_pgroup->sc_pgroup_fmri);
5202 		return (EINVAL);
5203 
5204 	default:
5205 		bad_error("fmri_equal", r);
5206 	}
5207 
5208 	/* compare dependency pgs in target */
5209 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5210 	switch (scfe) {
5211 	case SCF_ERROR_NONE:
5212 		break;
5213 
5214 	case SCF_ERROR_NO_MEMORY:
5215 		return (ENOMEM);
5216 
5217 	case SCF_ERROR_NOT_FOUND:
5218 		warn(emsg_dpt_dangling, ient->sc_fmri,
5219 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5220 		return (0);
5221 
5222 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5223 	case SCF_ERROR_INVALID_ARGUMENT:
5224 	default:
5225 		bad_error("fmri_to_entity", scfe);
5226 	}
5227 
5228 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5229 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5230 	switch (r) {
5231 	case 0:
5232 		break;
5233 
5234 	case ECONNABORTED:
5235 		return (r);
5236 
5237 	case ECANCELED:
5238 		warn(emsg_dpt_dangling, ient->sc_fmri,
5239 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5240 		return (0);
5241 
5242 	case EBADF:
5243 		if (tissvc)
5244 			warn(gettext("%s has an instance with a \"%s\" "
5245 			    "snapshot which is missing a snaplevel.\n"),
5246 			    ud_ctarg, "running");
5247 		else
5248 			warn(gettext("%s has a \"%s\" snapshot which is "
5249 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5250 		/* FALLTHROUGH */
5251 
5252 	case ENOENT:
5253 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5254 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5255 		    new_dpt_pgroup->sc_pgroup_name);
5256 		return (0);
5257 
5258 	case EINVAL:
5259 	default:
5260 		bad_error("entity_get_running_pg", r);
5261 	}
5262 
5263 	pgroup = internal_pgroup_new();
5264 	if (pgroup == NULL)
5265 		return (ENOMEM);
5266 
5267 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5268 	switch (r) {
5269 	case 0:
5270 		break;
5271 
5272 	case ECONNABORTED:
5273 	case EBADF:
5274 	case ENOMEM:
5275 		internal_pgroup_free(pgroup);
5276 		return (r);
5277 
5278 	case ECANCELED:
5279 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5280 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5281 		    new_dpt_pgroup->sc_pgroup_name);
5282 		internal_pgroup_free(pgroup);
5283 		return (0);
5284 
5285 	case EACCES:
5286 	default:
5287 		bad_error("load_pg", r);
5288 	}
5289 
5290 	/* report differences */
5291 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5292 	internal_pgroup_free(pgroup);
5293 	return (0);
5294 }
5295 
5296 /*
5297  * lipg is a property group in the last-import snapshot of ent, which is an
5298  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5299  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5300  * in ents's property groups, compare and upgrade ent appropriately.
5301  *
5302  * Returns
5303  *   0 - success
5304  *   ECONNABORTED - repository connection broken
5305  *   ENOMEM - out of memory
5306  *   ENOSPC - configd is out of resources
5307  *   EINVAL - ient has invalid dependent (error printed)
5308  *	    - ient has invalid pgroup_t (error printed)
5309  *   ECANCELED - ent has been deleted
5310  *   ENODEV - entity containing lipg has been deleted
5311  *	    - entity containing running has been deleted
5312  *   EPERM - could not delete pg (permission denied) (error printed)
5313  *	   - couldn't upgrade dependents (permission denied) (error printed)
5314  *	   - couldn't import pg (permission denied) (error printed)
5315  *	   - couldn't upgrade pg (permission denied) (error printed)
5316  *   EROFS - could not delete pg (repository read-only)
5317  *	   - couldn't upgrade dependents (repository read-only)
5318  *	   - couldn't import pg (repository read-only)
5319  *	   - couldn't upgrade pg (repository read-only)
5320  *   EACCES - could not delete pg (backend access denied)
5321  *	    - couldn't upgrade dependents (backend access denied)
5322  *	    - couldn't import pg (backend access denied)
5323  *	    - couldn't upgrade pg (backend access denied)
5324  *	    - couldn't read property (backend access denied)
5325  *   EBUSY - property group was added (error printed)
5326  *	   - property group was deleted (error printed)
5327  *	   - property group changed (error printed)
5328  *	   - "dependents" pg was added, changed, or deleted (error printed)
5329  *	   - dependent target deleted (error printed)
5330  *	   - dependent pg changed (error printed)
5331  *   EBADF - imp_snpl is corrupt (error printed)
5332  *	   - ent has bad pg (error printed)
5333  *   EEXIST - dependent collision in target service (error printed)
5334  */
5335 static int
5336 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5337     const scf_snaplevel_t *running)
5338 {
5339 	int r;
5340 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5341 	scf_callback_t cbdata;
5342 
5343 	const char * const cf_pg_missing =
5344 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5345 	const char * const deleting =
5346 	    gettext("%s: Deleting property group \"%s\".\n");
5347 
5348 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5349 
5350 	/* Skip dependent property groups. */
5351 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5352 		switch (scf_error()) {
5353 		case SCF_ERROR_DELETED:
5354 			return (ENODEV);
5355 
5356 		case SCF_ERROR_CONNECTION_BROKEN:
5357 			return (ECONNABORTED);
5358 
5359 		case SCF_ERROR_NOT_SET:
5360 		case SCF_ERROR_NOT_BOUND:
5361 		default:
5362 			bad_error("scf_pg_get_type", scf_error());
5363 		}
5364 	}
5365 
5366 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5367 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5368 			return (0);
5369 
5370 		switch (scf_error()) {
5371 		case SCF_ERROR_NOT_FOUND:
5372 			break;
5373 
5374 		case SCF_ERROR_CONNECTION_BROKEN:
5375 			return (ECONNABORTED);
5376 
5377 		case SCF_ERROR_DELETED:
5378 			return (ENODEV);
5379 
5380 		case SCF_ERROR_INVALID_ARGUMENT:
5381 		case SCF_ERROR_NOT_BOUND:
5382 		case SCF_ERROR_HANDLE_MISMATCH:
5383 		case SCF_ERROR_NOT_SET:
5384 		default:
5385 			bad_error("scf_pg_get_property", scf_error());
5386 		}
5387 	}
5388 
5389 	/* lookup pg in new properties */
5390 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5391 		switch (scf_error()) {
5392 		case SCF_ERROR_DELETED:
5393 			return (ENODEV);
5394 
5395 		case SCF_ERROR_CONNECTION_BROKEN:
5396 			return (ECONNABORTED);
5397 
5398 		case SCF_ERROR_NOT_SET:
5399 		case SCF_ERROR_NOT_BOUND:
5400 		default:
5401 			bad_error("scf_pg_get_name", scf_error());
5402 		}
5403 	}
5404 
5405 	pgrp.sc_pgroup_name = imp_str;
5406 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5407 
5408 	if (mpg != NULL)
5409 		mpg->sc_pgroup_seen = 1;
5410 
5411 	/* Special handling for dependents */
5412 	if (strcmp(imp_str, "dependents") == 0)
5413 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5414 
5415 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5416 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5417 
5418 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5419 		/* property group was deleted from manifest */
5420 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5421 			switch (scf_error()) {
5422 			case SCF_ERROR_NOT_FOUND:
5423 				return (0);
5424 
5425 			case SCF_ERROR_DELETED:
5426 			case SCF_ERROR_CONNECTION_BROKEN:
5427 				return (scferror2errno(scf_error()));
5428 
5429 			case SCF_ERROR_INVALID_ARGUMENT:
5430 			case SCF_ERROR_HANDLE_MISMATCH:
5431 			case SCF_ERROR_NOT_BOUND:
5432 			case SCF_ERROR_NOT_SET:
5433 			default:
5434 				bad_error("entity_get_pg", scf_error());
5435 			}
5436 		}
5437 
5438 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5439 			if (g_verbose)
5440 				warn(deleting, ient->sc_fmri, imp_str);
5441 			if (scf_pg_delete(imp_pg2) == 0)
5442 				return (0);
5443 
5444 			switch (scf_error()) {
5445 			case SCF_ERROR_DELETED:
5446 				return (0);
5447 
5448 			case SCF_ERROR_CONNECTION_BROKEN:
5449 			case SCF_ERROR_BACKEND_READONLY:
5450 			case SCF_ERROR_BACKEND_ACCESS:
5451 				return (scferror2errno(scf_error()));
5452 
5453 			case SCF_ERROR_PERMISSION_DENIED:
5454 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5455 				return (scferror2errno(scf_error()));
5456 
5457 			case SCF_ERROR_NOT_SET:
5458 			default:
5459 				bad_error("scf_pg_delete", scf_error());
5460 			}
5461 		}
5462 
5463 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5464 		switch (r) {
5465 		case 0:
5466 			break;
5467 
5468 		case ECANCELED:
5469 			return (ENODEV);
5470 
5471 		case ECONNABORTED:
5472 		case ENOMEM:
5473 		case EBADF:
5474 		case EACCES:
5475 			return (r);
5476 
5477 		default:
5478 			bad_error("load_pg", r);
5479 		}
5480 
5481 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5482 		switch (r) {
5483 		case 0:
5484 			break;
5485 
5486 		case ECANCELED:
5487 		case ECONNABORTED:
5488 		case ENOMEM:
5489 		case EBADF:
5490 		case EACCES:
5491 			internal_pgroup_free(lipg_i);
5492 			return (r);
5493 
5494 		default:
5495 			bad_error("load_pg", r);
5496 		}
5497 
5498 		if (pg_equal(lipg_i, curpg_i)) {
5499 			if (g_verbose)
5500 				warn(deleting, ient->sc_fmri, imp_str);
5501 			if (scf_pg_delete(imp_pg2) != 0) {
5502 				switch (scf_error()) {
5503 				case SCF_ERROR_DELETED:
5504 					break;
5505 
5506 				case SCF_ERROR_CONNECTION_BROKEN:
5507 					internal_pgroup_free(lipg_i);
5508 					internal_pgroup_free(curpg_i);
5509 					return (ECONNABORTED);
5510 
5511 				case SCF_ERROR_NOT_SET:
5512 				case SCF_ERROR_NOT_BOUND:
5513 				default:
5514 					bad_error("scf_pg_delete", scf_error());
5515 				}
5516 			}
5517 		} else {
5518 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5519 		}
5520 
5521 		internal_pgroup_free(lipg_i);
5522 		internal_pgroup_free(curpg_i);
5523 
5524 		return (0);
5525 	}
5526 
5527 	/*
5528 	 * Only dependent pgs can have override set, and we skipped those
5529 	 * above.
5530 	 */
5531 	assert(!mpg->sc_pgroup_override);
5532 
5533 	/* compare */
5534 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5535 	switch (r) {
5536 	case 0:
5537 		break;
5538 
5539 	case ECANCELED:
5540 		return (ENODEV);
5541 
5542 	case ECONNABORTED:
5543 	case EBADF:
5544 	case ENOMEM:
5545 	case EACCES:
5546 		return (r);
5547 
5548 	default:
5549 		bad_error("load_pg", r);
5550 	}
5551 
5552 	if (pg_equal(mpg, lipg_i)) {
5553 		/* The manifest pg has not changed.  Move on. */
5554 		r = 0;
5555 		goto out;
5556 	}
5557 
5558 	/* upgrade current properties according to lipg & mpg */
5559 	if (running != NULL)
5560 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5561 	else
5562 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5563 	if (r != 0) {
5564 		switch (scf_error()) {
5565 		case SCF_ERROR_CONNECTION_BROKEN:
5566 			r = scferror2errno(scf_error());
5567 			goto out;
5568 
5569 		case SCF_ERROR_DELETED:
5570 			if (running != NULL)
5571 				r = ENODEV;
5572 			else
5573 				r = ECANCELED;
5574 			goto out;
5575 
5576 		case SCF_ERROR_NOT_FOUND:
5577 			break;
5578 
5579 		case SCF_ERROR_INVALID_ARGUMENT:
5580 		case SCF_ERROR_HANDLE_MISMATCH:
5581 		case SCF_ERROR_NOT_BOUND:
5582 		case SCF_ERROR_NOT_SET:
5583 		default:
5584 			bad_error("entity_get_pg", scf_error());
5585 		}
5586 
5587 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5588 
5589 		r = 0;
5590 		goto out;
5591 	}
5592 
5593 	r = load_pg_attrs(imp_pg2, &curpg_i);
5594 	switch (r) {
5595 	case 0:
5596 		break;
5597 
5598 	case ECANCELED:
5599 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5600 		r = 0;
5601 		goto out;
5602 
5603 	case ECONNABORTED:
5604 	case ENOMEM:
5605 		goto out;
5606 
5607 	default:
5608 		bad_error("load_pg_attrs", r);
5609 	}
5610 
5611 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5612 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5613 		internal_pgroup_free(curpg_i);
5614 		r = 0;
5615 		goto out;
5616 	}
5617 
5618 	internal_pgroup_free(curpg_i);
5619 
5620 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5621 	switch (r) {
5622 	case 0:
5623 		break;
5624 
5625 	case ECANCELED:
5626 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5627 		r = 0;
5628 		goto out;
5629 
5630 	case ECONNABORTED:
5631 	case EBADF:
5632 	case ENOMEM:
5633 	case EACCES:
5634 		goto out;
5635 
5636 	default:
5637 		bad_error("load_pg", r);
5638 	}
5639 
5640 	if (pg_equal(lipg_i, curpg_i) &&
5641 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5642 		int do_delete = 1;
5643 
5644 		if (g_verbose)
5645 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5646 			    ient->sc_fmri, mpg->sc_pgroup_name);
5647 
5648 		internal_pgroup_free(curpg_i);
5649 
5650 		if (running != NULL &&
5651 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5652 			switch (scf_error()) {
5653 			case SCF_ERROR_DELETED:
5654 				r = ECANCELED;
5655 				goto out;
5656 
5657 			case SCF_ERROR_NOT_FOUND:
5658 				do_delete = 0;
5659 				break;
5660 
5661 			case SCF_ERROR_CONNECTION_BROKEN:
5662 				r = scferror2errno(scf_error());
5663 				goto out;
5664 
5665 			case SCF_ERROR_HANDLE_MISMATCH:
5666 			case SCF_ERROR_INVALID_ARGUMENT:
5667 			case SCF_ERROR_NOT_SET:
5668 			case SCF_ERROR_NOT_BOUND:
5669 			default:
5670 				bad_error("entity_get_pg", scf_error());
5671 			}
5672 		}
5673 
5674 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5675 			switch (scf_error()) {
5676 			case SCF_ERROR_DELETED:
5677 				break;
5678 
5679 			case SCF_ERROR_CONNECTION_BROKEN:
5680 			case SCF_ERROR_BACKEND_READONLY:
5681 			case SCF_ERROR_BACKEND_ACCESS:
5682 				r = scferror2errno(scf_error());
5683 				goto out;
5684 
5685 			case SCF_ERROR_PERMISSION_DENIED:
5686 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5687 				    ient->sc_fmri);
5688 				r = scferror2errno(scf_error());
5689 				goto out;
5690 
5691 			case SCF_ERROR_NOT_SET:
5692 			case SCF_ERROR_NOT_BOUND:
5693 			default:
5694 				bad_error("scf_pg_delete", scf_error());
5695 			}
5696 		}
5697 
5698 		cbdata.sc_handle = g_hndl;
5699 		cbdata.sc_parent = ent;
5700 		cbdata.sc_service = issvc;
5701 		cbdata.sc_flags = 0;
5702 		cbdata.sc_source_fmri = ient->sc_fmri;
5703 		cbdata.sc_target_fmri = ient->sc_fmri;
5704 
5705 		r = entity_pgroup_import(mpg, &cbdata);
5706 		switch (r) {
5707 		case UU_WALK_NEXT:
5708 			r = 0;
5709 			goto out;
5710 
5711 		case UU_WALK_ERROR:
5712 			if (cbdata.sc_err == EEXIST) {
5713 				warn(emsg_pg_added, ient->sc_fmri,
5714 				    mpg->sc_pgroup_name);
5715 				r = EBUSY;
5716 			} else {
5717 				r = cbdata.sc_err;
5718 			}
5719 			goto out;
5720 
5721 		default:
5722 			bad_error("entity_pgroup_import", r);
5723 		}
5724 	}
5725 
5726 	if (running != NULL &&
5727 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5728 		switch (scf_error()) {
5729 		case SCF_ERROR_CONNECTION_BROKEN:
5730 		case SCF_ERROR_DELETED:
5731 			r = scferror2errno(scf_error());
5732 			goto out;
5733 
5734 		case SCF_ERROR_NOT_FOUND:
5735 			break;
5736 
5737 		case SCF_ERROR_HANDLE_MISMATCH:
5738 		case SCF_ERROR_INVALID_ARGUMENT:
5739 		case SCF_ERROR_NOT_SET:
5740 		case SCF_ERROR_NOT_BOUND:
5741 		default:
5742 			bad_error("entity_get_pg", scf_error());
5743 		}
5744 
5745 		cbdata.sc_handle = g_hndl;
5746 		cbdata.sc_parent = ent;
5747 		cbdata.sc_service = issvc;
5748 		cbdata.sc_flags = SCI_FORCE;
5749 		cbdata.sc_source_fmri = ient->sc_fmri;
5750 		cbdata.sc_target_fmri = ient->sc_fmri;
5751 
5752 		r = entity_pgroup_import(mpg, &cbdata);
5753 		switch (r) {
5754 		case UU_WALK_NEXT:
5755 			r = 0;
5756 			goto out;
5757 
5758 		case UU_WALK_ERROR:
5759 			if (cbdata.sc_err == EEXIST) {
5760 				warn(emsg_pg_added, ient->sc_fmri,
5761 				    mpg->sc_pgroup_name);
5762 				r = EBUSY;
5763 			} else {
5764 				r = cbdata.sc_err;
5765 			}
5766 			goto out;
5767 
5768 		default:
5769 			bad_error("entity_pgroup_import", r);
5770 		}
5771 	}
5772 
5773 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5774 	internal_pgroup_free(curpg_i);
5775 	switch (r) {
5776 	case 0:
5777 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5778 		break;
5779 
5780 	case ECANCELED:
5781 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5782 		r = EBUSY;
5783 		break;
5784 
5785 	case EPERM:
5786 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5787 		break;
5788 
5789 	case EBUSY:
5790 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5791 		break;
5792 
5793 	case ECONNABORTED:
5794 	case ENOMEM:
5795 	case ENOSPC:
5796 	case EROFS:
5797 	case EACCES:
5798 	case EINVAL:
5799 		break;
5800 
5801 	default:
5802 		bad_error("upgrade_pg", r);
5803 	}
5804 
5805 out:
5806 	internal_pgroup_free(lipg_i);
5807 	return (r);
5808 }
5809 
5810 /*
5811  * Upgrade the properties of ent according to snpl & ient.
5812  *
5813  * Returns
5814  *   0 - success
5815  *   ECONNABORTED - repository connection broken
5816  *   ENOMEM - out of memory
5817  *   ENOSPC - configd is out of resources
5818  *   ECANCELED - ent was deleted
5819  *   ENODEV - entity containing snpl was deleted
5820  *	    - entity containing running was deleted
5821  *   EBADF - imp_snpl is corrupt (error printed)
5822  *	   - ent has corrupt pg (error printed)
5823  *	   - dependent has corrupt pg (error printed)
5824  *	   - dependent target has a corrupt snapshot (error printed)
5825  *   EBUSY - pg was added, changed, or deleted (error printed)
5826  *	   - dependent target was deleted (error printed)
5827  *	   - dependent pg changed (error printed)
5828  *   EINVAL - invalid property group name (error printed)
5829  *	    - invalid property name (error printed)
5830  *	    - invalid value (error printed)
5831  *	    - ient has invalid pgroup or dependent (error printed)
5832  *   EPERM - could not create property group (permission denied) (error printed)
5833  *	   - could not modify property group (permission denied) (error printed)
5834  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5835  *   EROFS - could not create property group (repository read-only)
5836  *	   - couldn't delete, upgrade, or import pg or dependent
5837  *   EACCES - could not create property group (backend access denied)
5838  *	    - couldn't delete, upgrade, or import pg or dependent
5839  *   EEXIST - dependent collision in target service (error printed)
5840  */
5841 static int
5842 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5843     entity_t *ient)
5844 {
5845 	pgroup_t *pg, *rpg;
5846 	int r;
5847 	uu_list_t *pgs = ient->sc_pgroups;
5848 
5849 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5850 
5851 	/* clear sc_sceen for pgs */
5852 	if (uu_list_walk(pgs, clear_int,
5853 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5854 		bad_error("uu_list_walk", uu_error());
5855 
5856 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5857 		switch (scf_error()) {
5858 		case SCF_ERROR_DELETED:
5859 			return (ENODEV);
5860 
5861 		case SCF_ERROR_CONNECTION_BROKEN:
5862 			return (ECONNABORTED);
5863 
5864 		case SCF_ERROR_NOT_SET:
5865 		case SCF_ERROR_NOT_BOUND:
5866 		case SCF_ERROR_HANDLE_MISMATCH:
5867 		default:
5868 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5869 		}
5870 	}
5871 
5872 	for (;;) {
5873 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5874 		if (r == 0)
5875 			break;
5876 		if (r == 1) {
5877 			r = process_old_pg(imp_pg, ient, ent, running);
5878 			switch (r) {
5879 			case 0:
5880 				break;
5881 
5882 			case ECONNABORTED:
5883 			case ENOMEM:
5884 			case ENOSPC:
5885 			case ECANCELED:
5886 			case ENODEV:
5887 			case EPERM:
5888 			case EROFS:
5889 			case EACCES:
5890 			case EBADF:
5891 			case EBUSY:
5892 			case EINVAL:
5893 			case EEXIST:
5894 				return (r);
5895 
5896 			default:
5897 				bad_error("process_old_pg", r);
5898 			}
5899 			continue;
5900 		}
5901 		if (r != -1)
5902 			bad_error("scf_iter_next_pg", r);
5903 
5904 		switch (scf_error()) {
5905 		case SCF_ERROR_DELETED:
5906 			return (ENODEV);
5907 
5908 		case SCF_ERROR_CONNECTION_BROKEN:
5909 			return (ECONNABORTED);
5910 
5911 		case SCF_ERROR_HANDLE_MISMATCH:
5912 		case SCF_ERROR_NOT_BOUND:
5913 		case SCF_ERROR_NOT_SET:
5914 		case SCF_ERROR_INVALID_ARGUMENT:
5915 		default:
5916 			bad_error("scf_iter_next_pg", scf_error());
5917 		}
5918 	}
5919 
5920 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5921 		if (pg->sc_pgroup_seen)
5922 			continue;
5923 
5924 		/* pg is new */
5925 
5926 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5927 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5928 			    ent);
5929 			switch (r) {
5930 			case 0:
5931 				break;
5932 
5933 			case ECONNABORTED:
5934 			case ENOMEM:
5935 			case ENOSPC:
5936 			case ECANCELED:
5937 			case ENODEV:
5938 			case EBADF:
5939 			case EBUSY:
5940 			case EINVAL:
5941 			case EPERM:
5942 			case EROFS:
5943 			case EACCES:
5944 			case EEXIST:
5945 				return (r);
5946 
5947 			default:
5948 				bad_error("upgrade_dependents", r);
5949 			}
5950 			continue;
5951 		}
5952 
5953 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
5954 			r = upgrade_manifestfiles(pg, ient, running, ent);
5955 			switch (r) {
5956 			case 0:
5957 				break;
5958 
5959 			case ECONNABORTED:
5960 			case ENOMEM:
5961 			case ENOSPC:
5962 			case ECANCELED:
5963 			case ENODEV:
5964 			case EBADF:
5965 			case EBUSY:
5966 			case EINVAL:
5967 			case EPERM:
5968 			case EROFS:
5969 			case EACCES:
5970 			case EEXIST:
5971 				return (r);
5972 
5973 			default:
5974 				bad_error("upgrade_manifestfiles", r);
5975 			}
5976 			continue;
5977 		}
5978 
5979 		if (running != NULL) {
5980 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
5981 			    imp_pg);
5982 		} else {
5983 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
5984 			    imp_pg);
5985 		}
5986 		if (r != 0) {
5987 			scf_callback_t cbdata;
5988 
5989 			switch (scf_error()) {
5990 			case SCF_ERROR_NOT_FOUND:
5991 				break;
5992 
5993 			case SCF_ERROR_CONNECTION_BROKEN:
5994 				return (scferror2errno(scf_error()));
5995 
5996 			case SCF_ERROR_DELETED:
5997 				if (running != NULL)
5998 					return (ENODEV);
5999 				else
6000 					return (scferror2errno(scf_error()));
6001 
6002 			case SCF_ERROR_INVALID_ARGUMENT:
6003 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6004 				    pg->sc_pgroup_name);
6005 				return (EINVAL);
6006 
6007 			case SCF_ERROR_NOT_SET:
6008 			case SCF_ERROR_HANDLE_MISMATCH:
6009 			case SCF_ERROR_NOT_BOUND:
6010 			default:
6011 				bad_error("entity_get_pg", scf_error());
6012 			}
6013 
6014 			/* User doesn't have pg, so import it. */
6015 
6016 			cbdata.sc_handle = g_hndl;
6017 			cbdata.sc_parent = ent;
6018 			cbdata.sc_service = issvc;
6019 			cbdata.sc_flags = SCI_FORCE;
6020 			cbdata.sc_source_fmri = ient->sc_fmri;
6021 			cbdata.sc_target_fmri = ient->sc_fmri;
6022 
6023 			r = entity_pgroup_import(pg, &cbdata);
6024 			switch (r) {
6025 			case UU_WALK_NEXT:
6026 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6027 				continue;
6028 
6029 			case UU_WALK_ERROR:
6030 				if (cbdata.sc_err == EEXIST) {
6031 					warn(emsg_pg_added, ient->sc_fmri,
6032 					    pg->sc_pgroup_name);
6033 					return (EBUSY);
6034 				}
6035 				return (cbdata.sc_err);
6036 
6037 			default:
6038 				bad_error("entity_pgroup_import", r);
6039 			}
6040 		}
6041 
6042 		/* report differences between pg & current */
6043 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6044 		switch (r) {
6045 		case 0:
6046 			break;
6047 
6048 		case ECANCELED:
6049 			warn(emsg_pg_deleted, ient->sc_fmri,
6050 			    pg->sc_pgroup_name);
6051 			return (EBUSY);
6052 
6053 		case ECONNABORTED:
6054 		case EBADF:
6055 		case ENOMEM:
6056 		case EACCES:
6057 			return (r);
6058 
6059 		default:
6060 			bad_error("load_pg", r);
6061 		}
6062 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6063 		internal_pgroup_free(rpg);
6064 		rpg = NULL;
6065 	}
6066 
6067 	return (0);
6068 }
6069 
6070 /*
6071  * Import an instance.  If it doesn't exist, create it.  If it has
6072  * a last-import snapshot, upgrade its properties.  Finish by updating its
6073  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6074  * could have been created for a dependent tag in another manifest.  Import the
6075  * new properties.  If there's a conflict, don't override, like now?
6076  *
6077  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6078  * lcbdata->sc_err to
6079  *   ECONNABORTED - repository connection broken
6080  *   ENOMEM - out of memory
6081  *   ENOSPC - svc.configd is out of resources
6082  *   EEXIST - dependency collision in dependent service (error printed)
6083  *   EPERM - couldn't create temporary instance (permission denied)
6084  *	   - couldn't import into temporary instance (permission denied)
6085  *	   - couldn't take snapshot (permission denied)
6086  *	   - couldn't upgrade properties (permission denied)
6087  *	   - couldn't import properties (permission denied)
6088  *	   - couldn't import dependents (permission denied)
6089  *   EROFS - couldn't create temporary instance (repository read-only)
6090  *	   - couldn't import into temporary instance (repository read-only)
6091  *	   - couldn't upgrade properties (repository read-only)
6092  *	   - couldn't import properties (repository read-only)
6093  *	   - couldn't import dependents (repository read-only)
6094  *   EACCES - couldn't create temporary instance (backend access denied)
6095  *	    - couldn't import into temporary instance (backend access denied)
6096  *	    - couldn't upgrade properties (backend access denied)
6097  *	    - couldn't import properties (backend access denied)
6098  *	    - couldn't import dependents (backend access denied)
6099  *   EINVAL - invalid instance name (error printed)
6100  *	    - invalid pgroup_t's (error printed)
6101  *	    - invalid dependents (error printed)
6102  *   EBUSY - temporary service deleted (error printed)
6103  *	   - temporary instance deleted (error printed)
6104  *	   - temporary instance changed (error printed)
6105  *	   - temporary instance already exists (error printed)
6106  *	   - instance deleted (error printed)
6107  *   EBADF - instance has corrupt last-import snapshot (error printed)
6108  *	   - instance is corrupt (error printed)
6109  *	   - dependent has corrupt pg (error printed)
6110  *	   - dependent target has a corrupt snapshot (error printed)
6111  *   -1 - unknown libscf error (error printed)
6112  */
6113 static int
6114 lscf_instance_import(void *v, void *pvt)
6115 {
6116 	entity_t *inst = v;
6117 	scf_callback_t ctx;
6118 	scf_callback_t *lcbdata = pvt;
6119 	scf_service_t *rsvc = lcbdata->sc_parent;
6120 	int r;
6121 	scf_snaplevel_t *running;
6122 	int flags = lcbdata->sc_flags;
6123 
6124 	const char * const emsg_tdel =
6125 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6126 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6127 	    "changed unexpectedly.\n");
6128 	const char * const emsg_del = gettext("%s changed unexpectedly "
6129 	    "(instance \"%s\" was deleted.)\n");
6130 	const char * const emsg_badsnap = gettext(
6131 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6132 
6133 	/*
6134 	 * prepare last-import snapshot:
6135 	 * create temporary instance (service was precreated)
6136 	 * populate with properties from bundle
6137 	 * take snapshot
6138 	 */
6139 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6140 		switch (scf_error()) {
6141 		case SCF_ERROR_CONNECTION_BROKEN:
6142 		case SCF_ERROR_NO_RESOURCES:
6143 		case SCF_ERROR_BACKEND_READONLY:
6144 		case SCF_ERROR_BACKEND_ACCESS:
6145 			return (stash_scferror(lcbdata));
6146 
6147 		case SCF_ERROR_EXISTS:
6148 			warn(gettext("Temporary service svc:/%s "
6149 			    "changed unexpectedly (instance \"%s\" added).\n"),
6150 			    imp_tsname, inst->sc_name);
6151 			lcbdata->sc_err = EBUSY;
6152 			return (UU_WALK_ERROR);
6153 
6154 		case SCF_ERROR_DELETED:
6155 			warn(gettext("Temporary service svc:/%s "
6156 			    "was deleted unexpectedly.\n"), imp_tsname);
6157 			lcbdata->sc_err = EBUSY;
6158 			return (UU_WALK_ERROR);
6159 
6160 		case SCF_ERROR_INVALID_ARGUMENT:
6161 			warn(gettext("Invalid instance name \"%s\".\n"),
6162 			    inst->sc_name);
6163 			return (stash_scferror(lcbdata));
6164 
6165 		case SCF_ERROR_PERMISSION_DENIED:
6166 			warn(gettext("Could not create temporary instance "
6167 			    "\"%s\" in svc:/%s (permission denied).\n"),
6168 			    inst->sc_name, imp_tsname);
6169 			return (stash_scferror(lcbdata));
6170 
6171 		case SCF_ERROR_HANDLE_MISMATCH:
6172 		case SCF_ERROR_NOT_BOUND:
6173 		case SCF_ERROR_NOT_SET:
6174 		default:
6175 			bad_error("scf_service_add_instance", scf_error());
6176 		}
6177 	}
6178 
6179 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6180 	    inst->sc_name);
6181 	if (r < 0)
6182 		bad_error("snprintf", errno);
6183 
6184 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6185 	    lcbdata->sc_flags | SCI_NOENABLED);
6186 	switch (r) {
6187 	case 0:
6188 		break;
6189 
6190 	case ECANCELED:
6191 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6192 		lcbdata->sc_err = EBUSY;
6193 		r = UU_WALK_ERROR;
6194 		goto deltemp;
6195 
6196 	case EEXIST:
6197 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6198 		lcbdata->sc_err = EBUSY;
6199 		r = UU_WALK_ERROR;
6200 		goto deltemp;
6201 
6202 	case ECONNABORTED:
6203 		goto connaborted;
6204 
6205 	case ENOMEM:
6206 	case ENOSPC:
6207 	case EPERM:
6208 	case EROFS:
6209 	case EACCES:
6210 	case EINVAL:
6211 	case EBUSY:
6212 		lcbdata->sc_err = r;
6213 		r = UU_WALK_ERROR;
6214 		goto deltemp;
6215 
6216 	default:
6217 		bad_error("lscf_import_instance_pgs", r);
6218 	}
6219 
6220 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6221 	    inst->sc_name);
6222 	if (r < 0)
6223 		bad_error("snprintf", errno);
6224 
6225 	ctx.sc_handle = lcbdata->sc_handle;
6226 	ctx.sc_parent = imp_tinst;
6227 	ctx.sc_service = 0;
6228 	ctx.sc_source_fmri = inst->sc_fmri;
6229 	ctx.sc_target_fmri = imp_str;
6230 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6231 	    UU_DEFAULT) != 0) {
6232 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6233 			bad_error("uu_list_walk", uu_error());
6234 
6235 		switch (ctx.sc_err) {
6236 		case ECONNABORTED:
6237 			goto connaborted;
6238 
6239 		case ECANCELED:
6240 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6241 			lcbdata->sc_err = EBUSY;
6242 			break;
6243 
6244 		case EEXIST:
6245 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6246 			lcbdata->sc_err = EBUSY;
6247 			break;
6248 
6249 		default:
6250 			lcbdata->sc_err = ctx.sc_err;
6251 		}
6252 		r = UU_WALK_ERROR;
6253 		goto deltemp;
6254 	}
6255 
6256 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6257 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6258 		switch (scf_error()) {
6259 		case SCF_ERROR_CONNECTION_BROKEN:
6260 			goto connaborted;
6261 
6262 		case SCF_ERROR_NO_RESOURCES:
6263 			r = stash_scferror(lcbdata);
6264 			goto deltemp;
6265 
6266 		case SCF_ERROR_EXISTS:
6267 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6268 			lcbdata->sc_err = EBUSY;
6269 			r = UU_WALK_ERROR;
6270 			goto deltemp;
6271 
6272 		case SCF_ERROR_PERMISSION_DENIED:
6273 			warn(gettext("Could not take \"%s\" snapshot of %s "
6274 			    "(permission denied).\n"), snap_lastimport,
6275 			    imp_str);
6276 			r = stash_scferror(lcbdata);
6277 			goto deltemp;
6278 
6279 		default:
6280 			scfwarn();
6281 			lcbdata->sc_err = -1;
6282 			r = UU_WALK_ERROR;
6283 			goto deltemp;
6284 
6285 		case SCF_ERROR_HANDLE_MISMATCH:
6286 		case SCF_ERROR_INVALID_ARGUMENT:
6287 		case SCF_ERROR_NOT_SET:
6288 			bad_error("_scf_snapshot_take_new_named", scf_error());
6289 		}
6290 	}
6291 
6292 	if (lcbdata->sc_flags & SCI_FRESH)
6293 		goto fresh;
6294 
6295 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6296 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6297 		    imp_lisnap) != 0) {
6298 			switch (scf_error()) {
6299 			case SCF_ERROR_DELETED:
6300 				warn(emsg_del, inst->sc_parent->sc_fmri,
6301 				    inst->sc_name);
6302 				lcbdata->sc_err = EBUSY;
6303 				r = UU_WALK_ERROR;
6304 				goto deltemp;
6305 
6306 			case SCF_ERROR_NOT_FOUND:
6307 				flags |= SCI_FORCE;
6308 				goto nosnap;
6309 
6310 			case SCF_ERROR_CONNECTION_BROKEN:
6311 				goto connaborted;
6312 
6313 			case SCF_ERROR_INVALID_ARGUMENT:
6314 			case SCF_ERROR_HANDLE_MISMATCH:
6315 			case SCF_ERROR_NOT_BOUND:
6316 			case SCF_ERROR_NOT_SET:
6317 			default:
6318 				bad_error("scf_instance_get_snapshot",
6319 				    scf_error());
6320 			}
6321 		}
6322 
6323 		/* upgrade */
6324 
6325 		/*
6326 		 * compare new properties with last-import properties
6327 		 * upgrade current properties
6328 		 */
6329 		/* clear sc_sceen for pgs */
6330 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6331 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6332 		    0)
6333 			bad_error("uu_list_walk", uu_error());
6334 
6335 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6336 		switch (r) {
6337 		case 0:
6338 			break;
6339 
6340 		case ECONNABORTED:
6341 			goto connaborted;
6342 
6343 		case ECANCELED:
6344 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6345 			lcbdata->sc_err = EBUSY;
6346 			r = UU_WALK_ERROR;
6347 			goto deltemp;
6348 
6349 		case ENOENT:
6350 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6351 			lcbdata->sc_err = EBADF;
6352 			r = UU_WALK_ERROR;
6353 			goto deltemp;
6354 
6355 		default:
6356 			bad_error("get_snaplevel", r);
6357 		}
6358 
6359 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6360 		    imp_rsnap) != 0) {
6361 			switch (scf_error()) {
6362 			case SCF_ERROR_DELETED:
6363 				warn(emsg_del, inst->sc_parent->sc_fmri,
6364 				    inst->sc_name);
6365 				lcbdata->sc_err = EBUSY;
6366 				r = UU_WALK_ERROR;
6367 				goto deltemp;
6368 
6369 			case SCF_ERROR_NOT_FOUND:
6370 				break;
6371 
6372 			case SCF_ERROR_CONNECTION_BROKEN:
6373 				goto connaborted;
6374 
6375 			case SCF_ERROR_INVALID_ARGUMENT:
6376 			case SCF_ERROR_HANDLE_MISMATCH:
6377 			case SCF_ERROR_NOT_BOUND:
6378 			case SCF_ERROR_NOT_SET:
6379 			default:
6380 				bad_error("scf_instance_get_snapshot",
6381 				    scf_error());
6382 			}
6383 
6384 			running = NULL;
6385 		} else {
6386 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6387 			switch (r) {
6388 			case 0:
6389 				running = imp_rsnpl;
6390 				break;
6391 
6392 			case ECONNABORTED:
6393 				goto connaborted;
6394 
6395 			case ECANCELED:
6396 				warn(emsg_del, inst->sc_parent->sc_fmri,
6397 				    inst->sc_name);
6398 				lcbdata->sc_err = EBUSY;
6399 				r = UU_WALK_ERROR;
6400 				goto deltemp;
6401 
6402 			case ENOENT:
6403 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6404 				lcbdata->sc_err = EBADF;
6405 				r = UU_WALK_ERROR;
6406 				goto deltemp;
6407 
6408 			default:
6409 				bad_error("get_snaplevel", r);
6410 			}
6411 		}
6412 
6413 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6414 		switch (r) {
6415 		case 0:
6416 			break;
6417 
6418 		case ECANCELED:
6419 		case ENODEV:
6420 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6421 			lcbdata->sc_err = EBUSY;
6422 			r = UU_WALK_ERROR;
6423 			goto deltemp;
6424 
6425 		case ECONNABORTED:
6426 			goto connaborted;
6427 
6428 		case ENOMEM:
6429 		case ENOSPC:
6430 		case EBADF:
6431 		case EBUSY:
6432 		case EINVAL:
6433 		case EPERM:
6434 		case EROFS:
6435 		case EACCES:
6436 		case EEXIST:
6437 			lcbdata->sc_err = r;
6438 			r = UU_WALK_ERROR;
6439 			goto deltemp;
6440 
6441 		default:
6442 			bad_error("upgrade_props", r);
6443 		}
6444 
6445 		inst->sc_import_state = IMPORT_PROP_DONE;
6446 	} else {
6447 		switch (scf_error()) {
6448 		case SCF_ERROR_CONNECTION_BROKEN:
6449 			goto connaborted;
6450 
6451 		case SCF_ERROR_NOT_FOUND:
6452 			break;
6453 
6454 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6455 		case SCF_ERROR_HANDLE_MISMATCH:
6456 		case SCF_ERROR_NOT_BOUND:
6457 		case SCF_ERROR_NOT_SET:
6458 		default:
6459 			bad_error("scf_service_get_instance", scf_error());
6460 		}
6461 
6462 fresh:
6463 		/* create instance */
6464 		if (scf_service_add_instance(rsvc, inst->sc_name,
6465 		    imp_inst) != 0) {
6466 			switch (scf_error()) {
6467 			case SCF_ERROR_CONNECTION_BROKEN:
6468 				goto connaborted;
6469 
6470 			case SCF_ERROR_NO_RESOURCES:
6471 			case SCF_ERROR_BACKEND_READONLY:
6472 			case SCF_ERROR_BACKEND_ACCESS:
6473 				r = stash_scferror(lcbdata);
6474 				goto deltemp;
6475 
6476 			case SCF_ERROR_EXISTS:
6477 				warn(gettext("%s changed unexpectedly "
6478 				    "(instance \"%s\" added).\n"),
6479 				    inst->sc_parent->sc_fmri, inst->sc_name);
6480 				lcbdata->sc_err = EBUSY;
6481 				r = UU_WALK_ERROR;
6482 				goto deltemp;
6483 
6484 			case SCF_ERROR_PERMISSION_DENIED:
6485 				warn(gettext("Could not create \"%s\" instance "
6486 				    "in %s (permission denied).\n"),
6487 				    inst->sc_name, inst->sc_parent->sc_fmri);
6488 				r = stash_scferror(lcbdata);
6489 				goto deltemp;
6490 
6491 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6492 			case SCF_ERROR_HANDLE_MISMATCH:
6493 			case SCF_ERROR_NOT_BOUND:
6494 			case SCF_ERROR_NOT_SET:
6495 			default:
6496 				bad_error("scf_service_add_instance",
6497 				    scf_error());
6498 			}
6499 		}
6500 
6501 nosnap:
6502 		/*
6503 		 * Create a last-import snapshot to serve as an attachment
6504 		 * point for the real one from the temporary instance.  Since
6505 		 * the contents is irrelevant, take it now, while the instance
6506 		 * is empty, to minimize svc.configd's work.
6507 		 */
6508 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6509 		    imp_lisnap) != 0) {
6510 			switch (scf_error()) {
6511 			case SCF_ERROR_CONNECTION_BROKEN:
6512 				goto connaborted;
6513 
6514 			case SCF_ERROR_NO_RESOURCES:
6515 				r = stash_scferror(lcbdata);
6516 				goto deltemp;
6517 
6518 			case SCF_ERROR_EXISTS:
6519 				warn(gettext("%s changed unexpectedly "
6520 				    "(snapshot \"%s\" added).\n"),
6521 				    inst->sc_fmri, snap_lastimport);
6522 				lcbdata->sc_err = EBUSY;
6523 				r = UU_WALK_ERROR;
6524 				goto deltemp;
6525 
6526 			case SCF_ERROR_PERMISSION_DENIED:
6527 				warn(gettext("Could not take \"%s\" snapshot "
6528 				    "of %s (permission denied).\n"),
6529 				    snap_lastimport, inst->sc_fmri);
6530 				r = stash_scferror(lcbdata);
6531 				goto deltemp;
6532 
6533 			default:
6534 				scfwarn();
6535 				lcbdata->sc_err = -1;
6536 				r = UU_WALK_ERROR;
6537 				goto deltemp;
6538 
6539 			case SCF_ERROR_NOT_SET:
6540 			case SCF_ERROR_INTERNAL:
6541 			case SCF_ERROR_INVALID_ARGUMENT:
6542 			case SCF_ERROR_HANDLE_MISMATCH:
6543 				bad_error("_scf_snapshot_take_new",
6544 				    scf_error());
6545 			}
6546 		}
6547 
6548 		if (li_only)
6549 			goto lionly;
6550 
6551 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6552 
6553 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6554 		    flags);
6555 		switch (r) {
6556 		case 0:
6557 			break;
6558 
6559 		case ECONNABORTED:
6560 			goto connaborted;
6561 
6562 		case ECANCELED:
6563 			warn(gettext("%s changed unexpectedly "
6564 			    "(instance \"%s\" deleted).\n"),
6565 			    inst->sc_parent->sc_fmri, inst->sc_name);
6566 			lcbdata->sc_err = EBUSY;
6567 			r = UU_WALK_ERROR;
6568 			goto deltemp;
6569 
6570 		case EEXIST:
6571 			warn(gettext("%s changed unexpectedly "
6572 			    "(property group added).\n"), inst->sc_fmri);
6573 			lcbdata->sc_err = EBUSY;
6574 			r = UU_WALK_ERROR;
6575 			goto deltemp;
6576 
6577 		default:
6578 			lcbdata->sc_err = r;
6579 			r = UU_WALK_ERROR;
6580 			goto deltemp;
6581 
6582 		case EINVAL:	/* caught above */
6583 			bad_error("lscf_import_instance_pgs", r);
6584 		}
6585 
6586 		ctx.sc_parent = imp_inst;
6587 		ctx.sc_service = 0;
6588 		ctx.sc_trans = NULL;
6589 		ctx.sc_flags = 0;
6590 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6591 		    &ctx, UU_DEFAULT) != 0) {
6592 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6593 				bad_error("uu_list_walk", uu_error());
6594 
6595 			if (ctx.sc_err == ECONNABORTED)
6596 				goto connaborted;
6597 			lcbdata->sc_err = ctx.sc_err;
6598 			r = UU_WALK_ERROR;
6599 			goto deltemp;
6600 		}
6601 
6602 		inst->sc_import_state = IMPORT_PROP_DONE;
6603 
6604 		if (g_verbose)
6605 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6606 			    snap_initial, inst->sc_fmri);
6607 		r = take_snap(imp_inst, snap_initial, imp_snap);
6608 		switch (r) {
6609 		case 0:
6610 			break;
6611 
6612 		case ECONNABORTED:
6613 			goto connaborted;
6614 
6615 		case ENOSPC:
6616 		case -1:
6617 			lcbdata->sc_err = r;
6618 			r = UU_WALK_ERROR;
6619 			goto deltemp;
6620 
6621 		case ECANCELED:
6622 			warn(gettext("%s changed unexpectedly "
6623 			    "(instance %s deleted).\n"),
6624 			    inst->sc_parent->sc_fmri, inst->sc_name);
6625 			lcbdata->sc_err = r;
6626 			r = UU_WALK_ERROR;
6627 			goto deltemp;
6628 
6629 		case EPERM:
6630 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6631 			lcbdata->sc_err = r;
6632 			r = UU_WALK_ERROR;
6633 			goto deltemp;
6634 
6635 		default:
6636 			bad_error("take_snap", r);
6637 		}
6638 	}
6639 
6640 lionly:
6641 	if (lcbdata->sc_flags & SCI_NOSNAP)
6642 		goto deltemp;
6643 
6644 	/* transfer snapshot from temporary instance */
6645 	if (g_verbose)
6646 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6647 		    snap_lastimport, inst->sc_fmri);
6648 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6649 		switch (scf_error()) {
6650 		case SCF_ERROR_CONNECTION_BROKEN:
6651 			goto connaborted;
6652 
6653 		case SCF_ERROR_NO_RESOURCES:
6654 			r = stash_scferror(lcbdata);
6655 			goto deltemp;
6656 
6657 		case SCF_ERROR_PERMISSION_DENIED:
6658 			warn(gettext("Could not take \"%s\" snapshot for %s "
6659 			    "(permission denied).\n"), snap_lastimport,
6660 			    inst->sc_fmri);
6661 			r = stash_scferror(lcbdata);
6662 			goto deltemp;
6663 
6664 		case SCF_ERROR_NOT_SET:
6665 		case SCF_ERROR_HANDLE_MISMATCH:
6666 		default:
6667 			bad_error("_scf_snapshot_attach", scf_error());
6668 		}
6669 	}
6670 
6671 	inst->sc_import_state = IMPORT_COMPLETE;
6672 
6673 	r = UU_WALK_NEXT;
6674 
6675 deltemp:
6676 	/* delete temporary instance */
6677 	if (scf_instance_delete(imp_tinst) != 0) {
6678 		switch (scf_error()) {
6679 		case SCF_ERROR_DELETED:
6680 			break;
6681 
6682 		case SCF_ERROR_CONNECTION_BROKEN:
6683 			goto connaborted;
6684 
6685 		case SCF_ERROR_NOT_SET:
6686 		case SCF_ERROR_NOT_BOUND:
6687 		default:
6688 			bad_error("scf_instance_delete", scf_error());
6689 		}
6690 	}
6691 
6692 	return (r);
6693 
6694 connaborted:
6695 	warn(gettext("Could not delete svc:/%s:%s "
6696 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6697 	lcbdata->sc_err = ECONNABORTED;
6698 	return (UU_WALK_ERROR);
6699 }
6700 
6701 /*
6702  * If the service is missing, create it, import its properties, and import the
6703  * instances.  Since the service is brand new, it should be empty, and if we
6704  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6705  *
6706  * If the service exists, we want to upgrade its properties and import the
6707  * instances.  Upgrade requires a last-import snapshot, though, which are
6708  * children of instances, so first we'll have to go through the instances
6709  * looking for a last-import snapshot.  If we don't find one then we'll just
6710  * override-import the service properties (but don't delete existing
6711  * properties: another service might have declared us as a dependent).  Before
6712  * we change anything, though, we want to take the previous snapshots.  We
6713  * also give lscf_instance_import() a leg up on taking last-import snapshots
6714  * by importing the manifest's service properties into a temporary service.
6715  *
6716  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6717  * sets lcbdata->sc_err to
6718  *   ECONNABORTED - repository connection broken
6719  *   ENOMEM - out of memory
6720  *   ENOSPC - svc.configd is out of resources
6721  *   EPERM - couldn't create temporary service (error printed)
6722  *	   - couldn't import into temp service (error printed)
6723  *	   - couldn't create service (error printed)
6724  *	   - couldn't import dependent (error printed)
6725  *	   - couldn't take snapshot (error printed)
6726  *	   - couldn't create instance (error printed)
6727  *	   - couldn't create, modify, or delete pg (error printed)
6728  *	   - couldn't create, modify, or delete dependent (error printed)
6729  *	   - couldn't import instance (error printed)
6730  *   EROFS - couldn't create temporary service (repository read-only)
6731  *	   - couldn't import into temporary service (repository read-only)
6732  *	   - couldn't create service (repository read-only)
6733  *	   - couldn't import dependent (repository read-only)
6734  *	   - couldn't create instance (repository read-only)
6735  *	   - couldn't create, modify, or delete pg or dependent
6736  *	   - couldn't import instance (repository read-only)
6737  *   EACCES - couldn't create temporary service (backend access denied)
6738  *	    - couldn't import into temporary service (backend access denied)
6739  *	    - couldn't create service (backend access denied)
6740  *	    - couldn't import dependent (backend access denied)
6741  *	    - couldn't create instance (backend access denied)
6742  *	    - couldn't create, modify, or delete pg or dependent
6743  *	    - couldn't import instance (backend access denied)
6744  *   EINVAL - service name is invalid (error printed)
6745  *	    - service name is too long (error printed)
6746  *	    - s has invalid pgroup (error printed)
6747  *	    - s has invalid dependent (error printed)
6748  *	    - instance name is invalid (error printed)
6749  *	    - instance entity_t is invalid (error printed)
6750  *   EEXIST - couldn't create temporary service (already exists) (error printed)
6751  *	    - couldn't import dependent (dependency pg already exists) (printed)
6752  *	    - dependency collision in dependent service (error printed)
6753  *   EBUSY - temporary service deleted (error printed)
6754  *	   - property group added to temporary service (error printed)
6755  *	   - new property group changed or was deleted (error printed)
6756  *	   - service was added unexpectedly (error printed)
6757  *	   - service was deleted unexpectedly (error printed)
6758  *	   - property group added to new service (error printed)
6759  *	   - instance added unexpectedly (error printed)
6760  *	   - instance deleted unexpectedly (error printed)
6761  *	   - dependent service deleted unexpectedly (error printed)
6762  *	   - pg was added, changed, or deleted (error printed)
6763  *	   - dependent pg changed (error printed)
6764  *	   - temporary instance added, changed, or deleted (error printed)
6765  *   EBADF - a last-import snapshot is corrupt (error printed)
6766  *	   - the service is corrupt (error printed)
6767  *	   - a dependent is corrupt (error printed)
6768  *	   - an instance is corrupt (error printed)
6769  *	   - an instance has a corrupt last-import snapshot (error printed)
6770  *	   - dependent target has a corrupt snapshot (error printed)
6771  *   -1 - unknown libscf error (error printed)
6772  */
6773 static int
6774 lscf_service_import(void *v, void *pvt)
6775 {
6776 	entity_t *s = v;
6777 	scf_callback_t cbdata;
6778 	scf_callback_t *lcbdata = pvt;
6779 	scf_scope_t *scope = lcbdata->sc_parent;
6780 	entity_t *inst, linst;
6781 	int r;
6782 	int fresh = 0;
6783 	scf_snaplevel_t *running;
6784 	int have_ge = 0;
6785 
6786 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
6787 	    "was deleted unexpectedly.\n");
6788 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6789 	    "changed unexpectedly (property group added).\n");
6790 	const char * const s_deleted =
6791 	    gettext("%s was deleted unexpectedly.\n");
6792 	const char * const i_deleted =
6793 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6794 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6795 	    "is corrupt (missing service snaplevel).\n");
6796 	const char * const s_mfile_upd =
6797 	    gettext("Unable to update the manifest file connection "
6798 	    "for %s\n");
6799 
6800 	li_only = 0;
6801 	/* Validate the service name */
6802 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6803 		switch (scf_error()) {
6804 		case SCF_ERROR_CONNECTION_BROKEN:
6805 			return (stash_scferror(lcbdata));
6806 
6807 		case SCF_ERROR_INVALID_ARGUMENT:
6808 			warn(gettext("\"%s\" is an invalid service name.  "
6809 			    "Cannot import.\n"), s->sc_name);
6810 			return (stash_scferror(lcbdata));
6811 
6812 		case SCF_ERROR_NOT_FOUND:
6813 			break;
6814 
6815 		case SCF_ERROR_HANDLE_MISMATCH:
6816 		case SCF_ERROR_NOT_BOUND:
6817 		case SCF_ERROR_NOT_SET:
6818 		default:
6819 			bad_error("scf_scope_get_service", scf_error());
6820 		}
6821 	}
6822 
6823 	/* create temporary service */
6824 	/*
6825 	 * the size of the buffer was reduced to max_scf_name_len to prevent
6826 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6827 	 * should be restored to its original value (max_scf_name_len +1)
6828 	 */
6829 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6830 	if (r < 0)
6831 		bad_error("snprintf", errno);
6832 	if (r > max_scf_name_len) {
6833 		warn(gettext(
6834 		    "Service name \"%s\" is too long.  Cannot import.\n"),
6835 		    s->sc_name);
6836 		lcbdata->sc_err = EINVAL;
6837 		return (UU_WALK_ERROR);
6838 	}
6839 
6840 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6841 		switch (scf_error()) {
6842 		case SCF_ERROR_CONNECTION_BROKEN:
6843 		case SCF_ERROR_NO_RESOURCES:
6844 		case SCF_ERROR_BACKEND_READONLY:
6845 		case SCF_ERROR_BACKEND_ACCESS:
6846 			return (stash_scferror(lcbdata));
6847 
6848 		case SCF_ERROR_EXISTS:
6849 			warn(gettext(
6850 			    "Temporary service \"%s\" must be deleted before "
6851 			    "this manifest can be imported.\n"), imp_tsname);
6852 			return (stash_scferror(lcbdata));
6853 
6854 		case SCF_ERROR_PERMISSION_DENIED:
6855 			warn(gettext("Could not create temporary service "
6856 			    "\"%s\" (permission denied).\n"), imp_tsname);
6857 			return (stash_scferror(lcbdata));
6858 
6859 		case SCF_ERROR_INVALID_ARGUMENT:
6860 		case SCF_ERROR_HANDLE_MISMATCH:
6861 		case SCF_ERROR_NOT_BOUND:
6862 		case SCF_ERROR_NOT_SET:
6863 		default:
6864 			bad_error("scf_scope_add_service", scf_error());
6865 		}
6866 	}
6867 
6868 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6869 	if (r < 0)
6870 		bad_error("snprintf", errno);
6871 
6872 	cbdata.sc_handle = lcbdata->sc_handle;
6873 	cbdata.sc_parent = imp_tsvc;
6874 	cbdata.sc_service = 1;
6875 	cbdata.sc_source_fmri = s->sc_fmri;
6876 	cbdata.sc_target_fmri = imp_str;
6877 	cbdata.sc_flags = 0;
6878 
6879 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6880 	    UU_DEFAULT) != 0) {
6881 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6882 			bad_error("uu_list_walk", uu_error());
6883 
6884 		lcbdata->sc_err = cbdata.sc_err;
6885 		switch (cbdata.sc_err) {
6886 		case ECONNABORTED:
6887 			goto connaborted;
6888 
6889 		case ECANCELED:
6890 			warn(ts_deleted, imp_tsname);
6891 			lcbdata->sc_err = EBUSY;
6892 			return (UU_WALK_ERROR);
6893 
6894 		case EEXIST:
6895 			warn(ts_pg_added, imp_tsname);
6896 			lcbdata->sc_err = EBUSY;
6897 			return (UU_WALK_ERROR);
6898 		}
6899 
6900 		r = UU_WALK_ERROR;
6901 		goto deltemp;
6902 	}
6903 
6904 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6905 	    UU_DEFAULT) != 0) {
6906 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6907 			bad_error("uu_list_walk", uu_error());
6908 
6909 		lcbdata->sc_err = cbdata.sc_err;
6910 		switch (cbdata.sc_err) {
6911 		case ECONNABORTED:
6912 			goto connaborted;
6913 
6914 		case ECANCELED:
6915 			warn(ts_deleted, imp_tsname);
6916 			lcbdata->sc_err = EBUSY;
6917 			return (UU_WALK_ERROR);
6918 
6919 		case EEXIST:
6920 			warn(ts_pg_added, imp_tsname);
6921 			lcbdata->sc_err = EBUSY;
6922 			return (UU_WALK_ERROR);
6923 		}
6924 
6925 		r = UU_WALK_ERROR;
6926 		goto deltemp;
6927 	}
6928 
6929 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6930 		switch (scf_error()) {
6931 		case SCF_ERROR_NOT_FOUND:
6932 			break;
6933 
6934 		case SCF_ERROR_CONNECTION_BROKEN:
6935 			goto connaborted;
6936 
6937 		case SCF_ERROR_INVALID_ARGUMENT:
6938 		case SCF_ERROR_HANDLE_MISMATCH:
6939 		case SCF_ERROR_NOT_BOUND:
6940 		case SCF_ERROR_NOT_SET:
6941 		default:
6942 			bad_error("scf_scope_get_service", scf_error());
6943 		}
6944 
6945 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6946 			switch (scf_error()) {
6947 			case SCF_ERROR_CONNECTION_BROKEN:
6948 				goto connaborted;
6949 
6950 			case SCF_ERROR_NO_RESOURCES:
6951 			case SCF_ERROR_BACKEND_READONLY:
6952 			case SCF_ERROR_BACKEND_ACCESS:
6953 				r = stash_scferror(lcbdata);
6954 				goto deltemp;
6955 
6956 			case SCF_ERROR_EXISTS:
6957 				warn(gettext("Scope \"%s\" changed unexpectedly"
6958 				    " (service \"%s\" added).\n"),
6959 				    SCF_SCOPE_LOCAL, s->sc_name);
6960 				lcbdata->sc_err = EBUSY;
6961 				goto deltemp;
6962 
6963 			case SCF_ERROR_PERMISSION_DENIED:
6964 				warn(gettext("Could not create service \"%s\" "
6965 				    "(permission denied).\n"), s->sc_name);
6966 				goto deltemp;
6967 
6968 			case SCF_ERROR_INVALID_ARGUMENT:
6969 			case SCF_ERROR_HANDLE_MISMATCH:
6970 			case SCF_ERROR_NOT_BOUND:
6971 			case SCF_ERROR_NOT_SET:
6972 			default:
6973 				bad_error("scf_scope_add_service", scf_error());
6974 			}
6975 		}
6976 
6977 		s->sc_import_state = IMPORT_PROP_BEGUN;
6978 
6979 		/* import service properties */
6980 		cbdata.sc_handle = lcbdata->sc_handle;
6981 		cbdata.sc_parent = imp_svc;
6982 		cbdata.sc_service = 1;
6983 		cbdata.sc_flags = lcbdata->sc_flags;
6984 		cbdata.sc_source_fmri = s->sc_fmri;
6985 		cbdata.sc_target_fmri = s->sc_fmri;
6986 
6987 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6988 		    &cbdata, UU_DEFAULT) != 0) {
6989 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6990 				bad_error("uu_list_walk", uu_error());
6991 
6992 			lcbdata->sc_err = cbdata.sc_err;
6993 			switch (cbdata.sc_err) {
6994 			case ECONNABORTED:
6995 				goto connaborted;
6996 
6997 			case ECANCELED:
6998 				warn(s_deleted, s->sc_fmri);
6999 				lcbdata->sc_err = EBUSY;
7000 				return (UU_WALK_ERROR);
7001 
7002 			case EEXIST:
7003 				warn(gettext("%s changed unexpectedly "
7004 				    "(property group added).\n"), s->sc_fmri);
7005 				lcbdata->sc_err = EBUSY;
7006 				return (UU_WALK_ERROR);
7007 
7008 			case EINVAL:
7009 				/* caught above */
7010 				bad_error("entity_pgroup_import",
7011 				    cbdata.sc_err);
7012 			}
7013 
7014 			r = UU_WALK_ERROR;
7015 			goto deltemp;
7016 		}
7017 
7018 		cbdata.sc_trans = NULL;
7019 		cbdata.sc_flags = 0;
7020 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7021 		    &cbdata, UU_DEFAULT) != 0) {
7022 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7023 				bad_error("uu_list_walk", uu_error());
7024 
7025 			lcbdata->sc_err = cbdata.sc_err;
7026 			if (cbdata.sc_err == ECONNABORTED)
7027 				goto connaborted;
7028 			r = UU_WALK_ERROR;
7029 			goto deltemp;
7030 		}
7031 
7032 		s->sc_import_state = IMPORT_PROP_DONE;
7033 
7034 		/*
7035 		 * This is a new service, so we can't take previous snapshots
7036 		 * or upgrade service properties.
7037 		 */
7038 		fresh = 1;
7039 		goto instances;
7040 	}
7041 
7042 	/* Clear sc_seen for the instances. */
7043 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7044 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7045 		bad_error("uu_list_walk", uu_error());
7046 
7047 	/*
7048 	 * Take previous snapshots for all instances.  Even for ones not
7049 	 * mentioned in the bundle, since we might change their service
7050 	 * properties.
7051 	 */
7052 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7053 		switch (scf_error()) {
7054 		case SCF_ERROR_CONNECTION_BROKEN:
7055 			goto connaborted;
7056 
7057 		case SCF_ERROR_DELETED:
7058 			warn(s_deleted, s->sc_fmri);
7059 			lcbdata->sc_err = EBUSY;
7060 			r = UU_WALK_ERROR;
7061 			goto deltemp;
7062 
7063 		case SCF_ERROR_HANDLE_MISMATCH:
7064 		case SCF_ERROR_NOT_BOUND:
7065 		case SCF_ERROR_NOT_SET:
7066 		default:
7067 			bad_error("scf_iter_service_instances", scf_error());
7068 		}
7069 	}
7070 
7071 	for (;;) {
7072 		r = scf_iter_next_instance(imp_iter, imp_inst);
7073 		if (r == 0)
7074 			break;
7075 		if (r != 1) {
7076 			switch (scf_error()) {
7077 			case SCF_ERROR_DELETED:
7078 				warn(s_deleted, s->sc_fmri);
7079 				lcbdata->sc_err = EBUSY;
7080 				r = UU_WALK_ERROR;
7081 				goto deltemp;
7082 
7083 			case SCF_ERROR_CONNECTION_BROKEN:
7084 				goto connaborted;
7085 
7086 			case SCF_ERROR_NOT_BOUND:
7087 			case SCF_ERROR_HANDLE_MISMATCH:
7088 			case SCF_ERROR_INVALID_ARGUMENT:
7089 			case SCF_ERROR_NOT_SET:
7090 			default:
7091 				bad_error("scf_iter_next_instance",
7092 				    scf_error());
7093 			}
7094 		}
7095 
7096 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7097 			switch (scf_error()) {
7098 			case SCF_ERROR_DELETED:
7099 				continue;
7100 
7101 			case SCF_ERROR_CONNECTION_BROKEN:
7102 				goto connaborted;
7103 
7104 			case SCF_ERROR_NOT_SET:
7105 			case SCF_ERROR_NOT_BOUND:
7106 			default:
7107 				bad_error("scf_instance_get_name", scf_error());
7108 			}
7109 		}
7110 
7111 		if (g_verbose)
7112 			warn(gettext(
7113 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7114 			    snap_previous, s->sc_name, imp_str);
7115 
7116 		r = take_snap(imp_inst, snap_previous, imp_snap);
7117 		switch (r) {
7118 		case 0:
7119 			break;
7120 
7121 		case ECANCELED:
7122 			continue;
7123 
7124 		case ECONNABORTED:
7125 			goto connaborted;
7126 
7127 		case EPERM:
7128 			warn(gettext("Could not take \"%s\" snapshot of "
7129 			    "svc:/%s:%s (permission denied).\n"),
7130 			    snap_previous, s->sc_name, imp_str);
7131 			lcbdata->sc_err = r;
7132 			return (UU_WALK_ERROR);
7133 
7134 		case ENOSPC:
7135 		case -1:
7136 			lcbdata->sc_err = r;
7137 			r = UU_WALK_ERROR;
7138 			goto deltemp;
7139 
7140 		default:
7141 			bad_error("take_snap", r);
7142 		}
7143 
7144 		linst.sc_name = imp_str;
7145 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7146 		    &linst, NULL, NULL);
7147 		if (inst != NULL) {
7148 			inst->sc_import_state = IMPORT_PREVIOUS;
7149 			inst->sc_seen = 1;
7150 		}
7151 	}
7152 
7153 	/*
7154 	 * Create the new instances and take previous snapshots of
7155 	 * them.  This is not necessary, but it maximizes data preservation.
7156 	 */
7157 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7158 	    inst != NULL;
7159 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7160 	    inst)) {
7161 		if (inst->sc_seen)
7162 			continue;
7163 
7164 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7165 		    imp_inst) != 0) {
7166 			switch (scf_error()) {
7167 			case SCF_ERROR_CONNECTION_BROKEN:
7168 				goto connaborted;
7169 
7170 			case SCF_ERROR_BACKEND_READONLY:
7171 			case SCF_ERROR_BACKEND_ACCESS:
7172 			case SCF_ERROR_NO_RESOURCES:
7173 				r = stash_scferror(lcbdata);
7174 				goto deltemp;
7175 
7176 			case SCF_ERROR_EXISTS:
7177 				warn(gettext("%s changed unexpectedly "
7178 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7179 				    inst->sc_name);
7180 				lcbdata->sc_err = EBUSY;
7181 				r = UU_WALK_ERROR;
7182 				goto deltemp;
7183 
7184 			case SCF_ERROR_INVALID_ARGUMENT:
7185 				warn(gettext("Service \"%s\" has instance with "
7186 				    "invalid name \"%s\".\n"), s->sc_name,
7187 				    inst->sc_name);
7188 				r = stash_scferror(lcbdata);
7189 				goto deltemp;
7190 
7191 			case SCF_ERROR_PERMISSION_DENIED:
7192 				warn(gettext("Could not create instance \"%s\" "
7193 				    "in %s (permission denied).\n"),
7194 				    inst->sc_name, s->sc_fmri);
7195 				r = stash_scferror(lcbdata);
7196 				goto deltemp;
7197 
7198 			case SCF_ERROR_HANDLE_MISMATCH:
7199 			case SCF_ERROR_NOT_BOUND:
7200 			case SCF_ERROR_NOT_SET:
7201 			default:
7202 				bad_error("scf_service_add_instance",
7203 				    scf_error());
7204 			}
7205 		}
7206 
7207 		if (g_verbose)
7208 			warn(gettext("Taking \"%s\" snapshot for "
7209 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7210 		r = take_snap(imp_inst, snap_previous, imp_snap);
7211 		switch (r) {
7212 		case 0:
7213 			break;
7214 
7215 		case ECANCELED:
7216 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7217 			lcbdata->sc_err = EBUSY;
7218 			r = UU_WALK_ERROR;
7219 			goto deltemp;
7220 
7221 		case ECONNABORTED:
7222 			goto connaborted;
7223 
7224 		case EPERM:
7225 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7226 			lcbdata->sc_err = r;
7227 			r = UU_WALK_ERROR;
7228 			goto deltemp;
7229 
7230 		case ENOSPC:
7231 		case -1:
7232 			r = UU_WALK_ERROR;
7233 			goto deltemp;
7234 
7235 		default:
7236 			bad_error("take_snap", r);
7237 		}
7238 	}
7239 
7240 	s->sc_import_state = IMPORT_PREVIOUS;
7241 
7242 	/*
7243 	 * Upgrade service properties, if we can find a last-import snapshot.
7244 	 * Any will do because we don't support different service properties
7245 	 * in different manifests, so all snaplevels of the service in all of
7246 	 * the last-import snapshots of the instances should be the same.
7247 	 */
7248 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7249 		switch (scf_error()) {
7250 		case SCF_ERROR_CONNECTION_BROKEN:
7251 			goto connaborted;
7252 
7253 		case SCF_ERROR_DELETED:
7254 			warn(s_deleted, s->sc_fmri);
7255 			lcbdata->sc_err = EBUSY;
7256 			r = UU_WALK_ERROR;
7257 			goto deltemp;
7258 
7259 		case SCF_ERROR_HANDLE_MISMATCH:
7260 		case SCF_ERROR_NOT_BOUND:
7261 		case SCF_ERROR_NOT_SET:
7262 		default:
7263 			bad_error("scf_iter_service_instances", scf_error());
7264 		}
7265 	}
7266 
7267 	for (;;) {
7268 		r = scf_iter_next_instance(imp_iter, imp_inst);
7269 		if (r == -1) {
7270 			switch (scf_error()) {
7271 			case SCF_ERROR_DELETED:
7272 				warn(s_deleted, s->sc_fmri);
7273 				lcbdata->sc_err = EBUSY;
7274 				r = UU_WALK_ERROR;
7275 				goto deltemp;
7276 
7277 			case SCF_ERROR_CONNECTION_BROKEN:
7278 				goto connaborted;
7279 
7280 			case SCF_ERROR_NOT_BOUND:
7281 			case SCF_ERROR_HANDLE_MISMATCH:
7282 			case SCF_ERROR_INVALID_ARGUMENT:
7283 			case SCF_ERROR_NOT_SET:
7284 			default:
7285 				bad_error("scf_iter_next_instance",
7286 				    scf_error());
7287 			}
7288 		}
7289 
7290 		if (r == 0) {
7291 			/*
7292 			 * Didn't find any last-import snapshots.  Override-
7293 			 * import the properties.  Unless one of the instances
7294 			 * has a general/enabled property, in which case we're
7295 			 * probably running a last-import-capable svccfg for
7296 			 * the first time, and we should only take the
7297 			 * last-import snapshot.
7298 			 */
7299 			if (have_ge) {
7300 				pgroup_t *mfpg;
7301 				scf_callback_t mfcbdata;
7302 
7303 				li_only = 1;
7304 				no_refresh = 1;
7305 				/*
7306 				 * Need to go ahead and import the manifestfiles
7307 				 * pg if it exists. If the last-import snapshot
7308 				 * upgrade code is ever removed this code can
7309 				 * be removed as well.
7310 				 */
7311 				mfpg = internal_pgroup_find(s,
7312 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7313 
7314 				if (mfpg) {
7315 					mfcbdata.sc_handle = g_hndl;
7316 					mfcbdata.sc_parent = imp_svc;
7317 					mfcbdata.sc_service = 1;
7318 					mfcbdata.sc_flags = SCI_FORCE;
7319 					mfcbdata.sc_source_fmri = s->sc_fmri;
7320 					mfcbdata.sc_target_fmri = s->sc_fmri;
7321 					if (entity_pgroup_import(mfpg,
7322 					    &mfcbdata) != UU_WALK_NEXT) {
7323 						warn(s_mfile_upd, s->sc_fmri);
7324 						r = UU_WALK_ERROR;
7325 						goto deltemp;
7326 					}
7327 				}
7328 				break;
7329 			}
7330 
7331 			s->sc_import_state = IMPORT_PROP_BEGUN;
7332 
7333 			cbdata.sc_handle = g_hndl;
7334 			cbdata.sc_parent = imp_svc;
7335 			cbdata.sc_service = 1;
7336 			cbdata.sc_flags = SCI_FORCE;
7337 			cbdata.sc_source_fmri = s->sc_fmri;
7338 			cbdata.sc_target_fmri = s->sc_fmri;
7339 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7340 			    &cbdata, UU_DEFAULT) != 0) {
7341 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7342 					bad_error("uu_list_walk", uu_error());
7343 				lcbdata->sc_err = cbdata.sc_err;
7344 				switch (cbdata.sc_err) {
7345 				case ECONNABORTED:
7346 					goto connaborted;
7347 
7348 				case ECANCELED:
7349 					warn(s_deleted, s->sc_fmri);
7350 					lcbdata->sc_err = EBUSY;
7351 					break;
7352 
7353 				case EINVAL:	/* caught above */
7354 				case EEXIST:
7355 					bad_error("entity_pgroup_import",
7356 					    cbdata.sc_err);
7357 				}
7358 
7359 				r = UU_WALK_ERROR;
7360 				goto deltemp;
7361 			}
7362 
7363 			cbdata.sc_trans = NULL;
7364 			cbdata.sc_flags = 0;
7365 			if (uu_list_walk(s->sc_dependents,
7366 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7367 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7368 					bad_error("uu_list_walk", uu_error());
7369 				lcbdata->sc_err = cbdata.sc_err;
7370 				if (cbdata.sc_err == ECONNABORTED)
7371 					goto connaborted;
7372 				r = UU_WALK_ERROR;
7373 				goto deltemp;
7374 			}
7375 			break;
7376 		}
7377 
7378 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7379 		    imp_snap) != 0) {
7380 			switch (scf_error()) {
7381 			case SCF_ERROR_DELETED:
7382 				continue;
7383 
7384 			case SCF_ERROR_NOT_FOUND:
7385 				break;
7386 
7387 			case SCF_ERROR_CONNECTION_BROKEN:
7388 				goto connaborted;
7389 
7390 			case SCF_ERROR_HANDLE_MISMATCH:
7391 			case SCF_ERROR_NOT_BOUND:
7392 			case SCF_ERROR_INVALID_ARGUMENT:
7393 			case SCF_ERROR_NOT_SET:
7394 			default:
7395 				bad_error("scf_instance_get_snapshot",
7396 				    scf_error());
7397 			}
7398 
7399 			if (have_ge)
7400 				continue;
7401 
7402 			/*
7403 			 * Check for a general/enabled property.  This is how
7404 			 * we tell whether to import if there turn out to be
7405 			 * no last-import snapshots.
7406 			 */
7407 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7408 			    imp_pg) == 0) {
7409 				if (scf_pg_get_property(imp_pg,
7410 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7411 					have_ge = 1;
7412 				} else {
7413 					switch (scf_error()) {
7414 					case SCF_ERROR_DELETED:
7415 					case SCF_ERROR_NOT_FOUND:
7416 						continue;
7417 
7418 					case SCF_ERROR_INVALID_ARGUMENT:
7419 					case SCF_ERROR_HANDLE_MISMATCH:
7420 					case SCF_ERROR_CONNECTION_BROKEN:
7421 					case SCF_ERROR_NOT_BOUND:
7422 					case SCF_ERROR_NOT_SET:
7423 					default:
7424 						bad_error("scf_pg_get_property",
7425 						    scf_error());
7426 					}
7427 				}
7428 			} else {
7429 				switch (scf_error()) {
7430 				case SCF_ERROR_DELETED:
7431 				case SCF_ERROR_NOT_FOUND:
7432 					continue;
7433 
7434 				case SCF_ERROR_CONNECTION_BROKEN:
7435 					goto connaborted;
7436 
7437 				case SCF_ERROR_NOT_BOUND:
7438 				case SCF_ERROR_NOT_SET:
7439 				case SCF_ERROR_INVALID_ARGUMENT:
7440 				case SCF_ERROR_HANDLE_MISMATCH:
7441 				default:
7442 					bad_error("scf_instance_get_pg",
7443 					    scf_error());
7444 				}
7445 			}
7446 			continue;
7447 		}
7448 
7449 		/* find service snaplevel */
7450 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7451 		switch (r) {
7452 		case 0:
7453 			break;
7454 
7455 		case ECONNABORTED:
7456 			goto connaborted;
7457 
7458 		case ECANCELED:
7459 			continue;
7460 
7461 		case ENOENT:
7462 			if (scf_instance_get_name(imp_inst, imp_str,
7463 			    imp_str_sz) < 0)
7464 				(void) strcpy(imp_str, "?");
7465 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7466 			lcbdata->sc_err = EBADF;
7467 			r = UU_WALK_ERROR;
7468 			goto deltemp;
7469 
7470 		default:
7471 			bad_error("get_snaplevel", r);
7472 		}
7473 
7474 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7475 		    imp_rsnap) != 0) {
7476 			switch (scf_error()) {
7477 			case SCF_ERROR_DELETED:
7478 				continue;
7479 
7480 			case SCF_ERROR_NOT_FOUND:
7481 				break;
7482 
7483 			case SCF_ERROR_CONNECTION_BROKEN:
7484 				goto connaborted;
7485 
7486 			case SCF_ERROR_INVALID_ARGUMENT:
7487 			case SCF_ERROR_HANDLE_MISMATCH:
7488 			case SCF_ERROR_NOT_BOUND:
7489 			case SCF_ERROR_NOT_SET:
7490 			default:
7491 				bad_error("scf_instance_get_snapshot",
7492 				    scf_error());
7493 			}
7494 			running = NULL;
7495 		} else {
7496 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7497 			switch (r) {
7498 			case 0:
7499 				running = imp_rsnpl;
7500 				break;
7501 
7502 			case ECONNABORTED:
7503 				goto connaborted;
7504 
7505 			case ECANCELED:
7506 				continue;
7507 
7508 			case ENOENT:
7509 				if (scf_instance_get_name(imp_inst, imp_str,
7510 				    imp_str_sz) < 0)
7511 					(void) strcpy(imp_str, "?");
7512 				warn(badsnap, snap_running, s->sc_name,
7513 				    imp_str);
7514 				lcbdata->sc_err = EBADF;
7515 				r = UU_WALK_ERROR;
7516 				goto deltemp;
7517 
7518 			default:
7519 				bad_error("get_snaplevel", r);
7520 			}
7521 		}
7522 
7523 		if (g_verbose) {
7524 			if (scf_instance_get_name(imp_inst, imp_str,
7525 			    imp_str_sz) < 0)
7526 				(void) strcpy(imp_str, "?");
7527 			warn(gettext("Upgrading properties of %s according to "
7528 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7529 		}
7530 
7531 		/* upgrade service properties */
7532 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7533 		if (r == 0)
7534 			break;
7535 
7536 		switch (r) {
7537 		case ECONNABORTED:
7538 			goto connaborted;
7539 
7540 		case ECANCELED:
7541 			warn(s_deleted, s->sc_fmri);
7542 			lcbdata->sc_err = EBUSY;
7543 			break;
7544 
7545 		case ENODEV:
7546 			if (scf_instance_get_name(imp_inst, imp_str,
7547 			    imp_str_sz) < 0)
7548 				(void) strcpy(imp_str, "?");
7549 			warn(i_deleted, s->sc_fmri, imp_str);
7550 			lcbdata->sc_err = EBUSY;
7551 			break;
7552 
7553 		default:
7554 			lcbdata->sc_err = r;
7555 		}
7556 
7557 		r = UU_WALK_ERROR;
7558 		goto deltemp;
7559 	}
7560 
7561 	s->sc_import_state = IMPORT_PROP_DONE;
7562 
7563 instances:
7564 	/* import instances */
7565 	cbdata.sc_handle = lcbdata->sc_handle;
7566 	cbdata.sc_parent = imp_svc;
7567 	cbdata.sc_service = 1;
7568 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7569 	cbdata.sc_general = NULL;
7570 
7571 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7572 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7573 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7574 			bad_error("uu_list_walk", uu_error());
7575 
7576 		lcbdata->sc_err = cbdata.sc_err;
7577 		if (cbdata.sc_err == ECONNABORTED)
7578 			goto connaborted;
7579 		r = UU_WALK_ERROR;
7580 		goto deltemp;
7581 	}
7582 
7583 	s->sc_import_state = IMPORT_COMPLETE;
7584 	r = UU_WALK_NEXT;
7585 
7586 deltemp:
7587 	/* delete temporary service */
7588 	if (scf_service_delete(imp_tsvc) != 0) {
7589 		switch (scf_error()) {
7590 		case SCF_ERROR_DELETED:
7591 			break;
7592 
7593 		case SCF_ERROR_CONNECTION_BROKEN:
7594 			goto connaborted;
7595 
7596 		case SCF_ERROR_EXISTS:
7597 			warn(gettext(
7598 			    "Could not delete svc:/%s (instances exist).\n"),
7599 			    imp_tsname);
7600 			break;
7601 
7602 		case SCF_ERROR_NOT_SET:
7603 		case SCF_ERROR_NOT_BOUND:
7604 		default:
7605 			bad_error("scf_service_delete", scf_error());
7606 		}
7607 	}
7608 
7609 	return (r);
7610 
7611 connaborted:
7612 	warn(gettext("Could not delete svc:/%s "
7613 	    "(repository connection broken).\n"), imp_tsname);
7614 	lcbdata->sc_err = ECONNABORTED;
7615 	return (UU_WALK_ERROR);
7616 }
7617 
7618 static const char *
7619 import_progress(int st)
7620 {
7621 	switch (st) {
7622 	case 0:
7623 		return (gettext("not reached."));
7624 
7625 	case IMPORT_PREVIOUS:
7626 		return (gettext("previous snapshot taken."));
7627 
7628 	case IMPORT_PROP_BEGUN:
7629 		return (gettext("some properties imported."));
7630 
7631 	case IMPORT_PROP_DONE:
7632 		return (gettext("properties imported."));
7633 
7634 	case IMPORT_COMPLETE:
7635 		return (gettext("imported."));
7636 
7637 	case IMPORT_REFRESHED:
7638 		return (gettext("refresh requested."));
7639 
7640 	default:
7641 #ifndef NDEBUG
7642 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7643 		    __FILE__, __LINE__, st);
7644 #endif
7645 		abort();
7646 		/* NOTREACHED */
7647 	}
7648 }
7649 
7650 /*
7651  * Returns
7652  *   0 - success
7653  *     - fmri wasn't found (error printed)
7654  *     - entity was deleted (error printed)
7655  *     - backend denied access (error printed)
7656  *   ENOMEM - out of memory (error printed)
7657  *   ECONNABORTED - repository connection broken (error printed)
7658  *   EPERM - permission denied (error printed)
7659  *   -1 - unknown libscf error (error printed)
7660  */
7661 static int
7662 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7663 {
7664 	scf_error_t serr;
7665 	void *ent;
7666 	int issvc;
7667 	int r;
7668 
7669 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7670 	const char *dpt_deleted = gettext("Could not refresh %s "
7671 	    "(dependent \"%s\" of %s) (deleted).\n");
7672 
7673 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7674 	switch (serr) {
7675 	case SCF_ERROR_NONE:
7676 		break;
7677 
7678 	case SCF_ERROR_NO_MEMORY:
7679 		if (name == NULL)
7680 			warn(gettext("Could not refresh %s (out of memory).\n"),
7681 			    fmri);
7682 		else
7683 			warn(gettext("Could not refresh %s "
7684 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7685 			    fmri, name, d_fmri);
7686 		return (ENOMEM);
7687 
7688 	case SCF_ERROR_NOT_FOUND:
7689 		if (name == NULL)
7690 			warn(deleted, fmri);
7691 		else
7692 			warn(dpt_deleted, fmri, name, d_fmri);
7693 		return (0);
7694 
7695 	case SCF_ERROR_INVALID_ARGUMENT:
7696 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7697 	default:
7698 		bad_error("fmri_to_entity", serr);
7699 	}
7700 
7701 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7702 	switch (r) {
7703 	case 0:
7704 		break;
7705 
7706 	case ECONNABORTED:
7707 		if (name != NULL)
7708 			warn(gettext("Could not refresh %s "
7709 			    "(dependent \"%s\" of %s) "
7710 			    "(repository connection broken).\n"), fmri, name,
7711 			    d_fmri);
7712 		return (r);
7713 
7714 	case ECANCELED:
7715 		if (name == NULL)
7716 			warn(deleted, fmri);
7717 		else
7718 			warn(dpt_deleted, fmri, name, d_fmri);
7719 		return (0);
7720 
7721 	case EACCES:
7722 		if (!g_verbose)
7723 			return (0);
7724 		if (name == NULL)
7725 			warn(gettext("Could not refresh %s "
7726 			    "(backend access denied).\n"), fmri);
7727 		else
7728 			warn(gettext("Could not refresh %s "
7729 			    "(dependent \"%s\" of %s) "
7730 			    "(backend access denied).\n"), fmri, name, d_fmri);
7731 		return (0);
7732 
7733 	case EPERM:
7734 		if (name == NULL)
7735 			warn(gettext("Could not refresh %s "
7736 			    "(permission denied).\n"), fmri);
7737 		else
7738 			warn(gettext("Could not refresh %s "
7739 			    "(dependent \"%s\" of %s) "
7740 			    "(permission denied).\n"), fmri, name, d_fmri);
7741 		return (r);
7742 
7743 	case ENOSPC:
7744 		if (name == NULL)
7745 			warn(gettext("Could not refresh %s "
7746 			    "(repository server out of resources).\n"),
7747 			    fmri);
7748 		else
7749 			warn(gettext("Could not refresh %s "
7750 			    "(dependent \"%s\" of %s) "
7751 			    "(repository server out of resources).\n"),
7752 			    fmri, name, d_fmri);
7753 		return (r);
7754 
7755 	case -1:
7756 		scfwarn();
7757 		return (r);
7758 
7759 	default:
7760 		bad_error("refresh_entity", r);
7761 	}
7762 
7763 	if (issvc)
7764 		scf_service_destroy(ent);
7765 	else
7766 		scf_instance_destroy(ent);
7767 
7768 	return (0);
7769 }
7770 
7771 static int
7772 alloc_imp_globals()
7773 {
7774 	int r;
7775 
7776 	const char * const emsg_nomem = gettext("Out of memory.\n");
7777 	const char * const emsg_nores =
7778 	    gettext("svc.configd is out of resources.\n");
7779 
7780 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7781 	    max_scf_name_len : max_scf_fmri_len) + 1;
7782 
7783 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7784 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
7785 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7786 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7787 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7788 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7789 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7790 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7791 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7792 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7793 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7794 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7795 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7796 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7797 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7798 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7799 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7800 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7801 	    (imp_str = malloc(imp_str_sz)) == NULL ||
7802 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7803 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7804 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7805 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7806 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7807 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7808 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7809 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7810 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7811 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7812 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7813 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7814 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7815 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7816 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7817 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7818 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7819 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7820 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7821 			warn(emsg_nores);
7822 		else
7823 			warn(emsg_nomem);
7824 
7825 		return (-1);
7826 	}
7827 
7828 	r = load_init();
7829 	switch (r) {
7830 	case 0:
7831 		break;
7832 
7833 	case ENOMEM:
7834 		warn(emsg_nomem);
7835 		return (-1);
7836 
7837 	default:
7838 		bad_error("load_init", r);
7839 	}
7840 
7841 	return (0);
7842 }
7843 
7844 static void
7845 free_imp_globals()
7846 {
7847 	pgroup_t *old_dpt;
7848 	void *cookie;
7849 
7850 	load_fini();
7851 
7852 	free(ud_ctarg);
7853 	free(ud_oldtarg);
7854 	free(ud_name);
7855 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7856 
7857 	scf_transaction_destroy(ud_tx);
7858 	ud_tx = NULL;
7859 	scf_iter_destroy(ud_iter);
7860 	scf_iter_destroy(ud_iter2);
7861 	ud_iter = ud_iter2 = NULL;
7862 	scf_value_destroy(ud_val);
7863 	ud_val = NULL;
7864 	scf_property_destroy(ud_prop);
7865 	scf_property_destroy(ud_dpt_prop);
7866 	ud_prop = ud_dpt_prop = NULL;
7867 	scf_pg_destroy(ud_pg);
7868 	scf_pg_destroy(ud_cur_depts_pg);
7869 	scf_pg_destroy(ud_run_dpts_pg);
7870 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7871 	scf_snaplevel_destroy(ud_snpl);
7872 	ud_snpl = NULL;
7873 	scf_instance_destroy(ud_inst);
7874 	ud_inst = NULL;
7875 
7876 	free(imp_str);
7877 	free(imp_tsname);
7878 	free(imp_fe1);
7879 	free(imp_fe2);
7880 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7881 
7882 	cookie = NULL;
7883 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7884 	    NULL) {
7885 		free((char *)old_dpt->sc_pgroup_name);
7886 		free((char *)old_dpt->sc_pgroup_fmri);
7887 		internal_pgroup_free(old_dpt);
7888 	}
7889 	uu_list_destroy(imp_deleted_dpts);
7890 
7891 	scf_transaction_destroy(imp_tx);
7892 	imp_tx = NULL;
7893 	scf_iter_destroy(imp_iter);
7894 	scf_iter_destroy(imp_rpg_iter);
7895 	scf_iter_destroy(imp_up_iter);
7896 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7897 	scf_property_destroy(imp_prop);
7898 	imp_prop = NULL;
7899 	scf_pg_destroy(imp_pg);
7900 	scf_pg_destroy(imp_pg2);
7901 	imp_pg = imp_pg2 = NULL;
7902 	scf_snaplevel_destroy(imp_snpl);
7903 	scf_snaplevel_destroy(imp_rsnpl);
7904 	imp_snpl = imp_rsnpl = NULL;
7905 	scf_snapshot_destroy(imp_snap);
7906 	scf_snapshot_destroy(imp_lisnap);
7907 	scf_snapshot_destroy(imp_tlisnap);
7908 	scf_snapshot_destroy(imp_rsnap);
7909 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7910 	scf_instance_destroy(imp_inst);
7911 	scf_instance_destroy(imp_tinst);
7912 	imp_inst = imp_tinst = NULL;
7913 	scf_service_destroy(imp_svc);
7914 	scf_service_destroy(imp_tsvc);
7915 	imp_svc = imp_tsvc = NULL;
7916 	scf_scope_destroy(imp_scope);
7917 	imp_scope = NULL;
7918 
7919 	load_fini();
7920 }
7921 
7922 int
7923 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7924 {
7925 	scf_callback_t cbdata;
7926 	int result = 0;
7927 	entity_t *svc, *inst;
7928 	uu_list_t *insts;
7929 	int r;
7930 	pgroup_t *old_dpt;
7931 	int annotation_set = 0;
7932 
7933 	const char * const emsg_nomem = gettext("Out of memory.\n");
7934 	const char * const emsg_nores =
7935 	    gettext("svc.configd is out of resources.\n");
7936 
7937 	lscf_prep_hndl();
7938 
7939 	if (alloc_imp_globals())
7940 		goto out;
7941 
7942 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7943 		switch (scf_error()) {
7944 		case SCF_ERROR_CONNECTION_BROKEN:
7945 			warn(gettext("Repository connection broken.\n"));
7946 			repository_teardown();
7947 			result = -1;
7948 			goto out;
7949 
7950 		case SCF_ERROR_NOT_FOUND:
7951 		case SCF_ERROR_INVALID_ARGUMENT:
7952 		case SCF_ERROR_NOT_BOUND:
7953 		case SCF_ERROR_HANDLE_MISMATCH:
7954 		default:
7955 			bad_error("scf_handle_get_scope", scf_error());
7956 		}
7957 	}
7958 
7959 	/* Set up the auditing annotation. */
7960 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7961 		annotation_set = 1;
7962 	} else {
7963 		switch (scf_error()) {
7964 		case SCF_ERROR_CONNECTION_BROKEN:
7965 			warn(gettext("Repository connection broken.\n"));
7966 			repository_teardown();
7967 			result = -1;
7968 			goto out;
7969 
7970 		case SCF_ERROR_INVALID_ARGUMENT:
7971 		case SCF_ERROR_NOT_BOUND:
7972 		case SCF_ERROR_NO_RESOURCES:
7973 		case SCF_ERROR_INTERNAL:
7974 			bad_error("_scf_set_annotation", scf_error());
7975 			/* NOTREACHED */
7976 
7977 		default:
7978 			/*
7979 			 * Do not terminate import because of inability to
7980 			 * generate annotation audit event.
7981 			 */
7982 			warn(gettext("_scf_set_annotation() unexpectedly "
7983 			    "failed with return code of %d\n"), scf_error());
7984 			break;
7985 		}
7986 	}
7987 
7988 	/*
7989 	 * Clear the sc_import_state's of all services & instances so we can
7990 	 * report how far we got if we fail.
7991 	 */
7992 	for (svc = uu_list_first(bndl->sc_bundle_services);
7993 	    svc != NULL;
7994 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7995 		svc->sc_import_state = 0;
7996 
7997 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
7998 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
7999 		    UU_DEFAULT) != 0)
8000 			bad_error("uu_list_walk", uu_error());
8001 	}
8002 
8003 	cbdata.sc_handle = g_hndl;
8004 	cbdata.sc_parent = imp_scope;
8005 	cbdata.sc_flags = flags;
8006 	cbdata.sc_general = NULL;
8007 
8008 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8009 	    &cbdata, UU_DEFAULT) == 0) {
8010 		/* Success.  Refresh everything. */
8011 
8012 		if (flags & SCI_NOREFRESH || no_refresh) {
8013 			no_refresh = 0;
8014 			result = 0;
8015 			goto out;
8016 		}
8017 
8018 		for (svc = uu_list_first(bndl->sc_bundle_services);
8019 		    svc != NULL;
8020 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8021 			pgroup_t *dpt;
8022 
8023 			insts = svc->sc_u.sc_service.sc_service_instances;
8024 
8025 			for (inst = uu_list_first(insts);
8026 			    inst != NULL;
8027 			    inst = uu_list_next(insts, inst)) {
8028 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8029 				switch (r) {
8030 				case 0:
8031 					break;
8032 
8033 				case ENOMEM:
8034 				case ECONNABORTED:
8035 				case EPERM:
8036 				case -1:
8037 					goto progress;
8038 
8039 				default:
8040 					bad_error("imp_refresh_fmri", r);
8041 				}
8042 
8043 				inst->sc_import_state = IMPORT_REFRESHED;
8044 
8045 				for (dpt = uu_list_first(inst->sc_dependents);
8046 				    dpt != NULL;
8047 				    dpt = uu_list_next(inst->sc_dependents,
8048 				    dpt))
8049 					if (imp_refresh_fmri(
8050 					    dpt->sc_pgroup_fmri,
8051 					    dpt->sc_pgroup_name,
8052 					    inst->sc_fmri) != 0)
8053 						goto progress;
8054 			}
8055 
8056 			for (dpt = uu_list_first(svc->sc_dependents);
8057 			    dpt != NULL;
8058 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8059 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8060 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8061 					goto progress;
8062 		}
8063 
8064 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8065 		    old_dpt != NULL;
8066 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8067 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8068 			    old_dpt->sc_pgroup_name,
8069 			    old_dpt->sc_parent->sc_fmri) != 0)
8070 				goto progress;
8071 
8072 		result = 0;
8073 		goto out;
8074 	}
8075 
8076 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8077 		bad_error("uu_list_walk", uu_error());
8078 
8079 printerr:
8080 	/* If the error hasn't been printed yet, do so here. */
8081 	switch (cbdata.sc_err) {
8082 	case ECONNABORTED:
8083 		warn(gettext("Repository connection broken.\n"));
8084 		break;
8085 
8086 	case ENOMEM:
8087 		warn(emsg_nomem);
8088 		break;
8089 
8090 	case ENOSPC:
8091 		warn(emsg_nores);
8092 		break;
8093 
8094 	case EROFS:
8095 		warn(gettext("Repository is read-only.\n"));
8096 		break;
8097 
8098 	case EACCES:
8099 		warn(gettext("Repository backend denied access.\n"));
8100 		break;
8101 
8102 	case EPERM:
8103 	case EINVAL:
8104 	case EEXIST:
8105 	case EBUSY:
8106 	case EBADF:
8107 	case -1:
8108 		break;
8109 
8110 	default:
8111 		bad_error("lscf_service_import", cbdata.sc_err);
8112 	}
8113 
8114 progress:
8115 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8116 
8117 	for (svc = uu_list_first(bndl->sc_bundle_services);
8118 	    svc != NULL;
8119 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8120 		insts = svc->sc_u.sc_service.sc_service_instances;
8121 
8122 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8123 		    import_progress(svc->sc_import_state));
8124 
8125 		for (inst = uu_list_first(insts);
8126 		    inst != NULL;
8127 		    inst = uu_list_next(insts, inst))
8128 			warn(gettext("    Instance \"%s\": %s\n"),
8129 			    inst->sc_name,
8130 			    import_progress(inst->sc_import_state));
8131 	}
8132 
8133 	if (cbdata.sc_err == ECONNABORTED)
8134 		repository_teardown();
8135 
8136 
8137 	result = -1;
8138 
8139 out:
8140 	if (annotation_set != 0) {
8141 		/* Turn off annotation.  It is no longer needed. */
8142 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8143 	}
8144 
8145 	free_imp_globals();
8146 
8147 	return (result);
8148 }
8149 
8150 /*
8151  * _lscf_import_err() summarize the error handling returned by
8152  * lscf_import_{instance | service}_pgs
8153  * Return values are:
8154  * IMPORT_NEXT
8155  * IMPORT_OUT
8156  * IMPORT_BAD
8157  */
8158 
8159 #define	IMPORT_BAD	-1
8160 #define	IMPORT_NEXT	0
8161 #define	IMPORT_OUT	1
8162 
8163 static int
8164 _lscf_import_err(int err, const char *fmri)
8165 {
8166 	switch (err) {
8167 	case 0:
8168 		if (g_verbose)
8169 			warn(gettext("%s updated.\n"), fmri);
8170 		return (IMPORT_NEXT);
8171 
8172 	case ECONNABORTED:
8173 		warn(gettext("Could not update %s "
8174 		    "(repository connection broken).\n"), fmri);
8175 		return (IMPORT_OUT);
8176 
8177 	case ENOMEM:
8178 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8179 		return (IMPORT_OUT);
8180 
8181 	case ENOSPC:
8182 		warn(gettext("Could not update %s "
8183 		    "(repository server out of resources).\n"), fmri);
8184 		return (IMPORT_OUT);
8185 
8186 	case ECANCELED:
8187 		warn(gettext(
8188 		    "Could not update %s (deleted).\n"), fmri);
8189 		return (IMPORT_NEXT);
8190 
8191 	case EPERM:
8192 	case EINVAL:
8193 	case EBUSY:
8194 		return (IMPORT_NEXT);
8195 
8196 	case EROFS:
8197 		warn(gettext("Could not update %s (repository read-only).\n"),
8198 		    fmri);
8199 		return (IMPORT_OUT);
8200 
8201 	case EACCES:
8202 		warn(gettext("Could not update %s "
8203 		    "(backend access denied).\n"), fmri);
8204 		return (IMPORT_NEXT);
8205 
8206 	case EEXIST:
8207 	default:
8208 		return (IMPORT_BAD);
8209 	}
8210 
8211 	/*NOTREACHED*/
8212 }
8213 
8214 /*
8215  * The global imp_svc and imp_inst should be set by the caller in the
8216  * check to make sure the service and instance exist that the apply is
8217  * working on.
8218  */
8219 static int
8220 lscf_dependent_apply(void *dpg, void *e)
8221 {
8222 	scf_callback_t cb;
8223 	pgroup_t *dpt_pgroup = dpg;
8224 	pgroup_t *deldpt;
8225 	entity_t *ent = e;
8226 	int tissvc;
8227 	void *sc_ent, *tent;
8228 	scf_error_t serr;
8229 	int r;
8230 
8231 	const char * const dependents = "dependents";
8232 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8233 
8234 	if (issvc)
8235 		sc_ent = imp_svc;
8236 	else
8237 		sc_ent = imp_inst;
8238 
8239 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8240 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8241 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8242 	    imp_prop) != 0) {
8243 		switch (scf_error()) {
8244 		case SCF_ERROR_NOT_FOUND:
8245 		case SCF_ERROR_DELETED:
8246 			break;
8247 
8248 		case SCF_ERROR_CONNECTION_BROKEN:
8249 		case SCF_ERROR_NOT_SET:
8250 		case SCF_ERROR_INVALID_ARGUMENT:
8251 		case SCF_ERROR_HANDLE_MISMATCH:
8252 		case SCF_ERROR_NOT_BOUND:
8253 		default:
8254 			bad_error("entity_get_pg", scf_error());
8255 		}
8256 	} else {
8257 		/*
8258 		 * Found the dependents/<wip dep> so check to
8259 		 * see if the service is different.  If so
8260 		 * store the service for later refresh, and
8261 		 * delete the wip dependency from the service
8262 		 */
8263 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8264 			switch (scf_error()) {
8265 				case SCF_ERROR_DELETED:
8266 					break;
8267 
8268 				case SCF_ERROR_CONNECTION_BROKEN:
8269 				case SCF_ERROR_NOT_SET:
8270 				case SCF_ERROR_INVALID_ARGUMENT:
8271 				case SCF_ERROR_HANDLE_MISMATCH:
8272 				case SCF_ERROR_NOT_BOUND:
8273 				default:
8274 					bad_error("scf_property_get_value",
8275 					    scf_error());
8276 			}
8277 		}
8278 
8279 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8280 		    max_scf_value_len + 1) < 0)
8281 			bad_error("scf_value_get_as_string", scf_error());
8282 
8283 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8284 		switch (r) {
8285 		case 1:
8286 			break;
8287 		case 0:
8288 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8289 			    &tissvc)) != SCF_ERROR_NONE) {
8290 				if (serr == SCF_ERROR_NOT_FOUND) {
8291 					break;
8292 				} else {
8293 					bad_error("fmri_to_entity", serr);
8294 				}
8295 			}
8296 
8297 			if (entity_get_pg(tent, tissvc,
8298 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8299 				serr = scf_error();
8300 				if (serr == SCF_ERROR_NOT_FOUND ||
8301 				    serr == SCF_ERROR_DELETED) {
8302 					break;
8303 				} else {
8304 					bad_error("entity_get_pg", scf_error());
8305 				}
8306 			}
8307 
8308 			if (scf_pg_delete(imp_pg) != 0) {
8309 				serr = scf_error();
8310 				if (serr == SCF_ERROR_NOT_FOUND ||
8311 				    serr == SCF_ERROR_DELETED) {
8312 					break;
8313 				} else {
8314 					bad_error("scf_pg_delete", scf_error());
8315 				}
8316 			}
8317 
8318 			deldpt = internal_pgroup_new();
8319 			if (deldpt == NULL)
8320 				return (ENOMEM);
8321 			deldpt->sc_pgroup_name =
8322 			    strdup(dpt_pgroup->sc_pgroup_name);
8323 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8324 			if (deldpt->sc_pgroup_name == NULL ||
8325 			    deldpt->sc_pgroup_fmri == NULL)
8326 				return (ENOMEM);
8327 			deldpt->sc_parent = (entity_t *)ent;
8328 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8329 			    deldpt) != 0)
8330 				uu_die(gettext("libuutil error: %s\n"),
8331 				    uu_strerror(uu_error()));
8332 
8333 			break;
8334 		default:
8335 			bad_error("fmri_equal", r);
8336 		}
8337 	}
8338 
8339 	cb.sc_handle = g_hndl;
8340 	cb.sc_parent = ent;
8341 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8342 	cb.sc_source_fmri = ent->sc_fmri;
8343 	cb.sc_target_fmri = ent->sc_fmri;
8344 	cb.sc_trans = NULL;
8345 	cb.sc_flags = SCI_FORCE;
8346 
8347 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8348 		return (UU_WALK_ERROR);
8349 
8350 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8351 	switch (r) {
8352 	case 0:
8353 		break;
8354 
8355 	case ENOMEM:
8356 	case ECONNABORTED:
8357 	case EPERM:
8358 	case -1:
8359 		warn(gettext("Unable to refresh \"%s\"\n"),
8360 		    dpt_pgroup->sc_pgroup_fmri);
8361 		return (UU_WALK_ERROR);
8362 
8363 	default:
8364 		bad_error("imp_refresh_fmri", r);
8365 	}
8366 
8367 	return (UU_WALK_NEXT);
8368 }
8369 
8370 /*
8371  * Returns
8372  *   0 - success
8373  *   -1 - lscf_import_instance_pgs() failed.
8374  */
8375 int
8376 lscf_bundle_apply(bundle_t *bndl, const char *file)
8377 {
8378 	pgroup_t *old_dpt;
8379 	entity_t *svc, *inst;
8380 	int annotation_set = 0;
8381 	int ret = 0;
8382 	int r = 0;
8383 
8384 	lscf_prep_hndl();
8385 
8386 	if ((ret = alloc_imp_globals()))
8387 		goto out;
8388 
8389 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8390 		scfdie();
8391 
8392 	/*
8393 	 * Set the strings to be used for the security audit annotation
8394 	 * event.
8395 	 */
8396 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8397 		annotation_set = 1;
8398 	} else {
8399 		switch (scf_error()) {
8400 		case SCF_ERROR_CONNECTION_BROKEN:
8401 			warn(gettext("Repository connection broken.\n"));
8402 			goto out;
8403 
8404 		case SCF_ERROR_INVALID_ARGUMENT:
8405 		case SCF_ERROR_NOT_BOUND:
8406 		case SCF_ERROR_NO_RESOURCES:
8407 		case SCF_ERROR_INTERNAL:
8408 			bad_error("_scf_set_annotation", scf_error());
8409 			/* NOTREACHED */
8410 
8411 		default:
8412 			/*
8413 			 * Do not abort apply operation because of
8414 			 * inability to create annotation audit event.
8415 			 */
8416 			warn(gettext("_scf_set_annotation() unexpectedly "
8417 			    "failed with return code of %d\n"), scf_error());
8418 			break;
8419 		}
8420 	}
8421 
8422 	for (svc = uu_list_first(bndl->sc_bundle_services);
8423 	    svc != NULL;
8424 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8425 		int refresh = 0;
8426 
8427 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8428 		    imp_svc) != 0) {
8429 			switch (scf_error()) {
8430 			case SCF_ERROR_NOT_FOUND:
8431 				if (g_verbose)
8432 					warn(gettext("Ignoring nonexistent "
8433 					    "service %s.\n"), svc->sc_name);
8434 				continue;
8435 
8436 			default:
8437 				scfdie();
8438 			}
8439 		}
8440 
8441 		/*
8442 		 * If there were missing types in the profile, then need to
8443 		 * attempt to find the types.
8444 		 */
8445 		if (svc->sc_miss_type) {
8446 			if (uu_list_numnodes(svc->sc_pgroups) &&
8447 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8448 			    svc, UU_DEFAULT) != 0) {
8449 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8450 					bad_error("uu_list_walk", uu_error());
8451 
8452 				ret = -1;
8453 				continue;
8454 			}
8455 
8456 			for (inst = uu_list_first(
8457 			    svc->sc_u.sc_service.sc_service_instances);
8458 			    inst != NULL;
8459 			    inst = uu_list_next(
8460 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8461 				/*
8462 				 * If the instance doesn't exist just
8463 				 * skip to the next instance and let the
8464 				 * import note the missing instance.
8465 				 */
8466 				if (scf_service_get_instance(imp_svc,
8467 				    inst->sc_name, imp_inst) != 0)
8468 					continue;
8469 
8470 				if (uu_list_walk(inst->sc_pgroups,
8471 				    find_current_pg_type, inst,
8472 				    UU_DEFAULT) != 0) {
8473 					if (uu_error() !=
8474 					    UU_ERROR_CALLBACK_FAILED)
8475 						bad_error("uu_list_walk",
8476 						    uu_error());
8477 
8478 					ret = -1;
8479 					inst->sc_miss_type = B_TRUE;
8480 				}
8481 			}
8482 		}
8483 
8484 		/*
8485 		 * if we have pgs in the profile, we need to refresh ALL
8486 		 * instances of the service
8487 		 */
8488 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8489 			refresh = 1;
8490 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8491 			    SCI_FORCE | SCI_KEEP);
8492 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8493 			case IMPORT_NEXT:
8494 				break;
8495 
8496 			case IMPORT_OUT:
8497 				goto out;
8498 
8499 			case IMPORT_BAD:
8500 			default:
8501 				bad_error("lscf_import_service_pgs", r);
8502 			}
8503 		}
8504 
8505 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8506 			uu_list_walk(svc->sc_dependents,
8507 			    lscf_dependent_apply, svc, UU_DEFAULT);
8508 		}
8509 
8510 		for (inst = uu_list_first(
8511 		    svc->sc_u.sc_service.sc_service_instances);
8512 		    inst != NULL;
8513 		    inst = uu_list_next(
8514 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8515 			/*
8516 			 * This instance still has missing types
8517 			 * so skip it.
8518 			 */
8519 			if (inst->sc_miss_type) {
8520 				if (g_verbose)
8521 					warn(gettext("Ignoring instance "
8522 					    "%s:%s with missing types\n"),
8523 					    inst->sc_parent->sc_name,
8524 					    inst->sc_name);
8525 
8526 				continue;
8527 			}
8528 
8529 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8530 			    imp_inst) != 0) {
8531 				switch (scf_error()) {
8532 				case SCF_ERROR_NOT_FOUND:
8533 					if (g_verbose)
8534 						warn(gettext("Ignoring "
8535 						    "nonexistant instance "
8536 						    "%s:%s.\n"),
8537 						    inst->sc_parent->sc_name,
8538 						    inst->sc_name);
8539 					continue;
8540 
8541 				default:
8542 					scfdie();
8543 				}
8544 			}
8545 
8546 			/*
8547 			 * If the instance does not have a general/enabled
8548 			 * property and no last-import snapshot then the
8549 			 * instance is not a fully installed instance and
8550 			 * should not have a profile applied to it.
8551 			 *
8552 			 * This could happen if a service/instance declares
8553 			 * a dependent on behalf of another service/instance.
8554 			 *
8555 			 */
8556 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8557 			    imp_snap) != 0) {
8558 				if (scf_instance_get_pg(imp_inst,
8559 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8560 				    scf_pg_get_property(imp_pg,
8561 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8562 					if (g_verbose)
8563 						warn(gettext("Ignoreing "
8564 						    "partial instance "
8565 						    "%s:%s.\n"),
8566 						    inst->sc_parent->sc_name,
8567 						    inst->sc_name);
8568 					continue;
8569 				}
8570 			}
8571 
8572 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8573 			    inst, SCI_FORCE | SCI_KEEP);
8574 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8575 			case IMPORT_NEXT:
8576 				break;
8577 
8578 			case IMPORT_OUT:
8579 				goto out;
8580 
8581 			case IMPORT_BAD:
8582 			default:
8583 				bad_error("lscf_import_instance_pgs", r);
8584 			}
8585 
8586 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8587 				uu_list_walk(inst->sc_dependents,
8588 				    lscf_dependent_apply, inst, UU_DEFAULT);
8589 			}
8590 
8591 			/* refresh only if there is no pgs in the service */
8592 			if (refresh == 0)
8593 				(void) refresh_entity(0, imp_inst,
8594 				    inst->sc_fmri, NULL, NULL, NULL);
8595 		}
8596 
8597 		if (refresh == 1) {
8598 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8599 
8600 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8601 			    imp_inst, imp_iter, name_buf);
8602 			free(name_buf);
8603 		}
8604 
8605 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8606 		    old_dpt != NULL;
8607 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8608 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8609 			    old_dpt->sc_pgroup_name,
8610 			    old_dpt->sc_parent->sc_fmri) != 0) {
8611 				warn(gettext("Unable to refresh \"%s\"\n"),
8612 				    old_dpt->sc_pgroup_fmri);
8613 			}
8614 		}
8615 	}
8616 
8617 out:
8618 	if (annotation_set) {
8619 		/* Remove security audit annotation strings. */
8620 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8621 	}
8622 
8623 	free_imp_globals();
8624 	return (ret);
8625 }
8626 
8627 
8628 /*
8629  * Export.  These functions create and output an XML tree of a service
8630  * description from the repository.  This is largely the inverse of
8631  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8632  *
8633  * - We must include any properties which are not represented specifically by
8634  *   a service manifest, e.g., properties created by an admin post-import.  To
8635  *   do so we'll iterate through all properties and deal with each
8636  *   apropriately.
8637  *
8638  * - Children of services and instances must must be in the order set by the
8639  *   DTD, but we iterate over the properties in undefined order.  The elements
8640  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8641  *   number of classes of them, however, we'll keep the classes separate and
8642  *   assemble them in order.
8643  */
8644 
8645 /*
8646  * Convenience function to handle xmlSetProp errors (and type casting).
8647  */
8648 static void
8649 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8650 {
8651 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8652 		uu_die(gettext("Could not set XML property.\n"));
8653 }
8654 
8655 /*
8656  * Convenience function to set an XML attribute to the single value of an
8657  * astring property.  If the value happens to be the default, don't set the
8658  * attribute.  "dval" should be the default value supplied by the DTD, or
8659  * NULL for no default.
8660  */
8661 static int
8662 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8663     const char *name, const char *dval)
8664 {
8665 	scf_value_t *val;
8666 	ssize_t len;
8667 	char *str;
8668 
8669 	val = scf_value_create(g_hndl);
8670 	if (val == NULL)
8671 		scfdie();
8672 
8673 	if (prop_get_val(prop, val) != 0) {
8674 		scf_value_destroy(val);
8675 		return (-1);
8676 	}
8677 
8678 	len = scf_value_get_as_string(val, NULL, 0);
8679 	if (len < 0)
8680 		scfdie();
8681 
8682 	str = safe_malloc(len + 1);
8683 
8684 	if (scf_value_get_as_string(val, str, len + 1) < 0)
8685 		scfdie();
8686 
8687 	scf_value_destroy(val);
8688 
8689 	if (dval == NULL || strcmp(str, dval) != 0)
8690 		safe_setprop(n, name, str);
8691 
8692 	free(str);
8693 
8694 	return (0);
8695 }
8696 
8697 /*
8698  * As above, but the attribute is always set.
8699  */
8700 static int
8701 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
8702 {
8703 	return (set_attr_from_prop_default(prop, n, name, NULL));
8704 }
8705 
8706 /*
8707  * Dump the given document onto f, with "'s replaced by ''s.
8708  */
8709 static int
8710 write_service_bundle(xmlDocPtr doc, FILE *f)
8711 {
8712 	xmlChar *mem;
8713 	int sz, i;
8714 
8715 	mem = NULL;
8716 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
8717 
8718 	if (mem == NULL) {
8719 		semerr(gettext("Could not dump XML tree.\n"));
8720 		return (-1);
8721 	}
8722 
8723 	/*
8724 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
8725 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
8726 	 * &apos; code?!
8727 	 */
8728 	for (i = 0; i < sz; ++i) {
8729 		char c = (char)mem[i];
8730 
8731 		if (c == '"')
8732 			(void) fputc('\'', f);
8733 		else if (c == '\'')
8734 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
8735 		else
8736 			(void) fputc(c, f);
8737 	}
8738 
8739 	return (0);
8740 }
8741 
8742 /*
8743  * Create the DOM elements in elts necessary to (generically) represent prop
8744  * (i.e., a property or propval element).  If the name of the property is
8745  * known, it should be passed as name_arg.  Otherwise, pass NULL.
8746  */
8747 static void
8748 export_property(scf_property_t *prop, const char *name_arg,
8749     struct pg_elts *elts, int flags)
8750 {
8751 	const char *type;
8752 	scf_error_t err = 0;
8753 	xmlNodePtr pnode, lnode;
8754 	char *lnname;
8755 	int ret;
8756 
8757 	/* name */
8758 	if (name_arg != NULL) {
8759 		(void) strcpy(exp_str, name_arg);
8760 	} else {
8761 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8762 			scfdie();
8763 	}
8764 
8765 	/* type */
8766 	type = prop_to_typestr(prop);
8767 	if (type == NULL)
8768 		uu_die(gettext("Can't export property %s: unknown type.\n"),
8769 		    exp_str);
8770 
8771 	/* If we're exporting values, and there's just one, export it here. */
8772 	if (!(flags & SCE_ALL_VALUES))
8773 		goto empty;
8774 
8775 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8776 		xmlNodePtr n;
8777 
8778 		/* Single value, so use propval */
8779 		n = xmlNewNode(NULL, (xmlChar *)"propval");
8780 		if (n == NULL)
8781 			uu_die(emsg_create_xml);
8782 
8783 		safe_setprop(n, name_attr, exp_str);
8784 		safe_setprop(n, type_attr, type);
8785 
8786 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8787 			scfdie();
8788 		safe_setprop(n, value_attr, exp_str);
8789 
8790 		if (elts->propvals == NULL)
8791 			elts->propvals = n;
8792 		else
8793 			(void) xmlAddSibling(elts->propvals, n);
8794 
8795 		return;
8796 	}
8797 
8798 	err = scf_error();
8799 
8800 	if (err == SCF_ERROR_PERMISSION_DENIED) {
8801 		semerr(emsg_permission_denied);
8802 		return;
8803 	}
8804 
8805 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8806 	    err != SCF_ERROR_NOT_FOUND &&
8807 	    err != SCF_ERROR_PERMISSION_DENIED)
8808 		scfdie();
8809 
8810 empty:
8811 	/* Multiple (or no) values, so use property */
8812 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
8813 	if (pnode == NULL)
8814 		uu_die(emsg_create_xml);
8815 
8816 	safe_setprop(pnode, name_attr, exp_str);
8817 	safe_setprop(pnode, type_attr, type);
8818 
8819 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8820 		lnname = uu_msprintf("%s_list", type);
8821 		if (lnname == NULL)
8822 			uu_die(gettext("Could not create string"));
8823 
8824 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8825 		if (lnode == NULL)
8826 			uu_die(emsg_create_xml);
8827 
8828 		uu_free(lnname);
8829 
8830 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8831 			scfdie();
8832 
8833 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8834 		    1) {
8835 			xmlNodePtr vn;
8836 
8837 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8838 			    NULL);
8839 			if (vn == NULL)
8840 				uu_die(emsg_create_xml);
8841 
8842 			if (scf_value_get_as_string(exp_val, exp_str,
8843 			    exp_str_sz) < 0)
8844 				scfdie();
8845 			safe_setprop(vn, value_attr, exp_str);
8846 		}
8847 		if (ret != 0)
8848 			scfdie();
8849 	}
8850 
8851 	if (elts->properties == NULL)
8852 		elts->properties = pnode;
8853 	else
8854 		(void) xmlAddSibling(elts->properties, pnode);
8855 }
8856 
8857 /*
8858  * Add a property_group element for this property group to elts.
8859  */
8860 static void
8861 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8862 {
8863 	xmlNodePtr n;
8864 	struct pg_elts elts;
8865 	int ret;
8866 	boolean_t read_protected;
8867 
8868 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
8869 
8870 	/* name */
8871 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8872 		scfdie();
8873 	safe_setprop(n, name_attr, exp_str);
8874 
8875 	/* type */
8876 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8877 		scfdie();
8878 	safe_setprop(n, type_attr, exp_str);
8879 
8880 	/* properties */
8881 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8882 		scfdie();
8883 
8884 	(void) memset(&elts, 0, sizeof (elts));
8885 
8886 	/*
8887 	 * If this property group is not read protected, we always want to
8888 	 * output all the values.  Otherwise, we only output the values if the
8889 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8890 	 */
8891 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8892 		scfdie();
8893 
8894 	if (!read_protected)
8895 		flags |= SCE_ALL_VALUES;
8896 
8897 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8898 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8899 			scfdie();
8900 
8901 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8902 			xmlNodePtr m;
8903 
8904 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8905 			if (m == NULL)
8906 				uu_die(emsg_create_xml);
8907 
8908 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8909 				elts.stability = m;
8910 				continue;
8911 			}
8912 
8913 			xmlFreeNode(m);
8914 		}
8915 
8916 		export_property(exp_prop, NULL, &elts, flags);
8917 	}
8918 	if (ret == -1)
8919 		scfdie();
8920 
8921 	(void) xmlAddChild(n, elts.stability);
8922 	(void) xmlAddChildList(n, elts.propvals);
8923 	(void) xmlAddChildList(n, elts.properties);
8924 
8925 	if (eelts->property_groups == NULL)
8926 		eelts->property_groups = n;
8927 	else
8928 		(void) xmlAddSibling(eelts->property_groups, n);
8929 }
8930 
8931 /*
8932  * Create an XML node representing the dependency described by the given
8933  * property group and put it in eelts.  Unless the dependency is not valid, in
8934  * which case create a generic property_group element which represents it and
8935  * put it in eelts.
8936  */
8937 static void
8938 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8939 {
8940 	xmlNodePtr n;
8941 	int err = 0, ret;
8942 	struct pg_elts elts;
8943 
8944 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
8945 	if (n == NULL)
8946 		uu_die(emsg_create_xml);
8947 
8948 	/*
8949 	 * If the external flag is present, skip this dependency because it
8950 	 * should have been created by another manifest.
8951 	 */
8952 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
8953 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8954 		    prop_get_val(exp_prop, exp_val) == 0) {
8955 			uint8_t b;
8956 
8957 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
8958 				scfdie();
8959 
8960 			if (b)
8961 				return;
8962 		}
8963 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
8964 		scfdie();
8965 
8966 	/* Get the required attributes. */
8967 
8968 	/* name */
8969 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8970 		scfdie();
8971 	safe_setprop(n, name_attr, exp_str);
8972 
8973 	/* grouping */
8974 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8975 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8976 		err = 1;
8977 
8978 	/* restart_on */
8979 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8980 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8981 		err = 1;
8982 
8983 	/* type */
8984 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8985 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8986 		err = 1;
8987 
8988 	/*
8989 	 * entities: Not required, but if we create no children, it will be
8990 	 * created as empty on import, so fail if it's missing.
8991 	 */
8992 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8993 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
8994 		scf_iter_t *eiter;
8995 		int ret2;
8996 
8997 		eiter = scf_iter_create(g_hndl);
8998 		if (eiter == NULL)
8999 			scfdie();
9000 
9001 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9002 			scfdie();
9003 
9004 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9005 			xmlNodePtr ch;
9006 
9007 			if (scf_value_get_astring(exp_val, exp_str,
9008 			    exp_str_sz) < 0)
9009 				scfdie();
9010 
9011 			/*
9012 			 * service_fmri's must be first, so we can add them
9013 			 * here.
9014 			 */
9015 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9016 			    NULL);
9017 			if (ch == NULL)
9018 				uu_die(emsg_create_xml);
9019 
9020 			safe_setprop(ch, value_attr, exp_str);
9021 		}
9022 		if (ret2 == -1)
9023 			scfdie();
9024 
9025 		scf_iter_destroy(eiter);
9026 	} else
9027 		err = 1;
9028 
9029 	if (err) {
9030 		xmlFreeNode(n);
9031 
9032 		export_pg(pg, eelts, 0);
9033 
9034 		return;
9035 	}
9036 
9037 	/* Iterate through the properties & handle each. */
9038 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9039 		scfdie();
9040 
9041 	(void) memset(&elts, 0, sizeof (elts));
9042 
9043 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9044 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9045 			scfdie();
9046 
9047 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9048 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9049 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9050 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9051 			continue;
9052 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9053 			xmlNodePtr m;
9054 
9055 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9056 			if (m == NULL)
9057 				uu_die(emsg_create_xml);
9058 
9059 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9060 				elts.stability = m;
9061 				continue;
9062 			}
9063 
9064 			xmlFreeNode(m);
9065 		}
9066 
9067 		export_property(exp_prop, exp_str, &elts, 0);
9068 	}
9069 	if (ret == -1)
9070 		scfdie();
9071 
9072 	(void) xmlAddChild(n, elts.stability);
9073 	(void) xmlAddChildList(n, elts.propvals);
9074 	(void) xmlAddChildList(n, elts.properties);
9075 
9076 	if (eelts->dependencies == NULL)
9077 		eelts->dependencies = n;
9078 	else
9079 		(void) xmlAddSibling(eelts->dependencies, n);
9080 }
9081 
9082 static xmlNodePtr
9083 export_method_environment(scf_propertygroup_t *pg)
9084 {
9085 	xmlNodePtr env;
9086 	int ret;
9087 	int children = 0;
9088 
9089 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9090 		return (NULL);
9091 
9092 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9093 	if (env == NULL)
9094 		uu_die(emsg_create_xml);
9095 
9096 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9097 		scfdie();
9098 
9099 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9100 		scfdie();
9101 
9102 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9103 		xmlNodePtr ev;
9104 		char *cp;
9105 
9106 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9107 			scfdie();
9108 
9109 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9110 			warn(gettext("Invalid environment variable \"%s\".\n"),
9111 			    exp_str);
9112 			continue;
9113 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9114 			warn(gettext("Invalid environment variable \"%s\"; "
9115 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9116 			continue;
9117 		}
9118 
9119 		*cp = '\0';
9120 		cp++;
9121 
9122 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9123 		if (ev == NULL)
9124 			uu_die(emsg_create_xml);
9125 
9126 		safe_setprop(ev, name_attr, exp_str);
9127 		safe_setprop(ev, value_attr, cp);
9128 		children++;
9129 	}
9130 
9131 	if (ret != 0)
9132 		scfdie();
9133 
9134 	if (children == 0) {
9135 		xmlFreeNode(env);
9136 		return (NULL);
9137 	}
9138 
9139 	return (env);
9140 }
9141 
9142 /*
9143  * As above, but for a method property group.
9144  */
9145 static void
9146 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9147 {
9148 	xmlNodePtr n, env;
9149 	char *str;
9150 	int err = 0, nonenv, ret;
9151 	uint8_t use_profile;
9152 	struct pg_elts elts;
9153 	xmlNodePtr ctxt = NULL;
9154 
9155 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9156 
9157 	/* Get the required attributes. */
9158 
9159 	/* name */
9160 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9161 		scfdie();
9162 	safe_setprop(n, name_attr, exp_str);
9163 
9164 	/* type */
9165 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9166 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9167 		err = 1;
9168 
9169 	/* exec */
9170 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9171 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9172 		err = 1;
9173 
9174 	/* timeout */
9175 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9176 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9177 	    prop_get_val(exp_prop, exp_val) == 0) {
9178 		uint64_t c;
9179 
9180 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9181 			scfdie();
9182 
9183 		str = uu_msprintf("%llu", c);
9184 		if (str == NULL)
9185 			uu_die(gettext("Could not create string"));
9186 
9187 		safe_setprop(n, "timeout_seconds", str);
9188 		free(str);
9189 	} else
9190 		err = 1;
9191 
9192 	if (err) {
9193 		xmlFreeNode(n);
9194 
9195 		export_pg(pg, eelts, 0);
9196 
9197 		return;
9198 	}
9199 
9200 
9201 	/*
9202 	 * If we're going to have a method_context child, we need to know
9203 	 * before we iterate through the properties.  Since method_context's
9204 	 * are optional, we don't want to complain about any properties
9205 	 * missing if none of them are there.  Thus we can't use the
9206 	 * convenience functions.
9207 	 */
9208 	nonenv =
9209 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9210 	    SCF_SUCCESS ||
9211 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9212 	    SCF_SUCCESS ||
9213 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9214 	    SCF_SUCCESS ||
9215 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9216 	    SCF_SUCCESS;
9217 
9218 	if (nonenv) {
9219 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9220 		if (ctxt == NULL)
9221 			uu_die(emsg_create_xml);
9222 
9223 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9224 		    0 &&
9225 		    set_attr_from_prop_default(exp_prop, ctxt,
9226 		    "working_directory", ":default") != 0)
9227 			err = 1;
9228 
9229 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9230 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9231 		    ":default") != 0)
9232 			err = 1;
9233 
9234 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9235 		    0 &&
9236 		    set_attr_from_prop_default(exp_prop, ctxt,
9237 		    "resource_pool", ":default") != 0)
9238 			err = 1;
9239 		/*
9240 		 * We only want to complain about profile or credential
9241 		 * properties if we will use them.  To determine that we must
9242 		 * examine USE_PROFILE.
9243 		 */
9244 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9245 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9246 		    prop_get_val(exp_prop, exp_val) == 0) {
9247 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9248 			    SCF_SUCCESS) {
9249 				scfdie();
9250 			}
9251 
9252 			if (use_profile) {
9253 				xmlNodePtr prof;
9254 
9255 				prof = xmlNewChild(ctxt, NULL,
9256 				    (xmlChar *)"method_profile", NULL);
9257 				if (prof == NULL)
9258 					uu_die(emsg_create_xml);
9259 
9260 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9261 				    exp_prop) != 0 ||
9262 				    set_attr_from_prop(exp_prop, prof,
9263 				    name_attr) != 0)
9264 					err = 1;
9265 			} else {
9266 				xmlNodePtr cred;
9267 
9268 				cred = xmlNewChild(ctxt, NULL,
9269 				    (xmlChar *)"method_credential", NULL);
9270 				if (cred == NULL)
9271 					uu_die(emsg_create_xml);
9272 
9273 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9274 				    exp_prop) != 0 ||
9275 				    set_attr_from_prop(exp_prop, cred,
9276 				    "user") != 0) {
9277 					err = 1;
9278 				}
9279 
9280 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9281 				    exp_prop) == 0 &&
9282 				    set_attr_from_prop_default(exp_prop, cred,
9283 				    "group", ":default") != 0)
9284 					err = 1;
9285 
9286 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9287 				    exp_prop) == 0 &&
9288 				    set_attr_from_prop_default(exp_prop, cred,
9289 				    "supp_groups", ":default") != 0)
9290 					err = 1;
9291 
9292 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9293 				    exp_prop) == 0 &&
9294 				    set_attr_from_prop_default(exp_prop, cred,
9295 				    "privileges", ":default") != 0)
9296 					err = 1;
9297 
9298 				if (pg_get_prop(pg,
9299 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9300 				    exp_prop) == 0 &&
9301 				    set_attr_from_prop_default(exp_prop, cred,
9302 				    "limit_privileges", ":default") != 0)
9303 					err = 1;
9304 			}
9305 		}
9306 	}
9307 
9308 	if ((env = export_method_environment(pg)) != NULL) {
9309 		if (ctxt == NULL) {
9310 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9311 			if (ctxt == NULL)
9312 				uu_die(emsg_create_xml);
9313 		}
9314 		(void) xmlAddChild(ctxt, env);
9315 	}
9316 
9317 	if (env != NULL || (nonenv && err == 0))
9318 		(void) xmlAddChild(n, ctxt);
9319 	else
9320 		xmlFreeNode(ctxt);
9321 
9322 	nonenv = (err == 0);
9323 
9324 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9325 		scfdie();
9326 
9327 	(void) memset(&elts, 0, sizeof (elts));
9328 
9329 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9330 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9331 			scfdie();
9332 
9333 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9334 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9335 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9336 			continue;
9337 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9338 			xmlNodePtr m;
9339 
9340 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9341 			if (m == NULL)
9342 				uu_die(emsg_create_xml);
9343 
9344 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9345 				elts.stability = m;
9346 				continue;
9347 			}
9348 
9349 			xmlFreeNode(m);
9350 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9351 		    0 ||
9352 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9353 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9354 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9355 			if (nonenv)
9356 				continue;
9357 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9358 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9359 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9360 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9361 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9362 			if (nonenv && !use_profile)
9363 				continue;
9364 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9365 			if (nonenv && use_profile)
9366 				continue;
9367 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9368 			if (env != NULL)
9369 				continue;
9370 		}
9371 
9372 		export_property(exp_prop, exp_str, &elts, 0);
9373 	}
9374 	if (ret == -1)
9375 		scfdie();
9376 
9377 	(void) xmlAddChild(n, elts.stability);
9378 	(void) xmlAddChildList(n, elts.propvals);
9379 	(void) xmlAddChildList(n, elts.properties);
9380 
9381 	if (eelts->exec_methods == NULL)
9382 		eelts->exec_methods = n;
9383 	else
9384 		(void) xmlAddSibling(eelts->exec_methods, n);
9385 }
9386 
9387 static void
9388 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9389     struct entity_elts *eelts)
9390 {
9391 	xmlNodePtr pgnode;
9392 
9393 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9394 	if (pgnode == NULL)
9395 		uu_die(emsg_create_xml);
9396 
9397 	safe_setprop(pgnode, name_attr, name);
9398 	safe_setprop(pgnode, type_attr, type);
9399 
9400 	(void) xmlAddChildList(pgnode, elts->propvals);
9401 	(void) xmlAddChildList(pgnode, elts->properties);
9402 
9403 	if (eelts->property_groups == NULL)
9404 		eelts->property_groups = pgnode;
9405 	else
9406 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9407 }
9408 
9409 /*
9410  * Process the general property group for a service.  This is the one with the
9411  * goodies.
9412  */
9413 static void
9414 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9415 {
9416 	struct pg_elts elts;
9417 	int ret;
9418 
9419 	/*
9420 	 * In case there are properties which don't correspond to child
9421 	 * entities of the service entity, we'll set up a pg_elts structure to
9422 	 * put them in.
9423 	 */
9424 	(void) memset(&elts, 0, sizeof (elts));
9425 
9426 	/* Walk the properties, looking for special ones. */
9427 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9428 		scfdie();
9429 
9430 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9431 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9432 			scfdie();
9433 
9434 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9435 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9436 			    prop_get_val(exp_prop, exp_val) == 0) {
9437 				uint8_t b;
9438 
9439 				if (scf_value_get_boolean(exp_val, &b) !=
9440 				    SCF_SUCCESS)
9441 					scfdie();
9442 
9443 				if (b) {
9444 					selts->single_instance =
9445 					    xmlNewNode(NULL,
9446 					    (xmlChar *)"single_instance");
9447 					if (selts->single_instance == NULL)
9448 						uu_die(emsg_create_xml);
9449 				}
9450 
9451 				continue;
9452 			}
9453 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9454 			xmlNodePtr rnode, sfnode;
9455 
9456 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9457 			if (rnode == NULL)
9458 				uu_die(emsg_create_xml);
9459 
9460 			sfnode = xmlNewChild(rnode, NULL,
9461 			    (xmlChar *)"service_fmri", NULL);
9462 			if (sfnode == NULL)
9463 				uu_die(emsg_create_xml);
9464 
9465 			if (set_attr_from_prop(exp_prop, sfnode,
9466 			    value_attr) == 0) {
9467 				selts->restarter = rnode;
9468 				continue;
9469 			}
9470 
9471 			xmlFreeNode(rnode);
9472 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9473 		    0) {
9474 			xmlNodePtr s;
9475 
9476 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9477 			if (s == NULL)
9478 				uu_die(emsg_create_xml);
9479 
9480 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9481 				selts->stability = s;
9482 				continue;
9483 			}
9484 
9485 			xmlFreeNode(s);
9486 		}
9487 
9488 		export_property(exp_prop, exp_str, &elts, 0);
9489 	}
9490 	if (ret == -1)
9491 		scfdie();
9492 
9493 	if (elts.propvals != NULL || elts.properties != NULL)
9494 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9495 		    selts);
9496 }
9497 
9498 static void
9499 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9500 {
9501 	xmlNodePtr n, prof, cred, env;
9502 	uint8_t use_profile;
9503 	int ret, err = 0;
9504 
9505 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9506 
9507 	env = export_method_environment(pg);
9508 
9509 	/* Need to know whether we'll use a profile or not. */
9510 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9511 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9512 	    prop_get_val(exp_prop, exp_val) == 0) {
9513 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9514 			scfdie();
9515 
9516 		if (use_profile)
9517 			prof =
9518 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9519 			    NULL);
9520 		else
9521 			cred =
9522 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9523 			    NULL);
9524 	}
9525 
9526 	if (env != NULL)
9527 		(void) xmlAddChild(n, env);
9528 
9529 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9530 		scfdie();
9531 
9532 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9533 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9534 			scfdie();
9535 
9536 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9537 			if (set_attr_from_prop(exp_prop, n,
9538 			    "working_directory") != 0)
9539 				err = 1;
9540 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9541 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9542 				err = 1;
9543 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9544 			if (set_attr_from_prop(exp_prop, n,
9545 			    "resource_pool") != 0)
9546 				err = 1;
9547 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9548 			/* EMPTY */
9549 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9550 			if (use_profile ||
9551 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9552 				err = 1;
9553 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9554 			if (use_profile ||
9555 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9556 				err = 1;
9557 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9558 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9559 			    "supp_groups") != 0)
9560 				err = 1;
9561 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9562 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9563 			    "privileges") != 0)
9564 				err = 1;
9565 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9566 		    0) {
9567 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9568 			    "limit_privileges") != 0)
9569 				err = 1;
9570 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9571 			if (!use_profile || set_attr_from_prop(exp_prop,
9572 			    prof, name_attr) != 0)
9573 				err = 1;
9574 		} else {
9575 			/* Can't have generic properties in method_context's */
9576 			err = 1;
9577 		}
9578 	}
9579 	if (ret == -1)
9580 		scfdie();
9581 
9582 	if (err && env == NULL) {
9583 		xmlFreeNode(n);
9584 		export_pg(pg, elts, 0);
9585 		return;
9586 	}
9587 
9588 	elts->method_context = n;
9589 }
9590 
9591 /*
9592  * Given a dependency property group in the tfmri entity (target fmri), return
9593  * a dependent element which represents it.
9594  */
9595 static xmlNodePtr
9596 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9597 {
9598 	uint8_t b;
9599 	xmlNodePtr n, sf;
9600 	int err = 0, ret;
9601 	struct pg_elts pgelts;
9602 
9603 	/*
9604 	 * If external isn't set to true then exporting the service will
9605 	 * export this as a normal dependency, so we should stop to avoid
9606 	 * duplication.
9607 	 */
9608 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9609 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9610 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9611 		if (g_verbose) {
9612 			warn(gettext("Dependent \"%s\" cannot be exported "
9613 			    "properly because the \"%s\" property of the "
9614 			    "\"%s\" dependency of %s is not set to true.\n"),
9615 			    name, scf_property_external, name, tfmri);
9616 		}
9617 
9618 		return (NULL);
9619 	}
9620 
9621 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9622 	if (n == NULL)
9623 		uu_die(emsg_create_xml);
9624 
9625 	safe_setprop(n, name_attr, name);
9626 
9627 	/* Get the required attributes */
9628 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9629 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9630 		err = 1;
9631 
9632 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9633 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9634 		err = 1;
9635 
9636 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9637 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9638 	    prop_get_val(exp_prop, exp_val) == 0) {
9639 		/* EMPTY */
9640 	} else
9641 		err = 1;
9642 
9643 	if (err) {
9644 		xmlFreeNode(n);
9645 		return (NULL);
9646 	}
9647 
9648 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9649 	if (sf == NULL)
9650 		uu_die(emsg_create_xml);
9651 
9652 	safe_setprop(sf, value_attr, tfmri);
9653 
9654 	/*
9655 	 * Now add elements for the other properties.
9656 	 */
9657 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9658 		scfdie();
9659 
9660 	(void) memset(&pgelts, 0, sizeof (pgelts));
9661 
9662 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9663 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9664 			scfdie();
9665 
9666 		if (strcmp(exp_str, scf_property_external) == 0 ||
9667 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9668 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9669 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9670 			continue;
9671 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9672 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9673 			    prop_get_val(exp_prop, exp_val) == 0) {
9674 				char type[sizeof ("service") + 1];
9675 
9676 				if (scf_value_get_astring(exp_val, type,
9677 				    sizeof (type)) < 0)
9678 					scfdie();
9679 
9680 				if (strcmp(type, "service") == 0)
9681 					continue;
9682 			}
9683 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9684 			xmlNodePtr s;
9685 
9686 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9687 			if (s == NULL)
9688 				uu_die(emsg_create_xml);
9689 
9690 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9691 				pgelts.stability = s;
9692 				continue;
9693 			}
9694 
9695 			xmlFreeNode(s);
9696 		}
9697 
9698 		export_property(exp_prop, exp_str, &pgelts, 0);
9699 	}
9700 	if (ret == -1)
9701 		scfdie();
9702 
9703 	(void) xmlAddChild(n, pgelts.stability);
9704 	(void) xmlAddChildList(n, pgelts.propvals);
9705 	(void) xmlAddChildList(n, pgelts.properties);
9706 
9707 	return (n);
9708 }
9709 
9710 static void
9711 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
9712 {
9713 	scf_propertygroup_t *opg;
9714 	scf_iter_t *iter;
9715 	char *type, *fmri;
9716 	int ret;
9717 	struct pg_elts pgelts;
9718 	xmlNodePtr n;
9719 	scf_error_t serr;
9720 
9721 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
9722 	    (iter = scf_iter_create(g_hndl)) == NULL)
9723 		scfdie();
9724 
9725 	/* Can't use exp_prop_iter due to export_dependent(). */
9726 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
9727 		scfdie();
9728 
9729 	type = safe_malloc(max_scf_pg_type_len + 1);
9730 
9731 	/* Get an extra byte so we can tell if values are too long. */
9732 	fmri = safe_malloc(max_scf_fmri_len + 2);
9733 
9734 	(void) memset(&pgelts, 0, sizeof (pgelts));
9735 
9736 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
9737 		void *entity;
9738 		int isservice;
9739 		scf_type_t ty;
9740 
9741 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
9742 			scfdie();
9743 
9744 		if ((ty != SCF_TYPE_ASTRING &&
9745 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
9746 		    prop_get_val(exp_prop, exp_val) != 0) {
9747 			export_property(exp_prop, NULL, &pgelts, 0);
9748 			continue;
9749 		}
9750 
9751 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9752 			scfdie();
9753 
9754 		if (scf_value_get_astring(exp_val, fmri,
9755 		    max_scf_fmri_len + 2) < 0)
9756 			scfdie();
9757 
9758 		/* Look for a dependency group in the target fmri. */
9759 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9760 		switch (serr) {
9761 		case SCF_ERROR_NONE:
9762 			break;
9763 
9764 		case SCF_ERROR_NO_MEMORY:
9765 			uu_die(gettext("Out of memory.\n"));
9766 			/* NOTREACHED */
9767 
9768 		case SCF_ERROR_INVALID_ARGUMENT:
9769 			if (g_verbose) {
9770 				if (scf_property_to_fmri(exp_prop, fmri,
9771 				    max_scf_fmri_len + 2) < 0)
9772 					scfdie();
9773 
9774 				warn(gettext("The value of %s is not a valid "
9775 				    "FMRI.\n"), fmri);
9776 			}
9777 
9778 			export_property(exp_prop, exp_str, &pgelts, 0);
9779 			continue;
9780 
9781 		case SCF_ERROR_CONSTRAINT_VIOLATED:
9782 			if (g_verbose) {
9783 				if (scf_property_to_fmri(exp_prop, fmri,
9784 				    max_scf_fmri_len + 2) < 0)
9785 					scfdie();
9786 
9787 				warn(gettext("The value of %s does not specify "
9788 				    "a service or an instance.\n"), fmri);
9789 			}
9790 
9791 			export_property(exp_prop, exp_str, &pgelts, 0);
9792 			continue;
9793 
9794 		case SCF_ERROR_NOT_FOUND:
9795 			if (g_verbose) {
9796 				if (scf_property_to_fmri(exp_prop, fmri,
9797 				    max_scf_fmri_len + 2) < 0)
9798 					scfdie();
9799 
9800 				warn(gettext("The entity specified by %s does "
9801 				    "not exist.\n"), fmri);
9802 			}
9803 
9804 			export_property(exp_prop, exp_str, &pgelts, 0);
9805 			continue;
9806 
9807 		default:
9808 #ifndef NDEBUG
9809 			(void) fprintf(stderr, "%s:%d: %s() failed with "
9810 			    "unexpected error %d.\n", __FILE__, __LINE__,
9811 			    "fmri_to_entity", serr);
9812 #endif
9813 			abort();
9814 		}
9815 
9816 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9817 			if (scf_error() != SCF_ERROR_NOT_FOUND)
9818 				scfdie();
9819 
9820 			warn(gettext("Entity %s is missing dependency property "
9821 			    "group %s.\n"), fmri, exp_str);
9822 
9823 			export_property(exp_prop, NULL, &pgelts, 0);
9824 			continue;
9825 		}
9826 
9827 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9828 			scfdie();
9829 
9830 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9831 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9832 				scfdie();
9833 
9834 			warn(gettext("Property group %s is not of "
9835 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9836 
9837 			export_property(exp_prop, NULL, &pgelts, 0);
9838 			continue;
9839 		}
9840 
9841 		n = export_dependent(opg, exp_str, fmri);
9842 		if (n == NULL)
9843 			export_property(exp_prop, exp_str, &pgelts, 0);
9844 		else {
9845 			if (eelts->dependents == NULL)
9846 				eelts->dependents = n;
9847 			else
9848 				(void) xmlAddSibling(eelts->dependents,
9849 				    n);
9850 		}
9851 	}
9852 	if (ret == -1)
9853 		scfdie();
9854 
9855 	free(fmri);
9856 	free(type);
9857 
9858 	scf_iter_destroy(iter);
9859 	scf_pg_destroy(opg);
9860 
9861 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9862 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9863 		    eelts);
9864 }
9865 
9866 static void
9867 make_node(xmlNodePtr *nodep, const char *name)
9868 {
9869 	if (*nodep == NULL) {
9870 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
9871 		if (*nodep == NULL)
9872 			uu_die(emsg_create_xml);
9873 	}
9874 }
9875 
9876 static xmlNodePtr
9877 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9878 {
9879 	int ret;
9880 	xmlNodePtr parent = NULL;
9881 	xmlNodePtr loctext = NULL;
9882 
9883 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9884 		scfdie();
9885 
9886 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9887 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9888 		    prop_get_val(exp_prop, exp_val) != 0)
9889 			continue;
9890 
9891 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9892 			scfdie();
9893 
9894 		make_node(&parent, parname);
9895 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9896 		    (xmlChar *)exp_str);
9897 		if (loctext == NULL)
9898 			uu_die(emsg_create_xml);
9899 
9900 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9901 			scfdie();
9902 
9903 		safe_setprop(loctext, "xml:lang", exp_str);
9904 	}
9905 
9906 	if (ret == -1)
9907 		scfdie();
9908 
9909 	return (parent);
9910 }
9911 
9912 static xmlNodePtr
9913 export_tm_manpage(scf_propertygroup_t *pg)
9914 {
9915 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9916 	if (manpage == NULL)
9917 		uu_die(emsg_create_xml);
9918 
9919 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9920 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9921 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9922 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9923 		xmlFreeNode(manpage);
9924 		return (NULL);
9925 	}
9926 
9927 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9928 		(void) set_attr_from_prop_default(exp_prop,
9929 		    manpage, "manpath", ":default");
9930 
9931 	return (manpage);
9932 }
9933 
9934 static xmlNodePtr
9935 export_tm_doc_link(scf_propertygroup_t *pg)
9936 {
9937 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9938 	if (doc_link == NULL)
9939 		uu_die(emsg_create_xml);
9940 
9941 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9942 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9943 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9944 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9945 		xmlFreeNode(doc_link);
9946 		return (NULL);
9947 	}
9948 	return (doc_link);
9949 }
9950 
9951 /*
9952  * Process template information for a service or instances.
9953  */
9954 static void
9955 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
9956     struct template_elts *telts)
9957 {
9958 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
9959 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
9960 	xmlNodePtr child = NULL;
9961 
9962 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
9963 		scfdie();
9964 
9965 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
9966 		telts->common_name = export_tm_loctext(pg, "common_name");
9967 		if (telts->common_name == NULL)
9968 			export_pg(pg, elts, 0);
9969 		return;
9970 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
9971 		telts->description = export_tm_loctext(pg, "description");
9972 		if (telts->description == NULL)
9973 			export_pg(pg, elts, 0);
9974 		return;
9975 	}
9976 
9977 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
9978 		child = export_tm_manpage(pg);
9979 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
9980 		child = export_tm_doc_link(pg);
9981 	}
9982 
9983 	if (child != NULL) {
9984 		make_node(&telts->documentation, "documentation");
9985 		(void) xmlAddChild(telts->documentation, child);
9986 	} else {
9987 		export_pg(pg, elts, 0);
9988 	}
9989 }
9990 
9991 /*
9992  * Process the general property group for an instance.
9993  */
9994 static void
9995 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
9996     struct entity_elts *elts)
9997 {
9998 	uint8_t enabled;
9999 	struct pg_elts pgelts;
10000 	int ret;
10001 
10002 	/* enabled */
10003 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10004 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10005 	    prop_get_val(exp_prop, exp_val) == 0) {
10006 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10007 			scfdie();
10008 	} else {
10009 		enabled = 0;
10010 	}
10011 
10012 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10013 
10014 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10015 		scfdie();
10016 
10017 	(void) memset(&pgelts, 0, sizeof (pgelts));
10018 
10019 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10020 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10021 			scfdie();
10022 
10023 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10024 			continue;
10025 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10026 			xmlNodePtr rnode, sfnode;
10027 
10028 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10029 			if (rnode == NULL)
10030 				uu_die(emsg_create_xml);
10031 
10032 			sfnode = xmlNewChild(rnode, NULL,
10033 			    (xmlChar *)"service_fmri", NULL);
10034 			if (sfnode == NULL)
10035 				uu_die(emsg_create_xml);
10036 
10037 			if (set_attr_from_prop(exp_prop, sfnode,
10038 			    value_attr) == 0) {
10039 				elts->restarter = rnode;
10040 				continue;
10041 			}
10042 
10043 			xmlFreeNode(rnode);
10044 		}
10045 
10046 		export_property(exp_prop, exp_str, &pgelts, 0);
10047 	}
10048 	if (ret == -1)
10049 		scfdie();
10050 
10051 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10052 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10053 		    elts);
10054 }
10055 
10056 /*
10057  * Put an instance element for the given instance into selts.
10058  */
10059 static void
10060 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10061 {
10062 	xmlNodePtr n;
10063 	boolean_t isdefault;
10064 	struct entity_elts elts;
10065 	struct template_elts template_elts;
10066 	int ret;
10067 
10068 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10069 	if (n == NULL)
10070 		uu_die(emsg_create_xml);
10071 
10072 	/* name */
10073 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10074 		scfdie();
10075 	safe_setprop(n, name_attr, exp_str);
10076 	isdefault = strcmp(exp_str, "default") == 0;
10077 
10078 	/* check existance of general pg (since general/enabled is required) */
10079 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10080 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10081 			scfdie();
10082 
10083 		if (g_verbose) {
10084 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10085 				scfdie();
10086 
10087 			warn(gettext("Instance %s has no general property "
10088 			    "group; it will be marked disabled.\n"), exp_str);
10089 		}
10090 
10091 		safe_setprop(n, enabled_attr, false);
10092 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10093 	    strcmp(exp_str, scf_group_framework) != 0) {
10094 		if (g_verbose) {
10095 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10096 				scfdie();
10097 
10098 			warn(gettext("Property group %s is not of type "
10099 			    "framework; the instance will be marked "
10100 			    "disabled.\n"), exp_str);
10101 		}
10102 
10103 		safe_setprop(n, enabled_attr, false);
10104 	}
10105 
10106 	/* property groups */
10107 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10108 		scfdie();
10109 
10110 	(void) memset(&elts, 0, sizeof (elts));
10111 	(void) memset(&template_elts, 0, sizeof (template_elts));
10112 
10113 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10114 		uint32_t pgflags;
10115 
10116 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10117 			scfdie();
10118 
10119 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10120 			continue;
10121 
10122 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10123 			scfdie();
10124 
10125 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10126 			export_dependency(exp_pg, &elts);
10127 			continue;
10128 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10129 			export_method(exp_pg, &elts);
10130 			continue;
10131 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10132 			if (scf_pg_get_name(exp_pg, exp_str,
10133 			    max_scf_name_len + 1) < 0)
10134 				scfdie();
10135 
10136 			if (strcmp(exp_str, scf_pg_general) == 0) {
10137 				export_inst_general(exp_pg, n, &elts);
10138 				continue;
10139 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10140 			    0) {
10141 				export_method_context(exp_pg, &elts);
10142 				continue;
10143 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10144 				export_dependents(exp_pg, &elts);
10145 				continue;
10146 			}
10147 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10148 			export_template(exp_pg, &elts, &template_elts);
10149 			continue;
10150 		}
10151 
10152 		/* Ordinary pg. */
10153 		export_pg(exp_pg, &elts, flags);
10154 	}
10155 	if (ret == -1)
10156 		scfdie();
10157 
10158 	if (template_elts.common_name != NULL) {
10159 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10160 		(void) xmlAddChild(elts.template, template_elts.common_name);
10161 		(void) xmlAddChild(elts.template, template_elts.description);
10162 		(void) xmlAddChild(elts.template, template_elts.documentation);
10163 	} else {
10164 		xmlFreeNode(template_elts.description);
10165 		xmlFreeNode(template_elts.documentation);
10166 	}
10167 
10168 	if (isdefault && elts.restarter == NULL &&
10169 	    elts.dependencies == NULL && elts.method_context == NULL &&
10170 	    elts.exec_methods == NULL && elts.property_groups == NULL &&
10171 	    elts.template == NULL) {
10172 		xmlChar *eval;
10173 
10174 		/* This is a default instance */
10175 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10176 
10177 		xmlFreeNode(n);
10178 
10179 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10180 		if (n == NULL)
10181 			uu_die(emsg_create_xml);
10182 
10183 		safe_setprop(n, enabled_attr, (char *)eval);
10184 		xmlFree(eval);
10185 
10186 		selts->create_default_instance = n;
10187 	} else {
10188 		/* Assemble the children in order. */
10189 		(void) xmlAddChild(n, elts.restarter);
10190 		(void) xmlAddChildList(n, elts.dependencies);
10191 		(void) xmlAddChildList(n, elts.dependents);
10192 		(void) xmlAddChild(n, elts.method_context);
10193 		(void) xmlAddChildList(n, elts.exec_methods);
10194 		(void) xmlAddChildList(n, elts.property_groups);
10195 		(void) xmlAddChild(n, elts.template);
10196 
10197 		if (selts->instances == NULL)
10198 			selts->instances = n;
10199 		else
10200 			(void) xmlAddSibling(selts->instances, n);
10201 	}
10202 }
10203 
10204 /*
10205  * Return a service element for the given service.
10206  */
10207 static xmlNodePtr
10208 export_service(scf_service_t *svc, int flags)
10209 {
10210 	xmlNodePtr snode;
10211 	struct entity_elts elts;
10212 	struct template_elts template_elts;
10213 	int ret;
10214 
10215 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10216 	if (snode == NULL)
10217 		uu_die(emsg_create_xml);
10218 
10219 	/* Get & set name attribute */
10220 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10221 		scfdie();
10222 	safe_setprop(snode, name_attr, exp_str);
10223 
10224 	safe_setprop(snode, type_attr, "service");
10225 	safe_setprop(snode, "version", "0");
10226 
10227 	/* Acquire child elements. */
10228 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10229 		scfdie();
10230 
10231 	(void) memset(&elts, 0, sizeof (elts));
10232 	(void) memset(&template_elts, 0, sizeof (template_elts));
10233 
10234 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10235 		uint32_t pgflags;
10236 
10237 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10238 			scfdie();
10239 
10240 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10241 			continue;
10242 
10243 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10244 			scfdie();
10245 
10246 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10247 			export_dependency(exp_pg, &elts);
10248 			continue;
10249 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10250 			export_method(exp_pg, &elts);
10251 			continue;
10252 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10253 			if (scf_pg_get_name(exp_pg, exp_str,
10254 			    max_scf_name_len + 1) < 0)
10255 				scfdie();
10256 
10257 			if (strcmp(exp_str, scf_pg_general) == 0) {
10258 				export_svc_general(exp_pg, &elts);
10259 				continue;
10260 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10261 			    0) {
10262 				export_method_context(exp_pg, &elts);
10263 				continue;
10264 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10265 				export_dependents(exp_pg, &elts);
10266 				continue;
10267 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10268 				continue;
10269 			}
10270 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10271 			export_template(exp_pg, &elts, &template_elts);
10272 			continue;
10273 		}
10274 
10275 		export_pg(exp_pg, &elts, flags);
10276 	}
10277 	if (ret == -1)
10278 		scfdie();
10279 
10280 	if (template_elts.common_name != NULL) {
10281 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10282 		(void) xmlAddChild(elts.template, template_elts.common_name);
10283 		(void) xmlAddChild(elts.template, template_elts.description);
10284 		(void) xmlAddChild(elts.template, template_elts.documentation);
10285 	} else {
10286 		xmlFreeNode(template_elts.description);
10287 		xmlFreeNode(template_elts.documentation);
10288 	}
10289 
10290 	/* Iterate instances */
10291 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10292 		scfdie();
10293 
10294 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10295 		export_instance(exp_inst, &elts, flags);
10296 	if (ret == -1)
10297 		scfdie();
10298 
10299 	/* Now add all of the accumulated elements in order. */
10300 	(void) xmlAddChild(snode, elts.create_default_instance);
10301 	(void) xmlAddChild(snode, elts.single_instance);
10302 	(void) xmlAddChild(snode, elts.restarter);
10303 	(void) xmlAddChildList(snode, elts.dependencies);
10304 	(void) xmlAddChildList(snode, elts.dependents);
10305 	(void) xmlAddChild(snode, elts.method_context);
10306 	(void) xmlAddChildList(snode, elts.exec_methods);
10307 	(void) xmlAddChildList(snode, elts.property_groups);
10308 	(void) xmlAddChildList(snode, elts.instances);
10309 	(void) xmlAddChild(snode, elts.stability);
10310 	(void) xmlAddChild(snode, elts.template);
10311 
10312 	return (snode);
10313 }
10314 
10315 static int
10316 export_callback(void *data, scf_walkinfo_t *wip)
10317 {
10318 	FILE *f;
10319 	xmlDocPtr doc;
10320 	xmlNodePtr sb;
10321 	int result;
10322 	struct export_args *argsp = (struct export_args *)data;
10323 
10324 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10325 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10326 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10327 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10328 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10329 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10330 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10331 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10332 		scfdie();
10333 
10334 	exp_str_sz = max_scf_len + 1;
10335 	exp_str = safe_malloc(exp_str_sz);
10336 
10337 	if (argsp->filename != NULL) {
10338 		errno = 0;
10339 		f = fopen(argsp->filename, "wb");
10340 		if (f == NULL) {
10341 			if (errno == 0)
10342 				uu_die(gettext("Could not open \"%s\": no free "
10343 				    "stdio streams.\n"), argsp->filename);
10344 			else
10345 				uu_die(gettext("Could not open \"%s\""),
10346 				    argsp->filename);
10347 		}
10348 	} else
10349 		f = stdout;
10350 
10351 	doc = xmlNewDoc((xmlChar *)"1.0");
10352 	if (doc == NULL)
10353 		uu_die(gettext("Could not create XML document.\n"));
10354 
10355 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10356 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10357 		uu_die(emsg_create_xml);
10358 
10359 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10360 	if (sb == NULL)
10361 		uu_die(emsg_create_xml);
10362 	safe_setprop(sb, type_attr, "manifest");
10363 	safe_setprop(sb, name_attr, "export");
10364 	(void) xmlAddSibling(doc->children, sb);
10365 
10366 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10367 
10368 	result = write_service_bundle(doc, f);
10369 
10370 	free(exp_str);
10371 	scf_iter_destroy(exp_val_iter);
10372 	scf_iter_destroy(exp_prop_iter);
10373 	scf_iter_destroy(exp_pg_iter);
10374 	scf_iter_destroy(exp_inst_iter);
10375 	scf_value_destroy(exp_val);
10376 	scf_property_destroy(exp_prop);
10377 	scf_pg_destroy(exp_pg);
10378 	scf_instance_destroy(exp_inst);
10379 
10380 	xmlFreeDoc(doc);
10381 
10382 	if (f != stdout)
10383 		(void) fclose(f);
10384 
10385 	return (result);
10386 }
10387 
10388 /*
10389  * Get the service named by fmri, build an XML tree which represents it, and
10390  * dump it into filename (or stdout if filename is NULL).
10391  */
10392 int
10393 lscf_service_export(char *fmri, const char *filename, int flags)
10394 {
10395 	struct export_args args;
10396 	int ret, err;
10397 
10398 	lscf_prep_hndl();
10399 
10400 	bzero(&args, sizeof (args));
10401 	args.filename = filename;
10402 	args.flags = flags;
10403 
10404 	err = 0;
10405 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10406 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10407 	    &args, &err, semerr)) != 0) {
10408 		if (ret != -1)
10409 			semerr(gettext("Failed to walk instances: %s\n"),
10410 			    scf_strerror(ret));
10411 		return (-1);
10412 	}
10413 
10414 	/*
10415 	 * Error message has already been printed.
10416 	 */
10417 	if (err != 0)
10418 		return (-1);
10419 
10420 	return (0);
10421 }
10422 
10423 
10424 /*
10425  * Archive
10426  */
10427 
10428 static xmlNodePtr
10429 make_archive(int flags)
10430 {
10431 	xmlNodePtr sb;
10432 	scf_scope_t *scope;
10433 	scf_service_t *svc;
10434 	scf_iter_t *iter;
10435 	int r;
10436 
10437 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10438 	    (svc = scf_service_create(g_hndl)) == NULL ||
10439 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10440 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10441 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10442 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10443 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10444 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10445 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10446 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10447 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10448 		scfdie();
10449 
10450 	exp_str_sz = max_scf_len + 1;
10451 	exp_str = safe_malloc(exp_str_sz);
10452 
10453 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10454 	if (sb == NULL)
10455 		uu_die(emsg_create_xml);
10456 	safe_setprop(sb, type_attr, "archive");
10457 	safe_setprop(sb, name_attr, "none");
10458 
10459 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10460 		scfdie();
10461 	if (scf_iter_scope_services(iter, scope) != 0)
10462 		scfdie();
10463 
10464 	for (;;) {
10465 		r = scf_iter_next_service(iter, svc);
10466 		if (r == 0)
10467 			break;
10468 		if (r != 1)
10469 			scfdie();
10470 
10471 		if (scf_service_get_name(svc, exp_str,
10472 		    max_scf_name_len + 1) < 0)
10473 			scfdie();
10474 
10475 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10476 			continue;
10477 
10478 		(void) xmlAddChild(sb, export_service(svc, flags));
10479 	}
10480 
10481 	free(exp_str);
10482 
10483 	scf_iter_destroy(exp_val_iter);
10484 	scf_iter_destroy(exp_prop_iter);
10485 	scf_iter_destroy(exp_pg_iter);
10486 	scf_iter_destroy(exp_inst_iter);
10487 	scf_value_destroy(exp_val);
10488 	scf_property_destroy(exp_prop);
10489 	scf_pg_destroy(exp_pg);
10490 	scf_instance_destroy(exp_inst);
10491 	scf_iter_destroy(iter);
10492 	scf_service_destroy(svc);
10493 	scf_scope_destroy(scope);
10494 
10495 	return (sb);
10496 }
10497 
10498 int
10499 lscf_archive(const char *filename, int flags)
10500 {
10501 	FILE *f;
10502 	xmlDocPtr doc;
10503 	int result;
10504 
10505 	lscf_prep_hndl();
10506 
10507 	if (filename != NULL) {
10508 		errno = 0;
10509 		f = fopen(filename, "wb");
10510 		if (f == NULL) {
10511 			if (errno == 0)
10512 				uu_die(gettext("Could not open \"%s\": no free "
10513 				    "stdio streams.\n"), filename);
10514 			else
10515 				uu_die(gettext("Could not open \"%s\""),
10516 				    filename);
10517 		}
10518 	} else
10519 		f = stdout;
10520 
10521 	doc = xmlNewDoc((xmlChar *)"1.0");
10522 	if (doc == NULL)
10523 		uu_die(gettext("Could not create XML document.\n"));
10524 
10525 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10526 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10527 		uu_die(emsg_create_xml);
10528 
10529 	(void) xmlAddSibling(doc->children, make_archive(flags));
10530 
10531 	result = write_service_bundle(doc, f);
10532 
10533 	xmlFreeDoc(doc);
10534 
10535 	if (f != stdout)
10536 		(void) fclose(f);
10537 
10538 	return (result);
10539 }
10540 
10541 
10542 /*
10543  * "Extract" a profile.
10544  */
10545 int
10546 lscf_profile_extract(const char *filename)
10547 {
10548 	FILE *f;
10549 	xmlDocPtr doc;
10550 	xmlNodePtr sb, snode, inode;
10551 	scf_scope_t *scope;
10552 	scf_service_t *svc;
10553 	scf_instance_t *inst;
10554 	scf_propertygroup_t *pg;
10555 	scf_property_t *prop;
10556 	scf_value_t *val;
10557 	scf_iter_t *siter, *iiter;
10558 	int r, s;
10559 	char *namebuf;
10560 	uint8_t b;
10561 	int result;
10562 
10563 	lscf_prep_hndl();
10564 
10565 	if (filename != NULL) {
10566 		errno = 0;
10567 		f = fopen(filename, "wb");
10568 		if (f == NULL) {
10569 			if (errno == 0)
10570 				uu_die(gettext("Could not open \"%s\": no "
10571 				    "free stdio streams.\n"), filename);
10572 			else
10573 				uu_die(gettext("Could not open \"%s\""),
10574 				    filename);
10575 		}
10576 	} else
10577 		f = stdout;
10578 
10579 	doc = xmlNewDoc((xmlChar *)"1.0");
10580 	if (doc == NULL)
10581 		uu_die(gettext("Could not create XML document.\n"));
10582 
10583 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10584 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10585 		uu_die(emsg_create_xml);
10586 
10587 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10588 	if (sb == NULL)
10589 		uu_die(emsg_create_xml);
10590 	safe_setprop(sb, type_attr, "profile");
10591 	safe_setprop(sb, name_attr, "extract");
10592 	(void) xmlAddSibling(doc->children, sb);
10593 
10594 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10595 	    (svc = scf_service_create(g_hndl)) == NULL ||
10596 	    (inst = scf_instance_create(g_hndl)) == NULL ||
10597 	    (pg = scf_pg_create(g_hndl)) == NULL ||
10598 	    (prop = scf_property_create(g_hndl)) == NULL ||
10599 	    (val = scf_value_create(g_hndl)) == NULL ||
10600 	    (siter = scf_iter_create(g_hndl)) == NULL ||
10601 	    (iiter = scf_iter_create(g_hndl)) == NULL)
10602 		scfdie();
10603 
10604 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
10605 		scfdie();
10606 
10607 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
10608 		scfdie();
10609 
10610 	namebuf = safe_malloc(max_scf_name_len + 1);
10611 
10612 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
10613 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
10614 			scfdie();
10615 
10616 		snode = xmlNewNode(NULL, (xmlChar *)"service");
10617 		if (snode == NULL)
10618 			uu_die(emsg_create_xml);
10619 
10620 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
10621 		    0)
10622 			scfdie();
10623 
10624 		safe_setprop(snode, name_attr, namebuf);
10625 
10626 		safe_setprop(snode, type_attr, "service");
10627 		safe_setprop(snode, "version", "0");
10628 
10629 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
10630 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
10631 			    SCF_SUCCESS) {
10632 				if (scf_error() != SCF_ERROR_NOT_FOUND)
10633 					scfdie();
10634 
10635 				if (g_verbose) {
10636 					ssize_t len;
10637 					char *fmri;
10638 
10639 					len =
10640 					    scf_instance_to_fmri(inst, NULL, 0);
10641 					if (len < 0)
10642 						scfdie();
10643 
10644 					fmri = safe_malloc(len + 1);
10645 
10646 					if (scf_instance_to_fmri(inst, fmri,
10647 					    len + 1) < 0)
10648 						scfdie();
10649 
10650 					warn("Instance %s has no \"%s\" "
10651 					    "property group.\n", fmri,
10652 					    scf_pg_general);
10653 
10654 					free(fmri);
10655 				}
10656 
10657 				continue;
10658 			}
10659 
10660 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
10661 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
10662 			    prop_get_val(prop, val) != 0)
10663 				continue;
10664 
10665 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
10666 			    NULL);
10667 			if (inode == NULL)
10668 				uu_die(emsg_create_xml);
10669 
10670 			if (scf_instance_get_name(inst, namebuf,
10671 			    max_scf_name_len + 1) < 0)
10672 				scfdie();
10673 
10674 			safe_setprop(inode, name_attr, namebuf);
10675 
10676 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
10677 				scfdie();
10678 
10679 			safe_setprop(inode, enabled_attr, b ? true : false);
10680 		}
10681 		if (s < 0)
10682 			scfdie();
10683 
10684 		if (snode->children != NULL)
10685 			(void) xmlAddChild(sb, snode);
10686 		else
10687 			xmlFreeNode(snode);
10688 	}
10689 	if (r < 0)
10690 		scfdie();
10691 
10692 	free(namebuf);
10693 
10694 	result = write_service_bundle(doc, f);
10695 
10696 	xmlFreeDoc(doc);
10697 
10698 	if (f != stdout)
10699 		(void) fclose(f);
10700 
10701 	return (result);
10702 }
10703 
10704 
10705 /*
10706  * Entity manipulation commands
10707  */
10708 
10709 /*
10710  * Entity selection.  If no entity is selected, then the current scope is in
10711  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
10712  * only cur_inst is NULL, and when an instance is selected, none are NULL.
10713  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
10714  * cur_inst will be non-NULL.
10715  */
10716 
10717 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
10718 static int
10719 select_inst(const char *name)
10720 {
10721 	scf_instance_t *inst;
10722 	scf_error_t err;
10723 
10724 	assert(cur_svc != NULL);
10725 
10726 	inst = scf_instance_create(g_hndl);
10727 	if (inst == NULL)
10728 		scfdie();
10729 
10730 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10731 		cur_inst = inst;
10732 		return (0);
10733 	}
10734 
10735 	err = scf_error();
10736 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10737 		scfdie();
10738 
10739 	scf_instance_destroy(inst);
10740 	return (1);
10741 }
10742 
10743 /* Returns as above. */
10744 static int
10745 select_svc(const char *name)
10746 {
10747 	scf_service_t *svc;
10748 	scf_error_t err;
10749 
10750 	assert(cur_scope != NULL);
10751 
10752 	svc = scf_service_create(g_hndl);
10753 	if (svc == NULL)
10754 		scfdie();
10755 
10756 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10757 		cur_svc = svc;
10758 		return (0);
10759 	}
10760 
10761 	err = scf_error();
10762 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10763 		scfdie();
10764 
10765 	scf_service_destroy(svc);
10766 	return (1);
10767 }
10768 
10769 /* ARGSUSED */
10770 static int
10771 select_callback(void *unused, scf_walkinfo_t *wip)
10772 {
10773 	scf_instance_t *inst;
10774 	scf_service_t *svc;
10775 	scf_scope_t *scope;
10776 
10777 	if (wip->inst != NULL) {
10778 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10779 		    (svc = scf_service_create(g_hndl)) == NULL ||
10780 		    (inst = scf_instance_create(g_hndl)) == NULL)
10781 			scfdie();
10782 
10783 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10784 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10785 			scfdie();
10786 	} else {
10787 		assert(wip->svc != NULL);
10788 
10789 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10790 		    (svc = scf_service_create(g_hndl)) == NULL)
10791 			scfdie();
10792 
10793 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10794 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10795 			scfdie();
10796 
10797 		inst = NULL;
10798 	}
10799 
10800 	/* Clear out the current selection */
10801 	assert(cur_scope != NULL);
10802 	scf_scope_destroy(cur_scope);
10803 	scf_service_destroy(cur_svc);
10804 	scf_instance_destroy(cur_inst);
10805 
10806 	cur_scope = scope;
10807 	cur_svc = svc;
10808 	cur_inst = inst;
10809 
10810 	return (0);
10811 }
10812 
10813 static int
10814 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
10815 {
10816 	char **fmri = fmri_p;
10817 
10818 	*fmri = strdup(wip->fmri);
10819 	if (*fmri == NULL)
10820 		uu_die(gettext("Out of memory.\n"));
10821 
10822 	return (0);
10823 }
10824 
10825 /*
10826  * validate [fmri]
10827  * Perform the validation of an FMRI instance.
10828  */
10829 void
10830 lscf_validate_fmri(const char *fmri)
10831 {
10832 	int ret = 0;
10833 	size_t inst_sz;
10834 	char *inst_fmri = NULL;
10835 	scf_tmpl_errors_t *errs = NULL;
10836 	char *snapbuf = NULL;
10837 
10838 	lscf_prep_hndl();
10839 
10840 	if (fmri == NULL) {
10841 		inst_sz = max_scf_fmri_len + 1;
10842 		inst_fmri = safe_malloc(inst_sz);
10843 
10844 		if (cur_snap != NULL) {
10845 			snapbuf = safe_malloc(max_scf_name_len + 1);
10846 			if (scf_snapshot_get_name(cur_snap, snapbuf,
10847 			    max_scf_name_len + 1) < 0)
10848 				scfdie();
10849 		}
10850 		if (cur_inst == NULL) {
10851 			semerr(gettext("No instance selected\n"));
10852 			goto cleanup;
10853 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
10854 		    inst_sz) >= inst_sz) {
10855 			/* sanity check. Should never get here */
10856 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
10857 			    __FILE__, __LINE__);
10858 		}
10859 	} else {
10860 		scf_error_t scf_err;
10861 		int err = 0;
10862 
10863 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
10864 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
10865 			uu_warn("Failed to walk instances: %s\n",
10866 			    scf_strerror(scf_err));
10867 			goto cleanup;
10868 		}
10869 		if (err != 0) {
10870 			/* error message displayed by scf_walk_fmri */
10871 			goto cleanup;
10872 		}
10873 	}
10874 
10875 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
10876 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
10877 	if (ret == -1) {
10878 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
10879 			warn(gettext("Template data for %s is invalid. "
10880 			    "Consider reverting to a previous snapshot or "
10881 			    "restoring original configuration.\n"), inst_fmri);
10882 		} else {
10883 			uu_warn("%s: %s\n",
10884 			    gettext("Error validating the instance"),
10885 			    scf_strerror(scf_error()));
10886 		}
10887 	} else if (ret == 1 && errs != NULL) {
10888 		scf_tmpl_error_t *err = NULL;
10889 		char *msg;
10890 		size_t len = 256;	/* initial error buffer size */
10891 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
10892 		    SCF_TMPL_STRERROR_HUMAN : 0;
10893 
10894 		msg = safe_malloc(len);
10895 
10896 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
10897 			int ret;
10898 
10899 			if ((ret = scf_tmpl_strerror(err, msg, len,
10900 			    flag)) >= len) {
10901 				len = ret + 1;
10902 				msg = realloc(msg, len);
10903 				if (msg == NULL)
10904 					uu_die(gettext(
10905 					    "Out of memory.\n"));
10906 				(void) scf_tmpl_strerror(err, msg, len,
10907 				    flag);
10908 			}
10909 			(void) fprintf(stderr, "%s\n", msg);
10910 		}
10911 		if (msg != NULL)
10912 			free(msg);
10913 	}
10914 	if (errs != NULL)
10915 		scf_tmpl_errors_destroy(errs);
10916 
10917 cleanup:
10918 	free(inst_fmri);
10919 	free(snapbuf);
10920 }
10921 
10922 static void
10923 lscf_validate_file(const char *filename)
10924 {
10925 	tmpl_errors_t *errs;
10926 
10927 	bundle_t *b = internal_bundle_new();
10928 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
10929 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
10930 			tmpl_errors_print(stderr, errs, "");
10931 			semerr(gettext("Validation failed.\n"));
10932 		}
10933 		tmpl_errors_destroy(errs);
10934 	}
10935 	(void) internal_bundle_free(b);
10936 }
10937 
10938 /*
10939  * validate [fmri|file]
10940  */
10941 void
10942 lscf_validate(const char *arg)
10943 {
10944 	const char *str;
10945 
10946 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
10947 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
10948 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
10949 		lscf_validate_file(str);
10950 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
10951 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
10952 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
10953 		lscf_validate_fmri(str);
10954 	} else if (access(arg, R_OK | F_OK) == 0) {
10955 		lscf_validate_file(arg);
10956 	} else {
10957 		lscf_validate_fmri(arg);
10958 	}
10959 }
10960 
10961 void
10962 lscf_select(const char *fmri)
10963 {
10964 	int ret, err;
10965 
10966 	lscf_prep_hndl();
10967 
10968 	if (cur_snap != NULL) {
10969 		struct snaplevel *elt;
10970 		char *buf;
10971 
10972 		/* Error unless name is that of the next level. */
10973 		elt = uu_list_next(cur_levels, cur_elt);
10974 		if (elt == NULL) {
10975 			semerr(gettext("No children.\n"));
10976 			return;
10977 		}
10978 
10979 		buf = safe_malloc(max_scf_name_len + 1);
10980 
10981 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10982 		    max_scf_name_len + 1) < 0)
10983 			scfdie();
10984 
10985 		if (strcmp(buf, fmri) != 0) {
10986 			semerr(gettext("No such child.\n"));
10987 			free(buf);
10988 			return;
10989 		}
10990 
10991 		free(buf);
10992 
10993 		cur_elt = elt;
10994 		cur_level = elt->sl;
10995 		return;
10996 	}
10997 
10998 	/*
10999 	 * Special case for 'svc:', which takes the user to the scope level.
11000 	 */
11001 	if (strcmp(fmri, "svc:") == 0) {
11002 		scf_instance_destroy(cur_inst);
11003 		scf_service_destroy(cur_svc);
11004 		cur_inst = NULL;
11005 		cur_svc = NULL;
11006 		return;
11007 	}
11008 
11009 	/*
11010 	 * Special case for ':properties'.  This appears as part of 'list' but
11011 	 * can't be selected.  Give a more helpful error message in this case.
11012 	 */
11013 	if (strcmp(fmri, ":properties") == 0) {
11014 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11015 		    "to list properties.\n"));
11016 		return;
11017 	}
11018 
11019 	/*
11020 	 * First try the argument as relative to the current selection.
11021 	 */
11022 	if (cur_inst != NULL) {
11023 		/* EMPTY */;
11024 	} else if (cur_svc != NULL) {
11025 		if (select_inst(fmri) != 1)
11026 			return;
11027 	} else {
11028 		if (select_svc(fmri) != 1)
11029 			return;
11030 	}
11031 
11032 	err = 0;
11033 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11034 	    select_callback, NULL, &err, semerr)) != 0) {
11035 		semerr(gettext("Failed to walk instances: %s\n"),
11036 		    scf_strerror(ret));
11037 	}
11038 }
11039 
11040 void
11041 lscf_unselect(void)
11042 {
11043 	lscf_prep_hndl();
11044 
11045 	if (cur_snap != NULL) {
11046 		struct snaplevel *elt;
11047 
11048 		elt = uu_list_prev(cur_levels, cur_elt);
11049 		if (elt == NULL) {
11050 			semerr(gettext("No parent levels.\n"));
11051 		} else {
11052 			cur_elt = elt;
11053 			cur_level = elt->sl;
11054 		}
11055 	} else if (cur_inst != NULL) {
11056 		scf_instance_destroy(cur_inst);
11057 		cur_inst = NULL;
11058 	} else if (cur_svc != NULL) {
11059 		scf_service_destroy(cur_svc);
11060 		cur_svc = NULL;
11061 	} else {
11062 		semerr(gettext("Cannot unselect at scope level.\n"));
11063 	}
11064 }
11065 
11066 /*
11067  * Return the FMRI of the current selection, for the prompt.
11068  */
11069 void
11070 lscf_get_selection_str(char *buf, size_t bufsz)
11071 {
11072 	char *cp;
11073 	ssize_t fmrilen, szret;
11074 	boolean_t deleted = B_FALSE;
11075 
11076 	if (g_hndl == NULL) {
11077 		(void) strlcpy(buf, "svc:", bufsz);
11078 		return;
11079 	}
11080 
11081 	if (cur_level != NULL) {
11082 		assert(cur_snap != NULL);
11083 
11084 		/* [ snapshot ] FMRI [: instance ] */
11085 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11086 		    + 2 + max_scf_name_len + 1 + 1);
11087 
11088 		buf[0] = '[';
11089 
11090 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11091 		    max_scf_name_len + 1);
11092 		if (szret < 0) {
11093 			if (scf_error() != SCF_ERROR_DELETED)
11094 				scfdie();
11095 
11096 			goto snap_deleted;
11097 		}
11098 
11099 		(void) strcat(buf, "]svc:/");
11100 
11101 		cp = strchr(buf, '\0');
11102 
11103 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11104 		    max_scf_name_len + 1);
11105 		if (szret < 0) {
11106 			if (scf_error() != SCF_ERROR_DELETED)
11107 				scfdie();
11108 
11109 			goto snap_deleted;
11110 		}
11111 
11112 		cp = strchr(cp, '\0');
11113 
11114 		if (snaplevel_is_instance(cur_level)) {
11115 			*cp++ = ':';
11116 
11117 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11118 			    max_scf_name_len + 1) < 0) {
11119 				if (scf_error() != SCF_ERROR_DELETED)
11120 					scfdie();
11121 
11122 				goto snap_deleted;
11123 			}
11124 		} else {
11125 			*cp++ = '[';
11126 			*cp++ = ':';
11127 
11128 			if (scf_instance_get_name(cur_inst, cp,
11129 			    max_scf_name_len + 1) < 0) {
11130 				if (scf_error() != SCF_ERROR_DELETED)
11131 					scfdie();
11132 
11133 				goto snap_deleted;
11134 			}
11135 
11136 			(void) strcat(buf, "]");
11137 		}
11138 
11139 		return;
11140 
11141 snap_deleted:
11142 		deleted = B_TRUE;
11143 		free(buf);
11144 		unselect_cursnap();
11145 	}
11146 
11147 	assert(cur_snap == NULL);
11148 
11149 	if (cur_inst != NULL) {
11150 		assert(cur_svc != NULL);
11151 		assert(cur_scope != NULL);
11152 
11153 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11154 		if (fmrilen >= 0) {
11155 			assert(fmrilen < bufsz);
11156 			if (deleted)
11157 				warn(emsg_deleted);
11158 			return;
11159 		}
11160 
11161 		if (scf_error() != SCF_ERROR_DELETED)
11162 			scfdie();
11163 
11164 		deleted = B_TRUE;
11165 
11166 		scf_instance_destroy(cur_inst);
11167 		cur_inst = NULL;
11168 	}
11169 
11170 	if (cur_svc != NULL) {
11171 		assert(cur_scope != NULL);
11172 
11173 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11174 		if (szret >= 0) {
11175 			assert(szret < bufsz);
11176 			if (deleted)
11177 				warn(emsg_deleted);
11178 			return;
11179 		}
11180 
11181 		if (scf_error() != SCF_ERROR_DELETED)
11182 			scfdie();
11183 
11184 		deleted = B_TRUE;
11185 		scf_service_destroy(cur_svc);
11186 		cur_svc = NULL;
11187 	}
11188 
11189 	assert(cur_scope != NULL);
11190 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11191 
11192 	if (fmrilen < 0)
11193 		scfdie();
11194 
11195 	assert(fmrilen < bufsz);
11196 	if (deleted)
11197 		warn(emsg_deleted);
11198 }
11199 
11200 /*
11201  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11202  * :statistics) are listed for the current selection.
11203  */
11204 void
11205 lscf_list(const char *pattern)
11206 {
11207 	scf_iter_t *iter;
11208 	char *buf;
11209 	int ret;
11210 
11211 	lscf_prep_hndl();
11212 
11213 	if (cur_level != NULL) {
11214 		struct snaplevel *elt;
11215 
11216 		(void) fputs(COLON_NAMESPACES, stdout);
11217 
11218 		elt = uu_list_next(cur_levels, cur_elt);
11219 		if (elt == NULL)
11220 			return;
11221 
11222 		/*
11223 		 * For now, we know that the next level is an instance.  But
11224 		 * if we ever have multiple scopes, this could be complicated.
11225 		 */
11226 		buf = safe_malloc(max_scf_name_len + 1);
11227 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11228 		    max_scf_name_len + 1) >= 0) {
11229 			(void) puts(buf);
11230 		} else {
11231 			if (scf_error() != SCF_ERROR_DELETED)
11232 				scfdie();
11233 		}
11234 
11235 		free(buf);
11236 
11237 		return;
11238 	}
11239 
11240 	if (cur_inst != NULL) {
11241 		(void) fputs(COLON_NAMESPACES, stdout);
11242 		return;
11243 	}
11244 
11245 	iter = scf_iter_create(g_hndl);
11246 	if (iter == NULL)
11247 		scfdie();
11248 
11249 	buf = safe_malloc(max_scf_name_len + 1);
11250 
11251 	if (cur_svc != NULL) {
11252 		/* List the instances in this service. */
11253 		scf_instance_t *inst;
11254 
11255 		inst = scf_instance_create(g_hndl);
11256 		if (inst == NULL)
11257 			scfdie();
11258 
11259 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11260 			safe_printf(COLON_NAMESPACES);
11261 
11262 			for (;;) {
11263 				ret = scf_iter_next_instance(iter, inst);
11264 				if (ret == 0)
11265 					break;
11266 				if (ret != 1) {
11267 					if (scf_error() != SCF_ERROR_DELETED)
11268 						scfdie();
11269 
11270 					break;
11271 				}
11272 
11273 				if (scf_instance_get_name(inst, buf,
11274 				    max_scf_name_len + 1) >= 0) {
11275 					if (pattern == NULL ||
11276 					    fnmatch(pattern, buf, 0) == 0)
11277 						(void) puts(buf);
11278 				} else {
11279 					if (scf_error() != SCF_ERROR_DELETED)
11280 						scfdie();
11281 				}
11282 			}
11283 		} else {
11284 			if (scf_error() != SCF_ERROR_DELETED)
11285 				scfdie();
11286 		}
11287 
11288 		scf_instance_destroy(inst);
11289 	} else {
11290 		/* List the services in this scope. */
11291 		scf_service_t *svc;
11292 
11293 		assert(cur_scope != NULL);
11294 
11295 		svc = scf_service_create(g_hndl);
11296 		if (svc == NULL)
11297 			scfdie();
11298 
11299 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11300 			scfdie();
11301 
11302 		for (;;) {
11303 			ret = scf_iter_next_service(iter, svc);
11304 			if (ret == 0)
11305 				break;
11306 			if (ret != 1)
11307 				scfdie();
11308 
11309 			if (scf_service_get_name(svc, buf,
11310 			    max_scf_name_len + 1) >= 0) {
11311 				if (pattern == NULL ||
11312 				    fnmatch(pattern, buf, 0) == 0)
11313 					safe_printf("%s\n", buf);
11314 			} else {
11315 				if (scf_error() != SCF_ERROR_DELETED)
11316 					scfdie();
11317 			}
11318 		}
11319 
11320 		scf_service_destroy(svc);
11321 	}
11322 
11323 	free(buf);
11324 	scf_iter_destroy(iter);
11325 }
11326 
11327 /*
11328  * Entity addition.  Creates an empty entity in the current selection.
11329  */
11330 void
11331 lscf_add(const char *name)
11332 {
11333 	lscf_prep_hndl();
11334 
11335 	if (cur_snap != NULL) {
11336 		semerr(emsg_cant_modify_snapshots);
11337 	} else if (cur_inst != NULL) {
11338 		semerr(gettext("Cannot add entities to an instance.\n"));
11339 	} else if (cur_svc != NULL) {
11340 
11341 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11342 		    SCF_SUCCESS) {
11343 			switch (scf_error()) {
11344 			case SCF_ERROR_INVALID_ARGUMENT:
11345 				semerr(gettext("Invalid name.\n"));
11346 				break;
11347 
11348 			case SCF_ERROR_EXISTS:
11349 				semerr(gettext("Instance already exists.\n"));
11350 				break;
11351 
11352 			case SCF_ERROR_PERMISSION_DENIED:
11353 				semerr(emsg_permission_denied);
11354 				break;
11355 
11356 			default:
11357 				scfdie();
11358 			}
11359 		}
11360 	} else {
11361 		assert(cur_scope != NULL);
11362 
11363 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11364 		    SCF_SUCCESS) {
11365 			switch (scf_error()) {
11366 			case SCF_ERROR_INVALID_ARGUMENT:
11367 				semerr(gettext("Invalid name.\n"));
11368 				break;
11369 
11370 			case SCF_ERROR_EXISTS:
11371 				semerr(gettext("Service already exists.\n"));
11372 				break;
11373 
11374 			case SCF_ERROR_PERMISSION_DENIED:
11375 				semerr(emsg_permission_denied);
11376 				break;
11377 
11378 			case SCF_ERROR_BACKEND_READONLY:
11379 				semerr(emsg_read_only);
11380 				break;
11381 
11382 			default:
11383 				scfdie();
11384 			}
11385 		}
11386 	}
11387 }
11388 
11389 /* return 1 if the entity has no persistent pgs, else return 0 */
11390 static int
11391 entity_has_no_pgs(void *ent, int isservice)
11392 {
11393 	scf_iter_t *iter = NULL;
11394 	scf_propertygroup_t *pg = NULL;
11395 	uint32_t flags;
11396 	int err;
11397 	int ret = 1;
11398 
11399 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11400 	    (pg = scf_pg_create(g_hndl)) == NULL)
11401 		scfdie();
11402 
11403 	if (isservice) {
11404 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11405 			scfdie();
11406 	} else {
11407 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11408 			scfdie();
11409 	}
11410 
11411 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11412 		if (scf_pg_get_flags(pg, &flags) != 0)
11413 			scfdie();
11414 
11415 		/* skip nonpersistent pgs */
11416 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11417 			continue;
11418 
11419 		ret = 0;
11420 		break;
11421 	}
11422 
11423 	if (err == -1)
11424 		scfdie();
11425 
11426 	scf_pg_destroy(pg);
11427 	scf_iter_destroy(iter);
11428 
11429 	return (ret);
11430 }
11431 
11432 /* return 1 if the service has no instances, else return 0 */
11433 static int
11434 svc_has_no_insts(scf_service_t *svc)
11435 {
11436 	scf_instance_t *inst;
11437 	scf_iter_t *iter;
11438 	int r;
11439 	int ret = 1;
11440 
11441 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11442 	    (iter = scf_iter_create(g_hndl)) == NULL)
11443 		scfdie();
11444 
11445 	if (scf_iter_service_instances(iter, svc) != 0)
11446 		scfdie();
11447 
11448 	r = scf_iter_next_instance(iter, inst);
11449 	if (r == 1) {
11450 		ret = 0;
11451 	} else if (r == 0) {
11452 		ret = 1;
11453 	} else if (r == -1) {
11454 		scfdie();
11455 	} else {
11456 		bad_error("scf_iter_next_instance", r);
11457 	}
11458 
11459 	scf_iter_destroy(iter);
11460 	scf_instance_destroy(inst);
11461 
11462 	return (ret);
11463 }
11464 
11465 /*
11466  * Entity deletion.
11467  */
11468 
11469 /*
11470  * Delete the property group <fmri>/:properties/<name>.  Returns
11471  * SCF_ERROR_NONE on success (or if the entity is not found),
11472  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11473  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11474  * denied.
11475  */
11476 static scf_error_t
11477 delete_dependency_pg(const char *fmri, const char *name)
11478 {
11479 	void *entity = NULL;
11480 	int isservice;
11481 	scf_propertygroup_t *pg = NULL;
11482 	scf_error_t result;
11483 	char *pgty;
11484 	scf_service_t *svc = NULL;
11485 	scf_instance_t *inst = NULL;
11486 	scf_iter_t *iter = NULL;
11487 	char *name_buf = NULL;
11488 
11489 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11490 	switch (result) {
11491 	case SCF_ERROR_NONE:
11492 		break;
11493 
11494 	case SCF_ERROR_NO_MEMORY:
11495 		uu_die(gettext("Out of memory.\n"));
11496 		/* NOTREACHED */
11497 
11498 	case SCF_ERROR_INVALID_ARGUMENT:
11499 	case SCF_ERROR_CONSTRAINT_VIOLATED:
11500 		return (SCF_ERROR_INVALID_ARGUMENT);
11501 
11502 	case SCF_ERROR_NOT_FOUND:
11503 		result = SCF_ERROR_NONE;
11504 		goto out;
11505 
11506 	default:
11507 		bad_error("fmri_to_entity", result);
11508 	}
11509 
11510 	pg = scf_pg_create(g_hndl);
11511 	if (pg == NULL)
11512 		scfdie();
11513 
11514 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
11515 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11516 			scfdie();
11517 
11518 		result = SCF_ERROR_NONE;
11519 		goto out;
11520 	}
11521 
11522 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11523 
11524 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11525 		scfdie();
11526 
11527 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
11528 		result = SCF_ERROR_TYPE_MISMATCH;
11529 		free(pgty);
11530 		goto out;
11531 	}
11532 
11533 	free(pgty);
11534 
11535 	if (scf_pg_delete(pg) != 0) {
11536 		result = scf_error();
11537 		if (result != SCF_ERROR_PERMISSION_DENIED)
11538 			scfdie();
11539 		goto out;
11540 	}
11541 
11542 	/*
11543 	 * We have to handle the case where we've just deleted the last
11544 	 * property group of a "dummy" entity (instance or service).
11545 	 * A "dummy" entity is an entity only present to hold an
11546 	 * external dependency.
11547 	 * So, in the case we deleted the last property group then we
11548 	 * can also delete the entity. If the entity is an instance then
11549 	 * we must verify if this was the last instance for the service
11550 	 * and if it is, we can also delete the service if it doesn't
11551 	 * have any property group either.
11552 	 */
11553 
11554 	result = SCF_ERROR_NONE;
11555 
11556 	if (isservice) {
11557 		svc = (scf_service_t *)entity;
11558 
11559 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
11560 		    (iter = scf_iter_create(g_hndl)) == NULL)
11561 			scfdie();
11562 
11563 		name_buf = safe_malloc(max_scf_name_len + 1);
11564 	} else {
11565 		inst = (scf_instance_t *)entity;
11566 	}
11567 
11568 	/*
11569 	 * If the entity is an instance and we've just deleted its last
11570 	 * property group then we should delete it.
11571 	 */
11572 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
11573 		/* find the service before deleting the inst. - needed later */
11574 		if ((svc = scf_service_create(g_hndl)) == NULL)
11575 			scfdie();
11576 
11577 		if (scf_instance_get_parent(inst, svc) != 0)
11578 			scfdie();
11579 
11580 		/* delete the instance */
11581 		if (scf_instance_delete(inst) != 0) {
11582 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11583 				scfdie();
11584 
11585 			result = SCF_ERROR_PERMISSION_DENIED;
11586 			goto out;
11587 		}
11588 		/* no need to refresh the instance */
11589 		inst = NULL;
11590 	}
11591 
11592 	/*
11593 	 * If the service has no more instances and pgs or we just deleted the
11594 	 * last instance and the service doesn't have anymore propery groups
11595 	 * then the service should be deleted.
11596 	 */
11597 	if (svc != NULL &&
11598 	    svc_has_no_insts(svc) &&
11599 	    entity_has_no_pgs((void *)svc, 1)) {
11600 		if (scf_service_delete(svc) == 0) {
11601 			if (isservice) {
11602 				/* no need to refresh the service */
11603 				svc = NULL;
11604 			}
11605 
11606 			goto out;
11607 		}
11608 
11609 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11610 			scfdie();
11611 
11612 		result = SCF_ERROR_PERMISSION_DENIED;
11613 	}
11614 
11615 	/* if the entity has not been deleted, refresh it */
11616 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
11617 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
11618 		    name_buf);
11619 	}
11620 
11621 out:
11622 	if (isservice && (inst != NULL && iter != NULL)) {
11623 		free(name_buf);
11624 		scf_iter_destroy(iter);
11625 		scf_instance_destroy(inst);
11626 	}
11627 
11628 	if (!isservice && svc != NULL) {
11629 		scf_service_destroy(svc);
11630 	}
11631 
11632 	scf_pg_destroy(pg);
11633 	if (entity != NULL)
11634 		entity_destroy(entity, isservice);
11635 
11636 	return (result);
11637 }
11638 
11639 static int
11640 delete_dependents(scf_propertygroup_t *pg)
11641 {
11642 	char *pgty, *name, *fmri;
11643 	scf_property_t *prop;
11644 	scf_value_t *val;
11645 	scf_iter_t *iter;
11646 	int r;
11647 	scf_error_t err;
11648 
11649 	/* Verify that the pg has the correct type. */
11650 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11651 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11652 		scfdie();
11653 
11654 	if (strcmp(pgty, scf_group_framework) != 0) {
11655 		if (g_verbose) {
11656 			fmri = safe_malloc(max_scf_fmri_len + 1);
11657 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
11658 				scfdie();
11659 
11660 			warn(gettext("Property group %s is not of expected "
11661 			    "type %s.\n"), fmri, scf_group_framework);
11662 
11663 			free(fmri);
11664 		}
11665 
11666 		free(pgty);
11667 		return (-1);
11668 	}
11669 
11670 	free(pgty);
11671 
11672 	/* map delete_dependency_pg onto the properties. */
11673 	if ((prop = scf_property_create(g_hndl)) == NULL ||
11674 	    (val = scf_value_create(g_hndl)) == NULL ||
11675 	    (iter = scf_iter_create(g_hndl)) == NULL)
11676 		scfdie();
11677 
11678 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
11679 		scfdie();
11680 
11681 	name = safe_malloc(max_scf_name_len + 1);
11682 	fmri = safe_malloc(max_scf_fmri_len + 2);
11683 
11684 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
11685 		scf_type_t ty;
11686 
11687 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
11688 			scfdie();
11689 
11690 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11691 			scfdie();
11692 
11693 		if ((ty != SCF_TYPE_ASTRING &&
11694 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
11695 		    prop_get_val(prop, val) != 0)
11696 			continue;
11697 
11698 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
11699 			scfdie();
11700 
11701 		err = delete_dependency_pg(fmri, name);
11702 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
11703 			if (scf_property_to_fmri(prop, fmri,
11704 			    max_scf_fmri_len + 2) < 0)
11705 				scfdie();
11706 
11707 			warn(gettext("Value of %s is not a valid FMRI.\n"),
11708 			    fmri);
11709 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
11710 			warn(gettext("Property group \"%s\" of entity \"%s\" "
11711 			    "does not have dependency type.\n"), name, fmri);
11712 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
11713 			warn(gettext("Could not delete property group \"%s\" "
11714 			    "of entity \"%s\" (permission denied).\n"), name,
11715 			    fmri);
11716 		}
11717 	}
11718 	if (r == -1)
11719 		scfdie();
11720 
11721 	scf_value_destroy(val);
11722 	scf_property_destroy(prop);
11723 
11724 	return (0);
11725 }
11726 
11727 /*
11728  * Returns 1 if the instance may be running, and 0 otherwise.
11729  */
11730 static int
11731 inst_is_running(scf_instance_t *inst)
11732 {
11733 	scf_propertygroup_t *pg;
11734 	scf_property_t *prop;
11735 	scf_value_t *val;
11736 	char buf[MAX_SCF_STATE_STRING_SZ];
11737 	int ret = 0;
11738 	ssize_t szret;
11739 
11740 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11741 	    (prop = scf_property_create(g_hndl)) == NULL ||
11742 	    (val = scf_value_create(g_hndl)) == NULL)
11743 		scfdie();
11744 
11745 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
11746 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11747 			scfdie();
11748 		goto out;
11749 	}
11750 
11751 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
11752 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
11753 	    prop_get_val(prop, val) != 0)
11754 		goto out;
11755 
11756 	szret = scf_value_get_astring(val, buf, sizeof (buf));
11757 	assert(szret >= 0);
11758 
11759 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11760 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11761 
11762 out:
11763 	scf_value_destroy(val);
11764 	scf_property_destroy(prop);
11765 	scf_pg_destroy(pg);
11766 	return (ret);
11767 }
11768 
11769 static uint8_t
11770 pg_is_external_dependency(scf_propertygroup_t *pg)
11771 {
11772 	char *type;
11773 	scf_value_t *val;
11774 	scf_property_t *prop;
11775 	uint8_t b = B_FALSE;
11776 
11777 	type = safe_malloc(max_scf_pg_type_len + 1);
11778 
11779 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
11780 		scfdie();
11781 
11782 	if ((prop = scf_property_create(g_hndl)) == NULL ||
11783 	    (val = scf_value_create(g_hndl)) == NULL)
11784 		scfdie();
11785 
11786 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
11787 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
11788 			if (scf_property_get_value(prop, val) != 0)
11789 				scfdie();
11790 			if (scf_value_get_boolean(val, &b) != 0)
11791 				scfdie();
11792 		}
11793 	}
11794 
11795 	free(type);
11796 	(void) scf_value_destroy(val);
11797 	(void) scf_property_destroy(prop);
11798 
11799 	return (b);
11800 }
11801 
11802 #define	DELETE_FAILURE			-1
11803 #define	DELETE_SUCCESS_NOEXTDEPS	0
11804 #define	DELETE_SUCCESS_EXTDEPS		1
11805 
11806 /*
11807  * lscf_instance_delete() deletes an instance.  Before calling
11808  * scf_instance_delete(), though, we make sure the instance isn't
11809  * running and delete dependencies in other entities which the instance
11810  * declared as "dependents".  If there are dependencies which were
11811  * created for other entities, then instead of deleting the instance we
11812  * make it "empty" by deleting all other property groups and all
11813  * snapshots.
11814  *
11815  * lscf_instance_delete() verifies that there is no external dependency pgs
11816  * before suppressing the instance. If there is, then we must not remove them
11817  * now in case the instance is re-created otherwise the dependencies would be
11818  * lost. The external dependency pgs will be removed if the dependencies are
11819  * removed.
11820  *
11821  * Returns:
11822  *  DELETE_FAILURE		on failure
11823  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11824  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11825  */
11826 static int
11827 lscf_instance_delete(scf_instance_t *inst, int force)
11828 {
11829 	scf_propertygroup_t *pg;
11830 	scf_snapshot_t *snap;
11831 	scf_iter_t *iter;
11832 	int err;
11833 	int external = 0;
11834 
11835 	/* If we're not forcing and the instance is running, refuse. */
11836 	if (!force && inst_is_running(inst)) {
11837 		char *fmri;
11838 
11839 		fmri = safe_malloc(max_scf_fmri_len + 1);
11840 
11841 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
11842 			scfdie();
11843 
11844 		semerr(gettext("Instance %s may be running.  "
11845 		    "Use delete -f if it is not.\n"), fmri);
11846 
11847 		free(fmri);
11848 		return (DELETE_FAILURE);
11849 	}
11850 
11851 	pg = scf_pg_create(g_hndl);
11852 	if (pg == NULL)
11853 		scfdie();
11854 
11855 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
11856 		(void) delete_dependents(pg);
11857 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11858 		scfdie();
11859 
11860 	scf_pg_destroy(pg);
11861 
11862 	/*
11863 	 * If the instance has some external dependencies then we must
11864 	 * keep them in case the instance is reimported otherwise the
11865 	 * dependencies would be lost on reimport.
11866 	 */
11867 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11868 	    (pg = scf_pg_create(g_hndl)) == NULL)
11869 		scfdie();
11870 
11871 	if (scf_iter_instance_pgs(iter, inst) < 0)
11872 		scfdie();
11873 
11874 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11875 		if (pg_is_external_dependency(pg)) {
11876 			external = 1;
11877 			continue;
11878 		}
11879 
11880 		if (scf_pg_delete(pg) != 0) {
11881 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11882 				scfdie();
11883 			else {
11884 				semerr(emsg_permission_denied);
11885 
11886 				(void) scf_iter_destroy(iter);
11887 				(void) scf_pg_destroy(pg);
11888 				return (DELETE_FAILURE);
11889 			}
11890 		}
11891 	}
11892 
11893 	if (err == -1)
11894 		scfdie();
11895 
11896 	(void) scf_iter_destroy(iter);
11897 	(void) scf_pg_destroy(pg);
11898 
11899 	if (external) {
11900 		/*
11901 		 * All the pgs have been deleted for the instance except
11902 		 * the ones holding the external dependencies.
11903 		 * For the job to be complete, we must also delete the
11904 		 * snapshots associated with the instance.
11905 		 */
11906 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
11907 		    NULL)
11908 			scfdie();
11909 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
11910 			scfdie();
11911 
11912 		if (scf_iter_instance_snapshots(iter, inst) == -1)
11913 			scfdie();
11914 
11915 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
11916 			if (_scf_snapshot_delete(snap) != 0) {
11917 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11918 					scfdie();
11919 
11920 				semerr(emsg_permission_denied);
11921 
11922 				(void) scf_iter_destroy(iter);
11923 				(void) scf_snapshot_destroy(snap);
11924 				return (DELETE_FAILURE);
11925 			}
11926 		}
11927 
11928 		if (err == -1)
11929 			scfdie();
11930 
11931 		(void) scf_iter_destroy(iter);
11932 		(void) scf_snapshot_destroy(snap);
11933 		return (DELETE_SUCCESS_EXTDEPS);
11934 	}
11935 
11936 	if (scf_instance_delete(inst) != 0) {
11937 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11938 			scfdie();
11939 
11940 		semerr(emsg_permission_denied);
11941 
11942 		return (DELETE_FAILURE);
11943 	}
11944 
11945 	return (DELETE_SUCCESS_NOEXTDEPS);
11946 }
11947 
11948 /*
11949  * lscf_service_delete() deletes a service.  Before calling
11950  * scf_service_delete(), though, we call lscf_instance_delete() for
11951  * each of the instances and delete dependencies in other entities
11952  * which were created as "dependents" of this service.  If there are
11953  * dependencies which were created for other entities, then we delete
11954  * all other property groups in the service and leave it as "empty".
11955  *
11956  * lscf_service_delete() verifies that there is no external dependency
11957  * pgs at the instance & service level before suppressing the service.
11958  * If there is, then we must not remove them now in case the service
11959  * is re-imported otherwise the dependencies would be lost. The external
11960  * dependency pgs will be removed if the dependencies are removed.
11961  *
11962  * Returns:
11963  *   DELETE_FAILURE		on failure
11964  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11965  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11966  */
11967 static int
11968 lscf_service_delete(scf_service_t *svc, int force)
11969 {
11970 	int r;
11971 	scf_instance_t *inst;
11972 	scf_propertygroup_t *pg;
11973 	scf_iter_t *iter;
11974 	int ret;
11975 	int external = 0;
11976 
11977 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11978 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11979 	    (iter = scf_iter_create(g_hndl)) == NULL)
11980 		scfdie();
11981 
11982 	if (scf_iter_service_instances(iter, svc) != 0)
11983 		scfdie();
11984 
11985 	for (r = scf_iter_next_instance(iter, inst);
11986 	    r == 1;
11987 	    r = scf_iter_next_instance(iter, inst)) {
11988 
11989 		ret = lscf_instance_delete(inst, force);
11990 		if (ret == DELETE_FAILURE) {
11991 			scf_iter_destroy(iter);
11992 			scf_pg_destroy(pg);
11993 			scf_instance_destroy(inst);
11994 			return (DELETE_FAILURE);
11995 		}
11996 
11997 		/*
11998 		 * Record the fact that there is some external dependencies
11999 		 * at the instance level.
12000 		 */
12001 		if (ret == DELETE_SUCCESS_EXTDEPS)
12002 			external |= 1;
12003 	}
12004 
12005 	if (r != 0)
12006 		scfdie();
12007 
12008 	/* Delete dependency property groups in dependent services. */
12009 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12010 		(void) delete_dependents(pg);
12011 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12012 		scfdie();
12013 
12014 	scf_iter_destroy(iter);
12015 	scf_pg_destroy(pg);
12016 	scf_instance_destroy(inst);
12017 
12018 	/*
12019 	 * If the service has some external dependencies then we don't
12020 	 * want to remove them in case the service is re-imported.
12021 	 */
12022 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12023 	    (iter = scf_iter_create(g_hndl)) == NULL)
12024 		scfdie();
12025 
12026 	if (scf_iter_service_pgs(iter, svc) < 0)
12027 		scfdie();
12028 
12029 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12030 		if (pg_is_external_dependency(pg)) {
12031 			external |= 2;
12032 			continue;
12033 		}
12034 
12035 		if (scf_pg_delete(pg) != 0) {
12036 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12037 				scfdie();
12038 			else {
12039 				semerr(emsg_permission_denied);
12040 
12041 				(void) scf_iter_destroy(iter);
12042 				(void) scf_pg_destroy(pg);
12043 				return (DELETE_FAILURE);
12044 			}
12045 		}
12046 	}
12047 
12048 	if (r == -1)
12049 		scfdie();
12050 
12051 	(void) scf_iter_destroy(iter);
12052 	(void) scf_pg_destroy(pg);
12053 
12054 	if (external != 0)
12055 		return (DELETE_SUCCESS_EXTDEPS);
12056 
12057 	if (scf_service_delete(svc) == 0)
12058 		return (DELETE_SUCCESS_NOEXTDEPS);
12059 
12060 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12061 		scfdie();
12062 
12063 	semerr(emsg_permission_denied);
12064 	return (DELETE_FAILURE);
12065 }
12066 
12067 static int
12068 delete_callback(void *data, scf_walkinfo_t *wip)
12069 {
12070 	int force = (int)data;
12071 
12072 	if (wip->inst != NULL)
12073 		(void) lscf_instance_delete(wip->inst, force);
12074 	else
12075 		(void) lscf_service_delete(wip->svc, force);
12076 
12077 	return (0);
12078 }
12079 
12080 void
12081 lscf_delete(const char *fmri, int force)
12082 {
12083 	scf_service_t *svc;
12084 	scf_instance_t *inst;
12085 	int ret;
12086 
12087 	lscf_prep_hndl();
12088 
12089 	if (cur_snap != NULL) {
12090 		if (!snaplevel_is_instance(cur_level)) {
12091 			char *buf;
12092 
12093 			buf = safe_malloc(max_scf_name_len + 1);
12094 			if (scf_instance_get_name(cur_inst, buf,
12095 			    max_scf_name_len + 1) >= 0) {
12096 				if (strcmp(buf, fmri) == 0) {
12097 					semerr(emsg_cant_modify_snapshots);
12098 					free(buf);
12099 					return;
12100 				}
12101 			} else if (scf_error() != SCF_ERROR_DELETED) {
12102 				scfdie();
12103 			}
12104 			free(buf);
12105 		}
12106 	} else if (cur_inst != NULL) {
12107 		/* EMPTY */;
12108 	} else if (cur_svc != NULL) {
12109 		inst = scf_instance_create(g_hndl);
12110 		if (inst == NULL)
12111 			scfdie();
12112 
12113 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12114 		    SCF_SUCCESS) {
12115 			(void) lscf_instance_delete(inst, force);
12116 			scf_instance_destroy(inst);
12117 			return;
12118 		}
12119 
12120 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12121 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12122 			scfdie();
12123 
12124 		scf_instance_destroy(inst);
12125 	} else {
12126 		assert(cur_scope != NULL);
12127 
12128 		svc = scf_service_create(g_hndl);
12129 		if (svc == NULL)
12130 			scfdie();
12131 
12132 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12133 		    SCF_SUCCESS) {
12134 			(void) lscf_service_delete(svc, force);
12135 			scf_service_destroy(svc);
12136 			return;
12137 		}
12138 
12139 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12140 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12141 			scfdie();
12142 
12143 		scf_service_destroy(svc);
12144 	}
12145 
12146 	/*
12147 	 * Match FMRI to entity.
12148 	 */
12149 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12150 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12151 		semerr(gettext("Failed to walk instances: %s\n"),
12152 		    scf_strerror(ret));
12153 	}
12154 }
12155 
12156 
12157 
12158 /*
12159  * :properties commands.  These all end with "pg" or "prop" and generally
12160  * operate on the currently selected entity.
12161  */
12162 
12163 /*
12164  * Property listing.  List the property groups, properties, their types and
12165  * their values for the currently selected entity.
12166  */
12167 static void
12168 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12169 {
12170 	char *buf;
12171 	uint32_t flags;
12172 
12173 	buf = safe_malloc(max_scf_pg_type_len + 1);
12174 
12175 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12176 		scfdie();
12177 
12178 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12179 		scfdie();
12180 
12181 	safe_printf("%-*s  %s", namewidth, name, buf);
12182 
12183 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12184 		safe_printf("\tNONPERSISTENT");
12185 
12186 	safe_printf("\n");
12187 
12188 	free(buf);
12189 }
12190 
12191 static boolean_t
12192 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12193 {
12194 	if (scf_property_get_value(prop, val) == 0) {
12195 		return (B_FALSE);
12196 	} else {
12197 		switch (scf_error()) {
12198 		case SCF_ERROR_NOT_FOUND:
12199 			return (B_FALSE);
12200 		case SCF_ERROR_PERMISSION_DENIED:
12201 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12202 			return (B_TRUE);
12203 		default:
12204 			scfdie();
12205 			/*NOTREACHED*/
12206 		}
12207 	}
12208 }
12209 
12210 static void
12211 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12212 {
12213 	scf_iter_t *iter;
12214 	scf_value_t *val;
12215 	const char *type;
12216 	int multiple_strings = 0;
12217 	int ret;
12218 
12219 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12220 	    (val = scf_value_create(g_hndl)) == NULL)
12221 		scfdie();
12222 
12223 	type = prop_to_typestr(prop);
12224 	assert(type != NULL);
12225 
12226 	safe_printf("%-*s  %-7s ", len, name, type);
12227 
12228 	if (prop_has_multiple_values(prop, val) &&
12229 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12230 	    scf_value_type(val) == SCF_TYPE_USTRING))
12231 		multiple_strings = 1;
12232 
12233 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12234 		scfdie();
12235 
12236 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12237 		char *buf;
12238 		ssize_t vlen, szret;
12239 
12240 		vlen = scf_value_get_as_string(val, NULL, 0);
12241 		if (vlen < 0)
12242 			scfdie();
12243 
12244 		buf = safe_malloc(vlen + 1);
12245 
12246 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12247 		if (szret < 0)
12248 			scfdie();
12249 		assert(szret <= vlen);
12250 
12251 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12252 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12253 			safe_printf(" \"");
12254 			(void) quote_and_print(buf, stdout, 0);
12255 			(void) putchar('"');
12256 			if (ferror(stdout)) {
12257 				(void) putchar('\n');
12258 				uu_die(gettext("Error writing to stdout.\n"));
12259 			}
12260 		} else {
12261 			safe_printf(" %s", buf);
12262 		}
12263 
12264 		free(buf);
12265 	}
12266 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12267 		scfdie();
12268 
12269 	if (putchar('\n') != '\n')
12270 		uu_die(gettext("Could not output newline"));
12271 }
12272 
12273 /*
12274  * Outputs template property group info for the describe subcommand.
12275  * If 'templates' == 2, verbose output is printed in the format expected
12276  * for describe -v, which includes all templates fields.  If pg is
12277  * not NULL, we're describing the template data, not an existing property
12278  * group, and formatting should be appropriate for describe -t.
12279  */
12280 static void
12281 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12282 {
12283 	char *buf;
12284 	uint8_t required;
12285 	scf_property_t *stability_prop;
12286 	scf_value_t *stability_val;
12287 
12288 	if (templates == 0)
12289 		return;
12290 
12291 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12292 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12293 		scfdie();
12294 
12295 	if (templates == 2 && pg != NULL) {
12296 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12297 		    stability_prop) == 0) {
12298 			if (prop_check_type(stability_prop,
12299 			    SCF_TYPE_ASTRING) == 0 &&
12300 			    prop_get_val(stability_prop, stability_val) == 0) {
12301 				char *stability;
12302 
12303 				stability = safe_malloc(max_scf_value_len + 1);
12304 
12305 				if (scf_value_get_astring(stability_val,
12306 				    stability, max_scf_value_len + 1) == -1 &&
12307 				    scf_error() != SCF_ERROR_NOT_FOUND)
12308 					scfdie();
12309 
12310 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12311 				    gettext("stability"), stability);
12312 
12313 				free(stability);
12314 			}
12315 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12316 			scfdie();
12317 	}
12318 
12319 	scf_property_destroy(stability_prop);
12320 	scf_value_destroy(stability_val);
12321 
12322 	if (pgt == NULL)
12323 		return;
12324 
12325 	if (pg == NULL || templates == 2) {
12326 		/* print type info only if scf_tmpl_pg_name succeeds */
12327 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12328 			if (pg != NULL)
12329 				safe_printf("%s", TMPL_INDENT);
12330 			safe_printf("%s: ", gettext("name"));
12331 			safe_printf("%s\n", buf);
12332 			free(buf);
12333 		}
12334 
12335 		/* print type info only if scf_tmpl_pg_type succeeds */
12336 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12337 			if (pg != NULL)
12338 				safe_printf("%s", TMPL_INDENT);
12339 			safe_printf("%s: ", gettext("type"));
12340 			safe_printf("%s\n", buf);
12341 			free(buf);
12342 		}
12343 	}
12344 
12345 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12346 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12347 		    required ? "true" : "false");
12348 
12349 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12350 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12351 		    buf);
12352 		free(buf);
12353 	}
12354 
12355 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12356 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12357 		    buf);
12358 		free(buf);
12359 	}
12360 
12361 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12362 		if (templates == 2)
12363 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12364 			    gettext("description"), buf);
12365 		else
12366 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12367 		free(buf);
12368 	}
12369 
12370 }
12371 
12372 /*
12373  * With as_value set to true, indent as appropriate for the value level.
12374  * If false, indent to appropriate level for inclusion in constraint
12375  * or choice printout.
12376  */
12377 static void
12378 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12379     int as_value)
12380 {
12381 	char *buf;
12382 
12383 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12384 		if (as_value == 0)
12385 			safe_printf("%s", TMPL_CHOICE_INDENT);
12386 		else
12387 			safe_printf("%s", TMPL_INDENT);
12388 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12389 		free(buf);
12390 	}
12391 
12392 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12393 		if (as_value == 0)
12394 			safe_printf("%s", TMPL_CHOICE_INDENT);
12395 		else
12396 			safe_printf("%s", TMPL_INDENT);
12397 		safe_printf("%s: %s\n", gettext("value description"), buf);
12398 		free(buf);
12399 	}
12400 }
12401 
12402 static void
12403 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12404 {
12405 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12406 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12407 	safe_printf("%s\n", val_buf);
12408 
12409 	print_template_value_details(prt, val_buf, 1);
12410 }
12411 
12412 static void
12413 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12414 {
12415 	int i, printed = 0;
12416 	scf_values_t values;
12417 	scf_count_ranges_t c_ranges;
12418 	scf_int_ranges_t i_ranges;
12419 
12420 	printed = 0;
12421 	i = 0;
12422 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12423 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12424 		    gettext("value constraints"));
12425 		printed++;
12426 		for (i = 0; i < values.value_count; ++i) {
12427 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12428 			    gettext("value name"), values.values_as_strings[i]);
12429 			if (verbose == 1)
12430 				print_template_value_details(prt,
12431 				    values.values_as_strings[i], 0);
12432 		}
12433 
12434 		scf_values_destroy(&values);
12435 	}
12436 
12437 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12438 		if (printed++ == 0)
12439 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12440 			    gettext("value constraints"));
12441 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12442 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12443 			    gettext("range"), c_ranges.scr_min[i],
12444 			    c_ranges.scr_max[i]);
12445 		}
12446 		scf_count_ranges_destroy(&c_ranges);
12447 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12448 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12449 		if (printed++ == 0)
12450 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12451 			    gettext("value constraints"));
12452 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12453 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12454 			    gettext("range"), i_ranges.sir_min[i],
12455 			    i_ranges.sir_max[i]);
12456 		}
12457 		scf_int_ranges_destroy(&i_ranges);
12458 	}
12459 }
12460 
12461 static void
12462 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12463 {
12464 	int i = 0, printed = 0;
12465 	scf_values_t values;
12466 	scf_count_ranges_t c_ranges;
12467 	scf_int_ranges_t i_ranges;
12468 
12469 	printed = 0;
12470 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12471 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12472 		    gettext("value constraints"));
12473 		printed++;
12474 		for (i = 0; i < values.value_count; i++) {
12475 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12476 			    gettext("value name"), values.values_as_strings[i]);
12477 			if (verbose == 1)
12478 				print_template_value_details(prt,
12479 				    values.values_as_strings[i], 0);
12480 		}
12481 
12482 		scf_values_destroy(&values);
12483 	}
12484 
12485 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12486 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12487 			if (printed++ == 0)
12488 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12489 				    gettext("value choices"));
12490 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12491 			    gettext("range"), c_ranges.scr_min[i],
12492 			    c_ranges.scr_max[i]);
12493 		}
12494 		scf_count_ranges_destroy(&c_ranges);
12495 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12496 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12497 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12498 			if (printed++ == 0)
12499 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12500 				    gettext("value choices"));
12501 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12502 			    gettext("range"), i_ranges.sir_min[i],
12503 			    i_ranges.sir_max[i]);
12504 		}
12505 		scf_int_ranges_destroy(&i_ranges);
12506 	}
12507 }
12508 
12509 static void
12510 list_values_by_template(scf_prop_tmpl_t *prt)
12511 {
12512 	print_template_constraints(prt, 1);
12513 	print_template_choices(prt, 1);
12514 }
12515 
12516 static void
12517 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
12518 {
12519 	char *val_buf;
12520 	scf_iter_t *iter;
12521 	scf_value_t *val;
12522 	int ret;
12523 
12524 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12525 	    (val = scf_value_create(g_hndl)) == NULL)
12526 		scfdie();
12527 
12528 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12529 		scfdie();
12530 
12531 	val_buf = safe_malloc(max_scf_value_len + 1);
12532 
12533 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12534 		if (scf_value_get_as_string(val, val_buf,
12535 		    max_scf_value_len + 1) < 0)
12536 			scfdie();
12537 
12538 		print_template_value(prt, val_buf);
12539 	}
12540 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12541 		scfdie();
12542 	free(val_buf);
12543 
12544 	print_template_constraints(prt, 0);
12545 	print_template_choices(prt, 0);
12546 
12547 }
12548 
12549 /*
12550  * Outputs property info for the describe subcommand
12551  * Verbose output if templates == 2, -v option of svccfg describe
12552  * Displays template data if prop is not NULL, -t option of svccfg describe
12553  */
12554 static void
12555 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
12556 {
12557 	char *buf;
12558 	uint8_t u_buf;
12559 	int i;
12560 	uint64_t min, max;
12561 	scf_values_t values;
12562 
12563 	if (prt == NULL || templates == 0)
12564 		return;
12565 
12566 	if (prop == NULL) {
12567 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
12568 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
12569 			safe_printf("%s\n", buf);
12570 			free(buf);
12571 		} else
12572 			safe_printf("(%s)\n", gettext("any"));
12573 	}
12574 
12575 	if (prop == NULL || templates == 2) {
12576 		if (prop != NULL)
12577 			safe_printf("%s", TMPL_INDENT);
12578 		else
12579 			safe_printf("%s", TMPL_VALUE_INDENT);
12580 		safe_printf("%s: ", gettext("type"));
12581 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
12582 			safe_printf("%s\n", buf);
12583 			free(buf);
12584 		} else
12585 			safe_printf("(%s)\n", gettext("any"));
12586 	}
12587 
12588 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
12589 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12590 		    u_buf ? "true" : "false");
12591 
12592 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
12593 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12594 		    buf);
12595 		free(buf);
12596 	}
12597 
12598 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
12599 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
12600 		    buf);
12601 		free(buf);
12602 	}
12603 
12604 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
12605 		safe_printf("%s%s\n", TMPL_INDENT, buf);
12606 		free(buf);
12607 	}
12608 
12609 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
12610 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
12611 		    scf_tmpl_visibility_to_string(u_buf));
12612 
12613 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
12614 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12615 		    gettext("minimum number of values"), min);
12616 		if (max == ULLONG_MAX) {
12617 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12618 			    gettext("maximum number of values"),
12619 			    gettext("unlimited"));
12620 		} else {
12621 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12622 			    gettext("maximum number of values"), max);
12623 		}
12624 	}
12625 
12626 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
12627 		for (i = 0; i < values.value_count; i++) {
12628 			if (i == 0) {
12629 				safe_printf("%s%s:", TMPL_INDENT,
12630 				    gettext("internal separators"));
12631 			}
12632 			safe_printf(" \"%s\"", values.values_as_strings[i]);
12633 		}
12634 		safe_printf("\n");
12635 	}
12636 
12637 	if (templates != 2)
12638 		return;
12639 
12640 	if (prop != NULL)
12641 		list_values_tmpl(prt, prop);
12642 	else
12643 		list_values_by_template(prt);
12644 }
12645 
12646 static char *
12647 read_astring(scf_propertygroup_t *pg, const char *prop_name)
12648 {
12649 	char *rv;
12650 
12651 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
12652 	if (rv == NULL) {
12653 		switch (scf_error()) {
12654 		case SCF_ERROR_NOT_FOUND:
12655 			break;
12656 		default:
12657 			scfdie();
12658 		}
12659 	}
12660 	return (rv);
12661 }
12662 
12663 static void
12664 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
12665 {
12666 	size_t doc_len;
12667 	size_t man_len;
12668 	char *pg_name;
12669 	char *text = NULL;
12670 	int rv;
12671 
12672 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
12673 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
12674 	pg_name = safe_malloc(max_scf_name_len + 1);
12675 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
12676 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
12677 			scfdie();
12678 		}
12679 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
12680 			/* Display doc_link and and uri */
12681 			safe_printf("%s%s:\n", TMPL_INDENT,
12682 			    gettext("doc_link"));
12683 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
12684 			if (text != NULL) {
12685 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12686 				    TMPL_INDENT, gettext("name"), text);
12687 				uu_free(text);
12688 			}
12689 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
12690 			if (text != NULL) {
12691 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
12692 				    gettext("uri"), text);
12693 				uu_free(text);
12694 			}
12695 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
12696 		    man_len) == 0) {
12697 			/* Display manpage title, section and path */
12698 			safe_printf("%s%s:\n", TMPL_INDENT,
12699 			    gettext("manpage"));
12700 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
12701 			if (text != NULL) {
12702 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12703 				    TMPL_INDENT, gettext("title"), text);
12704 				uu_free(text);
12705 			}
12706 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
12707 			if (text != NULL) {
12708 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12709 				    TMPL_INDENT, gettext("section"), text);
12710 				uu_free(text);
12711 			}
12712 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
12713 			if (text != NULL) {
12714 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12715 				    TMPL_INDENT, gettext("manpath"), text);
12716 				uu_free(text);
12717 			}
12718 		}
12719 	}
12720 	if (rv == -1)
12721 		scfdie();
12722 
12723 done:
12724 	free(pg_name);
12725 }
12726 
12727 static void
12728 list_entity_tmpl(int templates)
12729 {
12730 	char *common_name = NULL;
12731 	char *description = NULL;
12732 	char *locale = NULL;
12733 	scf_iter_t *iter;
12734 	scf_propertygroup_t *pg;
12735 	scf_property_t *prop;
12736 	int r;
12737 	scf_value_t *val;
12738 
12739 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12740 	    (prop = scf_property_create(g_hndl)) == NULL ||
12741 	    (val = scf_value_create(g_hndl)) == NULL ||
12742 	    (iter = scf_iter_create(g_hndl)) == NULL)
12743 		scfdie();
12744 
12745 	locale = setlocale(LC_MESSAGES, NULL);
12746 
12747 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
12748 		common_name = safe_malloc(max_scf_value_len + 1);
12749 
12750 		/* Try both the current locale and the "C" locale. */
12751 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
12752 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
12753 		    scf_pg_get_property(pg, "C", prop) == 0)) {
12754 			if (prop_get_val(prop, val) == 0 &&
12755 			    scf_value_get_ustring(val, common_name,
12756 			    max_scf_value_len + 1) != -1) {
12757 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12758 				    gettext("common name"), common_name);
12759 			}
12760 		}
12761 	}
12762 
12763 	/*
12764 	 * Do description, manpages, and doc links if templates == 2.
12765 	 */
12766 	if (templates == 2) {
12767 		/* Get the description. */
12768 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12769 			description = safe_malloc(max_scf_value_len + 1);
12770 
12771 			/* Try both the current locale and the "C" locale. */
12772 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
12773 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
12774 			    scf_pg_get_property(pg, "C", prop) == 0)) {
12775 				if (prop_get_val(prop, val) == 0 &&
12776 				    scf_value_get_ustring(val, description,
12777 				    max_scf_value_len + 1) != -1) {
12778 					safe_printf("%s%s: %s\n", TMPL_INDENT,
12779 					    gettext("description"),
12780 					    description);
12781 				}
12782 			}
12783 		}
12784 
12785 		/* Process doc_link & manpage elements. */
12786 		if (cur_level != NULL) {
12787 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
12788 			    SCF_GROUP_TEMPLATE);
12789 		} else if (cur_inst != NULL) {
12790 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
12791 			    SCF_GROUP_TEMPLATE);
12792 		} else {
12793 			r = scf_iter_service_pgs_typed(iter, cur_svc,
12794 			    SCF_GROUP_TEMPLATE);
12795 		}
12796 		if (r == 0) {
12797 			display_documentation(iter, pg);
12798 		}
12799 	}
12800 
12801 	free(common_name);
12802 	free(description);
12803 	scf_pg_destroy(pg);
12804 	scf_property_destroy(prop);
12805 	scf_value_destroy(val);
12806 	scf_iter_destroy(iter);
12807 }
12808 
12809 static void
12810 listtmpl(const char *pattern, int templates)
12811 {
12812 	scf_pg_tmpl_t *pgt;
12813 	scf_prop_tmpl_t *prt;
12814 	char *snapbuf = NULL;
12815 	char *fmribuf;
12816 	char *pg_name = NULL, *prop_name = NULL;
12817 	ssize_t prop_name_size;
12818 	char *qual_prop_name;
12819 	char *search_name;
12820 	int listed = 0;
12821 
12822 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12823 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
12824 		scfdie();
12825 
12826 	fmribuf = safe_malloc(max_scf_name_len + 1);
12827 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
12828 
12829 	if (cur_snap != NULL) {
12830 		snapbuf = safe_malloc(max_scf_name_len + 1);
12831 		if (scf_snapshot_get_name(cur_snap, snapbuf,
12832 		    max_scf_name_len + 1) < 0)
12833 			scfdie();
12834 	}
12835 
12836 	if (cur_inst != NULL) {
12837 		if (scf_instance_to_fmri(cur_inst, fmribuf,
12838 		    max_scf_name_len + 1) < 0)
12839 			scfdie();
12840 	} else if (cur_svc != NULL) {
12841 		if (scf_service_to_fmri(cur_svc, fmribuf,
12842 		    max_scf_name_len + 1) < 0)
12843 			scfdie();
12844 	} else
12845 		abort();
12846 
12847 	/* If pattern is specified, we want to list only those items. */
12848 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
12849 		listed = 0;
12850 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
12851 		    fnmatch(pattern, pg_name, 0) == 0)) {
12852 			list_pg_tmpl(pgt, NULL, templates);
12853 			listed++;
12854 		}
12855 
12856 		scf_tmpl_prop_reset(prt);
12857 
12858 		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
12859 			search_name = NULL;
12860 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
12861 			if ((prop_name_size > 0) && (pg_name != NULL)) {
12862 				if (snprintf(qual_prop_name,
12863 				    max_scf_name_len + 1, "%s/%s",
12864 				    pg_name, prop_name) >=
12865 				    max_scf_name_len + 1) {
12866 					prop_name_size = -1;
12867 				} else {
12868 					search_name = qual_prop_name;
12869 				}
12870 			}
12871 			if (listed > 0 || pattern == NULL ||
12872 			    (prop_name_size > 0 &&
12873 			    fnmatch(pattern, search_name,
12874 			    FNM_PATHNAME) == 0))
12875 				list_prop_tmpl(prt, NULL, templates);
12876 			if (prop_name != NULL) {
12877 				free(prop_name);
12878 				prop_name = NULL;
12879 			}
12880 		}
12881 		if (pg_name != NULL) {
12882 			free(pg_name);
12883 			pg_name = NULL;
12884 		}
12885 	}
12886 
12887 	scf_tmpl_prop_destroy(prt);
12888 	scf_tmpl_pg_destroy(pgt);
12889 	free(snapbuf);
12890 	free(fmribuf);
12891 	free(qual_prop_name);
12892 }
12893 
12894 static void
12895 listprop(const char *pattern, int only_pgs, int templates)
12896 {
12897 	scf_propertygroup_t *pg;
12898 	scf_property_t *prop;
12899 	scf_iter_t *iter, *piter;
12900 	char *pgnbuf, *prnbuf, *ppnbuf;
12901 	scf_pg_tmpl_t *pgt, *pgtp;
12902 	scf_prop_tmpl_t *prt;
12903 
12904 	void **objects;
12905 	char **names;
12906 	void **tmpls;
12907 	int allocd, i;
12908 
12909 	int ret;
12910 	ssize_t pgnlen, prnlen, szret;
12911 	size_t max_len = 0;
12912 
12913 	if (cur_svc == NULL && cur_inst == NULL) {
12914 		semerr(emsg_entity_not_selected);
12915 		return;
12916 	}
12917 
12918 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12919 	    (prop = scf_property_create(g_hndl)) == NULL ||
12920 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12921 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12922 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12923 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
12924 		scfdie();
12925 
12926 	prnbuf = safe_malloc(max_scf_name_len + 1);
12927 
12928 	if (cur_level != NULL)
12929 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
12930 	else if (cur_inst != NULL)
12931 		ret = scf_iter_instance_pgs(iter, cur_inst);
12932 	else
12933 		ret = scf_iter_service_pgs(iter, cur_svc);
12934 	if (ret != 0) {
12935 		return;
12936 	}
12937 
12938 	/*
12939 	 * We want to only list items which match pattern, and we want the
12940 	 * second column to line up, so during the first pass we'll save
12941 	 * matching items, their names, and their templates in objects,
12942 	 * names, and tmpls, computing the maximum name length as we go,
12943 	 * and then we'll print them out.
12944 	 *
12945 	 * Note: We always keep an extra slot available so the array can be
12946 	 * NULL-terminated.
12947 	 */
12948 	i = 0;
12949 	allocd = 1;
12950 	objects = safe_malloc(sizeof (*objects));
12951 	names = safe_malloc(sizeof (*names));
12952 	tmpls = safe_malloc(sizeof (*tmpls));
12953 
12954 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12955 		int new_pg = 0;
12956 		int print_props = 0;
12957 		pgtp = NULL;
12958 
12959 		pgnlen = scf_pg_get_name(pg, NULL, 0);
12960 		if (pgnlen < 0)
12961 			scfdie();
12962 
12963 		pgnbuf = safe_malloc(pgnlen + 1);
12964 
12965 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
12966 		if (szret < 0)
12967 			scfdie();
12968 		assert(szret <= pgnlen);
12969 
12970 		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
12971 			if (scf_error() != SCF_ERROR_NOT_FOUND)
12972 				scfdie();
12973 			pgtp = NULL;
12974 		} else {
12975 			pgtp = pgt;
12976 		}
12977 
12978 		if (pattern == NULL ||
12979 		    fnmatch(pattern, pgnbuf, 0) == 0) {
12980 			if (i+1 >= allocd) {
12981 				allocd *= 2;
12982 				objects = realloc(objects,
12983 				    sizeof (*objects) * allocd);
12984 				names =
12985 				    realloc(names, sizeof (*names) * allocd);
12986 				tmpls = realloc(tmpls,
12987 				    sizeof (*tmpls) * allocd);
12988 				if (objects == NULL || names == NULL ||
12989 				    tmpls == NULL)
12990 					uu_die(gettext("Out of memory"));
12991 			}
12992 			objects[i] = pg;
12993 			names[i] = pgnbuf;
12994 
12995 			if (pgtp == NULL)
12996 				tmpls[i] = NULL;
12997 			else
12998 				tmpls[i] = pgt;
12999 
13000 			++i;
13001 
13002 			if (pgnlen > max_len)
13003 				max_len = pgnlen;
13004 
13005 			new_pg = 1;
13006 			print_props = 1;
13007 		}
13008 
13009 		if (only_pgs) {
13010 			if (new_pg) {
13011 				pg = scf_pg_create(g_hndl);
13012 				if (pg == NULL)
13013 					scfdie();
13014 				pgt = scf_tmpl_pg_create(g_hndl);
13015 				if (pgt == NULL)
13016 					scfdie();
13017 			} else
13018 				free(pgnbuf);
13019 
13020 			continue;
13021 		}
13022 
13023 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13024 			scfdie();
13025 
13026 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13027 			prnlen = scf_property_get_name(prop, prnbuf,
13028 			    max_scf_name_len + 1);
13029 			if (prnlen < 0)
13030 				scfdie();
13031 
13032 			/* Will prepend the property group name and a slash. */
13033 			prnlen += pgnlen + 1;
13034 
13035 			ppnbuf = safe_malloc(prnlen + 1);
13036 
13037 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13038 			    prnbuf) < 0)
13039 				uu_die("snprintf");
13040 
13041 			if (pattern == NULL || print_props == 1 ||
13042 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13043 				if (i+1 >= allocd) {
13044 					allocd *= 2;
13045 					objects = realloc(objects,
13046 					    sizeof (*objects) * allocd);
13047 					names = realloc(names,
13048 					    sizeof (*names) * allocd);
13049 					tmpls = realloc(tmpls,
13050 					    sizeof (*tmpls) * allocd);
13051 					if (objects == NULL || names == NULL ||
13052 					    tmpls == NULL)
13053 						uu_die(gettext(
13054 						    "Out of memory"));
13055 				}
13056 
13057 				objects[i] = prop;
13058 				names[i] = ppnbuf;
13059 
13060 				if (pgtp != NULL) {
13061 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13062 					    prt, NULL) < 0) {
13063 						if (scf_error() !=
13064 						    SCF_ERROR_NOT_FOUND)
13065 							scfdie();
13066 						tmpls[i] = NULL;
13067 					} else {
13068 						tmpls[i] = prt;
13069 					}
13070 				} else {
13071 					tmpls[i] = NULL;
13072 				}
13073 
13074 				++i;
13075 
13076 				if (prnlen > max_len)
13077 					max_len = prnlen;
13078 
13079 				prop = scf_property_create(g_hndl);
13080 				prt = scf_tmpl_prop_create(g_hndl);
13081 			} else {
13082 				free(ppnbuf);
13083 			}
13084 		}
13085 
13086 		if (new_pg) {
13087 			pg = scf_pg_create(g_hndl);
13088 			if (pg == NULL)
13089 				scfdie();
13090 			pgt = scf_tmpl_pg_create(g_hndl);
13091 			if (pgt == NULL)
13092 				scfdie();
13093 		} else
13094 			free(pgnbuf);
13095 	}
13096 	if (ret != 0)
13097 		scfdie();
13098 
13099 	objects[i] = NULL;
13100 
13101 	scf_pg_destroy(pg);
13102 	scf_tmpl_pg_destroy(pgt);
13103 	scf_property_destroy(prop);
13104 	scf_tmpl_prop_destroy(prt);
13105 
13106 	for (i = 0; objects[i] != NULL; ++i) {
13107 		if (strchr(names[i], '/') == NULL) {
13108 			/* property group */
13109 			pg = (scf_propertygroup_t *)objects[i];
13110 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13111 			list_pg_info(pg, names[i], max_len);
13112 			list_pg_tmpl(pgt, pg, templates);
13113 			free(names[i]);
13114 			scf_pg_destroy(pg);
13115 			if (pgt != NULL)
13116 				scf_tmpl_pg_destroy(pgt);
13117 		} else {
13118 			/* property */
13119 			prop = (scf_property_t *)objects[i];
13120 			prt = (scf_prop_tmpl_t *)tmpls[i];
13121 			list_prop_info(prop, names[i], max_len);
13122 			list_prop_tmpl(prt, prop, templates);
13123 			free(names[i]);
13124 			scf_property_destroy(prop);
13125 			if (prt != NULL)
13126 				scf_tmpl_prop_destroy(prt);
13127 		}
13128 	}
13129 
13130 	free(names);
13131 	free(objects);
13132 	free(tmpls);
13133 }
13134 
13135 void
13136 lscf_listpg(const char *pattern)
13137 {
13138 	lscf_prep_hndl();
13139 
13140 	listprop(pattern, 1, 0);
13141 }
13142 
13143 /*
13144  * Property group and property creation, setting, and deletion.  setprop (and
13145  * its alias, addprop) can either create a property group of a given type, or
13146  * it can create or set a property to a given type and list of values.
13147  */
13148 void
13149 lscf_addpg(const char *name, const char *type, const char *flags)
13150 {
13151 	scf_propertygroup_t *pg;
13152 	int ret;
13153 	uint32_t flgs = 0;
13154 	const char *cp;
13155 
13156 
13157 	lscf_prep_hndl();
13158 
13159 	if (cur_snap != NULL) {
13160 		semerr(emsg_cant_modify_snapshots);
13161 		return;
13162 	}
13163 
13164 	if (cur_inst == NULL && cur_svc == NULL) {
13165 		semerr(emsg_entity_not_selected);
13166 		return;
13167 	}
13168 
13169 	if (flags != NULL) {
13170 		for (cp = flags; *cp != '\0'; ++cp) {
13171 			switch (*cp) {
13172 			case 'P':
13173 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13174 				break;
13175 
13176 			case 'p':
13177 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13178 				break;
13179 
13180 			default:
13181 				semerr(gettext("Invalid property group flag "
13182 				    "%c."), *cp);
13183 				return;
13184 			}
13185 		}
13186 	}
13187 
13188 	pg = scf_pg_create(g_hndl);
13189 	if (pg == NULL)
13190 		scfdie();
13191 
13192 	if (cur_inst != NULL)
13193 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13194 	else
13195 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13196 
13197 	if (ret != SCF_SUCCESS) {
13198 		switch (scf_error()) {
13199 		case SCF_ERROR_INVALID_ARGUMENT:
13200 			semerr(gettext("Name, type, or flags are invalid.\n"));
13201 			break;
13202 
13203 		case SCF_ERROR_EXISTS:
13204 			semerr(gettext("Property group already exists.\n"));
13205 			break;
13206 
13207 		case SCF_ERROR_PERMISSION_DENIED:
13208 			semerr(emsg_permission_denied);
13209 			break;
13210 
13211 		case SCF_ERROR_BACKEND_ACCESS:
13212 			semerr(gettext("Backend refused access.\n"));
13213 			break;
13214 
13215 		default:
13216 			scfdie();
13217 		}
13218 	}
13219 
13220 	scf_pg_destroy(pg);
13221 
13222 	private_refresh();
13223 }
13224 
13225 void
13226 lscf_delpg(char *name)
13227 {
13228 	lscf_prep_hndl();
13229 
13230 	if (cur_snap != NULL) {
13231 		semerr(emsg_cant_modify_snapshots);
13232 		return;
13233 	}
13234 
13235 	if (cur_inst == NULL && cur_svc == NULL) {
13236 		semerr(emsg_entity_not_selected);
13237 		return;
13238 	}
13239 
13240 	if (strchr(name, '/') != NULL) {
13241 		semerr(emsg_invalid_pg_name, name);
13242 		return;
13243 	}
13244 
13245 	lscf_delprop(name);
13246 }
13247 
13248 /*
13249  * scf_delhash() is used to remove the property group related to the
13250  * hash entry for a specific manifest in the repository. pgname will be
13251  * constructed from the location of the manifest file. If deathrow isn't 0,
13252  * manifest file doesn't need to exist (manifest string will be used as
13253  * an absolute path).
13254  */
13255 void
13256 lscf_delhash(char *manifest, int deathrow)
13257 {
13258 	char *pgname;
13259 
13260 	if (cur_snap != NULL ||
13261 	    cur_inst != NULL || cur_svc != NULL) {
13262 		warn(gettext("error, an entity is selected\n"));
13263 		return;
13264 	}
13265 
13266 	/* select smf/manifest */
13267 	lscf_select(HASH_SVC);
13268 	/*
13269 	 * Translate the manifest file name to property name. In the deathrow
13270 	 * case, the manifest file does not need to exist.
13271 	 */
13272 	pgname = mhash_filename_to_propname(manifest,
13273 	    deathrow ? B_TRUE : B_FALSE);
13274 	if (pgname == NULL) {
13275 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13276 		return;
13277 	}
13278 	/* delete the hash property name */
13279 	lscf_delpg(pgname);
13280 }
13281 
13282 void
13283 lscf_listprop(const char *pattern)
13284 {
13285 	lscf_prep_hndl();
13286 
13287 	listprop(pattern, 0, 0);
13288 }
13289 
13290 int
13291 lscf_setprop(const char *pgname, const char *type, const char *value,
13292     const uu_list_t *values)
13293 {
13294 	scf_type_t ty, current_ty;
13295 	scf_service_t *svc;
13296 	scf_propertygroup_t *pg, *parent_pg;
13297 	scf_property_t *prop, *parent_prop;
13298 	scf_pg_tmpl_t *pgt;
13299 	scf_prop_tmpl_t *prt;
13300 	int ret, result = 0;
13301 	scf_transaction_t *tx;
13302 	scf_transaction_entry_t *e;
13303 	scf_value_t *v;
13304 	uu_list_walk_t *walk;
13305 	string_list_t *sp;
13306 	char *propname;
13307 	int req_quotes = 0;
13308 
13309 	lscf_prep_hndl();
13310 
13311 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13312 	    (svc = scf_service_create(g_hndl)) == NULL ||
13313 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13314 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13315 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13316 	    (prop = scf_property_create(g_hndl)) == NULL ||
13317 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13318 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13319 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13320 		scfdie();
13321 
13322 	if (cur_snap != NULL) {
13323 		semerr(emsg_cant_modify_snapshots);
13324 		goto fail;
13325 	}
13326 
13327 	if (cur_inst == NULL && cur_svc == NULL) {
13328 		semerr(emsg_entity_not_selected);
13329 		goto fail;
13330 	}
13331 
13332 	propname = strchr(pgname, '/');
13333 	if (propname == NULL) {
13334 		semerr(gettext("Property names must contain a `/'.\n"));
13335 		goto fail;
13336 	}
13337 
13338 	*propname = '\0';
13339 	++propname;
13340 
13341 	if (type != NULL) {
13342 		ty = string_to_type(type);
13343 		if (ty == SCF_TYPE_INVALID) {
13344 			semerr(gettext("Unknown type \"%s\".\n"), type);
13345 			goto fail;
13346 		}
13347 	}
13348 
13349 	if (cur_inst != NULL)
13350 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13351 	else
13352 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13353 	if (ret != SCF_SUCCESS) {
13354 		switch (scf_error()) {
13355 		case SCF_ERROR_NOT_FOUND:
13356 			semerr(emsg_no_such_pg, pgname);
13357 			goto fail;
13358 
13359 		case SCF_ERROR_INVALID_ARGUMENT:
13360 			semerr(emsg_invalid_pg_name, pgname);
13361 			goto fail;
13362 
13363 		default:
13364 			scfdie();
13365 			break;
13366 		}
13367 	}
13368 
13369 	do {
13370 		if (scf_pg_update(pg) == -1)
13371 			scfdie();
13372 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13373 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13374 				scfdie();
13375 
13376 			semerr(emsg_permission_denied);
13377 			goto fail;
13378 		}
13379 
13380 		ret = scf_pg_get_property(pg, propname, prop);
13381 		if (ret == SCF_SUCCESS) {
13382 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13383 				scfdie();
13384 
13385 			if (type == NULL)
13386 				ty = current_ty;
13387 			if (scf_transaction_property_change_type(tx, e,
13388 			    propname, ty) == -1)
13389 				scfdie();
13390 
13391 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13392 			/* Infer the type, if possible. */
13393 			if (type == NULL) {
13394 				/*
13395 				 * First check if we're an instance and the
13396 				 * property is set on the service.
13397 				 */
13398 				if (cur_inst != NULL &&
13399 				    scf_instance_get_parent(cur_inst,
13400 				    svc) == 0 &&
13401 				    scf_service_get_pg(cur_svc, pgname,
13402 				    parent_pg) == 0 &&
13403 				    scf_pg_get_property(parent_pg, propname,
13404 				    parent_prop) == 0 &&
13405 				    scf_property_type(parent_prop,
13406 				    &current_ty) == 0) {
13407 					ty = current_ty;
13408 
13409 				/* Then check for a type set in a template. */
13410 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13411 				    NULL) == 0 &&
13412 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13413 				    NULL) == 0 &&
13414 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13415 					ty = current_ty;
13416 
13417 				/* If type can't be inferred, fail. */
13418 				} else {
13419 					semerr(gettext("Type required for new "
13420 					    "properties.\n"));
13421 					goto fail;
13422 				}
13423 			}
13424 			if (scf_transaction_property_new(tx, e, propname,
13425 			    ty) == -1)
13426 				scfdie();
13427 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13428 			semerr(emsg_invalid_prop_name, propname);
13429 			goto fail;
13430 		} else {
13431 			scfdie();
13432 		}
13433 
13434 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13435 			req_quotes = 1;
13436 
13437 		if (value != NULL) {
13438 			v = string_to_value(value, ty, 0);
13439 
13440 			if (v == NULL)
13441 				goto fail;
13442 
13443 			ret = scf_entry_add_value(e, v);
13444 			assert(ret == SCF_SUCCESS);
13445 		} else {
13446 			assert(values != NULL);
13447 
13448 			walk = uu_list_walk_start((uu_list_t *)values,
13449 			    UU_DEFAULT);
13450 			if (walk == NULL)
13451 				uu_die(gettext("Could not walk list"));
13452 
13453 			for (sp = uu_list_walk_next(walk); sp != NULL;
13454 			    sp = uu_list_walk_next(walk)) {
13455 				v = string_to_value(sp->str, ty, req_quotes);
13456 
13457 				if (v == NULL) {
13458 					scf_entry_destroy_children(e);
13459 					goto fail;
13460 				}
13461 
13462 				ret = scf_entry_add_value(e, v);
13463 				assert(ret == SCF_SUCCESS);
13464 			}
13465 			uu_list_walk_end(walk);
13466 		}
13467 		result = scf_transaction_commit(tx);
13468 
13469 		scf_transaction_reset(tx);
13470 		scf_entry_destroy_children(e);
13471 	} while (result == 0);
13472 
13473 	if (result < 0) {
13474 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13475 			scfdie();
13476 
13477 		semerr(emsg_permission_denied);
13478 		goto fail;
13479 	}
13480 
13481 	ret = 0;
13482 
13483 	private_refresh();
13484 
13485 	goto cleanup;
13486 
13487 fail:
13488 	ret = -1;
13489 
13490 cleanup:
13491 	scf_transaction_destroy(tx);
13492 	scf_entry_destroy(e);
13493 	scf_service_destroy(svc);
13494 	scf_pg_destroy(parent_pg);
13495 	scf_pg_destroy(pg);
13496 	scf_property_destroy(parent_prop);
13497 	scf_property_destroy(prop);
13498 	scf_tmpl_pg_destroy(pgt);
13499 	scf_tmpl_prop_destroy(prt);
13500 
13501 	return (ret);
13502 }
13503 
13504 void
13505 lscf_delprop(char *pgn)
13506 {
13507 	char *slash, *pn;
13508 	scf_propertygroup_t *pg;
13509 	scf_transaction_t *tx;
13510 	scf_transaction_entry_t *e;
13511 	int ret;
13512 
13513 
13514 	lscf_prep_hndl();
13515 
13516 	if (cur_snap != NULL) {
13517 		semerr(emsg_cant_modify_snapshots);
13518 		return;
13519 	}
13520 
13521 	if (cur_inst == NULL && cur_svc == NULL) {
13522 		semerr(emsg_entity_not_selected);
13523 		return;
13524 	}
13525 
13526 	pg = scf_pg_create(g_hndl);
13527 	if (pg == NULL)
13528 		scfdie();
13529 
13530 	slash = strchr(pgn, '/');
13531 	if (slash == NULL) {
13532 		pn = NULL;
13533 	} else {
13534 		*slash = '\0';
13535 		pn = slash + 1;
13536 	}
13537 
13538 	if (cur_inst != NULL)
13539 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
13540 	else
13541 		ret = scf_service_get_pg(cur_svc, pgn, pg);
13542 	if (ret != SCF_SUCCESS) {
13543 		switch (scf_error()) {
13544 		case SCF_ERROR_NOT_FOUND:
13545 			semerr(emsg_no_such_pg, pgn);
13546 			break;
13547 
13548 		case SCF_ERROR_INVALID_ARGUMENT:
13549 			semerr(emsg_invalid_pg_name, pgn);
13550 			break;
13551 
13552 		default:
13553 			scfdie();
13554 		}
13555 
13556 		scf_pg_destroy(pg);
13557 
13558 		return;
13559 	}
13560 
13561 	if (pn == NULL) {
13562 		/* Try to delete the property group. */
13563 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
13564 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13565 				scfdie();
13566 
13567 			semerr(emsg_permission_denied);
13568 		} else {
13569 			private_refresh();
13570 		}
13571 
13572 		scf_pg_destroy(pg);
13573 		return;
13574 	}
13575 
13576 	e = scf_entry_create(g_hndl);
13577 	tx = scf_transaction_create(g_hndl);
13578 
13579 	do {
13580 		if (scf_pg_update(pg) == -1)
13581 			scfdie();
13582 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13583 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13584 				scfdie();
13585 
13586 			semerr(emsg_permission_denied);
13587 			break;
13588 		}
13589 
13590 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
13591 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
13592 				semerr(gettext("No such property %s/%s.\n"),
13593 				    pgn, pn);
13594 				break;
13595 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13596 				semerr(emsg_invalid_prop_name, pn);
13597 				break;
13598 			} else {
13599 				scfdie();
13600 			}
13601 		}
13602 
13603 		ret = scf_transaction_commit(tx);
13604 
13605 		if (ret == 0)
13606 			scf_transaction_reset(tx);
13607 	} while (ret == 0);
13608 
13609 	if (ret < 0) {
13610 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13611 			scfdie();
13612 
13613 		semerr(emsg_permission_denied);
13614 	} else {
13615 		private_refresh();
13616 	}
13617 
13618 	scf_transaction_destroy(tx);
13619 	scf_entry_destroy(e);
13620 	scf_pg_destroy(pg);
13621 }
13622 
13623 /*
13624  * Property editing.
13625  */
13626 
13627 static int
13628 write_edit_script(FILE *strm)
13629 {
13630 	char *fmribuf;
13631 	ssize_t fmrilen;
13632 
13633 	scf_propertygroup_t *pg;
13634 	scf_property_t *prop;
13635 	scf_value_t *val;
13636 	scf_type_t ty;
13637 	int ret, result = 0;
13638 	scf_iter_t *iter, *piter, *viter;
13639 	char *buf, *tybuf, *pname;
13640 	const char *emsg_write_error;
13641 
13642 
13643 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
13644 
13645 
13646 	/* select fmri */
13647 	if (cur_inst != NULL) {
13648 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
13649 		if (fmrilen < 0)
13650 			scfdie();
13651 		fmribuf = safe_malloc(fmrilen + 1);
13652 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
13653 			scfdie();
13654 	} else {
13655 		assert(cur_svc != NULL);
13656 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
13657 		if (fmrilen < 0)
13658 			scfdie();
13659 		fmribuf = safe_malloc(fmrilen + 1);
13660 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
13661 			scfdie();
13662 	}
13663 
13664 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
13665 		warn(emsg_write_error, strerror(errno));
13666 		free(fmribuf);
13667 		return (-1);
13668 	}
13669 
13670 	free(fmribuf);
13671 
13672 
13673 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13674 	    (prop = scf_property_create(g_hndl)) == NULL ||
13675 	    (val = scf_value_create(g_hndl)) == NULL ||
13676 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13677 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13678 	    (viter = scf_iter_create(g_hndl)) == NULL)
13679 		scfdie();
13680 
13681 	buf = safe_malloc(max_scf_name_len + 1);
13682 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
13683 	pname = safe_malloc(max_scf_name_len + 1);
13684 
13685 	if (cur_inst != NULL)
13686 		ret = scf_iter_instance_pgs(iter, cur_inst);
13687 	else
13688 		ret = scf_iter_service_pgs(iter, cur_svc);
13689 	if (ret != SCF_SUCCESS)
13690 		scfdie();
13691 
13692 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13693 		int ret2;
13694 
13695 		/*
13696 		 * # delprop pg
13697 		 * # addpg pg type
13698 		 */
13699 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
13700 			scfdie();
13701 
13702 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
13703 			scfdie();
13704 
13705 		if (fprintf(strm, "# Property group \"%s\"\n"
13706 		    "# delprop %s\n"
13707 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
13708 			warn(emsg_write_error, strerror(errno));
13709 			result = -1;
13710 			goto out;
13711 		}
13712 
13713 		/* # setprop pg/prop = (values) */
13714 
13715 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13716 			scfdie();
13717 
13718 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
13719 			int first = 1;
13720 			int ret3;
13721 			int multiple;
13722 			int is_str;
13723 			scf_type_t bty;
13724 
13725 			if (scf_property_get_name(prop, pname,
13726 			    max_scf_name_len + 1) < 0)
13727 				scfdie();
13728 
13729 			if (scf_property_type(prop, &ty) != 0)
13730 				scfdie();
13731 
13732 			multiple = prop_has_multiple_values(prop, val);
13733 
13734 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13735 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
13736 			    < 0) {
13737 				warn(emsg_write_error, strerror(errno));
13738 				result = -1;
13739 				goto out;
13740 			}
13741 
13742 			(void) scf_type_base_type(ty, &bty);
13743 			is_str = (bty == SCF_TYPE_ASTRING);
13744 
13745 			if (scf_iter_property_values(viter, prop) !=
13746 			    SCF_SUCCESS)
13747 				scfdie();
13748 
13749 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
13750 				char *buf;
13751 				ssize_t buflen;
13752 
13753 				buflen = scf_value_get_as_string(val, NULL, 0);
13754 				if (buflen < 0)
13755 					scfdie();
13756 
13757 				buf = safe_malloc(buflen + 1);
13758 
13759 				if (scf_value_get_as_string(val, buf,
13760 				    buflen + 1) < 0)
13761 					scfdie();
13762 
13763 				if (first)
13764 					first = 0;
13765 				else {
13766 					if (putc(' ', strm) != ' ') {
13767 						warn(emsg_write_error,
13768 						    strerror(errno));
13769 						result = -1;
13770 						goto out;
13771 					}
13772 				}
13773 
13774 				if ((is_str && multiple) ||
13775 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
13776 					(void) putc('"', strm);
13777 					(void) quote_and_print(buf, strm, 1);
13778 					(void) putc('"', strm);
13779 
13780 					if (ferror(strm)) {
13781 						warn(emsg_write_error,
13782 						    strerror(errno));
13783 						result = -1;
13784 						goto out;
13785 					}
13786 				} else {
13787 					if (fprintf(strm, "%s", buf) < 0) {
13788 						warn(emsg_write_error,
13789 						    strerror(errno));
13790 						result = -1;
13791 						goto out;
13792 					}
13793 				}
13794 
13795 				free(buf);
13796 			}
13797 			if (ret3 < 0 &&
13798 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
13799 				scfdie();
13800 
13801 			/* Write closing paren if mult-value property */
13802 			if ((multiple && putc(')', strm) == EOF) ||
13803 
13804 			    /* Write final newline */
13805 			    fputc('\n', strm) == EOF) {
13806 				warn(emsg_write_error, strerror(errno));
13807 				result = -1;
13808 				goto out;
13809 			}
13810 		}
13811 		if (ret2 < 0)
13812 			scfdie();
13813 
13814 		if (fputc('\n', strm) == EOF) {
13815 			warn(emsg_write_error, strerror(errno));
13816 			result = -1;
13817 			goto out;
13818 		}
13819 	}
13820 	if (ret < 0)
13821 		scfdie();
13822 
13823 out:
13824 	free(pname);
13825 	free(tybuf);
13826 	free(buf);
13827 	scf_iter_destroy(viter);
13828 	scf_iter_destroy(piter);
13829 	scf_iter_destroy(iter);
13830 	scf_value_destroy(val);
13831 	scf_property_destroy(prop);
13832 	scf_pg_destroy(pg);
13833 
13834 	if (result == 0) {
13835 		if (fflush(strm) != 0) {
13836 			warn(emsg_write_error, strerror(errno));
13837 			return (-1);
13838 		}
13839 	}
13840 
13841 	return (result);
13842 }
13843 
13844 int
13845 lscf_editprop()
13846 {
13847 	char *buf, *editor;
13848 	size_t bufsz;
13849 	int tmpfd;
13850 	char tempname[] = TEMP_FILE_PATTERN;
13851 
13852 	lscf_prep_hndl();
13853 
13854 	if (cur_snap != NULL) {
13855 		semerr(emsg_cant_modify_snapshots);
13856 		return (-1);
13857 	}
13858 
13859 	if (cur_svc == NULL && cur_inst == NULL) {
13860 		semerr(emsg_entity_not_selected);
13861 		return (-1);
13862 	}
13863 
13864 	tmpfd = mkstemp(tempname);
13865 	if (tmpfd == -1) {
13866 		semerr(gettext("Could not create temporary file.\n"));
13867 		return (-1);
13868 	}
13869 
13870 	(void) strcpy(tempfilename, tempname);
13871 
13872 	tempfile = fdopen(tmpfd, "r+");
13873 	if (tempfile == NULL) {
13874 		warn(gettext("Could not create temporary file.\n"));
13875 		if (close(tmpfd) == -1)
13876 			warn(gettext("Could not close temporary file: %s.\n"),
13877 			    strerror(errno));
13878 
13879 		remove_tempfile();
13880 
13881 		return (-1);
13882 	}
13883 
13884 	if (write_edit_script(tempfile) == -1) {
13885 		remove_tempfile();
13886 		return (-1);
13887 	}
13888 
13889 	editor = getenv("EDITOR");
13890 	if (editor == NULL)
13891 		editor = "vi";
13892 
13893 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
13894 	buf = safe_malloc(bufsz);
13895 
13896 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
13897 		uu_die(gettext("Error creating editor command"));
13898 
13899 	if (system(buf) == -1) {
13900 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
13901 		    strerror(errno));
13902 		free(buf);
13903 		remove_tempfile();
13904 		return (-1);
13905 	}
13906 
13907 	free(buf);
13908 
13909 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
13910 
13911 	remove_tempfile();
13912 
13913 	return (0);
13914 }
13915 
13916 static void
13917 add_string(uu_list_t *strlist, const char *str)
13918 {
13919 	string_list_t *elem;
13920 	elem = safe_malloc(sizeof (*elem));
13921 	uu_list_node_init(elem, &elem->node, string_pool);
13922 	elem->str = safe_strdup(str);
13923 	if (uu_list_append(strlist, elem) != 0)
13924 		uu_die(gettext("libuutil error: %s\n"),
13925 		    uu_strerror(uu_error()));
13926 }
13927 
13928 static int
13929 remove_string(uu_list_t *strlist, const char *str)
13930 {
13931 	uu_list_walk_t	*elems;
13932 	string_list_t	*sp;
13933 
13934 	/*
13935 	 * Find the element that needs to be removed.
13936 	 */
13937 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
13938 	while ((sp = uu_list_walk_next(elems)) != NULL) {
13939 		if (strcmp(sp->str, str) == 0)
13940 			break;
13941 	}
13942 	uu_list_walk_end(elems);
13943 
13944 	/*
13945 	 * Returning 1 here as the value was not found, this
13946 	 * might not be an error.  Leave it to the caller to
13947 	 * decide.
13948 	 */
13949 	if (sp == NULL) {
13950 		return (1);
13951 	}
13952 
13953 	uu_list_remove(strlist, sp);
13954 
13955 	free(sp->str);
13956 	free(sp);
13957 
13958 	return (0);
13959 }
13960 
13961 /*
13962  * Get all property values that don't match the given glob pattern,
13963  * if a pattern is specified.
13964  */
13965 static void
13966 get_prop_values(scf_property_t *prop, uu_list_t *values,
13967     const char *pattern)
13968 {
13969 	scf_iter_t *iter;
13970 	scf_value_t *val;
13971 	int ret;
13972 
13973 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13974 	    (val = scf_value_create(g_hndl)) == NULL)
13975 		scfdie();
13976 
13977 	if (scf_iter_property_values(iter, prop) != 0)
13978 		scfdie();
13979 
13980 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13981 		char *buf;
13982 		ssize_t vlen, szret;
13983 
13984 		vlen = scf_value_get_as_string(val, NULL, 0);
13985 		if (vlen < 0)
13986 			scfdie();
13987 
13988 		buf = safe_malloc(vlen + 1);
13989 
13990 		szret = scf_value_get_as_string(val, buf, vlen + 1);
13991 		if (szret < 0)
13992 			scfdie();
13993 		assert(szret <= vlen);
13994 
13995 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
13996 			add_string(values, buf);
13997 
13998 		free(buf);
13999 	}
14000 
14001 	if (ret == -1)
14002 		scfdie();
14003 
14004 	scf_value_destroy(val);
14005 	scf_iter_destroy(iter);
14006 }
14007 
14008 static int
14009 lscf_setpropvalue(const char *pgname, const char *type,
14010     const char *arg, int isadd, int isnotfoundok)
14011 {
14012 	scf_type_t ty;
14013 	scf_propertygroup_t *pg;
14014 	scf_property_t *prop;
14015 	int ret, result = 0;
14016 	scf_transaction_t *tx;
14017 	scf_transaction_entry_t *e;
14018 	scf_value_t *v;
14019 	string_list_t *sp;
14020 	char *propname;
14021 	uu_list_t *values;
14022 	uu_list_walk_t *walk;
14023 	void *cookie = NULL;
14024 	char *pattern = NULL;
14025 
14026 	lscf_prep_hndl();
14027 
14028 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14029 		uu_die(gettext("Could not create property list: %s\n"),
14030 		    uu_strerror(uu_error()));
14031 
14032 	if (!isadd)
14033 		pattern = safe_strdup(arg);
14034 
14035 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14036 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14037 	    (prop = scf_property_create(g_hndl)) == NULL ||
14038 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14039 		scfdie();
14040 
14041 	if (cur_snap != NULL) {
14042 		semerr(emsg_cant_modify_snapshots);
14043 		goto fail;
14044 	}
14045 
14046 	if (cur_inst == NULL && cur_svc == NULL) {
14047 		semerr(emsg_entity_not_selected);
14048 		goto fail;
14049 	}
14050 
14051 	propname = strchr(pgname, '/');
14052 	if (propname == NULL) {
14053 		semerr(gettext("Property names must contain a `/'.\n"));
14054 		goto fail;
14055 	}
14056 
14057 	*propname = '\0';
14058 	++propname;
14059 
14060 	if (type != NULL) {
14061 		ty = string_to_type(type);
14062 		if (ty == SCF_TYPE_INVALID) {
14063 			semerr(gettext("Unknown type \"%s\".\n"), type);
14064 			goto fail;
14065 		}
14066 	}
14067 
14068 	if (cur_inst != NULL)
14069 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14070 	else
14071 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14072 	if (ret != 0) {
14073 		switch (scf_error()) {
14074 		case SCF_ERROR_NOT_FOUND:
14075 			if (isnotfoundok) {
14076 				result = 0;
14077 			} else {
14078 				semerr(emsg_no_such_pg, pgname);
14079 				result = -1;
14080 			}
14081 			goto out;
14082 
14083 		case SCF_ERROR_INVALID_ARGUMENT:
14084 			semerr(emsg_invalid_pg_name, pgname);
14085 			goto fail;
14086 
14087 		default:
14088 			scfdie();
14089 		}
14090 	}
14091 
14092 	do {
14093 		if (scf_pg_update(pg) == -1)
14094 			scfdie();
14095 		if (scf_transaction_start(tx, pg) != 0) {
14096 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14097 				scfdie();
14098 
14099 			semerr(emsg_permission_denied);
14100 			goto fail;
14101 		}
14102 
14103 		ret = scf_pg_get_property(pg, propname, prop);
14104 		if (ret == 0) {
14105 			scf_type_t ptype;
14106 			char *pat = pattern;
14107 
14108 			if (scf_property_type(prop, &ptype) != 0)
14109 				scfdie();
14110 
14111 			if (isadd) {
14112 				if (type != NULL && ptype != ty) {
14113 					semerr(gettext("Property \"%s\" is not "
14114 					    "of type \"%s\".\n"), propname,
14115 					    type);
14116 					goto fail;
14117 				}
14118 
14119 				pat = NULL;
14120 			} else {
14121 				size_t len = strlen(pat);
14122 				if (len > 0 && pat[len - 1] == '\"')
14123 					pat[len - 1] = '\0';
14124 				if (len > 0 && pat[0] == '\"')
14125 					pat++;
14126 			}
14127 
14128 			ty = ptype;
14129 
14130 			get_prop_values(prop, values, pat);
14131 
14132 			if (isadd)
14133 				add_string(values, arg);
14134 
14135 			if (scf_transaction_property_change(tx, e,
14136 			    propname, ty) == -1)
14137 				scfdie();
14138 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14139 			if (isadd) {
14140 				if (type == NULL) {
14141 					semerr(gettext("Type required "
14142 					    "for new properties.\n"));
14143 					goto fail;
14144 				}
14145 
14146 				add_string(values, arg);
14147 
14148 				if (scf_transaction_property_new(tx, e,
14149 				    propname, ty) == -1)
14150 					scfdie();
14151 			} else if (isnotfoundok) {
14152 				result = 0;
14153 				goto out;
14154 			} else {
14155 				semerr(gettext("No such property %s/%s.\n"),
14156 				    pgname, propname);
14157 				result = -1;
14158 				goto out;
14159 			}
14160 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14161 			semerr(emsg_invalid_prop_name, propname);
14162 			goto fail;
14163 		} else {
14164 			scfdie();
14165 		}
14166 
14167 		walk = uu_list_walk_start(values, UU_DEFAULT);
14168 		if (walk == NULL)
14169 			uu_die(gettext("Could not walk property list.\n"));
14170 
14171 		for (sp = uu_list_walk_next(walk); sp != NULL;
14172 		    sp = uu_list_walk_next(walk)) {
14173 			v = string_to_value(sp->str, ty, 0);
14174 
14175 			if (v == NULL) {
14176 				scf_entry_destroy_children(e);
14177 				goto fail;
14178 			}
14179 			ret = scf_entry_add_value(e, v);
14180 			assert(ret == 0);
14181 		}
14182 		uu_list_walk_end(walk);
14183 
14184 		result = scf_transaction_commit(tx);
14185 
14186 		scf_transaction_reset(tx);
14187 		scf_entry_destroy_children(e);
14188 	} while (result == 0);
14189 
14190 	if (result < 0) {
14191 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14192 			scfdie();
14193 
14194 		semerr(emsg_permission_denied);
14195 		goto fail;
14196 	}
14197 
14198 	result = 0;
14199 
14200 	private_refresh();
14201 
14202 out:
14203 	scf_transaction_destroy(tx);
14204 	scf_entry_destroy(e);
14205 	scf_pg_destroy(pg);
14206 	scf_property_destroy(prop);
14207 	free(pattern);
14208 
14209 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14210 		free(sp->str);
14211 		free(sp);
14212 	}
14213 
14214 	uu_list_destroy(values);
14215 
14216 	return (result);
14217 
14218 fail:
14219 	result = -1;
14220 	goto out;
14221 }
14222 
14223 int
14224 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14225 {
14226 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14227 }
14228 
14229 int
14230 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14231 {
14232 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14233 }
14234 
14235 /*
14236  * Look for a standard start method, first in the instance (if any),
14237  * then the service.
14238  */
14239 static const char *
14240 start_method_name(int *in_instance)
14241 {
14242 	scf_propertygroup_t *pg;
14243 	char **p;
14244 	int ret;
14245 	scf_instance_t *inst = cur_inst;
14246 
14247 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14248 		scfdie();
14249 
14250 again:
14251 	for (p = start_method_names; *p != NULL; p++) {
14252 		if (inst != NULL)
14253 			ret = scf_instance_get_pg(inst, *p, pg);
14254 		else
14255 			ret = scf_service_get_pg(cur_svc, *p, pg);
14256 
14257 		if (ret == 0) {
14258 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14259 			char *buf = safe_malloc(bufsz);
14260 
14261 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14262 				free(buf);
14263 				continue;
14264 			}
14265 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14266 				free(buf);
14267 				continue;
14268 			}
14269 
14270 			free(buf);
14271 			*in_instance = (inst != NULL);
14272 			scf_pg_destroy(pg);
14273 			return (*p);
14274 		}
14275 
14276 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14277 			continue;
14278 
14279 		scfdie();
14280 	}
14281 
14282 	if (inst != NULL) {
14283 		inst = NULL;
14284 		goto again;
14285 	}
14286 
14287 	scf_pg_destroy(pg);
14288 	return (NULL);
14289 }
14290 
14291 static int
14292 addpg(const char *name, const char *type)
14293 {
14294 	scf_propertygroup_t *pg;
14295 	int ret;
14296 
14297 	pg = scf_pg_create(g_hndl);
14298 	if (pg == NULL)
14299 		scfdie();
14300 
14301 	if (cur_inst != NULL)
14302 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14303 	else
14304 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14305 
14306 	if (ret != 0) {
14307 		switch (scf_error()) {
14308 		case SCF_ERROR_EXISTS:
14309 			ret = 0;
14310 			break;
14311 
14312 		case SCF_ERROR_PERMISSION_DENIED:
14313 			semerr(emsg_permission_denied);
14314 			break;
14315 
14316 		default:
14317 			scfdie();
14318 		}
14319 	}
14320 
14321 	scf_pg_destroy(pg);
14322 	return (ret);
14323 }
14324 
14325 int
14326 lscf_setenv(uu_list_t *args, int isunset)
14327 {
14328 	int ret = 0;
14329 	size_t i;
14330 	int argc;
14331 	char **argv = NULL;
14332 	string_list_t *slp;
14333 	char *pattern;
14334 	char *prop;
14335 	int do_service = 0;
14336 	int do_instance = 0;
14337 	const char *method = NULL;
14338 	const char *name = NULL;
14339 	const char *value = NULL;
14340 	scf_instance_t *saved_cur_inst = cur_inst;
14341 
14342 	lscf_prep_hndl();
14343 
14344 	argc = uu_list_numnodes(args);
14345 	if (argc < 1)
14346 		goto usage;
14347 
14348 	argv = calloc(argc + 1, sizeof (char *));
14349 	if (argv == NULL)
14350 		uu_die(gettext("Out of memory.\n"));
14351 
14352 	for (slp = uu_list_first(args), i = 0;
14353 	    slp != NULL;
14354 	    slp = uu_list_next(args, slp), ++i)
14355 		argv[i] = slp->str;
14356 
14357 	argv[i] = NULL;
14358 
14359 	opterr = 0;
14360 	optind = 0;
14361 	for (;;) {
14362 		ret = getopt(argc, argv, "sim:");
14363 		if (ret == -1)
14364 			break;
14365 
14366 		switch (ret) {
14367 		case 's':
14368 			do_service = 1;
14369 			cur_inst = NULL;
14370 			break;
14371 
14372 		case 'i':
14373 			do_instance = 1;
14374 			break;
14375 
14376 		case 'm':
14377 			method = optarg;
14378 			break;
14379 
14380 		case '?':
14381 			goto usage;
14382 
14383 		default:
14384 			bad_error("getopt", ret);
14385 		}
14386 	}
14387 
14388 	argc -= optind;
14389 	if ((do_service && do_instance) ||
14390 	    (isunset && argc != 1) ||
14391 	    (!isunset && argc != 2))
14392 		goto usage;
14393 
14394 	name = argv[optind];
14395 	if (!isunset)
14396 		value = argv[optind + 1];
14397 
14398 	if (cur_snap != NULL) {
14399 		semerr(emsg_cant_modify_snapshots);
14400 		ret = -1;
14401 		goto out;
14402 	}
14403 
14404 	if (cur_inst == NULL && cur_svc == NULL) {
14405 		semerr(emsg_entity_not_selected);
14406 		ret = -1;
14407 		goto out;
14408 	}
14409 
14410 	if (do_instance && cur_inst == NULL) {
14411 		semerr(gettext("No instance is selected.\n"));
14412 		ret = -1;
14413 		goto out;
14414 	}
14415 
14416 	if (do_service && cur_svc == NULL) {
14417 		semerr(gettext("No service is selected.\n"));
14418 		ret = -1;
14419 		goto out;
14420 	}
14421 
14422 	if (method == NULL) {
14423 		if (do_instance || do_service) {
14424 			method = "method_context";
14425 			if (!isunset) {
14426 				ret = addpg("method_context",
14427 				    SCF_GROUP_FRAMEWORK);
14428 				if (ret != 0)
14429 					goto out;
14430 			}
14431 		} else {
14432 			int in_instance;
14433 			method = start_method_name(&in_instance);
14434 			if (method == NULL) {
14435 				semerr(gettext(
14436 				    "Couldn't find start method; please "
14437 				    "specify a method with '-m'.\n"));
14438 				ret = -1;
14439 				goto out;
14440 			}
14441 			if (!in_instance)
14442 				cur_inst = NULL;
14443 		}
14444 	} else {
14445 		scf_propertygroup_t *pg;
14446 		size_t bufsz;
14447 		char *buf;
14448 		int ret;
14449 
14450 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14451 			scfdie();
14452 
14453 		if (cur_inst != NULL)
14454 			ret = scf_instance_get_pg(cur_inst, method, pg);
14455 		else
14456 			ret = scf_service_get_pg(cur_svc, method, pg);
14457 
14458 		if (ret != 0) {
14459 			scf_pg_destroy(pg);
14460 			switch (scf_error()) {
14461 			case SCF_ERROR_NOT_FOUND:
14462 				semerr(gettext("Couldn't find the method "
14463 				    "\"%s\".\n"), method);
14464 				goto out;
14465 
14466 			case SCF_ERROR_INVALID_ARGUMENT:
14467 				semerr(gettext("Invalid method name \"%s\".\n"),
14468 				    method);
14469 				goto out;
14470 
14471 			default:
14472 				scfdie();
14473 			}
14474 		}
14475 
14476 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
14477 		buf = safe_malloc(bufsz);
14478 
14479 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14480 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
14481 			semerr(gettext("Property group \"%s\" is not of type "
14482 			    "\"method\".\n"), method);
14483 			ret = -1;
14484 			free(buf);
14485 			scf_pg_destroy(pg);
14486 			goto out;
14487 		}
14488 
14489 		free(buf);
14490 		scf_pg_destroy(pg);
14491 	}
14492 
14493 	prop = uu_msprintf("%s/environment", method);
14494 	pattern = uu_msprintf("%s=*", name);
14495 
14496 	if (prop == NULL || pattern == NULL)
14497 		uu_die(gettext("Out of memory.\n"));
14498 
14499 	ret = lscf_delpropvalue(prop, pattern, !isunset);
14500 
14501 	if (ret == 0 && !isunset) {
14502 		uu_free(pattern);
14503 		uu_free(prop);
14504 		prop = uu_msprintf("%s/environment", method);
14505 		pattern = uu_msprintf("%s=%s", name, value);
14506 		if (prop == NULL || pattern == NULL)
14507 			uu_die(gettext("Out of memory.\n"));
14508 		ret = lscf_addpropvalue(prop, "astring:", pattern);
14509 	}
14510 	uu_free(pattern);
14511 	uu_free(prop);
14512 
14513 out:
14514 	cur_inst = saved_cur_inst;
14515 
14516 	free(argv);
14517 	return (ret);
14518 usage:
14519 	ret = -2;
14520 	goto out;
14521 }
14522 
14523 /*
14524  * Snapshot commands
14525  */
14526 
14527 void
14528 lscf_listsnap()
14529 {
14530 	scf_snapshot_t *snap;
14531 	scf_iter_t *iter;
14532 	char *nb;
14533 	int r;
14534 
14535 	lscf_prep_hndl();
14536 
14537 	if (cur_inst == NULL) {
14538 		semerr(gettext("Instance not selected.\n"));
14539 		return;
14540 	}
14541 
14542 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14543 	    (iter = scf_iter_create(g_hndl)) == NULL)
14544 		scfdie();
14545 
14546 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
14547 		scfdie();
14548 
14549 	nb = safe_malloc(max_scf_name_len + 1);
14550 
14551 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
14552 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
14553 			scfdie();
14554 
14555 		(void) puts(nb);
14556 	}
14557 	if (r < 0)
14558 		scfdie();
14559 
14560 	free(nb);
14561 	scf_iter_destroy(iter);
14562 	scf_snapshot_destroy(snap);
14563 }
14564 
14565 void
14566 lscf_selectsnap(const char *name)
14567 {
14568 	scf_snapshot_t *snap;
14569 	scf_snaplevel_t *level;
14570 
14571 	lscf_prep_hndl();
14572 
14573 	if (cur_inst == NULL) {
14574 		semerr(gettext("Instance not selected.\n"));
14575 		return;
14576 	}
14577 
14578 	if (cur_snap != NULL) {
14579 		if (name != NULL) {
14580 			char *cur_snap_name;
14581 			boolean_t nochange;
14582 
14583 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
14584 
14585 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
14586 			    max_scf_name_len + 1) < 0)
14587 				scfdie();
14588 
14589 			nochange = strcmp(name, cur_snap_name) == 0;
14590 
14591 			free(cur_snap_name);
14592 
14593 			if (nochange)
14594 				return;
14595 		}
14596 
14597 		unselect_cursnap();
14598 	}
14599 
14600 	if (name == NULL)
14601 		return;
14602 
14603 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14604 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
14605 		scfdie();
14606 
14607 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
14608 	    SCF_SUCCESS) {
14609 		switch (scf_error()) {
14610 		case SCF_ERROR_INVALID_ARGUMENT:
14611 			semerr(gettext("Invalid name \"%s\".\n"), name);
14612 			break;
14613 
14614 		case SCF_ERROR_NOT_FOUND:
14615 			semerr(gettext("No such snapshot \"%s\".\n"), name);
14616 			break;
14617 
14618 		default:
14619 			scfdie();
14620 		}
14621 
14622 		scf_snaplevel_destroy(level);
14623 		scf_snapshot_destroy(snap);
14624 		return;
14625 	}
14626 
14627 	/* Load the snaplevels into our list. */
14628 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
14629 	if (cur_levels == NULL)
14630 		uu_die(gettext("Could not create list: %s\n"),
14631 		    uu_strerror(uu_error()));
14632 
14633 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14634 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14635 			scfdie();
14636 
14637 		semerr(gettext("Snapshot has no snaplevels.\n"));
14638 
14639 		scf_snaplevel_destroy(level);
14640 		scf_snapshot_destroy(snap);
14641 		return;
14642 	}
14643 
14644 	cur_snap = snap;
14645 
14646 	for (;;) {
14647 		cur_elt = safe_malloc(sizeof (*cur_elt));
14648 		uu_list_node_init(cur_elt, &cur_elt->list_node,
14649 		    snaplevel_pool);
14650 		cur_elt->sl = level;
14651 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
14652 			uu_die(gettext("libuutil error: %s\n"),
14653 			    uu_strerror(uu_error()));
14654 
14655 		level = scf_snaplevel_create(g_hndl);
14656 		if (level == NULL)
14657 			scfdie();
14658 
14659 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
14660 		    level) != SCF_SUCCESS) {
14661 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14662 				scfdie();
14663 
14664 			scf_snaplevel_destroy(level);
14665 			break;
14666 		}
14667 	}
14668 
14669 	cur_elt = uu_list_last(cur_levels);
14670 	cur_level = cur_elt->sl;
14671 }
14672 
14673 /*
14674  * Copies the properties & values in src to dst.  Assumes src won't change.
14675  * Returns -1 if permission is denied, -2 if another transaction interrupts,
14676  * and 0 on success.
14677  *
14678  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
14679  * property, if it is copied and has type boolean.  (See comment in
14680  * lscf_revert()).
14681  */
14682 static int
14683 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
14684     uint8_t enabled)
14685 {
14686 	scf_transaction_t *tx;
14687 	scf_iter_t *iter, *viter;
14688 	scf_property_t *prop;
14689 	scf_value_t *v;
14690 	char *nbuf;
14691 	int r;
14692 
14693 	tx = scf_transaction_create(g_hndl);
14694 	if (tx == NULL)
14695 		scfdie();
14696 
14697 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
14698 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14699 			scfdie();
14700 
14701 		scf_transaction_destroy(tx);
14702 
14703 		return (-1);
14704 	}
14705 
14706 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14707 	    (prop = scf_property_create(g_hndl)) == NULL ||
14708 	    (viter = scf_iter_create(g_hndl)) == NULL)
14709 		scfdie();
14710 
14711 	nbuf = safe_malloc(max_scf_name_len + 1);
14712 
14713 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
14714 		scfdie();
14715 
14716 	for (;;) {
14717 		scf_transaction_entry_t *e;
14718 		scf_type_t ty;
14719 
14720 		r = scf_iter_next_property(iter, prop);
14721 		if (r == -1)
14722 			scfdie();
14723 		if (r == 0)
14724 			break;
14725 
14726 		e = scf_entry_create(g_hndl);
14727 		if (e == NULL)
14728 			scfdie();
14729 
14730 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14731 			scfdie();
14732 
14733 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14734 			scfdie();
14735 
14736 		if (scf_transaction_property_new(tx, e, nbuf,
14737 		    ty) != SCF_SUCCESS)
14738 			scfdie();
14739 
14740 		if ((enabled == 0 || enabled == 1) &&
14741 		    strcmp(nbuf, scf_property_enabled) == 0 &&
14742 		    ty == SCF_TYPE_BOOLEAN) {
14743 			v = scf_value_create(g_hndl);
14744 			if (v == NULL)
14745 				scfdie();
14746 
14747 			scf_value_set_boolean(v, enabled);
14748 
14749 			if (scf_entry_add_value(e, v) != 0)
14750 				scfdie();
14751 		} else {
14752 			if (scf_iter_property_values(viter, prop) != 0)
14753 				scfdie();
14754 
14755 			for (;;) {
14756 				v = scf_value_create(g_hndl);
14757 				if (v == NULL)
14758 					scfdie();
14759 
14760 				r = scf_iter_next_value(viter, v);
14761 				if (r == -1)
14762 					scfdie();
14763 				if (r == 0) {
14764 					scf_value_destroy(v);
14765 					break;
14766 				}
14767 
14768 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14769 					scfdie();
14770 			}
14771 		}
14772 	}
14773 
14774 	free(nbuf);
14775 	scf_iter_destroy(viter);
14776 	scf_property_destroy(prop);
14777 	scf_iter_destroy(iter);
14778 
14779 	r = scf_transaction_commit(tx);
14780 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
14781 		scfdie();
14782 
14783 	scf_transaction_destroy_children(tx);
14784 	scf_transaction_destroy(tx);
14785 
14786 	switch (r) {
14787 	case 1:		return (0);
14788 	case 0:		return (-2);
14789 	case -1:	return (-1);
14790 
14791 	default:
14792 		abort();
14793 	}
14794 
14795 	/* NOTREACHED */
14796 }
14797 
14798 void
14799 lscf_revert(const char *snapname)
14800 {
14801 	scf_snapshot_t *snap, *prev;
14802 	scf_snaplevel_t *level, *nlevel;
14803 	scf_iter_t *iter;
14804 	scf_propertygroup_t *pg, *npg;
14805 	scf_property_t *prop;
14806 	scf_value_t *val;
14807 	char *nbuf, *tbuf;
14808 	uint8_t enabled;
14809 
14810 	lscf_prep_hndl();
14811 
14812 	if (cur_inst == NULL) {
14813 		semerr(gettext("Instance not selected.\n"));
14814 		return;
14815 	}
14816 
14817 	if (snapname != NULL) {
14818 		snap = scf_snapshot_create(g_hndl);
14819 		if (snap == NULL)
14820 			scfdie();
14821 
14822 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
14823 		    SCF_SUCCESS) {
14824 			switch (scf_error()) {
14825 			case SCF_ERROR_INVALID_ARGUMENT:
14826 				semerr(gettext("Invalid snapshot name "
14827 				    "\"%s\".\n"), snapname);
14828 				break;
14829 
14830 			case SCF_ERROR_NOT_FOUND:
14831 				semerr(gettext("No such snapshot.\n"));
14832 				break;
14833 
14834 			default:
14835 				scfdie();
14836 			}
14837 
14838 			scf_snapshot_destroy(snap);
14839 			return;
14840 		}
14841 	} else {
14842 		if (cur_snap != NULL) {
14843 			snap = cur_snap;
14844 		} else {
14845 			semerr(gettext("No snapshot selected.\n"));
14846 			return;
14847 		}
14848 	}
14849 
14850 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
14851 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
14852 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14853 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14854 	    (npg = scf_pg_create(g_hndl)) == NULL ||
14855 	    (prop = scf_property_create(g_hndl)) == NULL ||
14856 	    (val = scf_value_create(g_hndl)) == NULL)
14857 		scfdie();
14858 
14859 	nbuf = safe_malloc(max_scf_name_len + 1);
14860 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
14861 
14862 	/* Take the "previous" snapshot before we blow away the properties. */
14863 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
14864 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
14865 			scfdie();
14866 	} else {
14867 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14868 			scfdie();
14869 
14870 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
14871 			scfdie();
14872 	}
14873 
14874 	/* Save general/enabled, since we're probably going to replace it. */
14875 	enabled = 2;
14876 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
14877 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
14878 	    scf_property_get_value(prop, val) == 0)
14879 		(void) scf_value_get_boolean(val, &enabled);
14880 
14881 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14882 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14883 			scfdie();
14884 
14885 		goto out;
14886 	}
14887 
14888 	for (;;) {
14889 		boolean_t isinst;
14890 		uint32_t flags;
14891 		int r;
14892 
14893 		/* Clear the properties from the corresponding entity. */
14894 		isinst = snaplevel_is_instance(level);
14895 
14896 		if (!isinst)
14897 			r = scf_iter_service_pgs(iter, cur_svc);
14898 		else
14899 			r = scf_iter_instance_pgs(iter, cur_inst);
14900 		if (r != SCF_SUCCESS)
14901 			scfdie();
14902 
14903 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14904 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14905 				scfdie();
14906 
14907 			/* Skip nonpersistent pgs. */
14908 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
14909 				continue;
14910 
14911 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
14912 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14913 					scfdie();
14914 
14915 				semerr(emsg_permission_denied);
14916 				goto out;
14917 			}
14918 		}
14919 		if (r == -1)
14920 			scfdie();
14921 
14922 		/* Copy the properties to the corresponding entity. */
14923 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
14924 			scfdie();
14925 
14926 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14927 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
14928 				scfdie();
14929 
14930 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
14931 			    0)
14932 				scfdie();
14933 
14934 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14935 				scfdie();
14936 
14937 			if (!isinst)
14938 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
14939 				    flags, npg);
14940 			else
14941 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
14942 				    flags, npg);
14943 			if (r != SCF_SUCCESS) {
14944 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14945 					scfdie();
14946 
14947 				semerr(emsg_permission_denied);
14948 				goto out;
14949 			}
14950 
14951 			if ((enabled == 0 || enabled == 1) &&
14952 			    strcmp(nbuf, scf_pg_general) == 0)
14953 				r = pg_copy(pg, npg, enabled);
14954 			else
14955 				r = pg_copy(pg, npg, 2);
14956 
14957 			switch (r) {
14958 			case 0:
14959 				break;
14960 
14961 			case -1:
14962 				semerr(emsg_permission_denied);
14963 				goto out;
14964 
14965 			case -2:
14966 				semerr(gettext(
14967 				    "Interrupted by another change.\n"));
14968 				goto out;
14969 
14970 			default:
14971 				abort();
14972 			}
14973 		}
14974 		if (r == -1)
14975 			scfdie();
14976 
14977 		/* Get next level. */
14978 		nlevel = scf_snaplevel_create(g_hndl);
14979 		if (nlevel == NULL)
14980 			scfdie();
14981 
14982 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
14983 		    SCF_SUCCESS) {
14984 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14985 				scfdie();
14986 
14987 			scf_snaplevel_destroy(nlevel);
14988 			break;
14989 		}
14990 
14991 		scf_snaplevel_destroy(level);
14992 		level = nlevel;
14993 	}
14994 
14995 	if (snapname == NULL) {
14996 		lscf_selectsnap(NULL);
14997 		snap = NULL;		/* cur_snap has been destroyed */
14998 	}
14999 
15000 out:
15001 	free(tbuf);
15002 	free(nbuf);
15003 	scf_value_destroy(val);
15004 	scf_property_destroy(prop);
15005 	scf_pg_destroy(npg);
15006 	scf_pg_destroy(pg);
15007 	scf_iter_destroy(iter);
15008 	scf_snaplevel_destroy(level);
15009 	scf_snapshot_destroy(prev);
15010 	if (snap != cur_snap)
15011 		scf_snapshot_destroy(snap);
15012 }
15013 
15014 void
15015 lscf_refresh(void)
15016 {
15017 	ssize_t fmrilen;
15018 	size_t bufsz;
15019 	char *fmribuf;
15020 	int r;
15021 
15022 	lscf_prep_hndl();
15023 
15024 	if (cur_inst == NULL) {
15025 		semerr(gettext("Instance not selected.\n"));
15026 		return;
15027 	}
15028 
15029 	bufsz = max_scf_fmri_len + 1;
15030 	fmribuf = safe_malloc(bufsz);
15031 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15032 	if (fmrilen < 0) {
15033 		free(fmribuf);
15034 		if (scf_error() != SCF_ERROR_DELETED)
15035 			scfdie();
15036 		scf_instance_destroy(cur_inst);
15037 		cur_inst = NULL;
15038 		warn(emsg_deleted);
15039 		return;
15040 	}
15041 	assert(fmrilen < bufsz);
15042 
15043 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15044 	switch (r) {
15045 	case 0:
15046 		break;
15047 
15048 	case ECONNABORTED:
15049 		warn(gettext("Could not refresh %s "
15050 		    "(repository connection broken).\n"), fmribuf);
15051 		break;
15052 
15053 	case ECANCELED:
15054 		warn(emsg_deleted);
15055 		break;
15056 
15057 	case EPERM:
15058 		warn(gettext("Could not refresh %s "
15059 		    "(permission denied).\n"), fmribuf);
15060 		break;
15061 
15062 	case ENOSPC:
15063 		warn(gettext("Could not refresh %s "
15064 		    "(repository server out of resources).\n"),
15065 		    fmribuf);
15066 		break;
15067 
15068 	case EACCES:
15069 	default:
15070 		bad_error("refresh_entity", scf_error());
15071 	}
15072 
15073 	free(fmribuf);
15074 }
15075 
15076 /*
15077  * describe [-v] [-t] [pg/prop]
15078  */
15079 int
15080 lscf_describe(uu_list_t *args, int hasargs)
15081 {
15082 	int ret = 0;
15083 	size_t i;
15084 	int argc;
15085 	char **argv = NULL;
15086 	string_list_t *slp;
15087 	int do_verbose = 0;
15088 	int do_templates = 0;
15089 	char *pattern = NULL;
15090 
15091 	lscf_prep_hndl();
15092 
15093 	if (hasargs != 0)  {
15094 		argc = uu_list_numnodes(args);
15095 		if (argc < 1)
15096 			goto usage;
15097 
15098 		argv = calloc(argc + 1, sizeof (char *));
15099 		if (argv == NULL)
15100 			uu_die(gettext("Out of memory.\n"));
15101 
15102 		for (slp = uu_list_first(args), i = 0;
15103 		    slp != NULL;
15104 		    slp = uu_list_next(args, slp), ++i)
15105 			argv[i] = slp->str;
15106 
15107 		argv[i] = NULL;
15108 
15109 		/*
15110 		 * We start optind = 0 because our list of arguments
15111 		 * starts at argv[0]
15112 		 */
15113 		optind = 0;
15114 		opterr = 0;
15115 		for (;;) {
15116 			ret = getopt(argc, argv, "vt");
15117 			if (ret == -1)
15118 				break;
15119 
15120 			switch (ret) {
15121 			case 'v':
15122 				do_verbose = 1;
15123 				break;
15124 
15125 			case 't':
15126 				do_templates = 1;
15127 				break;
15128 
15129 			case '?':
15130 				goto usage;
15131 
15132 			default:
15133 				bad_error("getopt", ret);
15134 			}
15135 		}
15136 
15137 		pattern = argv[optind];
15138 	}
15139 
15140 	if (cur_inst == NULL && cur_svc == NULL) {
15141 		semerr(emsg_entity_not_selected);
15142 		ret = -1;
15143 		goto out;
15144 	}
15145 
15146 	/*
15147 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15148 	 * output if their last parameter is set to 2.  Less information is
15149 	 * produced if the parameter is set to 1.
15150 	 */
15151 	if (pattern == NULL) {
15152 		if (do_verbose == 1)
15153 			list_entity_tmpl(2);
15154 		else
15155 			list_entity_tmpl(1);
15156 	}
15157 
15158 	if (do_templates == 0) {
15159 		if (do_verbose == 1)
15160 			listprop(pattern, 0, 2);
15161 		else
15162 			listprop(pattern, 0, 1);
15163 	} else {
15164 		if (do_verbose == 1)
15165 			listtmpl(pattern, 2);
15166 		else
15167 			listtmpl(pattern, 1);
15168 	}
15169 
15170 	ret = 0;
15171 out:
15172 	if (argv != NULL)
15173 		free(argv);
15174 	return (ret);
15175 usage:
15176 	ret = -2;
15177 	goto out;
15178 }
15179 
15180 /*
15181  * Creates a list of instance name strings associated with a service. If
15182  * wohandcrafted flag is set, get only instances that have a last-import
15183  * snapshot, instances that were imported via svccfg.
15184  */
15185 static uu_list_t *
15186 create_instance_list(scf_service_t *svc, int wohandcrafted)
15187 {
15188 	scf_snapshot_t  *snap = NULL;
15189 	scf_instance_t  *inst;
15190 	scf_iter_t	*inst_iter;
15191 	uu_list_t	*instances;
15192 	char		*instname;
15193 	int		r;
15194 
15195 	inst_iter = scf_iter_create(g_hndl);
15196 	inst = scf_instance_create(g_hndl);
15197 	if (inst_iter == NULL || inst == NULL) {
15198 		uu_warn(gettext("Could not create instance or iterator\n"));
15199 		scfdie();
15200 	}
15201 
15202 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
15203 		return (instances);
15204 
15205 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
15206 		switch (scf_error()) {
15207 		case SCF_ERROR_CONNECTION_BROKEN:
15208 		case SCF_ERROR_DELETED:
15209 			uu_list_destroy(instances);
15210 			instances = NULL;
15211 			goto out;
15212 
15213 		case SCF_ERROR_HANDLE_MISMATCH:
15214 		case SCF_ERROR_NOT_BOUND:
15215 		case SCF_ERROR_NOT_SET:
15216 		default:
15217 			bad_error("scf_iter_service_instances", scf_error());
15218 		}
15219 	}
15220 
15221 	instname = safe_malloc(max_scf_name_len + 1);
15222 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
15223 		if (r == -1) {
15224 			(void) uu_warn(gettext("Unable to iterate through "
15225 			    "instances to create instance list : %s\n"),
15226 			    scf_strerror(scf_error()));
15227 
15228 			uu_list_destroy(instances);
15229 			instances = NULL;
15230 			goto out;
15231 		}
15232 
15233 		/*
15234 		 * If the instance does not have a last-import snapshot
15235 		 * then do not add it to the list as it is a hand-crafted
15236 		 * instance that should not be managed.
15237 		 */
15238 		if (wohandcrafted) {
15239 			if (snap == NULL &&
15240 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
15241 				uu_warn(gettext("Unable to create snapshot "
15242 				    "entity\n"));
15243 				scfdie();
15244 			}
15245 
15246 			if (scf_instance_get_snapshot(inst,
15247 			    snap_lastimport, snap) != 0) {
15248 				switch (scf_error()) {
15249 				case SCF_ERROR_NOT_FOUND :
15250 				case SCF_ERROR_DELETED:
15251 					continue;
15252 
15253 				case SCF_ERROR_CONNECTION_BROKEN:
15254 					uu_list_destroy(instances);
15255 					instances = NULL;
15256 					goto out;
15257 
15258 				case SCF_ERROR_HANDLE_MISMATCH:
15259 				case SCF_ERROR_NOT_BOUND:
15260 				case SCF_ERROR_NOT_SET:
15261 				default:
15262 					bad_error("scf_iter_service_instances",
15263 					    scf_error());
15264 				}
15265 			}
15266 		}
15267 
15268 		if (scf_instance_get_name(inst, instname,
15269 		    max_scf_name_len + 1) < 0) {
15270 			switch (scf_error()) {
15271 			case SCF_ERROR_NOT_FOUND :
15272 				continue;
15273 
15274 			case SCF_ERROR_CONNECTION_BROKEN:
15275 			case SCF_ERROR_DELETED:
15276 				uu_list_destroy(instances);
15277 				instances = NULL;
15278 				goto out;
15279 
15280 			case SCF_ERROR_HANDLE_MISMATCH:
15281 			case SCF_ERROR_NOT_BOUND:
15282 			case SCF_ERROR_NOT_SET:
15283 			default:
15284 				bad_error("scf_iter_service_instances",
15285 				    scf_error());
15286 			}
15287 		}
15288 
15289 		add_string(instances, instname);
15290 	}
15291 
15292 out:
15293 	if (snap)
15294 		scf_snapshot_destroy(snap);
15295 
15296 	scf_instance_destroy(inst);
15297 	scf_iter_destroy(inst_iter);
15298 	free(instname);
15299 	return (instances);
15300 }
15301 
15302 /*
15303  * disable an instance but wait for the instance to
15304  * move out of the running state.
15305  *
15306  * Returns 0 : if the instance did not disable
15307  * Returns non-zero : if the instance disabled.
15308  *
15309  */
15310 static int
15311 disable_instance(scf_instance_t *instance)
15312 {
15313 	char	*fmribuf;
15314 	int	enabled = 10000;
15315 
15316 	if (inst_is_running(instance)) {
15317 		fmribuf = safe_malloc(max_scf_name_len + 1);
15318 		if (scf_instance_to_fmri(instance, fmribuf,
15319 		    max_scf_name_len + 1) < 0) {
15320 			free(fmribuf);
15321 			return (0);
15322 		}
15323 
15324 		/*
15325 		 * If the instance cannot be disabled then return
15326 		 * failure to disable and let the caller decide
15327 		 * if that is of importance.
15328 		 */
15329 		if (smf_disable_instance(fmribuf, 0) != 0) {
15330 			free(fmribuf);
15331 			return (0);
15332 		}
15333 
15334 		while (enabled) {
15335 			if (!inst_is_running(instance))
15336 				break;
15337 
15338 			(void) poll(NULL, 0, 5);
15339 			enabled = enabled - 5;
15340 		}
15341 
15342 		free(fmribuf);
15343 	}
15344 
15345 	return (enabled);
15346 }
15347 
15348 /*
15349  * Function to compare two service_manifest structures.
15350  */
15351 /* ARGSUSED2 */
15352 static int
15353 service_manifest_compare(const void *left, const void *right, void *unused)
15354 {
15355 	service_manifest_t *l = (service_manifest_t *)left;
15356 	service_manifest_t *r = (service_manifest_t *)right;
15357 	int rc;
15358 
15359 	rc = strcmp(l->servicename, r->servicename);
15360 
15361 	return (rc);
15362 }
15363 
15364 /*
15365  * Look for the provided service in the service to manifest
15366  * tree.  If the service exists, and a manifest was provided
15367  * then add the manifest to that service.  If the service
15368  * does not exist, then add the service and manifest to the
15369  * list.
15370  *
15371  * If the manifest is NULL, return the element if found.  If
15372  * the service is not found return NULL.
15373  */
15374 service_manifest_t *
15375 find_add_svc_mfst(const char *svnbuf, const char *mfst)
15376 {
15377 	service_manifest_t	elem;
15378 	service_manifest_t	*fnelem;
15379 	uu_avl_index_t		marker;
15380 
15381 	elem.servicename = svnbuf;
15382 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
15383 
15384 	if (mfst) {
15385 		if (fnelem) {
15386 			add_string(fnelem->mfstlist, strdup(mfst));
15387 		} else {
15388 			fnelem = safe_malloc(sizeof (*fnelem));
15389 			fnelem->servicename = safe_strdup(svnbuf);
15390 			if ((fnelem->mfstlist =
15391 			    uu_list_create(string_pool, NULL, 0)) == NULL)
15392 				uu_die(gettext("Could not create property "
15393 				    "list: %s\n"), uu_strerror(uu_error()));
15394 
15395 			add_string(fnelem->mfstlist, safe_strdup(mfst));
15396 
15397 			uu_avl_insert(service_manifest_tree, fnelem, marker);
15398 		}
15399 	}
15400 
15401 	return (fnelem);
15402 }
15403 
15404 /*
15405  * Create the service to manifest avl tree.
15406  *
15407  * Walk each of the manifests currently installed in the supported
15408  * directories, /lib/svc/manifests and /var/svc/manifests.  For
15409  * each of the manifests, inventory the services and add them to
15410  * the tree.
15411  *
15412  * Code that calls this function should make sure fileystem/minimal is online,
15413  * /var is available, since this function walks the /var/svc/manifest directory.
15414  */
15415 static void
15416 create_manifest_tree(void)
15417 {
15418 	manifest_info_t **entry;
15419 	manifest_info_t **manifests;
15420 	uu_list_walk_t	*svcs;
15421 	bundle_t	*b;
15422 	entity_t	*mfsvc;
15423 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
15424 	int		c, status;
15425 
15426 	if (service_manifest_pool)
15427 		return;
15428 
15429 	/*
15430 	 * Create the list pool for the service manifest list
15431 	 */
15432 	service_manifest_pool = uu_avl_pool_create("service_manifest",
15433 	    sizeof (service_manifest_t),
15434 	    offsetof(service_manifest_t, svcmfst_node),
15435 	    service_manifest_compare, UU_DEFAULT);
15436 	if (service_manifest_pool == NULL)
15437 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
15438 		    uu_strerror(uu_error()));
15439 
15440 	/*
15441 	 * Create the list
15442 	 */
15443 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
15444 	    UU_DEFAULT);
15445 	if (service_manifest_tree == NULL)
15446 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
15447 		    uu_strerror(uu_error()));
15448 
15449 	/*
15450 	 * Walk the manifests adding the service(s) from each manifest.
15451 	 *
15452 	 * If a service already exists add the manifest to the manifest
15453 	 * list for that service.  This covers the case of a service that
15454 	 * is supported by multiple manifest files.
15455 	 */
15456 	for (c = 0; dirs[c]; c++) {
15457 		status = find_manifests(dirs[c], &manifests, CHECKEXT);
15458 		if (status < 0) {
15459 			uu_warn(gettext("file tree walk of %s encountered "
15460 			    "error %s\n"), dirs[c], strerror(errno));
15461 
15462 			uu_avl_destroy(service_manifest_tree);
15463 			service_manifest_tree = NULL;
15464 			return;
15465 		}
15466 
15467 		/*
15468 		 * If a manifest that was in the list is not found
15469 		 * then skip and go to the next manifest file.
15470 		 */
15471 		if (manifests != NULL) {
15472 			for (entry = manifests; *entry != NULL; entry++) {
15473 				b = internal_bundle_new();
15474 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
15475 				    SVCCFG_OP_IMPORT) != 0) {
15476 					internal_bundle_free(b);
15477 					continue;
15478 				}
15479 
15480 				svcs = uu_list_walk_start(b->sc_bundle_services,
15481 				    0);
15482 				if (svcs == NULL) {
15483 					internal_bundle_free(b);
15484 					continue;
15485 				}
15486 
15487 				while ((mfsvc = uu_list_walk_next(svcs)) !=
15488 				    NULL) {
15489 					/* Add manifest to service */
15490 					(void) find_add_svc_mfst(mfsvc->sc_name,
15491 					    (*entry)->mi_path);
15492 				}
15493 
15494 				uu_list_walk_end(svcs);
15495 				internal_bundle_free(b);
15496 			}
15497 
15498 			free_manifest_array(manifests);
15499 		}
15500 	}
15501 }
15502 
15503 /*
15504  * Check the manifest history file to see
15505  * if the service was ever installed from
15506  * one of the supported directories.
15507  *
15508  * Return Values :
15509  * 	-1 - if there's error reading manifest history file
15510  *	 1 - if the service is not found
15511  *	 0 - if the service is found
15512  */
15513 static int
15514 check_mfst_history(const char *svcname)
15515 {
15516 	struct stat	st;
15517 	caddr_t		mfsthist_start;
15518 	char		*svnbuf;
15519 	int		fd;
15520 	int		r = 1;
15521 
15522 	fd = open(MFSTHISTFILE, O_RDONLY);
15523 	if (fd == -1) {
15524 		uu_warn(gettext("Unable to open the history file\n"));
15525 		return (-1);
15526 	}
15527 
15528 	if (fstat(fd, &st) == -1) {
15529 		uu_warn(gettext("Unable to stat the history file\n"));
15530 		return (-1);
15531 	}
15532 
15533 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
15534 	    MAP_PRIVATE, fd, 0);
15535 
15536 	(void) close(fd);
15537 	if (mfsthist_start == MAP_FAILED ||
15538 	    *(mfsthist_start + st.st_size) != '\0') {
15539 		(void) munmap(mfsthist_start, st.st_size);
15540 		return (-1);
15541 	}
15542 
15543 	/*
15544 	 * The manifest history file is a space delimited list
15545 	 * of service and instance to manifest linkage.  Adding
15546 	 * a space to the end of the service name so to get only
15547 	 * the service that is being searched for.
15548 	 */
15549 	svnbuf = uu_msprintf("%s ", svcname);
15550 	if (svnbuf == NULL)
15551 		uu_die(gettext("Out of memory"));
15552 
15553 	if (strstr(mfsthist_start, svnbuf) != NULL)
15554 		r = 0;
15555 
15556 	(void) munmap(mfsthist_start, st.st_size);
15557 	uu_free(svnbuf);
15558 	return (r);
15559 }
15560 
15561 /*
15562  * Take down each of the instances in the service
15563  * and remove them, then delete the service.
15564  */
15565 static void
15566 teardown_service(scf_service_t *svc, const char *svnbuf)
15567 {
15568 	scf_instance_t	*instance;
15569 	scf_iter_t	*iter;
15570 	int		r;
15571 
15572 	safe_printf(gettext("Delete service %s as there are no "
15573 	    "supporting manifests\n"), svnbuf);
15574 
15575 	instance = scf_instance_create(g_hndl);
15576 	iter = scf_iter_create(g_hndl);
15577 	if (iter == NULL || instance == NULL) {
15578 		uu_warn(gettext("Unable to create supporting entities to "
15579 		    "teardown the service\n"));
15580 		uu_warn(gettext("scf error is : %s\n"),
15581 		    scf_strerror(scf_error()));
15582 		scfdie();
15583 	}
15584 
15585 	if (scf_iter_service_instances(iter, svc) != 0) {
15586 		switch (scf_error()) {
15587 		case SCF_ERROR_CONNECTION_BROKEN:
15588 		case SCF_ERROR_DELETED:
15589 			goto out;
15590 
15591 		case SCF_ERROR_HANDLE_MISMATCH:
15592 		case SCF_ERROR_NOT_BOUND:
15593 		case SCF_ERROR_NOT_SET:
15594 		default:
15595 			bad_error("scf_iter_service_instances",
15596 			    scf_error());
15597 		}
15598 	}
15599 
15600 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
15601 		if (r == -1) {
15602 			uu_warn(gettext("Error - %s\n"),
15603 			    scf_strerror(scf_error()));
15604 			goto out;
15605 		}
15606 
15607 		(void) disable_instance(instance);
15608 	}
15609 
15610 	/*
15611 	 * Delete the service... forcing the deletion in case
15612 	 * any of the instances did not disable.
15613 	 */
15614 	(void) lscf_service_delete(svc, 1);
15615 out:
15616 	scf_instance_destroy(instance);
15617 	scf_iter_destroy(iter);
15618 }
15619 
15620 /*
15621  * Get the list of instances supported by the manifest
15622  * file.
15623  *
15624  * Return 0 if there are no instances.
15625  *
15626  * Return -1 if there are errors attempting to collect instances.
15627  *
15628  * Return the count of instances found if there are no errors.
15629  *
15630  */
15631 static int
15632 check_instance_support(char *mfstfile, const char *svcname,
15633     uu_list_t *instances)
15634 {
15635 	uu_list_walk_t	*svcs, *insts;
15636 	uu_list_t	*ilist;
15637 	bundle_t	*b;
15638 	entity_t	*mfsvc, *mfinst;
15639 	const char	*svcn;
15640 	int		rminstcnt = 0;
15641 
15642 
15643 	b = internal_bundle_new();
15644 
15645 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
15646 		/*
15647 		 * Unable to process the manifest file for
15648 		 * instance support, so just return as
15649 		 * don't want to remove instances that could
15650 		 * not be accounted for that might exist here.
15651 		 */
15652 		internal_bundle_free(b);
15653 		return (0);
15654 	}
15655 
15656 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
15657 	if (svcs == NULL) {
15658 		internal_bundle_free(b);
15659 		return (0);
15660 	}
15661 
15662 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
15663 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
15664 
15665 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
15666 		if (strcmp(mfsvc->sc_name, svcn) == 0)
15667 			break;
15668 	}
15669 	uu_list_walk_end(svcs);
15670 
15671 	if (mfsvc == NULL) {
15672 		internal_bundle_free(b);
15673 		return (-1);
15674 	}
15675 
15676 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
15677 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
15678 		internal_bundle_free(b);
15679 		return (0);
15680 	}
15681 
15682 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
15683 		/*
15684 		 * Remove the instance from the instances list.
15685 		 * The unaccounted for instances will be removed
15686 		 * from the service once all manifests are
15687 		 * processed.
15688 		 */
15689 		(void) remove_string(instances,
15690 		    mfinst->sc_name);
15691 		rminstcnt++;
15692 	}
15693 
15694 	uu_list_walk_end(insts);
15695 	internal_bundle_free(b);
15696 
15697 	return (rminstcnt);
15698 }
15699 
15700 /*
15701  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
15702  * 'false' to indicate there's no manifest file(s) found for the service.
15703  */
15704 static void
15705 svc_add_no_support(scf_service_t *svc)
15706 {
15707 	char	*pname;
15708 
15709 	/* Add no support */
15710 	cur_svc = svc;
15711 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
15712 		return;
15713 
15714 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
15715 	if (pname == NULL)
15716 		uu_die(gettext("Out of memory.\n"));
15717 
15718 	(void) lscf_addpropvalue(pname, "boolean:", "0");
15719 
15720 	uu_free(pname);
15721 	cur_svc = NULL;
15722 }
15723 
15724 /*
15725  * This function handles all upgrade scenarios for a service that doesn't have
15726  * SCF_PG_MANIFESTFILES pg. The function creates and populates
15727  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
15728  * manifest(s) mapping. Manifests under supported directories are inventoried
15729  * and a property is added for each file that delivers configuration to the
15730  * service.  A service that has no corresponding manifest files (deleted) are
15731  * removed from repository.
15732  *
15733  * Unsupported services:
15734  *
15735  * A service is considered unsupported if there is no corresponding manifest
15736  * in the supported directories for that service and the service isn't in the
15737  * history file list.  The history file, MFSTHISTFILE, contains a list of all
15738  * services and instances that were delivered by Solaris before the introduction
15739  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
15740  * the path to the manifest file that defined the service or instance.
15741  *
15742  * Another type of unsupported services is 'handcrafted' services,
15743  * programmatically created services or services created by dependent entries
15744  * in other manifests. A handcrafted service is identified by its lack of any
15745  * instance containing last-import snapshot which is created during svccfg
15746  * import.
15747  *
15748  * This function sets a flag for unsupported services by setting services'
15749  * SCF_PG_MANIFESTFILES/support property to false.
15750  */
15751 static void
15752 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
15753 {
15754 	service_manifest_t	*elem;
15755 	uu_list_walk_t		*mfwalk;
15756 	string_list_t		*mfile;
15757 	uu_list_t		*instances;
15758 	const char		*sname;
15759 	char			*pname;
15760 	int			r;
15761 
15762 	/*
15763 	 * Since there's no guarantee manifests under /var are available during
15764 	 * early import, don't perform any upgrade during early import.
15765 	 */
15766 	if (IGNORE_VAR)
15767 		return;
15768 
15769 	if (service_manifest_tree == NULL) {
15770 		create_manifest_tree();
15771 	}
15772 
15773 	/*
15774 	 * Find service's supporting manifest(s) after
15775 	 * stripping off the svc:/ prefix that is part
15776 	 * of the fmri that is not used in the service
15777 	 * manifest bundle list.
15778 	 */
15779 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
15780 	    strlen(SCF_FMRI_SERVICE_PREFIX);
15781 	elem = find_add_svc_mfst(sname, NULL);
15782 	if (elem == NULL) {
15783 
15784 		/*
15785 		 * A handcrafted service, one that has no instance containing
15786 		 * last-import snapshot, should get unsupported flag.
15787 		 */
15788 		instances = create_instance_list(svc, 1);
15789 		if (instances == NULL) {
15790 			uu_warn(gettext("Unable to create instance list %s\n"),
15791 			    svcname);
15792 			return;
15793 		}
15794 
15795 		if (uu_list_numnodes(instances) == 0) {
15796 			svc_add_no_support(svc);
15797 			return;
15798 		}
15799 
15800 		/*
15801 		 * If the service is in the history file, and its supporting
15802 		 * manifests are not found, we can safely delete the service
15803 		 * because its manifests are removed from the system.
15804 		 *
15805 		 * Services not found in the history file are not delivered by
15806 		 * Solaris and/or delivered outside supported directories, set
15807 		 * unsupported flag for these services.
15808 		 */
15809 		r = check_mfst_history(svcname);
15810 		if (r == -1)
15811 			return;
15812 
15813 		if (r) {
15814 			/* Set unsupported flag for service  */
15815 			svc_add_no_support(svc);
15816 		} else {
15817 			/* Delete the service */
15818 			teardown_service(svc, svcname);
15819 		}
15820 
15821 		return;
15822 	}
15823 
15824 	/*
15825 	 * Walk through the list of manifests and add them
15826 	 * to the service.
15827 	 *
15828 	 * Create a manifestfiles pg and add the property.
15829 	 */
15830 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
15831 	if (mfwalk == NULL)
15832 		return;
15833 
15834 	cur_svc = svc;
15835 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
15836 	if (r != 0) {
15837 		cur_svc = NULL;
15838 		return;
15839 	}
15840 
15841 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
15842 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
15843 		    mhash_filename_to_propname(mfile->str, 0));
15844 		if (pname == NULL)
15845 			uu_die(gettext("Out of memory.\n"));
15846 
15847 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
15848 		uu_free(pname);
15849 	}
15850 	uu_list_walk_end(mfwalk);
15851 
15852 	cur_svc = NULL;
15853 }
15854 
15855 /*
15856  * Take a service and process the manifest file entires to see if
15857  * there is continued support for the service and instances.  If
15858  * not cleanup as appropriate.
15859  *
15860  * If a service does not have a manifest files entry flag it for
15861  * upgrade and return.
15862  *
15863  * For each manifestfiles property check if the manifest file is
15864  * under the supported /lib/svc/manifest or /var/svc/manifest path
15865  * and if not then return immediately as this service is not supported
15866  * by the cleanup mechanism and should be ignored.
15867  *
15868  * For each manifest file that is supported, check to see if the
15869  * file exists.  If not then remove the manifest file property
15870  * from the service and the smf/manifest hash table.  If the manifest
15871  * file exists then verify that it supports the instances that are
15872  * part of the service.
15873  *
15874  * Once all manifest files have been accounted for remove any instances
15875  * that are no longer supported in the service.
15876  *
15877  * Return values :
15878  * 0 - Successfully processed the service
15879  * non-zero - failed to process the service
15880  *
15881  * On most errors, will just return to wait and get the next service,
15882  * unless in case of unable to create the needed structures which is
15883  * most likely a fatal error that is not going to be recoverable.
15884  */
15885 int
15886 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
15887 {
15888 	struct mpg_mfile	*mpntov;
15889 	struct mpg_mfile	**mpvarry = NULL;
15890 	scf_service_t		*svc;
15891 	scf_propertygroup_t	*mpg;
15892 	scf_property_t		*mp;
15893 	scf_value_t		*mv;
15894 	scf_iter_t		*mi;
15895 	scf_instance_t		*instance;
15896 	uu_list_walk_t		*insts;
15897 	uu_list_t		*instances = NULL;
15898 	boolean_t		activity = (boolean_t)act;
15899 	char			*mpnbuf;
15900 	char			*mpvbuf;
15901 	char			*pgpropbuf;
15902 	int			mfstcnt, rminstct, instct, mfstmax;
15903 	int			index;
15904 	int			r = 0;
15905 
15906 	assert(g_hndl != NULL);
15907 	assert(wip->svc != NULL);
15908 	assert(wip->fmri != NULL);
15909 
15910 	svc = wip->svc;
15911 
15912 	mpg = scf_pg_create(g_hndl);
15913 	mp = scf_property_create(g_hndl);
15914 	mi = scf_iter_create(g_hndl);
15915 	mv = scf_value_create(g_hndl);
15916 	instance = scf_instance_create(g_hndl);
15917 
15918 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
15919 	    instance == NULL) {
15920 		uu_warn(gettext("Unable to create the supporting entities\n"));
15921 		uu_warn(gettext("scf error is : %s\n"),
15922 		    scf_strerror(scf_error()));
15923 		scfdie();
15924 	}
15925 
15926 	/*
15927 	 * Get the manifestfiles property group to be parsed for
15928 	 * files existence.
15929 	 */
15930 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
15931 		switch (scf_error()) {
15932 		case SCF_ERROR_NOT_FOUND:
15933 			upgrade_svc_mfst_connection(svc, wip->fmri);
15934 			break;
15935 		case SCF_ERROR_DELETED:
15936 		case SCF_ERROR_CONNECTION_BROKEN:
15937 			goto out;
15938 
15939 		case SCF_ERROR_HANDLE_MISMATCH:
15940 		case SCF_ERROR_NOT_BOUND:
15941 		case SCF_ERROR_NOT_SET:
15942 		default:
15943 			bad_error("scf_iter_pg_properties",
15944 			    scf_error());
15945 		}
15946 
15947 		goto out;
15948 	}
15949 
15950 	/*
15951 	 * Iterate through each of the manifestfiles properties
15952 	 * to determine what manifestfiles are available.
15953 	 *
15954 	 * If a manifest file is supported then increment the
15955 	 * count and therefore the service is safe.
15956 	 */
15957 	if (scf_iter_pg_properties(mi, mpg) != 0) {
15958 		switch (scf_error()) {
15959 		case SCF_ERROR_DELETED:
15960 		case SCF_ERROR_CONNECTION_BROKEN:
15961 			goto out;
15962 
15963 		case SCF_ERROR_HANDLE_MISMATCH:
15964 		case SCF_ERROR_NOT_BOUND:
15965 		case SCF_ERROR_NOT_SET:
15966 		default:
15967 			bad_error("scf_iter_pg_properties",
15968 			    scf_error());
15969 		}
15970 	}
15971 
15972 	mfstcnt = 0;
15973 	mfstmax = MFSTFILE_MAX;
15974 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
15975 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
15976 		if (r == -1)
15977 			bad_error(gettext("Unable to iterate through "
15978 			    "manifestfiles properties : %s"),
15979 			    scf_error());
15980 
15981 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
15982 		mpnbuf = safe_malloc(max_scf_name_len + 1);
15983 		mpvbuf = safe_malloc(max_scf_value_len + 1);
15984 		mpntov->mpg = mpnbuf;
15985 		mpntov->mfile = mpvbuf;
15986 		mpntov->access = 1;
15987 		if (scf_property_get_name(mp, mpnbuf,
15988 		    max_scf_name_len + 1) < 0) {
15989 			uu_warn(gettext("Unable to get manifest file "
15990 			    "property : %s\n"),
15991 			    scf_strerror(scf_error()));
15992 
15993 			switch (scf_error()) {
15994 			case SCF_ERROR_DELETED:
15995 			case SCF_ERROR_CONNECTION_BROKEN:
15996 				r = scferror2errno(scf_error());
15997 				goto out_free;
15998 
15999 			case SCF_ERROR_HANDLE_MISMATCH:
16000 			case SCF_ERROR_NOT_BOUND:
16001 			case SCF_ERROR_NOT_SET:
16002 			default:
16003 				bad_error("scf_iter_pg_properties",
16004 				    scf_error());
16005 			}
16006 		}
16007 
16008 		/*
16009 		 * The support property is a boolean value that indicates
16010 		 * if the service is supported for manifest file deletion.
16011 		 * Currently at this time there is no code that sets this
16012 		 * value to true.  So while we could just let this be caught
16013 		 * by the support check below, in the future this by be set
16014 		 * to true and require processing.  So for that, go ahead
16015 		 * and check here, and just return if false.  Otherwise,
16016 		 * fall through expecting that other support checks will
16017 		 * handle the entries.
16018 		 */
16019 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
16020 			uint8_t	support;
16021 
16022 			if (scf_property_get_value(mp, mv) != 0 ||
16023 			    scf_value_get_boolean(mv, &support) != 0) {
16024 				uu_warn(gettext("Unable to get the manifest "
16025 				    "support value: %s\n"),
16026 				    scf_strerror(scf_error()));
16027 
16028 				switch (scf_error()) {
16029 				case SCF_ERROR_DELETED:
16030 				case SCF_ERROR_CONNECTION_BROKEN:
16031 					r = scferror2errno(scf_error());
16032 					goto out_free;
16033 
16034 				case SCF_ERROR_HANDLE_MISMATCH:
16035 				case SCF_ERROR_NOT_BOUND:
16036 				case SCF_ERROR_NOT_SET:
16037 				default:
16038 					bad_error("scf_iter_pg_properties",
16039 					    scf_error());
16040 				}
16041 			}
16042 
16043 			if (support == B_FALSE)
16044 				goto out_free;
16045 		}
16046 
16047 		/*
16048 		 * Anything with a manifest outside of the supported
16049 		 * directories, immediately bail out because that makes
16050 		 * this service non-supported.  We don't even want
16051 		 * to do instance processing in this case because the
16052 		 * instances could be part of the non-supported manifest.
16053 		 */
16054 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
16055 			/*
16056 			 * Manifest is not in /lib/svc, so we need to
16057 			 * consider the /var/svc case.
16058 			 */
16059 			if (strncmp(mpnbuf, VARSVC_PR,
16060 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
16061 				/*
16062 				 * Either the manifest is not in /var/svc or
16063 				 * /var is not yet mounted.  We ignore the
16064 				 * manifest either because it is not in a
16065 				 * standard location or because we cannot
16066 				 * currently access the manifest.
16067 				 */
16068 				goto out_free;
16069 			}
16070 		}
16071 
16072 		/*
16073 		 * Get the value to of the manifest file for this entry
16074 		 * for access verification and instance support
16075 		 * verification if it still exists.
16076 		 *
16077 		 * During Early Manifest Import if the manifest is in
16078 		 * /var/svc then it may not yet be available for checking
16079 		 * so we must determine if /var/svc is available.  If not
16080 		 * then defer until Late Manifest Import to cleanup.
16081 		 */
16082 		if (scf_property_get_value(mp, mv) != 0) {
16083 			uu_warn(gettext("Unable to get the manifest file "
16084 			    "value: %s\n"),
16085 			    scf_strerror(scf_error()));
16086 
16087 			switch (scf_error()) {
16088 			case SCF_ERROR_DELETED:
16089 			case SCF_ERROR_CONNECTION_BROKEN:
16090 				r = scferror2errno(scf_error());
16091 				goto out_free;
16092 
16093 			case SCF_ERROR_HANDLE_MISMATCH:
16094 			case SCF_ERROR_NOT_BOUND:
16095 			case SCF_ERROR_NOT_SET:
16096 			default:
16097 				bad_error("scf_property_get_value",
16098 				    scf_error());
16099 			}
16100 		}
16101 
16102 		if (scf_value_get_astring(mv, mpvbuf,
16103 		    max_scf_value_len + 1) < 0) {
16104 			uu_warn(gettext("Unable to get the manifest "
16105 			    "file : %s\n"),
16106 			    scf_strerror(scf_error()));
16107 
16108 			switch (scf_error()) {
16109 			case SCF_ERROR_DELETED:
16110 			case SCF_ERROR_CONNECTION_BROKEN:
16111 				r = scferror2errno(scf_error());
16112 				goto out_free;
16113 
16114 			case SCF_ERROR_HANDLE_MISMATCH:
16115 			case SCF_ERROR_NOT_BOUND:
16116 			case SCF_ERROR_NOT_SET:
16117 			default:
16118 				bad_error("scf_value_get_astring",
16119 				    scf_error());
16120 			}
16121 		}
16122 
16123 		mpvarry[mfstcnt] = mpntov;
16124 		mfstcnt++;
16125 
16126 		/*
16127 		 * Check for the need to reallocate array
16128 		 */
16129 		if (mfstcnt >= (mfstmax - 1)) {
16130 			struct mpg_mfile **newmpvarry;
16131 
16132 			mfstmax = mfstmax * 2;
16133 			newmpvarry = realloc(mpvarry,
16134 			    sizeof (struct mpg_mfile *) * mfstmax);
16135 
16136 			if (newmpvarry == NULL)
16137 				goto out_free;
16138 
16139 			mpvarry = newmpvarry;
16140 		}
16141 
16142 		mpvarry[mfstcnt] = NULL;
16143 	}
16144 
16145 	for (index = 0; mpvarry[index]; index++) {
16146 		mpntov = mpvarry[index];
16147 
16148 		/*
16149 		 * Check to see if the manifestfile is accessable, if so hand
16150 		 * this service and manifestfile off to be processed for
16151 		 * instance support.
16152 		 */
16153 		mpnbuf = mpntov->mpg;
16154 		mpvbuf = mpntov->mfile;
16155 		if (access(mpvbuf, F_OK) != 0) {
16156 			mpntov->access = 0;
16157 			activity++;
16158 			mfstcnt--;
16159 			/* Remove the entry from the service */
16160 			cur_svc = svc;
16161 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16162 			    mpnbuf);
16163 			if (pgpropbuf == NULL)
16164 				uu_die(gettext("Out of memory.\n"));
16165 
16166 			lscf_delprop(pgpropbuf);
16167 			cur_svc = NULL;
16168 
16169 			uu_free(pgpropbuf);
16170 		}
16171 	}
16172 
16173 	/*
16174 	 * If mfstcnt is 0, none of the manifests that supported the service
16175 	 * existed so remove the service.
16176 	 */
16177 	if (mfstcnt == 0) {
16178 		teardown_service(svc, wip->fmri);
16179 
16180 		goto out_free;
16181 	}
16182 
16183 	if (activity) {
16184 		int	nosvcsupport = 0;
16185 
16186 		/*
16187 		 * If the list of service instances is NULL then
16188 		 * create the list.
16189 		 */
16190 		instances = create_instance_list(svc, 1);
16191 		if (instances == NULL) {
16192 			uu_warn(gettext("Unable to create instance list %s\n"),
16193 			    wip->fmri);
16194 			goto out_free;
16195 		}
16196 
16197 		rminstct = uu_list_numnodes(instances);
16198 		instct = rminstct;
16199 
16200 		for (index = 0; mpvarry[index]; index++) {
16201 			mpntov = mpvarry[index];
16202 			if (mpntov->access == 0)
16203 				continue;
16204 
16205 			mpnbuf = mpntov->mpg;
16206 			mpvbuf = mpntov->mfile;
16207 			r = check_instance_support(mpvbuf, wip->fmri,
16208 			    instances);
16209 			if (r == -1) {
16210 				nosvcsupport++;
16211 			} else {
16212 				rminstct -= r;
16213 			}
16214 		}
16215 
16216 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
16217 			teardown_service(svc, wip->fmri);
16218 
16219 			goto out_free;
16220 		}
16221 	}
16222 
16223 	/*
16224 	 * If there are instances left on the instance list, then
16225 	 * we must remove them.
16226 	 */
16227 	if (instances != NULL && uu_list_numnodes(instances)) {
16228 		string_list_t *sp;
16229 
16230 		insts = uu_list_walk_start(instances, 0);
16231 		while ((sp = uu_list_walk_next(insts)) != NULL) {
16232 			/*
16233 			 * Remove the instance from the instances list.
16234 			 */
16235 			safe_printf(gettext("Delete instance %s from "
16236 			    "service %s\n"), sp->str, wip->fmri);
16237 			if (scf_service_get_instance(svc, sp->str,
16238 			    instance) != SCF_SUCCESS) {
16239 				(void) uu_warn("scf_error - %s\n",
16240 				    scf_strerror(scf_error()));
16241 
16242 				continue;
16243 			}
16244 
16245 			(void) disable_instance(instance);
16246 
16247 			(void) lscf_instance_delete(instance, 1);
16248 		}
16249 		scf_instance_destroy(instance);
16250 		uu_list_walk_end(insts);
16251 	}
16252 
16253 out_free:
16254 	if (mpvarry) {
16255 		struct mpg_mfile *fmpntov;
16256 
16257 		for (index = 0; mpvarry[index]; index++) {
16258 			fmpntov  = mpvarry[index];
16259 			if (fmpntov->mpg == mpnbuf)
16260 				mpnbuf = NULL;
16261 			free(fmpntov->mpg);
16262 
16263 			if (fmpntov->mfile == mpvbuf)
16264 				mpvbuf = NULL;
16265 			free(fmpntov->mfile);
16266 
16267 			if (fmpntov == mpntov)
16268 				mpntov = NULL;
16269 			free(fmpntov);
16270 		}
16271 		if (mpnbuf)
16272 			free(mpnbuf);
16273 		if (mpvbuf)
16274 			free(mpvbuf);
16275 		if (mpntov)
16276 			free(mpntov);
16277 
16278 		free(mpvarry);
16279 	}
16280 out:
16281 	scf_pg_destroy(mpg);
16282 	scf_property_destroy(mp);
16283 	scf_iter_destroy(mi);
16284 	scf_value_destroy(mv);
16285 
16286 	return (0);
16287 }
16288 
16289 /*
16290  * Take the service and search for the manifestfiles property
16291  * in each of the property groups.  If the manifest file
16292  * associated with the property does not exist then remove
16293  * the property group.
16294  */
16295 int
16296 lscf_hash_cleanup()
16297 {
16298 	scf_service_t		*svc;
16299 	scf_scope_t		*scope;
16300 	scf_propertygroup_t	*pg;
16301 	scf_property_t		*prop;
16302 	scf_value_t		*val;
16303 	scf_iter_t		*iter;
16304 	char			*pgname;
16305 	char			*mfile;
16306 	int			r;
16307 
16308 	svc = scf_service_create(g_hndl);
16309 	scope = scf_scope_create(g_hndl);
16310 	pg = scf_pg_create(g_hndl);
16311 	prop = scf_property_create(g_hndl);
16312 	val = scf_value_create(g_hndl);
16313 	iter = scf_iter_create(g_hndl);
16314 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
16315 	    svc == NULL || scope == NULL) {
16316 		uu_warn(gettext("Unable to create a property group, or "
16317 		    "property\n"));
16318 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
16319 		    "pg is not NULL");
16320 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
16321 		    "prop is not NULL");
16322 		uu_warn("%s\n", val == NULL ? "val is NULL" :
16323 		    "val is not NULL");
16324 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
16325 		    "iter is not NULL");
16326 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
16327 		    "svc is not NULL");
16328 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
16329 		    "scope is not NULL");
16330 		uu_warn(gettext("scf error is : %s\n"),
16331 		    scf_strerror(scf_error()));
16332 		scfdie();
16333 	}
16334 
16335 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
16336 		switch (scf_error()) {
16337 		case SCF_ERROR_CONNECTION_BROKEN:
16338 		case SCF_ERROR_NOT_FOUND:
16339 			goto out;
16340 
16341 		case SCF_ERROR_HANDLE_MISMATCH:
16342 		case SCF_ERROR_NOT_BOUND:
16343 		case SCF_ERROR_INVALID_ARGUMENT:
16344 		default:
16345 			bad_error("scf_handle_get_scope", scf_error());
16346 		}
16347 	}
16348 
16349 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
16350 		uu_warn(gettext("Unable to process the hash service, %s\n"),
16351 		    HASH_SVC);
16352 		goto out;
16353 	}
16354 
16355 	pgname = safe_malloc(max_scf_name_len + 1);
16356 	mfile = safe_malloc(max_scf_value_len + 1);
16357 
16358 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
16359 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
16360 		    scf_strerror(scf_error()));
16361 		goto out;
16362 	}
16363 
16364 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
16365 		if (r == -1)
16366 			goto out;
16367 
16368 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
16369 			switch (scf_error()) {
16370 			case SCF_ERROR_DELETED:
16371 				return (ENODEV);
16372 
16373 			case SCF_ERROR_CONNECTION_BROKEN:
16374 				return (ECONNABORTED);
16375 
16376 			case SCF_ERROR_NOT_SET:
16377 			case SCF_ERROR_NOT_BOUND:
16378 			default:
16379 				bad_error("scf_pg_get_name", scf_error());
16380 			}
16381 		}
16382 		if (IGNORE_VAR) {
16383 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
16384 				continue;
16385 		}
16386 
16387 		/*
16388 		 * If unable to get the property continue as this is an
16389 		 * entry that has no location to check against.
16390 		 */
16391 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
16392 			continue;
16393 		}
16394 
16395 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
16396 			uu_warn(gettext("Unable to get value from %s\n"),
16397 			    pgname);
16398 			goto error_handle;
16399 		}
16400 
16401 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) ==
16402 		    -1) {
16403 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
16404 			    pgname, scf_strerror(scf_error()));
16405 			goto error_handle;
16406 		}
16407 
16408 		if (access(mfile, F_OK) == 0)
16409 			continue;
16410 
16411 		(void) scf_pg_delete(pg);
16412 
16413 error_handle:
16414 		switch (scf_error()) {
16415 		case SCF_ERROR_DELETED:
16416 		case SCF_ERROR_CONSTRAINT_VIOLATED:
16417 		case SCF_ERROR_NOT_FOUND:
16418 		case SCF_ERROR_NOT_SET:
16419 			continue;
16420 
16421 		case SCF_ERROR_CONNECTION_BROKEN:
16422 			r = scferror2errno(scf_error());
16423 			goto out;
16424 
16425 		case SCF_ERROR_HANDLE_MISMATCH:
16426 		case SCF_ERROR_NOT_BOUND:
16427 		default:
16428 			bad_error("scf_value_get_astring",
16429 			    scf_error());
16430 		}
16431 	}
16432 
16433 out:
16434 	scf_scope_destroy(scope);
16435 	scf_service_destroy(svc);
16436 	scf_pg_destroy(pg);
16437 	scf_property_destroy(prop);
16438 	scf_value_destroy(val);
16439 	scf_iter_destroy(iter);
16440 	free(pgname);
16441 	free(mfile);
16442 
16443 	return (0);
16444 }
16445 
16446 #ifndef NATIVE_BUILD
16447 /* ARGSUSED */
16448 CPL_MATCH_FN(complete_select)
16449 {
16450 	const char *arg0, *arg1, *arg1end;
16451 	int word_start, err = 0, r;
16452 	size_t len;
16453 	char *buf;
16454 
16455 	lscf_prep_hndl();
16456 
16457 	arg0 = line + strspn(line, " \t");
16458 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
16459 
16460 	arg1 = arg0 + sizeof ("select") - 1;
16461 	arg1 += strspn(arg1, " \t");
16462 	word_start = arg1 - line;
16463 
16464 	arg1end = arg1 + strcspn(arg1, " \t");
16465 	if (arg1end < line + word_end)
16466 		return (0);
16467 
16468 	len = line + word_end - arg1;
16469 
16470 	buf = safe_malloc(max_scf_name_len + 1);
16471 
16472 	if (cur_snap != NULL) {
16473 		return (0);
16474 	} else if (cur_inst != NULL) {
16475 		return (0);
16476 	} else if (cur_svc != NULL) {
16477 		scf_instance_t *inst;
16478 		scf_iter_t *iter;
16479 
16480 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
16481 		    (iter = scf_iter_create(g_hndl)) == NULL)
16482 			scfdie();
16483 
16484 		if (scf_iter_service_instances(iter, cur_svc) != 0)
16485 			scfdie();
16486 
16487 		for (;;) {
16488 			r = scf_iter_next_instance(iter, inst);
16489 			if (r == 0)
16490 				break;
16491 			if (r != 1)
16492 				scfdie();
16493 
16494 			if (scf_instance_get_name(inst, buf,
16495 			    max_scf_name_len + 1) < 0)
16496 				scfdie();
16497 
16498 			if (strncmp(buf, arg1, len) == 0) {
16499 				err = cpl_add_completion(cpl, line, word_start,
16500 				    word_end, buf + len, "", " ");
16501 				if (err != 0)
16502 					break;
16503 			}
16504 		}
16505 
16506 		scf_iter_destroy(iter);
16507 		scf_instance_destroy(inst);
16508 
16509 		return (err);
16510 	} else {
16511 		scf_service_t *svc;
16512 		scf_iter_t *iter;
16513 
16514 		assert(cur_scope != NULL);
16515 
16516 		if ((svc = scf_service_create(g_hndl)) == NULL ||
16517 		    (iter = scf_iter_create(g_hndl)) == NULL)
16518 			scfdie();
16519 
16520 		if (scf_iter_scope_services(iter, cur_scope) != 0)
16521 			scfdie();
16522 
16523 		for (;;) {
16524 			r = scf_iter_next_service(iter, svc);
16525 			if (r == 0)
16526 				break;
16527 			if (r != 1)
16528 				scfdie();
16529 
16530 			if (scf_service_get_name(svc, buf,
16531 			    max_scf_name_len + 1) < 0)
16532 				scfdie();
16533 
16534 			if (strncmp(buf, arg1, len) == 0) {
16535 				err = cpl_add_completion(cpl, line, word_start,
16536 				    word_end, buf + len, "", " ");
16537 				if (err != 0)
16538 					break;
16539 			}
16540 		}
16541 
16542 		scf_iter_destroy(iter);
16543 		scf_service_destroy(svc);
16544 
16545 		return (err);
16546 	}
16547 }
16548 
16549 /* ARGSUSED */
16550 CPL_MATCH_FN(complete_command)
16551 {
16552 	uint32_t scope = 0;
16553 
16554 	if (cur_snap != NULL)
16555 		scope = CS_SNAP;
16556 	else if (cur_inst != NULL)
16557 		scope = CS_INST;
16558 	else if (cur_svc != NULL)
16559 		scope = CS_SVC;
16560 	else
16561 		scope = CS_SCOPE;
16562 
16563 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
16564 }
16565 #endif	/* NATIVE_BUILD */
16566