xref: /titanic_44/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision 11d0a659fdd288190c17d8600ecd218e9a9b546d)
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 /*
1776  * Import.  These functions import a bundle into the repository.
1777  */
1778 
1779 /*
1780  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
1781  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
1782  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1783  * lcbdata->sc_err to
1784  *   ENOMEM - out of memory
1785  *   ECONNABORTED - repository connection broken
1786  *   ECANCELED - sc_trans's property group was deleted
1787  *   EINVAL - p's name is invalid (error printed)
1788  *	    - p has an invalid value (error printed)
1789  */
1790 static int
1791 lscf_property_import(void *v, void *pvt)
1792 {
1793 	property_t *p = v;
1794 	scf_callback_t *lcbdata = pvt;
1795 	value_t *vp;
1796 	scf_transaction_t *trans = lcbdata->sc_trans;
1797 	scf_transaction_entry_t *entr;
1798 	scf_value_t *val;
1799 	scf_type_t tp;
1800 
1801 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
1802 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
1803 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
1804 		lcbdata->sc_enable = p;
1805 		return (UU_WALK_NEXT);
1806 	}
1807 
1808 	entr = scf_entry_create(lcbdata->sc_handle);
1809 	if (entr == NULL) {
1810 		switch (scf_error()) {
1811 		case SCF_ERROR_NO_MEMORY:
1812 			return (stash_scferror(lcbdata));
1813 
1814 		case SCF_ERROR_INVALID_ARGUMENT:
1815 		default:
1816 			bad_error("scf_entry_create", scf_error());
1817 		}
1818 	}
1819 
1820 	tp = p->sc_value_type;
1821 
1822 	if (scf_transaction_property_new(trans, entr,
1823 	    p->sc_property_name, tp) != 0) {
1824 		switch (scf_error()) {
1825 		case SCF_ERROR_INVALID_ARGUMENT:
1826 			semerr(emsg_invalid_prop_name, p->sc_property_name);
1827 			scf_entry_destroy(entr);
1828 			return (stash_scferror(lcbdata));
1829 
1830 		case SCF_ERROR_EXISTS:
1831 			break;
1832 
1833 		case SCF_ERROR_DELETED:
1834 		case SCF_ERROR_CONNECTION_BROKEN:
1835 			scf_entry_destroy(entr);
1836 			return (stash_scferror(lcbdata));
1837 
1838 		case SCF_ERROR_NOT_BOUND:
1839 		case SCF_ERROR_HANDLE_MISMATCH:
1840 		case SCF_ERROR_NOT_SET:
1841 		default:
1842 			bad_error("scf_transaction_property_new", scf_error());
1843 		}
1844 
1845 		if (scf_transaction_property_change_type(trans, entr,
1846 		    p->sc_property_name, tp) != 0) {
1847 			switch (scf_error()) {
1848 			case SCF_ERROR_DELETED:
1849 			case SCF_ERROR_CONNECTION_BROKEN:
1850 				scf_entry_destroy(entr);
1851 				return (stash_scferror(lcbdata));
1852 
1853 			case SCF_ERROR_INVALID_ARGUMENT:
1854 				semerr(emsg_invalid_prop_name,
1855 				    p->sc_property_name);
1856 				scf_entry_destroy(entr);
1857 				return (stash_scferror(lcbdata));
1858 
1859 			case SCF_ERROR_NOT_FOUND:
1860 			case SCF_ERROR_NOT_SET:
1861 			case SCF_ERROR_HANDLE_MISMATCH:
1862 			case SCF_ERROR_NOT_BOUND:
1863 			default:
1864 				bad_error(
1865 				    "scf_transaction_property_change_type",
1866 				    scf_error());
1867 			}
1868 		}
1869 	}
1870 
1871 	for (vp = uu_list_first(p->sc_property_values);
1872 	    vp != NULL;
1873 	    vp = uu_list_next(p->sc_property_values, vp)) {
1874 		val = scf_value_create(g_hndl);
1875 		if (val == NULL) {
1876 			switch (scf_error()) {
1877 			case SCF_ERROR_NO_MEMORY:
1878 				return (stash_scferror(lcbdata));
1879 
1880 			case SCF_ERROR_INVALID_ARGUMENT:
1881 			default:
1882 				bad_error("scf_value_create", scf_error());
1883 			}
1884 		}
1885 
1886 		switch (tp) {
1887 		case SCF_TYPE_BOOLEAN:
1888 			scf_value_set_boolean(val, vp->sc_u.sc_count);
1889 			break;
1890 		case SCF_TYPE_COUNT:
1891 			scf_value_set_count(val, vp->sc_u.sc_count);
1892 			break;
1893 		case SCF_TYPE_INTEGER:
1894 			scf_value_set_integer(val, vp->sc_u.sc_integer);
1895 			break;
1896 		default:
1897 			assert(vp->sc_u.sc_string != NULL);
1898 			if (scf_value_set_from_string(val, tp,
1899 			    vp->sc_u.sc_string) != 0) {
1900 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
1901 					bad_error("scf_value_set_from_string",
1902 					    scf_error());
1903 
1904 				warn(gettext("Value \"%s\" is not a valid "
1905 				    "%s.\n"), vp->sc_u.sc_string,
1906 				    scf_type_to_string(tp));
1907 				scf_value_destroy(val);
1908 				return (stash_scferror(lcbdata));
1909 			}
1910 			break;
1911 		}
1912 
1913 		if (scf_entry_add_value(entr, val) != 0)
1914 			bad_error("scf_entry_add_value", scf_error());
1915 	}
1916 
1917 	return (UU_WALK_NEXT);
1918 }
1919 
1920 /*
1921  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
1922  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
1923  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
1924  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1925  * lcbdata->sc_err to
1926  *   ECONNABORTED - repository connection broken
1927  *   ENOMEM - out of memory
1928  *   ENOSPC - svc.configd is out of resources
1929  *   ECANCELED - sc_parent was deleted
1930  *   EPERM - could not create property group (permission denied) (error printed)
1931  *	   - could not modify property group (permission denied) (error printed)
1932  *	   - could not delete property group (permission denied) (error	printed)
1933  *   EROFS - could not create property group (repository is read-only)
1934  *	   - could not delete property group (repository is read-only)
1935  *   EACCES - could not create property group (backend access denied)
1936  *	    - could not delete property group (backend access denied)
1937  *   EEXIST - could not create property group (already exists)
1938  *   EINVAL - invalid property group name (error printed)
1939  *	    - invalid property name (error printed)
1940  *	    - invalid value (error printed)
1941  *   EBUSY - new property group deleted (error printed)
1942  *	   - new property group changed (error printed)
1943  *	   - property group added (error printed)
1944  *	   - property group deleted (error printed)
1945  */
1946 static int
1947 entity_pgroup_import(void *v, void *pvt)
1948 {
1949 	pgroup_t *p = v;
1950 	scf_callback_t cbdata;
1951 	scf_callback_t *lcbdata = pvt;
1952 	void *ent = lcbdata->sc_parent;
1953 	int issvc = lcbdata->sc_service;
1954 	int r;
1955 
1956 	const char * const pg_changed = gettext("%s changed unexpectedly "
1957 	    "(new property group \"%s\" changed).\n");
1958 
1959 	/* Never import deleted property groups. */
1960 	if (p->sc_pgroup_delete)
1961 		return (UU_WALK_NEXT);
1962 
1963 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
1964 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
1965 		lcbdata->sc_general = p;
1966 		return (UU_WALK_NEXT);
1967 	}
1968 
1969 add_pg:
1970 	if (issvc)
1971 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
1972 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1973 	else
1974 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
1975 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1976 	if (r != 0) {
1977 		switch (scf_error()) {
1978 		case SCF_ERROR_DELETED:
1979 		case SCF_ERROR_CONNECTION_BROKEN:
1980 		case SCF_ERROR_BACKEND_READONLY:
1981 		case SCF_ERROR_BACKEND_ACCESS:
1982 		case SCF_ERROR_NO_RESOURCES:
1983 			return (stash_scferror(lcbdata));
1984 
1985 		case SCF_ERROR_EXISTS:
1986 			if (lcbdata->sc_flags & SCI_FORCE)
1987 				break;
1988 			return (stash_scferror(lcbdata));
1989 
1990 		case SCF_ERROR_INVALID_ARGUMENT:
1991 			warn(emsg_fmri_invalid_pg_name_type,
1992 			    lcbdata->sc_source_fmri,
1993 			    p->sc_pgroup_name, p->sc_pgroup_type);
1994 			return (stash_scferror(lcbdata));
1995 
1996 		case SCF_ERROR_PERMISSION_DENIED:
1997 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
1998 			    lcbdata->sc_target_fmri);
1999 			return (stash_scferror(lcbdata));
2000 
2001 		case SCF_ERROR_NOT_BOUND:
2002 		case SCF_ERROR_HANDLE_MISMATCH:
2003 		case SCF_ERROR_NOT_SET:
2004 		default:
2005 			bad_error("scf_service_add_pg", scf_error());
2006 		}
2007 
2008 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2009 			switch (scf_error()) {
2010 			case SCF_ERROR_CONNECTION_BROKEN:
2011 			case SCF_ERROR_DELETED:
2012 				return (stash_scferror(lcbdata));
2013 
2014 			case SCF_ERROR_INVALID_ARGUMENT:
2015 				warn(emsg_fmri_invalid_pg_name,
2016 				    lcbdata->sc_source_fmri,
2017 				    p->sc_pgroup_name);
2018 				return (stash_scferror(lcbdata));
2019 
2020 			case SCF_ERROR_NOT_FOUND:
2021 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2022 				    p->sc_pgroup_name);
2023 				lcbdata->sc_err = EBUSY;
2024 				return (UU_WALK_ERROR);
2025 
2026 			case SCF_ERROR_NOT_BOUND:
2027 			case SCF_ERROR_HANDLE_MISMATCH:
2028 			case SCF_ERROR_NOT_SET:
2029 			default:
2030 				bad_error("entity_get_pg", scf_error());
2031 			}
2032 		}
2033 
2034 		if (lcbdata->sc_flags & SCI_KEEP)
2035 			goto props;
2036 
2037 		if (scf_pg_delete(imp_pg) != 0) {
2038 			switch (scf_error()) {
2039 			case SCF_ERROR_DELETED:
2040 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2041 				    p->sc_pgroup_name);
2042 				lcbdata->sc_err = EBUSY;
2043 				return (UU_WALK_ERROR);
2044 
2045 			case SCF_ERROR_PERMISSION_DENIED:
2046 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2047 				    lcbdata->sc_target_fmri);
2048 				return (stash_scferror(lcbdata));
2049 
2050 			case SCF_ERROR_BACKEND_READONLY:
2051 			case SCF_ERROR_BACKEND_ACCESS:
2052 			case SCF_ERROR_CONNECTION_BROKEN:
2053 				return (stash_scferror(lcbdata));
2054 
2055 			case SCF_ERROR_NOT_SET:
2056 			default:
2057 				bad_error("scf_pg_delete", scf_error());
2058 			}
2059 		}
2060 
2061 		goto add_pg;
2062 	}
2063 
2064 props:
2065 
2066 	/*
2067 	 * Add properties to property group, if any.
2068 	 */
2069 	cbdata.sc_handle = lcbdata->sc_handle;
2070 	cbdata.sc_parent = imp_pg;
2071 	cbdata.sc_flags = lcbdata->sc_flags;
2072 	cbdata.sc_trans = imp_tx;
2073 	cbdata.sc_enable = NULL;
2074 
2075 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2076 		switch (scf_error()) {
2077 		case SCF_ERROR_BACKEND_ACCESS:
2078 		case SCF_ERROR_BACKEND_READONLY:
2079 		case SCF_ERROR_CONNECTION_BROKEN:
2080 			return (stash_scferror(lcbdata));
2081 
2082 		case SCF_ERROR_DELETED:
2083 			warn(pg_changed, lcbdata->sc_target_fmri,
2084 			    p->sc_pgroup_name);
2085 			lcbdata->sc_err = EBUSY;
2086 			return (UU_WALK_ERROR);
2087 
2088 		case SCF_ERROR_PERMISSION_DENIED:
2089 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2090 			    lcbdata->sc_target_fmri);
2091 			return (stash_scferror(lcbdata));
2092 
2093 		case SCF_ERROR_NOT_BOUND:
2094 		case SCF_ERROR_NOT_SET:
2095 		case SCF_ERROR_IN_USE:
2096 		case SCF_ERROR_HANDLE_MISMATCH:
2097 		default:
2098 			bad_error("scf_transaction_start", scf_error());
2099 		}
2100 	}
2101 
2102 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2103 	    UU_DEFAULT) != 0) {
2104 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2105 			bad_error("uu_list_walk", uu_error());
2106 		scf_transaction_reset(imp_tx);
2107 
2108 		lcbdata->sc_err = cbdata.sc_err;
2109 		if (cbdata.sc_err == ECANCELED) {
2110 			warn(pg_changed, lcbdata->sc_target_fmri,
2111 			    p->sc_pgroup_name);
2112 			lcbdata->sc_err = EBUSY;
2113 		}
2114 		return (UU_WALK_ERROR);
2115 	}
2116 
2117 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2118 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2119 
2120 		/*
2121 		 * take the snapshot running snapshot then
2122 		 * import the stored general/enable property
2123 		 */
2124 		r = take_snap(ent, snap_running, imp_rsnap);
2125 		switch (r) {
2126 		case 0:
2127 			break;
2128 
2129 		case ECONNABORTED:
2130 			warn(gettext("Could not take %s snapshot on import "
2131 			    "(repository connection broken).\n"),
2132 			    snap_running);
2133 			lcbdata->sc_err = r;
2134 			return (UU_WALK_ERROR);
2135 		case ECANCELED:
2136 			warn(emsg_deleted);
2137 			lcbdata->sc_err = r;
2138 			return (UU_WALK_ERROR);
2139 
2140 		case EPERM:
2141 			warn(gettext("Could not take %s snapshot "
2142 			    "(permission denied).\n"), snap_running);
2143 			lcbdata->sc_err = r;
2144 			return (UU_WALK_ERROR);
2145 
2146 		case ENOSPC:
2147 			warn(gettext("Could not take %s snapshot"
2148 			    "(repository server out of resources).\n"),
2149 			    snap_running);
2150 			lcbdata->sc_err = r;
2151 			return (UU_WALK_ERROR);
2152 
2153 		default:
2154 			bad_error("take_snap", r);
2155 		}
2156 
2157 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2158 		if (r != UU_WALK_NEXT) {
2159 			if (r != UU_WALK_ERROR)
2160 				bad_error("lscf_property_import", r);
2161 			return (EINVAL);
2162 		}
2163 	}
2164 
2165 	r = scf_transaction_commit(imp_tx);
2166 	switch (r) {
2167 	case 1:
2168 		r = UU_WALK_NEXT;
2169 		break;
2170 
2171 	case 0:
2172 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2173 		lcbdata->sc_err = EBUSY;
2174 		r = UU_WALK_ERROR;
2175 		break;
2176 
2177 	case -1:
2178 		switch (scf_error()) {
2179 		case SCF_ERROR_BACKEND_READONLY:
2180 		case SCF_ERROR_BACKEND_ACCESS:
2181 		case SCF_ERROR_CONNECTION_BROKEN:
2182 		case SCF_ERROR_NO_RESOURCES:
2183 			r = stash_scferror(lcbdata);
2184 			break;
2185 
2186 		case SCF_ERROR_DELETED:
2187 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2188 			    p->sc_pgroup_name);
2189 			lcbdata->sc_err = EBUSY;
2190 			r = UU_WALK_ERROR;
2191 			break;
2192 
2193 		case SCF_ERROR_PERMISSION_DENIED:
2194 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2195 			    lcbdata->sc_target_fmri);
2196 			r = stash_scferror(lcbdata);
2197 			break;
2198 
2199 		case SCF_ERROR_NOT_SET:
2200 		case SCF_ERROR_INVALID_ARGUMENT:
2201 		case SCF_ERROR_NOT_BOUND:
2202 		default:
2203 			bad_error("scf_transaction_commit", scf_error());
2204 		}
2205 		break;
2206 
2207 	default:
2208 		bad_error("scf_transaction_commit", r);
2209 	}
2210 
2211 	scf_transaction_destroy_children(imp_tx);
2212 
2213 	return (r);
2214 }
2215 
2216 /*
2217  * Returns
2218  *   0 - success
2219  *   ECONNABORTED - repository connection broken
2220  *   ENOMEM - out of memory
2221  *   ENOSPC - svc.configd is out of resources
2222  *   ECANCELED - inst was deleted
2223  *   EPERM - could not create property group (permission denied) (error printed)
2224  *	   - could not modify property group (permission denied) (error printed)
2225  *   EROFS - could not create property group (repository is read-only)
2226  *   EACCES - could not create property group (backend access denied)
2227  *   EEXIST - could not create property group (already exists)
2228  *   EINVAL - invalid property group name (error printed)
2229  *	    - invalid property name (error printed)
2230  *	    - invalid value (error printed)
2231  *   EBUSY - new property group changed (error printed)
2232  */
2233 static int
2234 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2235     const entity_t *isvc, int flags)
2236 {
2237 	scf_callback_t cbdata;
2238 
2239 	cbdata.sc_handle = scf_service_handle(svc);
2240 	cbdata.sc_parent = svc;
2241 	cbdata.sc_service = 1;
2242 	cbdata.sc_general = 0;
2243 	cbdata.sc_enable = 0;
2244 	cbdata.sc_flags = flags;
2245 	cbdata.sc_source_fmri = isvc->sc_fmri;
2246 	cbdata.sc_target_fmri = target_fmri;
2247 
2248 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2249 	    UU_DEFAULT) != 0) {
2250 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2251 			bad_error("uu_list_walk", uu_error());
2252 
2253 		return (cbdata.sc_err);
2254 	}
2255 
2256 	return (0);
2257 }
2258 
2259 /*
2260  * Returns
2261  *   0 - success
2262  *   ECONNABORTED - repository connection broken
2263  *   ENOMEM - out of memory
2264  *   ENOSPC - svc.configd is out of resources
2265  *   ECANCELED - inst was deleted
2266  *   EPERM - could not create property group (permission denied) (error printed)
2267  *	   - could not modify property group (permission denied) (error printed)
2268  *   EROFS - could not create property group (repository is read-only)
2269  *   EACCES - could not create property group (backend access denied)
2270  *   EEXIST - could not create property group (already exists)
2271  *   EINVAL - invalid property group name (error printed)
2272  *	    - invalid property name (error printed)
2273  *	    - invalid value (error printed)
2274  *   EBUSY - new property group changed (error printed)
2275  */
2276 static int
2277 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2278     const entity_t *iinst, int flags)
2279 {
2280 	scf_callback_t cbdata;
2281 
2282 	cbdata.sc_handle = scf_instance_handle(inst);
2283 	cbdata.sc_parent = inst;
2284 	cbdata.sc_service = 0;
2285 	cbdata.sc_general = NULL;
2286 	cbdata.sc_enable = NULL;
2287 	cbdata.sc_flags = flags;
2288 	cbdata.sc_source_fmri = iinst->sc_fmri;
2289 	cbdata.sc_target_fmri = target_fmri;
2290 
2291 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2292 	    UU_DEFAULT) != 0) {
2293 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2294 			bad_error("uu_list_walk", uu_error());
2295 
2296 		return (cbdata.sc_err);
2297 	}
2298 
2299 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2300 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2301 		/*
2302 		 * If importing with the SCI_NOENABLED flag then
2303 		 * skip the delay, but if not then add the delay
2304 		 * of the enable property.
2305 		 */
2306 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2307 			cbdata.sc_flags |= SCI_DELAYENABLE;
2308 		}
2309 
2310 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2311 		    != UU_WALK_NEXT)
2312 			return (cbdata.sc_err);
2313 	}
2314 
2315 	return (0);
2316 }
2317 
2318 /*
2319  * Report the reasons why we can't upgrade pg2 to pg1.
2320  */
2321 static void
2322 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2323     int new)
2324 {
2325 	property_t *p1, *p2;
2326 
2327 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2328 
2329 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2330 		return;
2331 
2332 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2333 	    p1 != NULL;
2334 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2335 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2336 		if (p2 != NULL) {
2337 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2338 			    new);
2339 			continue;
2340 		}
2341 
2342 		if (new)
2343 			warn(gettext("Conflict upgrading %s (new property "
2344 			    "group \"%s\" is missing property \"%s\").\n"),
2345 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2346 		else
2347 			warn(gettext("Conflict upgrading %s (property "
2348 			    "\"%s/%s\" is missing).\n"), fmri,
2349 			    pg1->sc_pgroup_name, p1->sc_property_name);
2350 	}
2351 
2352 	/*
2353 	 * Since pg1 should be from the manifest, any properties in pg2 which
2354 	 * aren't in pg1 shouldn't be reported as conflicts.
2355 	 */
2356 }
2357 
2358 /*
2359  * Add transaction entries to tx which will upgrade cur's pg according to old
2360  * & new.
2361  *
2362  * Returns
2363  *   0 - success
2364  *   EINVAL - new has a property with an invalid name or value (message emitted)
2365  *   ENOMEM - out of memory
2366  */
2367 static int
2368 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2369     pgroup_t *cur, int speak, const char *fmri)
2370 {
2371 	property_t *p, *new_p, *cur_p;
2372 	scf_transaction_entry_t *e;
2373 	int r;
2374 	int is_general;
2375 	int is_protected;
2376 
2377 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2378 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2379 		bad_error("uu_list_walk", uu_error());
2380 
2381 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2382 
2383 	for (p = uu_list_first(old->sc_pgroup_props);
2384 	    p != NULL;
2385 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2386 		/* p is a property in the old property group. */
2387 
2388 		/* Protect live properties. */
2389 		is_protected = 0;
2390 		if (is_general) {
2391 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2392 			    0 ||
2393 			    strcmp(p->sc_property_name,
2394 			    SCF_PROPERTY_RESTARTER) == 0)
2395 				is_protected = 1;
2396 		}
2397 
2398 		/* Look for the same property in the new properties. */
2399 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2400 		if (new_p != NULL) {
2401 			new_p->sc_seen = 1;
2402 
2403 			/*
2404 			 * If the new property is the same as the old, don't do
2405 			 * anything (leave any user customizations).
2406 			 */
2407 			if (prop_equal(p, new_p, NULL, NULL, 0))
2408 				continue;
2409 
2410 			if (new_p->sc_property_override)
2411 				goto upgrade;
2412 		}
2413 
2414 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2415 		if (cur_p == NULL) {
2416 			/*
2417 			 * p has been deleted from the repository.  If we were
2418 			 * going to delete it anyway, do nothing.  Otherwise
2419 			 * report a conflict.
2420 			 */
2421 			if (new_p == NULL)
2422 				continue;
2423 
2424 			if (is_protected)
2425 				continue;
2426 
2427 			warn(gettext("Conflict upgrading %s "
2428 			    "(property \"%s/%s\" is missing).\n"), fmri,
2429 			    old->sc_pgroup_name, p->sc_property_name);
2430 			continue;
2431 		}
2432 
2433 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2434 			/*
2435 			 * Conflict.  Don't warn if the property is already the
2436 			 * way we want it, though.
2437 			 */
2438 			if (is_protected)
2439 				continue;
2440 
2441 			if (new_p == NULL)
2442 				(void) prop_equal(p, cur_p, fmri,
2443 				    old->sc_pgroup_name, 0);
2444 			else
2445 				(void) prop_equal(cur_p, new_p, fmri,
2446 				    old->sc_pgroup_name, 0);
2447 			continue;
2448 		}
2449 
2450 		if (is_protected) {
2451 			if (speak)
2452 				warn(gettext("%s: Refusing to upgrade "
2453 				    "\"%s/%s\" (live property).\n"), fmri,
2454 				    old->sc_pgroup_name, p->sc_property_name);
2455 			continue;
2456 		}
2457 
2458 upgrade:
2459 		/* p hasn't been customized in the repository.  Upgrade it. */
2460 		if (new_p == NULL) {
2461 			/* p was deleted.  Delete from cur if unchanged. */
2462 			if (speak)
2463 				warn(gettext(
2464 				    "%s: Deleting property \"%s/%s\".\n"),
2465 				    fmri, old->sc_pgroup_name,
2466 				    p->sc_property_name);
2467 
2468 			e = scf_entry_create(g_hndl);
2469 			if (e == NULL)
2470 				return (ENOMEM);
2471 
2472 			if (scf_transaction_property_delete(tx, e,
2473 			    p->sc_property_name) != 0) {
2474 				switch (scf_error()) {
2475 				case SCF_ERROR_DELETED:
2476 					scf_entry_destroy(e);
2477 					return (ECANCELED);
2478 
2479 				case SCF_ERROR_CONNECTION_BROKEN:
2480 					scf_entry_destroy(e);
2481 					return (ECONNABORTED);
2482 
2483 				case SCF_ERROR_NOT_FOUND:
2484 					/*
2485 					 * This can happen if cur is from the
2486 					 * running snapshot (and it differs
2487 					 * from the live properties).
2488 					 */
2489 					scf_entry_destroy(e);
2490 					break;
2491 
2492 				case SCF_ERROR_HANDLE_MISMATCH:
2493 				case SCF_ERROR_NOT_BOUND:
2494 				case SCF_ERROR_NOT_SET:
2495 				case SCF_ERROR_INVALID_ARGUMENT:
2496 				default:
2497 					bad_error(
2498 					    "scf_transaction_property_delete",
2499 					    scf_error());
2500 				}
2501 			}
2502 		} else {
2503 			scf_callback_t ctx;
2504 
2505 			if (speak)
2506 				warn(gettext(
2507 				    "%s: Upgrading property \"%s/%s\".\n"),
2508 				    fmri, old->sc_pgroup_name,
2509 				    p->sc_property_name);
2510 
2511 			ctx.sc_handle = g_hndl;
2512 			ctx.sc_trans = tx;
2513 			ctx.sc_flags = 0;
2514 
2515 			r = lscf_property_import(new_p, &ctx);
2516 			if (r != UU_WALK_NEXT) {
2517 				if (r != UU_WALK_ERROR)
2518 					bad_error("lscf_property_import", r);
2519 				return (EINVAL);
2520 			}
2521 		}
2522 	}
2523 
2524 	/* Go over the properties which were added. */
2525 	for (new_p = uu_list_first(new->sc_pgroup_props);
2526 	    new_p != NULL;
2527 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
2528 		if (new_p->sc_seen)
2529 			continue;
2530 
2531 		/* This is a new property. */
2532 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
2533 		if (cur_p == NULL) {
2534 			scf_callback_t ctx;
2535 
2536 			ctx.sc_handle = g_hndl;
2537 			ctx.sc_trans = tx;
2538 			ctx.sc_flags = 0;
2539 
2540 			r = lscf_property_import(new_p, &ctx);
2541 			if (r != UU_WALK_NEXT) {
2542 				if (r != UU_WALK_ERROR)
2543 					bad_error("lscf_property_import", r);
2544 				return (EINVAL);
2545 			}
2546 			continue;
2547 		}
2548 
2549 		/*
2550 		 * Report a conflict if the new property differs from the
2551 		 * current one.  Unless it's general/enabled, since that's
2552 		 * never in the last-import snapshot.
2553 		 */
2554 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2555 		    0 &&
2556 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
2557 			continue;
2558 
2559 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
2560 	}
2561 
2562 	return (0);
2563 }
2564 
2565 /*
2566  * Upgrade pg according to old & new.
2567  *
2568  * Returns
2569  *   0 - success
2570  *   ECONNABORTED - repository connection broken
2571  *   ENOMEM - out of memory
2572  *   ENOSPC - svc.configd is out of resources
2573  *   ECANCELED - pg was deleted
2574  *   EPERM - couldn't modify pg (permission denied)
2575  *   EROFS - couldn't modify pg (backend read-only)
2576  *   EACCES - couldn't modify pg (backend access denied)
2577  *   EINVAL - new has a property with invalid name or value (error printed)
2578  *   EBUSY - pg changed unexpectedly
2579  */
2580 static int
2581 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
2582     pgroup_t *new, int speak, const char *fmri)
2583 {
2584 	int r;
2585 
2586 	if (scf_transaction_start(imp_tx, pg) != 0) {
2587 		switch (scf_error()) {
2588 		case SCF_ERROR_CONNECTION_BROKEN:
2589 		case SCF_ERROR_DELETED:
2590 		case SCF_ERROR_PERMISSION_DENIED:
2591 		case SCF_ERROR_BACKEND_READONLY:
2592 		case SCF_ERROR_BACKEND_ACCESS:
2593 			return (scferror2errno(scf_error()));
2594 
2595 		case SCF_ERROR_HANDLE_MISMATCH:
2596 		case SCF_ERROR_IN_USE:
2597 		case SCF_ERROR_NOT_BOUND:
2598 		case SCF_ERROR_NOT_SET:
2599 		default:
2600 			bad_error("scf_transaction_start", scf_error());
2601 		}
2602 	}
2603 
2604 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
2605 	switch (r) {
2606 	case 0:
2607 		break;
2608 
2609 	case EINVAL:
2610 	case ENOMEM:
2611 		scf_transaction_destroy_children(imp_tx);
2612 		return (r);
2613 
2614 	default:
2615 		bad_error("add_upgrade_entries", r);
2616 	}
2617 
2618 	r = scf_transaction_commit(imp_tx);
2619 
2620 	scf_transaction_destroy_children(imp_tx);
2621 
2622 	switch (r) {
2623 	case 1:
2624 		break;
2625 
2626 	case 0:
2627 		return (EBUSY);
2628 
2629 	case -1:
2630 		switch (scf_error()) {
2631 		case SCF_ERROR_CONNECTION_BROKEN:
2632 		case SCF_ERROR_NO_RESOURCES:
2633 		case SCF_ERROR_PERMISSION_DENIED:
2634 		case SCF_ERROR_BACKEND_READONLY:
2635 		case SCF_ERROR_BACKEND_ACCESS:
2636 		case SCF_ERROR_DELETED:
2637 			return (scferror2errno(scf_error()));
2638 
2639 		case SCF_ERROR_NOT_BOUND:
2640 		case SCF_ERROR_INVALID_ARGUMENT:
2641 		case SCF_ERROR_NOT_SET:
2642 		default:
2643 			bad_error("scf_transaction_commit", scf_error());
2644 		}
2645 
2646 	default:
2647 		bad_error("scf_transaction_commit", r);
2648 	}
2649 
2650 	return (0);
2651 }
2652 
2653 /*
2654  * Compares two entity FMRIs.  Returns
2655  *
2656  *   1 - equal
2657  *   0 - not equal
2658  *   -1 - f1 is invalid or not an entity
2659  *   -2 - f2 is invalid or not an entity
2660  */
2661 static int
2662 fmri_equal(const char *f1, const char *f2)
2663 {
2664 	int r;
2665 	const char *s1, *i1, *pg1;
2666 	const char *s2, *i2, *pg2;
2667 
2668 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2669 		return (-1);
2670 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
2671 		return (-1);
2672 
2673 	if (s1 == NULL || pg1 != NULL)
2674 		return (-1);
2675 
2676 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2677 		return (-2);
2678 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
2679 		return (-2);
2680 
2681 	if (s2 == NULL || pg2 != NULL)
2682 		return (-2);
2683 
2684 	r = strcmp(s1, s2);
2685 	if (r != 0)
2686 		return (0);
2687 
2688 	if (i1 == NULL && i2 == NULL)
2689 		return (1);
2690 
2691 	if (i1 == NULL || i2 == NULL)
2692 		return (0);
2693 
2694 	return (strcmp(i1, i2) == 0);
2695 }
2696 
2697 /*
2698  * Import a dependent by creating a dependency property group in the dependent
2699  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
2700  * dependents pg, and add an entry to create a new property for this
2701  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
2702  *
2703  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
2704  * lcbdata->sc_err to
2705  *   ECONNABORTED - repository connection broken
2706  *   ENOMEM - out of memory
2707  *   ENOSPC - configd is out of resources
2708  *   EINVAL - target is invalid (error printed)
2709  *	    - target is not an entity (error printed)
2710  *	    - dependent has invalid name (error printed)
2711  *	    - invalid property name (error printed)
2712  *	    - invalid value (error printed)
2713  *	    - scope of target does not exist (error printed)
2714  *   EPERM - couldn't create target (permission denied) (error printed)
2715  *	   - couldn't create dependency pg (permission denied) (error printed)
2716  *	   - couldn't modify dependency pg (permission denied) (error printed)
2717  *   EROFS - couldn't create target (repository read-only)
2718  *	   - couldn't create dependency pg (repository read-only)
2719  *   EACCES - couldn't create target (backend access denied)
2720  *	    - couldn't create dependency pg (backend access denied)
2721  *   ECANCELED - sc_trans's pg was deleted
2722  *   EALREADY - property for dependent already exists in sc_trans's pg
2723  *   EEXIST - dependency pg already exists in target (error printed)
2724  *   EBUSY - target deleted (error printed)
2725  *         - property group changed during import (error printed)
2726  */
2727 static int
2728 lscf_dependent_import(void *a1, void *pvt)
2729 {
2730 	pgroup_t *pgrp = a1;
2731 	scf_callback_t *lcbdata = pvt;
2732 
2733 	int isservice;
2734 	int ret;
2735 	scf_transaction_entry_t *e;
2736 	scf_value_t *val;
2737 	scf_callback_t dependent_cbdata;
2738 	scf_error_t scfe;
2739 
2740 	/*
2741 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
2742 	 * it's invalid, we fail before modifying the repository.
2743 	 */
2744 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2745 	    &dependent_cbdata.sc_parent, &isservice);
2746 	switch (scfe) {
2747 	case SCF_ERROR_NONE:
2748 		break;
2749 
2750 	case SCF_ERROR_NO_MEMORY:
2751 		return (stash_scferror_err(lcbdata, scfe));
2752 
2753 	case SCF_ERROR_INVALID_ARGUMENT:
2754 		semerr(gettext("The FMRI for the \"%s\" dependent is "
2755 		    "invalid.\n"), pgrp->sc_pgroup_name);
2756 		return (stash_scferror_err(lcbdata, scfe));
2757 
2758 	case SCF_ERROR_CONSTRAINT_VIOLATED:
2759 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
2760 		    "specifies neither a service nor an instance.\n"),
2761 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2762 		return (stash_scferror_err(lcbdata, scfe));
2763 
2764 	case SCF_ERROR_NOT_FOUND:
2765 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2766 		    &dependent_cbdata.sc_parent, &isservice);
2767 		switch (scfe) {
2768 		case SCF_ERROR_NONE:
2769 			break;
2770 
2771 		case SCF_ERROR_NO_MEMORY:
2772 		case SCF_ERROR_BACKEND_READONLY:
2773 		case SCF_ERROR_BACKEND_ACCESS:
2774 			return (stash_scferror_err(lcbdata, scfe));
2775 
2776 		case SCF_ERROR_NOT_FOUND:
2777 			semerr(gettext("The scope in FMRI \"%s\" for the "
2778 			    "\"%s\" dependent does not exist.\n"),
2779 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2780 			lcbdata->sc_err = EINVAL;
2781 			return (UU_WALK_ERROR);
2782 
2783 		case SCF_ERROR_PERMISSION_DENIED:
2784 			warn(gettext(
2785 			    "Could not create %s (permission denied).\n"),
2786 			    pgrp->sc_pgroup_fmri);
2787 			return (stash_scferror_err(lcbdata, scfe));
2788 
2789 		case SCF_ERROR_INVALID_ARGUMENT:
2790 		case SCF_ERROR_CONSTRAINT_VIOLATED:
2791 		default:
2792 			bad_error("create_entity", scfe);
2793 		}
2794 		break;
2795 
2796 	default:
2797 		bad_error("fmri_to_entity", scfe);
2798 	}
2799 
2800 	if (lcbdata->sc_trans != NULL) {
2801 		e = scf_entry_create(lcbdata->sc_handle);
2802 		if (e == NULL) {
2803 			if (scf_error() != SCF_ERROR_NO_MEMORY)
2804 				bad_error("scf_entry_create", scf_error());
2805 
2806 			entity_destroy(dependent_cbdata.sc_parent, isservice);
2807 			return (stash_scferror(lcbdata));
2808 		}
2809 
2810 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
2811 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
2812 			switch (scf_error()) {
2813 			case SCF_ERROR_INVALID_ARGUMENT:
2814 				warn(gettext("Dependent of %s has invalid name "
2815 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
2816 				    pgrp->sc_pgroup_name);
2817 				/* FALLTHROUGH */
2818 
2819 			case SCF_ERROR_DELETED:
2820 			case SCF_ERROR_CONNECTION_BROKEN:
2821 				scf_entry_destroy(e);
2822 				entity_destroy(dependent_cbdata.sc_parent,
2823 				    isservice);
2824 				return (stash_scferror(lcbdata));
2825 
2826 			case SCF_ERROR_EXISTS:
2827 				scf_entry_destroy(e);
2828 				entity_destroy(dependent_cbdata.sc_parent,
2829 				    isservice);
2830 				lcbdata->sc_err = EALREADY;
2831 				return (UU_WALK_ERROR);
2832 
2833 			case SCF_ERROR_NOT_BOUND:
2834 			case SCF_ERROR_HANDLE_MISMATCH:
2835 			case SCF_ERROR_NOT_SET:
2836 			default:
2837 				bad_error("scf_transaction_property_new",
2838 				    scf_error());
2839 			}
2840 		}
2841 
2842 		val = scf_value_create(lcbdata->sc_handle);
2843 		if (val == NULL) {
2844 			if (scf_error() != SCF_ERROR_NO_MEMORY)
2845 				bad_error("scf_value_create", scf_error());
2846 
2847 			entity_destroy(dependent_cbdata.sc_parent, isservice);
2848 			return (stash_scferror(lcbdata));
2849 		}
2850 
2851 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
2852 		    pgrp->sc_pgroup_fmri) != 0)
2853 			/* invalid should have been caught above */
2854 			bad_error("scf_value_set_from_string", scf_error());
2855 
2856 		if (scf_entry_add_value(e, val) != 0)
2857 			bad_error("scf_entry_add_value", scf_error());
2858 	}
2859 
2860 	/* Add the property group to the target entity. */
2861 
2862 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
2863 	dependent_cbdata.sc_flags = 0;
2864 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
2865 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
2866 
2867 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
2868 
2869 	entity_destroy(dependent_cbdata.sc_parent, isservice);
2870 
2871 	if (ret == UU_WALK_NEXT)
2872 		return (ret);
2873 
2874 	if (ret != UU_WALK_ERROR)
2875 		bad_error("entity_pgroup_import", ret);
2876 
2877 	switch (dependent_cbdata.sc_err) {
2878 	case ECANCELED:
2879 		warn(gettext("%s deleted unexpectedly.\n"),
2880 		    pgrp->sc_pgroup_fmri);
2881 		lcbdata->sc_err = EBUSY;
2882 		break;
2883 
2884 	case EEXIST:
2885 		warn(gettext("Could not create \"%s\" dependency in %s "
2886 		    "(already exists).\n"), pgrp->sc_pgroup_name,
2887 		    pgrp->sc_pgroup_fmri);
2888 		/* FALLTHROUGH */
2889 
2890 	default:
2891 		lcbdata->sc_err = dependent_cbdata.sc_err;
2892 	}
2893 
2894 	return (UU_WALK_ERROR);
2895 }
2896 
2897 static int upgrade_dependent(const scf_property_t *, const entity_t *,
2898     const scf_snaplevel_t *, scf_transaction_t *);
2899 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
2900     const pgroup_t *);
2901 
2902 /*
2903  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
2904  * the current dependent targets from running (the snaplevel of a running
2905  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
2906  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
2907  * dependent targets and dependency properties from li_dpts_pg (the
2908  * "dependents" property group in snpl) and snpl (the snaplevel which
2909  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
2910  * snpl doesn't have a "dependents" property group, and any dependents in ient
2911  * are new.
2912  *
2913  * Returns
2914  *   0 - success
2915  *   ECONNABORTED - repository connection broken
2916  *   ENOMEM - out of memory
2917  *   ENOSPC - configd is out of resources
2918  *   ECANCELED - ent was deleted
2919  *   ENODEV - the entity containing li_dpts_pg was deleted
2920  *   EPERM - could not modify dependents pg (permission denied) (error printed)
2921  *	   - couldn't upgrade dependent (permission denied) (error printed)
2922  *	   - couldn't create dependent (permission denied) (error printed)
2923  *   EROFS - could not modify dependents pg (repository read-only)
2924  *	   - couldn't upgrade dependent (repository read-only)
2925  *	   - couldn't create dependent (repository read-only)
2926  *   EACCES - could not modify dependents pg (backend access denied)
2927  *	    - could not upgrade dependent (backend access denied)
2928  *	    - could not create dependent (backend access denied)
2929  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
2930  *	   - dependent target deleted (error printed)
2931  *	   - dependent pg changed (error printed)
2932  *   EINVAL - new dependent is invalid (error printed)
2933  *   EBADF - snpl is corrupt (error printed)
2934  *	   - snpl has corrupt pg (error printed)
2935  *	   - dependency pg in target is corrupt (error printed)
2936  *	   - target has corrupt snapshot (error printed)
2937  *   EEXIST - dependency pg already existed in target service (error printed)
2938  */
2939 static int
2940 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
2941     const scf_snaplevel_t *snpl, const entity_t *ient,
2942     const scf_snaplevel_t *running, void *ent)
2943 {
2944 	pgroup_t *new_dpt_pgroup;
2945 	scf_callback_t cbdata;
2946 	int r, unseen, tx_started = 0;
2947 	int have_cur_depts;
2948 
2949 	const char * const dependents = "dependents";
2950 
2951 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
2952 
2953 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
2954 		/* Nothing to do. */
2955 		return (0);
2956 
2957 	/* Fetch the current version of the "dependents" property group. */
2958 	have_cur_depts = 1;
2959 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
2960 		switch (scf_error()) {
2961 		case SCF_ERROR_NOT_FOUND:
2962 			break;
2963 
2964 		case SCF_ERROR_DELETED:
2965 		case SCF_ERROR_CONNECTION_BROKEN:
2966 			return (scferror2errno(scf_error()));
2967 
2968 		case SCF_ERROR_NOT_SET:
2969 		case SCF_ERROR_INVALID_ARGUMENT:
2970 		case SCF_ERROR_HANDLE_MISMATCH:
2971 		case SCF_ERROR_NOT_BOUND:
2972 		default:
2973 			bad_error("entity_get_pg", scf_error());
2974 		}
2975 
2976 		have_cur_depts = 0;
2977 	}
2978 
2979 	/* Fetch the running version of the "dependents" property group. */
2980 	ud_run_dpts_pg_set = 0;
2981 	if (running != NULL)
2982 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
2983 	else
2984 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
2985 	if (r == 0) {
2986 		ud_run_dpts_pg_set = 1;
2987 	} else {
2988 		switch (scf_error()) {
2989 		case SCF_ERROR_NOT_FOUND:
2990 			break;
2991 
2992 		case SCF_ERROR_DELETED:
2993 		case SCF_ERROR_CONNECTION_BROKEN:
2994 			return (scferror2errno(scf_error()));
2995 
2996 		case SCF_ERROR_NOT_SET:
2997 		case SCF_ERROR_INVALID_ARGUMENT:
2998 		case SCF_ERROR_HANDLE_MISMATCH:
2999 		case SCF_ERROR_NOT_BOUND:
3000 		default:
3001 			bad_error(running ? "scf_snaplevel_get_pg" :
3002 			    "entity_get_pg", scf_error());
3003 		}
3004 	}
3005 
3006 	/*
3007 	 * Clear the seen fields of the dependents, so we can tell which ones
3008 	 * are new.
3009 	 */
3010 	if (uu_list_walk(ient->sc_dependents, clear_int,
3011 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3012 		bad_error("uu_list_walk", uu_error());
3013 
3014 	if (li_dpts_pg != NULL) {
3015 		/*
3016 		 * Each property in li_dpts_pg represents a dependent tag in
3017 		 * the old manifest.  For each, call upgrade_dependent(),
3018 		 * which will change ud_cur_depts_pg or dependencies in other
3019 		 * services as appropriate.  Note (a) that changes to
3020 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3021 		 * made en masse, and (b) it's ok if the entity doesn't have
3022 		 * a current version of the "dependents" property group,
3023 		 * because we'll just consider all dependents as customized
3024 		 * (by being deleted).
3025 		 */
3026 
3027 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3028 			switch (scf_error()) {
3029 			case SCF_ERROR_DELETED:
3030 				return (ENODEV);
3031 
3032 			case SCF_ERROR_CONNECTION_BROKEN:
3033 				return (ECONNABORTED);
3034 
3035 			case SCF_ERROR_HANDLE_MISMATCH:
3036 			case SCF_ERROR_NOT_BOUND:
3037 			case SCF_ERROR_NOT_SET:
3038 			default:
3039 				bad_error("scf_iter_pg_properties",
3040 				    scf_error());
3041 			}
3042 		}
3043 
3044 		if (have_cur_depts &&
3045 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3046 			switch (scf_error()) {
3047 			case SCF_ERROR_BACKEND_ACCESS:
3048 			case SCF_ERROR_BACKEND_READONLY:
3049 			case SCF_ERROR_CONNECTION_BROKEN:
3050 				return (scferror2errno(scf_error()));
3051 
3052 			case SCF_ERROR_DELETED:
3053 				warn(emsg_pg_deleted, ient->sc_fmri,
3054 				    dependents);
3055 				return (EBUSY);
3056 
3057 			case SCF_ERROR_PERMISSION_DENIED:
3058 				warn(emsg_pg_mod_perm, dependents,
3059 				    ient->sc_fmri);
3060 				return (scferror2errno(scf_error()));
3061 
3062 			case SCF_ERROR_HANDLE_MISMATCH:
3063 			case SCF_ERROR_IN_USE:
3064 			case SCF_ERROR_NOT_BOUND:
3065 			case SCF_ERROR_NOT_SET:
3066 			default:
3067 				bad_error("scf_transaction_start", scf_error());
3068 			}
3069 		}
3070 		tx_started = have_cur_depts;
3071 
3072 		for (;;) {
3073 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3074 			if (r == 0)
3075 				break;
3076 			if (r == 1) {
3077 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3078 				    tx_started ? ud_tx : NULL);
3079 				switch (r) {
3080 				case 0:
3081 					continue;
3082 
3083 				case ECONNABORTED:
3084 				case ENOMEM:
3085 				case ENOSPC:
3086 				case EBADF:
3087 				case EBUSY:
3088 				case EINVAL:
3089 				case EPERM:
3090 				case EROFS:
3091 				case EACCES:
3092 				case EEXIST:
3093 					break;
3094 
3095 				case ECANCELED:
3096 					r = ENODEV;
3097 					break;
3098 
3099 				default:
3100 					bad_error("upgrade_dependent", r);
3101 				}
3102 
3103 				if (tx_started)
3104 					scf_transaction_destroy_children(ud_tx);
3105 				return (r);
3106 			}
3107 			if (r != -1)
3108 				bad_error("scf_iter_next_property", r);
3109 
3110 			switch (scf_error()) {
3111 			case SCF_ERROR_DELETED:
3112 				r = ENODEV;
3113 				break;
3114 
3115 			case SCF_ERROR_CONNECTION_BROKEN:
3116 				r = ECONNABORTED;
3117 				break;
3118 
3119 			case SCF_ERROR_NOT_SET:
3120 			case SCF_ERROR_INVALID_ARGUMENT:
3121 			case SCF_ERROR_NOT_BOUND:
3122 			case SCF_ERROR_HANDLE_MISMATCH:
3123 			default:
3124 				bad_error("scf_iter_next_property",
3125 				    scf_error());
3126 			}
3127 
3128 			if (tx_started)
3129 				scf_transaction_destroy_children(ud_tx);
3130 			return (r);
3131 		}
3132 	}
3133 
3134 	/* import unseen dependents */
3135 	unseen = 0;
3136 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3137 	    new_dpt_pgroup != NULL;
3138 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3139 	    new_dpt_pgroup)) {
3140 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3141 			unseen = 1;
3142 			break;
3143 		}
3144 	}
3145 
3146 	/* If there are none, exit early. */
3147 	if (unseen == 0)
3148 		goto commit;
3149 
3150 	/* Set up for lscf_dependent_import() */
3151 	cbdata.sc_handle = g_hndl;
3152 	cbdata.sc_parent = ent;
3153 	cbdata.sc_service = issvc;
3154 	cbdata.sc_flags = 0;
3155 
3156 	if (!have_cur_depts) {
3157 		/*
3158 		 * We have new dependents to import, so we need a "dependents"
3159 		 * property group.
3160 		 */
3161 		if (issvc)
3162 			r = scf_service_add_pg(ent, dependents,
3163 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3164 		else
3165 			r = scf_instance_add_pg(ent, dependents,
3166 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3167 		if (r != 0) {
3168 			switch (scf_error()) {
3169 			case SCF_ERROR_DELETED:
3170 			case SCF_ERROR_CONNECTION_BROKEN:
3171 			case SCF_ERROR_BACKEND_READONLY:
3172 			case SCF_ERROR_BACKEND_ACCESS:
3173 			case SCF_ERROR_NO_RESOURCES:
3174 				return (scferror2errno(scf_error()));
3175 
3176 			case SCF_ERROR_EXISTS:
3177 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3178 				return (EBUSY);
3179 
3180 			case SCF_ERROR_PERMISSION_DENIED:
3181 				warn(emsg_pg_add_perm, dependents,
3182 				    ient->sc_fmri);
3183 				return (scferror2errno(scf_error()));
3184 
3185 			case SCF_ERROR_NOT_BOUND:
3186 			case SCF_ERROR_HANDLE_MISMATCH:
3187 			case SCF_ERROR_INVALID_ARGUMENT:
3188 			case SCF_ERROR_NOT_SET:
3189 			default:
3190 				bad_error("scf_service_add_pg", scf_error());
3191 			}
3192 		}
3193 	}
3194 
3195 	cbdata.sc_trans = ud_tx;
3196 
3197 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3198 		switch (scf_error()) {
3199 		case SCF_ERROR_CONNECTION_BROKEN:
3200 		case SCF_ERROR_BACKEND_ACCESS:
3201 		case SCF_ERROR_BACKEND_READONLY:
3202 			return (scferror2errno(scf_error()));
3203 
3204 		case SCF_ERROR_DELETED:
3205 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3206 			return (EBUSY);
3207 
3208 		case SCF_ERROR_PERMISSION_DENIED:
3209 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3210 			return (scferror2errno(scf_error()));
3211 
3212 		case SCF_ERROR_HANDLE_MISMATCH:
3213 		case SCF_ERROR_IN_USE:
3214 		case SCF_ERROR_NOT_BOUND:
3215 		case SCF_ERROR_NOT_SET:
3216 		default:
3217 			bad_error("scf_transaction_start", scf_error());
3218 		}
3219 	}
3220 	tx_started = 1;
3221 
3222 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3223 	    new_dpt_pgroup != NULL;
3224 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3225 	    new_dpt_pgroup)) {
3226 		if (new_dpt_pgroup->sc_pgroup_seen)
3227 			continue;
3228 
3229 		if (ud_run_dpts_pg_set) {
3230 			/*
3231 			 * If the dependent is already there, then we have
3232 			 * a conflict.
3233 			 */
3234 			if (scf_pg_get_property(ud_run_dpts_pg,
3235 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3236 				r = handle_dependent_conflict(ient, ud_prop,
3237 				    new_dpt_pgroup);
3238 				switch (r) {
3239 				case 0:
3240 					continue;
3241 
3242 				case ECONNABORTED:
3243 				case ENOMEM:
3244 				case EBUSY:
3245 				case EBADF:
3246 				case EINVAL:
3247 					scf_transaction_destroy_children(ud_tx);
3248 					return (r);
3249 
3250 				default:
3251 					bad_error("handle_dependent_conflict",
3252 					    r);
3253 				}
3254 			} else {
3255 				switch (scf_error()) {
3256 				case SCF_ERROR_NOT_FOUND:
3257 					break;
3258 
3259 				case SCF_ERROR_INVALID_ARGUMENT:
3260 					warn(emsg_fmri_invalid_pg_name,
3261 					    ient->sc_fmri,
3262 					    new_dpt_pgroup->sc_pgroup_name);
3263 					scf_transaction_destroy_children(ud_tx);
3264 					return (EINVAL);
3265 
3266 				case SCF_ERROR_DELETED:
3267 					warn(emsg_pg_deleted, ient->sc_fmri,
3268 					    new_dpt_pgroup->sc_pgroup_name);
3269 					scf_transaction_destroy_children(ud_tx);
3270 					return (EBUSY);
3271 
3272 				case SCF_ERROR_CONNECTION_BROKEN:
3273 					scf_transaction_destroy_children(ud_tx);
3274 					return (ECONNABORTED);
3275 
3276 				case SCF_ERROR_NOT_BOUND:
3277 				case SCF_ERROR_HANDLE_MISMATCH:
3278 				case SCF_ERROR_NOT_SET:
3279 				default:
3280 					bad_error("scf_pg_get_property",
3281 					    scf_error());
3282 				}
3283 			}
3284 		}
3285 
3286 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3287 		if (r != UU_WALK_NEXT) {
3288 			if (r != UU_WALK_ERROR)
3289 				bad_error("lscf_dependent_import", r);
3290 
3291 			if (cbdata.sc_err == EALREADY) {
3292 				/* Collisions were handled preemptively. */
3293 				bad_error("lscf_dependent_import",
3294 				    cbdata.sc_err);
3295 			}
3296 
3297 			scf_transaction_destroy_children(ud_tx);
3298 			return (cbdata.sc_err);
3299 		}
3300 	}
3301 
3302 commit:
3303 	if (!tx_started)
3304 		return (0);
3305 
3306 	r = scf_transaction_commit(ud_tx);
3307 
3308 	scf_transaction_destroy_children(ud_tx);
3309 
3310 	switch (r) {
3311 	case 1:
3312 		return (0);
3313 
3314 	case 0:
3315 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3316 		return (EBUSY);
3317 
3318 	case -1:
3319 		break;
3320 
3321 	default:
3322 		bad_error("scf_transaction_commit", r);
3323 	}
3324 
3325 	switch (scf_error()) {
3326 	case SCF_ERROR_CONNECTION_BROKEN:
3327 	case SCF_ERROR_BACKEND_READONLY:
3328 	case SCF_ERROR_BACKEND_ACCESS:
3329 	case SCF_ERROR_NO_RESOURCES:
3330 		return (scferror2errno(scf_error()));
3331 
3332 	case SCF_ERROR_DELETED:
3333 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3334 		return (EBUSY);
3335 
3336 	case SCF_ERROR_PERMISSION_DENIED:
3337 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3338 		return (scferror2errno(scf_error()));
3339 
3340 	case SCF_ERROR_NOT_BOUND:
3341 	case SCF_ERROR_INVALID_ARGUMENT:
3342 	case SCF_ERROR_NOT_SET:
3343 	default:
3344 		bad_error("scf_transaction_destroy", scf_error());
3345 		/* NOTREACHED */
3346 	}
3347 }
3348 
3349 /*
3350  * Used to add the manifests to the list of currently supported manifests.
3351  * We can modify the existing manifest list removing entries if the files
3352  * don't exist.
3353  *
3354  * Get the old list and the new file name
3355  * If the new file name is in the list return
3356  * If not then add the file to the list.
3357  * As we process the list check to see if the files in the old list exist
3358  * 	if not then remove the file from the list.
3359  * Commit the list of manifest file names.
3360  *
3361  */
3362 static int
3363 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3364     const scf_snaplevel_t *running, void *ent)
3365 {
3366 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3367 	scf_property_t *ud_prop = NULL;
3368 	scf_iter_t *ud_prop_iter;
3369 	scf_value_t *fname_value;
3370 	scf_callback_t cbdata;
3371 	pgroup_t *mfst_pgroup;
3372 	property_t *mfst_prop;
3373 	property_t *old_prop;
3374 	char *pname = malloc(MAXPATHLEN);
3375 	char *fval = NULL;
3376 	char *old_pname;
3377 	char *old_fval;
3378 	int no_upgrade_pg;
3379 	int mfst_seen;
3380 	int r;
3381 
3382 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3383 
3384 	/*
3385 	 * This should always be the service base on the code
3386 	 * path, and the fact that the manifests pg is a service
3387 	 * level property group only.
3388 	 */
3389 	ud_mfsts_pg = scf_pg_create(g_hndl);
3390 	ud_prop = scf_property_create(g_hndl);
3391 	ud_prop_iter = scf_iter_create(g_hndl);
3392 	fname_value = scf_value_create(g_hndl);
3393 
3394 	/* Fetch the "manifests" property group */
3395 	no_upgrade_pg = 0;
3396 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3397 	    ud_mfsts_pg);
3398 	if (r != 0) {
3399 		switch (scf_error()) {
3400 		case SCF_ERROR_NOT_FOUND:
3401 			no_upgrade_pg = 1;
3402 			break;
3403 
3404 		case SCF_ERROR_DELETED:
3405 		case SCF_ERROR_CONNECTION_BROKEN:
3406 			return (scferror2errno(scf_error()));
3407 
3408 		case SCF_ERROR_NOT_SET:
3409 		case SCF_ERROR_INVALID_ARGUMENT:
3410 		case SCF_ERROR_HANDLE_MISMATCH:
3411 		case SCF_ERROR_NOT_BOUND:
3412 		default:
3413 			bad_error(running ? "scf_snaplevel_get_pg" :
3414 			    "entity_get_pg", scf_error());
3415 		}
3416 	}
3417 
3418 	if (no_upgrade_pg) {
3419 		cbdata.sc_handle = g_hndl;
3420 		cbdata.sc_parent = ent;
3421 		cbdata.sc_service = issvc;
3422 		cbdata.sc_flags = SCI_FORCE;
3423 		cbdata.sc_source_fmri = ient->sc_fmri;
3424 		cbdata.sc_target_fmri = ient->sc_fmri;
3425 
3426 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3427 			return (cbdata.sc_err);
3428 
3429 		return (0);
3430 	}
3431 
3432 	/* Fetch the new manifests property group */
3433 	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3434 	    mfst_pgroup != NULL;
3435 	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3436 		if (strcmp(mfst_pgroup->sc_pgroup_name,
3437 		    SCF_PG_MANIFESTFILES) == 0)
3438 			break;
3439 	}
3440 
3441 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3442 	    SCF_SUCCESS)
3443 		return (-1);
3444 
3445 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3446 		mfst_seen = 0;
3447 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3448 			continue;
3449 
3450 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3451 		    mfst_prop != NULL;
3452 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3453 		    mfst_prop)) {
3454 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3455 				mfst_seen = 1;
3456 			}
3457 		}
3458 
3459 		/*
3460 		 * If the manifest is not seen then add it to the new mfst
3461 		 * property list to get proccessed into the repo.
3462 		 */
3463 		if (mfst_seen == 0) {
3464 			if (fval == NULL)
3465 				fval = malloc(MAXPATHLEN);
3466 
3467 			/*
3468 			 * If we cannot get the value then there is no
3469 			 * reason to attempt to attach the value to
3470 			 * the property group
3471 			 */
3472 			if (fval != NULL &&
3473 			    prop_get_val(ud_prop, fname_value) == 0 &&
3474 			    scf_value_get_astring(fname_value, fval,
3475 			    MAXPATHLEN) != -1)  {
3476 				/*
3477 				 * If the filesystem/minimal service is
3478 				 * online check to see if the manifest is
3479 				 * there.  If not then there is no need to
3480 				 * add it.
3481 				 *
3482 				 * If filesystem/minimal service is not
3483 				 * online, we go ahead and record the
3484 				 * manifest file name.  We don't check for
3485 				 * its existence because it may be on a
3486 				 * file system that is not yet mounted.
3487 				 */
3488 				if ((est->sc_fs_minimal) &&
3489 				    (access(fval, F_OK) == -1)) {
3490 					continue;
3491 				}
3492 
3493 				old_pname = safe_strdup(pname);
3494 				old_fval = safe_strdup(fval);
3495 				old_prop = internal_property_create(old_pname,
3496 				    SCF_TYPE_ASTRING, 1, old_fval);
3497 
3498 				/*
3499 				 * Already checked to see if the property exists
3500 				 * in the group, and it does not.
3501 				 */
3502 				(void) internal_attach_property(mfst_pgroup,
3503 				    old_prop);
3504 			}
3505 		}
3506 	}
3507 	free(fval);
3508 
3509 	cbdata.sc_handle = g_hndl;
3510 	cbdata.sc_parent = ent;
3511 	cbdata.sc_service = issvc;
3512 	cbdata.sc_flags = SCI_FORCE;
3513 	cbdata.sc_source_fmri = ient->sc_fmri;
3514 	cbdata.sc_target_fmri = ient->sc_fmri;
3515 
3516 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
3517 		return (cbdata.sc_err);
3518 
3519 	return (r);
3520 }
3521 
3522 /*
3523  * prop is taken to be a property in the "dependents" property group of snpl,
3524  * which is taken to be the snaplevel of a last-import snapshot corresponding
3525  * to ient.  If prop is a valid dependents property, upgrade the dependent it
3526  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
3527  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
3528  * of the entity ient represents (possibly in the running snapshot).  If it
3529  * needs to be changed, an entry will be added to tx, if not NULL.
3530  *
3531  * Returns
3532  *   0 - success
3533  *   ECONNABORTED - repository connection broken
3534  *   ENOMEM - out of memory
3535  *   ENOSPC - configd was out of resources
3536  *   ECANCELED - snpl's entity was deleted
3537  *   EINVAL - dependent target is invalid (error printed)
3538  *	    - dependent is invalid (error printed)
3539  *   EBADF - snpl is corrupt (error printed)
3540  *	   - snpl has corrupt pg (error printed)
3541  *	   - dependency pg in target is corrupt (error printed)
3542  *	   - running snapshot in dependent is missing snaplevel (error printed)
3543  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
3544  *	   - couldn't create dependent (permission denied) (error printed)
3545  *	   - couldn't modify dependent pg (permission denied) (error printed)
3546  *   EROFS - couldn't delete dependency pg (repository read-only)
3547  *	   - couldn't create dependent (repository read-only)
3548  *   EACCES - couldn't delete dependency pg (backend access denied)
3549  *	    - couldn't create dependent (backend access denied)
3550  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
3551  *	   - tx's pg was deleted (error printed)
3552  *	   - dependent pg was changed or deleted (error printed)
3553  *   EEXIST - dependency pg already exists in new target (error printed)
3554  */
3555 static int
3556 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
3557     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
3558 {
3559 	pgroup_t pgrp;
3560 	scf_type_t ty;
3561 	pgroup_t *new_dpt_pgroup;
3562 	pgroup_t *old_dpt_pgroup = NULL;
3563 	pgroup_t *current_pg;
3564 	scf_callback_t cbdata;
3565 	int tissvc;
3566 	void *target_ent;
3567 	scf_error_t serr;
3568 	int r;
3569 	scf_transaction_entry_t *ent;
3570 
3571 	const char * const cf_inval = gettext("Conflict upgrading %s "
3572 	    "(dependent \"%s\" has invalid dependents property).\n");
3573 	const char * const cf_missing = gettext("Conflict upgrading %s "
3574 	    "(dependent \"%s\" is missing).\n");
3575 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
3576 	    "(dependent \"%s\" has new dependency property group).\n");
3577 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
3578 	    "(dependent \"%s\" has new target).\n");
3579 	const char * const li_corrupt =
3580 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
3581 	const char * const upgrading =
3582 	    gettext("%s: Upgrading dependent \"%s\".\n");
3583 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
3584 	    "corrupt (missing snaplevel).\n");
3585 
3586 	if (scf_property_type(prop, &ty) != 0) {
3587 		switch (scf_error()) {
3588 		case SCF_ERROR_DELETED:
3589 		case SCF_ERROR_CONNECTION_BROKEN:
3590 			return (scferror2errno(scf_error()));
3591 
3592 		case SCF_ERROR_NOT_BOUND:
3593 		case SCF_ERROR_NOT_SET:
3594 		default:
3595 			bad_error("scf_property_type", scf_error());
3596 		}
3597 	}
3598 
3599 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3600 		warn(li_corrupt, ient->sc_fmri);
3601 		return (EBADF);
3602 	}
3603 
3604 	/*
3605 	 * prop represents a dependent in the old manifest.  It is named after
3606 	 * the dependent.
3607 	 */
3608 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
3609 		switch (scf_error()) {
3610 		case SCF_ERROR_DELETED:
3611 		case SCF_ERROR_CONNECTION_BROKEN:
3612 			return (scferror2errno(scf_error()));
3613 
3614 		case SCF_ERROR_NOT_BOUND:
3615 		case SCF_ERROR_NOT_SET:
3616 		default:
3617 			bad_error("scf_property_get_name", scf_error());
3618 		}
3619 	}
3620 
3621 	/* See if it's in the new manifest. */
3622 	pgrp.sc_pgroup_name = ud_name;
3623 	new_dpt_pgroup =
3624 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
3625 
3626 	/* If it's not, delete it... if it hasn't been customized. */
3627 	if (new_dpt_pgroup == NULL) {
3628 		pgroup_t *dpt;
3629 
3630 		if (!ud_run_dpts_pg_set)
3631 			return (0);
3632 
3633 		if (scf_property_get_value(prop, ud_val) != 0) {
3634 			switch (scf_error()) {
3635 			case SCF_ERROR_NOT_FOUND:
3636 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3637 				warn(li_corrupt, ient->sc_fmri);
3638 				return (EBADF);
3639 
3640 			case SCF_ERROR_DELETED:
3641 			case SCF_ERROR_CONNECTION_BROKEN:
3642 				return (scferror2errno(scf_error()));
3643 
3644 			case SCF_ERROR_HANDLE_MISMATCH:
3645 			case SCF_ERROR_NOT_BOUND:
3646 			case SCF_ERROR_NOT_SET:
3647 			case SCF_ERROR_PERMISSION_DENIED:
3648 			default:
3649 				bad_error("scf_property_get_value",
3650 				    scf_error());
3651 			}
3652 		}
3653 
3654 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
3655 		    max_scf_value_len + 1) < 0)
3656 			bad_error("scf_value_get_as_string", scf_error());
3657 
3658 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
3659 		    0) {
3660 			switch (scf_error()) {
3661 			case SCF_ERROR_NOT_FOUND:
3662 				return (0);
3663 
3664 			case SCF_ERROR_CONNECTION_BROKEN:
3665 				return (scferror2errno(scf_error()));
3666 
3667 			case SCF_ERROR_DELETED:
3668 				warn(emsg_pg_deleted, ient->sc_fmri,
3669 				    "dependents");
3670 				return (EBUSY);
3671 
3672 			case SCF_ERROR_INVALID_ARGUMENT:
3673 			case SCF_ERROR_NOT_BOUND:
3674 			case SCF_ERROR_HANDLE_MISMATCH:
3675 			case SCF_ERROR_NOT_SET:
3676 			default:
3677 				bad_error("scf_pg_get_property", scf_error());
3678 			}
3679 		}
3680 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
3681 			switch (scf_error()) {
3682 			case SCF_ERROR_NOT_FOUND:
3683 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3684 				warn(cf_inval, ient->sc_fmri, ud_name);
3685 				return (0);
3686 
3687 			case SCF_ERROR_DELETED:
3688 			case SCF_ERROR_CONNECTION_BROKEN:
3689 				return (scferror2errno(scf_error()));
3690 
3691 			case SCF_ERROR_HANDLE_MISMATCH:
3692 			case SCF_ERROR_NOT_BOUND:
3693 			case SCF_ERROR_NOT_SET:
3694 			case SCF_ERROR_PERMISSION_DENIED:
3695 			default:
3696 				bad_error("scf_property_get_value",
3697 				    scf_error());
3698 			}
3699 		}
3700 
3701 		ty = scf_value_type(ud_val);
3702 		assert(ty != SCF_TYPE_INVALID);
3703 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3704 			warn(cf_inval, ient->sc_fmri, ud_name);
3705 			return (0);
3706 		}
3707 
3708 		if (scf_value_get_as_string(ud_val, ud_ctarg,
3709 		    max_scf_value_len + 1) < 0)
3710 			bad_error("scf_value_get_as_string", scf_error());
3711 
3712 		r = fmri_equal(ud_ctarg, ud_oldtarg);
3713 		switch (r) {
3714 		case 1:
3715 			break;
3716 
3717 		case 0:
3718 		case -1:	/* warn? */
3719 			warn(cf_newtarg, ient->sc_fmri, ud_name);
3720 			return (0);
3721 
3722 		case -2:
3723 			warn(li_corrupt, ient->sc_fmri);
3724 			return (EBADF);
3725 
3726 		default:
3727 			bad_error("fmri_equal", r);
3728 		}
3729 
3730 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3731 			switch (scf_error()) {
3732 			case SCF_ERROR_NOT_FOUND:
3733 				warn(li_corrupt, ient->sc_fmri);
3734 				return (EBADF);
3735 
3736 			case SCF_ERROR_DELETED:
3737 			case SCF_ERROR_CONNECTION_BROKEN:
3738 				return (scferror2errno(scf_error()));
3739 
3740 			case SCF_ERROR_NOT_BOUND:
3741 			case SCF_ERROR_HANDLE_MISMATCH:
3742 			case SCF_ERROR_INVALID_ARGUMENT:
3743 			case SCF_ERROR_NOT_SET:
3744 			default:
3745 				bad_error("scf_snaplevel_get_pg", scf_error());
3746 			}
3747 		}
3748 
3749 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3750 		    snap_lastimport);
3751 		switch (r) {
3752 		case 0:
3753 			break;
3754 
3755 		case ECANCELED:
3756 		case ECONNABORTED:
3757 		case ENOMEM:
3758 		case EBADF:
3759 			return (r);
3760 
3761 		case EACCES:
3762 		default:
3763 			bad_error("load_pg", r);
3764 		}
3765 
3766 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3767 		switch (serr) {
3768 		case SCF_ERROR_NONE:
3769 			break;
3770 
3771 		case SCF_ERROR_NO_MEMORY:
3772 			internal_pgroup_free(old_dpt_pgroup);
3773 			return (ENOMEM);
3774 
3775 		case SCF_ERROR_NOT_FOUND:
3776 			internal_pgroup_free(old_dpt_pgroup);
3777 			goto delprop;
3778 
3779 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
3780 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
3781 		default:
3782 			bad_error("fmri_to_entity", serr);
3783 		}
3784 
3785 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
3786 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
3787 		switch (r) {
3788 		case 0:
3789 			break;
3790 
3791 		case ECONNABORTED:
3792 			internal_pgroup_free(old_dpt_pgroup);
3793 			return (r);
3794 
3795 		case ECANCELED:
3796 		case ENOENT:
3797 			internal_pgroup_free(old_dpt_pgroup);
3798 			goto delprop;
3799 
3800 		case EBADF:
3801 			warn(r_no_lvl, ud_ctarg);
3802 			internal_pgroup_free(old_dpt_pgroup);
3803 			return (r);
3804 
3805 		case EINVAL:
3806 		default:
3807 			bad_error("entity_get_running_pg", r);
3808 		}
3809 
3810 		/* load it */
3811 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
3812 		switch (r) {
3813 		case 0:
3814 			break;
3815 
3816 		case ECANCELED:
3817 			internal_pgroup_free(old_dpt_pgroup);
3818 			goto delprop;
3819 
3820 		case ECONNABORTED:
3821 		case ENOMEM:
3822 		case EBADF:
3823 			internal_pgroup_free(old_dpt_pgroup);
3824 			return (r);
3825 
3826 		case EACCES:
3827 		default:
3828 			bad_error("load_pg", r);
3829 		}
3830 
3831 		/* compare property groups */
3832 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
3833 			warn(cf_newdpg, ient->sc_fmri, ud_name);
3834 			internal_pgroup_free(old_dpt_pgroup);
3835 			internal_pgroup_free(current_pg);
3836 			return (0);
3837 		}
3838 
3839 		internal_pgroup_free(old_dpt_pgroup);
3840 		internal_pgroup_free(current_pg);
3841 
3842 		if (g_verbose)
3843 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
3844 			    ient->sc_fmri, ud_name);
3845 
3846 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
3847 			switch (scf_error()) {
3848 			case SCF_ERROR_NOT_FOUND:
3849 			case SCF_ERROR_DELETED:
3850 				internal_pgroup_free(old_dpt_pgroup);
3851 				goto delprop;
3852 
3853 			case SCF_ERROR_CONNECTION_BROKEN:
3854 				internal_pgroup_free(old_dpt_pgroup);
3855 				return (ECONNABORTED);
3856 
3857 			case SCF_ERROR_NOT_SET:
3858 			case SCF_ERROR_INVALID_ARGUMENT:
3859 			case SCF_ERROR_HANDLE_MISMATCH:
3860 			case SCF_ERROR_NOT_BOUND:
3861 			default:
3862 				bad_error("entity_get_pg", scf_error());
3863 			}
3864 		}
3865 
3866 		if (scf_pg_delete(ud_pg) != 0) {
3867 			switch (scf_error()) {
3868 			case SCF_ERROR_DELETED:
3869 				break;
3870 
3871 			case SCF_ERROR_CONNECTION_BROKEN:
3872 			case SCF_ERROR_BACKEND_READONLY:
3873 			case SCF_ERROR_BACKEND_ACCESS:
3874 				return (scferror2errno(scf_error()));
3875 
3876 			case SCF_ERROR_PERMISSION_DENIED:
3877 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
3878 				return (scferror2errno(scf_error()));
3879 
3880 			case SCF_ERROR_NOT_SET:
3881 			default:
3882 				bad_error("scf_pg_delete", scf_error());
3883 			}
3884 		}
3885 
3886 		/*
3887 		 * This service was changed, so it must be refreshed.  But
3888 		 * since it's not mentioned in the new manifest, we have to
3889 		 * record its FMRI here for use later.  We record the name
3890 		 * & the entity (via sc_parent) in case we need to print error
3891 		 * messages during the refresh.
3892 		 */
3893 		dpt = internal_pgroup_new();
3894 		if (dpt == NULL)
3895 			return (ENOMEM);
3896 		dpt->sc_pgroup_name = strdup(ud_name);
3897 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
3898 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
3899 			return (ENOMEM);
3900 		dpt->sc_parent = (entity_t *)ient;
3901 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
3902 			uu_die(gettext("libuutil error: %s\n"),
3903 			    uu_strerror(uu_error()));
3904 
3905 delprop:
3906 		if (tx == NULL)
3907 			return (0);
3908 
3909 		ent = scf_entry_create(g_hndl);
3910 		if (ent == NULL)
3911 			return (ENOMEM);
3912 
3913 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
3914 			scf_entry_destroy(ent);
3915 			switch (scf_error()) {
3916 			case SCF_ERROR_DELETED:
3917 				warn(emsg_pg_deleted, ient->sc_fmri,
3918 				    "dependents");
3919 				return (EBUSY);
3920 
3921 			case SCF_ERROR_CONNECTION_BROKEN:
3922 				return (scferror2errno(scf_error()));
3923 
3924 			case SCF_ERROR_NOT_FOUND:
3925 				break;
3926 
3927 			case SCF_ERROR_HANDLE_MISMATCH:
3928 			case SCF_ERROR_NOT_BOUND:
3929 			case SCF_ERROR_INVALID_ARGUMENT:
3930 			case SCF_ERROR_NOT_SET:
3931 			default:
3932 				bad_error("scf_transaction_property_delete",
3933 				    scf_error());
3934 			}
3935 		}
3936 
3937 		return (0);
3938 	}
3939 
3940 	new_dpt_pgroup->sc_pgroup_seen = 1;
3941 
3942 	/*
3943 	 * Decide whether the dependent has changed in the manifest.
3944 	 */
3945 	/* Compare the target. */
3946 	if (scf_property_get_value(prop, ud_val) != 0) {
3947 		switch (scf_error()) {
3948 		case SCF_ERROR_NOT_FOUND:
3949 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3950 			warn(li_corrupt, ient->sc_fmri);
3951 			return (EBADF);
3952 
3953 		case SCF_ERROR_DELETED:
3954 		case SCF_ERROR_CONNECTION_BROKEN:
3955 			return (scferror2errno(scf_error()));
3956 
3957 		case SCF_ERROR_HANDLE_MISMATCH:
3958 		case SCF_ERROR_NOT_BOUND:
3959 		case SCF_ERROR_NOT_SET:
3960 		case SCF_ERROR_PERMISSION_DENIED:
3961 		default:
3962 			bad_error("scf_property_get_value", scf_error());
3963 		}
3964 	}
3965 
3966 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
3967 	    0)
3968 		bad_error("scf_value_get_as_string", scf_error());
3969 
3970 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
3971 	switch (r) {
3972 	case 0:
3973 		break;
3974 
3975 	case 1:
3976 		/* Compare the dependency pgs. */
3977 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3978 			switch (scf_error()) {
3979 			case SCF_ERROR_NOT_FOUND:
3980 				warn(li_corrupt, ient->sc_fmri);
3981 				return (EBADF);
3982 
3983 			case SCF_ERROR_DELETED:
3984 			case SCF_ERROR_CONNECTION_BROKEN:
3985 				return (scferror2errno(scf_error()));
3986 
3987 			case SCF_ERROR_NOT_BOUND:
3988 			case SCF_ERROR_HANDLE_MISMATCH:
3989 			case SCF_ERROR_INVALID_ARGUMENT:
3990 			case SCF_ERROR_NOT_SET:
3991 			default:
3992 				bad_error("scf_snaplevel_get_pg", scf_error());
3993 			}
3994 		}
3995 
3996 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3997 		    snap_lastimport);
3998 		switch (r) {
3999 		case 0:
4000 			break;
4001 
4002 		case ECANCELED:
4003 		case ECONNABORTED:
4004 		case ENOMEM:
4005 		case EBADF:
4006 			return (r);
4007 
4008 		case EACCES:
4009 		default:
4010 			bad_error("load_pg", r);
4011 		}
4012 
4013 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4014 			/* no change, leave customizations */
4015 			internal_pgroup_free(old_dpt_pgroup);
4016 			return (0);
4017 		}
4018 		break;
4019 
4020 	case -1:
4021 		warn(li_corrupt, ient->sc_fmri);
4022 		return (EBADF);
4023 
4024 	case -2:
4025 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4026 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4027 		return (EINVAL);
4028 
4029 	default:
4030 		bad_error("fmri_equal", r);
4031 	}
4032 
4033 	/*
4034 	 * The dependent has changed in the manifest.  Upgrade the current
4035 	 * properties if they haven't been customized.
4036 	 */
4037 
4038 	/*
4039 	 * If new_dpt_pgroup->sc_override, then act as though the property
4040 	 * group hasn't been customized.
4041 	 */
4042 	if (new_dpt_pgroup->sc_pgroup_override)
4043 		goto nocust;
4044 
4045 	if (!ud_run_dpts_pg_set) {
4046 		warn(cf_missing, ient->sc_fmri, ud_name);
4047 		r = 0;
4048 		goto out;
4049 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4050 		switch (scf_error()) {
4051 		case SCF_ERROR_NOT_FOUND:
4052 			warn(cf_missing, ient->sc_fmri, ud_name);
4053 			r = 0;
4054 			goto out;
4055 
4056 		case SCF_ERROR_CONNECTION_BROKEN:
4057 			r = scferror2errno(scf_error());
4058 			goto out;
4059 
4060 		case SCF_ERROR_DELETED:
4061 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4062 			r = EBUSY;
4063 			goto out;
4064 
4065 		case SCF_ERROR_INVALID_ARGUMENT:
4066 		case SCF_ERROR_NOT_BOUND:
4067 		case SCF_ERROR_HANDLE_MISMATCH:
4068 		case SCF_ERROR_NOT_SET:
4069 		default:
4070 			bad_error("scf_pg_get_property", scf_error());
4071 		}
4072 	}
4073 
4074 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4075 		switch (scf_error()) {
4076 		case SCF_ERROR_NOT_FOUND:
4077 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4078 			warn(cf_inval, ient->sc_fmri, ud_name);
4079 			r = 0;
4080 			goto out;
4081 
4082 		case SCF_ERROR_DELETED:
4083 		case SCF_ERROR_CONNECTION_BROKEN:
4084 			r = scferror2errno(scf_error());
4085 			goto out;
4086 
4087 		case SCF_ERROR_HANDLE_MISMATCH:
4088 		case SCF_ERROR_NOT_BOUND:
4089 		case SCF_ERROR_NOT_SET:
4090 		case SCF_ERROR_PERMISSION_DENIED:
4091 		default:
4092 			bad_error("scf_property_get_value", scf_error());
4093 		}
4094 	}
4095 
4096 	ty = scf_value_type(ud_val);
4097 	assert(ty != SCF_TYPE_INVALID);
4098 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4099 		warn(cf_inval, ient->sc_fmri, ud_name);
4100 		r = 0;
4101 		goto out;
4102 	}
4103 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4104 	    0)
4105 		bad_error("scf_value_get_as_string", scf_error());
4106 
4107 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4108 	if (r == -1) {
4109 		warn(cf_inval, ient->sc_fmri, ud_name);
4110 		r = 0;
4111 		goto out;
4112 	} else if (r == -2) {
4113 		warn(li_corrupt, ient->sc_fmri);
4114 		r = EBADF;
4115 		goto out;
4116 	} else if (r == 0) {
4117 		/*
4118 		 * Target has been changed.  Only abort now if it's been
4119 		 * changed to something other than what's in the manifest.
4120 		 */
4121 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4122 		if (r == -1) {
4123 			warn(cf_inval, ient->sc_fmri, ud_name);
4124 			r = 0;
4125 			goto out;
4126 		} else if (r == 0) {
4127 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4128 			r = 0;
4129 			goto out;
4130 		} else if (r != 1) {
4131 			/* invalid sc_pgroup_fmri caught above */
4132 			bad_error("fmri_equal", r);
4133 		}
4134 
4135 		/*
4136 		 * Fetch the current dependency pg.  If it's what the manifest
4137 		 * says, then no problem.
4138 		 */
4139 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4140 		switch (serr) {
4141 		case SCF_ERROR_NONE:
4142 			break;
4143 
4144 		case SCF_ERROR_NOT_FOUND:
4145 			warn(cf_missing, ient->sc_fmri, ud_name);
4146 			r = 0;
4147 			goto out;
4148 
4149 		case SCF_ERROR_NO_MEMORY:
4150 			r = ENOMEM;
4151 			goto out;
4152 
4153 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4154 		case SCF_ERROR_INVALID_ARGUMENT:
4155 		default:
4156 			bad_error("fmri_to_entity", serr);
4157 		}
4158 
4159 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4160 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4161 		switch (r) {
4162 		case 0:
4163 			break;
4164 
4165 		case ECONNABORTED:
4166 			goto out;
4167 
4168 		case ECANCELED:
4169 		case ENOENT:
4170 			warn(cf_missing, ient->sc_fmri, ud_name);
4171 			r = 0;
4172 			goto out;
4173 
4174 		case EBADF:
4175 			warn(r_no_lvl, ud_ctarg);
4176 			goto out;
4177 
4178 		case EINVAL:
4179 		default:
4180 			bad_error("entity_get_running_pg", r);
4181 		}
4182 
4183 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4184 		switch (r) {
4185 		case 0:
4186 			break;
4187 
4188 		case ECANCELED:
4189 			warn(cf_missing, ient->sc_fmri, ud_name);
4190 			r = 0;
4191 			goto out;
4192 
4193 		case ECONNABORTED:
4194 		case ENOMEM:
4195 		case EBADF:
4196 			goto out;
4197 
4198 		case EACCES:
4199 		default:
4200 			bad_error("load_pg", r);
4201 		}
4202 
4203 		if (!pg_equal(current_pg, new_dpt_pgroup))
4204 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4205 		internal_pgroup_free(current_pg);
4206 		r = 0;
4207 		goto out;
4208 	} else if (r != 1) {
4209 		bad_error("fmri_equal", r);
4210 	}
4211 
4212 nocust:
4213 	/*
4214 	 * Target has not been customized.  Check the dependency property
4215 	 * group.
4216 	 */
4217 
4218 	if (old_dpt_pgroup == NULL) {
4219 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4220 		    ud_pg) != 0) {
4221 			switch (scf_error()) {
4222 			case SCF_ERROR_NOT_FOUND:
4223 				warn(li_corrupt, ient->sc_fmri);
4224 				return (EBADF);
4225 
4226 			case SCF_ERROR_DELETED:
4227 			case SCF_ERROR_CONNECTION_BROKEN:
4228 				return (scferror2errno(scf_error()));
4229 
4230 			case SCF_ERROR_NOT_BOUND:
4231 			case SCF_ERROR_HANDLE_MISMATCH:
4232 			case SCF_ERROR_INVALID_ARGUMENT:
4233 			case SCF_ERROR_NOT_SET:
4234 			default:
4235 				bad_error("scf_snaplevel_get_pg", scf_error());
4236 			}
4237 		}
4238 
4239 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4240 		    snap_lastimport);
4241 		switch (r) {
4242 		case 0:
4243 			break;
4244 
4245 		case ECANCELED:
4246 		case ECONNABORTED:
4247 		case ENOMEM:
4248 		case EBADF:
4249 			return (r);
4250 
4251 		case EACCES:
4252 		default:
4253 			bad_error("load_pg", r);
4254 		}
4255 	}
4256 
4257 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4258 	switch (serr) {
4259 	case SCF_ERROR_NONE:
4260 		break;
4261 
4262 	case SCF_ERROR_NOT_FOUND:
4263 		warn(cf_missing, ient->sc_fmri, ud_name);
4264 		r = 0;
4265 		goto out;
4266 
4267 	case SCF_ERROR_NO_MEMORY:
4268 		r = ENOMEM;
4269 		goto out;
4270 
4271 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4272 	case SCF_ERROR_INVALID_ARGUMENT:
4273 	default:
4274 		bad_error("fmri_to_entity", serr);
4275 	}
4276 
4277 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4278 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4279 	switch (r) {
4280 	case 0:
4281 		break;
4282 
4283 	case ECONNABORTED:
4284 		goto out;
4285 
4286 	case ECANCELED:
4287 	case ENOENT:
4288 		warn(cf_missing, ient->sc_fmri, ud_name);
4289 		r = 0;
4290 		goto out;
4291 
4292 	case EBADF:
4293 		warn(r_no_lvl, ud_ctarg);
4294 		goto out;
4295 
4296 	case EINVAL:
4297 	default:
4298 		bad_error("entity_get_running_pg", r);
4299 	}
4300 
4301 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4302 	switch (r) {
4303 	case 0:
4304 		break;
4305 
4306 	case ECANCELED:
4307 		warn(cf_missing, ient->sc_fmri, ud_name);
4308 		goto out;
4309 
4310 	case ECONNABORTED:
4311 	case ENOMEM:
4312 	case EBADF:
4313 		goto out;
4314 
4315 	case EACCES:
4316 	default:
4317 		bad_error("load_pg", r);
4318 	}
4319 
4320 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4321 		if (!pg_equal(current_pg, new_dpt_pgroup))
4322 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4323 		internal_pgroup_free(current_pg);
4324 		r = 0;
4325 		goto out;
4326 	}
4327 
4328 	/* Uncustomized.  Upgrade. */
4329 
4330 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4331 	switch (r) {
4332 	case 1:
4333 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4334 			/* Already upgraded. */
4335 			internal_pgroup_free(current_pg);
4336 			r = 0;
4337 			goto out;
4338 		}
4339 
4340 		internal_pgroup_free(current_pg);
4341 
4342 		/* upgrade current_pg */
4343 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4344 			switch (scf_error()) {
4345 			case SCF_ERROR_CONNECTION_BROKEN:
4346 				r = scferror2errno(scf_error());
4347 				goto out;
4348 
4349 			case SCF_ERROR_DELETED:
4350 				warn(cf_missing, ient->sc_fmri, ud_name);
4351 				r = 0;
4352 				goto out;
4353 
4354 			case SCF_ERROR_NOT_FOUND:
4355 				break;
4356 
4357 			case SCF_ERROR_INVALID_ARGUMENT:
4358 			case SCF_ERROR_NOT_BOUND:
4359 			case SCF_ERROR_NOT_SET:
4360 			case SCF_ERROR_HANDLE_MISMATCH:
4361 			default:
4362 				bad_error("entity_get_pg", scf_error());
4363 			}
4364 
4365 			if (tissvc)
4366 				r = scf_service_add_pg(target_ent, ud_name,
4367 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4368 			else
4369 				r = scf_instance_add_pg(target_ent, ud_name,
4370 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4371 			if (r != 0) {
4372 				switch (scf_error()) {
4373 				case SCF_ERROR_CONNECTION_BROKEN:
4374 				case SCF_ERROR_NO_RESOURCES:
4375 				case SCF_ERROR_BACKEND_READONLY:
4376 				case SCF_ERROR_BACKEND_ACCESS:
4377 					r = scferror2errno(scf_error());
4378 					goto out;
4379 
4380 				case SCF_ERROR_DELETED:
4381 					warn(cf_missing, ient->sc_fmri,
4382 					    ud_name);
4383 					r = 0;
4384 					goto out;
4385 
4386 				case SCF_ERROR_PERMISSION_DENIED:
4387 					warn(emsg_pg_deleted, ud_ctarg,
4388 					    ud_name);
4389 					r = EPERM;
4390 					goto out;
4391 
4392 				case SCF_ERROR_EXISTS:
4393 					warn(emsg_pg_added, ud_ctarg, ud_name);
4394 					r = EBUSY;
4395 					goto out;
4396 
4397 				case SCF_ERROR_NOT_BOUND:
4398 				case SCF_ERROR_HANDLE_MISMATCH:
4399 				case SCF_ERROR_INVALID_ARGUMENT:
4400 				case SCF_ERROR_NOT_SET:
4401 				default:
4402 					bad_error("entity_add_pg", scf_error());
4403 				}
4404 			}
4405 		}
4406 
4407 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4408 		switch (r) {
4409 		case 0:
4410 			break;
4411 
4412 		case ECANCELED:
4413 			warn(cf_missing, ient->sc_fmri, ud_name);
4414 			goto out;
4415 
4416 		case ECONNABORTED:
4417 		case ENOMEM:
4418 		case EBADF:
4419 			goto out;
4420 
4421 		case EACCES:
4422 		default:
4423 			bad_error("load_pg", r);
4424 		}
4425 
4426 		if (g_verbose)
4427 			warn(upgrading, ient->sc_fmri, ud_name);
4428 
4429 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4430 		    new_dpt_pgroup, 0, ient->sc_fmri);
4431 		switch (r) {
4432 		case 0:
4433 			break;
4434 
4435 		case ECANCELED:
4436 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4437 			r = EBUSY;
4438 			goto out;
4439 
4440 		case EPERM:
4441 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4442 			goto out;
4443 
4444 		case EBUSY:
4445 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4446 			goto out;
4447 
4448 		case ECONNABORTED:
4449 		case ENOMEM:
4450 		case ENOSPC:
4451 		case EROFS:
4452 		case EACCES:
4453 		case EINVAL:
4454 			goto out;
4455 
4456 		default:
4457 			bad_error("upgrade_pg", r);
4458 		}
4459 		break;
4460 
4461 	case 0: {
4462 		scf_transaction_entry_t *ent;
4463 		scf_value_t *val;
4464 
4465 		internal_pgroup_free(current_pg);
4466 
4467 		/* delete old pg */
4468 		if (g_verbose)
4469 			warn(upgrading, ient->sc_fmri, ud_name);
4470 
4471 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4472 			switch (scf_error()) {
4473 			case SCF_ERROR_CONNECTION_BROKEN:
4474 				r = scferror2errno(scf_error());
4475 				goto out;
4476 
4477 			case SCF_ERROR_DELETED:
4478 				warn(cf_missing, ient->sc_fmri, ud_name);
4479 				r = 0;
4480 				goto out;
4481 
4482 			case SCF_ERROR_NOT_FOUND:
4483 				break;
4484 
4485 			case SCF_ERROR_INVALID_ARGUMENT:
4486 			case SCF_ERROR_NOT_BOUND:
4487 			case SCF_ERROR_NOT_SET:
4488 			case SCF_ERROR_HANDLE_MISMATCH:
4489 			default:
4490 				bad_error("entity_get_pg", scf_error());
4491 			}
4492 		} else if (scf_pg_delete(ud_pg) != 0) {
4493 			switch (scf_error()) {
4494 			case SCF_ERROR_DELETED:
4495 				break;
4496 
4497 			case SCF_ERROR_CONNECTION_BROKEN:
4498 			case SCF_ERROR_BACKEND_READONLY:
4499 			case SCF_ERROR_BACKEND_ACCESS:
4500 				r = scferror2errno(scf_error());
4501 				goto out;
4502 
4503 			case SCF_ERROR_PERMISSION_DENIED:
4504 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4505 				r = scferror2errno(scf_error());
4506 				goto out;
4507 
4508 			case SCF_ERROR_NOT_SET:
4509 			default:
4510 				bad_error("scf_pg_delete", scf_error());
4511 			}
4512 		}
4513 
4514 		/* import new one */
4515 		cbdata.sc_handle = g_hndl;
4516 		cbdata.sc_trans = NULL;		/* handled below */
4517 
4518 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
4519 		if (r != UU_WALK_NEXT) {
4520 			if (r != UU_WALK_ERROR)
4521 				bad_error("lscf_dependent_import", r);
4522 
4523 			r = cbdata.sc_err;
4524 			goto out;
4525 		}
4526 
4527 		if (tx == NULL)
4528 			break;
4529 
4530 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
4531 		    (val = scf_value_create(g_hndl)) == NULL) {
4532 			if (scf_error() == SCF_ERROR_NO_MEMORY)
4533 				return (ENOMEM);
4534 
4535 			bad_error("scf_entry_create", scf_error());
4536 		}
4537 
4538 		if (scf_transaction_property_change_type(tx, ent, ud_name,
4539 		    SCF_TYPE_FMRI) != 0) {
4540 			switch (scf_error()) {
4541 			case SCF_ERROR_CONNECTION_BROKEN:
4542 				r = scferror2errno(scf_error());
4543 				goto out;
4544 
4545 			case SCF_ERROR_DELETED:
4546 				warn(emsg_pg_deleted, ient->sc_fmri,
4547 				    "dependents");
4548 				r = EBUSY;
4549 				goto out;
4550 
4551 			case SCF_ERROR_NOT_FOUND:
4552 				break;
4553 
4554 			case SCF_ERROR_NOT_BOUND:
4555 			case SCF_ERROR_HANDLE_MISMATCH:
4556 			case SCF_ERROR_INVALID_ARGUMENT:
4557 			case SCF_ERROR_NOT_SET:
4558 			default:
4559 				bad_error("scf_transaction_property_"
4560 				    "change_type", scf_error());
4561 			}
4562 
4563 			if (scf_transaction_property_new(tx, ent, ud_name,
4564 			    SCF_TYPE_FMRI) != 0) {
4565 				switch (scf_error()) {
4566 				case SCF_ERROR_CONNECTION_BROKEN:
4567 					r = scferror2errno(scf_error());
4568 					goto out;
4569 
4570 				case SCF_ERROR_DELETED:
4571 					warn(emsg_pg_deleted, ient->sc_fmri,
4572 					    "dependents");
4573 					r = EBUSY;
4574 					goto out;
4575 
4576 				case SCF_ERROR_EXISTS:
4577 					warn(emsg_pg_changed, ient->sc_fmri,
4578 					    "dependents");
4579 					r = EBUSY;
4580 					goto out;
4581 
4582 				case SCF_ERROR_INVALID_ARGUMENT:
4583 				case SCF_ERROR_HANDLE_MISMATCH:
4584 				case SCF_ERROR_NOT_BOUND:
4585 				case SCF_ERROR_NOT_SET:
4586 				default:
4587 					bad_error("scf_transaction_property_"
4588 					    "new", scf_error());
4589 				}
4590 			}
4591 		}
4592 
4593 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
4594 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
4595 			/* invalid sc_pgroup_fmri caught above */
4596 			bad_error("scf_value_set_from_string",
4597 			    scf_error());
4598 
4599 		if (scf_entry_add_value(ent, val) != 0)
4600 			bad_error("scf_entry_add_value", scf_error());
4601 		break;
4602 	}
4603 
4604 	case -2:
4605 		warn(li_corrupt, ient->sc_fmri);
4606 		internal_pgroup_free(current_pg);
4607 		r = EBADF;
4608 		goto out;
4609 
4610 	case -1:
4611 	default:
4612 		/* invalid sc_pgroup_fmri caught above */
4613 		bad_error("fmri_equal", r);
4614 	}
4615 
4616 	r = 0;
4617 
4618 out:
4619 	if (old_dpt_pgroup != NULL)
4620 		internal_pgroup_free(old_dpt_pgroup);
4621 
4622 	return (r);
4623 }
4624 
4625 /*
4626  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
4627  * would import it, except it seems to exist in the service anyway.  Compare
4628  * the existent dependent with the one we would import, and report any
4629  * differences (if there are none, be silent).  prop is the property which
4630  * represents the existent dependent (in the dependents property group) in the
4631  * entity corresponding to ient.
4632  *
4633  * Returns
4634  *   0 - success (Sort of.  At least, we can continue importing.)
4635  *   ECONNABORTED - repository connection broken
4636  *   EBUSY - ancestor of prop was deleted (error printed)
4637  *   ENOMEM - out of memory
4638  *   EBADF - corrupt property group (error printed)
4639  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
4640  */
4641 static int
4642 handle_dependent_conflict(const entity_t * const ient,
4643     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
4644 {
4645 	int r;
4646 	scf_type_t ty;
4647 	scf_error_t scfe;
4648 	void *tptr;
4649 	int tissvc;
4650 	pgroup_t *pgroup;
4651 
4652 	if (scf_property_get_value(prop, ud_val) != 0) {
4653 		switch (scf_error()) {
4654 		case SCF_ERROR_CONNECTION_BROKEN:
4655 			return (scferror2errno(scf_error()));
4656 
4657 		case SCF_ERROR_DELETED:
4658 			warn(emsg_pg_deleted, ient->sc_fmri,
4659 			    new_dpt_pgroup->sc_pgroup_name);
4660 			return (EBUSY);
4661 
4662 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4663 		case SCF_ERROR_NOT_FOUND:
4664 			warn(gettext("Conflict upgrading %s (not importing "
4665 			    "dependent \"%s\" because it already exists.)  "
4666 			    "Warning: The \"%s/%2$s\" property has more or "
4667 			    "fewer than one value)).\n"), ient->sc_fmri,
4668 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
4669 			return (0);
4670 
4671 		case SCF_ERROR_HANDLE_MISMATCH:
4672 		case SCF_ERROR_NOT_BOUND:
4673 		case SCF_ERROR_NOT_SET:
4674 		case SCF_ERROR_PERMISSION_DENIED:
4675 		default:
4676 			bad_error("scf_property_get_value",
4677 			    scf_error());
4678 		}
4679 	}
4680 
4681 	ty = scf_value_type(ud_val);
4682 	assert(ty != SCF_TYPE_INVALID);
4683 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4684 		warn(gettext("Conflict upgrading %s (not importing dependent "
4685 		    "\"%s\" because it already exists).  Warning: The "
4686 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
4687 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
4688 		    scf_type_to_string(ty), "dependents");
4689 		return (0);
4690 	}
4691 
4692 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4693 	    0)
4694 		bad_error("scf_value_get_as_string", scf_error());
4695 
4696 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4697 	switch (r) {
4698 	case 0:
4699 		warn(gettext("Conflict upgrading %s (not importing dependent "
4700 		    "\"%s\" (target \"%s\") because it already exists with "
4701 		    "target \"%s\").\n"), ient->sc_fmri,
4702 		    new_dpt_pgroup->sc_pgroup_name,
4703 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
4704 		return (0);
4705 
4706 	case 1:
4707 		break;
4708 
4709 	case -1:
4710 		warn(gettext("Conflict upgrading %s (not importing dependent "
4711 		    "\"%s\" because it already exists).  Warning: The current "
4712 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
4713 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4714 		return (0);
4715 
4716 	case -2:
4717 		warn(gettext("Dependent \"%s\" of %s has invalid target "
4718 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
4719 		    new_dpt_pgroup->sc_pgroup_fmri);
4720 		return (EINVAL);
4721 
4722 	default:
4723 		bad_error("fmri_equal", r);
4724 	}
4725 
4726 	/* compare dependency pgs in target */
4727 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
4728 	switch (scfe) {
4729 	case SCF_ERROR_NONE:
4730 		break;
4731 
4732 	case SCF_ERROR_NO_MEMORY:
4733 		return (ENOMEM);
4734 
4735 	case SCF_ERROR_NOT_FOUND:
4736 		warn(emsg_dpt_dangling, ient->sc_fmri,
4737 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4738 		return (0);
4739 
4740 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4741 	case SCF_ERROR_INVALID_ARGUMENT:
4742 	default:
4743 		bad_error("fmri_to_entity", scfe);
4744 	}
4745 
4746 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
4747 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
4748 	switch (r) {
4749 	case 0:
4750 		break;
4751 
4752 	case ECONNABORTED:
4753 		return (r);
4754 
4755 	case ECANCELED:
4756 		warn(emsg_dpt_dangling, ient->sc_fmri,
4757 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4758 		return (0);
4759 
4760 	case EBADF:
4761 		if (tissvc)
4762 			warn(gettext("%s has an instance with a \"%s\" "
4763 			    "snapshot which is missing a snaplevel.\n"),
4764 			    ud_ctarg, "running");
4765 		else
4766 			warn(gettext("%s has a \"%s\" snapshot which is "
4767 			    "missing a snaplevel.\n"), ud_ctarg, "running");
4768 		/* FALLTHROUGH */
4769 
4770 	case ENOENT:
4771 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4772 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4773 		    new_dpt_pgroup->sc_pgroup_name);
4774 		return (0);
4775 
4776 	case EINVAL:
4777 	default:
4778 		bad_error("entity_get_running_pg", r);
4779 	}
4780 
4781 	pgroup = internal_pgroup_new();
4782 	if (pgroup == NULL)
4783 		return (ENOMEM);
4784 
4785 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
4786 	switch (r) {
4787 	case 0:
4788 		break;
4789 
4790 	case ECONNABORTED:
4791 	case EBADF:
4792 	case ENOMEM:
4793 		internal_pgroup_free(pgroup);
4794 		return (r);
4795 
4796 	case ECANCELED:
4797 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4798 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4799 		    new_dpt_pgroup->sc_pgroup_name);
4800 		internal_pgroup_free(pgroup);
4801 		return (0);
4802 
4803 	case EACCES:
4804 	default:
4805 		bad_error("load_pg", r);
4806 	}
4807 
4808 	/* report differences */
4809 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
4810 	internal_pgroup_free(pgroup);
4811 	return (0);
4812 }
4813 
4814 /*
4815  * lipg is a property group in the last-import snapshot of ent, which is an
4816  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
4817  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
4818  * in ents's property groups, compare and upgrade ent appropriately.
4819  *
4820  * Returns
4821  *   0 - success
4822  *   ECONNABORTED - repository connection broken
4823  *   ENOMEM - out of memory
4824  *   ENOSPC - configd is out of resources
4825  *   EINVAL - ient has invalid dependent (error printed)
4826  *	    - ient has invalid pgroup_t (error printed)
4827  *   ECANCELED - ent has been deleted
4828  *   ENODEV - entity containing lipg has been deleted
4829  *	    - entity containing running has been deleted
4830  *   EPERM - could not delete pg (permission denied) (error printed)
4831  *	   - couldn't upgrade dependents (permission denied) (error printed)
4832  *	   - couldn't import pg (permission denied) (error printed)
4833  *	   - couldn't upgrade pg (permission denied) (error printed)
4834  *   EROFS - could not delete pg (repository read-only)
4835  *	   - couldn't upgrade dependents (repository read-only)
4836  *	   - couldn't import pg (repository read-only)
4837  *	   - couldn't upgrade pg (repository read-only)
4838  *   EACCES - could not delete pg (backend access denied)
4839  *	    - couldn't upgrade dependents (backend access denied)
4840  *	    - couldn't import pg (backend access denied)
4841  *	    - couldn't upgrade pg (backend access denied)
4842  *	    - couldn't read property (backend access denied)
4843  *   EBUSY - property group was added (error printed)
4844  *	   - property group was deleted (error printed)
4845  *	   - property group changed (error printed)
4846  *	   - "dependents" pg was added, changed, or deleted (error printed)
4847  *	   - dependent target deleted (error printed)
4848  *	   - dependent pg changed (error printed)
4849  *   EBADF - imp_snpl is corrupt (error printed)
4850  *	   - ent has bad pg (error printed)
4851  *   EEXIST - dependent collision in target service (error printed)
4852  */
4853 static int
4854 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
4855     const scf_snaplevel_t *running)
4856 {
4857 	int r;
4858 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
4859 	scf_callback_t cbdata;
4860 
4861 	const char * const cf_pg_missing =
4862 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
4863 	const char * const deleting =
4864 	    gettext("%s: Deleting property group \"%s\".\n");
4865 
4866 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
4867 
4868 	/* Skip dependent property groups. */
4869 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
4870 		switch (scf_error()) {
4871 		case SCF_ERROR_DELETED:
4872 			return (ENODEV);
4873 
4874 		case SCF_ERROR_CONNECTION_BROKEN:
4875 			return (ECONNABORTED);
4876 
4877 		case SCF_ERROR_NOT_SET:
4878 		case SCF_ERROR_NOT_BOUND:
4879 		default:
4880 			bad_error("scf_pg_get_type", scf_error());
4881 		}
4882 	}
4883 
4884 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
4885 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
4886 			return (0);
4887 
4888 		switch (scf_error()) {
4889 		case SCF_ERROR_NOT_FOUND:
4890 			break;
4891 
4892 		case SCF_ERROR_CONNECTION_BROKEN:
4893 			return (ECONNABORTED);
4894 
4895 		case SCF_ERROR_DELETED:
4896 			return (ENODEV);
4897 
4898 		case SCF_ERROR_INVALID_ARGUMENT:
4899 		case SCF_ERROR_NOT_BOUND:
4900 		case SCF_ERROR_HANDLE_MISMATCH:
4901 		case SCF_ERROR_NOT_SET:
4902 		default:
4903 			bad_error("scf_pg_get_property", scf_error());
4904 		}
4905 	}
4906 
4907 	/* lookup pg in new properties */
4908 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
4909 		switch (scf_error()) {
4910 		case SCF_ERROR_DELETED:
4911 			return (ENODEV);
4912 
4913 		case SCF_ERROR_CONNECTION_BROKEN:
4914 			return (ECONNABORTED);
4915 
4916 		case SCF_ERROR_NOT_SET:
4917 		case SCF_ERROR_NOT_BOUND:
4918 		default:
4919 			bad_error("scf_pg_get_name", scf_error());
4920 		}
4921 	}
4922 
4923 	pgrp.sc_pgroup_name = imp_str;
4924 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
4925 
4926 	if (mpg != NULL)
4927 		mpg->sc_pgroup_seen = 1;
4928 
4929 	/* Special handling for dependents */
4930 	if (strcmp(imp_str, "dependents") == 0)
4931 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
4932 
4933 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
4934 		return (upgrade_manifestfiles(NULL, ient, running, ent));
4935 
4936 	if (mpg == NULL || mpg->sc_pgroup_delete) {
4937 		/* property group was deleted from manifest */
4938 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4939 			switch (scf_error()) {
4940 			case SCF_ERROR_NOT_FOUND:
4941 				return (0);
4942 
4943 			case SCF_ERROR_DELETED:
4944 			case SCF_ERROR_CONNECTION_BROKEN:
4945 				return (scferror2errno(scf_error()));
4946 
4947 			case SCF_ERROR_INVALID_ARGUMENT:
4948 			case SCF_ERROR_HANDLE_MISMATCH:
4949 			case SCF_ERROR_NOT_BOUND:
4950 			case SCF_ERROR_NOT_SET:
4951 			default:
4952 				bad_error("entity_get_pg", scf_error());
4953 			}
4954 		}
4955 
4956 		if (mpg != NULL && mpg->sc_pgroup_delete) {
4957 			if (g_verbose)
4958 				warn(deleting, ient->sc_fmri, imp_str);
4959 			if (scf_pg_delete(imp_pg2) == 0)
4960 				return (0);
4961 
4962 			switch (scf_error()) {
4963 			case SCF_ERROR_DELETED:
4964 				return (0);
4965 
4966 			case SCF_ERROR_CONNECTION_BROKEN:
4967 			case SCF_ERROR_BACKEND_READONLY:
4968 			case SCF_ERROR_BACKEND_ACCESS:
4969 				return (scferror2errno(scf_error()));
4970 
4971 			case SCF_ERROR_PERMISSION_DENIED:
4972 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
4973 				return (scferror2errno(scf_error()));
4974 
4975 			case SCF_ERROR_NOT_SET:
4976 			default:
4977 				bad_error("scf_pg_delete", scf_error());
4978 			}
4979 		}
4980 
4981 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4982 		switch (r) {
4983 		case 0:
4984 			break;
4985 
4986 		case ECANCELED:
4987 			return (ENODEV);
4988 
4989 		case ECONNABORTED:
4990 		case ENOMEM:
4991 		case EBADF:
4992 		case EACCES:
4993 			return (r);
4994 
4995 		default:
4996 			bad_error("load_pg", r);
4997 		}
4998 
4999 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5000 		switch (r) {
5001 		case 0:
5002 			break;
5003 
5004 		case ECANCELED:
5005 		case ECONNABORTED:
5006 		case ENOMEM:
5007 		case EBADF:
5008 		case EACCES:
5009 			internal_pgroup_free(lipg_i);
5010 			return (r);
5011 
5012 		default:
5013 			bad_error("load_pg", r);
5014 		}
5015 
5016 		if (pg_equal(lipg_i, curpg_i)) {
5017 			if (g_verbose)
5018 				warn(deleting, ient->sc_fmri, imp_str);
5019 			if (scf_pg_delete(imp_pg2) != 0) {
5020 				switch (scf_error()) {
5021 				case SCF_ERROR_DELETED:
5022 					break;
5023 
5024 				case SCF_ERROR_CONNECTION_BROKEN:
5025 					internal_pgroup_free(lipg_i);
5026 					internal_pgroup_free(curpg_i);
5027 					return (ECONNABORTED);
5028 
5029 				case SCF_ERROR_NOT_SET:
5030 				case SCF_ERROR_NOT_BOUND:
5031 				default:
5032 					bad_error("scf_pg_delete", scf_error());
5033 				}
5034 			}
5035 		} else {
5036 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5037 		}
5038 
5039 		internal_pgroup_free(lipg_i);
5040 		internal_pgroup_free(curpg_i);
5041 
5042 		return (0);
5043 	}
5044 
5045 	/*
5046 	 * Only dependent pgs can have override set, and we skipped those
5047 	 * above.
5048 	 */
5049 	assert(!mpg->sc_pgroup_override);
5050 
5051 	/* compare */
5052 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5053 	switch (r) {
5054 	case 0:
5055 		break;
5056 
5057 	case ECANCELED:
5058 		return (ENODEV);
5059 
5060 	case ECONNABORTED:
5061 	case EBADF:
5062 	case ENOMEM:
5063 	case EACCES:
5064 		return (r);
5065 
5066 	default:
5067 		bad_error("load_pg", r);
5068 	}
5069 
5070 	if (pg_equal(mpg, lipg_i)) {
5071 		/* The manifest pg has not changed.  Move on. */
5072 		r = 0;
5073 		goto out;
5074 	}
5075 
5076 	/* upgrade current properties according to lipg & mpg */
5077 	if (running != NULL)
5078 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5079 	else
5080 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5081 	if (r != 0) {
5082 		switch (scf_error()) {
5083 		case SCF_ERROR_CONNECTION_BROKEN:
5084 			r = scferror2errno(scf_error());
5085 			goto out;
5086 
5087 		case SCF_ERROR_DELETED:
5088 			if (running != NULL)
5089 				r = ENODEV;
5090 			else
5091 				r = ECANCELED;
5092 			goto out;
5093 
5094 		case SCF_ERROR_NOT_FOUND:
5095 			break;
5096 
5097 		case SCF_ERROR_INVALID_ARGUMENT:
5098 		case SCF_ERROR_HANDLE_MISMATCH:
5099 		case SCF_ERROR_NOT_BOUND:
5100 		case SCF_ERROR_NOT_SET:
5101 		default:
5102 			bad_error("entity_get_pg", scf_error());
5103 		}
5104 
5105 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5106 
5107 		r = 0;
5108 		goto out;
5109 	}
5110 
5111 	r = load_pg_attrs(imp_pg2, &curpg_i);
5112 	switch (r) {
5113 	case 0:
5114 		break;
5115 
5116 	case ECANCELED:
5117 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5118 		r = 0;
5119 		goto out;
5120 
5121 	case ECONNABORTED:
5122 	case ENOMEM:
5123 		goto out;
5124 
5125 	default:
5126 		bad_error("load_pg_attrs", r);
5127 	}
5128 
5129 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5130 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5131 		internal_pgroup_free(curpg_i);
5132 		r = 0;
5133 		goto out;
5134 	}
5135 
5136 	internal_pgroup_free(curpg_i);
5137 
5138 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5139 	switch (r) {
5140 	case 0:
5141 		break;
5142 
5143 	case ECANCELED:
5144 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5145 		r = 0;
5146 		goto out;
5147 
5148 	case ECONNABORTED:
5149 	case EBADF:
5150 	case ENOMEM:
5151 	case EACCES:
5152 		goto out;
5153 
5154 	default:
5155 		bad_error("load_pg", r);
5156 	}
5157 
5158 	if (pg_equal(lipg_i, curpg_i) &&
5159 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5160 		int do_delete = 1;
5161 
5162 		if (g_verbose)
5163 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5164 			    ient->sc_fmri, mpg->sc_pgroup_name);
5165 
5166 		internal_pgroup_free(curpg_i);
5167 
5168 		if (running != NULL &&
5169 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5170 			switch (scf_error()) {
5171 			case SCF_ERROR_DELETED:
5172 				r = ECANCELED;
5173 				goto out;
5174 
5175 			case SCF_ERROR_NOT_FOUND:
5176 				do_delete = 0;
5177 				break;
5178 
5179 			case SCF_ERROR_CONNECTION_BROKEN:
5180 				r = scferror2errno(scf_error());
5181 				goto out;
5182 
5183 			case SCF_ERROR_HANDLE_MISMATCH:
5184 			case SCF_ERROR_INVALID_ARGUMENT:
5185 			case SCF_ERROR_NOT_SET:
5186 			case SCF_ERROR_NOT_BOUND:
5187 			default:
5188 				bad_error("entity_get_pg", scf_error());
5189 			}
5190 		}
5191 
5192 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5193 			switch (scf_error()) {
5194 			case SCF_ERROR_DELETED:
5195 				break;
5196 
5197 			case SCF_ERROR_CONNECTION_BROKEN:
5198 			case SCF_ERROR_BACKEND_READONLY:
5199 			case SCF_ERROR_BACKEND_ACCESS:
5200 				r = scferror2errno(scf_error());
5201 				goto out;
5202 
5203 			case SCF_ERROR_PERMISSION_DENIED:
5204 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5205 				    ient->sc_fmri);
5206 				r = scferror2errno(scf_error());
5207 				goto out;
5208 
5209 			case SCF_ERROR_NOT_SET:
5210 			case SCF_ERROR_NOT_BOUND:
5211 			default:
5212 				bad_error("scf_pg_delete", scf_error());
5213 			}
5214 		}
5215 
5216 		cbdata.sc_handle = g_hndl;
5217 		cbdata.sc_parent = ent;
5218 		cbdata.sc_service = issvc;
5219 		cbdata.sc_flags = 0;
5220 		cbdata.sc_source_fmri = ient->sc_fmri;
5221 		cbdata.sc_target_fmri = ient->sc_fmri;
5222 
5223 		r = entity_pgroup_import(mpg, &cbdata);
5224 		switch (r) {
5225 		case UU_WALK_NEXT:
5226 			r = 0;
5227 			goto out;
5228 
5229 		case UU_WALK_ERROR:
5230 			if (cbdata.sc_err == EEXIST) {
5231 				warn(emsg_pg_added, ient->sc_fmri,
5232 				    mpg->sc_pgroup_name);
5233 				r = EBUSY;
5234 			} else {
5235 				r = cbdata.sc_err;
5236 			}
5237 			goto out;
5238 
5239 		default:
5240 			bad_error("entity_pgroup_import", r);
5241 		}
5242 	}
5243 
5244 	if (running != NULL &&
5245 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5246 		switch (scf_error()) {
5247 		case SCF_ERROR_CONNECTION_BROKEN:
5248 		case SCF_ERROR_DELETED:
5249 			r = scferror2errno(scf_error());
5250 			goto out;
5251 
5252 		case SCF_ERROR_NOT_FOUND:
5253 			break;
5254 
5255 		case SCF_ERROR_HANDLE_MISMATCH:
5256 		case SCF_ERROR_INVALID_ARGUMENT:
5257 		case SCF_ERROR_NOT_SET:
5258 		case SCF_ERROR_NOT_BOUND:
5259 		default:
5260 			bad_error("entity_get_pg", scf_error());
5261 		}
5262 
5263 		cbdata.sc_handle = g_hndl;
5264 		cbdata.sc_parent = ent;
5265 		cbdata.sc_service = issvc;
5266 		cbdata.sc_flags = SCI_FORCE;
5267 		cbdata.sc_source_fmri = ient->sc_fmri;
5268 		cbdata.sc_target_fmri = ient->sc_fmri;
5269 
5270 		r = entity_pgroup_import(mpg, &cbdata);
5271 		switch (r) {
5272 		case UU_WALK_NEXT:
5273 			r = 0;
5274 			goto out;
5275 
5276 		case UU_WALK_ERROR:
5277 			if (cbdata.sc_err == EEXIST) {
5278 				warn(emsg_pg_added, ient->sc_fmri,
5279 				    mpg->sc_pgroup_name);
5280 				r = EBUSY;
5281 			} else {
5282 				r = cbdata.sc_err;
5283 			}
5284 			goto out;
5285 
5286 		default:
5287 			bad_error("entity_pgroup_import", r);
5288 		}
5289 	}
5290 
5291 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5292 	internal_pgroup_free(curpg_i);
5293 	switch (r) {
5294 	case 0:
5295 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5296 		break;
5297 
5298 	case ECANCELED:
5299 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5300 		r = EBUSY;
5301 		break;
5302 
5303 	case EPERM:
5304 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5305 		break;
5306 
5307 	case EBUSY:
5308 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5309 		break;
5310 
5311 	case ECONNABORTED:
5312 	case ENOMEM:
5313 	case ENOSPC:
5314 	case EROFS:
5315 	case EACCES:
5316 	case EINVAL:
5317 		break;
5318 
5319 	default:
5320 		bad_error("upgrade_pg", r);
5321 	}
5322 
5323 out:
5324 	internal_pgroup_free(lipg_i);
5325 	return (r);
5326 }
5327 
5328 /*
5329  * Upgrade the properties of ent according to snpl & ient.
5330  *
5331  * Returns
5332  *   0 - success
5333  *   ECONNABORTED - repository connection broken
5334  *   ENOMEM - out of memory
5335  *   ENOSPC - configd is out of resources
5336  *   ECANCELED - ent was deleted
5337  *   ENODEV - entity containing snpl was deleted
5338  *	    - entity containing running was deleted
5339  *   EBADF - imp_snpl is corrupt (error printed)
5340  *	   - ent has corrupt pg (error printed)
5341  *	   - dependent has corrupt pg (error printed)
5342  *	   - dependent target has a corrupt snapshot (error printed)
5343  *   EBUSY - pg was added, changed, or deleted (error printed)
5344  *	   - dependent target was deleted (error printed)
5345  *	   - dependent pg changed (error printed)
5346  *   EINVAL - invalid property group name (error printed)
5347  *	    - invalid property name (error printed)
5348  *	    - invalid value (error printed)
5349  *	    - ient has invalid pgroup or dependent (error printed)
5350  *   EPERM - could not create property group (permission denied) (error printed)
5351  *	   - could not modify property group (permission denied) (error printed)
5352  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5353  *   EROFS - could not create property group (repository read-only)
5354  *	   - couldn't delete, upgrade, or import pg or dependent
5355  *   EACCES - could not create property group (backend access denied)
5356  *	    - couldn't delete, upgrade, or import pg or dependent
5357  *   EEXIST - dependent collision in target service (error printed)
5358  */
5359 static int
5360 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5361     entity_t *ient)
5362 {
5363 	pgroup_t *pg, *rpg;
5364 	int r;
5365 	uu_list_t *pgs = ient->sc_pgroups;
5366 
5367 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5368 
5369 	/* clear sc_sceen for pgs */
5370 	if (uu_list_walk(pgs, clear_int,
5371 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5372 		bad_error("uu_list_walk", uu_error());
5373 
5374 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5375 		switch (scf_error()) {
5376 		case SCF_ERROR_DELETED:
5377 			return (ENODEV);
5378 
5379 		case SCF_ERROR_CONNECTION_BROKEN:
5380 			return (ECONNABORTED);
5381 
5382 		case SCF_ERROR_NOT_SET:
5383 		case SCF_ERROR_NOT_BOUND:
5384 		case SCF_ERROR_HANDLE_MISMATCH:
5385 		default:
5386 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5387 		}
5388 	}
5389 
5390 	for (;;) {
5391 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5392 		if (r == 0)
5393 			break;
5394 		if (r == 1) {
5395 			r = process_old_pg(imp_pg, ient, ent, running);
5396 			switch (r) {
5397 			case 0:
5398 				break;
5399 
5400 			case ECONNABORTED:
5401 			case ENOMEM:
5402 			case ENOSPC:
5403 			case ECANCELED:
5404 			case ENODEV:
5405 			case EPERM:
5406 			case EROFS:
5407 			case EACCES:
5408 			case EBADF:
5409 			case EBUSY:
5410 			case EINVAL:
5411 			case EEXIST:
5412 				return (r);
5413 
5414 			default:
5415 				bad_error("process_old_pg", r);
5416 			}
5417 			continue;
5418 		}
5419 		if (r != -1)
5420 			bad_error("scf_iter_next_pg", r);
5421 
5422 		switch (scf_error()) {
5423 		case SCF_ERROR_DELETED:
5424 			return (ENODEV);
5425 
5426 		case SCF_ERROR_CONNECTION_BROKEN:
5427 			return (ECONNABORTED);
5428 
5429 		case SCF_ERROR_HANDLE_MISMATCH:
5430 		case SCF_ERROR_NOT_BOUND:
5431 		case SCF_ERROR_NOT_SET:
5432 		case SCF_ERROR_INVALID_ARGUMENT:
5433 		default:
5434 			bad_error("scf_iter_next_pg", scf_error());
5435 		}
5436 	}
5437 
5438 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5439 		if (pg->sc_pgroup_seen)
5440 			continue;
5441 
5442 		/* pg is new */
5443 
5444 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5445 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5446 			    ent);
5447 			switch (r) {
5448 			case 0:
5449 				break;
5450 
5451 			case ECONNABORTED:
5452 			case ENOMEM:
5453 			case ENOSPC:
5454 			case ECANCELED:
5455 			case ENODEV:
5456 			case EBADF:
5457 			case EBUSY:
5458 			case EINVAL:
5459 			case EPERM:
5460 			case EROFS:
5461 			case EACCES:
5462 			case EEXIST:
5463 				return (r);
5464 
5465 			default:
5466 				bad_error("upgrade_dependents", r);
5467 			}
5468 			continue;
5469 		}
5470 
5471 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
5472 			r = upgrade_manifestfiles(pg, ient, running, ent);
5473 			switch (r) {
5474 			case 0:
5475 				break;
5476 
5477 			case ECONNABORTED:
5478 			case ENOMEM:
5479 			case ENOSPC:
5480 			case ECANCELED:
5481 			case ENODEV:
5482 			case EBADF:
5483 			case EBUSY:
5484 			case EINVAL:
5485 			case EPERM:
5486 			case EROFS:
5487 			case EACCES:
5488 			case EEXIST:
5489 				return (r);
5490 
5491 			default:
5492 				bad_error("upgrade_manifestfiles", r);
5493 			}
5494 			continue;
5495 		}
5496 
5497 		if (running != NULL) {
5498 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
5499 			    imp_pg);
5500 		} else {
5501 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
5502 			    imp_pg);
5503 		}
5504 		if (r != 0) {
5505 			scf_callback_t cbdata;
5506 
5507 			switch (scf_error()) {
5508 			case SCF_ERROR_NOT_FOUND:
5509 				break;
5510 
5511 			case SCF_ERROR_CONNECTION_BROKEN:
5512 				return (scferror2errno(scf_error()));
5513 
5514 			case SCF_ERROR_DELETED:
5515 				if (running != NULL)
5516 					return (ENODEV);
5517 				else
5518 					return (scferror2errno(scf_error()));
5519 
5520 			case SCF_ERROR_INVALID_ARGUMENT:
5521 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
5522 				    pg->sc_pgroup_name);
5523 				return (EINVAL);
5524 
5525 			case SCF_ERROR_NOT_SET:
5526 			case SCF_ERROR_HANDLE_MISMATCH:
5527 			case SCF_ERROR_NOT_BOUND:
5528 			default:
5529 				bad_error("entity_get_pg", scf_error());
5530 			}
5531 
5532 			/* User doesn't have pg, so import it. */
5533 
5534 			cbdata.sc_handle = g_hndl;
5535 			cbdata.sc_parent = ent;
5536 			cbdata.sc_service = issvc;
5537 			cbdata.sc_flags = SCI_FORCE;
5538 			cbdata.sc_source_fmri = ient->sc_fmri;
5539 			cbdata.sc_target_fmri = ient->sc_fmri;
5540 
5541 			r = entity_pgroup_import(pg, &cbdata);
5542 			switch (r) {
5543 			case UU_WALK_NEXT:
5544 				ient->sc_import_state = IMPORT_PROP_BEGUN;
5545 				continue;
5546 
5547 			case UU_WALK_ERROR:
5548 				if (cbdata.sc_err == EEXIST) {
5549 					warn(emsg_pg_added, ient->sc_fmri,
5550 					    pg->sc_pgroup_name);
5551 					return (EBUSY);
5552 				}
5553 				return (cbdata.sc_err);
5554 
5555 			default:
5556 				bad_error("entity_pgroup_import", r);
5557 			}
5558 		}
5559 
5560 		/* report differences between pg & current */
5561 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
5562 		switch (r) {
5563 		case 0:
5564 			break;
5565 
5566 		case ECANCELED:
5567 			warn(emsg_pg_deleted, ient->sc_fmri,
5568 			    pg->sc_pgroup_name);
5569 			return (EBUSY);
5570 
5571 		case ECONNABORTED:
5572 		case EBADF:
5573 		case ENOMEM:
5574 		case EACCES:
5575 			return (r);
5576 
5577 		default:
5578 			bad_error("load_pg", r);
5579 		}
5580 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
5581 		internal_pgroup_free(rpg);
5582 		rpg = NULL;
5583 	}
5584 
5585 	return (0);
5586 }
5587 
5588 /*
5589  * Import an instance.  If it doesn't exist, create it.  If it has
5590  * a last-import snapshot, upgrade its properties.  Finish by updating its
5591  * last-import snapshot.  If it doesn't have a last-import snapshot then it
5592  * could have been created for a dependent tag in another manifest.  Import the
5593  * new properties.  If there's a conflict, don't override, like now?
5594  *
5595  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
5596  * lcbdata->sc_err to
5597  *   ECONNABORTED - repository connection broken
5598  *   ENOMEM - out of memory
5599  *   ENOSPC - svc.configd is out of resources
5600  *   EEXIST - dependency collision in dependent service (error printed)
5601  *   EPERM - couldn't create temporary instance (permission denied)
5602  *	   - couldn't import into temporary instance (permission denied)
5603  *	   - couldn't take snapshot (permission denied)
5604  *	   - couldn't upgrade properties (permission denied)
5605  *	   - couldn't import properties (permission denied)
5606  *	   - couldn't import dependents (permission denied)
5607  *   EROFS - couldn't create temporary instance (repository read-only)
5608  *	   - couldn't import into temporary instance (repository read-only)
5609  *	   - couldn't upgrade properties (repository read-only)
5610  *	   - couldn't import properties (repository read-only)
5611  *	   - couldn't import dependents (repository read-only)
5612  *   EACCES - couldn't create temporary instance (backend access denied)
5613  *	    - couldn't import into temporary instance (backend access denied)
5614  *	    - couldn't upgrade properties (backend access denied)
5615  *	    - couldn't import properties (backend access denied)
5616  *	    - couldn't import dependents (backend access denied)
5617  *   EINVAL - invalid instance name (error printed)
5618  *	    - invalid pgroup_t's (error printed)
5619  *	    - invalid dependents (error printed)
5620  *   EBUSY - temporary service deleted (error printed)
5621  *	   - temporary instance deleted (error printed)
5622  *	   - temporary instance changed (error printed)
5623  *	   - temporary instance already exists (error printed)
5624  *	   - instance deleted (error printed)
5625  *   EBADF - instance has corrupt last-import snapshot (error printed)
5626  *	   - instance is corrupt (error printed)
5627  *	   - dependent has corrupt pg (error printed)
5628  *	   - dependent target has a corrupt snapshot (error printed)
5629  *   -1 - unknown libscf error (error printed)
5630  */
5631 static int
5632 lscf_instance_import(void *v, void *pvt)
5633 {
5634 	entity_t *inst = v;
5635 	scf_callback_t ctx;
5636 	scf_callback_t *lcbdata = pvt;
5637 	scf_service_t *rsvc = lcbdata->sc_parent;
5638 	int r;
5639 	scf_snaplevel_t *running;
5640 	int flags = lcbdata->sc_flags;
5641 
5642 	const char * const emsg_tdel =
5643 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
5644 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
5645 	    "changed unexpectedly.\n");
5646 	const char * const emsg_del = gettext("%s changed unexpectedly "
5647 	    "(instance \"%s\" was deleted.)\n");
5648 	const char * const emsg_badsnap = gettext(
5649 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
5650 
5651 	/*
5652 	 * prepare last-import snapshot:
5653 	 * create temporary instance (service was precreated)
5654 	 * populate with properties from bundle
5655 	 * take snapshot
5656 	 */
5657 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
5658 		switch (scf_error()) {
5659 		case SCF_ERROR_CONNECTION_BROKEN:
5660 		case SCF_ERROR_NO_RESOURCES:
5661 		case SCF_ERROR_BACKEND_READONLY:
5662 		case SCF_ERROR_BACKEND_ACCESS:
5663 			return (stash_scferror(lcbdata));
5664 
5665 		case SCF_ERROR_EXISTS:
5666 			warn(gettext("Temporary service svc:/%s "
5667 			    "changed unexpectedly (instance \"%s\" added).\n"),
5668 			    imp_tsname, inst->sc_name);
5669 			lcbdata->sc_err = EBUSY;
5670 			return (UU_WALK_ERROR);
5671 
5672 		case SCF_ERROR_DELETED:
5673 			warn(gettext("Temporary service svc:/%s "
5674 			    "was deleted unexpectedly.\n"), imp_tsname);
5675 			lcbdata->sc_err = EBUSY;
5676 			return (UU_WALK_ERROR);
5677 
5678 		case SCF_ERROR_INVALID_ARGUMENT:
5679 			warn(gettext("Invalid instance name \"%s\".\n"),
5680 			    inst->sc_name);
5681 			return (stash_scferror(lcbdata));
5682 
5683 		case SCF_ERROR_PERMISSION_DENIED:
5684 			warn(gettext("Could not create temporary instance "
5685 			    "\"%s\" in svc:/%s (permission denied).\n"),
5686 			    inst->sc_name, imp_tsname);
5687 			return (stash_scferror(lcbdata));
5688 
5689 		case SCF_ERROR_HANDLE_MISMATCH:
5690 		case SCF_ERROR_NOT_BOUND:
5691 		case SCF_ERROR_NOT_SET:
5692 		default:
5693 			bad_error("scf_service_add_instance", scf_error());
5694 		}
5695 	}
5696 
5697 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5698 	    inst->sc_name);
5699 	if (r < 0)
5700 		bad_error("snprintf", errno);
5701 
5702 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
5703 	    lcbdata->sc_flags | SCI_NOENABLED);
5704 	switch (r) {
5705 	case 0:
5706 		break;
5707 
5708 	case ECANCELED:
5709 		warn(emsg_tdel, imp_tsname, inst->sc_name);
5710 		lcbdata->sc_err = EBUSY;
5711 		r = UU_WALK_ERROR;
5712 		goto deltemp;
5713 
5714 	case EEXIST:
5715 		warn(emsg_tchg, imp_tsname, inst->sc_name);
5716 		lcbdata->sc_err = EBUSY;
5717 		r = UU_WALK_ERROR;
5718 		goto deltemp;
5719 
5720 	case ECONNABORTED:
5721 		goto connaborted;
5722 
5723 	case ENOMEM:
5724 	case ENOSPC:
5725 	case EPERM:
5726 	case EROFS:
5727 	case EACCES:
5728 	case EINVAL:
5729 	case EBUSY:
5730 		lcbdata->sc_err = r;
5731 		r = UU_WALK_ERROR;
5732 		goto deltemp;
5733 
5734 	default:
5735 		bad_error("lscf_import_instance_pgs", r);
5736 	}
5737 
5738 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5739 	    inst->sc_name);
5740 	if (r < 0)
5741 		bad_error("snprintf", errno);
5742 
5743 	ctx.sc_handle = lcbdata->sc_handle;
5744 	ctx.sc_parent = imp_tinst;
5745 	ctx.sc_service = 0;
5746 	ctx.sc_source_fmri = inst->sc_fmri;
5747 	ctx.sc_target_fmri = imp_str;
5748 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
5749 	    UU_DEFAULT) != 0) {
5750 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5751 			bad_error("uu_list_walk", uu_error());
5752 
5753 		switch (ctx.sc_err) {
5754 		case ECONNABORTED:
5755 			goto connaborted;
5756 
5757 		case ECANCELED:
5758 			warn(emsg_tdel, imp_tsname, inst->sc_name);
5759 			lcbdata->sc_err = EBUSY;
5760 			break;
5761 
5762 		case EEXIST:
5763 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5764 			lcbdata->sc_err = EBUSY;
5765 			break;
5766 
5767 		default:
5768 			lcbdata->sc_err = ctx.sc_err;
5769 		}
5770 		r = UU_WALK_ERROR;
5771 		goto deltemp;
5772 	}
5773 
5774 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
5775 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
5776 		switch (scf_error()) {
5777 		case SCF_ERROR_CONNECTION_BROKEN:
5778 			goto connaborted;
5779 
5780 		case SCF_ERROR_NO_RESOURCES:
5781 			r = stash_scferror(lcbdata);
5782 			goto deltemp;
5783 
5784 		case SCF_ERROR_EXISTS:
5785 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5786 			lcbdata->sc_err = EBUSY;
5787 			r = UU_WALK_ERROR;
5788 			goto deltemp;
5789 
5790 		case SCF_ERROR_PERMISSION_DENIED:
5791 			warn(gettext("Could not take \"%s\" snapshot of %s "
5792 			    "(permission denied).\n"), snap_lastimport,
5793 			    imp_str);
5794 			r = stash_scferror(lcbdata);
5795 			goto deltemp;
5796 
5797 		default:
5798 			scfwarn();
5799 			lcbdata->sc_err = -1;
5800 			r = UU_WALK_ERROR;
5801 			goto deltemp;
5802 
5803 		case SCF_ERROR_HANDLE_MISMATCH:
5804 		case SCF_ERROR_INVALID_ARGUMENT:
5805 		case SCF_ERROR_NOT_SET:
5806 			bad_error("_scf_snapshot_take_new_named", scf_error());
5807 		}
5808 	}
5809 
5810 	if (lcbdata->sc_flags & SCI_FRESH)
5811 		goto fresh;
5812 
5813 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
5814 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
5815 		    imp_lisnap) != 0) {
5816 			switch (scf_error()) {
5817 			case SCF_ERROR_DELETED:
5818 				warn(emsg_del, inst->sc_parent->sc_fmri,
5819 				    inst->sc_name);
5820 				lcbdata->sc_err = EBUSY;
5821 				r = UU_WALK_ERROR;
5822 				goto deltemp;
5823 
5824 			case SCF_ERROR_NOT_FOUND:
5825 				flags |= SCI_FORCE;
5826 				goto nosnap;
5827 
5828 			case SCF_ERROR_CONNECTION_BROKEN:
5829 				goto connaborted;
5830 
5831 			case SCF_ERROR_INVALID_ARGUMENT:
5832 			case SCF_ERROR_HANDLE_MISMATCH:
5833 			case SCF_ERROR_NOT_BOUND:
5834 			case SCF_ERROR_NOT_SET:
5835 			default:
5836 				bad_error("scf_instance_get_snapshot",
5837 				    scf_error());
5838 			}
5839 		}
5840 
5841 		/* upgrade */
5842 
5843 		/*
5844 		 * compare new properties with last-import properties
5845 		 * upgrade current properties
5846 		 */
5847 		/* clear sc_sceen for pgs */
5848 		if (uu_list_walk(inst->sc_pgroups, clear_int,
5849 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
5850 		    0)
5851 			bad_error("uu_list_walk", uu_error());
5852 
5853 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
5854 		switch (r) {
5855 		case 0:
5856 			break;
5857 
5858 		case ECONNABORTED:
5859 			goto connaborted;
5860 
5861 		case ECANCELED:
5862 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5863 			lcbdata->sc_err = EBUSY;
5864 			r = UU_WALK_ERROR;
5865 			goto deltemp;
5866 
5867 		case ENOENT:
5868 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
5869 			lcbdata->sc_err = EBADF;
5870 			r = UU_WALK_ERROR;
5871 			goto deltemp;
5872 
5873 		default:
5874 			bad_error("get_snaplevel", r);
5875 		}
5876 
5877 		if (scf_instance_get_snapshot(imp_inst, snap_running,
5878 		    imp_rsnap) != 0) {
5879 			switch (scf_error()) {
5880 			case SCF_ERROR_DELETED:
5881 				warn(emsg_del, inst->sc_parent->sc_fmri,
5882 				    inst->sc_name);
5883 				lcbdata->sc_err = EBUSY;
5884 				r = UU_WALK_ERROR;
5885 				goto deltemp;
5886 
5887 			case SCF_ERROR_NOT_FOUND:
5888 				break;
5889 
5890 			case SCF_ERROR_CONNECTION_BROKEN:
5891 				goto connaborted;
5892 
5893 			case SCF_ERROR_INVALID_ARGUMENT:
5894 			case SCF_ERROR_HANDLE_MISMATCH:
5895 			case SCF_ERROR_NOT_BOUND:
5896 			case SCF_ERROR_NOT_SET:
5897 			default:
5898 				bad_error("scf_instance_get_snapshot",
5899 				    scf_error());
5900 			}
5901 
5902 			running = NULL;
5903 		} else {
5904 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
5905 			switch (r) {
5906 			case 0:
5907 				running = imp_rsnpl;
5908 				break;
5909 
5910 			case ECONNABORTED:
5911 				goto connaborted;
5912 
5913 			case ECANCELED:
5914 				warn(emsg_del, inst->sc_parent->sc_fmri,
5915 				    inst->sc_name);
5916 				lcbdata->sc_err = EBUSY;
5917 				r = UU_WALK_ERROR;
5918 				goto deltemp;
5919 
5920 			case ENOENT:
5921 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
5922 				lcbdata->sc_err = EBADF;
5923 				r = UU_WALK_ERROR;
5924 				goto deltemp;
5925 
5926 			default:
5927 				bad_error("get_snaplevel", r);
5928 			}
5929 		}
5930 
5931 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
5932 		switch (r) {
5933 		case 0:
5934 			break;
5935 
5936 		case ECANCELED:
5937 		case ENODEV:
5938 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5939 			lcbdata->sc_err = EBUSY;
5940 			r = UU_WALK_ERROR;
5941 			goto deltemp;
5942 
5943 		case ECONNABORTED:
5944 			goto connaborted;
5945 
5946 		case ENOMEM:
5947 		case ENOSPC:
5948 		case EBADF:
5949 		case EBUSY:
5950 		case EINVAL:
5951 		case EPERM:
5952 		case EROFS:
5953 		case EACCES:
5954 		case EEXIST:
5955 			lcbdata->sc_err = r;
5956 			r = UU_WALK_ERROR;
5957 			goto deltemp;
5958 
5959 		default:
5960 			bad_error("upgrade_props", r);
5961 		}
5962 
5963 		inst->sc_import_state = IMPORT_PROP_DONE;
5964 	} else {
5965 		switch (scf_error()) {
5966 		case SCF_ERROR_CONNECTION_BROKEN:
5967 			goto connaborted;
5968 
5969 		case SCF_ERROR_NOT_FOUND:
5970 			break;
5971 
5972 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
5973 		case SCF_ERROR_HANDLE_MISMATCH:
5974 		case SCF_ERROR_NOT_BOUND:
5975 		case SCF_ERROR_NOT_SET:
5976 		default:
5977 			bad_error("scf_service_get_instance", scf_error());
5978 		}
5979 
5980 fresh:
5981 		/* create instance */
5982 		if (scf_service_add_instance(rsvc, inst->sc_name,
5983 		    imp_inst) != 0) {
5984 			switch (scf_error()) {
5985 			case SCF_ERROR_CONNECTION_BROKEN:
5986 				goto connaborted;
5987 
5988 			case SCF_ERROR_NO_RESOURCES:
5989 			case SCF_ERROR_BACKEND_READONLY:
5990 			case SCF_ERROR_BACKEND_ACCESS:
5991 				r = stash_scferror(lcbdata);
5992 				goto deltemp;
5993 
5994 			case SCF_ERROR_EXISTS:
5995 				warn(gettext("%s changed unexpectedly "
5996 				    "(instance \"%s\" added).\n"),
5997 				    inst->sc_parent->sc_fmri, inst->sc_name);
5998 				lcbdata->sc_err = EBUSY;
5999 				r = UU_WALK_ERROR;
6000 				goto deltemp;
6001 
6002 			case SCF_ERROR_PERMISSION_DENIED:
6003 				warn(gettext("Could not create \"%s\" instance "
6004 				    "in %s (permission denied).\n"),
6005 				    inst->sc_name, inst->sc_parent->sc_fmri);
6006 				r = stash_scferror(lcbdata);
6007 				goto deltemp;
6008 
6009 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6010 			case SCF_ERROR_HANDLE_MISMATCH:
6011 			case SCF_ERROR_NOT_BOUND:
6012 			case SCF_ERROR_NOT_SET:
6013 			default:
6014 				bad_error("scf_service_add_instance",
6015 				    scf_error());
6016 			}
6017 		}
6018 
6019 nosnap:
6020 		/*
6021 		 * Create a last-import snapshot to serve as an attachment
6022 		 * point for the real one from the temporary instance.  Since
6023 		 * the contents is irrelevant, take it now, while the instance
6024 		 * is empty, to minimize svc.configd's work.
6025 		 */
6026 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6027 		    imp_lisnap) != 0) {
6028 			switch (scf_error()) {
6029 			case SCF_ERROR_CONNECTION_BROKEN:
6030 				goto connaborted;
6031 
6032 			case SCF_ERROR_NO_RESOURCES:
6033 				r = stash_scferror(lcbdata);
6034 				goto deltemp;
6035 
6036 			case SCF_ERROR_EXISTS:
6037 				warn(gettext("%s changed unexpectedly "
6038 				    "(snapshot \"%s\" added).\n"),
6039 				    inst->sc_fmri, snap_lastimport);
6040 				lcbdata->sc_err = EBUSY;
6041 				r = UU_WALK_ERROR;
6042 				goto deltemp;
6043 
6044 			case SCF_ERROR_PERMISSION_DENIED:
6045 				warn(gettext("Could not take \"%s\" snapshot "
6046 				    "of %s (permission denied).\n"),
6047 				    snap_lastimport, inst->sc_fmri);
6048 				r = stash_scferror(lcbdata);
6049 				goto deltemp;
6050 
6051 			default:
6052 				scfwarn();
6053 				lcbdata->sc_err = -1;
6054 				r = UU_WALK_ERROR;
6055 				goto deltemp;
6056 
6057 			case SCF_ERROR_NOT_SET:
6058 			case SCF_ERROR_INTERNAL:
6059 			case SCF_ERROR_INVALID_ARGUMENT:
6060 			case SCF_ERROR_HANDLE_MISMATCH:
6061 				bad_error("_scf_snapshot_take_new",
6062 				    scf_error());
6063 			}
6064 		}
6065 
6066 		if (li_only)
6067 			goto lionly;
6068 
6069 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6070 
6071 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6072 		    flags);
6073 		switch (r) {
6074 		case 0:
6075 			break;
6076 
6077 		case ECONNABORTED:
6078 			goto connaborted;
6079 
6080 		case ECANCELED:
6081 			warn(gettext("%s changed unexpectedly "
6082 			    "(instance \"%s\" deleted).\n"),
6083 			    inst->sc_parent->sc_fmri, inst->sc_name);
6084 			lcbdata->sc_err = EBUSY;
6085 			r = UU_WALK_ERROR;
6086 			goto deltemp;
6087 
6088 		case EEXIST:
6089 			warn(gettext("%s changed unexpectedly "
6090 			    "(property group added).\n"), inst->sc_fmri);
6091 			lcbdata->sc_err = EBUSY;
6092 			r = UU_WALK_ERROR;
6093 			goto deltemp;
6094 
6095 		default:
6096 			lcbdata->sc_err = r;
6097 			r = UU_WALK_ERROR;
6098 			goto deltemp;
6099 
6100 		case EINVAL:	/* caught above */
6101 			bad_error("lscf_import_instance_pgs", r);
6102 		}
6103 
6104 		ctx.sc_parent = imp_inst;
6105 		ctx.sc_service = 0;
6106 		ctx.sc_trans = NULL;
6107 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6108 		    &ctx, UU_DEFAULT) != 0) {
6109 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6110 				bad_error("uu_list_walk", uu_error());
6111 
6112 			if (ctx.sc_err == ECONNABORTED)
6113 				goto connaborted;
6114 			lcbdata->sc_err = ctx.sc_err;
6115 			r = UU_WALK_ERROR;
6116 			goto deltemp;
6117 		}
6118 
6119 		inst->sc_import_state = IMPORT_PROP_DONE;
6120 
6121 		if (g_verbose)
6122 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6123 			    snap_initial, inst->sc_fmri);
6124 		r = take_snap(imp_inst, snap_initial, imp_snap);
6125 		switch (r) {
6126 		case 0:
6127 			break;
6128 
6129 		case ECONNABORTED:
6130 			goto connaborted;
6131 
6132 		case ENOSPC:
6133 		case -1:
6134 			lcbdata->sc_err = r;
6135 			r = UU_WALK_ERROR;
6136 			goto deltemp;
6137 
6138 		case ECANCELED:
6139 			warn(gettext("%s changed unexpectedly "
6140 			    "(instance %s deleted).\n"),
6141 			    inst->sc_parent->sc_fmri, inst->sc_name);
6142 			lcbdata->sc_err = r;
6143 			r = UU_WALK_ERROR;
6144 			goto deltemp;
6145 
6146 		case EPERM:
6147 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6148 			lcbdata->sc_err = r;
6149 			r = UU_WALK_ERROR;
6150 			goto deltemp;
6151 
6152 		default:
6153 			bad_error("take_snap", r);
6154 		}
6155 	}
6156 
6157 lionly:
6158 	if (lcbdata->sc_flags & SCI_NOSNAP)
6159 		goto deltemp;
6160 
6161 	/* transfer snapshot from temporary instance */
6162 	if (g_verbose)
6163 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6164 		    snap_lastimport, inst->sc_fmri);
6165 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6166 		switch (scf_error()) {
6167 		case SCF_ERROR_CONNECTION_BROKEN:
6168 			goto connaborted;
6169 
6170 		case SCF_ERROR_NO_RESOURCES:
6171 			r = stash_scferror(lcbdata);
6172 			goto deltemp;
6173 
6174 		case SCF_ERROR_PERMISSION_DENIED:
6175 			warn(gettext("Could not take \"%s\" snapshot for %s "
6176 			    "(permission denied).\n"), snap_lastimport,
6177 			    inst->sc_fmri);
6178 			r = stash_scferror(lcbdata);
6179 			goto deltemp;
6180 
6181 		case SCF_ERROR_NOT_SET:
6182 		case SCF_ERROR_HANDLE_MISMATCH:
6183 		default:
6184 			bad_error("_scf_snapshot_attach", scf_error());
6185 		}
6186 	}
6187 
6188 	inst->sc_import_state = IMPORT_COMPLETE;
6189 
6190 	r = UU_WALK_NEXT;
6191 
6192 deltemp:
6193 	/* delete temporary instance */
6194 	if (scf_instance_delete(imp_tinst) != 0) {
6195 		switch (scf_error()) {
6196 		case SCF_ERROR_DELETED:
6197 			break;
6198 
6199 		case SCF_ERROR_CONNECTION_BROKEN:
6200 			goto connaborted;
6201 
6202 		case SCF_ERROR_NOT_SET:
6203 		case SCF_ERROR_NOT_BOUND:
6204 		default:
6205 			bad_error("scf_instance_delete", scf_error());
6206 		}
6207 	}
6208 
6209 	return (r);
6210 
6211 connaborted:
6212 	warn(gettext("Could not delete svc:/%s:%s "
6213 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6214 	lcbdata->sc_err = ECONNABORTED;
6215 	return (UU_WALK_ERROR);
6216 }
6217 
6218 /*
6219  * If the service is missing, create it, import its properties, and import the
6220  * instances.  Since the service is brand new, it should be empty, and if we
6221  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6222  *
6223  * If the service exists, we want to upgrade its properties and import the
6224  * instances.  Upgrade requires a last-import snapshot, though, which are
6225  * children of instances, so first we'll have to go through the instances
6226  * looking for a last-import snapshot.  If we don't find one then we'll just
6227  * override-import the service properties (but don't delete existing
6228  * properties: another service might have declared us as a dependent).  Before
6229  * we change anything, though, we want to take the previous snapshots.  We
6230  * also give lscf_instance_import() a leg up on taking last-import snapshots
6231  * by importing the manifest's service properties into a temporary service.
6232  *
6233  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6234  * sets lcbdata->sc_err to
6235  *   ECONNABORTED - repository connection broken
6236  *   ENOMEM - out of memory
6237  *   ENOSPC - svc.configd is out of resources
6238  *   EPERM - couldn't create temporary service (error printed)
6239  *	   - couldn't import into temp service (error printed)
6240  *	   - couldn't create service (error printed)
6241  *	   - couldn't import dependent (error printed)
6242  *	   - couldn't take snapshot (error printed)
6243  *	   - couldn't create instance (error printed)
6244  *	   - couldn't create, modify, or delete pg (error printed)
6245  *	   - couldn't create, modify, or delete dependent (error printed)
6246  *	   - couldn't import instance (error printed)
6247  *   EROFS - couldn't create temporary service (repository read-only)
6248  *	   - couldn't import into temporary service (repository read-only)
6249  *	   - couldn't create service (repository read-only)
6250  *	   - couldn't import dependent (repository read-only)
6251  *	   - couldn't create instance (repository read-only)
6252  *	   - couldn't create, modify, or delete pg or dependent
6253  *	   - couldn't import instance (repository read-only)
6254  *   EACCES - couldn't create temporary service (backend access denied)
6255  *	    - couldn't import into temporary service (backend access denied)
6256  *	    - couldn't create service (backend access denied)
6257  *	    - couldn't import dependent (backend access denied)
6258  *	    - couldn't create instance (backend access denied)
6259  *	    - couldn't create, modify, or delete pg or dependent
6260  *	    - couldn't import instance (backend access denied)
6261  *   EINVAL - service name is invalid (error printed)
6262  *	    - service name is too long (error printed)
6263  *	    - s has invalid pgroup (error printed)
6264  *	    - s has invalid dependent (error printed)
6265  *	    - instance name is invalid (error printed)
6266  *	    - instance entity_t is invalid (error printed)
6267  *   EEXIST - couldn't create temporary service (already exists) (error printed)
6268  *	    - couldn't import dependent (dependency pg already exists) (printed)
6269  *	    - dependency collision in dependent service (error printed)
6270  *   EBUSY - temporary service deleted (error printed)
6271  *	   - property group added to temporary service (error printed)
6272  *	   - new property group changed or was deleted (error printed)
6273  *	   - service was added unexpectedly (error printed)
6274  *	   - service was deleted unexpectedly (error printed)
6275  *	   - property group added to new service (error printed)
6276  *	   - instance added unexpectedly (error printed)
6277  *	   - instance deleted unexpectedly (error printed)
6278  *	   - dependent service deleted unexpectedly (error printed)
6279  *	   - pg was added, changed, or deleted (error printed)
6280  *	   - dependent pg changed (error printed)
6281  *	   - temporary instance added, changed, or deleted (error printed)
6282  *   EBADF - a last-import snapshot is corrupt (error printed)
6283  *	   - the service is corrupt (error printed)
6284  *	   - a dependent is corrupt (error printed)
6285  *	   - an instance is corrupt (error printed)
6286  *	   - an instance has a corrupt last-import snapshot (error printed)
6287  *	   - dependent target has a corrupt snapshot (error printed)
6288  *   -1 - unknown libscf error (error printed)
6289  */
6290 static int
6291 lscf_service_import(void *v, void *pvt)
6292 {
6293 	entity_t *s = v;
6294 	scf_callback_t cbdata;
6295 	scf_callback_t *lcbdata = pvt;
6296 	scf_scope_t *scope = lcbdata->sc_parent;
6297 	entity_t *inst, linst;
6298 	int r;
6299 	int fresh = 0;
6300 	scf_snaplevel_t *running;
6301 	int have_ge = 0;
6302 
6303 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
6304 	    "was deleted unexpectedly.\n");
6305 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6306 	    "changed unexpectedly (property group added).\n");
6307 	const char * const s_deleted =
6308 	    gettext("%s was deleted unexpectedly.\n");
6309 	const char * const i_deleted =
6310 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6311 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6312 	    "is corrupt (missing service snaplevel).\n");
6313 	const char * const s_mfile_upd =
6314 	    gettext("Unable to update the manifest file connection "
6315 	    "for %s\n");
6316 
6317 	li_only = 0;
6318 	/* Validate the service name */
6319 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6320 		switch (scf_error()) {
6321 		case SCF_ERROR_CONNECTION_BROKEN:
6322 			return (stash_scferror(lcbdata));
6323 
6324 		case SCF_ERROR_INVALID_ARGUMENT:
6325 			warn(gettext("\"%s\" is an invalid service name.  "
6326 			    "Cannot import.\n"), s->sc_name);
6327 			return (stash_scferror(lcbdata));
6328 
6329 		case SCF_ERROR_NOT_FOUND:
6330 			break;
6331 
6332 		case SCF_ERROR_HANDLE_MISMATCH:
6333 		case SCF_ERROR_NOT_BOUND:
6334 		case SCF_ERROR_NOT_SET:
6335 		default:
6336 			bad_error("scf_scope_get_service", scf_error());
6337 		}
6338 	}
6339 
6340 	/* create temporary service */
6341 	/*
6342 	 * the size of the buffer was reduced to max_scf_name_len to prevent
6343 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6344 	 * should be restored to its original value (max_scf_name_len +1)
6345 	 */
6346 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6347 	if (r < 0)
6348 		bad_error("snprintf", errno);
6349 	if (r > max_scf_name_len) {
6350 		warn(gettext(
6351 		    "Service name \"%s\" is too long.  Cannot import.\n"),
6352 		    s->sc_name);
6353 		lcbdata->sc_err = EINVAL;
6354 		return (UU_WALK_ERROR);
6355 	}
6356 
6357 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6358 		switch (scf_error()) {
6359 		case SCF_ERROR_CONNECTION_BROKEN:
6360 		case SCF_ERROR_NO_RESOURCES:
6361 		case SCF_ERROR_BACKEND_READONLY:
6362 		case SCF_ERROR_BACKEND_ACCESS:
6363 			return (stash_scferror(lcbdata));
6364 
6365 		case SCF_ERROR_EXISTS:
6366 			warn(gettext(
6367 			    "Temporary service \"%s\" must be deleted before "
6368 			    "this manifest can be imported.\n"), imp_tsname);
6369 			return (stash_scferror(lcbdata));
6370 
6371 		case SCF_ERROR_PERMISSION_DENIED:
6372 			warn(gettext("Could not create temporary service "
6373 			    "\"%s\" (permission denied).\n"), imp_tsname);
6374 			return (stash_scferror(lcbdata));
6375 
6376 		case SCF_ERROR_INVALID_ARGUMENT:
6377 		case SCF_ERROR_HANDLE_MISMATCH:
6378 		case SCF_ERROR_NOT_BOUND:
6379 		case SCF_ERROR_NOT_SET:
6380 		default:
6381 			bad_error("scf_scope_add_service", scf_error());
6382 		}
6383 	}
6384 
6385 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6386 	if (r < 0)
6387 		bad_error("snprintf", errno);
6388 
6389 	cbdata.sc_handle = lcbdata->sc_handle;
6390 	cbdata.sc_parent = imp_tsvc;
6391 	cbdata.sc_service = 1;
6392 	cbdata.sc_source_fmri = s->sc_fmri;
6393 	cbdata.sc_target_fmri = imp_str;
6394 	cbdata.sc_flags = 0;
6395 
6396 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6397 	    UU_DEFAULT) != 0) {
6398 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6399 			bad_error("uu_list_walk", uu_error());
6400 
6401 		lcbdata->sc_err = cbdata.sc_err;
6402 		switch (cbdata.sc_err) {
6403 		case ECONNABORTED:
6404 			goto connaborted;
6405 
6406 		case ECANCELED:
6407 			warn(ts_deleted, imp_tsname);
6408 			lcbdata->sc_err = EBUSY;
6409 			return (UU_WALK_ERROR);
6410 
6411 		case EEXIST:
6412 			warn(ts_pg_added, imp_tsname);
6413 			lcbdata->sc_err = EBUSY;
6414 			return (UU_WALK_ERROR);
6415 		}
6416 
6417 		r = UU_WALK_ERROR;
6418 		goto deltemp;
6419 	}
6420 
6421 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6422 	    UU_DEFAULT) != 0) {
6423 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6424 			bad_error("uu_list_walk", uu_error());
6425 
6426 		lcbdata->sc_err = cbdata.sc_err;
6427 		switch (cbdata.sc_err) {
6428 		case ECONNABORTED:
6429 			goto connaborted;
6430 
6431 		case ECANCELED:
6432 			warn(ts_deleted, imp_tsname);
6433 			lcbdata->sc_err = EBUSY;
6434 			return (UU_WALK_ERROR);
6435 
6436 		case EEXIST:
6437 			warn(ts_pg_added, imp_tsname);
6438 			lcbdata->sc_err = EBUSY;
6439 			return (UU_WALK_ERROR);
6440 		}
6441 
6442 		r = UU_WALK_ERROR;
6443 		goto deltemp;
6444 	}
6445 
6446 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6447 		switch (scf_error()) {
6448 		case SCF_ERROR_NOT_FOUND:
6449 			break;
6450 
6451 		case SCF_ERROR_CONNECTION_BROKEN:
6452 			goto connaborted;
6453 
6454 		case SCF_ERROR_INVALID_ARGUMENT:
6455 		case SCF_ERROR_HANDLE_MISMATCH:
6456 		case SCF_ERROR_NOT_BOUND:
6457 		case SCF_ERROR_NOT_SET:
6458 		default:
6459 			bad_error("scf_scope_get_service", scf_error());
6460 		}
6461 
6462 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6463 			switch (scf_error()) {
6464 			case SCF_ERROR_CONNECTION_BROKEN:
6465 				goto connaborted;
6466 
6467 			case SCF_ERROR_NO_RESOURCES:
6468 			case SCF_ERROR_BACKEND_READONLY:
6469 			case SCF_ERROR_BACKEND_ACCESS:
6470 				r = stash_scferror(lcbdata);
6471 				goto deltemp;
6472 
6473 			case SCF_ERROR_EXISTS:
6474 				warn(gettext("Scope \"%s\" changed unexpectedly"
6475 				    " (service \"%s\" added).\n"),
6476 				    SCF_SCOPE_LOCAL, s->sc_name);
6477 				lcbdata->sc_err = EBUSY;
6478 				goto deltemp;
6479 
6480 			case SCF_ERROR_PERMISSION_DENIED:
6481 				warn(gettext("Could not create service \"%s\" "
6482 				    "(permission denied).\n"), s->sc_name);
6483 				goto deltemp;
6484 
6485 			case SCF_ERROR_INVALID_ARGUMENT:
6486 			case SCF_ERROR_HANDLE_MISMATCH:
6487 			case SCF_ERROR_NOT_BOUND:
6488 			case SCF_ERROR_NOT_SET:
6489 			default:
6490 				bad_error("scf_scope_add_service", scf_error());
6491 			}
6492 		}
6493 
6494 		s->sc_import_state = IMPORT_PROP_BEGUN;
6495 
6496 		/* import service properties */
6497 		cbdata.sc_handle = lcbdata->sc_handle;
6498 		cbdata.sc_parent = imp_svc;
6499 		cbdata.sc_service = 1;
6500 		cbdata.sc_flags = lcbdata->sc_flags;
6501 		cbdata.sc_source_fmri = s->sc_fmri;
6502 		cbdata.sc_target_fmri = s->sc_fmri;
6503 
6504 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6505 		    &cbdata, UU_DEFAULT) != 0) {
6506 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6507 				bad_error("uu_list_walk", uu_error());
6508 
6509 			lcbdata->sc_err = cbdata.sc_err;
6510 			switch (cbdata.sc_err) {
6511 			case ECONNABORTED:
6512 				goto connaborted;
6513 
6514 			case ECANCELED:
6515 				warn(s_deleted, s->sc_fmri);
6516 				lcbdata->sc_err = EBUSY;
6517 				return (UU_WALK_ERROR);
6518 
6519 			case EEXIST:
6520 				warn(gettext("%s changed unexpectedly "
6521 				    "(property group added).\n"), s->sc_fmri);
6522 				lcbdata->sc_err = EBUSY;
6523 				return (UU_WALK_ERROR);
6524 
6525 			case EINVAL:
6526 				/* caught above */
6527 				bad_error("entity_pgroup_import",
6528 				    cbdata.sc_err);
6529 			}
6530 
6531 			r = UU_WALK_ERROR;
6532 			goto deltemp;
6533 		}
6534 
6535 		cbdata.sc_trans = NULL;
6536 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
6537 		    &cbdata, UU_DEFAULT) != 0) {
6538 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6539 				bad_error("uu_list_walk", uu_error());
6540 
6541 			lcbdata->sc_err = cbdata.sc_err;
6542 			if (cbdata.sc_err == ECONNABORTED)
6543 				goto connaborted;
6544 			r = UU_WALK_ERROR;
6545 			goto deltemp;
6546 		}
6547 
6548 		s->sc_import_state = IMPORT_PROP_DONE;
6549 
6550 		/*
6551 		 * This is a new service, so we can't take previous snapshots
6552 		 * or upgrade service properties.
6553 		 */
6554 		fresh = 1;
6555 		goto instances;
6556 	}
6557 
6558 	/* Clear sc_seen for the instances. */
6559 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
6560 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
6561 		bad_error("uu_list_walk", uu_error());
6562 
6563 	/*
6564 	 * Take previous snapshots for all instances.  Even for ones not
6565 	 * mentioned in the bundle, since we might change their service
6566 	 * properties.
6567 	 */
6568 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6569 		switch (scf_error()) {
6570 		case SCF_ERROR_CONNECTION_BROKEN:
6571 			goto connaborted;
6572 
6573 		case SCF_ERROR_DELETED:
6574 			warn(s_deleted, s->sc_fmri);
6575 			lcbdata->sc_err = EBUSY;
6576 			r = UU_WALK_ERROR;
6577 			goto deltemp;
6578 
6579 		case SCF_ERROR_HANDLE_MISMATCH:
6580 		case SCF_ERROR_NOT_BOUND:
6581 		case SCF_ERROR_NOT_SET:
6582 		default:
6583 			bad_error("scf_iter_service_instances", scf_error());
6584 		}
6585 	}
6586 
6587 	for (;;) {
6588 		r = scf_iter_next_instance(imp_iter, imp_inst);
6589 		if (r == 0)
6590 			break;
6591 		if (r != 1) {
6592 			switch (scf_error()) {
6593 			case SCF_ERROR_DELETED:
6594 				warn(s_deleted, s->sc_fmri);
6595 				lcbdata->sc_err = EBUSY;
6596 				r = UU_WALK_ERROR;
6597 				goto deltemp;
6598 
6599 			case SCF_ERROR_CONNECTION_BROKEN:
6600 				goto connaborted;
6601 
6602 			case SCF_ERROR_NOT_BOUND:
6603 			case SCF_ERROR_HANDLE_MISMATCH:
6604 			case SCF_ERROR_INVALID_ARGUMENT:
6605 			case SCF_ERROR_NOT_SET:
6606 			default:
6607 				bad_error("scf_iter_next_instance",
6608 				    scf_error());
6609 			}
6610 		}
6611 
6612 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
6613 			switch (scf_error()) {
6614 			case SCF_ERROR_DELETED:
6615 				continue;
6616 
6617 			case SCF_ERROR_CONNECTION_BROKEN:
6618 				goto connaborted;
6619 
6620 			case SCF_ERROR_NOT_SET:
6621 			case SCF_ERROR_NOT_BOUND:
6622 			default:
6623 				bad_error("scf_instance_get_name", scf_error());
6624 			}
6625 		}
6626 
6627 		if (g_verbose)
6628 			warn(gettext(
6629 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
6630 			    snap_previous, s->sc_name, imp_str);
6631 
6632 		r = take_snap(imp_inst, snap_previous, imp_snap);
6633 		switch (r) {
6634 		case 0:
6635 			break;
6636 
6637 		case ECANCELED:
6638 			continue;
6639 
6640 		case ECONNABORTED:
6641 			goto connaborted;
6642 
6643 		case EPERM:
6644 			warn(gettext("Could not take \"%s\" snapshot of "
6645 			    "svc:/%s:%s (permission denied).\n"),
6646 			    snap_previous, s->sc_name, imp_str);
6647 			lcbdata->sc_err = r;
6648 			return (UU_WALK_ERROR);
6649 
6650 		case ENOSPC:
6651 		case -1:
6652 			lcbdata->sc_err = r;
6653 			r = UU_WALK_ERROR;
6654 			goto deltemp;
6655 
6656 		default:
6657 			bad_error("take_snap", r);
6658 		}
6659 
6660 		linst.sc_name = imp_str;
6661 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
6662 		    &linst, NULL, NULL);
6663 		if (inst != NULL) {
6664 			inst->sc_import_state = IMPORT_PREVIOUS;
6665 			inst->sc_seen = 1;
6666 		}
6667 	}
6668 
6669 	/*
6670 	 * Create the new instances and take previous snapshots of
6671 	 * them.  This is not necessary, but it maximizes data preservation.
6672 	 */
6673 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
6674 	    inst != NULL;
6675 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
6676 	    inst)) {
6677 		if (inst->sc_seen)
6678 			continue;
6679 
6680 		if (scf_service_add_instance(imp_svc, inst->sc_name,
6681 		    imp_inst) != 0) {
6682 			switch (scf_error()) {
6683 			case SCF_ERROR_CONNECTION_BROKEN:
6684 				goto connaborted;
6685 
6686 			case SCF_ERROR_BACKEND_READONLY:
6687 			case SCF_ERROR_BACKEND_ACCESS:
6688 			case SCF_ERROR_NO_RESOURCES:
6689 				r = stash_scferror(lcbdata);
6690 				goto deltemp;
6691 
6692 			case SCF_ERROR_EXISTS:
6693 				warn(gettext("%s changed unexpectedly "
6694 				    "(instance \"%s\" added).\n"), s->sc_fmri,
6695 				    inst->sc_name);
6696 				lcbdata->sc_err = EBUSY;
6697 				r = UU_WALK_ERROR;
6698 				goto deltemp;
6699 
6700 			case SCF_ERROR_INVALID_ARGUMENT:
6701 				warn(gettext("Service \"%s\" has instance with "
6702 				    "invalid name \"%s\".\n"), s->sc_name,
6703 				    inst->sc_name);
6704 				r = stash_scferror(lcbdata);
6705 				goto deltemp;
6706 
6707 			case SCF_ERROR_PERMISSION_DENIED:
6708 				warn(gettext("Could not create instance \"%s\" "
6709 				    "in %s (permission denied).\n"),
6710 				    inst->sc_name, s->sc_fmri);
6711 				r = stash_scferror(lcbdata);
6712 				goto deltemp;
6713 
6714 			case SCF_ERROR_HANDLE_MISMATCH:
6715 			case SCF_ERROR_NOT_BOUND:
6716 			case SCF_ERROR_NOT_SET:
6717 			default:
6718 				bad_error("scf_service_add_instance",
6719 				    scf_error());
6720 			}
6721 		}
6722 
6723 		if (g_verbose)
6724 			warn(gettext("Taking \"%s\" snapshot for "
6725 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
6726 		r = take_snap(imp_inst, snap_previous, imp_snap);
6727 		switch (r) {
6728 		case 0:
6729 			break;
6730 
6731 		case ECANCELED:
6732 			warn(i_deleted, s->sc_fmri, inst->sc_name);
6733 			lcbdata->sc_err = EBUSY;
6734 			r = UU_WALK_ERROR;
6735 			goto deltemp;
6736 
6737 		case ECONNABORTED:
6738 			goto connaborted;
6739 
6740 		case EPERM:
6741 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
6742 			lcbdata->sc_err = r;
6743 			r = UU_WALK_ERROR;
6744 			goto deltemp;
6745 
6746 		case ENOSPC:
6747 		case -1:
6748 			r = UU_WALK_ERROR;
6749 			goto deltemp;
6750 
6751 		default:
6752 			bad_error("take_snap", r);
6753 		}
6754 	}
6755 
6756 	s->sc_import_state = IMPORT_PREVIOUS;
6757 
6758 	/*
6759 	 * Upgrade service properties, if we can find a last-import snapshot.
6760 	 * Any will do because we don't support different service properties
6761 	 * in different manifests, so all snaplevels of the service in all of
6762 	 * the last-import snapshots of the instances should be the same.
6763 	 */
6764 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6765 		switch (scf_error()) {
6766 		case SCF_ERROR_CONNECTION_BROKEN:
6767 			goto connaborted;
6768 
6769 		case SCF_ERROR_DELETED:
6770 			warn(s_deleted, s->sc_fmri);
6771 			lcbdata->sc_err = EBUSY;
6772 			r = UU_WALK_ERROR;
6773 			goto deltemp;
6774 
6775 		case SCF_ERROR_HANDLE_MISMATCH:
6776 		case SCF_ERROR_NOT_BOUND:
6777 		case SCF_ERROR_NOT_SET:
6778 		default:
6779 			bad_error("scf_iter_service_instances", scf_error());
6780 		}
6781 	}
6782 
6783 	for (;;) {
6784 		r = scf_iter_next_instance(imp_iter, imp_inst);
6785 		if (r == -1) {
6786 			switch (scf_error()) {
6787 			case SCF_ERROR_DELETED:
6788 				warn(s_deleted, s->sc_fmri);
6789 				lcbdata->sc_err = EBUSY;
6790 				r = UU_WALK_ERROR;
6791 				goto deltemp;
6792 
6793 			case SCF_ERROR_CONNECTION_BROKEN:
6794 				goto connaborted;
6795 
6796 			case SCF_ERROR_NOT_BOUND:
6797 			case SCF_ERROR_HANDLE_MISMATCH:
6798 			case SCF_ERROR_INVALID_ARGUMENT:
6799 			case SCF_ERROR_NOT_SET:
6800 			default:
6801 				bad_error("scf_iter_next_instance",
6802 				    scf_error());
6803 			}
6804 		}
6805 
6806 		if (r == 0) {
6807 			/*
6808 			 * Didn't find any last-import snapshots.  Override-
6809 			 * import the properties.  Unless one of the instances
6810 			 * has a general/enabled property, in which case we're
6811 			 * probably running a last-import-capable svccfg for
6812 			 * the first time, and we should only take the
6813 			 * last-import snapshot.
6814 			 */
6815 			if (have_ge) {
6816 				pgroup_t *mfpg;
6817 				scf_callback_t mfcbdata;
6818 
6819 				li_only = 1;
6820 				no_refresh = 1;
6821 				/*
6822 				 * Need to go ahead and import the manifestfiles
6823 				 * pg if it exists. If the last-import snapshot
6824 				 * upgrade code is ever removed this code can
6825 				 * be removed as well.
6826 				 */
6827 				mfpg = internal_pgroup_find(s,
6828 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
6829 
6830 				if (mfpg) {
6831 					mfcbdata.sc_handle = g_hndl;
6832 					mfcbdata.sc_parent = imp_svc;
6833 					mfcbdata.sc_service = 1;
6834 					mfcbdata.sc_flags = SCI_FORCE;
6835 					mfcbdata.sc_source_fmri = s->sc_fmri;
6836 					mfcbdata.sc_target_fmri = s->sc_fmri;
6837 					if (entity_pgroup_import(mfpg,
6838 					    &mfcbdata) != UU_WALK_NEXT) {
6839 						warn(s_mfile_upd, s->sc_fmri);
6840 						r = UU_WALK_ERROR;
6841 						goto deltemp;
6842 					}
6843 				}
6844 				break;
6845 			}
6846 
6847 			s->sc_import_state = IMPORT_PROP_BEGUN;
6848 
6849 			cbdata.sc_handle = g_hndl;
6850 			cbdata.sc_parent = imp_svc;
6851 			cbdata.sc_service = 1;
6852 			cbdata.sc_flags = SCI_FORCE;
6853 			cbdata.sc_source_fmri = s->sc_fmri;
6854 			cbdata.sc_target_fmri = s->sc_fmri;
6855 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6856 			    &cbdata, UU_DEFAULT) != 0) {
6857 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6858 					bad_error("uu_list_walk", uu_error());
6859 				lcbdata->sc_err = cbdata.sc_err;
6860 				switch (cbdata.sc_err) {
6861 				case ECONNABORTED:
6862 					goto connaborted;
6863 
6864 				case ECANCELED:
6865 					warn(s_deleted, s->sc_fmri);
6866 					lcbdata->sc_err = EBUSY;
6867 					break;
6868 
6869 				case EINVAL:	/* caught above */
6870 				case EEXIST:
6871 					bad_error("entity_pgroup_import",
6872 					    cbdata.sc_err);
6873 				}
6874 
6875 				r = UU_WALK_ERROR;
6876 				goto deltemp;
6877 			}
6878 
6879 			cbdata.sc_trans = NULL;
6880 			if (uu_list_walk(s->sc_dependents,
6881 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
6882 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6883 					bad_error("uu_list_walk", uu_error());
6884 				lcbdata->sc_err = cbdata.sc_err;
6885 				if (cbdata.sc_err == ECONNABORTED)
6886 					goto connaborted;
6887 				r = UU_WALK_ERROR;
6888 				goto deltemp;
6889 			}
6890 			break;
6891 		}
6892 
6893 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6894 		    imp_snap) != 0) {
6895 			switch (scf_error()) {
6896 			case SCF_ERROR_DELETED:
6897 				continue;
6898 
6899 			case SCF_ERROR_NOT_FOUND:
6900 				break;
6901 
6902 			case SCF_ERROR_CONNECTION_BROKEN:
6903 				goto connaborted;
6904 
6905 			case SCF_ERROR_HANDLE_MISMATCH:
6906 			case SCF_ERROR_NOT_BOUND:
6907 			case SCF_ERROR_INVALID_ARGUMENT:
6908 			case SCF_ERROR_NOT_SET:
6909 			default:
6910 				bad_error("scf_instance_get_snapshot",
6911 				    scf_error());
6912 			}
6913 
6914 			if (have_ge)
6915 				continue;
6916 
6917 			/*
6918 			 * Check for a general/enabled property.  This is how
6919 			 * we tell whether to import if there turn out to be
6920 			 * no last-import snapshots.
6921 			 */
6922 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
6923 			    imp_pg) == 0) {
6924 				if (scf_pg_get_property(imp_pg,
6925 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
6926 					have_ge = 1;
6927 				} else {
6928 					switch (scf_error()) {
6929 					case SCF_ERROR_DELETED:
6930 					case SCF_ERROR_NOT_FOUND:
6931 						continue;
6932 
6933 					case SCF_ERROR_INVALID_ARGUMENT:
6934 					case SCF_ERROR_HANDLE_MISMATCH:
6935 					case SCF_ERROR_CONNECTION_BROKEN:
6936 					case SCF_ERROR_NOT_BOUND:
6937 					case SCF_ERROR_NOT_SET:
6938 					default:
6939 						bad_error("scf_pg_get_property",
6940 						    scf_error());
6941 					}
6942 				}
6943 			} else {
6944 				switch (scf_error()) {
6945 				case SCF_ERROR_DELETED:
6946 				case SCF_ERROR_NOT_FOUND:
6947 					continue;
6948 
6949 				case SCF_ERROR_CONNECTION_BROKEN:
6950 					goto connaborted;
6951 
6952 				case SCF_ERROR_NOT_BOUND:
6953 				case SCF_ERROR_NOT_SET:
6954 				case SCF_ERROR_INVALID_ARGUMENT:
6955 				case SCF_ERROR_HANDLE_MISMATCH:
6956 				default:
6957 					bad_error("scf_instance_get_pg",
6958 					    scf_error());
6959 				}
6960 			}
6961 			continue;
6962 		}
6963 
6964 		/* find service snaplevel */
6965 		r = get_snaplevel(imp_snap, 1, imp_snpl);
6966 		switch (r) {
6967 		case 0:
6968 			break;
6969 
6970 		case ECONNABORTED:
6971 			goto connaborted;
6972 
6973 		case ECANCELED:
6974 			continue;
6975 
6976 		case ENOENT:
6977 			if (scf_instance_get_name(imp_inst, imp_str,
6978 			    imp_str_sz) < 0)
6979 				(void) strcpy(imp_str, "?");
6980 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
6981 			lcbdata->sc_err = EBADF;
6982 			r = UU_WALK_ERROR;
6983 			goto deltemp;
6984 
6985 		default:
6986 			bad_error("get_snaplevel", r);
6987 		}
6988 
6989 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6990 		    imp_rsnap) != 0) {
6991 			switch (scf_error()) {
6992 			case SCF_ERROR_DELETED:
6993 				continue;
6994 
6995 			case SCF_ERROR_NOT_FOUND:
6996 				break;
6997 
6998 			case SCF_ERROR_CONNECTION_BROKEN:
6999 				goto connaborted;
7000 
7001 			case SCF_ERROR_INVALID_ARGUMENT:
7002 			case SCF_ERROR_HANDLE_MISMATCH:
7003 			case SCF_ERROR_NOT_BOUND:
7004 			case SCF_ERROR_NOT_SET:
7005 			default:
7006 				bad_error("scf_instance_get_snapshot",
7007 				    scf_error());
7008 			}
7009 			running = NULL;
7010 		} else {
7011 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7012 			switch (r) {
7013 			case 0:
7014 				running = imp_rsnpl;
7015 				break;
7016 
7017 			case ECONNABORTED:
7018 				goto connaborted;
7019 
7020 			case ECANCELED:
7021 				continue;
7022 
7023 			case ENOENT:
7024 				if (scf_instance_get_name(imp_inst, imp_str,
7025 				    imp_str_sz) < 0)
7026 					(void) strcpy(imp_str, "?");
7027 				warn(badsnap, snap_running, s->sc_name,
7028 				    imp_str);
7029 				lcbdata->sc_err = EBADF;
7030 				r = UU_WALK_ERROR;
7031 				goto deltemp;
7032 
7033 			default:
7034 				bad_error("get_snaplevel", r);
7035 			}
7036 		}
7037 
7038 		if (g_verbose) {
7039 			if (scf_instance_get_name(imp_inst, imp_str,
7040 			    imp_str_sz) < 0)
7041 				(void) strcpy(imp_str, "?");
7042 			warn(gettext("Upgrading properties of %s according to "
7043 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7044 		}
7045 
7046 		/* upgrade service properties */
7047 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7048 		if (r == 0)
7049 			break;
7050 
7051 		switch (r) {
7052 		case ECONNABORTED:
7053 			goto connaborted;
7054 
7055 		case ECANCELED:
7056 			warn(s_deleted, s->sc_fmri);
7057 			lcbdata->sc_err = EBUSY;
7058 			break;
7059 
7060 		case ENODEV:
7061 			if (scf_instance_get_name(imp_inst, imp_str,
7062 			    imp_str_sz) < 0)
7063 				(void) strcpy(imp_str, "?");
7064 			warn(i_deleted, s->sc_fmri, imp_str);
7065 			lcbdata->sc_err = EBUSY;
7066 			break;
7067 
7068 		default:
7069 			lcbdata->sc_err = r;
7070 		}
7071 
7072 		r = UU_WALK_ERROR;
7073 		goto deltemp;
7074 	}
7075 
7076 	s->sc_import_state = IMPORT_PROP_DONE;
7077 
7078 instances:
7079 	/* import instances */
7080 	cbdata.sc_handle = lcbdata->sc_handle;
7081 	cbdata.sc_parent = imp_svc;
7082 	cbdata.sc_service = 1;
7083 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7084 	cbdata.sc_general = NULL;
7085 
7086 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7087 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7088 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7089 			bad_error("uu_list_walk", uu_error());
7090 
7091 		lcbdata->sc_err = cbdata.sc_err;
7092 		if (cbdata.sc_err == ECONNABORTED)
7093 			goto connaborted;
7094 		r = UU_WALK_ERROR;
7095 		goto deltemp;
7096 	}
7097 
7098 	s->sc_import_state = IMPORT_COMPLETE;
7099 	r = UU_WALK_NEXT;
7100 
7101 deltemp:
7102 	/* delete temporary service */
7103 	if (scf_service_delete(imp_tsvc) != 0) {
7104 		switch (scf_error()) {
7105 		case SCF_ERROR_DELETED:
7106 			break;
7107 
7108 		case SCF_ERROR_CONNECTION_BROKEN:
7109 			goto connaborted;
7110 
7111 		case SCF_ERROR_EXISTS:
7112 			warn(gettext(
7113 			    "Could not delete svc:/%s (instances exist).\n"),
7114 			    imp_tsname);
7115 			break;
7116 
7117 		case SCF_ERROR_NOT_SET:
7118 		case SCF_ERROR_NOT_BOUND:
7119 		default:
7120 			bad_error("scf_service_delete", scf_error());
7121 		}
7122 	}
7123 
7124 	return (r);
7125 
7126 connaborted:
7127 	warn(gettext("Could not delete svc:/%s "
7128 	    "(repository connection broken).\n"), imp_tsname);
7129 	lcbdata->sc_err = ECONNABORTED;
7130 	return (UU_WALK_ERROR);
7131 }
7132 
7133 static const char *
7134 import_progress(int st)
7135 {
7136 	switch (st) {
7137 	case 0:
7138 		return (gettext("not reached."));
7139 
7140 	case IMPORT_PREVIOUS:
7141 		return (gettext("previous snapshot taken."));
7142 
7143 	case IMPORT_PROP_BEGUN:
7144 		return (gettext("some properties imported."));
7145 
7146 	case IMPORT_PROP_DONE:
7147 		return (gettext("properties imported."));
7148 
7149 	case IMPORT_COMPLETE:
7150 		return (gettext("imported."));
7151 
7152 	case IMPORT_REFRESHED:
7153 		return (gettext("refresh requested."));
7154 
7155 	default:
7156 #ifndef NDEBUG
7157 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7158 		    __FILE__, __LINE__, st);
7159 #endif
7160 		abort();
7161 		/* NOTREACHED */
7162 	}
7163 }
7164 
7165 /*
7166  * Returns
7167  *   0 - success
7168  *     - fmri wasn't found (error printed)
7169  *     - entity was deleted (error printed)
7170  *     - backend denied access (error printed)
7171  *   ENOMEM - out of memory (error printed)
7172  *   ECONNABORTED - repository connection broken (error printed)
7173  *   EPERM - permission denied (error printed)
7174  *   -1 - unknown libscf error (error printed)
7175  */
7176 static int
7177 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7178 {
7179 	scf_error_t serr;
7180 	void *ent;
7181 	int issvc;
7182 	int r;
7183 
7184 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7185 	const char *dpt_deleted = gettext("Could not refresh %s "
7186 	    "(dependent \"%s\" of %s) (deleted).\n");
7187 
7188 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7189 	switch (serr) {
7190 	case SCF_ERROR_NONE:
7191 		break;
7192 
7193 	case SCF_ERROR_NO_MEMORY:
7194 		if (name == NULL)
7195 			warn(gettext("Could not refresh %s (out of memory).\n"),
7196 			    fmri);
7197 		else
7198 			warn(gettext("Could not refresh %s "
7199 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7200 			    fmri, name, d_fmri);
7201 		return (ENOMEM);
7202 
7203 	case SCF_ERROR_NOT_FOUND:
7204 		if (name == NULL)
7205 			warn(deleted, fmri);
7206 		else
7207 			warn(dpt_deleted, fmri, name, d_fmri);
7208 		return (0);
7209 
7210 	case SCF_ERROR_INVALID_ARGUMENT:
7211 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7212 	default:
7213 		bad_error("fmri_to_entity", serr);
7214 	}
7215 
7216 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7217 	switch (r) {
7218 	case 0:
7219 		break;
7220 
7221 	case ECONNABORTED:
7222 		if (name != NULL)
7223 			warn(gettext("Could not refresh %s "
7224 			    "(dependent \"%s\" of %s) "
7225 			    "(repository connection broken).\n"), fmri, name,
7226 			    d_fmri);
7227 		return (r);
7228 
7229 	case ECANCELED:
7230 		if (name == NULL)
7231 			warn(deleted, fmri);
7232 		else
7233 			warn(dpt_deleted, fmri, name, d_fmri);
7234 		return (0);
7235 
7236 	case EACCES:
7237 		if (!g_verbose)
7238 			return (0);
7239 		if (name == NULL)
7240 			warn(gettext("Could not refresh %s "
7241 			    "(backend access denied).\n"), fmri);
7242 		else
7243 			warn(gettext("Could not refresh %s "
7244 			    "(dependent \"%s\" of %s) "
7245 			    "(backend access denied).\n"), fmri, name, d_fmri);
7246 		return (0);
7247 
7248 	case EPERM:
7249 		if (name == NULL)
7250 			warn(gettext("Could not refresh %s "
7251 			    "(permission denied).\n"), fmri);
7252 		else
7253 			warn(gettext("Could not refresh %s "
7254 			    "(dependent \"%s\" of %s) "
7255 			    "(permission denied).\n"), fmri, name, d_fmri);
7256 		return (r);
7257 
7258 	case ENOSPC:
7259 		if (name == NULL)
7260 			warn(gettext("Could not refresh %s "
7261 			    "(repository server out of resources).\n"),
7262 			    fmri);
7263 		else
7264 			warn(gettext("Could not refresh %s "
7265 			    "(dependent \"%s\" of %s) "
7266 			    "(repository server out of resources).\n"),
7267 			    fmri, name, d_fmri);
7268 		return (r);
7269 
7270 	case -1:
7271 		scfwarn();
7272 		return (r);
7273 
7274 	default:
7275 		bad_error("refresh_entity", r);
7276 	}
7277 
7278 	if (issvc)
7279 		scf_service_destroy(ent);
7280 	else
7281 		scf_instance_destroy(ent);
7282 
7283 	return (0);
7284 }
7285 
7286 int
7287 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7288 {
7289 	scf_callback_t cbdata;
7290 	int result = 0;
7291 	entity_t *svc, *inst;
7292 	uu_list_t *insts;
7293 	int r;
7294 	pgroup_t *old_dpt;
7295 	void *cookie;
7296 	int annotation_set = 0;
7297 
7298 	const char * const emsg_nomem = gettext("Out of memory.\n");
7299 	const char * const emsg_nores =
7300 	    gettext("svc.configd is out of resources.\n");
7301 
7302 	lscf_prep_hndl();
7303 
7304 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7305 	    max_scf_name_len : max_scf_fmri_len) + 1;
7306 
7307 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7308 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
7309 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7310 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7311 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7312 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7313 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7314 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7315 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7316 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7317 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7318 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7319 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7320 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7321 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7322 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7323 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7324 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7325 	    (imp_str = malloc(imp_str_sz)) == NULL ||
7326 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7327 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7328 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7329 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7330 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7331 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7332 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7333 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7334 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7335 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7336 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7337 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7338 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7339 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7340 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7341 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7342 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7343 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7344 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7345 			warn(emsg_nores);
7346 		else
7347 			warn(emsg_nomem);
7348 		result = -1;
7349 		goto out;
7350 	}
7351 
7352 	r = load_init();
7353 	switch (r) {
7354 	case 0:
7355 		break;
7356 
7357 	case ENOMEM:
7358 		warn(emsg_nomem);
7359 		result = -1;
7360 		goto out;
7361 
7362 	default:
7363 		bad_error("load_init", r);
7364 	}
7365 
7366 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7367 		switch (scf_error()) {
7368 		case SCF_ERROR_CONNECTION_BROKEN:
7369 			warn(gettext("Repository connection broken.\n"));
7370 			repository_teardown();
7371 			result = -1;
7372 			goto out;
7373 
7374 		case SCF_ERROR_NOT_FOUND:
7375 		case SCF_ERROR_INVALID_ARGUMENT:
7376 		case SCF_ERROR_NOT_BOUND:
7377 		case SCF_ERROR_HANDLE_MISMATCH:
7378 		default:
7379 			bad_error("scf_handle_get_scope", scf_error());
7380 		}
7381 	}
7382 
7383 	/* Set up the auditing annotation. */
7384 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7385 		annotation_set = 1;
7386 	} else {
7387 		switch (scf_error()) {
7388 		case SCF_ERROR_CONNECTION_BROKEN:
7389 			warn(gettext("Repository connection broken.\n"));
7390 			repository_teardown();
7391 			result = -1;
7392 			goto out;
7393 
7394 		case SCF_ERROR_INVALID_ARGUMENT:
7395 		case SCF_ERROR_NOT_BOUND:
7396 		case SCF_ERROR_NO_RESOURCES:
7397 		case SCF_ERROR_INTERNAL:
7398 			bad_error("_scf_set_annotation", scf_error());
7399 			/* NOTREACHED */
7400 
7401 		default:
7402 			/*
7403 			 * Do not terminate import because of inability to
7404 			 * generate annotation audit event.
7405 			 */
7406 			warn(gettext("_scf_set_annotation() unexpectedly "
7407 			    "failed with return code of %d\n"), scf_error());
7408 			break;
7409 		}
7410 	}
7411 
7412 	/*
7413 	 * Clear the sc_import_state's of all services & instances so we can
7414 	 * report how far we got if we fail.
7415 	 */
7416 	for (svc = uu_list_first(bndl->sc_bundle_services);
7417 	    svc != NULL;
7418 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7419 		svc->sc_import_state = 0;
7420 
7421 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
7422 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
7423 		    UU_DEFAULT) != 0)
7424 			bad_error("uu_list_walk", uu_error());
7425 	}
7426 
7427 	cbdata.sc_handle = g_hndl;
7428 	cbdata.sc_parent = imp_scope;
7429 	cbdata.sc_flags = flags;
7430 	cbdata.sc_general = NULL;
7431 
7432 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
7433 	    &cbdata, UU_DEFAULT) == 0) {
7434 		/* Success.  Refresh everything. */
7435 
7436 		if (flags & SCI_NOREFRESH || no_refresh) {
7437 			no_refresh = 0;
7438 			result = 0;
7439 			goto out;
7440 		}
7441 
7442 		for (svc = uu_list_first(bndl->sc_bundle_services);
7443 		    svc != NULL;
7444 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7445 			pgroup_t *dpt;
7446 
7447 			insts = svc->sc_u.sc_service.sc_service_instances;
7448 
7449 			for (inst = uu_list_first(insts);
7450 			    inst != NULL;
7451 			    inst = uu_list_next(insts, inst)) {
7452 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
7453 				switch (r) {
7454 				case 0:
7455 					break;
7456 
7457 				case ENOMEM:
7458 				case ECONNABORTED:
7459 				case EPERM:
7460 				case -1:
7461 					goto progress;
7462 
7463 				default:
7464 					bad_error("imp_refresh_fmri", r);
7465 				}
7466 
7467 				inst->sc_import_state = IMPORT_REFRESHED;
7468 
7469 				for (dpt = uu_list_first(inst->sc_dependents);
7470 				    dpt != NULL;
7471 				    dpt = uu_list_next(inst->sc_dependents,
7472 				    dpt))
7473 					if (imp_refresh_fmri(
7474 					    dpt->sc_pgroup_fmri,
7475 					    dpt->sc_pgroup_name,
7476 					    inst->sc_fmri) != 0)
7477 						goto progress;
7478 			}
7479 
7480 			for (dpt = uu_list_first(svc->sc_dependents);
7481 			    dpt != NULL;
7482 			    dpt = uu_list_next(svc->sc_dependents, dpt))
7483 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
7484 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
7485 					goto progress;
7486 		}
7487 
7488 		for (old_dpt = uu_list_first(imp_deleted_dpts);
7489 		    old_dpt != NULL;
7490 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
7491 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
7492 			    old_dpt->sc_pgroup_name,
7493 			    old_dpt->sc_parent->sc_fmri) != 0)
7494 				goto progress;
7495 
7496 		result = 0;
7497 		goto out;
7498 	}
7499 
7500 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7501 		bad_error("uu_list_walk", uu_error());
7502 
7503 printerr:
7504 	/* If the error hasn't been printed yet, do so here. */
7505 	switch (cbdata.sc_err) {
7506 	case ECONNABORTED:
7507 		warn(gettext("Repository connection broken.\n"));
7508 		break;
7509 
7510 	case ENOMEM:
7511 		warn(emsg_nomem);
7512 		break;
7513 
7514 	case ENOSPC:
7515 		warn(emsg_nores);
7516 		break;
7517 
7518 	case EROFS:
7519 		warn(gettext("Repository is read-only.\n"));
7520 		break;
7521 
7522 	case EACCES:
7523 		warn(gettext("Repository backend denied access.\n"));
7524 		break;
7525 
7526 	case EPERM:
7527 	case EINVAL:
7528 	case EEXIST:
7529 	case EBUSY:
7530 	case EBADF:
7531 	case -1:
7532 		break;
7533 
7534 	default:
7535 		bad_error("lscf_service_import", cbdata.sc_err);
7536 	}
7537 
7538 progress:
7539 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
7540 
7541 	for (svc = uu_list_first(bndl->sc_bundle_services);
7542 	    svc != NULL;
7543 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7544 		insts = svc->sc_u.sc_service.sc_service_instances;
7545 
7546 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
7547 		    import_progress(svc->sc_import_state));
7548 
7549 		for (inst = uu_list_first(insts);
7550 		    inst != NULL;
7551 		    inst = uu_list_next(insts, inst))
7552 			warn(gettext("    Instance \"%s\": %s\n"),
7553 			    inst->sc_name,
7554 			    import_progress(inst->sc_import_state));
7555 	}
7556 
7557 	if (cbdata.sc_err == ECONNABORTED)
7558 		repository_teardown();
7559 
7560 
7561 	result = -1;
7562 
7563 out:
7564 	if (annotation_set != 0) {
7565 		/* Turn off annotation.  It is no longer needed. */
7566 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7567 	}
7568 	load_fini();
7569 
7570 	free(ud_ctarg);
7571 	free(ud_oldtarg);
7572 	free(ud_name);
7573 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7574 
7575 	scf_transaction_destroy(ud_tx);
7576 	ud_tx = NULL;
7577 	scf_iter_destroy(ud_iter);
7578 	scf_iter_destroy(ud_iter2);
7579 	ud_iter = ud_iter2 = NULL;
7580 	scf_value_destroy(ud_val);
7581 	ud_val = NULL;
7582 	scf_property_destroy(ud_prop);
7583 	scf_property_destroy(ud_dpt_prop);
7584 	ud_prop = ud_dpt_prop = NULL;
7585 	scf_pg_destroy(ud_pg);
7586 	scf_pg_destroy(ud_cur_depts_pg);
7587 	scf_pg_destroy(ud_run_dpts_pg);
7588 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7589 	scf_snaplevel_destroy(ud_snpl);
7590 	ud_snpl = NULL;
7591 	scf_instance_destroy(ud_inst);
7592 	ud_inst = NULL;
7593 
7594 	free(imp_str);
7595 	free(imp_tsname);
7596 	free(imp_fe1);
7597 	free(imp_fe2);
7598 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7599 
7600 	cookie = NULL;
7601 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7602 	    NULL) {
7603 		free((char *)old_dpt->sc_pgroup_name);
7604 		free((char *)old_dpt->sc_pgroup_fmri);
7605 		internal_pgroup_free(old_dpt);
7606 	}
7607 	uu_list_destroy(imp_deleted_dpts);
7608 
7609 	scf_transaction_destroy(imp_tx);
7610 	imp_tx = NULL;
7611 	scf_iter_destroy(imp_iter);
7612 	scf_iter_destroy(imp_rpg_iter);
7613 	scf_iter_destroy(imp_up_iter);
7614 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7615 	scf_property_destroy(imp_prop);
7616 	imp_prop = NULL;
7617 	scf_pg_destroy(imp_pg);
7618 	scf_pg_destroy(imp_pg2);
7619 	imp_pg = imp_pg2 = NULL;
7620 	scf_snaplevel_destroy(imp_snpl);
7621 	scf_snaplevel_destroy(imp_rsnpl);
7622 	imp_snpl = imp_rsnpl = NULL;
7623 	scf_snapshot_destroy(imp_snap);
7624 	scf_snapshot_destroy(imp_lisnap);
7625 	scf_snapshot_destroy(imp_tlisnap);
7626 	scf_snapshot_destroy(imp_rsnap);
7627 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7628 	scf_instance_destroy(imp_inst);
7629 	scf_instance_destroy(imp_tinst);
7630 	imp_inst = imp_tinst = NULL;
7631 	scf_service_destroy(imp_svc);
7632 	scf_service_destroy(imp_tsvc);
7633 	imp_svc = imp_tsvc = NULL;
7634 	scf_scope_destroy(imp_scope);
7635 	imp_scope = NULL;
7636 
7637 	return (result);
7638 }
7639 
7640 /*
7641  * _lscf_import_err() summarize the error handling returned by
7642  * lscf_import_{instance | service}_pgs
7643  * Return values are:
7644  * IMPORT_NEXT
7645  * IMPORT_OUT
7646  * IMPORT_BAD
7647  */
7648 
7649 #define	IMPORT_BAD	-1
7650 #define	IMPORT_NEXT	0
7651 #define	IMPORT_OUT	1
7652 
7653 static int
7654 _lscf_import_err(int err, const char *fmri)
7655 {
7656 	switch (err) {
7657 	case 0:
7658 		if (g_verbose)
7659 			warn(gettext("%s updated.\n"), fmri);
7660 		return (IMPORT_NEXT);
7661 
7662 	case ECONNABORTED:
7663 		warn(gettext("Could not update %s "
7664 		    "(repository connection broken).\n"), fmri);
7665 		return (IMPORT_OUT);
7666 
7667 	case ENOMEM:
7668 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
7669 		return (IMPORT_OUT);
7670 
7671 	case ENOSPC:
7672 		warn(gettext("Could not update %s "
7673 		    "(repository server out of resources).\n"), fmri);
7674 		return (IMPORT_OUT);
7675 
7676 	case ECANCELED:
7677 		warn(gettext(
7678 		    "Could not update %s (deleted).\n"), fmri);
7679 		return (IMPORT_NEXT);
7680 
7681 	case EPERM:
7682 	case EINVAL:
7683 	case EBUSY:
7684 		return (IMPORT_NEXT);
7685 
7686 	case EROFS:
7687 		warn(gettext("Could not update %s (repository read-only).\n"),
7688 		    fmri);
7689 		return (IMPORT_OUT);
7690 
7691 	case EACCES:
7692 		warn(gettext("Could not update %s "
7693 		    "(backend access denied).\n"), fmri);
7694 		return (IMPORT_NEXT);
7695 
7696 	case EEXIST:
7697 	default:
7698 		return (IMPORT_BAD);
7699 	}
7700 
7701 	/*NOTREACHED*/
7702 }
7703 
7704 /*
7705  * Returns
7706  *   0 - success
7707  *   -1 - lscf_import_instance_pgs() failed.
7708  */
7709 int
7710 lscf_bundle_apply(bundle_t *bndl, const char *file)
7711 {
7712 	entity_t *svc, *inst;
7713 	scf_scope_t *rscope;
7714 	scf_service_t *rsvc;
7715 	scf_instance_t *rinst;
7716 	scf_snapshot_t *rsnap;
7717 	scf_iter_t *iter;
7718 	int annotation_set = 0;
7719 	int r;
7720 
7721 	lscf_prep_hndl();
7722 
7723 	if ((rscope = scf_scope_create(g_hndl)) == NULL ||
7724 	    (rsvc = scf_service_create(g_hndl)) == NULL ||
7725 	    (rinst = scf_instance_create(g_hndl)) == NULL ||
7726 	    (rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7727 	    (iter = scf_iter_create(g_hndl)) == NULL ||
7728 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7729 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7730 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL)
7731 		scfdie();
7732 
7733 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0)
7734 		scfdie();
7735 
7736 	/*
7737 	 * Set the strings to be used for the security audit annotation
7738 	 * event.
7739 	 */
7740 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
7741 		annotation_set = 1;
7742 	} else {
7743 		switch (scf_error()) {
7744 		case SCF_ERROR_CONNECTION_BROKEN:
7745 			warn(gettext("Repository connection broken.\n"));
7746 			goto out;
7747 
7748 		case SCF_ERROR_INVALID_ARGUMENT:
7749 		case SCF_ERROR_NOT_BOUND:
7750 		case SCF_ERROR_NO_RESOURCES:
7751 		case SCF_ERROR_INTERNAL:
7752 			bad_error("_scf_set_annotation", scf_error());
7753 			/* NOTREACHED */
7754 
7755 		default:
7756 			/*
7757 			 * Do not abort apply operation because of
7758 			 * inability to create annotation audit event.
7759 			 */
7760 			warn(gettext("_scf_set_annotation() unexpectedly "
7761 			    "failed with return code of %d\n"), scf_error());
7762 			break;
7763 		}
7764 	}
7765 
7766 	for (svc = uu_list_first(bndl->sc_bundle_services);
7767 	    svc != NULL;
7768 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7769 		int refresh = 0;
7770 
7771 		if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) {
7772 			switch (scf_error()) {
7773 			case SCF_ERROR_NOT_FOUND:
7774 				if (g_verbose)
7775 					warn(gettext("Ignoring nonexistent "
7776 					    "service %s.\n"), svc->sc_name);
7777 				continue;
7778 
7779 			default:
7780 				scfdie();
7781 			}
7782 		}
7783 
7784 		/*
7785 		 * if we have pgs in the profile, we need to refresh ALL
7786 		 * instances of the service
7787 		 */
7788 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
7789 			refresh = 1;
7790 			r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc,
7791 			    SCI_FORCE | SCI_KEEP);
7792 			switch (_lscf_import_err(r, svc->sc_fmri)) {
7793 			case IMPORT_NEXT:
7794 				break;
7795 
7796 			case IMPORT_OUT:
7797 				goto out;
7798 
7799 			case IMPORT_BAD:
7800 			default:
7801 				bad_error("lscf_import_service_pgs", r);
7802 			}
7803 		}
7804 
7805 		for (inst = uu_list_first(
7806 		    svc->sc_u.sc_service.sc_service_instances);
7807 		    inst != NULL;
7808 		    inst = uu_list_next(
7809 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
7810 			if (scf_service_get_instance(rsvc, inst->sc_name,
7811 			    rinst) != 0) {
7812 				switch (scf_error()) {
7813 				case SCF_ERROR_NOT_FOUND:
7814 					if (g_verbose)
7815 						warn(gettext("Ignoring "
7816 						    "nonexistant instance "
7817 						    "%s:%s.\n"),
7818 						    inst->sc_parent->sc_name,
7819 						    inst->sc_name);
7820 					continue;
7821 
7822 				default:
7823 					scfdie();
7824 				}
7825 			}
7826 
7827 			/*
7828 			 * If the instance does not have a general/enabled
7829 			 * property and no last-import snapshot then the
7830 			 * instance is not a fully installed instance and
7831 			 * should not have a profile applied to it.
7832 			 *
7833 			 * This could happen if a service/instance declares
7834 			 * a dependent on behalf of another service/instance.
7835 			 */
7836 			if (scf_instance_get_snapshot(rinst, snap_lastimport,
7837 			    rsnap) != 0) {
7838 				if (scf_instance_get_pg(rinst, SCF_PG_GENERAL,
7839 				    imp_pg) != 0 || scf_pg_get_property(imp_pg,
7840 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
7841 					if (g_verbose)
7842 						warn(gettext("Ignoreing "
7843 						    "partial instance "
7844 						    "%s:%s.\n"),
7845 						    inst->sc_parent->sc_name,
7846 						    inst->sc_name);
7847 					continue;
7848 				}
7849 			}
7850 
7851 			r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst,
7852 			    SCI_FORCE | SCI_KEEP);
7853 			switch (_lscf_import_err(r, inst->sc_fmri)) {
7854 			case IMPORT_NEXT:
7855 				break;
7856 
7857 			case IMPORT_OUT:
7858 				goto out;
7859 
7860 			case IMPORT_BAD:
7861 			default:
7862 				bad_error("lscf_import_instance_pgs", r);
7863 			}
7864 
7865 			/* refresh only if there is no pgs in the service */
7866 			if (refresh == 0)
7867 				(void) refresh_entity(0, rinst, inst->sc_fmri,
7868 				    NULL, NULL, NULL);
7869 		}
7870 
7871 		if (refresh == 1) {
7872 			char *name_buf = safe_malloc(max_scf_name_len + 1);
7873 
7874 			(void) refresh_entity(1, rsvc, svc->sc_name, rinst,
7875 			    iter, name_buf);
7876 			free(name_buf);
7877 		}
7878 	}
7879 
7880 out:
7881 	if (annotation_set) {
7882 		/* Remove security audit annotation strings. */
7883 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7884 	}
7885 
7886 	scf_transaction_destroy(imp_tx);
7887 	imp_tx = NULL;
7888 	scf_pg_destroy(imp_pg);
7889 	imp_pg = NULL;
7890 	scf_property_destroy(imp_prop);
7891 	imp_prop = NULL;
7892 
7893 	scf_snapshot_destroy(rsnap);
7894 	scf_iter_destroy(iter);
7895 	scf_instance_destroy(rinst);
7896 	scf_service_destroy(rsvc);
7897 	scf_scope_destroy(rscope);
7898 	return (0);
7899 }
7900 
7901 
7902 /*
7903  * Export.  These functions create and output an XML tree of a service
7904  * description from the repository.  This is largely the inverse of
7905  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
7906  *
7907  * - We must include any properties which are not represented specifically by
7908  *   a service manifest, e.g., properties created by an admin post-import.  To
7909  *   do so we'll iterate through all properties and deal with each
7910  *   apropriately.
7911  *
7912  * - Children of services and instances must must be in the order set by the
7913  *   DTD, but we iterate over the properties in undefined order.  The elements
7914  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
7915  *   number of classes of them, however, we'll keep the classes separate and
7916  *   assemble them in order.
7917  */
7918 
7919 /*
7920  * Convenience function to handle xmlSetProp errors (and type casting).
7921  */
7922 static void
7923 safe_setprop(xmlNodePtr n, const char *name, const char *val)
7924 {
7925 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
7926 		uu_die(gettext("Could not set XML property.\n"));
7927 }
7928 
7929 /*
7930  * Convenience function to set an XML attribute to the single value of an
7931  * astring property.  If the value happens to be the default, don't set the
7932  * attribute.  "dval" should be the default value supplied by the DTD, or
7933  * NULL for no default.
7934  */
7935 static int
7936 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
7937     const char *name, const char *dval)
7938 {
7939 	scf_value_t *val;
7940 	ssize_t len;
7941 	char *str;
7942 
7943 	val = scf_value_create(g_hndl);
7944 	if (val == NULL)
7945 		scfdie();
7946 
7947 	if (prop_get_val(prop, val) != 0) {
7948 		scf_value_destroy(val);
7949 		return (-1);
7950 	}
7951 
7952 	len = scf_value_get_as_string(val, NULL, 0);
7953 	if (len < 0)
7954 		scfdie();
7955 
7956 	str = safe_malloc(len + 1);
7957 
7958 	if (scf_value_get_as_string(val, str, len + 1) < 0)
7959 		scfdie();
7960 
7961 	scf_value_destroy(val);
7962 
7963 	if (dval == NULL || strcmp(str, dval) != 0)
7964 		safe_setprop(n, name, str);
7965 
7966 	free(str);
7967 
7968 	return (0);
7969 }
7970 
7971 /*
7972  * As above, but the attribute is always set.
7973  */
7974 static int
7975 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
7976 {
7977 	return (set_attr_from_prop_default(prop, n, name, NULL));
7978 }
7979 
7980 /*
7981  * Dump the given document onto f, with "'s replaced by ''s.
7982  */
7983 static int
7984 write_service_bundle(xmlDocPtr doc, FILE *f)
7985 {
7986 	xmlChar *mem;
7987 	int sz, i;
7988 
7989 	mem = NULL;
7990 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
7991 
7992 	if (mem == NULL) {
7993 		semerr(gettext("Could not dump XML tree.\n"));
7994 		return (-1);
7995 	}
7996 
7997 	/*
7998 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
7999 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
8000 	 * &apos; code?!
8001 	 */
8002 	for (i = 0; i < sz; ++i) {
8003 		char c = (char)mem[i];
8004 
8005 		if (c == '"')
8006 			(void) fputc('\'', f);
8007 		else if (c == '\'')
8008 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
8009 		else
8010 			(void) fputc(c, f);
8011 	}
8012 
8013 	return (0);
8014 }
8015 
8016 /*
8017  * Create the DOM elements in elts necessary to (generically) represent prop
8018  * (i.e., a property or propval element).  If the name of the property is
8019  * known, it should be passed as name_arg.  Otherwise, pass NULL.
8020  */
8021 static void
8022 export_property(scf_property_t *prop, const char *name_arg,
8023     struct pg_elts *elts, int flags)
8024 {
8025 	const char *type;
8026 	scf_error_t err = 0;
8027 	xmlNodePtr pnode, lnode;
8028 	char *lnname;
8029 	int ret;
8030 
8031 	/* name */
8032 	if (name_arg != NULL) {
8033 		(void) strcpy(exp_str, name_arg);
8034 	} else {
8035 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8036 			scfdie();
8037 	}
8038 
8039 	/* type */
8040 	type = prop_to_typestr(prop);
8041 	if (type == NULL)
8042 		uu_die(gettext("Can't export property %s: unknown type.\n"),
8043 		    exp_str);
8044 
8045 	/* If we're exporting values, and there's just one, export it here. */
8046 	if (!(flags & SCE_ALL_VALUES))
8047 		goto empty;
8048 
8049 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8050 		xmlNodePtr n;
8051 
8052 		/* Single value, so use propval */
8053 		n = xmlNewNode(NULL, (xmlChar *)"propval");
8054 		if (n == NULL)
8055 			uu_die(emsg_create_xml);
8056 
8057 		safe_setprop(n, name_attr, exp_str);
8058 		safe_setprop(n, type_attr, type);
8059 
8060 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8061 			scfdie();
8062 		safe_setprop(n, value_attr, exp_str);
8063 
8064 		if (elts->propvals == NULL)
8065 			elts->propvals = n;
8066 		else
8067 			(void) xmlAddSibling(elts->propvals, n);
8068 
8069 		return;
8070 	}
8071 
8072 	err = scf_error();
8073 
8074 	if (err == SCF_ERROR_PERMISSION_DENIED) {
8075 		semerr(emsg_permission_denied);
8076 		return;
8077 	}
8078 
8079 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8080 	    err != SCF_ERROR_NOT_FOUND &&
8081 	    err != SCF_ERROR_PERMISSION_DENIED)
8082 		scfdie();
8083 
8084 empty:
8085 	/* Multiple (or no) values, so use property */
8086 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
8087 	if (pnode == NULL)
8088 		uu_die(emsg_create_xml);
8089 
8090 	safe_setprop(pnode, name_attr, exp_str);
8091 	safe_setprop(pnode, type_attr, type);
8092 
8093 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8094 		lnname = uu_msprintf("%s_list", type);
8095 		if (lnname == NULL)
8096 			uu_die(gettext("Could not create string"));
8097 
8098 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8099 		if (lnode == NULL)
8100 			uu_die(emsg_create_xml);
8101 
8102 		uu_free(lnname);
8103 
8104 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8105 			scfdie();
8106 
8107 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8108 		    1) {
8109 			xmlNodePtr vn;
8110 
8111 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8112 			    NULL);
8113 			if (vn == NULL)
8114 				uu_die(emsg_create_xml);
8115 
8116 			if (scf_value_get_as_string(exp_val, exp_str,
8117 			    exp_str_sz) < 0)
8118 				scfdie();
8119 			safe_setprop(vn, value_attr, exp_str);
8120 		}
8121 		if (ret != 0)
8122 			scfdie();
8123 	}
8124 
8125 	if (elts->properties == NULL)
8126 		elts->properties = pnode;
8127 	else
8128 		(void) xmlAddSibling(elts->properties, pnode);
8129 }
8130 
8131 /*
8132  * Add a property_group element for this property group to elts.
8133  */
8134 static void
8135 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8136 {
8137 	xmlNodePtr n;
8138 	struct pg_elts elts;
8139 	int ret;
8140 	boolean_t read_protected;
8141 
8142 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
8143 
8144 	/* name */
8145 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8146 		scfdie();
8147 	safe_setprop(n, name_attr, exp_str);
8148 
8149 	/* type */
8150 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8151 		scfdie();
8152 	safe_setprop(n, type_attr, exp_str);
8153 
8154 	/* properties */
8155 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8156 		scfdie();
8157 
8158 	(void) memset(&elts, 0, sizeof (elts));
8159 
8160 	/*
8161 	 * If this property group is not read protected, we always want to
8162 	 * output all the values.  Otherwise, we only output the values if the
8163 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8164 	 */
8165 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8166 		scfdie();
8167 
8168 	if (!read_protected)
8169 		flags |= SCE_ALL_VALUES;
8170 
8171 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8172 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8173 			scfdie();
8174 
8175 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8176 			xmlNodePtr m;
8177 
8178 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8179 			if (m == NULL)
8180 				uu_die(emsg_create_xml);
8181 
8182 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8183 				elts.stability = m;
8184 				continue;
8185 			}
8186 
8187 			xmlFreeNode(m);
8188 		}
8189 
8190 		export_property(exp_prop, NULL, &elts, flags);
8191 	}
8192 	if (ret == -1)
8193 		scfdie();
8194 
8195 	(void) xmlAddChild(n, elts.stability);
8196 	(void) xmlAddChildList(n, elts.propvals);
8197 	(void) xmlAddChildList(n, elts.properties);
8198 
8199 	if (eelts->property_groups == NULL)
8200 		eelts->property_groups = n;
8201 	else
8202 		(void) xmlAddSibling(eelts->property_groups, n);
8203 }
8204 
8205 /*
8206  * Create an XML node representing the dependency described by the given
8207  * property group and put it in eelts.  Unless the dependency is not valid, in
8208  * which case create a generic property_group element which represents it and
8209  * put it in eelts.
8210  */
8211 static void
8212 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8213 {
8214 	xmlNodePtr n;
8215 	int err = 0, ret;
8216 	struct pg_elts elts;
8217 
8218 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
8219 	if (n == NULL)
8220 		uu_die(emsg_create_xml);
8221 
8222 	/*
8223 	 * If the external flag is present, skip this dependency because it
8224 	 * should have been created by another manifest.
8225 	 */
8226 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
8227 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8228 		    prop_get_val(exp_prop, exp_val) == 0) {
8229 			uint8_t b;
8230 
8231 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
8232 				scfdie();
8233 
8234 			if (b)
8235 				return;
8236 		}
8237 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
8238 		scfdie();
8239 
8240 	/* Get the required attributes. */
8241 
8242 	/* name */
8243 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8244 		scfdie();
8245 	safe_setprop(n, name_attr, exp_str);
8246 
8247 	/* grouping */
8248 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8249 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8250 		err = 1;
8251 
8252 	/* restart_on */
8253 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8254 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8255 		err = 1;
8256 
8257 	/* type */
8258 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8259 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8260 		err = 1;
8261 
8262 	/*
8263 	 * entities: Not required, but if we create no children, it will be
8264 	 * created as empty on import, so fail if it's missing.
8265 	 */
8266 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8267 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
8268 		scf_iter_t *eiter;
8269 		int ret2;
8270 
8271 		eiter = scf_iter_create(g_hndl);
8272 		if (eiter == NULL)
8273 			scfdie();
8274 
8275 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
8276 			scfdie();
8277 
8278 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
8279 			xmlNodePtr ch;
8280 
8281 			if (scf_value_get_astring(exp_val, exp_str,
8282 			    exp_str_sz) < 0)
8283 				scfdie();
8284 
8285 			/*
8286 			 * service_fmri's must be first, so we can add them
8287 			 * here.
8288 			 */
8289 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
8290 			    NULL);
8291 			if (ch == NULL)
8292 				uu_die(emsg_create_xml);
8293 
8294 			safe_setprop(ch, value_attr, exp_str);
8295 		}
8296 		if (ret2 == -1)
8297 			scfdie();
8298 
8299 		scf_iter_destroy(eiter);
8300 	} else
8301 		err = 1;
8302 
8303 	if (err) {
8304 		xmlFreeNode(n);
8305 
8306 		export_pg(pg, eelts, 0);
8307 
8308 		return;
8309 	}
8310 
8311 	/* Iterate through the properties & handle each. */
8312 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8313 		scfdie();
8314 
8315 	(void) memset(&elts, 0, sizeof (elts));
8316 
8317 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8318 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8319 			scfdie();
8320 
8321 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8322 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8323 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8324 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8325 			continue;
8326 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8327 			xmlNodePtr m;
8328 
8329 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8330 			if (m == NULL)
8331 				uu_die(emsg_create_xml);
8332 
8333 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8334 				elts.stability = m;
8335 				continue;
8336 			}
8337 
8338 			xmlFreeNode(m);
8339 		}
8340 
8341 		export_property(exp_prop, exp_str, &elts, 0);
8342 	}
8343 	if (ret == -1)
8344 		scfdie();
8345 
8346 	(void) xmlAddChild(n, elts.stability);
8347 	(void) xmlAddChildList(n, elts.propvals);
8348 	(void) xmlAddChildList(n, elts.properties);
8349 
8350 	if (eelts->dependencies == NULL)
8351 		eelts->dependencies = n;
8352 	else
8353 		(void) xmlAddSibling(eelts->dependencies, n);
8354 }
8355 
8356 static xmlNodePtr
8357 export_method_environment(scf_propertygroup_t *pg)
8358 {
8359 	xmlNodePtr env;
8360 	int ret;
8361 	int children = 0;
8362 
8363 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
8364 		return (NULL);
8365 
8366 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
8367 	if (env == NULL)
8368 		uu_die(emsg_create_xml);
8369 
8370 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
8371 		scfdie();
8372 
8373 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
8374 		scfdie();
8375 
8376 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
8377 		xmlNodePtr ev;
8378 		char *cp;
8379 
8380 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8381 			scfdie();
8382 
8383 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
8384 			warn(gettext("Invalid environment variable \"%s\".\n"),
8385 			    exp_str);
8386 			continue;
8387 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
8388 			warn(gettext("Invalid environment variable \"%s\"; "
8389 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
8390 			continue;
8391 		}
8392 
8393 		*cp = '\0';
8394 		cp++;
8395 
8396 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
8397 		if (ev == NULL)
8398 			uu_die(emsg_create_xml);
8399 
8400 		safe_setprop(ev, name_attr, exp_str);
8401 		safe_setprop(ev, value_attr, cp);
8402 		children++;
8403 	}
8404 
8405 	if (ret != 0)
8406 		scfdie();
8407 
8408 	if (children == 0) {
8409 		xmlFreeNode(env);
8410 		return (NULL);
8411 	}
8412 
8413 	return (env);
8414 }
8415 
8416 /*
8417  * As above, but for a method property group.
8418  */
8419 static void
8420 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
8421 {
8422 	xmlNodePtr n, env;
8423 	char *str;
8424 	int err = 0, nonenv, ret;
8425 	uint8_t use_profile;
8426 	struct pg_elts elts;
8427 	xmlNodePtr ctxt = NULL;
8428 
8429 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
8430 
8431 	/* Get the required attributes. */
8432 
8433 	/* name */
8434 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8435 		scfdie();
8436 	safe_setprop(n, name_attr, exp_str);
8437 
8438 	/* type */
8439 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8440 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8441 		err = 1;
8442 
8443 	/* exec */
8444 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
8445 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
8446 		err = 1;
8447 
8448 	/* timeout */
8449 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
8450 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
8451 	    prop_get_val(exp_prop, exp_val) == 0) {
8452 		uint64_t c;
8453 
8454 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
8455 			scfdie();
8456 
8457 		str = uu_msprintf("%llu", c);
8458 		if (str == NULL)
8459 			uu_die(gettext("Could not create string"));
8460 
8461 		safe_setprop(n, "timeout_seconds", str);
8462 		free(str);
8463 	} else
8464 		err = 1;
8465 
8466 	if (err) {
8467 		xmlFreeNode(n);
8468 
8469 		export_pg(pg, eelts, 0);
8470 
8471 		return;
8472 	}
8473 
8474 
8475 	/*
8476 	 * If we're going to have a method_context child, we need to know
8477 	 * before we iterate through the properties.  Since method_context's
8478 	 * are optional, we don't want to complain about any properties
8479 	 * missing if none of them are there.  Thus we can't use the
8480 	 * convenience functions.
8481 	 */
8482 	nonenv =
8483 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
8484 	    SCF_SUCCESS ||
8485 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
8486 	    SCF_SUCCESS ||
8487 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
8488 	    SCF_SUCCESS ||
8489 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
8490 	    SCF_SUCCESS;
8491 
8492 	if (nonenv) {
8493 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8494 		if (ctxt == NULL)
8495 			uu_die(emsg_create_xml);
8496 
8497 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
8498 		    0 &&
8499 		    set_attr_from_prop_default(exp_prop, ctxt,
8500 		    "working_directory", ":default") != 0)
8501 			err = 1;
8502 
8503 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
8504 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
8505 		    ":default") != 0)
8506 			err = 1;
8507 
8508 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
8509 		    0 &&
8510 		    set_attr_from_prop_default(exp_prop, ctxt,
8511 		    "resource_pool", ":default") != 0)
8512 			err = 1;
8513 		/*
8514 		 * We only want to complain about profile or credential
8515 		 * properties if we will use them.  To determine that we must
8516 		 * examine USE_PROFILE.
8517 		 */
8518 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8519 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8520 		    prop_get_val(exp_prop, exp_val) == 0) {
8521 			if (scf_value_get_boolean(exp_val, &use_profile) !=
8522 			    SCF_SUCCESS) {
8523 				scfdie();
8524 			}
8525 
8526 			if (use_profile) {
8527 				xmlNodePtr prof;
8528 
8529 				prof = xmlNewChild(ctxt, NULL,
8530 				    (xmlChar *)"method_profile", NULL);
8531 				if (prof == NULL)
8532 					uu_die(emsg_create_xml);
8533 
8534 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
8535 				    exp_prop) != 0 ||
8536 				    set_attr_from_prop(exp_prop, prof,
8537 				    name_attr) != 0)
8538 					err = 1;
8539 			} else {
8540 				xmlNodePtr cred;
8541 
8542 				cred = xmlNewChild(ctxt, NULL,
8543 				    (xmlChar *)"method_credential", NULL);
8544 				if (cred == NULL)
8545 					uu_die(emsg_create_xml);
8546 
8547 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
8548 				    exp_prop) != 0 ||
8549 				    set_attr_from_prop(exp_prop, cred,
8550 				    "user") != 0) {
8551 					err = 1;
8552 				}
8553 
8554 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
8555 				    exp_prop) == 0 &&
8556 				    set_attr_from_prop_default(exp_prop, cred,
8557 				    "group", ":default") != 0)
8558 					err = 1;
8559 
8560 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
8561 				    exp_prop) == 0 &&
8562 				    set_attr_from_prop_default(exp_prop, cred,
8563 				    "supp_groups", ":default") != 0)
8564 					err = 1;
8565 
8566 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
8567 				    exp_prop) == 0 &&
8568 				    set_attr_from_prop_default(exp_prop, cred,
8569 				    "privileges", ":default") != 0)
8570 					err = 1;
8571 
8572 				if (pg_get_prop(pg,
8573 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
8574 				    exp_prop) == 0 &&
8575 				    set_attr_from_prop_default(exp_prop, cred,
8576 				    "limit_privileges", ":default") != 0)
8577 					err = 1;
8578 			}
8579 		}
8580 	}
8581 
8582 	if ((env = export_method_environment(pg)) != NULL) {
8583 		if (ctxt == NULL) {
8584 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8585 			if (ctxt == NULL)
8586 				uu_die(emsg_create_xml);
8587 		}
8588 		(void) xmlAddChild(ctxt, env);
8589 	}
8590 
8591 	if (env != NULL || (nonenv && err == 0))
8592 		(void) xmlAddChild(n, ctxt);
8593 	else
8594 		xmlFreeNode(ctxt);
8595 
8596 	nonenv = (err == 0);
8597 
8598 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8599 		scfdie();
8600 
8601 	(void) memset(&elts, 0, sizeof (elts));
8602 
8603 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8604 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8605 			scfdie();
8606 
8607 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8608 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
8609 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
8610 			continue;
8611 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8612 			xmlNodePtr m;
8613 
8614 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8615 			if (m == NULL)
8616 				uu_die(emsg_create_xml);
8617 
8618 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8619 				elts.stability = m;
8620 				continue;
8621 			}
8622 
8623 			xmlFreeNode(m);
8624 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
8625 		    0 ||
8626 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
8627 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
8628 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8629 			if (nonenv)
8630 				continue;
8631 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
8632 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
8633 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
8634 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
8635 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
8636 			if (nonenv && !use_profile)
8637 				continue;
8638 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8639 			if (nonenv && use_profile)
8640 				continue;
8641 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
8642 			if (env != NULL)
8643 				continue;
8644 		}
8645 
8646 		export_property(exp_prop, exp_str, &elts, 0);
8647 	}
8648 	if (ret == -1)
8649 		scfdie();
8650 
8651 	(void) xmlAddChild(n, elts.stability);
8652 	(void) xmlAddChildList(n, elts.propvals);
8653 	(void) xmlAddChildList(n, elts.properties);
8654 
8655 	if (eelts->exec_methods == NULL)
8656 		eelts->exec_methods = n;
8657 	else
8658 		(void) xmlAddSibling(eelts->exec_methods, n);
8659 }
8660 
8661 static void
8662 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
8663     struct entity_elts *eelts)
8664 {
8665 	xmlNodePtr pgnode;
8666 
8667 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
8668 	if (pgnode == NULL)
8669 		uu_die(emsg_create_xml);
8670 
8671 	safe_setprop(pgnode, name_attr, name);
8672 	safe_setprop(pgnode, type_attr, type);
8673 
8674 	(void) xmlAddChildList(pgnode, elts->propvals);
8675 	(void) xmlAddChildList(pgnode, elts->properties);
8676 
8677 	if (eelts->property_groups == NULL)
8678 		eelts->property_groups = pgnode;
8679 	else
8680 		(void) xmlAddSibling(eelts->property_groups, pgnode);
8681 }
8682 
8683 /*
8684  * Process the general property group for a service.  This is the one with the
8685  * goodies.
8686  */
8687 static void
8688 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
8689 {
8690 	struct pg_elts elts;
8691 	int ret;
8692 
8693 	/*
8694 	 * In case there are properties which don't correspond to child
8695 	 * entities of the service entity, we'll set up a pg_elts structure to
8696 	 * put them in.
8697 	 */
8698 	(void) memset(&elts, 0, sizeof (elts));
8699 
8700 	/* Walk the properties, looking for special ones. */
8701 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8702 		scfdie();
8703 
8704 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8705 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8706 			scfdie();
8707 
8708 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
8709 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8710 			    prop_get_val(exp_prop, exp_val) == 0) {
8711 				uint8_t b;
8712 
8713 				if (scf_value_get_boolean(exp_val, &b) !=
8714 				    SCF_SUCCESS)
8715 					scfdie();
8716 
8717 				if (b) {
8718 					selts->single_instance =
8719 					    xmlNewNode(NULL,
8720 					    (xmlChar *)"single_instance");
8721 					if (selts->single_instance == NULL)
8722 						uu_die(emsg_create_xml);
8723 				}
8724 
8725 				continue;
8726 			}
8727 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8728 			xmlNodePtr rnode, sfnode;
8729 
8730 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8731 			if (rnode == NULL)
8732 				uu_die(emsg_create_xml);
8733 
8734 			sfnode = xmlNewChild(rnode, NULL,
8735 			    (xmlChar *)"service_fmri", NULL);
8736 			if (sfnode == NULL)
8737 				uu_die(emsg_create_xml);
8738 
8739 			if (set_attr_from_prop(exp_prop, sfnode,
8740 			    value_attr) == 0) {
8741 				selts->restarter = rnode;
8742 				continue;
8743 			}
8744 
8745 			xmlFreeNode(rnode);
8746 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
8747 		    0) {
8748 			xmlNodePtr s;
8749 
8750 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8751 			if (s == NULL)
8752 				uu_die(emsg_create_xml);
8753 
8754 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8755 				selts->stability = s;
8756 				continue;
8757 			}
8758 
8759 			xmlFreeNode(s);
8760 		}
8761 
8762 		export_property(exp_prop, exp_str, &elts, 0);
8763 	}
8764 	if (ret == -1)
8765 		scfdie();
8766 
8767 	if (elts.propvals != NULL || elts.properties != NULL)
8768 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
8769 		    selts);
8770 }
8771 
8772 static void
8773 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
8774 {
8775 	xmlNodePtr n, prof, cred, env;
8776 	uint8_t use_profile;
8777 	int ret, err = 0;
8778 
8779 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
8780 
8781 	env = export_method_environment(pg);
8782 
8783 	/* Need to know whether we'll use a profile or not. */
8784 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8785 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8786 	    prop_get_val(exp_prop, exp_val) == 0) {
8787 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
8788 			scfdie();
8789 
8790 		if (use_profile)
8791 			prof =
8792 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
8793 			    NULL);
8794 		else
8795 			cred =
8796 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
8797 			    NULL);
8798 	}
8799 
8800 	if (env != NULL)
8801 		(void) xmlAddChild(n, env);
8802 
8803 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8804 		scfdie();
8805 
8806 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8807 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8808 			scfdie();
8809 
8810 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
8811 			if (set_attr_from_prop(exp_prop, n,
8812 			    "working_directory") != 0)
8813 				err = 1;
8814 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
8815 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
8816 				err = 1;
8817 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
8818 			if (set_attr_from_prop(exp_prop, n,
8819 			    "resource_pool") != 0)
8820 				err = 1;
8821 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8822 			/* EMPTY */
8823 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
8824 			if (use_profile ||
8825 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
8826 				err = 1;
8827 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
8828 			if (use_profile ||
8829 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
8830 				err = 1;
8831 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
8832 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8833 			    "supp_groups") != 0)
8834 				err = 1;
8835 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
8836 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8837 			    "privileges") != 0)
8838 				err = 1;
8839 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
8840 		    0) {
8841 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8842 			    "limit_privileges") != 0)
8843 				err = 1;
8844 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8845 			if (!use_profile || set_attr_from_prop(exp_prop,
8846 			    prof, name_attr) != 0)
8847 				err = 1;
8848 		} else {
8849 			/* Can't have generic properties in method_context's */
8850 			err = 1;
8851 		}
8852 	}
8853 	if (ret == -1)
8854 		scfdie();
8855 
8856 	if (err && env == NULL) {
8857 		xmlFreeNode(n);
8858 		export_pg(pg, elts, 0);
8859 		return;
8860 	}
8861 
8862 	elts->method_context = n;
8863 }
8864 
8865 /*
8866  * Given a dependency property group in the tfmri entity (target fmri), return
8867  * a dependent element which represents it.
8868  */
8869 static xmlNodePtr
8870 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
8871 {
8872 	uint8_t b;
8873 	xmlNodePtr n, sf;
8874 	int err = 0, ret;
8875 	struct pg_elts pgelts;
8876 
8877 	/*
8878 	 * If external isn't set to true then exporting the service will
8879 	 * export this as a normal dependency, so we should stop to avoid
8880 	 * duplication.
8881 	 */
8882 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
8883 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
8884 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
8885 		if (g_verbose) {
8886 			warn(gettext("Dependent \"%s\" cannot be exported "
8887 			    "properly because the \"%s\" property of the "
8888 			    "\"%s\" dependency of %s is not set to true.\n"),
8889 			    name, scf_property_external, name, tfmri);
8890 		}
8891 
8892 		return (NULL);
8893 	}
8894 
8895 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
8896 	if (n == NULL)
8897 		uu_die(emsg_create_xml);
8898 
8899 	safe_setprop(n, name_attr, name);
8900 
8901 	/* Get the required attributes */
8902 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8903 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8904 		err = 1;
8905 
8906 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8907 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8908 		err = 1;
8909 
8910 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8911 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
8912 	    prop_get_val(exp_prop, exp_val) == 0) {
8913 		/* EMPTY */
8914 	} else
8915 		err = 1;
8916 
8917 	if (err) {
8918 		xmlFreeNode(n);
8919 		return (NULL);
8920 	}
8921 
8922 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
8923 	if (sf == NULL)
8924 		uu_die(emsg_create_xml);
8925 
8926 	safe_setprop(sf, value_attr, tfmri);
8927 
8928 	/*
8929 	 * Now add elements for the other properties.
8930 	 */
8931 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8932 		scfdie();
8933 
8934 	(void) memset(&pgelts, 0, sizeof (pgelts));
8935 
8936 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8937 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8938 			scfdie();
8939 
8940 		if (strcmp(exp_str, scf_property_external) == 0 ||
8941 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8942 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8943 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8944 			continue;
8945 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
8946 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
8947 			    prop_get_val(exp_prop, exp_val) == 0) {
8948 				char type[sizeof ("service") + 1];
8949 
8950 				if (scf_value_get_astring(exp_val, type,
8951 				    sizeof (type)) < 0)
8952 					scfdie();
8953 
8954 				if (strcmp(type, "service") == 0)
8955 					continue;
8956 			}
8957 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8958 			xmlNodePtr s;
8959 
8960 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8961 			if (s == NULL)
8962 				uu_die(emsg_create_xml);
8963 
8964 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8965 				pgelts.stability = s;
8966 				continue;
8967 			}
8968 
8969 			xmlFreeNode(s);
8970 		}
8971 
8972 		export_property(exp_prop, exp_str, &pgelts, 0);
8973 	}
8974 	if (ret == -1)
8975 		scfdie();
8976 
8977 	(void) xmlAddChild(n, pgelts.stability);
8978 	(void) xmlAddChildList(n, pgelts.propvals);
8979 	(void) xmlAddChildList(n, pgelts.properties);
8980 
8981 	return (n);
8982 }
8983 
8984 static void
8985 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
8986 {
8987 	scf_propertygroup_t *opg;
8988 	scf_iter_t *iter;
8989 	char *type, *fmri;
8990 	int ret;
8991 	struct pg_elts pgelts;
8992 	xmlNodePtr n;
8993 	scf_error_t serr;
8994 
8995 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
8996 	    (iter = scf_iter_create(g_hndl)) == NULL)
8997 		scfdie();
8998 
8999 	/* Can't use exp_prop_iter due to export_dependent(). */
9000 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
9001 		scfdie();
9002 
9003 	type = safe_malloc(max_scf_pg_type_len + 1);
9004 
9005 	/* Get an extra byte so we can tell if values are too long. */
9006 	fmri = safe_malloc(max_scf_fmri_len + 2);
9007 
9008 	(void) memset(&pgelts, 0, sizeof (pgelts));
9009 
9010 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
9011 		void *entity;
9012 		int isservice;
9013 		scf_type_t ty;
9014 
9015 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
9016 			scfdie();
9017 
9018 		if ((ty != SCF_TYPE_ASTRING &&
9019 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
9020 		    prop_get_val(exp_prop, exp_val) != 0) {
9021 			export_property(exp_prop, NULL, &pgelts, 0);
9022 			continue;
9023 		}
9024 
9025 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9026 			scfdie();
9027 
9028 		if (scf_value_get_astring(exp_val, fmri,
9029 		    max_scf_fmri_len + 2) < 0)
9030 			scfdie();
9031 
9032 		/* Look for a dependency group in the target fmri. */
9033 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9034 		switch (serr) {
9035 		case SCF_ERROR_NONE:
9036 			break;
9037 
9038 		case SCF_ERROR_NO_MEMORY:
9039 			uu_die(gettext("Out of memory.\n"));
9040 			/* NOTREACHED */
9041 
9042 		case SCF_ERROR_INVALID_ARGUMENT:
9043 			if (g_verbose) {
9044 				if (scf_property_to_fmri(exp_prop, fmri,
9045 				    max_scf_fmri_len + 2) < 0)
9046 					scfdie();
9047 
9048 				warn(gettext("The value of %s is not a valid "
9049 				    "FMRI.\n"), fmri);
9050 			}
9051 
9052 			export_property(exp_prop, exp_str, &pgelts, 0);
9053 			continue;
9054 
9055 		case SCF_ERROR_CONSTRAINT_VIOLATED:
9056 			if (g_verbose) {
9057 				if (scf_property_to_fmri(exp_prop, fmri,
9058 				    max_scf_fmri_len + 2) < 0)
9059 					scfdie();
9060 
9061 				warn(gettext("The value of %s does not specify "
9062 				    "a service or an instance.\n"), fmri);
9063 			}
9064 
9065 			export_property(exp_prop, exp_str, &pgelts, 0);
9066 			continue;
9067 
9068 		case SCF_ERROR_NOT_FOUND:
9069 			if (g_verbose) {
9070 				if (scf_property_to_fmri(exp_prop, fmri,
9071 				    max_scf_fmri_len + 2) < 0)
9072 					scfdie();
9073 
9074 				warn(gettext("The entity specified by %s does "
9075 				    "not exist.\n"), fmri);
9076 			}
9077 
9078 			export_property(exp_prop, exp_str, &pgelts, 0);
9079 			continue;
9080 
9081 		default:
9082 #ifndef NDEBUG
9083 			(void) fprintf(stderr, "%s:%d: %s() failed with "
9084 			    "unexpected error %d.\n", __FILE__, __LINE__,
9085 			    "fmri_to_entity", serr);
9086 #endif
9087 			abort();
9088 		}
9089 
9090 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9091 			if (scf_error() != SCF_ERROR_NOT_FOUND)
9092 				scfdie();
9093 
9094 			warn(gettext("Entity %s is missing dependency property "
9095 			    "group %s.\n"), fmri, exp_str);
9096 
9097 			export_property(exp_prop, NULL, &pgelts, 0);
9098 			continue;
9099 		}
9100 
9101 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9102 			scfdie();
9103 
9104 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9105 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9106 				scfdie();
9107 
9108 			warn(gettext("Property group %s is not of "
9109 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9110 
9111 			export_property(exp_prop, NULL, &pgelts, 0);
9112 			continue;
9113 		}
9114 
9115 		n = export_dependent(opg, exp_str, fmri);
9116 		if (n == NULL)
9117 			export_property(exp_prop, exp_str, &pgelts, 0);
9118 		else {
9119 			if (eelts->dependents == NULL)
9120 				eelts->dependents = n;
9121 			else
9122 				(void) xmlAddSibling(eelts->dependents,
9123 				    n);
9124 		}
9125 	}
9126 	if (ret == -1)
9127 		scfdie();
9128 
9129 	free(fmri);
9130 	free(type);
9131 
9132 	scf_iter_destroy(iter);
9133 	scf_pg_destroy(opg);
9134 
9135 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9136 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9137 		    eelts);
9138 }
9139 
9140 static void
9141 make_node(xmlNodePtr *nodep, const char *name)
9142 {
9143 	if (*nodep == NULL) {
9144 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
9145 		if (*nodep == NULL)
9146 			uu_die(emsg_create_xml);
9147 	}
9148 }
9149 
9150 static xmlNodePtr
9151 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9152 {
9153 	int ret;
9154 	xmlNodePtr parent = NULL;
9155 	xmlNodePtr loctext = NULL;
9156 
9157 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9158 		scfdie();
9159 
9160 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9161 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9162 		    prop_get_val(exp_prop, exp_val) != 0)
9163 			continue;
9164 
9165 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9166 			scfdie();
9167 
9168 		make_node(&parent, parname);
9169 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9170 		    (xmlChar *)exp_str);
9171 		if (loctext == NULL)
9172 			uu_die(emsg_create_xml);
9173 
9174 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9175 			scfdie();
9176 
9177 		safe_setprop(loctext, "xml:lang", exp_str);
9178 	}
9179 
9180 	if (ret == -1)
9181 		scfdie();
9182 
9183 	return (parent);
9184 }
9185 
9186 static xmlNodePtr
9187 export_tm_manpage(scf_propertygroup_t *pg)
9188 {
9189 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9190 	if (manpage == NULL)
9191 		uu_die(emsg_create_xml);
9192 
9193 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9194 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9195 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9196 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9197 		xmlFreeNode(manpage);
9198 		return (NULL);
9199 	}
9200 
9201 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9202 		(void) set_attr_from_prop_default(exp_prop,
9203 		    manpage, "manpath", ":default");
9204 
9205 	return (manpage);
9206 }
9207 
9208 static xmlNodePtr
9209 export_tm_doc_link(scf_propertygroup_t *pg)
9210 {
9211 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9212 	if (doc_link == NULL)
9213 		uu_die(emsg_create_xml);
9214 
9215 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9216 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9217 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9218 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9219 		xmlFreeNode(doc_link);
9220 		return (NULL);
9221 	}
9222 	return (doc_link);
9223 }
9224 
9225 /*
9226  * Process template information for a service or instances.
9227  */
9228 static void
9229 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
9230     struct template_elts *telts)
9231 {
9232 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
9233 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
9234 	xmlNodePtr child = NULL;
9235 
9236 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
9237 		scfdie();
9238 
9239 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
9240 		telts->common_name = export_tm_loctext(pg, "common_name");
9241 		if (telts->common_name == NULL)
9242 			export_pg(pg, elts, 0);
9243 		return;
9244 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
9245 		telts->description = export_tm_loctext(pg, "description");
9246 		if (telts->description == NULL)
9247 			export_pg(pg, elts, 0);
9248 		return;
9249 	}
9250 
9251 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
9252 		child = export_tm_manpage(pg);
9253 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
9254 		child = export_tm_doc_link(pg);
9255 	}
9256 
9257 	if (child != NULL) {
9258 		make_node(&telts->documentation, "documentation");
9259 		(void) xmlAddChild(telts->documentation, child);
9260 	} else {
9261 		export_pg(pg, elts, 0);
9262 	}
9263 }
9264 
9265 /*
9266  * Process the general property group for an instance.
9267  */
9268 static void
9269 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
9270     struct entity_elts *elts)
9271 {
9272 	uint8_t enabled;
9273 	struct pg_elts pgelts;
9274 	int ret;
9275 
9276 	/* enabled */
9277 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
9278 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9279 	    prop_get_val(exp_prop, exp_val) == 0) {
9280 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
9281 			scfdie();
9282 	} else {
9283 		enabled = 0;
9284 	}
9285 
9286 	safe_setprop(inode, enabled_attr, enabled ? true : false);
9287 
9288 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9289 		scfdie();
9290 
9291 	(void) memset(&pgelts, 0, sizeof (pgelts));
9292 
9293 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9294 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9295 			scfdie();
9296 
9297 		if (strcmp(exp_str, scf_property_enabled) == 0) {
9298 			continue;
9299 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9300 			xmlNodePtr rnode, sfnode;
9301 
9302 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9303 			if (rnode == NULL)
9304 				uu_die(emsg_create_xml);
9305 
9306 			sfnode = xmlNewChild(rnode, NULL,
9307 			    (xmlChar *)"service_fmri", NULL);
9308 			if (sfnode == NULL)
9309 				uu_die(emsg_create_xml);
9310 
9311 			if (set_attr_from_prop(exp_prop, sfnode,
9312 			    value_attr) == 0) {
9313 				elts->restarter = rnode;
9314 				continue;
9315 			}
9316 
9317 			xmlFreeNode(rnode);
9318 		}
9319 
9320 		export_property(exp_prop, exp_str, &pgelts, 0);
9321 	}
9322 	if (ret == -1)
9323 		scfdie();
9324 
9325 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9326 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
9327 		    elts);
9328 }
9329 
9330 /*
9331  * Put an instance element for the given instance into selts.
9332  */
9333 static void
9334 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
9335 {
9336 	xmlNodePtr n;
9337 	boolean_t isdefault;
9338 	struct entity_elts elts;
9339 	struct template_elts template_elts;
9340 	int ret;
9341 
9342 	n = xmlNewNode(NULL, (xmlChar *)"instance");
9343 	if (n == NULL)
9344 		uu_die(emsg_create_xml);
9345 
9346 	/* name */
9347 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
9348 		scfdie();
9349 	safe_setprop(n, name_attr, exp_str);
9350 	isdefault = strcmp(exp_str, "default") == 0;
9351 
9352 	/* check existance of general pg (since general/enabled is required) */
9353 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
9354 		if (scf_error() != SCF_ERROR_NOT_FOUND)
9355 			scfdie();
9356 
9357 		if (g_verbose) {
9358 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
9359 				scfdie();
9360 
9361 			warn(gettext("Instance %s has no general property "
9362 			    "group; it will be marked disabled.\n"), exp_str);
9363 		}
9364 
9365 		safe_setprop(n, enabled_attr, false);
9366 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
9367 	    strcmp(exp_str, scf_group_framework) != 0) {
9368 		if (g_verbose) {
9369 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
9370 				scfdie();
9371 
9372 			warn(gettext("Property group %s is not of type "
9373 			    "framework; the instance will be marked "
9374 			    "disabled.\n"), exp_str);
9375 		}
9376 
9377 		safe_setprop(n, enabled_attr, false);
9378 	}
9379 
9380 	/* property groups */
9381 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
9382 		scfdie();
9383 
9384 	(void) memset(&elts, 0, sizeof (elts));
9385 	(void) memset(&template_elts, 0, sizeof (template_elts));
9386 
9387 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9388 		uint32_t pgflags;
9389 
9390 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9391 			scfdie();
9392 
9393 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9394 			continue;
9395 
9396 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9397 			scfdie();
9398 
9399 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9400 			export_dependency(exp_pg, &elts);
9401 			continue;
9402 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9403 			export_method(exp_pg, &elts);
9404 			continue;
9405 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9406 			if (scf_pg_get_name(exp_pg, exp_str,
9407 			    max_scf_name_len + 1) < 0)
9408 				scfdie();
9409 
9410 			if (strcmp(exp_str, scf_pg_general) == 0) {
9411 				export_inst_general(exp_pg, n, &elts);
9412 				continue;
9413 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9414 			    0) {
9415 				export_method_context(exp_pg, &elts);
9416 				continue;
9417 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9418 				export_dependents(exp_pg, &elts);
9419 				continue;
9420 			}
9421 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9422 			export_template(exp_pg, &elts, &template_elts);
9423 			continue;
9424 		}
9425 
9426 		/* Ordinary pg. */
9427 		export_pg(exp_pg, &elts, flags);
9428 	}
9429 	if (ret == -1)
9430 		scfdie();
9431 
9432 	if (template_elts.common_name != NULL) {
9433 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9434 		(void) xmlAddChild(elts.template, template_elts.common_name);
9435 		(void) xmlAddChild(elts.template, template_elts.description);
9436 		(void) xmlAddChild(elts.template, template_elts.documentation);
9437 	} else {
9438 		xmlFreeNode(template_elts.description);
9439 		xmlFreeNode(template_elts.documentation);
9440 	}
9441 
9442 	if (isdefault && elts.restarter == NULL &&
9443 	    elts.dependencies == NULL && elts.method_context == NULL &&
9444 	    elts.exec_methods == NULL && elts.property_groups == NULL &&
9445 	    elts.template == NULL) {
9446 		xmlChar *eval;
9447 
9448 		/* This is a default instance */
9449 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
9450 
9451 		xmlFreeNode(n);
9452 
9453 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
9454 		if (n == NULL)
9455 			uu_die(emsg_create_xml);
9456 
9457 		safe_setprop(n, enabled_attr, (char *)eval);
9458 		xmlFree(eval);
9459 
9460 		selts->create_default_instance = n;
9461 	} else {
9462 		/* Assemble the children in order. */
9463 		(void) xmlAddChild(n, elts.restarter);
9464 		(void) xmlAddChildList(n, elts.dependencies);
9465 		(void) xmlAddChildList(n, elts.dependents);
9466 		(void) xmlAddChild(n, elts.method_context);
9467 		(void) xmlAddChildList(n, elts.exec_methods);
9468 		(void) xmlAddChildList(n, elts.property_groups);
9469 		(void) xmlAddChild(n, elts.template);
9470 
9471 		if (selts->instances == NULL)
9472 			selts->instances = n;
9473 		else
9474 			(void) xmlAddSibling(selts->instances, n);
9475 	}
9476 }
9477 
9478 /*
9479  * Return a service element for the given service.
9480  */
9481 static xmlNodePtr
9482 export_service(scf_service_t *svc, int flags)
9483 {
9484 	xmlNodePtr snode;
9485 	struct entity_elts elts;
9486 	struct template_elts template_elts;
9487 	int ret;
9488 
9489 	snode = xmlNewNode(NULL, (xmlChar *)"service");
9490 	if (snode == NULL)
9491 		uu_die(emsg_create_xml);
9492 
9493 	/* Get & set name attribute */
9494 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
9495 		scfdie();
9496 	safe_setprop(snode, name_attr, exp_str);
9497 
9498 	safe_setprop(snode, type_attr, "service");
9499 	safe_setprop(snode, "version", "0");
9500 
9501 	/* Acquire child elements. */
9502 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
9503 		scfdie();
9504 
9505 	(void) memset(&elts, 0, sizeof (elts));
9506 	(void) memset(&template_elts, 0, sizeof (template_elts));
9507 
9508 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9509 		uint32_t pgflags;
9510 
9511 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9512 			scfdie();
9513 
9514 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9515 			continue;
9516 
9517 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9518 			scfdie();
9519 
9520 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9521 			export_dependency(exp_pg, &elts);
9522 			continue;
9523 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9524 			export_method(exp_pg, &elts);
9525 			continue;
9526 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9527 			if (scf_pg_get_name(exp_pg, exp_str,
9528 			    max_scf_name_len + 1) < 0)
9529 				scfdie();
9530 
9531 			if (strcmp(exp_str, scf_pg_general) == 0) {
9532 				export_svc_general(exp_pg, &elts);
9533 				continue;
9534 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9535 			    0) {
9536 				export_method_context(exp_pg, &elts);
9537 				continue;
9538 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9539 				export_dependents(exp_pg, &elts);
9540 				continue;
9541 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
9542 				continue;
9543 			}
9544 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9545 			export_template(exp_pg, &elts, &template_elts);
9546 			continue;
9547 		}
9548 
9549 		export_pg(exp_pg, &elts, flags);
9550 	}
9551 	if (ret == -1)
9552 		scfdie();
9553 
9554 	if (template_elts.common_name != NULL) {
9555 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9556 		(void) xmlAddChild(elts.template, template_elts.common_name);
9557 		(void) xmlAddChild(elts.template, template_elts.description);
9558 		(void) xmlAddChild(elts.template, template_elts.documentation);
9559 	} else {
9560 		xmlFreeNode(template_elts.description);
9561 		xmlFreeNode(template_elts.documentation);
9562 	}
9563 
9564 	/* Iterate instances */
9565 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
9566 		scfdie();
9567 
9568 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
9569 		export_instance(exp_inst, &elts, flags);
9570 	if (ret == -1)
9571 		scfdie();
9572 
9573 	/* Now add all of the accumulated elements in order. */
9574 	(void) xmlAddChild(snode, elts.create_default_instance);
9575 	(void) xmlAddChild(snode, elts.single_instance);
9576 	(void) xmlAddChild(snode, elts.restarter);
9577 	(void) xmlAddChildList(snode, elts.dependencies);
9578 	(void) xmlAddChildList(snode, elts.dependents);
9579 	(void) xmlAddChild(snode, elts.method_context);
9580 	(void) xmlAddChildList(snode, elts.exec_methods);
9581 	(void) xmlAddChildList(snode, elts.property_groups);
9582 	(void) xmlAddChildList(snode, elts.instances);
9583 	(void) xmlAddChild(snode, elts.stability);
9584 	(void) xmlAddChild(snode, elts.template);
9585 
9586 	return (snode);
9587 }
9588 
9589 static int
9590 export_callback(void *data, scf_walkinfo_t *wip)
9591 {
9592 	FILE *f;
9593 	xmlDocPtr doc;
9594 	xmlNodePtr sb;
9595 	int result;
9596 	struct export_args *argsp = (struct export_args *)data;
9597 
9598 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
9599 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9600 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9601 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9602 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9603 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9604 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9605 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9606 		scfdie();
9607 
9608 	exp_str_sz = max_scf_len + 1;
9609 	exp_str = safe_malloc(exp_str_sz);
9610 
9611 	if (argsp->filename != NULL) {
9612 		errno = 0;
9613 		f = fopen(argsp->filename, "wb");
9614 		if (f == NULL) {
9615 			if (errno == 0)
9616 				uu_die(gettext("Could not open \"%s\": no free "
9617 				    "stdio streams.\n"), argsp->filename);
9618 			else
9619 				uu_die(gettext("Could not open \"%s\""),
9620 				    argsp->filename);
9621 		}
9622 	} else
9623 		f = stdout;
9624 
9625 	doc = xmlNewDoc((xmlChar *)"1.0");
9626 	if (doc == NULL)
9627 		uu_die(gettext("Could not create XML document.\n"));
9628 
9629 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9630 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9631 		uu_die(emsg_create_xml);
9632 
9633 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9634 	if (sb == NULL)
9635 		uu_die(emsg_create_xml);
9636 	safe_setprop(sb, type_attr, "manifest");
9637 	safe_setprop(sb, name_attr, "export");
9638 	(void) xmlAddSibling(doc->children, sb);
9639 
9640 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
9641 
9642 	result = write_service_bundle(doc, f);
9643 
9644 	free(exp_str);
9645 	scf_iter_destroy(exp_val_iter);
9646 	scf_iter_destroy(exp_prop_iter);
9647 	scf_iter_destroy(exp_pg_iter);
9648 	scf_iter_destroy(exp_inst_iter);
9649 	scf_value_destroy(exp_val);
9650 	scf_property_destroy(exp_prop);
9651 	scf_pg_destroy(exp_pg);
9652 	scf_instance_destroy(exp_inst);
9653 
9654 	xmlFreeDoc(doc);
9655 
9656 	if (f != stdout)
9657 		(void) fclose(f);
9658 
9659 	return (result);
9660 }
9661 
9662 /*
9663  * Get the service named by fmri, build an XML tree which represents it, and
9664  * dump it into filename (or stdout if filename is NULL).
9665  */
9666 int
9667 lscf_service_export(char *fmri, const char *filename, int flags)
9668 {
9669 	struct export_args args;
9670 	int ret, err;
9671 
9672 	lscf_prep_hndl();
9673 
9674 	bzero(&args, sizeof (args));
9675 	args.filename = filename;
9676 	args.flags = flags;
9677 
9678 	err = 0;
9679 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
9680 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
9681 	    &args, &err, semerr)) != 0) {
9682 		if (ret != -1)
9683 			semerr(gettext("Failed to walk instances: %s\n"),
9684 			    scf_strerror(ret));
9685 		return (-1);
9686 	}
9687 
9688 	/*
9689 	 * Error message has already been printed.
9690 	 */
9691 	if (err != 0)
9692 		return (-1);
9693 
9694 	return (0);
9695 }
9696 
9697 
9698 /*
9699  * Archive
9700  */
9701 
9702 static xmlNodePtr
9703 make_archive(int flags)
9704 {
9705 	xmlNodePtr sb;
9706 	scf_scope_t *scope;
9707 	scf_service_t *svc;
9708 	scf_iter_t *iter;
9709 	int r;
9710 
9711 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9712 	    (svc = scf_service_create(g_hndl)) == NULL ||
9713 	    (iter = scf_iter_create(g_hndl)) == NULL ||
9714 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
9715 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9716 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9717 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9718 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9719 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9720 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9721 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9722 		scfdie();
9723 
9724 	exp_str_sz = max_scf_len + 1;
9725 	exp_str = safe_malloc(exp_str_sz);
9726 
9727 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9728 	if (sb == NULL)
9729 		uu_die(emsg_create_xml);
9730 	safe_setprop(sb, type_attr, "archive");
9731 	safe_setprop(sb, name_attr, "none");
9732 
9733 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
9734 		scfdie();
9735 	if (scf_iter_scope_services(iter, scope) != 0)
9736 		scfdie();
9737 
9738 	for (;;) {
9739 		r = scf_iter_next_service(iter, svc);
9740 		if (r == 0)
9741 			break;
9742 		if (r != 1)
9743 			scfdie();
9744 
9745 		if (scf_service_get_name(svc, exp_str,
9746 		    max_scf_name_len + 1) < 0)
9747 			scfdie();
9748 
9749 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
9750 			continue;
9751 
9752 		(void) xmlAddChild(sb, export_service(svc, flags));
9753 	}
9754 
9755 	free(exp_str);
9756 
9757 	scf_iter_destroy(exp_val_iter);
9758 	scf_iter_destroy(exp_prop_iter);
9759 	scf_iter_destroy(exp_pg_iter);
9760 	scf_iter_destroy(exp_inst_iter);
9761 	scf_value_destroy(exp_val);
9762 	scf_property_destroy(exp_prop);
9763 	scf_pg_destroy(exp_pg);
9764 	scf_instance_destroy(exp_inst);
9765 	scf_iter_destroy(iter);
9766 	scf_service_destroy(svc);
9767 	scf_scope_destroy(scope);
9768 
9769 	return (sb);
9770 }
9771 
9772 int
9773 lscf_archive(const char *filename, int flags)
9774 {
9775 	FILE *f;
9776 	xmlDocPtr doc;
9777 	int result;
9778 
9779 	lscf_prep_hndl();
9780 
9781 	if (filename != NULL) {
9782 		errno = 0;
9783 		f = fopen(filename, "wb");
9784 		if (f == NULL) {
9785 			if (errno == 0)
9786 				uu_die(gettext("Could not open \"%s\": no free "
9787 				    "stdio streams.\n"), filename);
9788 			else
9789 				uu_die(gettext("Could not open \"%s\""),
9790 				    filename);
9791 		}
9792 	} else
9793 		f = stdout;
9794 
9795 	doc = xmlNewDoc((xmlChar *)"1.0");
9796 	if (doc == NULL)
9797 		uu_die(gettext("Could not create XML document.\n"));
9798 
9799 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9800 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9801 		uu_die(emsg_create_xml);
9802 
9803 	(void) xmlAddSibling(doc->children, make_archive(flags));
9804 
9805 	result = write_service_bundle(doc, f);
9806 
9807 	xmlFreeDoc(doc);
9808 
9809 	if (f != stdout)
9810 		(void) fclose(f);
9811 
9812 	return (result);
9813 }
9814 
9815 
9816 /*
9817  * "Extract" a profile.
9818  */
9819 int
9820 lscf_profile_extract(const char *filename)
9821 {
9822 	FILE *f;
9823 	xmlDocPtr doc;
9824 	xmlNodePtr sb, snode, inode;
9825 	scf_scope_t *scope;
9826 	scf_service_t *svc;
9827 	scf_instance_t *inst;
9828 	scf_propertygroup_t *pg;
9829 	scf_property_t *prop;
9830 	scf_value_t *val;
9831 	scf_iter_t *siter, *iiter;
9832 	int r, s;
9833 	char *namebuf;
9834 	uint8_t b;
9835 	int result;
9836 
9837 	lscf_prep_hndl();
9838 
9839 	if (filename != NULL) {
9840 		errno = 0;
9841 		f = fopen(filename, "wb");
9842 		if (f == NULL) {
9843 			if (errno == 0)
9844 				uu_die(gettext("Could not open \"%s\": no "
9845 				    "free stdio streams.\n"), filename);
9846 			else
9847 				uu_die(gettext("Could not open \"%s\""),
9848 				    filename);
9849 		}
9850 	} else
9851 		f = stdout;
9852 
9853 	doc = xmlNewDoc((xmlChar *)"1.0");
9854 	if (doc == NULL)
9855 		uu_die(gettext("Could not create XML document.\n"));
9856 
9857 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9858 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9859 		uu_die(emsg_create_xml);
9860 
9861 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9862 	if (sb == NULL)
9863 		uu_die(emsg_create_xml);
9864 	safe_setprop(sb, type_attr, "profile");
9865 	safe_setprop(sb, name_attr, "extract");
9866 	(void) xmlAddSibling(doc->children, sb);
9867 
9868 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9869 	    (svc = scf_service_create(g_hndl)) == NULL ||
9870 	    (inst = scf_instance_create(g_hndl)) == NULL ||
9871 	    (pg = scf_pg_create(g_hndl)) == NULL ||
9872 	    (prop = scf_property_create(g_hndl)) == NULL ||
9873 	    (val = scf_value_create(g_hndl)) == NULL ||
9874 	    (siter = scf_iter_create(g_hndl)) == NULL ||
9875 	    (iiter = scf_iter_create(g_hndl)) == NULL)
9876 		scfdie();
9877 
9878 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
9879 		scfdie();
9880 
9881 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
9882 		scfdie();
9883 
9884 	namebuf = safe_malloc(max_scf_name_len + 1);
9885 
9886 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
9887 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
9888 			scfdie();
9889 
9890 		snode = xmlNewNode(NULL, (xmlChar *)"service");
9891 		if (snode == NULL)
9892 			uu_die(emsg_create_xml);
9893 
9894 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
9895 		    0)
9896 			scfdie();
9897 
9898 		safe_setprop(snode, name_attr, namebuf);
9899 
9900 		safe_setprop(snode, type_attr, "service");
9901 		safe_setprop(snode, "version", "0");
9902 
9903 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
9904 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
9905 			    SCF_SUCCESS) {
9906 				if (scf_error() != SCF_ERROR_NOT_FOUND)
9907 					scfdie();
9908 
9909 				if (g_verbose) {
9910 					ssize_t len;
9911 					char *fmri;
9912 
9913 					len =
9914 					    scf_instance_to_fmri(inst, NULL, 0);
9915 					if (len < 0)
9916 						scfdie();
9917 
9918 					fmri = safe_malloc(len + 1);
9919 
9920 					if (scf_instance_to_fmri(inst, fmri,
9921 					    len + 1) < 0)
9922 						scfdie();
9923 
9924 					warn("Instance %s has no \"%s\" "
9925 					    "property group.\n", fmri,
9926 					    scf_pg_general);
9927 
9928 					free(fmri);
9929 				}
9930 
9931 				continue;
9932 			}
9933 
9934 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
9935 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
9936 			    prop_get_val(prop, val) != 0)
9937 				continue;
9938 
9939 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
9940 			    NULL);
9941 			if (inode == NULL)
9942 				uu_die(emsg_create_xml);
9943 
9944 			if (scf_instance_get_name(inst, namebuf,
9945 			    max_scf_name_len + 1) < 0)
9946 				scfdie();
9947 
9948 			safe_setprop(inode, name_attr, namebuf);
9949 
9950 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
9951 				scfdie();
9952 
9953 			safe_setprop(inode, enabled_attr, b ? true : false);
9954 		}
9955 		if (s < 0)
9956 			scfdie();
9957 
9958 		if (snode->children != NULL)
9959 			(void) xmlAddChild(sb, snode);
9960 		else
9961 			xmlFreeNode(snode);
9962 	}
9963 	if (r < 0)
9964 		scfdie();
9965 
9966 	free(namebuf);
9967 
9968 	result = write_service_bundle(doc, f);
9969 
9970 	xmlFreeDoc(doc);
9971 
9972 	if (f != stdout)
9973 		(void) fclose(f);
9974 
9975 	return (result);
9976 }
9977 
9978 
9979 /*
9980  * Entity manipulation commands
9981  */
9982 
9983 /*
9984  * Entity selection.  If no entity is selected, then the current scope is in
9985  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
9986  * only cur_inst is NULL, and when an instance is selected, none are NULL.
9987  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
9988  * cur_inst will be non-NULL.
9989  */
9990 
9991 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
9992 static int
9993 select_inst(const char *name)
9994 {
9995 	scf_instance_t *inst;
9996 	scf_error_t err;
9997 
9998 	assert(cur_svc != NULL);
9999 
10000 	inst = scf_instance_create(g_hndl);
10001 	if (inst == NULL)
10002 		scfdie();
10003 
10004 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10005 		cur_inst = inst;
10006 		return (0);
10007 	}
10008 
10009 	err = scf_error();
10010 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10011 		scfdie();
10012 
10013 	scf_instance_destroy(inst);
10014 	return (1);
10015 }
10016 
10017 /* Returns as above. */
10018 static int
10019 select_svc(const char *name)
10020 {
10021 	scf_service_t *svc;
10022 	scf_error_t err;
10023 
10024 	assert(cur_scope != NULL);
10025 
10026 	svc = scf_service_create(g_hndl);
10027 	if (svc == NULL)
10028 		scfdie();
10029 
10030 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10031 		cur_svc = svc;
10032 		return (0);
10033 	}
10034 
10035 	err = scf_error();
10036 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10037 		scfdie();
10038 
10039 	scf_service_destroy(svc);
10040 	return (1);
10041 }
10042 
10043 /* ARGSUSED */
10044 static int
10045 select_callback(void *unused, scf_walkinfo_t *wip)
10046 {
10047 	scf_instance_t *inst;
10048 	scf_service_t *svc;
10049 	scf_scope_t *scope;
10050 
10051 	if (wip->inst != NULL) {
10052 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10053 		    (svc = scf_service_create(g_hndl)) == NULL ||
10054 		    (inst = scf_instance_create(g_hndl)) == NULL)
10055 			scfdie();
10056 
10057 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10058 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10059 			scfdie();
10060 	} else {
10061 		assert(wip->svc != NULL);
10062 
10063 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10064 		    (svc = scf_service_create(g_hndl)) == NULL)
10065 			scfdie();
10066 
10067 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10068 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10069 			scfdie();
10070 
10071 		inst = NULL;
10072 	}
10073 
10074 	/* Clear out the current selection */
10075 	assert(cur_scope != NULL);
10076 	scf_scope_destroy(cur_scope);
10077 	scf_service_destroy(cur_svc);
10078 	scf_instance_destroy(cur_inst);
10079 
10080 	cur_scope = scope;
10081 	cur_svc = svc;
10082 	cur_inst = inst;
10083 
10084 	return (0);
10085 }
10086 
10087 static int
10088 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
10089 {
10090 	char **fmri = fmri_p;
10091 
10092 	*fmri = strdup(wip->fmri);
10093 	if (*fmri == NULL)
10094 		uu_die(gettext("Out of memory.\n"));
10095 
10096 	return (0);
10097 }
10098 
10099 /*
10100  * validate [fmri]
10101  * Perform the validation of an FMRI instance.
10102  */
10103 void
10104 lscf_validate_fmri(const char *fmri)
10105 {
10106 	int ret = 0;
10107 	size_t inst_sz;
10108 	char *inst_fmri = NULL;
10109 	scf_tmpl_errors_t *errs = NULL;
10110 	char *snapbuf = NULL;
10111 
10112 	lscf_prep_hndl();
10113 
10114 	if (fmri == NULL) {
10115 		inst_sz = max_scf_fmri_len + 1;
10116 		inst_fmri = safe_malloc(inst_sz);
10117 
10118 		if (cur_snap != NULL) {
10119 			snapbuf = safe_malloc(max_scf_name_len + 1);
10120 			if (scf_snapshot_get_name(cur_snap, snapbuf,
10121 			    max_scf_name_len + 1) < 0)
10122 				scfdie();
10123 		}
10124 		if (cur_inst == NULL) {
10125 			semerr(gettext("No instance selected\n"));
10126 			goto cleanup;
10127 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
10128 		    inst_sz) >= inst_sz) {
10129 			/* sanity check. Should never get here */
10130 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
10131 			    __FILE__, __LINE__);
10132 		}
10133 	} else {
10134 		scf_error_t scf_err;
10135 		int err = 0;
10136 
10137 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
10138 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
10139 			uu_warn("Failed to walk instances: %s\n",
10140 			    scf_strerror(scf_err));
10141 			goto cleanup;
10142 		}
10143 		if (err != 0) {
10144 			/* error message displayed by scf_walk_fmri */
10145 			goto cleanup;
10146 		}
10147 	}
10148 
10149 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
10150 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
10151 	if (ret == -1) {
10152 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
10153 			warn(gettext("Template data for %s is invalid. "
10154 			    "Consider reverting to a previous snapshot or "
10155 			    "restoring original configuration.\n"), inst_fmri);
10156 		} else {
10157 			uu_warn("%s: %s\n",
10158 			    gettext("Error validating the instance"),
10159 			    scf_strerror(scf_error()));
10160 		}
10161 	} else if (ret == 1 && errs != NULL) {
10162 		scf_tmpl_error_t *err = NULL;
10163 		char *msg;
10164 		size_t len = 256;	/* initial error buffer size */
10165 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
10166 		    SCF_TMPL_STRERROR_HUMAN : 0;
10167 
10168 		msg = safe_malloc(len);
10169 
10170 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
10171 			int ret;
10172 
10173 			if ((ret = scf_tmpl_strerror(err, msg, len,
10174 			    flag)) >= len) {
10175 				len = ret + 1;
10176 				msg = realloc(msg, len);
10177 				if (msg == NULL)
10178 					uu_die(gettext(
10179 					    "Out of memory.\n"));
10180 				(void) scf_tmpl_strerror(err, msg, len,
10181 				    flag);
10182 			}
10183 			(void) fprintf(stderr, "%s\n", msg);
10184 		}
10185 		if (msg != NULL)
10186 			free(msg);
10187 	}
10188 	if (errs != NULL)
10189 		scf_tmpl_errors_destroy(errs);
10190 
10191 cleanup:
10192 	free(inst_fmri);
10193 	free(snapbuf);
10194 }
10195 
10196 static void
10197 lscf_validate_file(const char *filename)
10198 {
10199 	tmpl_errors_t *errs;
10200 
10201 	bundle_t *b = internal_bundle_new();
10202 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
10203 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
10204 			tmpl_errors_print(stderr, errs, "");
10205 			semerr(gettext("Validation failed.\n"));
10206 		}
10207 		tmpl_errors_destroy(errs);
10208 	}
10209 	(void) internal_bundle_free(b);
10210 }
10211 
10212 /*
10213  * validate [fmri|file]
10214  */
10215 void
10216 lscf_validate(const char *arg)
10217 {
10218 	const char *str;
10219 
10220 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
10221 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
10222 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
10223 		lscf_validate_file(str);
10224 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
10225 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
10226 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
10227 		lscf_validate_fmri(str);
10228 	} else if (access(arg, R_OK | F_OK) == 0) {
10229 		lscf_validate_file(arg);
10230 	} else {
10231 		lscf_validate_fmri(arg);
10232 	}
10233 }
10234 
10235 void
10236 lscf_select(const char *fmri)
10237 {
10238 	int ret, err;
10239 
10240 	lscf_prep_hndl();
10241 
10242 	if (cur_snap != NULL) {
10243 		struct snaplevel *elt;
10244 		char *buf;
10245 
10246 		/* Error unless name is that of the next level. */
10247 		elt = uu_list_next(cur_levels, cur_elt);
10248 		if (elt == NULL) {
10249 			semerr(gettext("No children.\n"));
10250 			return;
10251 		}
10252 
10253 		buf = safe_malloc(max_scf_name_len + 1);
10254 
10255 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10256 		    max_scf_name_len + 1) < 0)
10257 			scfdie();
10258 
10259 		if (strcmp(buf, fmri) != 0) {
10260 			semerr(gettext("No such child.\n"));
10261 			free(buf);
10262 			return;
10263 		}
10264 
10265 		free(buf);
10266 
10267 		cur_elt = elt;
10268 		cur_level = elt->sl;
10269 		return;
10270 	}
10271 
10272 	/*
10273 	 * Special case for 'svc:', which takes the user to the scope level.
10274 	 */
10275 	if (strcmp(fmri, "svc:") == 0) {
10276 		scf_instance_destroy(cur_inst);
10277 		scf_service_destroy(cur_svc);
10278 		cur_inst = NULL;
10279 		cur_svc = NULL;
10280 		return;
10281 	}
10282 
10283 	/*
10284 	 * Special case for ':properties'.  This appears as part of 'list' but
10285 	 * can't be selected.  Give a more helpful error message in this case.
10286 	 */
10287 	if (strcmp(fmri, ":properties") == 0) {
10288 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
10289 		    "to list properties.\n"));
10290 		return;
10291 	}
10292 
10293 	/*
10294 	 * First try the argument as relative to the current selection.
10295 	 */
10296 	if (cur_inst != NULL) {
10297 		/* EMPTY */;
10298 	} else if (cur_svc != NULL) {
10299 		if (select_inst(fmri) != 1)
10300 			return;
10301 	} else {
10302 		if (select_svc(fmri) != 1)
10303 			return;
10304 	}
10305 
10306 	err = 0;
10307 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
10308 	    select_callback, NULL, &err, semerr)) != 0) {
10309 		semerr(gettext("Failed to walk instances: %s\n"),
10310 		    scf_strerror(ret));
10311 	}
10312 }
10313 
10314 void
10315 lscf_unselect(void)
10316 {
10317 	lscf_prep_hndl();
10318 
10319 	if (cur_snap != NULL) {
10320 		struct snaplevel *elt;
10321 
10322 		elt = uu_list_prev(cur_levels, cur_elt);
10323 		if (elt == NULL) {
10324 			semerr(gettext("No parent levels.\n"));
10325 		} else {
10326 			cur_elt = elt;
10327 			cur_level = elt->sl;
10328 		}
10329 	} else if (cur_inst != NULL) {
10330 		scf_instance_destroy(cur_inst);
10331 		cur_inst = NULL;
10332 	} else if (cur_svc != NULL) {
10333 		scf_service_destroy(cur_svc);
10334 		cur_svc = NULL;
10335 	} else {
10336 		semerr(gettext("Cannot unselect at scope level.\n"));
10337 	}
10338 }
10339 
10340 /*
10341  * Return the FMRI of the current selection, for the prompt.
10342  */
10343 void
10344 lscf_get_selection_str(char *buf, size_t bufsz)
10345 {
10346 	char *cp;
10347 	ssize_t fmrilen, szret;
10348 	boolean_t deleted = B_FALSE;
10349 
10350 	if (g_hndl == NULL) {
10351 		(void) strlcpy(buf, "svc:", bufsz);
10352 		return;
10353 	}
10354 
10355 	if (cur_level != NULL) {
10356 		assert(cur_snap != NULL);
10357 
10358 		/* [ snapshot ] FMRI [: instance ] */
10359 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
10360 		    + 2 + max_scf_name_len + 1 + 1);
10361 
10362 		buf[0] = '[';
10363 
10364 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
10365 		    max_scf_name_len + 1);
10366 		if (szret < 0) {
10367 			if (scf_error() != SCF_ERROR_DELETED)
10368 				scfdie();
10369 
10370 			goto snap_deleted;
10371 		}
10372 
10373 		(void) strcat(buf, "]svc:/");
10374 
10375 		cp = strchr(buf, '\0');
10376 
10377 		szret = scf_snaplevel_get_service_name(cur_level, cp,
10378 		    max_scf_name_len + 1);
10379 		if (szret < 0) {
10380 			if (scf_error() != SCF_ERROR_DELETED)
10381 				scfdie();
10382 
10383 			goto snap_deleted;
10384 		}
10385 
10386 		cp = strchr(cp, '\0');
10387 
10388 		if (snaplevel_is_instance(cur_level)) {
10389 			*cp++ = ':';
10390 
10391 			if (scf_snaplevel_get_instance_name(cur_level, cp,
10392 			    max_scf_name_len + 1) < 0) {
10393 				if (scf_error() != SCF_ERROR_DELETED)
10394 					scfdie();
10395 
10396 				goto snap_deleted;
10397 			}
10398 		} else {
10399 			*cp++ = '[';
10400 			*cp++ = ':';
10401 
10402 			if (scf_instance_get_name(cur_inst, cp,
10403 			    max_scf_name_len + 1) < 0) {
10404 				if (scf_error() != SCF_ERROR_DELETED)
10405 					scfdie();
10406 
10407 				goto snap_deleted;
10408 			}
10409 
10410 			(void) strcat(buf, "]");
10411 		}
10412 
10413 		return;
10414 
10415 snap_deleted:
10416 		deleted = B_TRUE;
10417 		free(buf);
10418 		unselect_cursnap();
10419 	}
10420 
10421 	assert(cur_snap == NULL);
10422 
10423 	if (cur_inst != NULL) {
10424 		assert(cur_svc != NULL);
10425 		assert(cur_scope != NULL);
10426 
10427 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
10428 		if (fmrilen >= 0) {
10429 			assert(fmrilen < bufsz);
10430 			if (deleted)
10431 				warn(emsg_deleted);
10432 			return;
10433 		}
10434 
10435 		if (scf_error() != SCF_ERROR_DELETED)
10436 			scfdie();
10437 
10438 		deleted = B_TRUE;
10439 
10440 		scf_instance_destroy(cur_inst);
10441 		cur_inst = NULL;
10442 	}
10443 
10444 	if (cur_svc != NULL) {
10445 		assert(cur_scope != NULL);
10446 
10447 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
10448 		if (szret >= 0) {
10449 			assert(szret < bufsz);
10450 			if (deleted)
10451 				warn(emsg_deleted);
10452 			return;
10453 		}
10454 
10455 		if (scf_error() != SCF_ERROR_DELETED)
10456 			scfdie();
10457 
10458 		deleted = B_TRUE;
10459 		scf_service_destroy(cur_svc);
10460 		cur_svc = NULL;
10461 	}
10462 
10463 	assert(cur_scope != NULL);
10464 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
10465 
10466 	if (fmrilen < 0)
10467 		scfdie();
10468 
10469 	assert(fmrilen < bufsz);
10470 	if (deleted)
10471 		warn(emsg_deleted);
10472 }
10473 
10474 /*
10475  * Entity listing.  Entities and colon namespaces (e.g., :properties and
10476  * :statistics) are listed for the current selection.
10477  */
10478 void
10479 lscf_list(const char *pattern)
10480 {
10481 	scf_iter_t *iter;
10482 	char *buf;
10483 	int ret;
10484 
10485 	lscf_prep_hndl();
10486 
10487 	if (cur_level != NULL) {
10488 		struct snaplevel *elt;
10489 
10490 		(void) fputs(COLON_NAMESPACES, stdout);
10491 
10492 		elt = uu_list_next(cur_levels, cur_elt);
10493 		if (elt == NULL)
10494 			return;
10495 
10496 		/*
10497 		 * For now, we know that the next level is an instance.  But
10498 		 * if we ever have multiple scopes, this could be complicated.
10499 		 */
10500 		buf = safe_malloc(max_scf_name_len + 1);
10501 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10502 		    max_scf_name_len + 1) >= 0) {
10503 			(void) puts(buf);
10504 		} else {
10505 			if (scf_error() != SCF_ERROR_DELETED)
10506 				scfdie();
10507 		}
10508 
10509 		free(buf);
10510 
10511 		return;
10512 	}
10513 
10514 	if (cur_inst != NULL) {
10515 		(void) fputs(COLON_NAMESPACES, stdout);
10516 		return;
10517 	}
10518 
10519 	iter = scf_iter_create(g_hndl);
10520 	if (iter == NULL)
10521 		scfdie();
10522 
10523 	buf = safe_malloc(max_scf_name_len + 1);
10524 
10525 	if (cur_svc != NULL) {
10526 		/* List the instances in this service. */
10527 		scf_instance_t *inst;
10528 
10529 		inst = scf_instance_create(g_hndl);
10530 		if (inst == NULL)
10531 			scfdie();
10532 
10533 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
10534 			safe_printf(COLON_NAMESPACES);
10535 
10536 			for (;;) {
10537 				ret = scf_iter_next_instance(iter, inst);
10538 				if (ret == 0)
10539 					break;
10540 				if (ret != 1) {
10541 					if (scf_error() != SCF_ERROR_DELETED)
10542 						scfdie();
10543 
10544 					break;
10545 				}
10546 
10547 				if (scf_instance_get_name(inst, buf,
10548 				    max_scf_name_len + 1) >= 0) {
10549 					if (pattern == NULL ||
10550 					    fnmatch(pattern, buf, 0) == 0)
10551 						(void) puts(buf);
10552 				} else {
10553 					if (scf_error() != SCF_ERROR_DELETED)
10554 						scfdie();
10555 				}
10556 			}
10557 		} else {
10558 			if (scf_error() != SCF_ERROR_DELETED)
10559 				scfdie();
10560 		}
10561 
10562 		scf_instance_destroy(inst);
10563 	} else {
10564 		/* List the services in this scope. */
10565 		scf_service_t *svc;
10566 
10567 		assert(cur_scope != NULL);
10568 
10569 		svc = scf_service_create(g_hndl);
10570 		if (svc == NULL)
10571 			scfdie();
10572 
10573 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
10574 			scfdie();
10575 
10576 		for (;;) {
10577 			ret = scf_iter_next_service(iter, svc);
10578 			if (ret == 0)
10579 				break;
10580 			if (ret != 1)
10581 				scfdie();
10582 
10583 			if (scf_service_get_name(svc, buf,
10584 			    max_scf_name_len + 1) >= 0) {
10585 				if (pattern == NULL ||
10586 				    fnmatch(pattern, buf, 0) == 0)
10587 					safe_printf("%s\n", buf);
10588 			} else {
10589 				if (scf_error() != SCF_ERROR_DELETED)
10590 					scfdie();
10591 			}
10592 		}
10593 
10594 		scf_service_destroy(svc);
10595 	}
10596 
10597 	free(buf);
10598 	scf_iter_destroy(iter);
10599 }
10600 
10601 /*
10602  * Entity addition.  Creates an empty entity in the current selection.
10603  */
10604 void
10605 lscf_add(const char *name)
10606 {
10607 	lscf_prep_hndl();
10608 
10609 	if (cur_snap != NULL) {
10610 		semerr(emsg_cant_modify_snapshots);
10611 	} else if (cur_inst != NULL) {
10612 		semerr(gettext("Cannot add entities to an instance.\n"));
10613 	} else if (cur_svc != NULL) {
10614 
10615 		if (scf_service_add_instance(cur_svc, name, NULL) !=
10616 		    SCF_SUCCESS) {
10617 			switch (scf_error()) {
10618 			case SCF_ERROR_INVALID_ARGUMENT:
10619 				semerr(gettext("Invalid name.\n"));
10620 				break;
10621 
10622 			case SCF_ERROR_EXISTS:
10623 				semerr(gettext("Instance already exists.\n"));
10624 				break;
10625 
10626 			case SCF_ERROR_PERMISSION_DENIED:
10627 				semerr(emsg_permission_denied);
10628 				break;
10629 
10630 			default:
10631 				scfdie();
10632 			}
10633 		}
10634 	} else {
10635 		assert(cur_scope != NULL);
10636 
10637 		if (scf_scope_add_service(cur_scope, name, NULL) !=
10638 		    SCF_SUCCESS) {
10639 			switch (scf_error()) {
10640 			case SCF_ERROR_INVALID_ARGUMENT:
10641 				semerr(gettext("Invalid name.\n"));
10642 				break;
10643 
10644 			case SCF_ERROR_EXISTS:
10645 				semerr(gettext("Service already exists.\n"));
10646 				break;
10647 
10648 			case SCF_ERROR_PERMISSION_DENIED:
10649 				semerr(emsg_permission_denied);
10650 				break;
10651 
10652 			case SCF_ERROR_BACKEND_READONLY:
10653 				semerr(emsg_read_only);
10654 				break;
10655 
10656 			default:
10657 				scfdie();
10658 			}
10659 		}
10660 	}
10661 }
10662 
10663 /* return 1 if the entity has no persistent pgs, else return 0 */
10664 static int
10665 entity_has_no_pgs(void *ent, int isservice)
10666 {
10667 	scf_iter_t *iter = NULL;
10668 	scf_propertygroup_t *pg = NULL;
10669 	uint32_t flags;
10670 	int err;
10671 	int ret = 1;
10672 
10673 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10674 	    (pg = scf_pg_create(g_hndl)) == NULL)
10675 		scfdie();
10676 
10677 	if (isservice) {
10678 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
10679 			scfdie();
10680 	} else {
10681 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
10682 			scfdie();
10683 	}
10684 
10685 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10686 		if (scf_pg_get_flags(pg, &flags) != 0)
10687 			scfdie();
10688 
10689 		/* skip nonpersistent pgs */
10690 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
10691 			continue;
10692 
10693 		ret = 0;
10694 		break;
10695 	}
10696 
10697 	if (err == -1)
10698 		scfdie();
10699 
10700 	scf_pg_destroy(pg);
10701 	scf_iter_destroy(iter);
10702 
10703 	return (ret);
10704 }
10705 
10706 /* return 1 if the service has no instances, else return 0 */
10707 static int
10708 svc_has_no_insts(scf_service_t *svc)
10709 {
10710 	scf_instance_t *inst;
10711 	scf_iter_t *iter;
10712 	int r;
10713 	int ret = 1;
10714 
10715 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10716 	    (iter = scf_iter_create(g_hndl)) == NULL)
10717 		scfdie();
10718 
10719 	if (scf_iter_service_instances(iter, svc) != 0)
10720 		scfdie();
10721 
10722 	r = scf_iter_next_instance(iter, inst);
10723 	if (r == 1) {
10724 		ret = 0;
10725 	} else if (r == 0) {
10726 		ret = 1;
10727 	} else if (r == -1) {
10728 		scfdie();
10729 	} else {
10730 		bad_error("scf_iter_next_instance", r);
10731 	}
10732 
10733 	scf_iter_destroy(iter);
10734 	scf_instance_destroy(inst);
10735 
10736 	return (ret);
10737 }
10738 
10739 /*
10740  * Entity deletion.
10741  */
10742 
10743 /*
10744  * Delete the property group <fmri>/:properties/<name>.  Returns
10745  * SCF_ERROR_NONE on success (or if the entity is not found),
10746  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
10747  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
10748  * denied.
10749  */
10750 static scf_error_t
10751 delete_dependency_pg(const char *fmri, const char *name)
10752 {
10753 	void *entity = NULL;
10754 	int isservice;
10755 	scf_propertygroup_t *pg = NULL;
10756 	scf_error_t result;
10757 	char *pgty;
10758 	scf_service_t *svc = NULL;
10759 	scf_instance_t *inst = NULL;
10760 	scf_iter_t *iter = NULL;
10761 	char *name_buf = NULL;
10762 
10763 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10764 	switch (result) {
10765 	case SCF_ERROR_NONE:
10766 		break;
10767 
10768 	case SCF_ERROR_NO_MEMORY:
10769 		uu_die(gettext("Out of memory.\n"));
10770 		/* NOTREACHED */
10771 
10772 	case SCF_ERROR_INVALID_ARGUMENT:
10773 	case SCF_ERROR_CONSTRAINT_VIOLATED:
10774 		return (SCF_ERROR_INVALID_ARGUMENT);
10775 
10776 	case SCF_ERROR_NOT_FOUND:
10777 		result = SCF_ERROR_NONE;
10778 		goto out;
10779 
10780 	default:
10781 		bad_error("fmri_to_entity", result);
10782 	}
10783 
10784 	pg = scf_pg_create(g_hndl);
10785 	if (pg == NULL)
10786 		scfdie();
10787 
10788 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
10789 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10790 			scfdie();
10791 
10792 		result = SCF_ERROR_NONE;
10793 		goto out;
10794 	}
10795 
10796 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10797 
10798 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10799 		scfdie();
10800 
10801 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
10802 		result = SCF_ERROR_TYPE_MISMATCH;
10803 		free(pgty);
10804 		goto out;
10805 	}
10806 
10807 	free(pgty);
10808 
10809 	if (scf_pg_delete(pg) != 0) {
10810 		result = scf_error();
10811 		if (result != SCF_ERROR_PERMISSION_DENIED)
10812 			scfdie();
10813 		goto out;
10814 	}
10815 
10816 	/*
10817 	 * We have to handle the case where we've just deleted the last
10818 	 * property group of a "dummy" entity (instance or service).
10819 	 * A "dummy" entity is an entity only present to hold an
10820 	 * external dependency.
10821 	 * So, in the case we deleted the last property group then we
10822 	 * can also delete the entity. If the entity is an instance then
10823 	 * we must verify if this was the last instance for the service
10824 	 * and if it is, we can also delete the service if it doesn't
10825 	 * have any property group either.
10826 	 */
10827 
10828 	result = SCF_ERROR_NONE;
10829 
10830 	if (isservice) {
10831 		svc = (scf_service_t *)entity;
10832 
10833 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
10834 		    (iter = scf_iter_create(g_hndl)) == NULL)
10835 			scfdie();
10836 
10837 		name_buf = safe_malloc(max_scf_name_len + 1);
10838 	} else {
10839 		inst = (scf_instance_t *)entity;
10840 	}
10841 
10842 	/*
10843 	 * If the entity is an instance and we've just deleted its last
10844 	 * property group then we should delete it.
10845 	 */
10846 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
10847 		/* find the service before deleting the inst. - needed later */
10848 		if ((svc = scf_service_create(g_hndl)) == NULL)
10849 			scfdie();
10850 
10851 		if (scf_instance_get_parent(inst, svc) != 0)
10852 			scfdie();
10853 
10854 		/* delete the instance */
10855 		if (scf_instance_delete(inst) != 0) {
10856 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10857 				scfdie();
10858 
10859 			result = SCF_ERROR_PERMISSION_DENIED;
10860 			goto out;
10861 		}
10862 		/* no need to refresh the instance */
10863 		inst = NULL;
10864 	}
10865 
10866 	/*
10867 	 * If the service has no more instances and pgs or we just deleted the
10868 	 * last instance and the service doesn't have anymore propery groups
10869 	 * then the service should be deleted.
10870 	 */
10871 	if (svc != NULL &&
10872 	    svc_has_no_insts(svc) &&
10873 	    entity_has_no_pgs((void *)svc, 1)) {
10874 		if (scf_service_delete(svc) == 0) {
10875 			if (isservice) {
10876 				/* no need to refresh the service */
10877 				svc = NULL;
10878 			}
10879 
10880 			goto out;
10881 		}
10882 
10883 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10884 			scfdie();
10885 
10886 		result = SCF_ERROR_PERMISSION_DENIED;
10887 	}
10888 
10889 	/* if the entity has not been deleted, refresh it */
10890 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
10891 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
10892 		    name_buf);
10893 	}
10894 
10895 out:
10896 	if (isservice && (inst != NULL && iter != NULL)) {
10897 		free(name_buf);
10898 		scf_iter_destroy(iter);
10899 		scf_instance_destroy(inst);
10900 	}
10901 
10902 	if (!isservice && svc != NULL) {
10903 		scf_service_destroy(svc);
10904 	}
10905 
10906 	scf_pg_destroy(pg);
10907 	if (entity != NULL)
10908 		entity_destroy(entity, isservice);
10909 
10910 	return (result);
10911 }
10912 
10913 static int
10914 delete_dependents(scf_propertygroup_t *pg)
10915 {
10916 	char *pgty, *name, *fmri;
10917 	scf_property_t *prop;
10918 	scf_value_t *val;
10919 	scf_iter_t *iter;
10920 	int r;
10921 	scf_error_t err;
10922 
10923 	/* Verify that the pg has the correct type. */
10924 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10925 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10926 		scfdie();
10927 
10928 	if (strcmp(pgty, scf_group_framework) != 0) {
10929 		if (g_verbose) {
10930 			fmri = safe_malloc(max_scf_fmri_len + 1);
10931 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
10932 				scfdie();
10933 
10934 			warn(gettext("Property group %s is not of expected "
10935 			    "type %s.\n"), fmri, scf_group_framework);
10936 
10937 			free(fmri);
10938 		}
10939 
10940 		free(pgty);
10941 		return (-1);
10942 	}
10943 
10944 	free(pgty);
10945 
10946 	/* map delete_dependency_pg onto the properties. */
10947 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10948 	    (val = scf_value_create(g_hndl)) == NULL ||
10949 	    (iter = scf_iter_create(g_hndl)) == NULL)
10950 		scfdie();
10951 
10952 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10953 		scfdie();
10954 
10955 	name = safe_malloc(max_scf_name_len + 1);
10956 	fmri = safe_malloc(max_scf_fmri_len + 2);
10957 
10958 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
10959 		scf_type_t ty;
10960 
10961 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
10962 			scfdie();
10963 
10964 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
10965 			scfdie();
10966 
10967 		if ((ty != SCF_TYPE_ASTRING &&
10968 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
10969 		    prop_get_val(prop, val) != 0)
10970 			continue;
10971 
10972 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
10973 			scfdie();
10974 
10975 		err = delete_dependency_pg(fmri, name);
10976 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
10977 			if (scf_property_to_fmri(prop, fmri,
10978 			    max_scf_fmri_len + 2) < 0)
10979 				scfdie();
10980 
10981 			warn(gettext("Value of %s is not a valid FMRI.\n"),
10982 			    fmri);
10983 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
10984 			warn(gettext("Property group \"%s\" of entity \"%s\" "
10985 			    "does not have dependency type.\n"), name, fmri);
10986 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
10987 			warn(gettext("Could not delete property group \"%s\" "
10988 			    "of entity \"%s\" (permission denied).\n"), name,
10989 			    fmri);
10990 		}
10991 	}
10992 	if (r == -1)
10993 		scfdie();
10994 
10995 	scf_value_destroy(val);
10996 	scf_property_destroy(prop);
10997 
10998 	return (0);
10999 }
11000 
11001 /*
11002  * Returns 1 if the instance may be running, and 0 otherwise.
11003  */
11004 static int
11005 inst_is_running(scf_instance_t *inst)
11006 {
11007 	scf_propertygroup_t *pg;
11008 	scf_property_t *prop;
11009 	scf_value_t *val;
11010 	char buf[MAX_SCF_STATE_STRING_SZ];
11011 	int ret = 0;
11012 	ssize_t szret;
11013 
11014 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11015 	    (prop = scf_property_create(g_hndl)) == NULL ||
11016 	    (val = scf_value_create(g_hndl)) == NULL)
11017 		scfdie();
11018 
11019 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
11020 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11021 			scfdie();
11022 		goto out;
11023 	}
11024 
11025 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
11026 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
11027 	    prop_get_val(prop, val) != 0)
11028 		goto out;
11029 
11030 	szret = scf_value_get_astring(val, buf, sizeof (buf));
11031 	assert(szret >= 0);
11032 
11033 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11034 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11035 
11036 out:
11037 	scf_value_destroy(val);
11038 	scf_property_destroy(prop);
11039 	scf_pg_destroy(pg);
11040 	return (ret);
11041 }
11042 
11043 static uint8_t
11044 pg_is_external_dependency(scf_propertygroup_t *pg)
11045 {
11046 	char *type;
11047 	scf_value_t *val;
11048 	scf_property_t *prop;
11049 	uint8_t b = B_FALSE;
11050 
11051 	type = safe_malloc(max_scf_pg_type_len + 1);
11052 
11053 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
11054 		scfdie();
11055 
11056 	if ((prop = scf_property_create(g_hndl)) == NULL ||
11057 	    (val = scf_value_create(g_hndl)) == NULL)
11058 		scfdie();
11059 
11060 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
11061 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
11062 			if (scf_property_get_value(prop, val) != 0)
11063 				scfdie();
11064 			if (scf_value_get_boolean(val, &b) != 0)
11065 				scfdie();
11066 		}
11067 	}
11068 
11069 	free(type);
11070 	(void) scf_value_destroy(val);
11071 	(void) scf_property_destroy(prop);
11072 
11073 	return (b);
11074 }
11075 
11076 #define	DELETE_FAILURE			-1
11077 #define	DELETE_SUCCESS_NOEXTDEPS	0
11078 #define	DELETE_SUCCESS_EXTDEPS		1
11079 
11080 /*
11081  * lscf_instance_delete() deletes an instance.  Before calling
11082  * scf_instance_delete(), though, we make sure the instance isn't
11083  * running and delete dependencies in other entities which the instance
11084  * declared as "dependents".  If there are dependencies which were
11085  * created for other entities, then instead of deleting the instance we
11086  * make it "empty" by deleting all other property groups and all
11087  * snapshots.
11088  *
11089  * lscf_instance_delete() verifies that there is no external dependency pgs
11090  * before suppressing the instance. If there is, then we must not remove them
11091  * now in case the instance is re-created otherwise the dependencies would be
11092  * lost. The external dependency pgs will be removed if the dependencies are
11093  * removed.
11094  *
11095  * Returns:
11096  *  DELETE_FAILURE		on failure
11097  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11098  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11099  */
11100 static int
11101 lscf_instance_delete(scf_instance_t *inst, int force)
11102 {
11103 	scf_propertygroup_t *pg;
11104 	scf_snapshot_t *snap;
11105 	scf_iter_t *iter;
11106 	int err;
11107 	int external = 0;
11108 
11109 	/* If we're not forcing and the instance is running, refuse. */
11110 	if (!force && inst_is_running(inst)) {
11111 		char *fmri;
11112 
11113 		fmri = safe_malloc(max_scf_fmri_len + 1);
11114 
11115 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
11116 			scfdie();
11117 
11118 		semerr(gettext("Instance %s may be running.  "
11119 		    "Use delete -f if it is not.\n"), fmri);
11120 
11121 		free(fmri);
11122 		return (DELETE_FAILURE);
11123 	}
11124 
11125 	pg = scf_pg_create(g_hndl);
11126 	if (pg == NULL)
11127 		scfdie();
11128 
11129 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
11130 		(void) delete_dependents(pg);
11131 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11132 		scfdie();
11133 
11134 	scf_pg_destroy(pg);
11135 
11136 	/*
11137 	 * If the instance has some external dependencies then we must
11138 	 * keep them in case the instance is reimported otherwise the
11139 	 * dependencies would be lost on reimport.
11140 	 */
11141 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11142 	    (pg = scf_pg_create(g_hndl)) == NULL)
11143 		scfdie();
11144 
11145 	if (scf_iter_instance_pgs(iter, inst) < 0)
11146 		scfdie();
11147 
11148 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11149 		if (pg_is_external_dependency(pg)) {
11150 			external = 1;
11151 			continue;
11152 		}
11153 
11154 		if (scf_pg_delete(pg) != 0) {
11155 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11156 				scfdie();
11157 			else {
11158 				semerr(emsg_permission_denied);
11159 
11160 				(void) scf_iter_destroy(iter);
11161 				(void) scf_pg_destroy(pg);
11162 				return (DELETE_FAILURE);
11163 			}
11164 		}
11165 	}
11166 
11167 	if (err == -1)
11168 		scfdie();
11169 
11170 	(void) scf_iter_destroy(iter);
11171 	(void) scf_pg_destroy(pg);
11172 
11173 	if (external) {
11174 		/*
11175 		 * All the pgs have been deleted for the instance except
11176 		 * the ones holding the external dependencies.
11177 		 * For the job to be complete, we must also delete the
11178 		 * snapshots associated with the instance.
11179 		 */
11180 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
11181 		    NULL)
11182 			scfdie();
11183 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
11184 			scfdie();
11185 
11186 		if (scf_iter_instance_snapshots(iter, inst) == -1)
11187 			scfdie();
11188 
11189 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
11190 			if (_scf_snapshot_delete(snap) != 0) {
11191 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11192 					scfdie();
11193 
11194 				semerr(emsg_permission_denied);
11195 
11196 				(void) scf_iter_destroy(iter);
11197 				(void) scf_snapshot_destroy(snap);
11198 				return (DELETE_FAILURE);
11199 			}
11200 		}
11201 
11202 		if (err == -1)
11203 			scfdie();
11204 
11205 		(void) scf_iter_destroy(iter);
11206 		(void) scf_snapshot_destroy(snap);
11207 		return (DELETE_SUCCESS_EXTDEPS);
11208 	}
11209 
11210 	if (scf_instance_delete(inst) != 0) {
11211 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11212 			scfdie();
11213 
11214 		semerr(emsg_permission_denied);
11215 
11216 		return (DELETE_FAILURE);
11217 	}
11218 
11219 	return (DELETE_SUCCESS_NOEXTDEPS);
11220 }
11221 
11222 /*
11223  * lscf_service_delete() deletes a service.  Before calling
11224  * scf_service_delete(), though, we call lscf_instance_delete() for
11225  * each of the instances and delete dependencies in other entities
11226  * which were created as "dependents" of this service.  If there are
11227  * dependencies which were created for other entities, then we delete
11228  * all other property groups in the service and leave it as "empty".
11229  *
11230  * lscf_service_delete() verifies that there is no external dependency
11231  * pgs at the instance & service level before suppressing the service.
11232  * If there is, then we must not remove them now in case the service
11233  * is re-imported otherwise the dependencies would be lost. The external
11234  * dependency pgs will be removed if the dependencies are removed.
11235  *
11236  * Returns:
11237  *   DELETE_FAILURE		on failure
11238  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11239  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11240  */
11241 static int
11242 lscf_service_delete(scf_service_t *svc, int force)
11243 {
11244 	int r;
11245 	scf_instance_t *inst;
11246 	scf_propertygroup_t *pg;
11247 	scf_iter_t *iter;
11248 	int ret;
11249 	int external = 0;
11250 
11251 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11252 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11253 	    (iter = scf_iter_create(g_hndl)) == NULL)
11254 		scfdie();
11255 
11256 	if (scf_iter_service_instances(iter, svc) != 0)
11257 		scfdie();
11258 
11259 	for (r = scf_iter_next_instance(iter, inst);
11260 	    r == 1;
11261 	    r = scf_iter_next_instance(iter, inst)) {
11262 
11263 		ret = lscf_instance_delete(inst, force);
11264 		if (ret == DELETE_FAILURE) {
11265 			scf_iter_destroy(iter);
11266 			scf_pg_destroy(pg);
11267 			scf_instance_destroy(inst);
11268 			return (DELETE_FAILURE);
11269 		}
11270 
11271 		/*
11272 		 * Record the fact that there is some external dependencies
11273 		 * at the instance level.
11274 		 */
11275 		if (ret == DELETE_SUCCESS_EXTDEPS)
11276 			external |= 1;
11277 	}
11278 
11279 	if (r != 0)
11280 		scfdie();
11281 
11282 	/* Delete dependency property groups in dependent services. */
11283 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
11284 		(void) delete_dependents(pg);
11285 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11286 		scfdie();
11287 
11288 	scf_iter_destroy(iter);
11289 	scf_pg_destroy(pg);
11290 	scf_instance_destroy(inst);
11291 
11292 	/*
11293 	 * If the service has some external dependencies then we don't
11294 	 * want to remove them in case the service is re-imported.
11295 	 */
11296 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11297 	    (iter = scf_iter_create(g_hndl)) == NULL)
11298 		scfdie();
11299 
11300 	if (scf_iter_service_pgs(iter, svc) < 0)
11301 		scfdie();
11302 
11303 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
11304 		if (pg_is_external_dependency(pg)) {
11305 			external |= 2;
11306 			continue;
11307 		}
11308 
11309 		if (scf_pg_delete(pg) != 0) {
11310 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11311 				scfdie();
11312 			else {
11313 				semerr(emsg_permission_denied);
11314 
11315 				(void) scf_iter_destroy(iter);
11316 				(void) scf_pg_destroy(pg);
11317 				return (DELETE_FAILURE);
11318 			}
11319 		}
11320 	}
11321 
11322 	if (r == -1)
11323 		scfdie();
11324 
11325 	(void) scf_iter_destroy(iter);
11326 	(void) scf_pg_destroy(pg);
11327 
11328 	if (external != 0)
11329 		return (DELETE_SUCCESS_EXTDEPS);
11330 
11331 	if (scf_service_delete(svc) == 0)
11332 		return (DELETE_SUCCESS_NOEXTDEPS);
11333 
11334 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11335 		scfdie();
11336 
11337 	semerr(emsg_permission_denied);
11338 	return (DELETE_FAILURE);
11339 }
11340 
11341 static int
11342 delete_callback(void *data, scf_walkinfo_t *wip)
11343 {
11344 	int force = (int)data;
11345 
11346 	if (wip->inst != NULL)
11347 		(void) lscf_instance_delete(wip->inst, force);
11348 	else
11349 		(void) lscf_service_delete(wip->svc, force);
11350 
11351 	return (0);
11352 }
11353 
11354 void
11355 lscf_delete(const char *fmri, int force)
11356 {
11357 	scf_service_t *svc;
11358 	scf_instance_t *inst;
11359 	int ret;
11360 
11361 	lscf_prep_hndl();
11362 
11363 	if (cur_snap != NULL) {
11364 		if (!snaplevel_is_instance(cur_level)) {
11365 			char *buf;
11366 
11367 			buf = safe_malloc(max_scf_name_len + 1);
11368 			if (scf_instance_get_name(cur_inst, buf,
11369 			    max_scf_name_len + 1) >= 0) {
11370 				if (strcmp(buf, fmri) == 0) {
11371 					semerr(emsg_cant_modify_snapshots);
11372 					free(buf);
11373 					return;
11374 				}
11375 			} else if (scf_error() != SCF_ERROR_DELETED) {
11376 				scfdie();
11377 			}
11378 			free(buf);
11379 		}
11380 	} else if (cur_inst != NULL) {
11381 		/* EMPTY */;
11382 	} else if (cur_svc != NULL) {
11383 		inst = scf_instance_create(g_hndl);
11384 		if (inst == NULL)
11385 			scfdie();
11386 
11387 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
11388 		    SCF_SUCCESS) {
11389 			(void) lscf_instance_delete(inst, force);
11390 			scf_instance_destroy(inst);
11391 			return;
11392 		}
11393 
11394 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11395 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11396 			scfdie();
11397 
11398 		scf_instance_destroy(inst);
11399 	} else {
11400 		assert(cur_scope != NULL);
11401 
11402 		svc = scf_service_create(g_hndl);
11403 		if (svc == NULL)
11404 			scfdie();
11405 
11406 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
11407 		    SCF_SUCCESS) {
11408 			(void) lscf_service_delete(svc, force);
11409 			scf_service_destroy(svc);
11410 			return;
11411 		}
11412 
11413 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11414 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11415 			scfdie();
11416 
11417 		scf_service_destroy(svc);
11418 	}
11419 
11420 	/*
11421 	 * Match FMRI to entity.
11422 	 */
11423 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11424 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
11425 		semerr(gettext("Failed to walk instances: %s\n"),
11426 		    scf_strerror(ret));
11427 	}
11428 }
11429 
11430 
11431 
11432 /*
11433  * :properties commands.  These all end with "pg" or "prop" and generally
11434  * operate on the currently selected entity.
11435  */
11436 
11437 /*
11438  * Property listing.  List the property groups, properties, their types and
11439  * their values for the currently selected entity.
11440  */
11441 static void
11442 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
11443 {
11444 	char *buf;
11445 	uint32_t flags;
11446 
11447 	buf = safe_malloc(max_scf_pg_type_len + 1);
11448 
11449 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
11450 		scfdie();
11451 
11452 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
11453 		scfdie();
11454 
11455 	safe_printf("%-*s  %s", namewidth, name, buf);
11456 
11457 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
11458 		safe_printf("\tNONPERSISTENT");
11459 
11460 	safe_printf("\n");
11461 
11462 	free(buf);
11463 }
11464 
11465 static boolean_t
11466 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
11467 {
11468 	if (scf_property_get_value(prop, val) == 0) {
11469 		return (B_FALSE);
11470 	} else {
11471 		switch (scf_error()) {
11472 		case SCF_ERROR_NOT_FOUND:
11473 			return (B_FALSE);
11474 		case SCF_ERROR_PERMISSION_DENIED:
11475 		case SCF_ERROR_CONSTRAINT_VIOLATED:
11476 			return (B_TRUE);
11477 		default:
11478 			scfdie();
11479 			/*NOTREACHED*/
11480 		}
11481 	}
11482 }
11483 
11484 static void
11485 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
11486 {
11487 	scf_iter_t *iter;
11488 	scf_value_t *val;
11489 	const char *type;
11490 	int multiple_strings = 0;
11491 	int ret;
11492 
11493 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11494 	    (val = scf_value_create(g_hndl)) == NULL)
11495 		scfdie();
11496 
11497 	type = prop_to_typestr(prop);
11498 	assert(type != NULL);
11499 
11500 	safe_printf("%-*s  %-7s ", len, name, type);
11501 
11502 	if (prop_has_multiple_values(prop, val) &&
11503 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
11504 	    scf_value_type(val) == SCF_TYPE_USTRING))
11505 		multiple_strings = 1;
11506 
11507 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11508 		scfdie();
11509 
11510 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11511 		char *buf;
11512 		ssize_t vlen, szret;
11513 
11514 		vlen = scf_value_get_as_string(val, NULL, 0);
11515 		if (vlen < 0)
11516 			scfdie();
11517 
11518 		buf = safe_malloc(vlen + 1);
11519 
11520 		szret = scf_value_get_as_string(val, buf, vlen + 1);
11521 		if (szret < 0)
11522 			scfdie();
11523 		assert(szret <= vlen);
11524 
11525 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11526 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
11527 			safe_printf(" \"");
11528 			(void) quote_and_print(buf, stdout, 0);
11529 			(void) putchar('"');
11530 			if (ferror(stdout)) {
11531 				(void) putchar('\n');
11532 				uu_die(gettext("Error writing to stdout.\n"));
11533 			}
11534 		} else {
11535 			safe_printf(" %s", buf);
11536 		}
11537 
11538 		free(buf);
11539 	}
11540 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11541 		scfdie();
11542 
11543 	if (putchar('\n') != '\n')
11544 		uu_die(gettext("Could not output newline"));
11545 }
11546 
11547 /*
11548  * Outputs template property group info for the describe subcommand.
11549  * If 'templates' == 2, verbose output is printed in the format expected
11550  * for describe -v, which includes all templates fields.  If pg is
11551  * not NULL, we're describing the template data, not an existing property
11552  * group, and formatting should be appropriate for describe -t.
11553  */
11554 static void
11555 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
11556 {
11557 	char *buf;
11558 	uint8_t required;
11559 	scf_property_t *stability_prop;
11560 	scf_value_t *stability_val;
11561 
11562 	if (templates == 0)
11563 		return;
11564 
11565 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
11566 	    (stability_val = scf_value_create(g_hndl)) == NULL)
11567 		scfdie();
11568 
11569 	if (templates == 2 && pg != NULL) {
11570 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
11571 		    stability_prop) == 0) {
11572 			if (prop_check_type(stability_prop,
11573 			    SCF_TYPE_ASTRING) == 0 &&
11574 			    prop_get_val(stability_prop, stability_val) == 0) {
11575 				char *stability;
11576 
11577 				stability = safe_malloc(max_scf_value_len + 1);
11578 
11579 				if (scf_value_get_astring(stability_val,
11580 				    stability, max_scf_value_len + 1) == -1 &&
11581 				    scf_error() != SCF_ERROR_NOT_FOUND)
11582 					scfdie();
11583 
11584 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11585 				    gettext("stability"), stability);
11586 
11587 				free(stability);
11588 			}
11589 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
11590 			scfdie();
11591 	}
11592 
11593 	scf_property_destroy(stability_prop);
11594 	scf_value_destroy(stability_val);
11595 
11596 	if (pgt == NULL)
11597 		return;
11598 
11599 	if (pg == NULL || templates == 2) {
11600 		/* print type info only if scf_tmpl_pg_name succeeds */
11601 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
11602 			if (pg != NULL)
11603 				safe_printf("%s", TMPL_INDENT);
11604 			safe_printf("%s: ", gettext("name"));
11605 			safe_printf("%s\n", buf);
11606 			free(buf);
11607 		}
11608 
11609 		/* print type info only if scf_tmpl_pg_type succeeds */
11610 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
11611 			if (pg != NULL)
11612 				safe_printf("%s", TMPL_INDENT);
11613 			safe_printf("%s: ", gettext("type"));
11614 			safe_printf("%s\n", buf);
11615 			free(buf);
11616 		}
11617 	}
11618 
11619 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
11620 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11621 		    required ? "true" : "false");
11622 
11623 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
11624 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
11625 		    buf);
11626 		free(buf);
11627 	}
11628 
11629 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
11630 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11631 		    buf);
11632 		free(buf);
11633 	}
11634 
11635 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
11636 		if (templates == 2)
11637 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11638 			    gettext("description"), buf);
11639 		else
11640 			safe_printf("%s%s\n", TMPL_INDENT, buf);
11641 		free(buf);
11642 	}
11643 
11644 }
11645 
11646 /*
11647  * With as_value set to true, indent as appropriate for the value level.
11648  * If false, indent to appropriate level for inclusion in constraint
11649  * or choice printout.
11650  */
11651 static void
11652 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
11653     int as_value)
11654 {
11655 	char *buf;
11656 
11657 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
11658 		if (as_value == 0)
11659 			safe_printf("%s", TMPL_CHOICE_INDENT);
11660 		else
11661 			safe_printf("%s", TMPL_INDENT);
11662 		safe_printf("%s: %s\n", gettext("value common name"), buf);
11663 		free(buf);
11664 	}
11665 
11666 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
11667 		if (as_value == 0)
11668 			safe_printf("%s", TMPL_CHOICE_INDENT);
11669 		else
11670 			safe_printf("%s", TMPL_INDENT);
11671 		safe_printf("%s: %s\n", gettext("value description"), buf);
11672 		free(buf);
11673 	}
11674 }
11675 
11676 static void
11677 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
11678 {
11679 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
11680 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11681 	safe_printf("%s\n", val_buf);
11682 
11683 	print_template_value_details(prt, val_buf, 1);
11684 }
11685 
11686 static void
11687 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
11688 {
11689 	int i, printed = 0;
11690 	scf_values_t values;
11691 	scf_count_ranges_t c_ranges;
11692 	scf_int_ranges_t i_ranges;
11693 
11694 	printed = 0;
11695 	i = 0;
11696 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
11697 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11698 		    gettext("value constraints"));
11699 		printed++;
11700 		for (i = 0; i < values.value_count; ++i) {
11701 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11702 			    gettext("value name"), values.values_as_strings[i]);
11703 			if (verbose == 1)
11704 				print_template_value_details(prt,
11705 				    values.values_as_strings[i], 0);
11706 		}
11707 
11708 		scf_values_destroy(&values);
11709 	}
11710 
11711 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
11712 		if (printed++ == 0)
11713 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11714 			    gettext("value constraints"));
11715 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11716 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11717 			    gettext("range"), c_ranges.scr_min[i],
11718 			    c_ranges.scr_max[i]);
11719 		}
11720 		scf_count_ranges_destroy(&c_ranges);
11721 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11722 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
11723 		if (printed++ == 0)
11724 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11725 			    gettext("value constraints"));
11726 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11727 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11728 			    gettext("range"), i_ranges.sir_min[i],
11729 			    i_ranges.sir_max[i]);
11730 		}
11731 		scf_int_ranges_destroy(&i_ranges);
11732 	}
11733 }
11734 
11735 static void
11736 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
11737 {
11738 	int i = 0, printed = 0;
11739 	scf_values_t values;
11740 	scf_count_ranges_t c_ranges;
11741 	scf_int_ranges_t i_ranges;
11742 
11743 	printed = 0;
11744 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
11745 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11746 		    gettext("value constraints"));
11747 		printed++;
11748 		for (i = 0; i < values.value_count; i++) {
11749 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11750 			    gettext("value name"), values.values_as_strings[i]);
11751 			if (verbose == 1)
11752 				print_template_value_details(prt,
11753 				    values.values_as_strings[i], 0);
11754 		}
11755 
11756 		scf_values_destroy(&values);
11757 	}
11758 
11759 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
11760 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11761 			if (printed++ == 0)
11762 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11763 				    gettext("value choices"));
11764 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11765 			    gettext("range"), c_ranges.scr_min[i],
11766 			    c_ranges.scr_max[i]);
11767 		}
11768 		scf_count_ranges_destroy(&c_ranges);
11769 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11770 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
11771 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11772 			if (printed++ == 0)
11773 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11774 				    gettext("value choices"));
11775 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11776 			    gettext("range"), i_ranges.sir_min[i],
11777 			    i_ranges.sir_max[i]);
11778 		}
11779 		scf_int_ranges_destroy(&i_ranges);
11780 	}
11781 }
11782 
11783 static void
11784 list_values_by_template(scf_prop_tmpl_t *prt)
11785 {
11786 	print_template_constraints(prt, 1);
11787 	print_template_choices(prt, 1);
11788 }
11789 
11790 static void
11791 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
11792 {
11793 	char *val_buf;
11794 	scf_iter_t *iter;
11795 	scf_value_t *val;
11796 	int ret;
11797 
11798 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11799 	    (val = scf_value_create(g_hndl)) == NULL)
11800 		scfdie();
11801 
11802 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11803 		scfdie();
11804 
11805 	val_buf = safe_malloc(max_scf_value_len + 1);
11806 
11807 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11808 		if (scf_value_get_as_string(val, val_buf,
11809 		    max_scf_value_len + 1) < 0)
11810 			scfdie();
11811 
11812 		print_template_value(prt, val_buf);
11813 	}
11814 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11815 		scfdie();
11816 	free(val_buf);
11817 
11818 	print_template_constraints(prt, 0);
11819 	print_template_choices(prt, 0);
11820 
11821 }
11822 
11823 /*
11824  * Outputs property info for the describe subcommand
11825  * Verbose output if templates == 2, -v option of svccfg describe
11826  * Displays template data if prop is not NULL, -t option of svccfg describe
11827  */
11828 static void
11829 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
11830 {
11831 	char *buf;
11832 	uint8_t u_buf;
11833 	int i;
11834 	uint64_t min, max;
11835 	scf_values_t values;
11836 
11837 	if (prt == NULL || templates == 0)
11838 		return;
11839 
11840 	if (prop == NULL) {
11841 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
11842 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
11843 			safe_printf("%s\n", buf);
11844 			free(buf);
11845 		} else
11846 			safe_printf("(%s)\n", gettext("any"));
11847 	}
11848 
11849 	if (prop == NULL || templates == 2) {
11850 		if (prop != NULL)
11851 			safe_printf("%s", TMPL_INDENT);
11852 		else
11853 			safe_printf("%s", TMPL_VALUE_INDENT);
11854 		safe_printf("%s: ", gettext("type"));
11855 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
11856 			safe_printf("%s\n", buf);
11857 			free(buf);
11858 		} else
11859 			safe_printf("(%s)\n", gettext("any"));
11860 	}
11861 
11862 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
11863 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11864 		    u_buf ? "true" : "false");
11865 
11866 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
11867 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11868 		    buf);
11869 		free(buf);
11870 	}
11871 
11872 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
11873 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
11874 		    buf);
11875 		free(buf);
11876 	}
11877 
11878 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
11879 		safe_printf("%s%s\n", TMPL_INDENT, buf);
11880 		free(buf);
11881 	}
11882 
11883 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
11884 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
11885 		    scf_tmpl_visibility_to_string(u_buf));
11886 
11887 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
11888 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11889 		    gettext("minimum number of values"), min);
11890 		if (max == ULLONG_MAX) {
11891 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11892 			    gettext("maximum number of values"),
11893 			    gettext("unlimited"));
11894 		} else {
11895 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11896 			    gettext("maximum number of values"), max);
11897 		}
11898 	}
11899 
11900 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
11901 		for (i = 0; i < values.value_count; i++) {
11902 			if (i == 0) {
11903 				safe_printf("%s%s:", TMPL_INDENT,
11904 				    gettext("internal separators"));
11905 			}
11906 			safe_printf(" \"%s\"", values.values_as_strings[i]);
11907 		}
11908 		safe_printf("\n");
11909 	}
11910 
11911 	if (templates != 2)
11912 		return;
11913 
11914 	if (prop != NULL)
11915 		list_values_tmpl(prt, prop);
11916 	else
11917 		list_values_by_template(prt);
11918 }
11919 
11920 static char *
11921 read_astring(scf_propertygroup_t *pg, const char *prop_name)
11922 {
11923 	char *rv;
11924 
11925 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
11926 	if (rv == NULL) {
11927 		switch (scf_error()) {
11928 		case SCF_ERROR_NOT_FOUND:
11929 			break;
11930 		default:
11931 			scfdie();
11932 		}
11933 	}
11934 	return (rv);
11935 }
11936 
11937 static void
11938 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
11939 {
11940 	size_t doc_len;
11941 	size_t man_len;
11942 	char *pg_name;
11943 	char *text = NULL;
11944 	int rv;
11945 
11946 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
11947 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
11948 	pg_name = safe_malloc(max_scf_name_len + 1);
11949 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
11950 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
11951 			scfdie();
11952 		}
11953 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
11954 			/* Display doc_link and and uri */
11955 			safe_printf("%s%s:\n", TMPL_INDENT,
11956 			    gettext("doc_link"));
11957 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
11958 			if (text != NULL) {
11959 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11960 				    TMPL_INDENT, gettext("name"), text);
11961 				uu_free(text);
11962 			}
11963 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
11964 			if (text != NULL) {
11965 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
11966 				    gettext("uri"), text);
11967 				uu_free(text);
11968 			}
11969 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
11970 		    man_len) == 0) {
11971 			/* Display manpage title, section and path */
11972 			safe_printf("%s%s:\n", TMPL_INDENT,
11973 			    gettext("manpage"));
11974 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
11975 			if (text != NULL) {
11976 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11977 				    TMPL_INDENT, gettext("title"), text);
11978 				uu_free(text);
11979 			}
11980 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
11981 			if (text != NULL) {
11982 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11983 				    TMPL_INDENT, gettext("section"), text);
11984 				uu_free(text);
11985 			}
11986 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
11987 			if (text != NULL) {
11988 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11989 				    TMPL_INDENT, gettext("manpath"), text);
11990 				uu_free(text);
11991 			}
11992 		}
11993 	}
11994 	if (rv == -1)
11995 		scfdie();
11996 
11997 done:
11998 	free(pg_name);
11999 }
12000 
12001 static void
12002 list_entity_tmpl(int templates)
12003 {
12004 	char *common_name = NULL;
12005 	char *description = NULL;
12006 	char *locale = NULL;
12007 	scf_iter_t *iter;
12008 	scf_propertygroup_t *pg;
12009 	scf_property_t *prop;
12010 	int r;
12011 	scf_value_t *val;
12012 
12013 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12014 	    (prop = scf_property_create(g_hndl)) == NULL ||
12015 	    (val = scf_value_create(g_hndl)) == NULL ||
12016 	    (iter = scf_iter_create(g_hndl)) == NULL)
12017 		scfdie();
12018 
12019 	locale = setlocale(LC_MESSAGES, NULL);
12020 
12021 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
12022 		common_name = safe_malloc(max_scf_value_len + 1);
12023 
12024 		/* Try both the current locale and the "C" locale. */
12025 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
12026 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
12027 		    scf_pg_get_property(pg, "C", prop) == 0)) {
12028 			if (prop_get_val(prop, val) == 0 &&
12029 			    scf_value_get_ustring(val, common_name,
12030 			    max_scf_value_len + 1) != -1) {
12031 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12032 				    gettext("common name"), common_name);
12033 			}
12034 		}
12035 	}
12036 
12037 	/*
12038 	 * Do description, manpages, and doc links if templates == 2.
12039 	 */
12040 	if (templates == 2) {
12041 		/* Get the description. */
12042 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12043 			description = safe_malloc(max_scf_value_len + 1);
12044 
12045 			/* Try both the current locale and the "C" locale. */
12046 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
12047 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
12048 			    scf_pg_get_property(pg, "C", prop) == 0)) {
12049 				if (prop_get_val(prop, val) == 0 &&
12050 				    scf_value_get_ustring(val, description,
12051 				    max_scf_value_len + 1) != -1) {
12052 					safe_printf("%s%s: %s\n", TMPL_INDENT,
12053 					    gettext("description"),
12054 					    description);
12055 				}
12056 			}
12057 		}
12058 
12059 		/* Process doc_link & manpage elements. */
12060 		if (cur_level != NULL) {
12061 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
12062 			    SCF_GROUP_TEMPLATE);
12063 		} else if (cur_inst != NULL) {
12064 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
12065 			    SCF_GROUP_TEMPLATE);
12066 		} else {
12067 			r = scf_iter_service_pgs_typed(iter, cur_svc,
12068 			    SCF_GROUP_TEMPLATE);
12069 		}
12070 		if (r == 0) {
12071 			display_documentation(iter, pg);
12072 		}
12073 	}
12074 
12075 	free(common_name);
12076 	free(description);
12077 	scf_pg_destroy(pg);
12078 	scf_property_destroy(prop);
12079 	scf_value_destroy(val);
12080 	scf_iter_destroy(iter);
12081 }
12082 
12083 static void
12084 listtmpl(const char *pattern, int templates)
12085 {
12086 	scf_pg_tmpl_t *pgt;
12087 	scf_prop_tmpl_t *prt;
12088 	char *snapbuf = NULL;
12089 	char *fmribuf;
12090 	char *pg_name = NULL, *prop_name = NULL;
12091 	ssize_t prop_name_size;
12092 	char *qual_prop_name;
12093 	char *search_name;
12094 	int listed = 0;
12095 
12096 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12097 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
12098 		scfdie();
12099 
12100 	fmribuf = safe_malloc(max_scf_name_len + 1);
12101 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
12102 
12103 	if (cur_snap != NULL) {
12104 		snapbuf = safe_malloc(max_scf_name_len + 1);
12105 		if (scf_snapshot_get_name(cur_snap, snapbuf,
12106 		    max_scf_name_len + 1) < 0)
12107 			scfdie();
12108 	}
12109 
12110 	if (cur_inst != NULL) {
12111 		if (scf_instance_to_fmri(cur_inst, fmribuf,
12112 		    max_scf_name_len + 1) < 0)
12113 			scfdie();
12114 	} else if (cur_svc != NULL) {
12115 		if (scf_service_to_fmri(cur_svc, fmribuf,
12116 		    max_scf_name_len + 1) < 0)
12117 			scfdie();
12118 	} else
12119 		abort();
12120 
12121 	/* If pattern is specified, we want to list only those items. */
12122 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
12123 		listed = 0;
12124 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
12125 		    fnmatch(pattern, pg_name, 0) == 0)) {
12126 			list_pg_tmpl(pgt, NULL, templates);
12127 			listed++;
12128 		}
12129 
12130 		scf_tmpl_prop_reset(prt);
12131 
12132 		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
12133 			search_name = NULL;
12134 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
12135 			if ((prop_name_size > 0) && (pg_name != NULL)) {
12136 				if (snprintf(qual_prop_name,
12137 				    max_scf_name_len + 1, "%s/%s",
12138 				    pg_name, prop_name) >=
12139 				    max_scf_name_len + 1) {
12140 					prop_name_size = -1;
12141 				} else {
12142 					search_name = qual_prop_name;
12143 				}
12144 			}
12145 			if (listed > 0 || pattern == NULL ||
12146 			    (prop_name_size > 0 &&
12147 			    fnmatch(pattern, search_name,
12148 			    FNM_PATHNAME) == 0))
12149 				list_prop_tmpl(prt, NULL, templates);
12150 			if (prop_name != NULL) {
12151 				free(prop_name);
12152 				prop_name = NULL;
12153 			}
12154 		}
12155 		if (pg_name != NULL) {
12156 			free(pg_name);
12157 			pg_name = NULL;
12158 		}
12159 	}
12160 
12161 	scf_tmpl_prop_destroy(prt);
12162 	scf_tmpl_pg_destroy(pgt);
12163 	free(snapbuf);
12164 	free(fmribuf);
12165 	free(qual_prop_name);
12166 }
12167 
12168 static void
12169 listprop(const char *pattern, int only_pgs, int templates)
12170 {
12171 	scf_propertygroup_t *pg;
12172 	scf_property_t *prop;
12173 	scf_iter_t *iter, *piter;
12174 	char *pgnbuf, *prnbuf, *ppnbuf;
12175 	scf_pg_tmpl_t *pgt, *pgtp;
12176 	scf_prop_tmpl_t *prt;
12177 
12178 	void **objects;
12179 	char **names;
12180 	void **tmpls;
12181 	int allocd, i;
12182 
12183 	int ret;
12184 	ssize_t pgnlen, prnlen, szret;
12185 	size_t max_len = 0;
12186 
12187 	if (cur_svc == NULL && cur_inst == NULL) {
12188 		semerr(emsg_entity_not_selected);
12189 		return;
12190 	}
12191 
12192 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12193 	    (prop = scf_property_create(g_hndl)) == NULL ||
12194 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12195 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12196 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12197 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
12198 		scfdie();
12199 
12200 	prnbuf = safe_malloc(max_scf_name_len + 1);
12201 
12202 	if (cur_level != NULL)
12203 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
12204 	else if (cur_inst != NULL)
12205 		ret = scf_iter_instance_pgs(iter, cur_inst);
12206 	else
12207 		ret = scf_iter_service_pgs(iter, cur_svc);
12208 	if (ret != 0) {
12209 		return;
12210 	}
12211 
12212 	/*
12213 	 * We want to only list items which match pattern, and we want the
12214 	 * second column to line up, so during the first pass we'll save
12215 	 * matching items, their names, and their templates in objects,
12216 	 * names, and tmpls, computing the maximum name length as we go,
12217 	 * and then we'll print them out.
12218 	 *
12219 	 * Note: We always keep an extra slot available so the array can be
12220 	 * NULL-terminated.
12221 	 */
12222 	i = 0;
12223 	allocd = 1;
12224 	objects = safe_malloc(sizeof (*objects));
12225 	names = safe_malloc(sizeof (*names));
12226 	tmpls = safe_malloc(sizeof (*tmpls));
12227 
12228 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12229 		int new_pg = 0;
12230 		int print_props = 0;
12231 		pgtp = NULL;
12232 
12233 		pgnlen = scf_pg_get_name(pg, NULL, 0);
12234 		if (pgnlen < 0)
12235 			scfdie();
12236 
12237 		pgnbuf = safe_malloc(pgnlen + 1);
12238 
12239 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
12240 		if (szret < 0)
12241 			scfdie();
12242 		assert(szret <= pgnlen);
12243 
12244 		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
12245 			if (scf_error() != SCF_ERROR_NOT_FOUND)
12246 				scfdie();
12247 			pgtp = NULL;
12248 		} else {
12249 			pgtp = pgt;
12250 		}
12251 
12252 		if (pattern == NULL ||
12253 		    fnmatch(pattern, pgnbuf, 0) == 0) {
12254 			if (i+1 >= allocd) {
12255 				allocd *= 2;
12256 				objects = realloc(objects,
12257 				    sizeof (*objects) * allocd);
12258 				names =
12259 				    realloc(names, sizeof (*names) * allocd);
12260 				tmpls = realloc(tmpls,
12261 				    sizeof (*tmpls) * allocd);
12262 				if (objects == NULL || names == NULL ||
12263 				    tmpls == NULL)
12264 					uu_die(gettext("Out of memory"));
12265 			}
12266 			objects[i] = pg;
12267 			names[i] = pgnbuf;
12268 
12269 			if (pgtp == NULL)
12270 				tmpls[i] = NULL;
12271 			else
12272 				tmpls[i] = pgt;
12273 
12274 			++i;
12275 
12276 			if (pgnlen > max_len)
12277 				max_len = pgnlen;
12278 
12279 			new_pg = 1;
12280 			print_props = 1;
12281 		}
12282 
12283 		if (only_pgs) {
12284 			if (new_pg) {
12285 				pg = scf_pg_create(g_hndl);
12286 				if (pg == NULL)
12287 					scfdie();
12288 				pgt = scf_tmpl_pg_create(g_hndl);
12289 				if (pgt == NULL)
12290 					scfdie();
12291 			} else
12292 				free(pgnbuf);
12293 
12294 			continue;
12295 		}
12296 
12297 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12298 			scfdie();
12299 
12300 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
12301 			prnlen = scf_property_get_name(prop, prnbuf,
12302 			    max_scf_name_len + 1);
12303 			if (prnlen < 0)
12304 				scfdie();
12305 
12306 			/* Will prepend the property group name and a slash. */
12307 			prnlen += pgnlen + 1;
12308 
12309 			ppnbuf = safe_malloc(prnlen + 1);
12310 
12311 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
12312 			    prnbuf) < 0)
12313 				uu_die("snprintf");
12314 
12315 			if (pattern == NULL || print_props == 1 ||
12316 			    fnmatch(pattern, ppnbuf, 0) == 0) {
12317 				if (i+1 >= allocd) {
12318 					allocd *= 2;
12319 					objects = realloc(objects,
12320 					    sizeof (*objects) * allocd);
12321 					names = realloc(names,
12322 					    sizeof (*names) * allocd);
12323 					tmpls = realloc(tmpls,
12324 					    sizeof (*tmpls) * allocd);
12325 					if (objects == NULL || names == NULL ||
12326 					    tmpls == NULL)
12327 						uu_die(gettext(
12328 						    "Out of memory"));
12329 				}
12330 
12331 				objects[i] = prop;
12332 				names[i] = ppnbuf;
12333 
12334 				if (pgtp != NULL) {
12335 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
12336 					    prt, NULL) < 0) {
12337 						if (scf_error() !=
12338 						    SCF_ERROR_NOT_FOUND)
12339 							scfdie();
12340 						tmpls[i] = NULL;
12341 					} else {
12342 						tmpls[i] = prt;
12343 					}
12344 				} else {
12345 					tmpls[i] = NULL;
12346 				}
12347 
12348 				++i;
12349 
12350 				if (prnlen > max_len)
12351 					max_len = prnlen;
12352 
12353 				prop = scf_property_create(g_hndl);
12354 				prt = scf_tmpl_prop_create(g_hndl);
12355 			} else {
12356 				free(ppnbuf);
12357 			}
12358 		}
12359 
12360 		if (new_pg) {
12361 			pg = scf_pg_create(g_hndl);
12362 			if (pg == NULL)
12363 				scfdie();
12364 			pgt = scf_tmpl_pg_create(g_hndl);
12365 			if (pgt == NULL)
12366 				scfdie();
12367 		} else
12368 			free(pgnbuf);
12369 	}
12370 	if (ret != 0)
12371 		scfdie();
12372 
12373 	objects[i] = NULL;
12374 
12375 	scf_pg_destroy(pg);
12376 	scf_tmpl_pg_destroy(pgt);
12377 	scf_property_destroy(prop);
12378 	scf_tmpl_prop_destroy(prt);
12379 
12380 	for (i = 0; objects[i] != NULL; ++i) {
12381 		if (strchr(names[i], '/') == NULL) {
12382 			/* property group */
12383 			pg = (scf_propertygroup_t *)objects[i];
12384 			pgt = (scf_pg_tmpl_t *)tmpls[i];
12385 			list_pg_info(pg, names[i], max_len);
12386 			list_pg_tmpl(pgt, pg, templates);
12387 			free(names[i]);
12388 			scf_pg_destroy(pg);
12389 			if (pgt != NULL)
12390 				scf_tmpl_pg_destroy(pgt);
12391 		} else {
12392 			/* property */
12393 			prop = (scf_property_t *)objects[i];
12394 			prt = (scf_prop_tmpl_t *)tmpls[i];
12395 			list_prop_info(prop, names[i], max_len);
12396 			list_prop_tmpl(prt, prop, templates);
12397 			free(names[i]);
12398 			scf_property_destroy(prop);
12399 			if (prt != NULL)
12400 				scf_tmpl_prop_destroy(prt);
12401 		}
12402 	}
12403 
12404 	free(names);
12405 	free(objects);
12406 	free(tmpls);
12407 }
12408 
12409 void
12410 lscf_listpg(const char *pattern)
12411 {
12412 	lscf_prep_hndl();
12413 
12414 	listprop(pattern, 1, 0);
12415 }
12416 
12417 /*
12418  * Property group and property creation, setting, and deletion.  setprop (and
12419  * its alias, addprop) can either create a property group of a given type, or
12420  * it can create or set a property to a given type and list of values.
12421  */
12422 void
12423 lscf_addpg(const char *name, const char *type, const char *flags)
12424 {
12425 	scf_propertygroup_t *pg;
12426 	int ret;
12427 	uint32_t flgs = 0;
12428 	const char *cp;
12429 
12430 
12431 	lscf_prep_hndl();
12432 
12433 	if (cur_snap != NULL) {
12434 		semerr(emsg_cant_modify_snapshots);
12435 		return;
12436 	}
12437 
12438 	if (cur_inst == NULL && cur_svc == NULL) {
12439 		semerr(emsg_entity_not_selected);
12440 		return;
12441 	}
12442 
12443 	if (flags != NULL) {
12444 		for (cp = flags; *cp != '\0'; ++cp) {
12445 			switch (*cp) {
12446 			case 'P':
12447 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
12448 				break;
12449 
12450 			case 'p':
12451 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
12452 				break;
12453 
12454 			default:
12455 				semerr(gettext("Invalid property group flag "
12456 				    "%c."), *cp);
12457 				return;
12458 			}
12459 		}
12460 	}
12461 
12462 	pg = scf_pg_create(g_hndl);
12463 	if (pg == NULL)
12464 		scfdie();
12465 
12466 	if (cur_inst != NULL)
12467 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
12468 	else
12469 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
12470 
12471 	if (ret != SCF_SUCCESS) {
12472 		switch (scf_error()) {
12473 		case SCF_ERROR_INVALID_ARGUMENT:
12474 			semerr(gettext("Name, type, or flags are invalid.\n"));
12475 			break;
12476 
12477 		case SCF_ERROR_EXISTS:
12478 			semerr(gettext("Property group already exists.\n"));
12479 			break;
12480 
12481 		case SCF_ERROR_PERMISSION_DENIED:
12482 			semerr(emsg_permission_denied);
12483 			break;
12484 
12485 		case SCF_ERROR_BACKEND_ACCESS:
12486 			semerr(gettext("Backend refused access.\n"));
12487 			break;
12488 
12489 		default:
12490 			scfdie();
12491 		}
12492 	}
12493 
12494 	scf_pg_destroy(pg);
12495 
12496 	private_refresh();
12497 }
12498 
12499 void
12500 lscf_delpg(char *name)
12501 {
12502 	lscf_prep_hndl();
12503 
12504 	if (cur_snap != NULL) {
12505 		semerr(emsg_cant_modify_snapshots);
12506 		return;
12507 	}
12508 
12509 	if (cur_inst == NULL && cur_svc == NULL) {
12510 		semerr(emsg_entity_not_selected);
12511 		return;
12512 	}
12513 
12514 	if (strchr(name, '/') != NULL) {
12515 		semerr(emsg_invalid_pg_name, name);
12516 		return;
12517 	}
12518 
12519 	lscf_delprop(name);
12520 }
12521 
12522 /*
12523  * scf_delhash() is used to remove the property group related to the
12524  * hash entry for a specific manifest in the repository. pgname will be
12525  * constructed from the location of the manifest file. If deathrow isn't 0,
12526  * manifest file doesn't need to exist (manifest string will be used as
12527  * an absolute path).
12528  */
12529 void
12530 lscf_delhash(char *manifest, int deathrow)
12531 {
12532 	char *pgname;
12533 
12534 	if (cur_snap != NULL ||
12535 	    cur_inst != NULL || cur_svc != NULL) {
12536 		warn(gettext("error, an entity is selected\n"));
12537 		return;
12538 	}
12539 
12540 	/* select smf/manifest */
12541 	lscf_select(HASH_SVC);
12542 	/*
12543 	 * Translate the manifest file name to property name. In the deathrow
12544 	 * case, the manifest file does not need to exist.
12545 	 */
12546 	pgname = mhash_filename_to_propname(manifest,
12547 	    deathrow ? B_TRUE : B_FALSE);
12548 	if (pgname == NULL) {
12549 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
12550 		return;
12551 	}
12552 	/* delete the hash property name */
12553 	lscf_delpg(pgname);
12554 }
12555 
12556 void
12557 lscf_listprop(const char *pattern)
12558 {
12559 	lscf_prep_hndl();
12560 
12561 	listprop(pattern, 0, 0);
12562 }
12563 
12564 int
12565 lscf_setprop(const char *pgname, const char *type, const char *value,
12566     const uu_list_t *values)
12567 {
12568 	scf_type_t ty, current_ty;
12569 	scf_service_t *svc;
12570 	scf_propertygroup_t *pg, *parent_pg;
12571 	scf_property_t *prop, *parent_prop;
12572 	scf_pg_tmpl_t *pgt;
12573 	scf_prop_tmpl_t *prt;
12574 	int ret, result = 0;
12575 	scf_transaction_t *tx;
12576 	scf_transaction_entry_t *e;
12577 	scf_value_t *v;
12578 	uu_list_walk_t *walk;
12579 	string_list_t *sp;
12580 	char *propname;
12581 	int req_quotes = 0;
12582 
12583 	lscf_prep_hndl();
12584 
12585 	if ((e = scf_entry_create(g_hndl)) == NULL ||
12586 	    (svc = scf_service_create(g_hndl)) == NULL ||
12587 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
12588 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12589 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
12590 	    (prop = scf_property_create(g_hndl)) == NULL ||
12591 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12592 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12593 	    (tx = scf_transaction_create(g_hndl)) == NULL)
12594 		scfdie();
12595 
12596 	if (cur_snap != NULL) {
12597 		semerr(emsg_cant_modify_snapshots);
12598 		goto fail;
12599 	}
12600 
12601 	if (cur_inst == NULL && cur_svc == NULL) {
12602 		semerr(emsg_entity_not_selected);
12603 		goto fail;
12604 	}
12605 
12606 	propname = strchr(pgname, '/');
12607 	if (propname == NULL) {
12608 		semerr(gettext("Property names must contain a `/'.\n"));
12609 		goto fail;
12610 	}
12611 
12612 	*propname = '\0';
12613 	++propname;
12614 
12615 	if (type != NULL) {
12616 		ty = string_to_type(type);
12617 		if (ty == SCF_TYPE_INVALID) {
12618 			semerr(gettext("Unknown type \"%s\".\n"), type);
12619 			goto fail;
12620 		}
12621 	}
12622 
12623 	if (cur_inst != NULL)
12624 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12625 	else
12626 		ret = scf_service_get_pg(cur_svc, pgname, pg);
12627 	if (ret != SCF_SUCCESS) {
12628 		switch (scf_error()) {
12629 		case SCF_ERROR_NOT_FOUND:
12630 			semerr(emsg_no_such_pg, pgname);
12631 			goto fail;
12632 
12633 		case SCF_ERROR_INVALID_ARGUMENT:
12634 			semerr(emsg_invalid_pg_name, pgname);
12635 			goto fail;
12636 
12637 		default:
12638 			scfdie();
12639 			break;
12640 		}
12641 	}
12642 
12643 	do {
12644 		if (scf_pg_update(pg) == -1)
12645 			scfdie();
12646 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12647 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12648 				scfdie();
12649 
12650 			semerr(emsg_permission_denied);
12651 			goto fail;
12652 		}
12653 
12654 		ret = scf_pg_get_property(pg, propname, prop);
12655 		if (ret == SCF_SUCCESS) {
12656 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
12657 				scfdie();
12658 
12659 			if (type == NULL)
12660 				ty = current_ty;
12661 			if (scf_transaction_property_change_type(tx, e,
12662 			    propname, ty) == -1)
12663 				scfdie();
12664 
12665 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12666 			/* Infer the type, if possible. */
12667 			if (type == NULL) {
12668 				/*
12669 				 * First check if we're an instance and the
12670 				 * property is set on the service.
12671 				 */
12672 				if (cur_inst != NULL &&
12673 				    scf_instance_get_parent(cur_inst,
12674 				    svc) == 0 &&
12675 				    scf_service_get_pg(cur_svc, pgname,
12676 				    parent_pg) == 0 &&
12677 				    scf_pg_get_property(parent_pg, propname,
12678 				    parent_prop) == 0 &&
12679 				    scf_property_type(parent_prop,
12680 				    &current_ty) == 0) {
12681 					ty = current_ty;
12682 
12683 				/* Then check for a type set in a template. */
12684 				} else if (scf_tmpl_get_by_pg(pg, pgt,
12685 				    NULL) == 0 &&
12686 				    scf_tmpl_get_by_prop(pgt, propname, prt,
12687 				    NULL) == 0 &&
12688 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
12689 					ty = current_ty;
12690 
12691 				/* If type can't be inferred, fail. */
12692 				} else {
12693 					semerr(gettext("Type required for new "
12694 					    "properties.\n"));
12695 					goto fail;
12696 				}
12697 			}
12698 			if (scf_transaction_property_new(tx, e, propname,
12699 			    ty) == -1)
12700 				scfdie();
12701 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12702 			semerr(emsg_invalid_prop_name, propname);
12703 			goto fail;
12704 		} else {
12705 			scfdie();
12706 		}
12707 
12708 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
12709 			req_quotes = 1;
12710 
12711 		if (value != NULL) {
12712 			v = string_to_value(value, ty, 0);
12713 
12714 			if (v == NULL)
12715 				goto fail;
12716 
12717 			ret = scf_entry_add_value(e, v);
12718 			assert(ret == SCF_SUCCESS);
12719 		} else {
12720 			assert(values != NULL);
12721 
12722 			walk = uu_list_walk_start((uu_list_t *)values,
12723 			    UU_DEFAULT);
12724 			if (walk == NULL)
12725 				uu_die(gettext("Could not walk list"));
12726 
12727 			for (sp = uu_list_walk_next(walk); sp != NULL;
12728 			    sp = uu_list_walk_next(walk)) {
12729 				v = string_to_value(sp->str, ty, req_quotes);
12730 
12731 				if (v == NULL) {
12732 					scf_entry_destroy_children(e);
12733 					goto fail;
12734 				}
12735 
12736 				ret = scf_entry_add_value(e, v);
12737 				assert(ret == SCF_SUCCESS);
12738 			}
12739 			uu_list_walk_end(walk);
12740 		}
12741 		result = scf_transaction_commit(tx);
12742 
12743 		scf_transaction_reset(tx);
12744 		scf_entry_destroy_children(e);
12745 	} while (result == 0);
12746 
12747 	if (result < 0) {
12748 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12749 			scfdie();
12750 
12751 		semerr(emsg_permission_denied);
12752 		goto fail;
12753 	}
12754 
12755 	ret = 0;
12756 
12757 	private_refresh();
12758 
12759 	goto cleanup;
12760 
12761 fail:
12762 	ret = -1;
12763 
12764 cleanup:
12765 	scf_transaction_destroy(tx);
12766 	scf_entry_destroy(e);
12767 	scf_service_destroy(svc);
12768 	scf_pg_destroy(parent_pg);
12769 	scf_pg_destroy(pg);
12770 	scf_property_destroy(parent_prop);
12771 	scf_property_destroy(prop);
12772 	scf_tmpl_pg_destroy(pgt);
12773 	scf_tmpl_prop_destroy(prt);
12774 
12775 	return (ret);
12776 }
12777 
12778 void
12779 lscf_delprop(char *pgn)
12780 {
12781 	char *slash, *pn;
12782 	scf_propertygroup_t *pg;
12783 	scf_transaction_t *tx;
12784 	scf_transaction_entry_t *e;
12785 	int ret;
12786 
12787 
12788 	lscf_prep_hndl();
12789 
12790 	if (cur_snap != NULL) {
12791 		semerr(emsg_cant_modify_snapshots);
12792 		return;
12793 	}
12794 
12795 	if (cur_inst == NULL && cur_svc == NULL) {
12796 		semerr(emsg_entity_not_selected);
12797 		return;
12798 	}
12799 
12800 	pg = scf_pg_create(g_hndl);
12801 	if (pg == NULL)
12802 		scfdie();
12803 
12804 	slash = strchr(pgn, '/');
12805 	if (slash == NULL) {
12806 		pn = NULL;
12807 	} else {
12808 		*slash = '\0';
12809 		pn = slash + 1;
12810 	}
12811 
12812 	if (cur_inst != NULL)
12813 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
12814 	else
12815 		ret = scf_service_get_pg(cur_svc, pgn, pg);
12816 	if (ret != SCF_SUCCESS) {
12817 		switch (scf_error()) {
12818 		case SCF_ERROR_NOT_FOUND:
12819 			semerr(emsg_no_such_pg, pgn);
12820 			break;
12821 
12822 		case SCF_ERROR_INVALID_ARGUMENT:
12823 			semerr(emsg_invalid_pg_name, pgn);
12824 			break;
12825 
12826 		default:
12827 			scfdie();
12828 		}
12829 
12830 		scf_pg_destroy(pg);
12831 
12832 		return;
12833 	}
12834 
12835 	if (pn == NULL) {
12836 		/* Try to delete the property group. */
12837 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
12838 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12839 				scfdie();
12840 
12841 			semerr(emsg_permission_denied);
12842 		} else {
12843 			private_refresh();
12844 		}
12845 
12846 		scf_pg_destroy(pg);
12847 		return;
12848 	}
12849 
12850 	e = scf_entry_create(g_hndl);
12851 	tx = scf_transaction_create(g_hndl);
12852 
12853 	do {
12854 		if (scf_pg_update(pg) == -1)
12855 			scfdie();
12856 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12857 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12858 				scfdie();
12859 
12860 			semerr(emsg_permission_denied);
12861 			break;
12862 		}
12863 
12864 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
12865 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
12866 				semerr(gettext("No such property %s/%s.\n"),
12867 				    pgn, pn);
12868 				break;
12869 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12870 				semerr(emsg_invalid_prop_name, pn);
12871 				break;
12872 			} else {
12873 				scfdie();
12874 			}
12875 		}
12876 
12877 		ret = scf_transaction_commit(tx);
12878 
12879 		if (ret == 0)
12880 			scf_transaction_reset(tx);
12881 	} while (ret == 0);
12882 
12883 	if (ret < 0) {
12884 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12885 			scfdie();
12886 
12887 		semerr(emsg_permission_denied);
12888 	} else {
12889 		private_refresh();
12890 	}
12891 
12892 	scf_transaction_destroy(tx);
12893 	scf_entry_destroy(e);
12894 	scf_pg_destroy(pg);
12895 }
12896 
12897 /*
12898  * Property editing.
12899  */
12900 
12901 static int
12902 write_edit_script(FILE *strm)
12903 {
12904 	char *fmribuf;
12905 	ssize_t fmrilen;
12906 
12907 	scf_propertygroup_t *pg;
12908 	scf_property_t *prop;
12909 	scf_value_t *val;
12910 	scf_type_t ty;
12911 	int ret, result = 0;
12912 	scf_iter_t *iter, *piter, *viter;
12913 	char *buf, *tybuf, *pname;
12914 	const char *emsg_write_error;
12915 
12916 
12917 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
12918 
12919 
12920 	/* select fmri */
12921 	if (cur_inst != NULL) {
12922 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
12923 		if (fmrilen < 0)
12924 			scfdie();
12925 		fmribuf = safe_malloc(fmrilen + 1);
12926 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
12927 			scfdie();
12928 	} else {
12929 		assert(cur_svc != NULL);
12930 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
12931 		if (fmrilen < 0)
12932 			scfdie();
12933 		fmribuf = safe_malloc(fmrilen + 1);
12934 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
12935 			scfdie();
12936 	}
12937 
12938 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
12939 		warn(emsg_write_error, strerror(errno));
12940 		free(fmribuf);
12941 		return (-1);
12942 	}
12943 
12944 	free(fmribuf);
12945 
12946 
12947 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12948 	    (prop = scf_property_create(g_hndl)) == NULL ||
12949 	    (val = scf_value_create(g_hndl)) == NULL ||
12950 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12951 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12952 	    (viter = scf_iter_create(g_hndl)) == NULL)
12953 		scfdie();
12954 
12955 	buf = safe_malloc(max_scf_name_len + 1);
12956 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
12957 	pname = safe_malloc(max_scf_name_len + 1);
12958 
12959 	if (cur_inst != NULL)
12960 		ret = scf_iter_instance_pgs(iter, cur_inst);
12961 	else
12962 		ret = scf_iter_service_pgs(iter, cur_svc);
12963 	if (ret != SCF_SUCCESS)
12964 		scfdie();
12965 
12966 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12967 		int ret2;
12968 
12969 		/*
12970 		 * # delprop pg
12971 		 * # addpg pg type
12972 		 */
12973 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
12974 			scfdie();
12975 
12976 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
12977 			scfdie();
12978 
12979 		if (fprintf(strm, "# Property group \"%s\"\n"
12980 		    "# delprop %s\n"
12981 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
12982 			warn(emsg_write_error, strerror(errno));
12983 			result = -1;
12984 			goto out;
12985 		}
12986 
12987 		/* # setprop pg/prop = (values) */
12988 
12989 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12990 			scfdie();
12991 
12992 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
12993 			int first = 1;
12994 			int ret3;
12995 			int multiple;
12996 			int is_str;
12997 			scf_type_t bty;
12998 
12999 			if (scf_property_get_name(prop, pname,
13000 			    max_scf_name_len + 1) < 0)
13001 				scfdie();
13002 
13003 			if (scf_property_type(prop, &ty) != 0)
13004 				scfdie();
13005 
13006 			multiple = prop_has_multiple_values(prop, val);
13007 
13008 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13009 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
13010 			    < 0) {
13011 				warn(emsg_write_error, strerror(errno));
13012 				result = -1;
13013 				goto out;
13014 			}
13015 
13016 			(void) scf_type_base_type(ty, &bty);
13017 			is_str = (bty == SCF_TYPE_ASTRING);
13018 
13019 			if (scf_iter_property_values(viter, prop) !=
13020 			    SCF_SUCCESS)
13021 				scfdie();
13022 
13023 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
13024 				char *buf;
13025 				ssize_t buflen;
13026 
13027 				buflen = scf_value_get_as_string(val, NULL, 0);
13028 				if (buflen < 0)
13029 					scfdie();
13030 
13031 				buf = safe_malloc(buflen + 1);
13032 
13033 				if (scf_value_get_as_string(val, buf,
13034 				    buflen + 1) < 0)
13035 					scfdie();
13036 
13037 				if (first)
13038 					first = 0;
13039 				else {
13040 					if (putc(' ', strm) != ' ') {
13041 						warn(emsg_write_error,
13042 						    strerror(errno));
13043 						result = -1;
13044 						goto out;
13045 					}
13046 				}
13047 
13048 				if ((is_str && multiple) ||
13049 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
13050 					(void) putc('"', strm);
13051 					(void) quote_and_print(buf, strm, 1);
13052 					(void) putc('"', strm);
13053 
13054 					if (ferror(strm)) {
13055 						warn(emsg_write_error,
13056 						    strerror(errno));
13057 						result = -1;
13058 						goto out;
13059 					}
13060 				} else {
13061 					if (fprintf(strm, "%s", buf) < 0) {
13062 						warn(emsg_write_error,
13063 						    strerror(errno));
13064 						result = -1;
13065 						goto out;
13066 					}
13067 				}
13068 
13069 				free(buf);
13070 			}
13071 			if (ret3 < 0 &&
13072 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
13073 				scfdie();
13074 
13075 			/* Write closing paren if mult-value property */
13076 			if ((multiple && putc(')', strm) == EOF) ||
13077 
13078 			    /* Write final newline */
13079 			    fputc('\n', strm) == EOF) {
13080 				warn(emsg_write_error, strerror(errno));
13081 				result = -1;
13082 				goto out;
13083 			}
13084 		}
13085 		if (ret2 < 0)
13086 			scfdie();
13087 
13088 		if (fputc('\n', strm) == EOF) {
13089 			warn(emsg_write_error, strerror(errno));
13090 			result = -1;
13091 			goto out;
13092 		}
13093 	}
13094 	if (ret < 0)
13095 		scfdie();
13096 
13097 out:
13098 	free(pname);
13099 	free(tybuf);
13100 	free(buf);
13101 	scf_iter_destroy(viter);
13102 	scf_iter_destroy(piter);
13103 	scf_iter_destroy(iter);
13104 	scf_value_destroy(val);
13105 	scf_property_destroy(prop);
13106 	scf_pg_destroy(pg);
13107 
13108 	if (result == 0) {
13109 		if (fflush(strm) != 0) {
13110 			warn(emsg_write_error, strerror(errno));
13111 			return (-1);
13112 		}
13113 	}
13114 
13115 	return (result);
13116 }
13117 
13118 int
13119 lscf_editprop()
13120 {
13121 	char *buf, *editor;
13122 	size_t bufsz;
13123 	int tmpfd;
13124 	char tempname[] = TEMP_FILE_PATTERN;
13125 
13126 	lscf_prep_hndl();
13127 
13128 	if (cur_snap != NULL) {
13129 		semerr(emsg_cant_modify_snapshots);
13130 		return (-1);
13131 	}
13132 
13133 	if (cur_svc == NULL && cur_inst == NULL) {
13134 		semerr(emsg_entity_not_selected);
13135 		return (-1);
13136 	}
13137 
13138 	tmpfd = mkstemp(tempname);
13139 	if (tmpfd == -1) {
13140 		semerr(gettext("Could not create temporary file.\n"));
13141 		return (-1);
13142 	}
13143 
13144 	(void) strcpy(tempfilename, tempname);
13145 
13146 	tempfile = fdopen(tmpfd, "r+");
13147 	if (tempfile == NULL) {
13148 		warn(gettext("Could not create temporary file.\n"));
13149 		if (close(tmpfd) == -1)
13150 			warn(gettext("Could not close temporary file: %s.\n"),
13151 			    strerror(errno));
13152 
13153 		remove_tempfile();
13154 
13155 		return (-1);
13156 	}
13157 
13158 	if (write_edit_script(tempfile) == -1) {
13159 		remove_tempfile();
13160 		return (-1);
13161 	}
13162 
13163 	editor = getenv("EDITOR");
13164 	if (editor == NULL)
13165 		editor = "vi";
13166 
13167 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
13168 	buf = safe_malloc(bufsz);
13169 
13170 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
13171 		uu_die(gettext("Error creating editor command"));
13172 
13173 	if (system(buf) == -1) {
13174 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
13175 		    strerror(errno));
13176 		free(buf);
13177 		remove_tempfile();
13178 		return (-1);
13179 	}
13180 
13181 	free(buf);
13182 
13183 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
13184 
13185 	remove_tempfile();
13186 
13187 	return (0);
13188 }
13189 
13190 static void
13191 add_string(uu_list_t *strlist, const char *str)
13192 {
13193 	string_list_t *elem;
13194 	elem = safe_malloc(sizeof (*elem));
13195 	uu_list_node_init(elem, &elem->node, string_pool);
13196 	elem->str = safe_strdup(str);
13197 	if (uu_list_append(strlist, elem) != 0)
13198 		uu_die(gettext("libuutil error: %s\n"),
13199 		    uu_strerror(uu_error()));
13200 }
13201 
13202 static int
13203 remove_string(uu_list_t *strlist, const char *str)
13204 {
13205 	uu_list_walk_t	*elems;
13206 	string_list_t	*sp;
13207 
13208 	/*
13209 	 * Find the element that needs to be removed.
13210 	 */
13211 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
13212 	while ((sp = uu_list_walk_next(elems)) != NULL) {
13213 		if (strcmp(sp->str, str) == 0)
13214 			break;
13215 	}
13216 	uu_list_walk_end(elems);
13217 
13218 	/*
13219 	 * Returning 1 here as the value was not found, this
13220 	 * might not be an error.  Leave it to the caller to
13221 	 * decide.
13222 	 */
13223 	if (sp == NULL) {
13224 		return (1);
13225 	}
13226 
13227 	uu_list_remove(strlist, sp);
13228 
13229 	free(sp->str);
13230 	free(sp);
13231 
13232 	return (0);
13233 }
13234 
13235 /*
13236  * Get all property values that don't match the given glob pattern,
13237  * if a pattern is specified.
13238  */
13239 static void
13240 get_prop_values(scf_property_t *prop, uu_list_t *values,
13241     const char *pattern)
13242 {
13243 	scf_iter_t *iter;
13244 	scf_value_t *val;
13245 	int ret;
13246 
13247 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13248 	    (val = scf_value_create(g_hndl)) == NULL)
13249 		scfdie();
13250 
13251 	if (scf_iter_property_values(iter, prop) != 0)
13252 		scfdie();
13253 
13254 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13255 		char *buf;
13256 		ssize_t vlen, szret;
13257 
13258 		vlen = scf_value_get_as_string(val, NULL, 0);
13259 		if (vlen < 0)
13260 			scfdie();
13261 
13262 		buf = safe_malloc(vlen + 1);
13263 
13264 		szret = scf_value_get_as_string(val, buf, vlen + 1);
13265 		if (szret < 0)
13266 			scfdie();
13267 		assert(szret <= vlen);
13268 
13269 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
13270 			add_string(values, buf);
13271 
13272 		free(buf);
13273 	}
13274 
13275 	if (ret == -1)
13276 		scfdie();
13277 
13278 	scf_value_destroy(val);
13279 	scf_iter_destroy(iter);
13280 }
13281 
13282 static int
13283 lscf_setpropvalue(const char *pgname, const char *type,
13284     const char *arg, int isadd, int isnotfoundok)
13285 {
13286 	scf_type_t ty;
13287 	scf_propertygroup_t *pg;
13288 	scf_property_t *prop;
13289 	int ret, result = 0;
13290 	scf_transaction_t *tx;
13291 	scf_transaction_entry_t *e;
13292 	scf_value_t *v;
13293 	string_list_t *sp;
13294 	char *propname;
13295 	uu_list_t *values;
13296 	uu_list_walk_t *walk;
13297 	void *cookie = NULL;
13298 	char *pattern = NULL;
13299 
13300 	lscf_prep_hndl();
13301 
13302 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
13303 		uu_die(gettext("Could not create property list: %s\n"),
13304 		    uu_strerror(uu_error()));
13305 
13306 	if (!isadd)
13307 		pattern = safe_strdup(arg);
13308 
13309 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13310 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13311 	    (prop = scf_property_create(g_hndl)) == NULL ||
13312 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13313 		scfdie();
13314 
13315 	if (cur_snap != NULL) {
13316 		semerr(emsg_cant_modify_snapshots);
13317 		goto fail;
13318 	}
13319 
13320 	if (cur_inst == NULL && cur_svc == NULL) {
13321 		semerr(emsg_entity_not_selected);
13322 		goto fail;
13323 	}
13324 
13325 	propname = strchr(pgname, '/');
13326 	if (propname == NULL) {
13327 		semerr(gettext("Property names must contain a `/'.\n"));
13328 		goto fail;
13329 	}
13330 
13331 	*propname = '\0';
13332 	++propname;
13333 
13334 	if (type != NULL) {
13335 		ty = string_to_type(type);
13336 		if (ty == SCF_TYPE_INVALID) {
13337 			semerr(gettext("Unknown type \"%s\".\n"), type);
13338 			goto fail;
13339 		}
13340 	}
13341 
13342 	if (cur_inst != NULL)
13343 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13344 	else
13345 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13346 	if (ret != 0) {
13347 		switch (scf_error()) {
13348 		case SCF_ERROR_NOT_FOUND:
13349 			if (isnotfoundok) {
13350 				result = 0;
13351 			} else {
13352 				semerr(emsg_no_such_pg, pgname);
13353 				result = -1;
13354 			}
13355 			goto out;
13356 
13357 		case SCF_ERROR_INVALID_ARGUMENT:
13358 			semerr(emsg_invalid_pg_name, pgname);
13359 			goto fail;
13360 
13361 		default:
13362 			scfdie();
13363 		}
13364 	}
13365 
13366 	do {
13367 		if (scf_pg_update(pg) == -1)
13368 			scfdie();
13369 		if (scf_transaction_start(tx, pg) != 0) {
13370 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13371 				scfdie();
13372 
13373 			semerr(emsg_permission_denied);
13374 			goto fail;
13375 		}
13376 
13377 		ret = scf_pg_get_property(pg, propname, prop);
13378 		if (ret == 0) {
13379 			scf_type_t ptype;
13380 			char *pat = pattern;
13381 
13382 			if (scf_property_type(prop, &ptype) != 0)
13383 				scfdie();
13384 
13385 			if (isadd) {
13386 				if (type != NULL && ptype != ty) {
13387 					semerr(gettext("Property \"%s\" is not "
13388 					    "of type \"%s\".\n"), propname,
13389 					    type);
13390 					goto fail;
13391 				}
13392 
13393 				pat = NULL;
13394 			} else {
13395 				size_t len = strlen(pat);
13396 				if (len > 0 && pat[len - 1] == '\"')
13397 					pat[len - 1] = '\0';
13398 				if (len > 0 && pat[0] == '\"')
13399 					pat++;
13400 			}
13401 
13402 			ty = ptype;
13403 
13404 			get_prop_values(prop, values, pat);
13405 
13406 			if (isadd)
13407 				add_string(values, arg);
13408 
13409 			if (scf_transaction_property_change(tx, e,
13410 			    propname, ty) == -1)
13411 				scfdie();
13412 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13413 			if (isadd) {
13414 				if (type == NULL) {
13415 					semerr(gettext("Type required "
13416 					    "for new properties.\n"));
13417 					goto fail;
13418 				}
13419 
13420 				add_string(values, arg);
13421 
13422 				if (scf_transaction_property_new(tx, e,
13423 				    propname, ty) == -1)
13424 					scfdie();
13425 			} else if (isnotfoundok) {
13426 				result = 0;
13427 				goto out;
13428 			} else {
13429 				semerr(gettext("No such property %s/%s.\n"),
13430 				    pgname, propname);
13431 				result = -1;
13432 				goto out;
13433 			}
13434 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13435 			semerr(emsg_invalid_prop_name, propname);
13436 			goto fail;
13437 		} else {
13438 			scfdie();
13439 		}
13440 
13441 		walk = uu_list_walk_start(values, UU_DEFAULT);
13442 		if (walk == NULL)
13443 			uu_die(gettext("Could not walk property list.\n"));
13444 
13445 		for (sp = uu_list_walk_next(walk); sp != NULL;
13446 		    sp = uu_list_walk_next(walk)) {
13447 			v = string_to_value(sp->str, ty, 0);
13448 
13449 			if (v == NULL) {
13450 				scf_entry_destroy_children(e);
13451 				goto fail;
13452 			}
13453 			ret = scf_entry_add_value(e, v);
13454 			assert(ret == 0);
13455 		}
13456 		uu_list_walk_end(walk);
13457 
13458 		result = scf_transaction_commit(tx);
13459 
13460 		scf_transaction_reset(tx);
13461 		scf_entry_destroy_children(e);
13462 	} while (result == 0);
13463 
13464 	if (result < 0) {
13465 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13466 			scfdie();
13467 
13468 		semerr(emsg_permission_denied);
13469 		goto fail;
13470 	}
13471 
13472 	result = 0;
13473 
13474 	private_refresh();
13475 
13476 out:
13477 	scf_transaction_destroy(tx);
13478 	scf_entry_destroy(e);
13479 	scf_pg_destroy(pg);
13480 	scf_property_destroy(prop);
13481 	free(pattern);
13482 
13483 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
13484 		free(sp->str);
13485 		free(sp);
13486 	}
13487 
13488 	uu_list_destroy(values);
13489 
13490 	return (result);
13491 
13492 fail:
13493 	result = -1;
13494 	goto out;
13495 }
13496 
13497 int
13498 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
13499 {
13500 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
13501 }
13502 
13503 int
13504 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
13505 {
13506 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
13507 }
13508 
13509 /*
13510  * Look for a standard start method, first in the instance (if any),
13511  * then the service.
13512  */
13513 static const char *
13514 start_method_name(int *in_instance)
13515 {
13516 	scf_propertygroup_t *pg;
13517 	char **p;
13518 	int ret;
13519 	scf_instance_t *inst = cur_inst;
13520 
13521 	if ((pg = scf_pg_create(g_hndl)) == NULL)
13522 		scfdie();
13523 
13524 again:
13525 	for (p = start_method_names; *p != NULL; p++) {
13526 		if (inst != NULL)
13527 			ret = scf_instance_get_pg(inst, *p, pg);
13528 		else
13529 			ret = scf_service_get_pg(cur_svc, *p, pg);
13530 
13531 		if (ret == 0) {
13532 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
13533 			char *buf = safe_malloc(bufsz);
13534 
13535 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
13536 				free(buf);
13537 				continue;
13538 			}
13539 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
13540 				free(buf);
13541 				continue;
13542 			}
13543 
13544 			free(buf);
13545 			*in_instance = (inst != NULL);
13546 			scf_pg_destroy(pg);
13547 			return (*p);
13548 		}
13549 
13550 		if (scf_error() == SCF_ERROR_NOT_FOUND)
13551 			continue;
13552 
13553 		scfdie();
13554 	}
13555 
13556 	if (inst != NULL) {
13557 		inst = NULL;
13558 		goto again;
13559 	}
13560 
13561 	scf_pg_destroy(pg);
13562 	return (NULL);
13563 }
13564 
13565 static int
13566 addpg(const char *name, const char *type)
13567 {
13568 	scf_propertygroup_t *pg;
13569 	int ret;
13570 
13571 	pg = scf_pg_create(g_hndl);
13572 	if (pg == NULL)
13573 		scfdie();
13574 
13575 	if (cur_inst != NULL)
13576 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
13577 	else
13578 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
13579 
13580 	if (ret != 0) {
13581 		switch (scf_error()) {
13582 		case SCF_ERROR_EXISTS:
13583 			ret = 0;
13584 			break;
13585 
13586 		case SCF_ERROR_PERMISSION_DENIED:
13587 			semerr(emsg_permission_denied);
13588 			break;
13589 
13590 		default:
13591 			scfdie();
13592 		}
13593 	}
13594 
13595 	scf_pg_destroy(pg);
13596 	return (ret);
13597 }
13598 
13599 int
13600 lscf_setenv(uu_list_t *args, int isunset)
13601 {
13602 	int ret = 0;
13603 	size_t i;
13604 	int argc;
13605 	char **argv = NULL;
13606 	string_list_t *slp;
13607 	char *pattern;
13608 	char *prop;
13609 	int do_service = 0;
13610 	int do_instance = 0;
13611 	const char *method = NULL;
13612 	const char *name = NULL;
13613 	const char *value = NULL;
13614 	scf_instance_t *saved_cur_inst = cur_inst;
13615 
13616 	lscf_prep_hndl();
13617 
13618 	argc = uu_list_numnodes(args);
13619 	if (argc < 1)
13620 		goto usage;
13621 
13622 	argv = calloc(argc + 1, sizeof (char *));
13623 	if (argv == NULL)
13624 		uu_die(gettext("Out of memory.\n"));
13625 
13626 	for (slp = uu_list_first(args), i = 0;
13627 	    slp != NULL;
13628 	    slp = uu_list_next(args, slp), ++i)
13629 		argv[i] = slp->str;
13630 
13631 	argv[i] = NULL;
13632 
13633 	opterr = 0;
13634 	optind = 0;
13635 	for (;;) {
13636 		ret = getopt(argc, argv, "sim:");
13637 		if (ret == -1)
13638 			break;
13639 
13640 		switch (ret) {
13641 		case 's':
13642 			do_service = 1;
13643 			cur_inst = NULL;
13644 			break;
13645 
13646 		case 'i':
13647 			do_instance = 1;
13648 			break;
13649 
13650 		case 'm':
13651 			method = optarg;
13652 			break;
13653 
13654 		case '?':
13655 			goto usage;
13656 
13657 		default:
13658 			bad_error("getopt", ret);
13659 		}
13660 	}
13661 
13662 	argc -= optind;
13663 	if ((do_service && do_instance) ||
13664 	    (isunset && argc != 1) ||
13665 	    (!isunset && argc != 2))
13666 		goto usage;
13667 
13668 	name = argv[optind];
13669 	if (!isunset)
13670 		value = argv[optind + 1];
13671 
13672 	if (cur_snap != NULL) {
13673 		semerr(emsg_cant_modify_snapshots);
13674 		ret = -1;
13675 		goto out;
13676 	}
13677 
13678 	if (cur_inst == NULL && cur_svc == NULL) {
13679 		semerr(emsg_entity_not_selected);
13680 		ret = -1;
13681 		goto out;
13682 	}
13683 
13684 	if (do_instance && cur_inst == NULL) {
13685 		semerr(gettext("No instance is selected.\n"));
13686 		ret = -1;
13687 		goto out;
13688 	}
13689 
13690 	if (do_service && cur_svc == NULL) {
13691 		semerr(gettext("No service is selected.\n"));
13692 		ret = -1;
13693 		goto out;
13694 	}
13695 
13696 	if (method == NULL) {
13697 		if (do_instance || do_service) {
13698 			method = "method_context";
13699 			if (!isunset) {
13700 				ret = addpg("method_context",
13701 				    SCF_GROUP_FRAMEWORK);
13702 				if (ret != 0)
13703 					goto out;
13704 			}
13705 		} else {
13706 			int in_instance;
13707 			method = start_method_name(&in_instance);
13708 			if (method == NULL) {
13709 				semerr(gettext(
13710 				    "Couldn't find start method; please "
13711 				    "specify a method with '-m'.\n"));
13712 				ret = -1;
13713 				goto out;
13714 			}
13715 			if (!in_instance)
13716 				cur_inst = NULL;
13717 		}
13718 	} else {
13719 		scf_propertygroup_t *pg;
13720 		size_t bufsz;
13721 		char *buf;
13722 		int ret;
13723 
13724 		if ((pg = scf_pg_create(g_hndl)) == NULL)
13725 			scfdie();
13726 
13727 		if (cur_inst != NULL)
13728 			ret = scf_instance_get_pg(cur_inst, method, pg);
13729 		else
13730 			ret = scf_service_get_pg(cur_svc, method, pg);
13731 
13732 		if (ret != 0) {
13733 			scf_pg_destroy(pg);
13734 			switch (scf_error()) {
13735 			case SCF_ERROR_NOT_FOUND:
13736 				semerr(gettext("Couldn't find the method "
13737 				    "\"%s\".\n"), method);
13738 				goto out;
13739 
13740 			case SCF_ERROR_INVALID_ARGUMENT:
13741 				semerr(gettext("Invalid method name \"%s\".\n"),
13742 				    method);
13743 				goto out;
13744 
13745 			default:
13746 				scfdie();
13747 			}
13748 		}
13749 
13750 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
13751 		buf = safe_malloc(bufsz);
13752 
13753 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
13754 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
13755 			semerr(gettext("Property group \"%s\" is not of type "
13756 			    "\"method\".\n"), method);
13757 			ret = -1;
13758 			free(buf);
13759 			scf_pg_destroy(pg);
13760 			goto out;
13761 		}
13762 
13763 		free(buf);
13764 		scf_pg_destroy(pg);
13765 	}
13766 
13767 	prop = uu_msprintf("%s/environment", method);
13768 	pattern = uu_msprintf("%s=*", name);
13769 
13770 	if (prop == NULL || pattern == NULL)
13771 		uu_die(gettext("Out of memory.\n"));
13772 
13773 	ret = lscf_delpropvalue(prop, pattern, !isunset);
13774 
13775 	if (ret == 0 && !isunset) {
13776 		uu_free(pattern);
13777 		uu_free(prop);
13778 		prop = uu_msprintf("%s/environment", method);
13779 		pattern = uu_msprintf("%s=%s", name, value);
13780 		if (prop == NULL || pattern == NULL)
13781 			uu_die(gettext("Out of memory.\n"));
13782 		ret = lscf_addpropvalue(prop, "astring:", pattern);
13783 	}
13784 	uu_free(pattern);
13785 	uu_free(prop);
13786 
13787 out:
13788 	cur_inst = saved_cur_inst;
13789 
13790 	free(argv);
13791 	return (ret);
13792 usage:
13793 	ret = -2;
13794 	goto out;
13795 }
13796 
13797 /*
13798  * Snapshot commands
13799  */
13800 
13801 void
13802 lscf_listsnap()
13803 {
13804 	scf_snapshot_t *snap;
13805 	scf_iter_t *iter;
13806 	char *nb;
13807 	int r;
13808 
13809 	lscf_prep_hndl();
13810 
13811 	if (cur_inst == NULL) {
13812 		semerr(gettext("Instance not selected.\n"));
13813 		return;
13814 	}
13815 
13816 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13817 	    (iter = scf_iter_create(g_hndl)) == NULL)
13818 		scfdie();
13819 
13820 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
13821 		scfdie();
13822 
13823 	nb = safe_malloc(max_scf_name_len + 1);
13824 
13825 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
13826 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
13827 			scfdie();
13828 
13829 		(void) puts(nb);
13830 	}
13831 	if (r < 0)
13832 		scfdie();
13833 
13834 	free(nb);
13835 	scf_iter_destroy(iter);
13836 	scf_snapshot_destroy(snap);
13837 }
13838 
13839 void
13840 lscf_selectsnap(const char *name)
13841 {
13842 	scf_snapshot_t *snap;
13843 	scf_snaplevel_t *level;
13844 
13845 	lscf_prep_hndl();
13846 
13847 	if (cur_inst == NULL) {
13848 		semerr(gettext("Instance not selected.\n"));
13849 		return;
13850 	}
13851 
13852 	if (cur_snap != NULL) {
13853 		if (name != NULL) {
13854 			char *cur_snap_name;
13855 			boolean_t nochange;
13856 
13857 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
13858 
13859 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
13860 			    max_scf_name_len + 1) < 0)
13861 				scfdie();
13862 
13863 			nochange = strcmp(name, cur_snap_name) == 0;
13864 
13865 			free(cur_snap_name);
13866 
13867 			if (nochange)
13868 				return;
13869 		}
13870 
13871 		unselect_cursnap();
13872 	}
13873 
13874 	if (name == NULL)
13875 		return;
13876 
13877 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13878 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
13879 		scfdie();
13880 
13881 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
13882 	    SCF_SUCCESS) {
13883 		switch (scf_error()) {
13884 		case SCF_ERROR_INVALID_ARGUMENT:
13885 			semerr(gettext("Invalid name \"%s\".\n"), name);
13886 			break;
13887 
13888 		case SCF_ERROR_NOT_FOUND:
13889 			semerr(gettext("No such snapshot \"%s\".\n"), name);
13890 			break;
13891 
13892 		default:
13893 			scfdie();
13894 		}
13895 
13896 		scf_snaplevel_destroy(level);
13897 		scf_snapshot_destroy(snap);
13898 		return;
13899 	}
13900 
13901 	/* Load the snaplevels into our list. */
13902 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
13903 	if (cur_levels == NULL)
13904 		uu_die(gettext("Could not create list: %s\n"),
13905 		    uu_strerror(uu_error()));
13906 
13907 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13908 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13909 			scfdie();
13910 
13911 		semerr(gettext("Snapshot has no snaplevels.\n"));
13912 
13913 		scf_snaplevel_destroy(level);
13914 		scf_snapshot_destroy(snap);
13915 		return;
13916 	}
13917 
13918 	cur_snap = snap;
13919 
13920 	for (;;) {
13921 		cur_elt = safe_malloc(sizeof (*cur_elt));
13922 		uu_list_node_init(cur_elt, &cur_elt->list_node,
13923 		    snaplevel_pool);
13924 		cur_elt->sl = level;
13925 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
13926 			uu_die(gettext("libuutil error: %s\n"),
13927 			    uu_strerror(uu_error()));
13928 
13929 		level = scf_snaplevel_create(g_hndl);
13930 		if (level == NULL)
13931 			scfdie();
13932 
13933 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
13934 		    level) != SCF_SUCCESS) {
13935 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13936 				scfdie();
13937 
13938 			scf_snaplevel_destroy(level);
13939 			break;
13940 		}
13941 	}
13942 
13943 	cur_elt = uu_list_last(cur_levels);
13944 	cur_level = cur_elt->sl;
13945 }
13946 
13947 /*
13948  * Copies the properties & values in src to dst.  Assumes src won't change.
13949  * Returns -1 if permission is denied, -2 if another transaction interrupts,
13950  * and 0 on success.
13951  *
13952  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
13953  * property, if it is copied and has type boolean.  (See comment in
13954  * lscf_revert()).
13955  */
13956 static int
13957 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
13958     uint8_t enabled)
13959 {
13960 	scf_transaction_t *tx;
13961 	scf_iter_t *iter, *viter;
13962 	scf_property_t *prop;
13963 	scf_value_t *v;
13964 	char *nbuf;
13965 	int r;
13966 
13967 	tx = scf_transaction_create(g_hndl);
13968 	if (tx == NULL)
13969 		scfdie();
13970 
13971 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
13972 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13973 			scfdie();
13974 
13975 		scf_transaction_destroy(tx);
13976 
13977 		return (-1);
13978 	}
13979 
13980 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13981 	    (prop = scf_property_create(g_hndl)) == NULL ||
13982 	    (viter = scf_iter_create(g_hndl)) == NULL)
13983 		scfdie();
13984 
13985 	nbuf = safe_malloc(max_scf_name_len + 1);
13986 
13987 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
13988 		scfdie();
13989 
13990 	for (;;) {
13991 		scf_transaction_entry_t *e;
13992 		scf_type_t ty;
13993 
13994 		r = scf_iter_next_property(iter, prop);
13995 		if (r == -1)
13996 			scfdie();
13997 		if (r == 0)
13998 			break;
13999 
14000 		e = scf_entry_create(g_hndl);
14001 		if (e == NULL)
14002 			scfdie();
14003 
14004 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14005 			scfdie();
14006 
14007 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14008 			scfdie();
14009 
14010 		if (scf_transaction_property_new(tx, e, nbuf,
14011 		    ty) != SCF_SUCCESS)
14012 			scfdie();
14013 
14014 		if ((enabled == 0 || enabled == 1) &&
14015 		    strcmp(nbuf, scf_property_enabled) == 0 &&
14016 		    ty == SCF_TYPE_BOOLEAN) {
14017 			v = scf_value_create(g_hndl);
14018 			if (v == NULL)
14019 				scfdie();
14020 
14021 			scf_value_set_boolean(v, enabled);
14022 
14023 			if (scf_entry_add_value(e, v) != 0)
14024 				scfdie();
14025 		} else {
14026 			if (scf_iter_property_values(viter, prop) != 0)
14027 				scfdie();
14028 
14029 			for (;;) {
14030 				v = scf_value_create(g_hndl);
14031 				if (v == NULL)
14032 					scfdie();
14033 
14034 				r = scf_iter_next_value(viter, v);
14035 				if (r == -1)
14036 					scfdie();
14037 				if (r == 0) {
14038 					scf_value_destroy(v);
14039 					break;
14040 				}
14041 
14042 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14043 					scfdie();
14044 			}
14045 		}
14046 	}
14047 
14048 	free(nbuf);
14049 	scf_iter_destroy(viter);
14050 	scf_property_destroy(prop);
14051 	scf_iter_destroy(iter);
14052 
14053 	r = scf_transaction_commit(tx);
14054 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
14055 		scfdie();
14056 
14057 	scf_transaction_destroy_children(tx);
14058 	scf_transaction_destroy(tx);
14059 
14060 	switch (r) {
14061 	case 1:		return (0);
14062 	case 0:		return (-2);
14063 	case -1:	return (-1);
14064 
14065 	default:
14066 		abort();
14067 	}
14068 
14069 	/* NOTREACHED */
14070 }
14071 
14072 void
14073 lscf_revert(const char *snapname)
14074 {
14075 	scf_snapshot_t *snap, *prev;
14076 	scf_snaplevel_t *level, *nlevel;
14077 	scf_iter_t *iter;
14078 	scf_propertygroup_t *pg, *npg;
14079 	scf_property_t *prop;
14080 	scf_value_t *val;
14081 	char *nbuf, *tbuf;
14082 	uint8_t enabled;
14083 
14084 	lscf_prep_hndl();
14085 
14086 	if (cur_inst == NULL) {
14087 		semerr(gettext("Instance not selected.\n"));
14088 		return;
14089 	}
14090 
14091 	if (snapname != NULL) {
14092 		snap = scf_snapshot_create(g_hndl);
14093 		if (snap == NULL)
14094 			scfdie();
14095 
14096 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
14097 		    SCF_SUCCESS) {
14098 			switch (scf_error()) {
14099 			case SCF_ERROR_INVALID_ARGUMENT:
14100 				semerr(gettext("Invalid snapshot name "
14101 				    "\"%s\".\n"), snapname);
14102 				break;
14103 
14104 			case SCF_ERROR_NOT_FOUND:
14105 				semerr(gettext("No such snapshot.\n"));
14106 				break;
14107 
14108 			default:
14109 				scfdie();
14110 			}
14111 
14112 			scf_snapshot_destroy(snap);
14113 			return;
14114 		}
14115 	} else {
14116 		if (cur_snap != NULL) {
14117 			snap = cur_snap;
14118 		} else {
14119 			semerr(gettext("No snapshot selected.\n"));
14120 			return;
14121 		}
14122 	}
14123 
14124 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
14125 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
14126 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14127 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14128 	    (npg = scf_pg_create(g_hndl)) == NULL ||
14129 	    (prop = scf_property_create(g_hndl)) == NULL ||
14130 	    (val = scf_value_create(g_hndl)) == NULL)
14131 		scfdie();
14132 
14133 	nbuf = safe_malloc(max_scf_name_len + 1);
14134 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
14135 
14136 	/* Take the "previous" snapshot before we blow away the properties. */
14137 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
14138 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
14139 			scfdie();
14140 	} else {
14141 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14142 			scfdie();
14143 
14144 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
14145 			scfdie();
14146 	}
14147 
14148 	/* Save general/enabled, since we're probably going to replace it. */
14149 	enabled = 2;
14150 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
14151 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
14152 	    scf_property_get_value(prop, val) == 0)
14153 		(void) scf_value_get_boolean(val, &enabled);
14154 
14155 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14156 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14157 			scfdie();
14158 
14159 		goto out;
14160 	}
14161 
14162 	for (;;) {
14163 		boolean_t isinst;
14164 		uint32_t flags;
14165 		int r;
14166 
14167 		/* Clear the properties from the corresponding entity. */
14168 		isinst = snaplevel_is_instance(level);
14169 
14170 		if (!isinst)
14171 			r = scf_iter_service_pgs(iter, cur_svc);
14172 		else
14173 			r = scf_iter_instance_pgs(iter, cur_inst);
14174 		if (r != SCF_SUCCESS)
14175 			scfdie();
14176 
14177 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14178 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14179 				scfdie();
14180 
14181 			/* Skip nonpersistent pgs. */
14182 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
14183 				continue;
14184 
14185 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
14186 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14187 					scfdie();
14188 
14189 				semerr(emsg_permission_denied);
14190 				goto out;
14191 			}
14192 		}
14193 		if (r == -1)
14194 			scfdie();
14195 
14196 		/* Copy the properties to the corresponding entity. */
14197 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
14198 			scfdie();
14199 
14200 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14201 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
14202 				scfdie();
14203 
14204 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
14205 			    0)
14206 				scfdie();
14207 
14208 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14209 				scfdie();
14210 
14211 			if (!isinst)
14212 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
14213 				    flags, npg);
14214 			else
14215 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
14216 				    flags, npg);
14217 			if (r != SCF_SUCCESS) {
14218 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14219 					scfdie();
14220 
14221 				semerr(emsg_permission_denied);
14222 				goto out;
14223 			}
14224 
14225 			if ((enabled == 0 || enabled == 1) &&
14226 			    strcmp(nbuf, scf_pg_general) == 0)
14227 				r = pg_copy(pg, npg, enabled);
14228 			else
14229 				r = pg_copy(pg, npg, 2);
14230 
14231 			switch (r) {
14232 			case 0:
14233 				break;
14234 
14235 			case -1:
14236 				semerr(emsg_permission_denied);
14237 				goto out;
14238 
14239 			case -2:
14240 				semerr(gettext(
14241 				    "Interrupted by another change.\n"));
14242 				goto out;
14243 
14244 			default:
14245 				abort();
14246 			}
14247 		}
14248 		if (r == -1)
14249 			scfdie();
14250 
14251 		/* Get next level. */
14252 		nlevel = scf_snaplevel_create(g_hndl);
14253 		if (nlevel == NULL)
14254 			scfdie();
14255 
14256 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
14257 		    SCF_SUCCESS) {
14258 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14259 				scfdie();
14260 
14261 			scf_snaplevel_destroy(nlevel);
14262 			break;
14263 		}
14264 
14265 		scf_snaplevel_destroy(level);
14266 		level = nlevel;
14267 	}
14268 
14269 	if (snapname == NULL) {
14270 		lscf_selectsnap(NULL);
14271 		snap = NULL;		/* cur_snap has been destroyed */
14272 	}
14273 
14274 out:
14275 	free(tbuf);
14276 	free(nbuf);
14277 	scf_value_destroy(val);
14278 	scf_property_destroy(prop);
14279 	scf_pg_destroy(npg);
14280 	scf_pg_destroy(pg);
14281 	scf_iter_destroy(iter);
14282 	scf_snaplevel_destroy(level);
14283 	scf_snapshot_destroy(prev);
14284 	if (snap != cur_snap)
14285 		scf_snapshot_destroy(snap);
14286 }
14287 
14288 void
14289 lscf_refresh(void)
14290 {
14291 	ssize_t fmrilen;
14292 	size_t bufsz;
14293 	char *fmribuf;
14294 	int r;
14295 
14296 	lscf_prep_hndl();
14297 
14298 	if (cur_inst == NULL) {
14299 		semerr(gettext("Instance not selected.\n"));
14300 		return;
14301 	}
14302 
14303 	bufsz = max_scf_fmri_len + 1;
14304 	fmribuf = safe_malloc(bufsz);
14305 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
14306 	if (fmrilen < 0) {
14307 		free(fmribuf);
14308 		if (scf_error() != SCF_ERROR_DELETED)
14309 			scfdie();
14310 		scf_instance_destroy(cur_inst);
14311 		cur_inst = NULL;
14312 		warn(emsg_deleted);
14313 		return;
14314 	}
14315 	assert(fmrilen < bufsz);
14316 
14317 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
14318 	switch (r) {
14319 	case 0:
14320 		break;
14321 
14322 	case ECONNABORTED:
14323 		warn(gettext("Could not refresh %s "
14324 		    "(repository connection broken).\n"), fmribuf);
14325 		break;
14326 
14327 	case ECANCELED:
14328 		warn(emsg_deleted);
14329 		break;
14330 
14331 	case EPERM:
14332 		warn(gettext("Could not refresh %s "
14333 		    "(permission denied).\n"), fmribuf);
14334 		break;
14335 
14336 	case ENOSPC:
14337 		warn(gettext("Could not refresh %s "
14338 		    "(repository server out of resources).\n"),
14339 		    fmribuf);
14340 		break;
14341 
14342 	case EACCES:
14343 	default:
14344 		bad_error("refresh_entity", scf_error());
14345 	}
14346 
14347 	free(fmribuf);
14348 }
14349 
14350 /*
14351  * describe [-v] [-t] [pg/prop]
14352  */
14353 int
14354 lscf_describe(uu_list_t *args, int hasargs)
14355 {
14356 	int ret = 0;
14357 	size_t i;
14358 	int argc;
14359 	char **argv = NULL;
14360 	string_list_t *slp;
14361 	int do_verbose = 0;
14362 	int do_templates = 0;
14363 	char *pattern = NULL;
14364 
14365 	lscf_prep_hndl();
14366 
14367 	if (hasargs != 0)  {
14368 		argc = uu_list_numnodes(args);
14369 		if (argc < 1)
14370 			goto usage;
14371 
14372 		argv = calloc(argc + 1, sizeof (char *));
14373 		if (argv == NULL)
14374 			uu_die(gettext("Out of memory.\n"));
14375 
14376 		for (slp = uu_list_first(args), i = 0;
14377 		    slp != NULL;
14378 		    slp = uu_list_next(args, slp), ++i)
14379 			argv[i] = slp->str;
14380 
14381 		argv[i] = NULL;
14382 
14383 		/*
14384 		 * We start optind = 0 because our list of arguments
14385 		 * starts at argv[0]
14386 		 */
14387 		optind = 0;
14388 		opterr = 0;
14389 		for (;;) {
14390 			ret = getopt(argc, argv, "vt");
14391 			if (ret == -1)
14392 				break;
14393 
14394 			switch (ret) {
14395 			case 'v':
14396 				do_verbose = 1;
14397 				break;
14398 
14399 			case 't':
14400 				do_templates = 1;
14401 				break;
14402 
14403 			case '?':
14404 				goto usage;
14405 
14406 			default:
14407 				bad_error("getopt", ret);
14408 			}
14409 		}
14410 
14411 		pattern = argv[optind];
14412 	}
14413 
14414 	if (cur_inst == NULL && cur_svc == NULL) {
14415 		semerr(emsg_entity_not_selected);
14416 		ret = -1;
14417 		goto out;
14418 	}
14419 
14420 	/*
14421 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
14422 	 * output if their last parameter is set to 2.  Less information is
14423 	 * produced if the parameter is set to 1.
14424 	 */
14425 	if (pattern == NULL) {
14426 		if (do_verbose == 1)
14427 			list_entity_tmpl(2);
14428 		else
14429 			list_entity_tmpl(1);
14430 	}
14431 
14432 	if (do_templates == 0) {
14433 		if (do_verbose == 1)
14434 			listprop(pattern, 0, 2);
14435 		else
14436 			listprop(pattern, 0, 1);
14437 	} else {
14438 		if (do_verbose == 1)
14439 			listtmpl(pattern, 2);
14440 		else
14441 			listtmpl(pattern, 1);
14442 	}
14443 
14444 	ret = 0;
14445 out:
14446 	if (argv != NULL)
14447 		free(argv);
14448 	return (ret);
14449 usage:
14450 	ret = -2;
14451 	goto out;
14452 }
14453 
14454 /*
14455  * Creates a list of instance name strings associated with a service. If
14456  * wohandcrafted flag is set, get only instances that have a last-import
14457  * snapshot, instances that were imported via svccfg.
14458  */
14459 static uu_list_t *
14460 create_instance_list(scf_service_t *svc, int wohandcrafted)
14461 {
14462 	scf_snapshot_t  *snap = NULL;
14463 	scf_instance_t  *inst;
14464 	scf_iter_t	*inst_iter;
14465 	uu_list_t	*instances;
14466 	char		*instname;
14467 	int		r;
14468 
14469 	inst_iter = scf_iter_create(g_hndl);
14470 	inst = scf_instance_create(g_hndl);
14471 	if (inst_iter == NULL || inst == NULL) {
14472 		uu_warn(gettext("Could not create instance or iterator\n"));
14473 		scfdie();
14474 	}
14475 
14476 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
14477 		return (instances);
14478 
14479 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
14480 		switch (scf_error()) {
14481 		case SCF_ERROR_CONNECTION_BROKEN:
14482 		case SCF_ERROR_DELETED:
14483 			uu_list_destroy(instances);
14484 			instances = NULL;
14485 			goto out;
14486 
14487 		case SCF_ERROR_HANDLE_MISMATCH:
14488 		case SCF_ERROR_NOT_BOUND:
14489 		case SCF_ERROR_NOT_SET:
14490 		default:
14491 			bad_error("scf_iter_service_instances", scf_error());
14492 		}
14493 	}
14494 
14495 	instname = safe_malloc(max_scf_name_len + 1);
14496 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
14497 		if (r == -1) {
14498 			(void) uu_warn(gettext("Unable to iterate through "
14499 			    "instances to create instance list : %s\n"),
14500 			    scf_strerror(scf_error()));
14501 
14502 			uu_list_destroy(instances);
14503 			instances = NULL;
14504 			goto out;
14505 		}
14506 
14507 		/*
14508 		 * If the instance does not have a last-import snapshot
14509 		 * then do not add it to the list as it is a hand-crafted
14510 		 * instance that should not be managed.
14511 		 */
14512 		if (wohandcrafted) {
14513 			if (snap == NULL &&
14514 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
14515 				uu_warn(gettext("Unable to create snapshot "
14516 				    "entity\n"));
14517 				scfdie();
14518 			}
14519 
14520 			if (scf_instance_get_snapshot(inst,
14521 			    snap_lastimport, snap) != 0) {
14522 				switch (scf_error()) {
14523 				case SCF_ERROR_NOT_FOUND :
14524 				case SCF_ERROR_DELETED:
14525 					continue;
14526 
14527 				case SCF_ERROR_CONNECTION_BROKEN:
14528 					uu_list_destroy(instances);
14529 					instances = NULL;
14530 					goto out;
14531 
14532 				case SCF_ERROR_HANDLE_MISMATCH:
14533 				case SCF_ERROR_NOT_BOUND:
14534 				case SCF_ERROR_NOT_SET:
14535 				default:
14536 					bad_error("scf_iter_service_instances",
14537 					    scf_error());
14538 				}
14539 			}
14540 		}
14541 
14542 		if (scf_instance_get_name(inst, instname,
14543 		    max_scf_name_len + 1) < 0) {
14544 			switch (scf_error()) {
14545 			case SCF_ERROR_NOT_FOUND :
14546 				continue;
14547 
14548 			case SCF_ERROR_CONNECTION_BROKEN:
14549 			case SCF_ERROR_DELETED:
14550 				uu_list_destroy(instances);
14551 				instances = NULL;
14552 				goto out;
14553 
14554 			case SCF_ERROR_HANDLE_MISMATCH:
14555 			case SCF_ERROR_NOT_BOUND:
14556 			case SCF_ERROR_NOT_SET:
14557 			default:
14558 				bad_error("scf_iter_service_instances",
14559 				    scf_error());
14560 			}
14561 		}
14562 
14563 		add_string(instances, instname);
14564 	}
14565 
14566 out:
14567 	if (snap)
14568 		scf_snapshot_destroy(snap);
14569 
14570 	scf_instance_destroy(inst);
14571 	scf_iter_destroy(inst_iter);
14572 	free(instname);
14573 	return (instances);
14574 }
14575 
14576 /*
14577  * disable an instance but wait for the instance to
14578  * move out of the running state.
14579  *
14580  * Returns 0 : if the instance did not disable
14581  * Returns non-zero : if the instance disabled.
14582  *
14583  */
14584 static int
14585 disable_instance(scf_instance_t *instance)
14586 {
14587 	char	*fmribuf;
14588 	int	enabled = 10000;
14589 
14590 	if (inst_is_running(instance)) {
14591 		fmribuf = safe_malloc(max_scf_name_len + 1);
14592 		if (scf_instance_to_fmri(instance, fmribuf,
14593 		    max_scf_name_len + 1) < 0) {
14594 			free(fmribuf);
14595 			return (0);
14596 		}
14597 
14598 		/*
14599 		 * If the instance cannot be disabled then return
14600 		 * failure to disable and let the caller decide
14601 		 * if that is of importance.
14602 		 */
14603 		if (smf_disable_instance(fmribuf, 0) != 0) {
14604 			free(fmribuf);
14605 			return (0);
14606 		}
14607 
14608 		while (enabled) {
14609 			if (!inst_is_running(instance))
14610 				break;
14611 
14612 			(void) poll(NULL, 0, 5);
14613 			enabled = enabled - 5;
14614 		}
14615 
14616 		free(fmribuf);
14617 	}
14618 
14619 	return (enabled);
14620 }
14621 
14622 /*
14623  * Function to compare two service_manifest structures.
14624  */
14625 /* ARGSUSED2 */
14626 static int
14627 service_manifest_compare(const void *left, const void *right, void *unused)
14628 {
14629 	service_manifest_t *l = (service_manifest_t *)left;
14630 	service_manifest_t *r = (service_manifest_t *)right;
14631 	int rc;
14632 
14633 	rc = strcmp(l->servicename, r->servicename);
14634 
14635 	return (rc);
14636 }
14637 
14638 /*
14639  * Look for the provided service in the service to manifest
14640  * tree.  If the service exists, and a manifest was provided
14641  * then add the manifest to that service.  If the service
14642  * does not exist, then add the service and manifest to the
14643  * list.
14644  *
14645  * If the manifest is NULL, return the element if found.  If
14646  * the service is not found return NULL.
14647  */
14648 service_manifest_t *
14649 find_add_svc_mfst(const char *svnbuf, const char *mfst)
14650 {
14651 	service_manifest_t	elem;
14652 	service_manifest_t	*fnelem;
14653 	uu_avl_index_t		marker;
14654 
14655 	elem.servicename = svnbuf;
14656 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
14657 
14658 	if (mfst) {
14659 		if (fnelem) {
14660 			add_string(fnelem->mfstlist, strdup(mfst));
14661 		} else {
14662 			fnelem = safe_malloc(sizeof (*fnelem));
14663 			fnelem->servicename = safe_strdup(svnbuf);
14664 			if ((fnelem->mfstlist =
14665 			    uu_list_create(string_pool, NULL, 0)) == NULL)
14666 				uu_die(gettext("Could not create property "
14667 				    "list: %s\n"), uu_strerror(uu_error()));
14668 
14669 			add_string(fnelem->mfstlist, safe_strdup(mfst));
14670 
14671 			uu_avl_insert(service_manifest_tree, fnelem, marker);
14672 		}
14673 	}
14674 
14675 	return (fnelem);
14676 }
14677 
14678 /*
14679  * Create the service to manifest avl tree.
14680  *
14681  * Walk each of the manifests currently installed in the supported
14682  * directories, /lib/svc/manifests and /var/svc/manifests.  For
14683  * each of the manifests, inventory the services and add them to
14684  * the tree.
14685  *
14686  * Code that calls this function should make sure fileystem/minimal is online,
14687  * /var is available, since this function walks the /var/svc/manifest directory.
14688  */
14689 static void
14690 create_manifest_tree(void)
14691 {
14692 	manifest_info_t **entry;
14693 	manifest_info_t **manifests;
14694 	uu_list_walk_t	*svcs;
14695 	bundle_t	*b;
14696 	entity_t	*mfsvc;
14697 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
14698 	int		c, status;
14699 
14700 	if (service_manifest_pool)
14701 		return;
14702 
14703 	/*
14704 	 * Create the list pool for the service manifest list
14705 	 */
14706 	service_manifest_pool = uu_avl_pool_create("service_manifest",
14707 	    sizeof (service_manifest_t),
14708 	    offsetof(service_manifest_t, svcmfst_node),
14709 	    service_manifest_compare, UU_DEFAULT);
14710 	if (service_manifest_pool == NULL)
14711 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
14712 		    uu_strerror(uu_error()));
14713 
14714 	/*
14715 	 * Create the list
14716 	 */
14717 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
14718 	    UU_DEFAULT);
14719 	if (service_manifest_tree == NULL)
14720 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
14721 		    uu_strerror(uu_error()));
14722 
14723 	/*
14724 	 * Walk the manifests adding the service(s) from each manifest.
14725 	 *
14726 	 * If a service already exists add the manifest to the manifest
14727 	 * list for that service.  This covers the case of a service that
14728 	 * is supported by multiple manifest files.
14729 	 */
14730 	for (c = 0; dirs[c]; c++) {
14731 		status = find_manifests(dirs[c], &manifests, CHECKEXT);
14732 		if (status < 0) {
14733 			uu_warn(gettext("file tree walk of %s encountered "
14734 			    "error %s\n"), dirs[c], strerror(errno));
14735 
14736 			uu_avl_destroy(service_manifest_tree);
14737 			service_manifest_tree = NULL;
14738 			return;
14739 		}
14740 
14741 		/*
14742 		 * If a manifest that was in the list is not found
14743 		 * then skip and go to the next manifest file.
14744 		 */
14745 		if (manifests != NULL) {
14746 			for (entry = manifests; *entry != NULL; entry++) {
14747 				b = internal_bundle_new();
14748 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
14749 				    SVCCFG_OP_IMPORT) != 0) {
14750 					internal_bundle_free(b);
14751 					continue;
14752 				}
14753 
14754 				svcs = uu_list_walk_start(b->sc_bundle_services,
14755 				    0);
14756 				if (svcs == NULL) {
14757 					internal_bundle_free(b);
14758 					continue;
14759 				}
14760 
14761 				while ((mfsvc = uu_list_walk_next(svcs)) !=
14762 				    NULL) {
14763 					/* Add manifest to service */
14764 					(void) find_add_svc_mfst(mfsvc->sc_name,
14765 					    (*entry)->mi_path);
14766 				}
14767 
14768 				uu_list_walk_end(svcs);
14769 				internal_bundle_free(b);
14770 			}
14771 
14772 			free_manifest_array(manifests);
14773 		}
14774 	}
14775 }
14776 
14777 /*
14778  * Check the manifest history file to see
14779  * if the service was ever installed from
14780  * one of the supported directories.
14781  *
14782  * Return Values :
14783  * 	-1 - if there's error reading manifest history file
14784  *	 1 - if the service is not found
14785  *	 0 - if the service is found
14786  */
14787 static int
14788 check_mfst_history(const char *svcname)
14789 {
14790 	struct stat	st;
14791 	caddr_t		mfsthist_start;
14792 	char		*svnbuf;
14793 	int		fd;
14794 	int		r = 1;
14795 
14796 	fd = open(MFSTHISTFILE, O_RDONLY);
14797 	if (fd == -1) {
14798 		uu_warn(gettext("Unable to open the history file\n"));
14799 		return (-1);
14800 	}
14801 
14802 	if (fstat(fd, &st) == -1) {
14803 		uu_warn(gettext("Unable to stat the history file\n"));
14804 		return (-1);
14805 	}
14806 
14807 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
14808 	    MAP_PRIVATE, fd, 0);
14809 
14810 	(void) close(fd);
14811 	if (mfsthist_start == MAP_FAILED ||
14812 	    *(mfsthist_start + st.st_size) != '\0') {
14813 		(void) munmap(mfsthist_start, st.st_size);
14814 		return (-1);
14815 	}
14816 
14817 	/*
14818 	 * The manifest history file is a space delimited list
14819 	 * of service and instance to manifest linkage.  Adding
14820 	 * a space to the end of the service name so to get only
14821 	 * the service that is being searched for.
14822 	 */
14823 	svnbuf = uu_msprintf("%s ", svcname);
14824 	if (svnbuf == NULL)
14825 		uu_die(gettext("Out of memory"));
14826 
14827 	if (strstr(mfsthist_start, svnbuf) != NULL)
14828 		r = 0;
14829 
14830 	(void) munmap(mfsthist_start, st.st_size);
14831 	uu_free(svnbuf);
14832 	return (r);
14833 }
14834 
14835 /*
14836  * Take down each of the instances in the service
14837  * and remove them, then delete the service.
14838  */
14839 static void
14840 teardown_service(scf_service_t *svc, const char *svnbuf)
14841 {
14842 	scf_instance_t	*instance;
14843 	scf_iter_t	*iter;
14844 	int		r;
14845 
14846 	safe_printf(gettext("Delete service %s as there are no "
14847 	    "supporting manifests\n"), svnbuf);
14848 
14849 	instance = scf_instance_create(g_hndl);
14850 	iter = scf_iter_create(g_hndl);
14851 	if (iter == NULL || instance == NULL) {
14852 		uu_warn(gettext("Unable to create supporting entities to "
14853 		    "teardown the service\n"));
14854 		uu_warn(gettext("scf error is : %s\n"),
14855 		    scf_strerror(scf_error()));
14856 		scfdie();
14857 	}
14858 
14859 	if (scf_iter_service_instances(iter, svc) != 0) {
14860 		switch (scf_error()) {
14861 		case SCF_ERROR_CONNECTION_BROKEN:
14862 		case SCF_ERROR_DELETED:
14863 			goto out;
14864 
14865 		case SCF_ERROR_HANDLE_MISMATCH:
14866 		case SCF_ERROR_NOT_BOUND:
14867 		case SCF_ERROR_NOT_SET:
14868 		default:
14869 			bad_error("scf_iter_service_instances",
14870 			    scf_error());
14871 		}
14872 	}
14873 
14874 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
14875 		if (r == -1) {
14876 			uu_warn(gettext("Error - %s\n"),
14877 			    scf_strerror(scf_error()));
14878 			goto out;
14879 		}
14880 
14881 		(void) disable_instance(instance);
14882 	}
14883 
14884 	/*
14885 	 * Delete the service... forcing the deletion in case
14886 	 * any of the instances did not disable.
14887 	 */
14888 	(void) lscf_service_delete(svc, 1);
14889 out:
14890 	scf_instance_destroy(instance);
14891 	scf_iter_destroy(iter);
14892 }
14893 
14894 /*
14895  * Get the list of instances supported by the manifest
14896  * file.
14897  *
14898  * Return 0 if there are no instances.
14899  *
14900  * Return -1 if there are errors attempting to collect instances.
14901  *
14902  * Return the count of instances found if there are no errors.
14903  *
14904  */
14905 static int
14906 check_instance_support(char *mfstfile, const char *svcname,
14907     uu_list_t *instances)
14908 {
14909 	uu_list_walk_t	*svcs, *insts;
14910 	uu_list_t	*ilist;
14911 	bundle_t	*b;
14912 	entity_t	*mfsvc, *mfinst;
14913 	const char	*svcn;
14914 	int		rminstcnt = 0;
14915 
14916 
14917 	b = internal_bundle_new();
14918 
14919 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
14920 		/*
14921 		 * Unable to process the manifest file for
14922 		 * instance support, so just return as
14923 		 * don't want to remove instances that could
14924 		 * not be accounted for that might exist here.
14925 		 */
14926 		internal_bundle_free(b);
14927 		return (0);
14928 	}
14929 
14930 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
14931 	if (svcs == NULL) {
14932 		internal_bundle_free(b);
14933 		return (0);
14934 	}
14935 
14936 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
14937 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
14938 
14939 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
14940 		if (strcmp(mfsvc->sc_name, svcn) == 0)
14941 			break;
14942 	}
14943 	uu_list_walk_end(svcs);
14944 
14945 	if (mfsvc == NULL) {
14946 		internal_bundle_free(b);
14947 		return (-1);
14948 	}
14949 
14950 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
14951 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
14952 		internal_bundle_free(b);
14953 		return (0);
14954 	}
14955 
14956 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
14957 		/*
14958 		 * Remove the instance from the instances list.
14959 		 * The unaccounted for instances will be removed
14960 		 * from the service once all manifests are
14961 		 * processed.
14962 		 */
14963 		(void) remove_string(instances,
14964 		    mfinst->sc_name);
14965 		rminstcnt++;
14966 	}
14967 
14968 	uu_list_walk_end(insts);
14969 	internal_bundle_free(b);
14970 
14971 	return (rminstcnt);
14972 }
14973 
14974 /*
14975  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
14976  * 'false' to indicate there's no manifest file(s) found for the service.
14977  */
14978 static void
14979 svc_add_no_support(scf_service_t *svc)
14980 {
14981 	char	*pname;
14982 
14983 	/* Add no support */
14984 	cur_svc = svc;
14985 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
14986 		return;
14987 
14988 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
14989 	if (pname == NULL)
14990 		uu_die(gettext("Out of memory.\n"));
14991 
14992 	(void) lscf_addpropvalue(pname, "boolean:", "0");
14993 
14994 	uu_free(pname);
14995 	cur_svc = NULL;
14996 }
14997 
14998 /*
14999  * This function handles all upgrade scenarios for a service that doesn't have
15000  * SCF_PG_MANIFESTFILES pg. The function creates and populates
15001  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
15002  * manifest(s) mapping. Manifests under supported directories are inventoried
15003  * and a property is added for each file that delivers configuration to the
15004  * service.  A service that has no corresponding manifest files (deleted) are
15005  * removed from repository.
15006  *
15007  * Unsupported services:
15008  *
15009  * A service is considered unsupported if there is no corresponding manifest
15010  * in the supported directories for that service and the service isn't in the
15011  * history file list.  The history file, MFSTHISTFILE, contains a list of all
15012  * services and instances that were delivered by Solaris before the introduction
15013  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
15014  * the path to the manifest file that defined the service or instance.
15015  *
15016  * Another type of unsupported services is 'handcrafted' services,
15017  * programmatically created services or services created by dependent entries
15018  * in other manifests. A handcrafted service is identified by its lack of any
15019  * instance containing last-import snapshot which is created during svccfg
15020  * import.
15021  *
15022  * This function sets a flag for unsupported services by setting services'
15023  * SCF_PG_MANIFESTFILES/support property to false.
15024  */
15025 static void
15026 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
15027 {
15028 	service_manifest_t	*elem;
15029 	uu_list_walk_t		*mfwalk;
15030 	string_list_t		*mfile;
15031 	uu_list_t		*instances;
15032 	const char		*sname;
15033 	char			*pname;
15034 	int			r;
15035 
15036 	/*
15037 	 * Since there's no guarantee manifests under /var are available during
15038 	 * early import, don't perform any upgrade during early import.
15039 	 */
15040 	if (IGNORE_VAR)
15041 		return;
15042 
15043 	if (service_manifest_tree == NULL) {
15044 		create_manifest_tree();
15045 	}
15046 
15047 	/*
15048 	 * Find service's supporting manifest(s) after
15049 	 * stripping off the svc:/ prefix that is part
15050 	 * of the fmri that is not used in the service
15051 	 * manifest bundle list.
15052 	 */
15053 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
15054 	    strlen(SCF_FMRI_SERVICE_PREFIX);
15055 	elem = find_add_svc_mfst(sname, NULL);
15056 	if (elem == NULL) {
15057 
15058 		/*
15059 		 * A handcrafted service, one that has no instance containing
15060 		 * last-import snapshot, should get unsupported flag.
15061 		 */
15062 		instances = create_instance_list(svc, 1);
15063 		if (instances == NULL) {
15064 			uu_warn(gettext("Unable to create instance list %s\n"),
15065 			    svcname);
15066 			return;
15067 		}
15068 
15069 		if (uu_list_numnodes(instances) == 0) {
15070 			svc_add_no_support(svc);
15071 			return;
15072 		}
15073 
15074 		/*
15075 		 * If the service is in the history file, and its supporting
15076 		 * manifests are not found, we can safely delete the service
15077 		 * because its manifests are removed from the system.
15078 		 *
15079 		 * Services not found in the history file are not delivered by
15080 		 * Solaris and/or delivered outside supported directories, set
15081 		 * unsupported flag for these services.
15082 		 */
15083 		r = check_mfst_history(svcname);
15084 		if (r == -1)
15085 			return;
15086 
15087 		if (r) {
15088 			/* Set unsupported flag for service  */
15089 			svc_add_no_support(svc);
15090 		} else {
15091 			/* Delete the service */
15092 			teardown_service(svc, svcname);
15093 		}
15094 
15095 		return;
15096 	}
15097 
15098 	/*
15099 	 * Walk through the list of manifests and add them
15100 	 * to the service.
15101 	 *
15102 	 * Create a manifestfiles pg and add the property.
15103 	 */
15104 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
15105 	if (mfwalk == NULL)
15106 		return;
15107 
15108 	cur_svc = svc;
15109 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
15110 	if (r != 0) {
15111 		cur_svc = NULL;
15112 		return;
15113 	}
15114 
15115 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
15116 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
15117 		    mhash_filename_to_propname(mfile->str, 0));
15118 		if (pname == NULL)
15119 			uu_die(gettext("Out of memory.\n"));
15120 
15121 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
15122 		uu_free(pname);
15123 	}
15124 	uu_list_walk_end(mfwalk);
15125 
15126 	cur_svc = NULL;
15127 }
15128 
15129 /*
15130  * Take a service and process the manifest file entires to see if
15131  * there is continued support for the service and instances.  If
15132  * not cleanup as appropriate.
15133  *
15134  * If a service does not have a manifest files entry flag it for
15135  * upgrade and return.
15136  *
15137  * For each manifestfiles property check if the manifest file is
15138  * under the supported /lib/svc/manifest or /var/svc/manifest path
15139  * and if not then return immediately as this service is not supported
15140  * by the cleanup mechanism and should be ignored.
15141  *
15142  * For each manifest file that is supported, check to see if the
15143  * file exists.  If not then remove the manifest file property
15144  * from the service and the smf/manifest hash table.  If the manifest
15145  * file exists then verify that it supports the instances that are
15146  * part of the service.
15147  *
15148  * Once all manifest files have been accounted for remove any instances
15149  * that are no longer supported in the service.
15150  *
15151  * Return values :
15152  * 0 - Successfully processed the service
15153  * non-zero - failed to process the service
15154  *
15155  * On most errors, will just return to wait and get the next service,
15156  * unless in case of unable to create the needed structures which is
15157  * most likely a fatal error that is not going to be recoverable.
15158  */
15159 int
15160 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
15161 {
15162 	struct mpg_mfile	*mpntov;
15163 	struct mpg_mfile	**mpvarry = NULL;
15164 	scf_service_t		*svc;
15165 	scf_propertygroup_t	*mpg;
15166 	scf_property_t		*mp;
15167 	scf_value_t		*mv;
15168 	scf_iter_t		*mi;
15169 	scf_instance_t		*instance;
15170 	uu_list_walk_t		*insts;
15171 	uu_list_t		*instances = NULL;
15172 	boolean_t		activity = (boolean_t)act;
15173 	char			*mpnbuf;
15174 	char			*mpvbuf;
15175 	char			*pgpropbuf;
15176 	int			mfstcnt, rminstct, instct, mfstmax;
15177 	int			index;
15178 	int			r = 0;
15179 
15180 	assert(g_hndl != NULL);
15181 	assert(wip->svc != NULL);
15182 	assert(wip->fmri != NULL);
15183 
15184 	svc = wip->svc;
15185 
15186 	mpg = scf_pg_create(g_hndl);
15187 	mp = scf_property_create(g_hndl);
15188 	mi = scf_iter_create(g_hndl);
15189 	mv = scf_value_create(g_hndl);
15190 	instance = scf_instance_create(g_hndl);
15191 
15192 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
15193 	    instance == NULL) {
15194 		uu_warn(gettext("Unable to create the supporting entities\n"));
15195 		uu_warn(gettext("scf error is : %s\n"),
15196 		    scf_strerror(scf_error()));
15197 		scfdie();
15198 	}
15199 
15200 	/*
15201 	 * Get the manifestfiles property group to be parsed for
15202 	 * files existence.
15203 	 */
15204 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
15205 		switch (scf_error()) {
15206 		case SCF_ERROR_NOT_FOUND:
15207 			upgrade_svc_mfst_connection(svc, wip->fmri);
15208 			break;
15209 		case SCF_ERROR_DELETED:
15210 		case SCF_ERROR_CONNECTION_BROKEN:
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_pg_properties",
15218 			    scf_error());
15219 		}
15220 
15221 		goto out;
15222 	}
15223 
15224 	/*
15225 	 * Iterate through each of the manifestfiles properties
15226 	 * to determine what manifestfiles are available.
15227 	 *
15228 	 * If a manifest file is supported then increment the
15229 	 * count and therefore the service is safe.
15230 	 */
15231 	if (scf_iter_pg_properties(mi, mpg) != 0) {
15232 		switch (scf_error()) {
15233 		case SCF_ERROR_DELETED:
15234 		case SCF_ERROR_CONNECTION_BROKEN:
15235 			goto out;
15236 
15237 		case SCF_ERROR_HANDLE_MISMATCH:
15238 		case SCF_ERROR_NOT_BOUND:
15239 		case SCF_ERROR_NOT_SET:
15240 		default:
15241 			bad_error("scf_iter_pg_properties",
15242 			    scf_error());
15243 		}
15244 	}
15245 
15246 	mfstcnt = 0;
15247 	mfstmax = MFSTFILE_MAX;
15248 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
15249 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
15250 		if (r == -1)
15251 			bad_error(gettext("Unable to iterate through "
15252 			    "manifestfiles properties : %s"),
15253 			    scf_error());
15254 
15255 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
15256 		mpnbuf = safe_malloc(max_scf_name_len + 1);
15257 		mpvbuf = safe_malloc(max_scf_value_len + 1);
15258 		mpntov->mpg = mpnbuf;
15259 		mpntov->mfile = mpvbuf;
15260 		mpntov->access = 1;
15261 		if (scf_property_get_name(mp, mpnbuf,
15262 		    max_scf_name_len + 1) < 0) {
15263 			uu_warn(gettext("Unable to get manifest file "
15264 			    "property : %s\n"),
15265 			    scf_strerror(scf_error()));
15266 
15267 			switch (scf_error()) {
15268 			case SCF_ERROR_DELETED:
15269 			case SCF_ERROR_CONNECTION_BROKEN:
15270 				r = scferror2errno(scf_error());
15271 				goto out_free;
15272 
15273 			case SCF_ERROR_HANDLE_MISMATCH:
15274 			case SCF_ERROR_NOT_BOUND:
15275 			case SCF_ERROR_NOT_SET:
15276 			default:
15277 				bad_error("scf_iter_pg_properties",
15278 				    scf_error());
15279 			}
15280 		}
15281 
15282 		/*
15283 		 * The support property is a boolean value that indicates
15284 		 * if the service is supported for manifest file deletion.
15285 		 * Currently at this time there is no code that sets this
15286 		 * value to true.  So while we could just let this be caught
15287 		 * by the support check below, in the future this by be set
15288 		 * to true and require processing.  So for that, go ahead
15289 		 * and check here, and just return if false.  Otherwise,
15290 		 * fall through expecting that other support checks will
15291 		 * handle the entries.
15292 		 */
15293 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
15294 			uint8_t	support;
15295 
15296 			if (scf_property_get_value(mp, mv) != 0 ||
15297 			    scf_value_get_boolean(mv, &support) != 0) {
15298 				uu_warn(gettext("Unable to get the manifest "
15299 				    "support value: %s\n"),
15300 				    scf_strerror(scf_error()));
15301 
15302 				switch (scf_error()) {
15303 				case SCF_ERROR_DELETED:
15304 				case SCF_ERROR_CONNECTION_BROKEN:
15305 					r = scferror2errno(scf_error());
15306 					goto out_free;
15307 
15308 				case SCF_ERROR_HANDLE_MISMATCH:
15309 				case SCF_ERROR_NOT_BOUND:
15310 				case SCF_ERROR_NOT_SET:
15311 				default:
15312 					bad_error("scf_iter_pg_properties",
15313 					    scf_error());
15314 				}
15315 			}
15316 
15317 			if (support == B_FALSE)
15318 				goto out_free;
15319 		}
15320 
15321 		/*
15322 		 * Anything with a manifest outside of the supported
15323 		 * directories, immediately bail out because that makes
15324 		 * this service non-supported.  We don't even want
15325 		 * to do instance processing in this case because the
15326 		 * instances could be part of the non-supported manifest.
15327 		 */
15328 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
15329 			/*
15330 			 * Manifest is not in /lib/svc, so we need to
15331 			 * consider the /var/svc case.
15332 			 */
15333 			if (strncmp(mpnbuf, VARSVC_PR,
15334 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
15335 				/*
15336 				 * Either the manifest is not in /var/svc or
15337 				 * /var is not yet mounted.  We ignore the
15338 				 * manifest either because it is not in a
15339 				 * standard location or because we cannot
15340 				 * currently access the manifest.
15341 				 */
15342 				goto out_free;
15343 			}
15344 		}
15345 
15346 		/*
15347 		 * Get the value to of the manifest file for this entry
15348 		 * for access verification and instance support
15349 		 * verification if it still exists.
15350 		 *
15351 		 * During Early Manifest Import if the manifest is in
15352 		 * /var/svc then it may not yet be available for checking
15353 		 * so we must determine if /var/svc is available.  If not
15354 		 * then defer until Late Manifest Import to cleanup.
15355 		 */
15356 		if (scf_property_get_value(mp, mv) != 0) {
15357 			uu_warn(gettext("Unable to get the manifest file "
15358 			    "value: %s\n"),
15359 			    scf_strerror(scf_error()));
15360 
15361 			switch (scf_error()) {
15362 			case SCF_ERROR_DELETED:
15363 			case SCF_ERROR_CONNECTION_BROKEN:
15364 				r = scferror2errno(scf_error());
15365 				goto out_free;
15366 
15367 			case SCF_ERROR_HANDLE_MISMATCH:
15368 			case SCF_ERROR_NOT_BOUND:
15369 			case SCF_ERROR_NOT_SET:
15370 			default:
15371 				bad_error("scf_property_get_value",
15372 				    scf_error());
15373 			}
15374 		}
15375 
15376 		if (scf_value_get_astring(mv, mpvbuf,
15377 		    max_scf_value_len + 1) < 0) {
15378 			uu_warn(gettext("Unable to get the manifest "
15379 			    "file : %s\n"),
15380 			    scf_strerror(scf_error()));
15381 
15382 			switch (scf_error()) {
15383 			case SCF_ERROR_DELETED:
15384 			case SCF_ERROR_CONNECTION_BROKEN:
15385 				r = scferror2errno(scf_error());
15386 				goto out_free;
15387 
15388 			case SCF_ERROR_HANDLE_MISMATCH:
15389 			case SCF_ERROR_NOT_BOUND:
15390 			case SCF_ERROR_NOT_SET:
15391 			default:
15392 				bad_error("scf_value_get_astring",
15393 				    scf_error());
15394 			}
15395 		}
15396 
15397 		mpvarry[mfstcnt] = mpntov;
15398 		mfstcnt++;
15399 
15400 		/*
15401 		 * Check for the need to reallocate array
15402 		 */
15403 		if (mfstcnt >= (mfstmax - 1)) {
15404 			struct mpg_mfile **newmpvarry;
15405 
15406 			mfstmax = mfstmax * 2;
15407 			newmpvarry = realloc(mpvarry,
15408 			    sizeof (struct mpg_mfile *) * mfstmax);
15409 
15410 			if (newmpvarry == NULL)
15411 				goto out_free;
15412 
15413 			mpvarry = newmpvarry;
15414 		}
15415 
15416 		mpvarry[mfstcnt] = NULL;
15417 	}
15418 
15419 	for (index = 0; mpvarry[index]; index++) {
15420 		mpntov = mpvarry[index];
15421 
15422 		/*
15423 		 * Check to see if the manifestfile is accessable, if so hand
15424 		 * this service and manifestfile off to be processed for
15425 		 * instance support.
15426 		 */
15427 		mpnbuf = mpntov->mpg;
15428 		mpvbuf = mpntov->mfile;
15429 		if (access(mpvbuf, F_OK) != 0) {
15430 			mpntov->access = 0;
15431 			activity++;
15432 			mfstcnt--;
15433 			/* Remove the entry from the service */
15434 			cur_svc = svc;
15435 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
15436 			    mpnbuf);
15437 			if (pgpropbuf == NULL)
15438 				uu_die(gettext("Out of memory.\n"));
15439 
15440 			lscf_delprop(pgpropbuf);
15441 			cur_svc = NULL;
15442 
15443 			uu_free(pgpropbuf);
15444 		}
15445 	}
15446 
15447 	/*
15448 	 * If mfstcnt is 0, none of the manifests that supported the service
15449 	 * existed so remove the service.
15450 	 */
15451 	if (mfstcnt == 0) {
15452 		teardown_service(svc, wip->fmri);
15453 
15454 		goto out_free;
15455 	}
15456 
15457 	if (activity) {
15458 		int	nosvcsupport = 0;
15459 
15460 		/*
15461 		 * If the list of service instances is NULL then
15462 		 * create the list.
15463 		 */
15464 		instances = create_instance_list(svc, 1);
15465 		if (instances == NULL) {
15466 			uu_warn(gettext("Unable to create instance list %s\n"),
15467 			    wip->fmri);
15468 			goto out_free;
15469 		}
15470 
15471 		rminstct = uu_list_numnodes(instances);
15472 		instct = rminstct;
15473 
15474 		for (index = 0; mpvarry[index]; index++) {
15475 			mpntov = mpvarry[index];
15476 			if (mpntov->access == 0)
15477 				continue;
15478 
15479 			mpnbuf = mpntov->mpg;
15480 			mpvbuf = mpntov->mfile;
15481 			r = check_instance_support(mpvbuf, wip->fmri,
15482 			    instances);
15483 			if (r == -1) {
15484 				nosvcsupport++;
15485 			} else {
15486 				rminstct -= r;
15487 			}
15488 		}
15489 
15490 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
15491 			teardown_service(svc, wip->fmri);
15492 
15493 			goto out_free;
15494 		}
15495 	}
15496 
15497 	/*
15498 	 * If there are instances left on the instance list, then
15499 	 * we must remove them.
15500 	 */
15501 	if (instances != NULL && uu_list_numnodes(instances)) {
15502 		string_list_t *sp;
15503 
15504 		insts = uu_list_walk_start(instances, 0);
15505 		while ((sp = uu_list_walk_next(insts)) != NULL) {
15506 			/*
15507 			 * Remove the instance from the instances list.
15508 			 */
15509 			safe_printf(gettext("Delete instance %s from "
15510 			    "service %s\n"), sp->str, wip->fmri);
15511 			if (scf_service_get_instance(svc, sp->str,
15512 			    instance) != SCF_SUCCESS) {
15513 				(void) uu_warn("scf_error - %s\n",
15514 				    scf_strerror(scf_error()));
15515 
15516 				continue;
15517 			}
15518 
15519 			(void) disable_instance(instance);
15520 
15521 			(void) lscf_instance_delete(instance, 1);
15522 		}
15523 		scf_instance_destroy(instance);
15524 		uu_list_walk_end(insts);
15525 	}
15526 
15527 out_free:
15528 	if (mpvarry) {
15529 		struct mpg_mfile *fmpntov;
15530 
15531 		for (index = 0; mpvarry[index]; index++) {
15532 			fmpntov  = mpvarry[index];
15533 			if (fmpntov->mpg == mpnbuf)
15534 				mpnbuf = NULL;
15535 			free(fmpntov->mpg);
15536 
15537 			if (fmpntov->mfile == mpvbuf)
15538 				mpvbuf = NULL;
15539 			free(fmpntov->mfile);
15540 
15541 			if (fmpntov == mpntov)
15542 				mpntov = NULL;
15543 			free(fmpntov);
15544 		}
15545 		if (mpnbuf)
15546 			free(mpnbuf);
15547 		if (mpvbuf)
15548 			free(mpvbuf);
15549 		if (mpntov)
15550 			free(mpntov);
15551 
15552 		free(mpvarry);
15553 	}
15554 out:
15555 	scf_pg_destroy(mpg);
15556 	scf_property_destroy(mp);
15557 	scf_iter_destroy(mi);
15558 	scf_value_destroy(mv);
15559 
15560 	return (0);
15561 }
15562 
15563 /*
15564  * Take the service and search for the manifestfiles property
15565  * in each of the property groups.  If the manifest file
15566  * associated with the property does not exist then remove
15567  * the property group.
15568  */
15569 int
15570 lscf_hash_cleanup()
15571 {
15572 	scf_service_t		*svc;
15573 	scf_scope_t		*scope;
15574 	scf_propertygroup_t	*pg;
15575 	scf_property_t		*prop;
15576 	scf_value_t		*val;
15577 	scf_iter_t		*iter;
15578 	char			*pgname;
15579 	char			*mfile;
15580 	int			r;
15581 
15582 	svc = scf_service_create(g_hndl);
15583 	scope = scf_scope_create(g_hndl);
15584 	pg = scf_pg_create(g_hndl);
15585 	prop = scf_property_create(g_hndl);
15586 	val = scf_value_create(g_hndl);
15587 	iter = scf_iter_create(g_hndl);
15588 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
15589 	    svc == NULL || scope == NULL) {
15590 		uu_warn(gettext("Unable to create a property group, or "
15591 		    "property\n"));
15592 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
15593 		    "pg is not NULL");
15594 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
15595 		    "prop is not NULL");
15596 		uu_warn("%s\n", val == NULL ? "val is NULL" :
15597 		    "val is not NULL");
15598 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
15599 		    "iter is not NULL");
15600 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
15601 		    "svc is not NULL");
15602 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
15603 		    "scope is not NULL");
15604 		uu_warn(gettext("scf error is : %s\n"),
15605 		    scf_strerror(scf_error()));
15606 		scfdie();
15607 	}
15608 
15609 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
15610 		switch (scf_error()) {
15611 		case SCF_ERROR_CONNECTION_BROKEN:
15612 		case SCF_ERROR_NOT_FOUND:
15613 			goto out;
15614 
15615 		case SCF_ERROR_HANDLE_MISMATCH:
15616 		case SCF_ERROR_NOT_BOUND:
15617 		case SCF_ERROR_INVALID_ARGUMENT:
15618 		default:
15619 			bad_error("scf_handle_get_scope", scf_error());
15620 		}
15621 	}
15622 
15623 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
15624 		uu_warn(gettext("Unable to process the hash service, %s\n"),
15625 		    HASH_SVC);
15626 		goto out;
15627 	}
15628 
15629 	pgname = safe_malloc(max_scf_name_len + 1);
15630 	mfile = safe_malloc(max_scf_value_len + 1);
15631 
15632 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
15633 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
15634 		    scf_strerror(scf_error()));
15635 		goto out;
15636 	}
15637 
15638 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
15639 		if (r == -1)
15640 			goto out;
15641 
15642 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
15643 			switch (scf_error()) {
15644 			case SCF_ERROR_DELETED:
15645 				return (ENODEV);
15646 
15647 			case SCF_ERROR_CONNECTION_BROKEN:
15648 				return (ECONNABORTED);
15649 
15650 			case SCF_ERROR_NOT_SET:
15651 			case SCF_ERROR_NOT_BOUND:
15652 			default:
15653 				bad_error("scf_pg_get_name", scf_error());
15654 			}
15655 		}
15656 		if (IGNORE_VAR) {
15657 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
15658 				continue;
15659 		}
15660 
15661 		/*
15662 		 * If unable to get the property continue as this is an
15663 		 * entry that has no location to check against.
15664 		 */
15665 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
15666 			continue;
15667 		}
15668 
15669 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
15670 			uu_warn(gettext("Unable to get value from %s\n"),
15671 			    pgname);
15672 			goto error_handle;
15673 		}
15674 
15675 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) ==
15676 		    -1) {
15677 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
15678 			    pgname, scf_strerror(scf_error()));
15679 			goto error_handle;
15680 		}
15681 
15682 		if (access(mfile, F_OK) == 0)
15683 			continue;
15684 
15685 		(void) scf_pg_delete(pg);
15686 
15687 error_handle:
15688 		switch (scf_error()) {
15689 		case SCF_ERROR_DELETED:
15690 		case SCF_ERROR_CONSTRAINT_VIOLATED:
15691 		case SCF_ERROR_NOT_FOUND:
15692 		case SCF_ERROR_NOT_SET:
15693 			continue;
15694 
15695 		case SCF_ERROR_CONNECTION_BROKEN:
15696 			r = scferror2errno(scf_error());
15697 			goto out;
15698 
15699 		case SCF_ERROR_HANDLE_MISMATCH:
15700 		case SCF_ERROR_NOT_BOUND:
15701 		default:
15702 			bad_error("scf_value_get_astring",
15703 			    scf_error());
15704 		}
15705 	}
15706 
15707 out:
15708 	scf_scope_destroy(scope);
15709 	scf_service_destroy(svc);
15710 	scf_pg_destroy(pg);
15711 	scf_property_destroy(prop);
15712 	scf_value_destroy(val);
15713 	scf_iter_destroy(iter);
15714 	free(pgname);
15715 	free(mfile);
15716 
15717 	return (0);
15718 }
15719 
15720 #ifndef NATIVE_BUILD
15721 /* ARGSUSED */
15722 CPL_MATCH_FN(complete_select)
15723 {
15724 	const char *arg0, *arg1, *arg1end;
15725 	int word_start, err = 0, r;
15726 	size_t len;
15727 	char *buf;
15728 
15729 	lscf_prep_hndl();
15730 
15731 	arg0 = line + strspn(line, " \t");
15732 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
15733 
15734 	arg1 = arg0 + sizeof ("select") - 1;
15735 	arg1 += strspn(arg1, " \t");
15736 	word_start = arg1 - line;
15737 
15738 	arg1end = arg1 + strcspn(arg1, " \t");
15739 	if (arg1end < line + word_end)
15740 		return (0);
15741 
15742 	len = line + word_end - arg1;
15743 
15744 	buf = safe_malloc(max_scf_name_len + 1);
15745 
15746 	if (cur_snap != NULL) {
15747 		return (0);
15748 	} else if (cur_inst != NULL) {
15749 		return (0);
15750 	} else if (cur_svc != NULL) {
15751 		scf_instance_t *inst;
15752 		scf_iter_t *iter;
15753 
15754 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
15755 		    (iter = scf_iter_create(g_hndl)) == NULL)
15756 			scfdie();
15757 
15758 		if (scf_iter_service_instances(iter, cur_svc) != 0)
15759 			scfdie();
15760 
15761 		for (;;) {
15762 			r = scf_iter_next_instance(iter, inst);
15763 			if (r == 0)
15764 				break;
15765 			if (r != 1)
15766 				scfdie();
15767 
15768 			if (scf_instance_get_name(inst, buf,
15769 			    max_scf_name_len + 1) < 0)
15770 				scfdie();
15771 
15772 			if (strncmp(buf, arg1, len) == 0) {
15773 				err = cpl_add_completion(cpl, line, word_start,
15774 				    word_end, buf + len, "", " ");
15775 				if (err != 0)
15776 					break;
15777 			}
15778 		}
15779 
15780 		scf_iter_destroy(iter);
15781 		scf_instance_destroy(inst);
15782 
15783 		return (err);
15784 	} else {
15785 		scf_service_t *svc;
15786 		scf_iter_t *iter;
15787 
15788 		assert(cur_scope != NULL);
15789 
15790 		if ((svc = scf_service_create(g_hndl)) == NULL ||
15791 		    (iter = scf_iter_create(g_hndl)) == NULL)
15792 			scfdie();
15793 
15794 		if (scf_iter_scope_services(iter, cur_scope) != 0)
15795 			scfdie();
15796 
15797 		for (;;) {
15798 			r = scf_iter_next_service(iter, svc);
15799 			if (r == 0)
15800 				break;
15801 			if (r != 1)
15802 				scfdie();
15803 
15804 			if (scf_service_get_name(svc, buf,
15805 			    max_scf_name_len + 1) < 0)
15806 				scfdie();
15807 
15808 			if (strncmp(buf, arg1, len) == 0) {
15809 				err = cpl_add_completion(cpl, line, word_start,
15810 				    word_end, buf + len, "", " ");
15811 				if (err != 0)
15812 					break;
15813 			}
15814 		}
15815 
15816 		scf_iter_destroy(iter);
15817 		scf_service_destroy(svc);
15818 
15819 		return (err);
15820 	}
15821 }
15822 
15823 /* ARGSUSED */
15824 CPL_MATCH_FN(complete_command)
15825 {
15826 	uint32_t scope = 0;
15827 
15828 	if (cur_snap != NULL)
15829 		scope = CS_SNAP;
15830 	else if (cur_inst != NULL)
15831 		scope = CS_INST;
15832 	else if (cur_svc != NULL)
15833 		scope = CS_SVC;
15834 	else
15835 		scope = CS_SCOPE;
15836 
15837 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
15838 }
15839 #endif	/* NATIVE_BUILD */
15840