xref: /titanic_41/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision ba7866cd2cbdf574f47d4e38a1301b90744dd677)
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 	/*
919 	 * When a value of type opaque is represented as a string, the
920 	 * string contains 2 characters for every byte of data.  That is
921 	 * because the string contains the hex representation of the opaque
922 	 * value.
923 	 */
924 	if (2 * max_scf_value_len > max_scf_len)
925 		max_scf_len = 2 * max_scf_value_len;
926 
927 	if (atexit(remove_tempfile) != 0)
928 		uu_die(gettext("Could not register atexit() function"));
929 
930 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
931 	emsg_permission_denied = gettext("Permission denied.\n");
932 	emsg_create_xml = gettext("Could not create XML node.\n");
933 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
934 	emsg_read_only = gettext("Backend read-only.\n");
935 	emsg_deleted = gettext("Current selection has been deleted.\n");
936 	emsg_invalid_pg_name =
937 	    gettext("Invalid property group name \"%s\".\n");
938 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
939 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
940 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
941 	    "with invalid name \"%s\".\n");
942 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
943 	    "group with invalid name \"%s\" or type \"%s\".\n");
944 	emsg_pg_added = gettext("%s changed unexpectedly "
945 	    "(property group \"%s\" added).\n");
946 	emsg_pg_changed = gettext("%s changed unexpectedly "
947 	    "(property group \"%s\" changed).\n");
948 	emsg_pg_deleted = gettext("%s changed unexpectedly "
949 	    "(property group \"%s\" or an ancestor was deleted).\n");
950 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
951 	    "in %s (permission denied).\n");
952 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
953 	    "in %s (permission denied).\n");
954 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
955 	    "in %s (permission denied).\n");
956 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
957 	    "(permission denied).\n");
958 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
959 	    "new dependent \"%s\" because it already exists).  Warning: The "
960 	    "current dependent's target (%s) does not exist.\n");
961 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
962 	    "dependent \"%s\" because it already exists).  Warning: The "
963 	    "current dependent's target (%s) does not have a dependency named "
964 	    "\"%s\" as expected.\n");
965 
966 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
967 	    offsetof(string_list_t, node), NULL, 0);
968 	snaplevel_pool = uu_list_pool_create("snaplevels",
969 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
970 	    NULL, 0);
971 }
972 
973 
974 static const char *
975 prop_to_typestr(const scf_property_t *prop)
976 {
977 	scf_type_t ty;
978 
979 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
980 		scfdie();
981 
982 	return (scf_type_to_string(ty));
983 }
984 
985 static scf_type_t
986 string_to_type(const char *type)
987 {
988 	size_t len = strlen(type);
989 	char *buf;
990 
991 	if (len == 0 || type[len - 1] != ':')
992 		return (SCF_TYPE_INVALID);
993 
994 	buf = (char *)alloca(len + 1);
995 	(void) strlcpy(buf, type, len + 1);
996 	buf[len - 1] = 0;
997 
998 	return (scf_string_to_type(buf));
999 }
1000 
1001 static scf_value_t *
1002 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1003 {
1004 	scf_value_t *v;
1005 	char *dup, *nstr;
1006 	size_t len;
1007 
1008 	v = scf_value_create(g_hndl);
1009 	if (v == NULL)
1010 		scfdie();
1011 
1012 	len = strlen(str);
1013 	if (require_quotes &&
1014 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1015 		semerr(gettext("Multiple string values or string values "
1016 		    "with spaces must be quoted with '\"'.\n"));
1017 		scf_value_destroy(v);
1018 		return (NULL);
1019 	}
1020 
1021 	nstr = dup = safe_strdup(str);
1022 	if (dup[0] == '\"') {
1023 		/*
1024 		 * Strip out the first and the last quote.
1025 		 */
1026 		dup[len - 1] = '\0';
1027 		nstr = dup + 1;
1028 	}
1029 
1030 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1031 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1032 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1033 		    scf_type_to_string(ty), nstr);
1034 		scf_value_destroy(v);
1035 		v = NULL;
1036 	}
1037 	free(dup);
1038 	return (v);
1039 }
1040 
1041 /*
1042  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1043  * Optionally append a comment prefix ('#') to newlines ('\n').
1044  */
1045 static int
1046 quote_and_print(const char *str, FILE *strm, int commentnl)
1047 {
1048 	const char *cp;
1049 
1050 	for (cp = str; *cp != '\0'; ++cp) {
1051 		if (*cp == '"' || *cp == '\\')
1052 			(void) putc('\\', strm);
1053 
1054 		(void) putc(*cp, strm);
1055 
1056 		if (commentnl && *cp == '\n') {
1057 			(void) putc('#', strm);
1058 		}
1059 	}
1060 
1061 	return (ferror(strm));
1062 }
1063 
1064 /*
1065  * These wrappers around lowlevel functions provide consistent error checking
1066  * and warnings.
1067  */
1068 static int
1069 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1070 {
1071 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1072 		return (0);
1073 
1074 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1075 		scfdie();
1076 
1077 	if (g_verbose) {
1078 		ssize_t len;
1079 		char *fmri;
1080 
1081 		len = scf_pg_to_fmri(pg, NULL, 0);
1082 		if (len < 0)
1083 			scfdie();
1084 
1085 		fmri = safe_malloc(len + 1);
1086 
1087 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1088 			scfdie();
1089 
1090 		warn(gettext("Expected property %s of property group %s is "
1091 		    "missing.\n"), propname, fmri);
1092 
1093 		free(fmri);
1094 	}
1095 
1096 	return (-1);
1097 }
1098 
1099 static int
1100 prop_check_type(scf_property_t *prop, scf_type_t ty)
1101 {
1102 	scf_type_t pty;
1103 
1104 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1105 		scfdie();
1106 
1107 	if (ty == pty)
1108 		return (0);
1109 
1110 	if (g_verbose) {
1111 		ssize_t len;
1112 		char *fmri;
1113 		const char *tystr;
1114 
1115 		len = scf_property_to_fmri(prop, NULL, 0);
1116 		if (len < 0)
1117 			scfdie();
1118 
1119 		fmri = safe_malloc(len + 1);
1120 
1121 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1122 			scfdie();
1123 
1124 		tystr = scf_type_to_string(ty);
1125 		if (tystr == NULL)
1126 			tystr = "?";
1127 
1128 		warn(gettext("Property %s is not of expected type %s.\n"),
1129 		    fmri, tystr);
1130 
1131 		free(fmri);
1132 	}
1133 
1134 	return (-1);
1135 }
1136 
1137 static int
1138 prop_get_val(scf_property_t *prop, scf_value_t *val)
1139 {
1140 	scf_error_t err;
1141 
1142 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1143 		return (0);
1144 
1145 	err = scf_error();
1146 
1147 	if (err != SCF_ERROR_NOT_FOUND &&
1148 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1149 	    err != SCF_ERROR_PERMISSION_DENIED)
1150 		scfdie();
1151 
1152 	if (g_verbose) {
1153 		ssize_t len;
1154 		char *fmri, *emsg;
1155 
1156 		len = scf_property_to_fmri(prop, NULL, 0);
1157 		if (len < 0)
1158 			scfdie();
1159 
1160 		fmri = safe_malloc(len + 1);
1161 
1162 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1163 			scfdie();
1164 
1165 		if (err == SCF_ERROR_NOT_FOUND)
1166 			emsg = gettext("Property %s has no values; expected "
1167 			    "one.\n");
1168 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1169 			emsg = gettext("Property %s has multiple values; "
1170 			    "expected one.\n");
1171 		else
1172 			emsg = gettext("No permission to read property %s.\n");
1173 
1174 		warn(emsg, fmri);
1175 
1176 		free(fmri);
1177 	}
1178 
1179 	return (-1);
1180 }
1181 
1182 
1183 static boolean_t
1184 snaplevel_is_instance(const scf_snaplevel_t *level)
1185 {
1186 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1187 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1188 			scfdie();
1189 		return (0);
1190 	} else {
1191 		return (1);
1192 	}
1193 }
1194 
1195 /*
1196  * Decode FMRI into a service or instance, and put the result in *ep.  If
1197  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1198  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1199  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1200  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1201  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1202  * whether *ep is a service.
1203  */
1204 static scf_error_t
1205 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1206 {
1207 	char *fmri_copy;
1208 	const char *sstr, *istr, *pgstr;
1209 	scf_service_t *svc;
1210 	scf_instance_t *inst;
1211 
1212 	fmri_copy = strdup(fmri);
1213 	if (fmri_copy == NULL)
1214 		return (SCF_ERROR_NO_MEMORY);
1215 
1216 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1217 	    SCF_SUCCESS) {
1218 		free(fmri_copy);
1219 		return (SCF_ERROR_INVALID_ARGUMENT);
1220 	}
1221 
1222 	free(fmri_copy);
1223 
1224 	if (sstr == NULL || pgstr != NULL)
1225 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1226 
1227 	if (istr == NULL) {
1228 		svc = scf_service_create(h);
1229 		if (svc == NULL)
1230 			return (SCF_ERROR_NO_MEMORY);
1231 
1232 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1233 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1234 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1235 				scfdie();
1236 
1237 			return (SCF_ERROR_NOT_FOUND);
1238 		}
1239 
1240 		*ep = svc;
1241 		*isservice = 1;
1242 	} else {
1243 		inst = scf_instance_create(h);
1244 		if (inst == NULL)
1245 			return (SCF_ERROR_NO_MEMORY);
1246 
1247 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1248 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1249 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1250 				scfdie();
1251 
1252 			return (SCF_ERROR_NOT_FOUND);
1253 		}
1254 
1255 		*ep = inst;
1256 		*isservice = 0;
1257 	}
1258 
1259 	return (SCF_ERROR_NONE);
1260 }
1261 
1262 /*
1263  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1264  * *ep, and set or clear *isservicep if it is a service or an instance.
1265  * Returns
1266  *   SCF_ERROR_NONE - success
1267  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1268  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1269  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1270  *   SCF_ERROR_NOT_FOUND - no such scope
1271  *   SCF_ERROR_PERMISSION_DENIED
1272  *   SCF_ERROR_BACKEND_READONLY
1273  *   SCF_ERROR_BACKEND_ACCESS
1274  */
1275 static scf_error_t
1276 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1277 {
1278 	char *fmri_copy;
1279 	const char *scstr, *sstr, *istr, *pgstr;
1280 	scf_scope_t *scope = NULL;
1281 	scf_service_t *svc = NULL;
1282 	scf_instance_t *inst = NULL;
1283 	scf_error_t scfe;
1284 
1285 	fmri_copy = safe_strdup(fmri);
1286 
1287 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1288 	    0) {
1289 		free(fmri_copy);
1290 		return (SCF_ERROR_INVALID_ARGUMENT);
1291 	}
1292 
1293 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1294 		free(fmri_copy);
1295 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1296 	}
1297 
1298 	*ep = NULL;
1299 
1300 	if ((scope = scf_scope_create(h)) == NULL ||
1301 	    (svc = scf_service_create(h)) == NULL ||
1302 	    (inst = scf_instance_create(h)) == NULL) {
1303 		scfe = SCF_ERROR_NO_MEMORY;
1304 		goto out;
1305 	}
1306 
1307 get_scope:
1308 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1309 		switch (scf_error()) {
1310 		case SCF_ERROR_CONNECTION_BROKEN:
1311 			scfdie();
1312 			/* NOTREACHED */
1313 
1314 		case SCF_ERROR_NOT_FOUND:
1315 			scfe = SCF_ERROR_NOT_FOUND;
1316 			goto out;
1317 
1318 		case SCF_ERROR_HANDLE_MISMATCH:
1319 		case SCF_ERROR_NOT_BOUND:
1320 		case SCF_ERROR_INVALID_ARGUMENT:
1321 		default:
1322 			bad_error("scf_handle_get_scope", scf_error());
1323 		}
1324 	}
1325 
1326 get_svc:
1327 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1328 		switch (scf_error()) {
1329 		case SCF_ERROR_CONNECTION_BROKEN:
1330 			scfdie();
1331 			/* NOTREACHED */
1332 
1333 		case SCF_ERROR_DELETED:
1334 			goto get_scope;
1335 
1336 		case SCF_ERROR_NOT_FOUND:
1337 			break;
1338 
1339 		case SCF_ERROR_HANDLE_MISMATCH:
1340 		case SCF_ERROR_INVALID_ARGUMENT:
1341 		case SCF_ERROR_NOT_BOUND:
1342 		case SCF_ERROR_NOT_SET:
1343 		default:
1344 			bad_error("scf_scope_get_service", scf_error());
1345 		}
1346 
1347 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1348 			switch (scf_error()) {
1349 			case SCF_ERROR_CONNECTION_BROKEN:
1350 				scfdie();
1351 				/* NOTREACHED */
1352 
1353 			case SCF_ERROR_DELETED:
1354 				goto get_scope;
1355 
1356 			case SCF_ERROR_PERMISSION_DENIED:
1357 			case SCF_ERROR_BACKEND_READONLY:
1358 			case SCF_ERROR_BACKEND_ACCESS:
1359 				scfe = scf_error();
1360 				goto out;
1361 
1362 			case SCF_ERROR_HANDLE_MISMATCH:
1363 			case SCF_ERROR_INVALID_ARGUMENT:
1364 			case SCF_ERROR_NOT_BOUND:
1365 			case SCF_ERROR_NOT_SET:
1366 			default:
1367 				bad_error("scf_scope_get_service", scf_error());
1368 			}
1369 		}
1370 	}
1371 
1372 	if (istr == NULL) {
1373 		scfe = SCF_ERROR_NONE;
1374 		*ep = svc;
1375 		*isservicep = 1;
1376 		goto out;
1377 	}
1378 
1379 get_inst:
1380 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1381 		switch (scf_error()) {
1382 		case SCF_ERROR_CONNECTION_BROKEN:
1383 			scfdie();
1384 			/* NOTREACHED */
1385 
1386 		case SCF_ERROR_DELETED:
1387 			goto get_svc;
1388 
1389 		case SCF_ERROR_NOT_FOUND:
1390 			break;
1391 
1392 		case SCF_ERROR_HANDLE_MISMATCH:
1393 		case SCF_ERROR_INVALID_ARGUMENT:
1394 		case SCF_ERROR_NOT_BOUND:
1395 		case SCF_ERROR_NOT_SET:
1396 		default:
1397 			bad_error("scf_service_get_instance", scf_error());
1398 		}
1399 
1400 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1401 			switch (scf_error()) {
1402 			case SCF_ERROR_CONNECTION_BROKEN:
1403 				scfdie();
1404 				/* NOTREACHED */
1405 
1406 			case SCF_ERROR_DELETED:
1407 				goto get_svc;
1408 
1409 			case SCF_ERROR_PERMISSION_DENIED:
1410 			case SCF_ERROR_BACKEND_READONLY:
1411 			case SCF_ERROR_BACKEND_ACCESS:
1412 				scfe = scf_error();
1413 				goto out;
1414 
1415 			case SCF_ERROR_HANDLE_MISMATCH:
1416 			case SCF_ERROR_INVALID_ARGUMENT:
1417 			case SCF_ERROR_NOT_BOUND:
1418 			case SCF_ERROR_NOT_SET:
1419 			default:
1420 				bad_error("scf_service_add_instance",
1421 				    scf_error());
1422 			}
1423 		}
1424 	}
1425 
1426 	scfe = SCF_ERROR_NONE;
1427 	*ep = inst;
1428 	*isservicep = 0;
1429 
1430 out:
1431 	if (*ep != inst)
1432 		scf_instance_destroy(inst);
1433 	if (*ep != svc)
1434 		scf_service_destroy(svc);
1435 	scf_scope_destroy(scope);
1436 	free(fmri_copy);
1437 	return (scfe);
1438 }
1439 
1440 /*
1441  * Create or update a snapshot of inst.  snap is a required scratch object.
1442  *
1443  * Returns
1444  *   0 - success
1445  *   ECONNABORTED - repository connection broken
1446  *   EPERM - permission denied
1447  *   ENOSPC - configd is out of resources
1448  *   ECANCELED - inst was deleted
1449  *   -1 - unknown libscf error (message printed)
1450  */
1451 static int
1452 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1453 {
1454 again:
1455 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1456 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1457 			switch (scf_error()) {
1458 			case SCF_ERROR_CONNECTION_BROKEN:
1459 			case SCF_ERROR_PERMISSION_DENIED:
1460 			case SCF_ERROR_NO_RESOURCES:
1461 				return (scferror2errno(scf_error()));
1462 
1463 			case SCF_ERROR_NOT_SET:
1464 			case SCF_ERROR_INVALID_ARGUMENT:
1465 			default:
1466 				bad_error("_scf_snapshot_take_attach",
1467 				    scf_error());
1468 			}
1469 		}
1470 	} else {
1471 		switch (scf_error()) {
1472 		case SCF_ERROR_NOT_FOUND:
1473 			break;
1474 
1475 		case SCF_ERROR_DELETED:
1476 		case SCF_ERROR_CONNECTION_BROKEN:
1477 			return (scferror2errno(scf_error()));
1478 
1479 		case SCF_ERROR_HANDLE_MISMATCH:
1480 		case SCF_ERROR_NOT_BOUND:
1481 		case SCF_ERROR_INVALID_ARGUMENT:
1482 		case SCF_ERROR_NOT_SET:
1483 		default:
1484 			bad_error("scf_instance_get_snapshot", scf_error());
1485 		}
1486 
1487 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1488 			switch (scf_error()) {
1489 			case SCF_ERROR_EXISTS:
1490 				goto again;
1491 
1492 			case SCF_ERROR_CONNECTION_BROKEN:
1493 			case SCF_ERROR_NO_RESOURCES:
1494 			case SCF_ERROR_PERMISSION_DENIED:
1495 				return (scferror2errno(scf_error()));
1496 
1497 			default:
1498 				scfwarn();
1499 				return (-1);
1500 
1501 			case SCF_ERROR_NOT_SET:
1502 			case SCF_ERROR_INTERNAL:
1503 			case SCF_ERROR_INVALID_ARGUMENT:
1504 			case SCF_ERROR_HANDLE_MISMATCH:
1505 				bad_error("_scf_snapshot_take_new",
1506 				    scf_error());
1507 			}
1508 		}
1509 	}
1510 
1511 	return (0);
1512 }
1513 
1514 static int
1515 refresh_running_snapshot(void *entity)
1516 {
1517 	scf_snapshot_t *snap;
1518 	int r;
1519 
1520 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1521 		scfdie();
1522 	r = take_snap(entity, snap_running, snap);
1523 	scf_snapshot_destroy(snap);
1524 
1525 	return (r);
1526 }
1527 
1528 /*
1529  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1530  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1531  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1532  * for scratch space.  Returns
1533  *   0 - success
1534  *   ECONNABORTED - repository connection broken
1535  *   ECANCELED - entity was deleted
1536  *   EACCES - backend denied access
1537  *   EPERM - permission denied
1538  *   ENOSPC - repository server out of resources
1539  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1540  */
1541 static int
1542 refresh_entity(int isservice, void *entity, const char *fmri,
1543     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1544 {
1545 	scf_error_t scfe;
1546 	int r;
1547 
1548 	if (!isservice) {
1549 		/*
1550 		 * Let restarter handles refreshing and making new running
1551 		 * snapshot only if operating on a live repository and not
1552 		 * running in early import.
1553 		 */
1554 		if (est->sc_repo_filename == NULL &&
1555 		    est->sc_repo_doorname == NULL &&
1556 		    est->sc_in_emi == 0) {
1557 			if (_smf_refresh_instance_i(entity) == 0) {
1558 				if (g_verbose)
1559 					warn(gettext("Refreshed %s.\n"), fmri);
1560 				return (0);
1561 			}
1562 
1563 			switch (scf_error()) {
1564 			case SCF_ERROR_BACKEND_ACCESS:
1565 				return (EACCES);
1566 
1567 			case SCF_ERROR_PERMISSION_DENIED:
1568 				return (EPERM);
1569 
1570 			default:
1571 				return (-1);
1572 			}
1573 		} else {
1574 			r = refresh_running_snapshot(entity);
1575 			switch (r) {
1576 			case 0:
1577 				break;
1578 
1579 			case ECONNABORTED:
1580 			case ECANCELED:
1581 			case EPERM:
1582 			case ENOSPC:
1583 				break;
1584 
1585 			default:
1586 				bad_error("refresh_running_snapshot",
1587 				    scf_error());
1588 			}
1589 
1590 			return (r);
1591 		}
1592 	}
1593 
1594 	if (scf_iter_service_instances(iter, entity) != 0) {
1595 		switch (scf_error()) {
1596 		case SCF_ERROR_CONNECTION_BROKEN:
1597 			return (ECONNABORTED);
1598 
1599 		case SCF_ERROR_DELETED:
1600 			return (ECANCELED);
1601 
1602 		case SCF_ERROR_HANDLE_MISMATCH:
1603 		case SCF_ERROR_NOT_BOUND:
1604 		case SCF_ERROR_NOT_SET:
1605 		default:
1606 			bad_error("scf_iter_service_instances", scf_error());
1607 		}
1608 	}
1609 
1610 	for (;;) {
1611 		r = scf_iter_next_instance(iter, inst);
1612 		if (r == 0)
1613 			break;
1614 		if (r != 1) {
1615 			switch (scf_error()) {
1616 			case SCF_ERROR_CONNECTION_BROKEN:
1617 				return (ECONNABORTED);
1618 
1619 			case SCF_ERROR_DELETED:
1620 				return (ECANCELED);
1621 
1622 			case SCF_ERROR_HANDLE_MISMATCH:
1623 			case SCF_ERROR_NOT_BOUND:
1624 			case SCF_ERROR_NOT_SET:
1625 			case SCF_ERROR_INVALID_ARGUMENT:
1626 			default:
1627 				bad_error("scf_iter_next_instance",
1628 				    scf_error());
1629 			}
1630 		}
1631 
1632 		/*
1633 		 * Similarly, just take a new running snapshot if operating on
1634 		 * a non-live repository or running during early import.
1635 		 */
1636 		if (est->sc_repo_filename != NULL ||
1637 		    est->sc_repo_doorname != NULL ||
1638 		    est->sc_in_emi == 1) {
1639 			r = refresh_running_snapshot(inst);
1640 			switch (r) {
1641 			case 0:
1642 				continue;
1643 
1644 			case ECONNABORTED:
1645 			case ECANCELED:
1646 			case EPERM:
1647 			case ENOSPC:
1648 				break;
1649 			default:
1650 				bad_error("refresh_running_snapshot",
1651 				    scf_error());
1652 			}
1653 
1654 			return (r);
1655 
1656 		}
1657 
1658 		if (_smf_refresh_instance_i(inst) == 0) {
1659 			if (g_verbose) {
1660 				if (scf_instance_get_name(inst, name_buf,
1661 				    max_scf_name_len + 1) < 0)
1662 					(void) strcpy(name_buf, "?");
1663 
1664 				warn(gettext("Refreshed %s:%s.\n"),
1665 				    fmri, name_buf);
1666 			}
1667 		} else {
1668 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1669 			    g_verbose) {
1670 				scfe = scf_error();
1671 
1672 				if (scf_instance_to_fmri(inst, name_buf,
1673 				    max_scf_name_len + 1) < 0)
1674 					(void) strcpy(name_buf, "?");
1675 
1676 				warn(gettext(
1677 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1678 				    name_buf, scf_strerror(scfe));
1679 			}
1680 		}
1681 	}
1682 
1683 	return (0);
1684 }
1685 
1686 static void
1687 private_refresh(void)
1688 {
1689 	scf_instance_t *pinst = NULL;
1690 	scf_iter_t *piter = NULL;
1691 	ssize_t fmrilen;
1692 	size_t bufsz;
1693 	char *fmribuf;
1694 	void *ent;
1695 	int issvc;
1696 	int r;
1697 
1698 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1699 		return;
1700 
1701 	assert(cur_svc != NULL);
1702 
1703 	bufsz = max_scf_fmri_len + 1;
1704 	fmribuf = safe_malloc(bufsz);
1705 	if (cur_inst) {
1706 		issvc = 0;
1707 		ent = cur_inst;
1708 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1709 	} else {
1710 		issvc = 1;
1711 		ent = cur_svc;
1712 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1713 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1714 			scfdie();
1715 
1716 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1717 			scfdie();
1718 	}
1719 	if (fmrilen < 0) {
1720 		free(fmribuf);
1721 		if (scf_error() != SCF_ERROR_DELETED)
1722 			scfdie();
1723 
1724 		warn(emsg_deleted);
1725 		return;
1726 	}
1727 	assert(fmrilen < bufsz);
1728 
1729 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1730 	switch (r) {
1731 	case 0:
1732 		break;
1733 
1734 	case ECONNABORTED:
1735 		warn(gettext("Could not refresh %s "
1736 		    "(repository connection broken).\n"), fmribuf);
1737 		break;
1738 
1739 	case ECANCELED:
1740 		warn(emsg_deleted);
1741 		break;
1742 
1743 	case EPERM:
1744 		warn(gettext("Could not refresh %s "
1745 		    "(permission denied).\n"), fmribuf);
1746 		break;
1747 
1748 	case ENOSPC:
1749 		warn(gettext("Could not refresh %s "
1750 		    "(repository server out of resources).\n"),
1751 		    fmribuf);
1752 		break;
1753 
1754 	case EACCES:
1755 	default:
1756 		bad_error("refresh_entity", scf_error());
1757 	}
1758 
1759 	if (issvc) {
1760 		scf_instance_destroy(pinst);
1761 		scf_iter_destroy(piter);
1762 	}
1763 
1764 	free(fmribuf);
1765 }
1766 
1767 
1768 static int
1769 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1770 {
1771 	cbp->sc_err = scferror2errno(err);
1772 	return (UU_WALK_ERROR);
1773 }
1774 
1775 static int
1776 stash_scferror(scf_callback_t *cbp)
1777 {
1778 	return (stash_scferror_err(cbp, scf_error()));
1779 }
1780 
1781 static int select_inst(const char *);
1782 static int select_svc(const char *);
1783 
1784 /*
1785  * Take a property that does not have a type and check to see if a type
1786  * exists or can be gleened from the current data.  Set the type.
1787  *
1788  * Check the current level (instance) and then check the higher level
1789  * (service).  This could be the case for adding a new property to
1790  * the instance that's going to "override" a service level property.
1791  *
1792  * For a property :
1793  * 1. Take the type from an existing property
1794  * 2. Take the type from a template entry
1795  *
1796  * If the type can not be found, then leave the type as is, and let the import
1797  * report the problem of the missing type.
1798  */
1799 static int
1800 find_current_prop_type(void *p, void *g)
1801 {
1802 	property_t *prop = p;
1803 	scf_callback_t *lcb = g;
1804 	pgroup_t *pg = NULL;
1805 
1806 	const char *fmri = NULL;
1807 	char *lfmri = NULL;
1808 	char *cur_selection = NULL;
1809 
1810 	scf_propertygroup_t *sc_pg = NULL;
1811 	scf_property_t *sc_prop = NULL;
1812 	scf_pg_tmpl_t *t_pg = NULL;
1813 	scf_prop_tmpl_t *t_prop = NULL;
1814 	scf_type_t prop_type;
1815 
1816 	value_t *vp;
1817 	int issvc = lcb->sc_service;
1818 	int r = UU_WALK_ERROR;
1819 
1820 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1821 		return (UU_WALK_NEXT);
1822 
1823 	t_prop = scf_tmpl_prop_create(g_hndl);
1824 	sc_prop = scf_property_create(g_hndl);
1825 	if (sc_prop == NULL || t_prop == NULL) {
1826 		warn(gettext("Unable to create the property to attempt and "
1827 		    "find a missing type.\n"));
1828 
1829 		scf_property_destroy(sc_prop);
1830 		scf_tmpl_prop_destroy(t_prop);
1831 
1832 		return (UU_WALK_ERROR);
1833 	}
1834 
1835 	if (lcb->sc_flags == 1) {
1836 		pg = lcb->sc_parent;
1837 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1838 		fmri = pg->sc_parent->sc_fmri;
1839 retry_pg:
1840 		if (cur_svc && cur_selection == NULL) {
1841 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1842 			lscf_get_selection_str(cur_selection,
1843 			    max_scf_fmri_len + 1);
1844 
1845 			if (strcmp(cur_selection, fmri) != 0) {
1846 				lscf_select(fmri);
1847 			} else {
1848 				free(cur_selection);
1849 				cur_selection = NULL;
1850 			}
1851 		} else {
1852 			lscf_select(fmri);
1853 		}
1854 
1855 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1856 			warn(gettext("Unable to create property group to "
1857 			    "find a missing property type.\n"));
1858 
1859 			goto out;
1860 		}
1861 
1862 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1863 			/*
1864 			 * If this is the sc_pg from the parent
1865 			 * let the caller clean up the sc_pg,
1866 			 * and just throw it away in this case.
1867 			 */
1868 			if (sc_pg != lcb->sc_parent)
1869 				scf_pg_destroy(sc_pg);
1870 
1871 			sc_pg = NULL;
1872 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1873 				warn(gettext("Unable to create template "
1874 				    "property group to find a property "
1875 				    "type.\n"));
1876 
1877 				goto out;
1878 			}
1879 
1880 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1881 			    pg->sc_pgroup_name, NULL, t_pg,
1882 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1883 				/*
1884 				 * if instance get service and jump back
1885 				 */
1886 				scf_tmpl_pg_destroy(t_pg);
1887 				t_pg = NULL;
1888 				if (issvc == 0) {
1889 					entity_t *e = pg->sc_parent->sc_parent;
1890 
1891 					fmri = e->sc_fmri;
1892 					issvc = 1;
1893 					goto retry_pg;
1894 				} else {
1895 					goto out;
1896 				}
1897 			}
1898 		}
1899 	} else {
1900 		sc_pg = lcb->sc_parent;
1901 	}
1902 
1903 	/*
1904 	 * Attempt to get the type from an existing property.  If the property
1905 	 * cannot be found then attempt to get the type from a template entry
1906 	 * for the property.
1907 	 *
1908 	 * Finally, if at the instance level look at the service level.
1909 	 */
1910 	if (sc_pg != NULL &&
1911 	    pg_get_prop(sc_pg, prop->sc_property_name,
1912 	    sc_prop) == SCF_SUCCESS &&
1913 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1914 		prop->sc_value_type = prop_type;
1915 
1916 		/*
1917 		 * Found a type, update the value types and validate
1918 		 * the actual value against this type.
1919 		 */
1920 		for (vp = uu_list_first(prop->sc_property_values);
1921 		    vp != NULL;
1922 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1923 			vp->sc_type = prop->sc_value_type;
1924 			lxml_store_value(vp, 0, NULL);
1925 		}
1926 
1927 		r = UU_WALK_NEXT;
1928 		goto out;
1929 	}
1930 
1931 	/*
1932 	 * If we get here with t_pg set to NULL then we had to have
1933 	 * gotten an sc_pg but that sc_pg did not have the property
1934 	 * we are looking for.   So if the t_pg is not null look up
1935 	 * the template entry for the property.
1936 	 *
1937 	 * If the t_pg is null then need to attempt to get a matching
1938 	 * template entry for the sc_pg, and see if there is a property
1939 	 * entry for that template entry.
1940 	 */
1941 do_tmpl :
1942 	if (t_pg != NULL &&
1943 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1944 	    t_prop, 0) == SCF_SUCCESS) {
1945 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1946 			prop->sc_value_type = prop_type;
1947 
1948 			/*
1949 			 * Found a type, update the value types and validate
1950 			 * the actual value against this type.
1951 			 */
1952 			for (vp = uu_list_first(prop->sc_property_values);
1953 			    vp != NULL;
1954 			    vp = uu_list_next(prop->sc_property_values, vp)) {
1955 				vp->sc_type = prop->sc_value_type;
1956 				lxml_store_value(vp, 0, NULL);
1957 			}
1958 
1959 			r = UU_WALK_NEXT;
1960 			goto out;
1961 		}
1962 	} else {
1963 		if (t_pg == NULL && sc_pg) {
1964 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1965 				warn(gettext("Unable to create template "
1966 				    "property group to find a property "
1967 				    "type.\n"));
1968 
1969 				goto out;
1970 			}
1971 
1972 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
1973 				scf_tmpl_pg_destroy(t_pg);
1974 				t_pg = NULL;
1975 			} else {
1976 				goto do_tmpl;
1977 			}
1978 		}
1979 	}
1980 
1981 	if (issvc == 0) {
1982 		scf_instance_t *i;
1983 		scf_service_t *s;
1984 
1985 		issvc = 1;
1986 		if (lcb->sc_flags == 1) {
1987 			entity_t *e = pg->sc_parent->sc_parent;
1988 
1989 			fmri = e->sc_fmri;
1990 			goto retry_pg;
1991 		}
1992 
1993 		/*
1994 		 * because lcb->sc_flags was not set then this means
1995 		 * the pg was not used and can be used here.
1996 		 */
1997 		if ((pg = internal_pgroup_new()) == NULL) {
1998 			warn(gettext("Could not create internal property group "
1999 			    "to find a missing type."));
2000 
2001 			goto out;
2002 		}
2003 
2004 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2005 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2006 		    max_scf_name_len + 1) < 0)
2007 				goto out;
2008 
2009 		i = scf_instance_create(g_hndl);
2010 		s = scf_service_create(g_hndl);
2011 		if (i == NULL || s == NULL ||
2012 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2013 			warn(gettext("Could not get a service for the instance "
2014 			    "to find a missing type."));
2015 
2016 			goto out;
2017 		}
2018 
2019 		/*
2020 		 * Check to see truly at the instance level.
2021 		 */
2022 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2023 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2024 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2025 			goto out;
2026 		else
2027 			fmri = (const char *)lfmri;
2028 
2029 		goto retry_pg;
2030 	}
2031 
2032 out :
2033 	if (sc_pg != lcb->sc_parent) {
2034 		scf_pg_destroy(sc_pg);
2035 	}
2036 
2037 	/*
2038 	 * If this is true then the pg was allocated
2039 	 * here, and the name was set so need to free
2040 	 * the name and the pg.
2041 	 */
2042 	if (pg != NULL && pg != lcb->sc_parent) {
2043 		free((char *)pg->sc_pgroup_name);
2044 		internal_pgroup_free(pg);
2045 	}
2046 
2047 	if (cur_selection) {
2048 		lscf_select(cur_selection);
2049 		free(cur_selection);
2050 	}
2051 
2052 	scf_tmpl_pg_destroy(t_pg);
2053 	scf_tmpl_prop_destroy(t_prop);
2054 	scf_property_destroy(sc_prop);
2055 
2056 	if (r != UU_WALK_NEXT)
2057 		warn(gettext("Could not find property type for \"%s\" "
2058 		    "from \"%s\"\n"), prop->sc_property_name,
2059 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2060 
2061 	free(lfmri);
2062 
2063 	return (r);
2064 }
2065 
2066 /*
2067  * Take a property group that does not have a type and check to see if a type
2068  * exists or can be gleened from the current data.  Set the type.
2069  *
2070  * Check the current level (instance) and then check the higher level
2071  * (service).  This could be the case for adding a new property to
2072  * the instance that's going to "override" a service level property.
2073  *
2074  * For a property group
2075  * 1. Take the type from an existing property group
2076  * 2. Take the type from a template entry
2077  *
2078  * If the type can not be found, then leave the type as is, and let the import
2079  * report the problem of the missing type.
2080  */
2081 static int
2082 find_current_pg_type(void *p, void *sori)
2083 {
2084 	entity_t *si = sori;
2085 	pgroup_t *pg = p;
2086 
2087 	const char *ofmri, *fmri;
2088 	char *cur_selection = NULL;
2089 	char *pg_type = NULL;
2090 
2091 	scf_propertygroup_t *sc_pg = NULL;
2092 	scf_pg_tmpl_t *t_pg = NULL;
2093 
2094 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2095 	int r = UU_WALK_ERROR;
2096 
2097 	ofmri = fmri = si->sc_fmri;
2098 	if (pg->sc_pgroup_type != NULL) {
2099 		r = UU_WALK_NEXT;
2100 
2101 		goto out;
2102 	}
2103 
2104 	sc_pg = scf_pg_create(g_hndl);
2105 	if (sc_pg == NULL) {
2106 		warn(gettext("Unable to create property group to attempt "
2107 		    "and find a missing type.\n"));
2108 
2109 		return (UU_WALK_ERROR);
2110 	}
2111 
2112 	/*
2113 	 * Using get_pg() requires that the cur_svc/cur_inst be
2114 	 * via lscf_select.  Need to preserve the current selection
2115 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2116 	 */
2117 	if (cur_svc) {
2118 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2119 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2120 	}
2121 
2122 	/*
2123 	 * If the property group exists get the type, and set
2124 	 * the pgroup_t type of that type.
2125 	 *
2126 	 * If not the check for a template pg_pattern entry
2127 	 * and take the type from that.
2128 	 */
2129 retry_svc:
2130 	lscf_select(fmri);
2131 
2132 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2133 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2134 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2135 		    max_scf_pg_type_len + 1) != -1) {
2136 			pg->sc_pgroup_type = pg_type;
2137 
2138 			r = UU_WALK_NEXT;
2139 			goto out;
2140 		} else {
2141 			free(pg_type);
2142 		}
2143 	} else {
2144 		if ((t_pg == NULL) &&
2145 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2146 			goto out;
2147 
2148 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2149 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2150 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2151 			pg->sc_pgroup_type = pg_type;
2152 
2153 			r = UU_WALK_NEXT;
2154 			goto out;
2155 		}
2156 	}
2157 
2158 	/*
2159 	 * If type is not found at the instance level then attempt to
2160 	 * find the type at the service level.
2161 	 */
2162 	if (!issvc) {
2163 		si = si->sc_parent;
2164 		fmri = si->sc_fmri;
2165 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2166 		goto retry_svc;
2167 	}
2168 
2169 out :
2170 	if (cur_selection) {
2171 		lscf_select(cur_selection);
2172 		free(cur_selection);
2173 	}
2174 
2175 	/*
2176 	 * Now walk the properties of the property group to make sure that
2177 	 * all properties have the correct type and values are valid for
2178 	 * those types.
2179 	 */
2180 	if (r == UU_WALK_NEXT) {
2181 		scf_callback_t cb;
2182 
2183 		cb.sc_service = issvc;
2184 		cb.sc_source_fmri = ofmri;
2185 		if (sc_pg != NULL) {
2186 			cb.sc_parent = sc_pg;
2187 			cb.sc_flags = 0;
2188 		} else {
2189 			cb.sc_parent = pg;
2190 			cb.sc_flags = 1;
2191 		}
2192 
2193 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2194 		    &cb, UU_DEFAULT) != 0) {
2195 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2196 				bad_error("uu_list_walk", uu_error());
2197 
2198 			r = UU_WALK_ERROR;
2199 		}
2200 	} else {
2201 		warn(gettext("Could not find property group type for "
2202 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2203 	}
2204 
2205 	scf_tmpl_pg_destroy(t_pg);
2206 	scf_pg_destroy(sc_pg);
2207 
2208 	return (r);
2209 }
2210 
2211 /*
2212  * Import.  These functions import a bundle into the repository.
2213  */
2214 
2215 /*
2216  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2217  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2218  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2219  * lcbdata->sc_err to
2220  *   ENOMEM - out of memory
2221  *   ECONNABORTED - repository connection broken
2222  *   ECANCELED - sc_trans's property group was deleted
2223  *   EINVAL - p's name is invalid (error printed)
2224  *	    - p has an invalid value (error printed)
2225  */
2226 static int
2227 lscf_property_import(void *v, void *pvt)
2228 {
2229 	property_t *p = v;
2230 	scf_callback_t *lcbdata = pvt;
2231 	value_t *vp;
2232 	scf_transaction_t *trans = lcbdata->sc_trans;
2233 	scf_transaction_entry_t *entr;
2234 	scf_value_t *val;
2235 	scf_type_t tp;
2236 
2237 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2238 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2239 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2240 		lcbdata->sc_enable = p;
2241 		return (UU_WALK_NEXT);
2242 	}
2243 
2244 	entr = scf_entry_create(lcbdata->sc_handle);
2245 	if (entr == NULL) {
2246 		switch (scf_error()) {
2247 		case SCF_ERROR_NO_MEMORY:
2248 			return (stash_scferror(lcbdata));
2249 
2250 		case SCF_ERROR_INVALID_ARGUMENT:
2251 		default:
2252 			bad_error("scf_entry_create", scf_error());
2253 		}
2254 	}
2255 
2256 	tp = p->sc_value_type;
2257 
2258 	if (scf_transaction_property_new(trans, entr,
2259 	    p->sc_property_name, tp) != 0) {
2260 		switch (scf_error()) {
2261 		case SCF_ERROR_INVALID_ARGUMENT:
2262 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2263 			scf_entry_destroy(entr);
2264 			return (stash_scferror(lcbdata));
2265 
2266 		case SCF_ERROR_EXISTS:
2267 			break;
2268 
2269 		case SCF_ERROR_DELETED:
2270 		case SCF_ERROR_CONNECTION_BROKEN:
2271 			scf_entry_destroy(entr);
2272 			return (stash_scferror(lcbdata));
2273 
2274 		case SCF_ERROR_NOT_BOUND:
2275 		case SCF_ERROR_HANDLE_MISMATCH:
2276 		case SCF_ERROR_NOT_SET:
2277 		default:
2278 			bad_error("scf_transaction_property_new", scf_error());
2279 		}
2280 
2281 		if (scf_transaction_property_change_type(trans, entr,
2282 		    p->sc_property_name, tp) != 0) {
2283 			switch (scf_error()) {
2284 			case SCF_ERROR_DELETED:
2285 			case SCF_ERROR_CONNECTION_BROKEN:
2286 				scf_entry_destroy(entr);
2287 				return (stash_scferror(lcbdata));
2288 
2289 			case SCF_ERROR_INVALID_ARGUMENT:
2290 				semerr(emsg_invalid_prop_name,
2291 				    p->sc_property_name);
2292 				scf_entry_destroy(entr);
2293 				return (stash_scferror(lcbdata));
2294 
2295 			case SCF_ERROR_NOT_FOUND:
2296 			case SCF_ERROR_NOT_SET:
2297 			case SCF_ERROR_HANDLE_MISMATCH:
2298 			case SCF_ERROR_NOT_BOUND:
2299 			default:
2300 				bad_error(
2301 				    "scf_transaction_property_change_type",
2302 				    scf_error());
2303 			}
2304 		}
2305 	}
2306 
2307 	for (vp = uu_list_first(p->sc_property_values);
2308 	    vp != NULL;
2309 	    vp = uu_list_next(p->sc_property_values, vp)) {
2310 		val = scf_value_create(g_hndl);
2311 		if (val == NULL) {
2312 			switch (scf_error()) {
2313 			case SCF_ERROR_NO_MEMORY:
2314 				return (stash_scferror(lcbdata));
2315 
2316 			case SCF_ERROR_INVALID_ARGUMENT:
2317 			default:
2318 				bad_error("scf_value_create", scf_error());
2319 			}
2320 		}
2321 
2322 		switch (tp) {
2323 		case SCF_TYPE_BOOLEAN:
2324 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2325 			break;
2326 		case SCF_TYPE_COUNT:
2327 			scf_value_set_count(val, vp->sc_u.sc_count);
2328 			break;
2329 		case SCF_TYPE_INTEGER:
2330 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2331 			break;
2332 		default:
2333 			assert(vp->sc_u.sc_string != NULL);
2334 			if (scf_value_set_from_string(val, tp,
2335 			    vp->sc_u.sc_string) != 0) {
2336 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2337 					bad_error("scf_value_set_from_string",
2338 					    scf_error());
2339 
2340 				warn(gettext("Value \"%s\" is not a valid "
2341 				    "%s.\n"), vp->sc_u.sc_string,
2342 				    scf_type_to_string(tp));
2343 				scf_value_destroy(val);
2344 				return (stash_scferror(lcbdata));
2345 			}
2346 			break;
2347 		}
2348 
2349 		if (scf_entry_add_value(entr, val) != 0)
2350 			bad_error("scf_entry_add_value", scf_error());
2351 	}
2352 
2353 	return (UU_WALK_NEXT);
2354 }
2355 
2356 /*
2357  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2358  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2359  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2360  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2361  * lcbdata->sc_err to
2362  *   ECONNABORTED - repository connection broken
2363  *   ENOMEM - out of memory
2364  *   ENOSPC - svc.configd is out of resources
2365  *   ECANCELED - sc_parent was deleted
2366  *   EPERM - could not create property group (permission denied) (error printed)
2367  *	   - could not modify property group (permission denied) (error printed)
2368  *	   - could not delete property group (permission denied) (error	printed)
2369  *   EROFS - could not create property group (repository is read-only)
2370  *	   - could not delete property group (repository is read-only)
2371  *   EACCES - could not create property group (backend access denied)
2372  *	    - could not delete property group (backend access denied)
2373  *   EEXIST - could not create property group (already exists)
2374  *   EINVAL - invalid property group name (error printed)
2375  *	    - invalid property name (error printed)
2376  *	    - invalid value (error printed)
2377  *   EBUSY - new property group deleted (error printed)
2378  *	   - new property group changed (error printed)
2379  *	   - property group added (error printed)
2380  *	   - property group deleted (error printed)
2381  */
2382 static int
2383 entity_pgroup_import(void *v, void *pvt)
2384 {
2385 	pgroup_t *p = v;
2386 	scf_callback_t cbdata;
2387 	scf_callback_t *lcbdata = pvt;
2388 	void *ent = lcbdata->sc_parent;
2389 	int issvc = lcbdata->sc_service;
2390 	int r;
2391 
2392 	const char * const pg_changed = gettext("%s changed unexpectedly "
2393 	    "(new property group \"%s\" changed).\n");
2394 
2395 	/* Never import deleted property groups. */
2396 	if (p->sc_pgroup_delete) {
2397 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2398 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2399 			goto delete_pg;
2400 		}
2401 		return (UU_WALK_NEXT);
2402 	}
2403 
2404 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2405 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2406 		lcbdata->sc_general = p;
2407 		return (UU_WALK_NEXT);
2408 	}
2409 
2410 add_pg:
2411 	if (issvc)
2412 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2413 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2414 	else
2415 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2416 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2417 	if (r != 0) {
2418 		switch (scf_error()) {
2419 		case SCF_ERROR_DELETED:
2420 		case SCF_ERROR_CONNECTION_BROKEN:
2421 		case SCF_ERROR_BACKEND_READONLY:
2422 		case SCF_ERROR_BACKEND_ACCESS:
2423 		case SCF_ERROR_NO_RESOURCES:
2424 			return (stash_scferror(lcbdata));
2425 
2426 		case SCF_ERROR_EXISTS:
2427 			if (lcbdata->sc_flags & SCI_FORCE)
2428 				break;
2429 			return (stash_scferror(lcbdata));
2430 
2431 		case SCF_ERROR_INVALID_ARGUMENT:
2432 			warn(emsg_fmri_invalid_pg_name_type,
2433 			    lcbdata->sc_source_fmri,
2434 			    p->sc_pgroup_name, p->sc_pgroup_type);
2435 			return (stash_scferror(lcbdata));
2436 
2437 		case SCF_ERROR_PERMISSION_DENIED:
2438 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2439 			    lcbdata->sc_target_fmri);
2440 			return (stash_scferror(lcbdata));
2441 
2442 		case SCF_ERROR_NOT_BOUND:
2443 		case SCF_ERROR_HANDLE_MISMATCH:
2444 		case SCF_ERROR_NOT_SET:
2445 		default:
2446 			bad_error("scf_service_add_pg", scf_error());
2447 		}
2448 
2449 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2450 			switch (scf_error()) {
2451 			case SCF_ERROR_CONNECTION_BROKEN:
2452 			case SCF_ERROR_DELETED:
2453 				return (stash_scferror(lcbdata));
2454 
2455 			case SCF_ERROR_INVALID_ARGUMENT:
2456 				warn(emsg_fmri_invalid_pg_name,
2457 				    lcbdata->sc_source_fmri,
2458 				    p->sc_pgroup_name);
2459 				return (stash_scferror(lcbdata));
2460 
2461 			case SCF_ERROR_NOT_FOUND:
2462 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2463 				    p->sc_pgroup_name);
2464 				lcbdata->sc_err = EBUSY;
2465 				return (UU_WALK_ERROR);
2466 
2467 			case SCF_ERROR_NOT_BOUND:
2468 			case SCF_ERROR_HANDLE_MISMATCH:
2469 			case SCF_ERROR_NOT_SET:
2470 			default:
2471 				bad_error("entity_get_pg", scf_error());
2472 			}
2473 		}
2474 
2475 		if (lcbdata->sc_flags & SCI_KEEP)
2476 			goto props;
2477 
2478 delete_pg:
2479 		if (scf_pg_delete(imp_pg) != 0) {
2480 			switch (scf_error()) {
2481 			case SCF_ERROR_DELETED:
2482 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2483 				    p->sc_pgroup_name);
2484 				lcbdata->sc_err = EBUSY;
2485 				return (UU_WALK_ERROR);
2486 
2487 			case SCF_ERROR_PERMISSION_DENIED:
2488 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2489 				    lcbdata->sc_target_fmri);
2490 				return (stash_scferror(lcbdata));
2491 
2492 			case SCF_ERROR_BACKEND_READONLY:
2493 			case SCF_ERROR_BACKEND_ACCESS:
2494 			case SCF_ERROR_CONNECTION_BROKEN:
2495 				return (stash_scferror(lcbdata));
2496 
2497 			case SCF_ERROR_NOT_SET:
2498 			default:
2499 				bad_error("scf_pg_delete", scf_error());
2500 			}
2501 		}
2502 
2503 		if (p->sc_pgroup_delete)
2504 			return (UU_WALK_NEXT);
2505 
2506 		goto add_pg;
2507 	}
2508 
2509 props:
2510 
2511 	/*
2512 	 * Add properties to property group, if any.
2513 	 */
2514 	cbdata.sc_handle = lcbdata->sc_handle;
2515 	cbdata.sc_parent = imp_pg;
2516 	cbdata.sc_flags = lcbdata->sc_flags;
2517 	cbdata.sc_trans = imp_tx;
2518 	cbdata.sc_enable = NULL;
2519 
2520 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2521 		switch (scf_error()) {
2522 		case SCF_ERROR_BACKEND_ACCESS:
2523 		case SCF_ERROR_BACKEND_READONLY:
2524 		case SCF_ERROR_CONNECTION_BROKEN:
2525 			return (stash_scferror(lcbdata));
2526 
2527 		case SCF_ERROR_DELETED:
2528 			warn(pg_changed, lcbdata->sc_target_fmri,
2529 			    p->sc_pgroup_name);
2530 			lcbdata->sc_err = EBUSY;
2531 			return (UU_WALK_ERROR);
2532 
2533 		case SCF_ERROR_PERMISSION_DENIED:
2534 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2535 			    lcbdata->sc_target_fmri);
2536 			return (stash_scferror(lcbdata));
2537 
2538 		case SCF_ERROR_NOT_BOUND:
2539 		case SCF_ERROR_NOT_SET:
2540 		case SCF_ERROR_IN_USE:
2541 		case SCF_ERROR_HANDLE_MISMATCH:
2542 		default:
2543 			bad_error("scf_transaction_start", scf_error());
2544 		}
2545 	}
2546 
2547 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2548 	    UU_DEFAULT) != 0) {
2549 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2550 			bad_error("uu_list_walk", uu_error());
2551 		scf_transaction_reset(imp_tx);
2552 
2553 		lcbdata->sc_err = cbdata.sc_err;
2554 		if (cbdata.sc_err == ECANCELED) {
2555 			warn(pg_changed, lcbdata->sc_target_fmri,
2556 			    p->sc_pgroup_name);
2557 			lcbdata->sc_err = EBUSY;
2558 		}
2559 		return (UU_WALK_ERROR);
2560 	}
2561 
2562 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2563 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2564 
2565 		/*
2566 		 * take the snapshot running snapshot then
2567 		 * import the stored general/enable property
2568 		 */
2569 		r = take_snap(ent, snap_running, imp_rsnap);
2570 		switch (r) {
2571 		case 0:
2572 			break;
2573 
2574 		case ECONNABORTED:
2575 			warn(gettext("Could not take %s snapshot on import "
2576 			    "(repository connection broken).\n"),
2577 			    snap_running);
2578 			lcbdata->sc_err = r;
2579 			return (UU_WALK_ERROR);
2580 		case ECANCELED:
2581 			warn(emsg_deleted);
2582 			lcbdata->sc_err = r;
2583 			return (UU_WALK_ERROR);
2584 
2585 		case EPERM:
2586 			warn(gettext("Could not take %s snapshot "
2587 			    "(permission denied).\n"), snap_running);
2588 			lcbdata->sc_err = r;
2589 			return (UU_WALK_ERROR);
2590 
2591 		case ENOSPC:
2592 			warn(gettext("Could not take %s snapshot"
2593 			    "(repository server out of resources).\n"),
2594 			    snap_running);
2595 			lcbdata->sc_err = r;
2596 			return (UU_WALK_ERROR);
2597 
2598 		default:
2599 			bad_error("take_snap", r);
2600 		}
2601 
2602 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2603 		if (r != UU_WALK_NEXT) {
2604 			if (r != UU_WALK_ERROR)
2605 				bad_error("lscf_property_import", r);
2606 			return (EINVAL);
2607 		}
2608 	}
2609 
2610 	r = scf_transaction_commit(imp_tx);
2611 	switch (r) {
2612 	case 1:
2613 		r = UU_WALK_NEXT;
2614 		break;
2615 
2616 	case 0:
2617 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2618 		lcbdata->sc_err = EBUSY;
2619 		r = UU_WALK_ERROR;
2620 		break;
2621 
2622 	case -1:
2623 		switch (scf_error()) {
2624 		case SCF_ERROR_BACKEND_READONLY:
2625 		case SCF_ERROR_BACKEND_ACCESS:
2626 		case SCF_ERROR_CONNECTION_BROKEN:
2627 		case SCF_ERROR_NO_RESOURCES:
2628 			r = stash_scferror(lcbdata);
2629 			break;
2630 
2631 		case SCF_ERROR_DELETED:
2632 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2633 			    p->sc_pgroup_name);
2634 			lcbdata->sc_err = EBUSY;
2635 			r = UU_WALK_ERROR;
2636 			break;
2637 
2638 		case SCF_ERROR_PERMISSION_DENIED:
2639 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2640 			    lcbdata->sc_target_fmri);
2641 			r = stash_scferror(lcbdata);
2642 			break;
2643 
2644 		case SCF_ERROR_NOT_SET:
2645 		case SCF_ERROR_INVALID_ARGUMENT:
2646 		case SCF_ERROR_NOT_BOUND:
2647 		default:
2648 			bad_error("scf_transaction_commit", scf_error());
2649 		}
2650 		break;
2651 
2652 	default:
2653 		bad_error("scf_transaction_commit", r);
2654 	}
2655 
2656 	scf_transaction_destroy_children(imp_tx);
2657 
2658 	return (r);
2659 }
2660 
2661 /*
2662  * Returns
2663  *   0 - success
2664  *   ECONNABORTED - repository connection broken
2665  *   ENOMEM - out of memory
2666  *   ENOSPC - svc.configd is out of resources
2667  *   ECANCELED - inst was deleted
2668  *   EPERM - could not create property group (permission denied) (error printed)
2669  *	   - could not modify property group (permission denied) (error printed)
2670  *   EROFS - could not create property group (repository is read-only)
2671  *   EACCES - could not create property group (backend access denied)
2672  *   EEXIST - could not create property group (already exists)
2673  *   EINVAL - invalid property group name (error printed)
2674  *	    - invalid property name (error printed)
2675  *	    - invalid value (error printed)
2676  *   EBUSY - new property group changed (error printed)
2677  */
2678 static int
2679 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2680     const entity_t *isvc, int flags)
2681 {
2682 	scf_callback_t cbdata;
2683 
2684 	cbdata.sc_handle = scf_service_handle(svc);
2685 	cbdata.sc_parent = svc;
2686 	cbdata.sc_service = 1;
2687 	cbdata.sc_general = 0;
2688 	cbdata.sc_enable = 0;
2689 	cbdata.sc_flags = flags;
2690 	cbdata.sc_source_fmri = isvc->sc_fmri;
2691 	cbdata.sc_target_fmri = target_fmri;
2692 
2693 	/*
2694 	 * If the op is set, then add the flag to the callback
2695 	 * flags for later use.
2696 	 */
2697 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2698 		switch (isvc->sc_op) {
2699 		case SVCCFG_OP_IMPORT :
2700 			cbdata.sc_flags |= SCI_OP_IMPORT;
2701 			break;
2702 		case SVCCFG_OP_APPLY :
2703 			cbdata.sc_flags |= SCI_OP_APPLY;
2704 			break;
2705 		case SVCCFG_OP_RESTORE :
2706 			cbdata.sc_flags |= SCI_OP_RESTORE;
2707 			break;
2708 		default :
2709 			uu_die(gettext("lscf_import_service_pgs : "
2710 			    "Unknown op stored in the service entity\n"));
2711 
2712 		}
2713 	}
2714 
2715 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2716 	    UU_DEFAULT) != 0) {
2717 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2718 			bad_error("uu_list_walk", uu_error());
2719 
2720 		return (cbdata.sc_err);
2721 	}
2722 
2723 	return (0);
2724 }
2725 
2726 /*
2727  * Returns
2728  *   0 - success
2729  *   ECONNABORTED - repository connection broken
2730  *   ENOMEM - out of memory
2731  *   ENOSPC - svc.configd is out of resources
2732  *   ECANCELED - inst was deleted
2733  *   EPERM - could not create property group (permission denied) (error printed)
2734  *	   - could not modify property group (permission denied) (error printed)
2735  *   EROFS - could not create property group (repository is read-only)
2736  *   EACCES - could not create property group (backend access denied)
2737  *   EEXIST - could not create property group (already exists)
2738  *   EINVAL - invalid property group name (error printed)
2739  *	    - invalid property name (error printed)
2740  *	    - invalid value (error printed)
2741  *   EBUSY - new property group changed (error printed)
2742  */
2743 static int
2744 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2745     const entity_t *iinst, int flags)
2746 {
2747 	scf_callback_t cbdata;
2748 
2749 	cbdata.sc_handle = scf_instance_handle(inst);
2750 	cbdata.sc_parent = inst;
2751 	cbdata.sc_service = 0;
2752 	cbdata.sc_general = NULL;
2753 	cbdata.sc_enable = NULL;
2754 	cbdata.sc_flags = flags;
2755 	cbdata.sc_source_fmri = iinst->sc_fmri;
2756 	cbdata.sc_target_fmri = target_fmri;
2757 
2758 	/*
2759 	 * If the op is set, then add the flag to the callback
2760 	 * flags for later use.
2761 	 */
2762 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2763 		switch (iinst->sc_op) {
2764 		case SVCCFG_OP_IMPORT :
2765 			cbdata.sc_flags |= SCI_OP_IMPORT;
2766 			break;
2767 		case SVCCFG_OP_APPLY :
2768 			cbdata.sc_flags |= SCI_OP_APPLY;
2769 			break;
2770 		case SVCCFG_OP_RESTORE :
2771 			cbdata.sc_flags |= SCI_OP_RESTORE;
2772 			break;
2773 		default :
2774 			uu_die(gettext("lscf_import_instance_pgs : "
2775 			    "Unknown op stored in the instance entity\n"));
2776 		}
2777 	}
2778 
2779 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2780 	    UU_DEFAULT) != 0) {
2781 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2782 			bad_error("uu_list_walk", uu_error());
2783 
2784 		return (cbdata.sc_err);
2785 	}
2786 
2787 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2788 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2789 		/*
2790 		 * If importing with the SCI_NOENABLED flag then
2791 		 * skip the delay, but if not then add the delay
2792 		 * of the enable property.
2793 		 */
2794 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2795 			cbdata.sc_flags |= SCI_DELAYENABLE;
2796 		}
2797 
2798 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2799 		    != UU_WALK_NEXT)
2800 			return (cbdata.sc_err);
2801 	}
2802 
2803 	return (0);
2804 }
2805 
2806 /*
2807  * Report the reasons why we can't upgrade pg2 to pg1.
2808  */
2809 static void
2810 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2811     int new)
2812 {
2813 	property_t *p1, *p2;
2814 
2815 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2816 
2817 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2818 		return;
2819 
2820 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2821 	    p1 != NULL;
2822 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2823 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2824 		if (p2 != NULL) {
2825 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2826 			    new);
2827 			continue;
2828 		}
2829 
2830 		if (new)
2831 			warn(gettext("Conflict upgrading %s (new property "
2832 			    "group \"%s\" is missing property \"%s\").\n"),
2833 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2834 		else
2835 			warn(gettext("Conflict upgrading %s (property "
2836 			    "\"%s/%s\" is missing).\n"), fmri,
2837 			    pg1->sc_pgroup_name, p1->sc_property_name);
2838 	}
2839 
2840 	/*
2841 	 * Since pg1 should be from the manifest, any properties in pg2 which
2842 	 * aren't in pg1 shouldn't be reported as conflicts.
2843 	 */
2844 }
2845 
2846 /*
2847  * Add transaction entries to tx which will upgrade cur's pg according to old
2848  * & new.
2849  *
2850  * Returns
2851  *   0 - success
2852  *   EINVAL - new has a property with an invalid name or value (message emitted)
2853  *   ENOMEM - out of memory
2854  */
2855 static int
2856 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2857     pgroup_t *cur, int speak, const char *fmri)
2858 {
2859 	property_t *p, *new_p, *cur_p;
2860 	scf_transaction_entry_t *e;
2861 	int r;
2862 	int is_general;
2863 	int is_protected;
2864 
2865 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2866 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2867 		bad_error("uu_list_walk", uu_error());
2868 
2869 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2870 
2871 	for (p = uu_list_first(old->sc_pgroup_props);
2872 	    p != NULL;
2873 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2874 		/* p is a property in the old property group. */
2875 
2876 		/* Protect live properties. */
2877 		is_protected = 0;
2878 		if (is_general) {
2879 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2880 			    0 ||
2881 			    strcmp(p->sc_property_name,
2882 			    SCF_PROPERTY_RESTARTER) == 0)
2883 				is_protected = 1;
2884 		}
2885 
2886 		/* Look for the same property in the new properties. */
2887 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2888 		if (new_p != NULL) {
2889 			new_p->sc_seen = 1;
2890 
2891 			/*
2892 			 * If the new property is the same as the old, don't do
2893 			 * anything (leave any user customizations).
2894 			 */
2895 			if (prop_equal(p, new_p, NULL, NULL, 0))
2896 				continue;
2897 
2898 			if (new_p->sc_property_override)
2899 				goto upgrade;
2900 		}
2901 
2902 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2903 		if (cur_p == NULL) {
2904 			/*
2905 			 * p has been deleted from the repository.  If we were
2906 			 * going to delete it anyway, do nothing.  Otherwise
2907 			 * report a conflict.
2908 			 */
2909 			if (new_p == NULL)
2910 				continue;
2911 
2912 			if (is_protected)
2913 				continue;
2914 
2915 			warn(gettext("Conflict upgrading %s "
2916 			    "(property \"%s/%s\" is missing).\n"), fmri,
2917 			    old->sc_pgroup_name, p->sc_property_name);
2918 			continue;
2919 		}
2920 
2921 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2922 			/*
2923 			 * Conflict.  Don't warn if the property is already the
2924 			 * way we want it, though.
2925 			 */
2926 			if (is_protected)
2927 				continue;
2928 
2929 			if (new_p == NULL)
2930 				(void) prop_equal(p, cur_p, fmri,
2931 				    old->sc_pgroup_name, 0);
2932 			else
2933 				(void) prop_equal(cur_p, new_p, fmri,
2934 				    old->sc_pgroup_name, 0);
2935 			continue;
2936 		}
2937 
2938 		if (is_protected) {
2939 			if (speak)
2940 				warn(gettext("%s: Refusing to upgrade "
2941 				    "\"%s/%s\" (live property).\n"), fmri,
2942 				    old->sc_pgroup_name, p->sc_property_name);
2943 			continue;
2944 		}
2945 
2946 upgrade:
2947 		/* p hasn't been customized in the repository.  Upgrade it. */
2948 		if (new_p == NULL) {
2949 			/* p was deleted.  Delete from cur if unchanged. */
2950 			if (speak)
2951 				warn(gettext(
2952 				    "%s: Deleting property \"%s/%s\".\n"),
2953 				    fmri, old->sc_pgroup_name,
2954 				    p->sc_property_name);
2955 
2956 			e = scf_entry_create(g_hndl);
2957 			if (e == NULL)
2958 				return (ENOMEM);
2959 
2960 			if (scf_transaction_property_delete(tx, e,
2961 			    p->sc_property_name) != 0) {
2962 				switch (scf_error()) {
2963 				case SCF_ERROR_DELETED:
2964 					scf_entry_destroy(e);
2965 					return (ECANCELED);
2966 
2967 				case SCF_ERROR_CONNECTION_BROKEN:
2968 					scf_entry_destroy(e);
2969 					return (ECONNABORTED);
2970 
2971 				case SCF_ERROR_NOT_FOUND:
2972 					/*
2973 					 * This can happen if cur is from the
2974 					 * running snapshot (and it differs
2975 					 * from the live properties).
2976 					 */
2977 					scf_entry_destroy(e);
2978 					break;
2979 
2980 				case SCF_ERROR_HANDLE_MISMATCH:
2981 				case SCF_ERROR_NOT_BOUND:
2982 				case SCF_ERROR_NOT_SET:
2983 				case SCF_ERROR_INVALID_ARGUMENT:
2984 				default:
2985 					bad_error(
2986 					    "scf_transaction_property_delete",
2987 					    scf_error());
2988 				}
2989 			}
2990 		} else {
2991 			scf_callback_t ctx;
2992 
2993 			if (speak)
2994 				warn(gettext(
2995 				    "%s: Upgrading property \"%s/%s\".\n"),
2996 				    fmri, old->sc_pgroup_name,
2997 				    p->sc_property_name);
2998 
2999 			ctx.sc_handle = g_hndl;
3000 			ctx.sc_trans = tx;
3001 			ctx.sc_flags = 0;
3002 
3003 			r = lscf_property_import(new_p, &ctx);
3004 			if (r != UU_WALK_NEXT) {
3005 				if (r != UU_WALK_ERROR)
3006 					bad_error("lscf_property_import", r);
3007 				return (EINVAL);
3008 			}
3009 		}
3010 	}
3011 
3012 	/* Go over the properties which were added. */
3013 	for (new_p = uu_list_first(new->sc_pgroup_props);
3014 	    new_p != NULL;
3015 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3016 		if (new_p->sc_seen)
3017 			continue;
3018 
3019 		/* This is a new property. */
3020 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3021 		if (cur_p == NULL) {
3022 			scf_callback_t ctx;
3023 
3024 			ctx.sc_handle = g_hndl;
3025 			ctx.sc_trans = tx;
3026 			ctx.sc_flags = 0;
3027 
3028 			r = lscf_property_import(new_p, &ctx);
3029 			if (r != UU_WALK_NEXT) {
3030 				if (r != UU_WALK_ERROR)
3031 					bad_error("lscf_property_import", r);
3032 				return (EINVAL);
3033 			}
3034 			continue;
3035 		}
3036 
3037 		/*
3038 		 * Report a conflict if the new property differs from the
3039 		 * current one.  Unless it's general/enabled, since that's
3040 		 * never in the last-import snapshot.
3041 		 */
3042 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3043 		    0 &&
3044 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3045 			continue;
3046 
3047 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3048 	}
3049 
3050 	return (0);
3051 }
3052 
3053 /*
3054  * Upgrade pg according to old & new.
3055  *
3056  * Returns
3057  *   0 - success
3058  *   ECONNABORTED - repository connection broken
3059  *   ENOMEM - out of memory
3060  *   ENOSPC - svc.configd is out of resources
3061  *   ECANCELED - pg was deleted
3062  *   EPERM - couldn't modify pg (permission denied)
3063  *   EROFS - couldn't modify pg (backend read-only)
3064  *   EACCES - couldn't modify pg (backend access denied)
3065  *   EINVAL - new has a property with invalid name or value (error printed)
3066  *   EBUSY - pg changed unexpectedly
3067  */
3068 static int
3069 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3070     pgroup_t *new, int speak, const char *fmri)
3071 {
3072 	int r;
3073 
3074 	if (scf_transaction_start(imp_tx, pg) != 0) {
3075 		switch (scf_error()) {
3076 		case SCF_ERROR_CONNECTION_BROKEN:
3077 		case SCF_ERROR_DELETED:
3078 		case SCF_ERROR_PERMISSION_DENIED:
3079 		case SCF_ERROR_BACKEND_READONLY:
3080 		case SCF_ERROR_BACKEND_ACCESS:
3081 			return (scferror2errno(scf_error()));
3082 
3083 		case SCF_ERROR_HANDLE_MISMATCH:
3084 		case SCF_ERROR_IN_USE:
3085 		case SCF_ERROR_NOT_BOUND:
3086 		case SCF_ERROR_NOT_SET:
3087 		default:
3088 			bad_error("scf_transaction_start", scf_error());
3089 		}
3090 	}
3091 
3092 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3093 	switch (r) {
3094 	case 0:
3095 		break;
3096 
3097 	case EINVAL:
3098 	case ENOMEM:
3099 		scf_transaction_destroy_children(imp_tx);
3100 		return (r);
3101 
3102 	default:
3103 		bad_error("add_upgrade_entries", r);
3104 	}
3105 
3106 	r = scf_transaction_commit(imp_tx);
3107 
3108 	scf_transaction_destroy_children(imp_tx);
3109 
3110 	switch (r) {
3111 	case 1:
3112 		break;
3113 
3114 	case 0:
3115 		return (EBUSY);
3116 
3117 	case -1:
3118 		switch (scf_error()) {
3119 		case SCF_ERROR_CONNECTION_BROKEN:
3120 		case SCF_ERROR_NO_RESOURCES:
3121 		case SCF_ERROR_PERMISSION_DENIED:
3122 		case SCF_ERROR_BACKEND_READONLY:
3123 		case SCF_ERROR_BACKEND_ACCESS:
3124 		case SCF_ERROR_DELETED:
3125 			return (scferror2errno(scf_error()));
3126 
3127 		case SCF_ERROR_NOT_BOUND:
3128 		case SCF_ERROR_INVALID_ARGUMENT:
3129 		case SCF_ERROR_NOT_SET:
3130 		default:
3131 			bad_error("scf_transaction_commit", scf_error());
3132 		}
3133 
3134 	default:
3135 		bad_error("scf_transaction_commit", r);
3136 	}
3137 
3138 	return (0);
3139 }
3140 
3141 /*
3142  * Compares two entity FMRIs.  Returns
3143  *
3144  *   1 - equal
3145  *   0 - not equal
3146  *   -1 - f1 is invalid or not an entity
3147  *   -2 - f2 is invalid or not an entity
3148  */
3149 static int
3150 fmri_equal(const char *f1, const char *f2)
3151 {
3152 	int r;
3153 	const char *s1, *i1, *pg1;
3154 	const char *s2, *i2, *pg2;
3155 
3156 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3157 		return (-1);
3158 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3159 		return (-1);
3160 
3161 	if (s1 == NULL || pg1 != NULL)
3162 		return (-1);
3163 
3164 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3165 		return (-2);
3166 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3167 		return (-2);
3168 
3169 	if (s2 == NULL || pg2 != NULL)
3170 		return (-2);
3171 
3172 	r = strcmp(s1, s2);
3173 	if (r != 0)
3174 		return (0);
3175 
3176 	if (i1 == NULL && i2 == NULL)
3177 		return (1);
3178 
3179 	if (i1 == NULL || i2 == NULL)
3180 		return (0);
3181 
3182 	return (strcmp(i1, i2) == 0);
3183 }
3184 
3185 /*
3186  * Import a dependent by creating a dependency property group in the dependent
3187  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3188  * dependents pg, and add an entry to create a new property for this
3189  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3190  *
3191  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3192  * lcbdata->sc_err to
3193  *   ECONNABORTED - repository connection broken
3194  *   ENOMEM - out of memory
3195  *   ENOSPC - configd is out of resources
3196  *   EINVAL - target is invalid (error printed)
3197  *	    - target is not an entity (error printed)
3198  *	    - dependent has invalid name (error printed)
3199  *	    - invalid property name (error printed)
3200  *	    - invalid value (error printed)
3201  *	    - scope of target does not exist (error printed)
3202  *   EPERM - couldn't create target (permission denied) (error printed)
3203  *	   - couldn't create dependency pg (permission denied) (error printed)
3204  *	   - couldn't modify dependency pg (permission denied) (error printed)
3205  *   EROFS - couldn't create target (repository read-only)
3206  *	   - couldn't create dependency pg (repository read-only)
3207  *   EACCES - couldn't create target (backend access denied)
3208  *	    - couldn't create dependency pg (backend access denied)
3209  *   ECANCELED - sc_trans's pg was deleted
3210  *   EALREADY - property for dependent already exists in sc_trans's pg
3211  *   EEXIST - dependency pg already exists in target (error printed)
3212  *   EBUSY - target deleted (error printed)
3213  *         - property group changed during import (error printed)
3214  */
3215 static int
3216 lscf_dependent_import(void *a1, void *pvt)
3217 {
3218 	pgroup_t *pgrp = a1;
3219 	scf_callback_t *lcbdata = pvt;
3220 
3221 	int isservice;
3222 	int ret;
3223 	scf_transaction_entry_t *e;
3224 	scf_value_t *val;
3225 	scf_callback_t dependent_cbdata;
3226 	scf_error_t scfe;
3227 
3228 	/*
3229 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3230 	 * it's invalid, we fail before modifying the repository.
3231 	 */
3232 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3233 	    &dependent_cbdata.sc_parent, &isservice);
3234 	switch (scfe) {
3235 	case SCF_ERROR_NONE:
3236 		break;
3237 
3238 	case SCF_ERROR_NO_MEMORY:
3239 		return (stash_scferror_err(lcbdata, scfe));
3240 
3241 	case SCF_ERROR_INVALID_ARGUMENT:
3242 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3243 		    "invalid.\n"), pgrp->sc_pgroup_name);
3244 		return (stash_scferror_err(lcbdata, scfe));
3245 
3246 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3247 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3248 		    "specifies neither a service nor an instance.\n"),
3249 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3250 		return (stash_scferror_err(lcbdata, scfe));
3251 
3252 	case SCF_ERROR_NOT_FOUND:
3253 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3254 		    &dependent_cbdata.sc_parent, &isservice);
3255 		switch (scfe) {
3256 		case SCF_ERROR_NONE:
3257 			break;
3258 
3259 		case SCF_ERROR_NO_MEMORY:
3260 		case SCF_ERROR_BACKEND_READONLY:
3261 		case SCF_ERROR_BACKEND_ACCESS:
3262 			return (stash_scferror_err(lcbdata, scfe));
3263 
3264 		case SCF_ERROR_NOT_FOUND:
3265 			semerr(gettext("The scope in FMRI \"%s\" for the "
3266 			    "\"%s\" dependent does not exist.\n"),
3267 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3268 			lcbdata->sc_err = EINVAL;
3269 			return (UU_WALK_ERROR);
3270 
3271 		case SCF_ERROR_PERMISSION_DENIED:
3272 			warn(gettext(
3273 			    "Could not create %s (permission denied).\n"),
3274 			    pgrp->sc_pgroup_fmri);
3275 			return (stash_scferror_err(lcbdata, scfe));
3276 
3277 		case SCF_ERROR_INVALID_ARGUMENT:
3278 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3279 		default:
3280 			bad_error("create_entity", scfe);
3281 		}
3282 		break;
3283 
3284 	default:
3285 		bad_error("fmri_to_entity", scfe);
3286 	}
3287 
3288 	if (lcbdata->sc_trans != NULL) {
3289 		e = scf_entry_create(lcbdata->sc_handle);
3290 		if (e == NULL) {
3291 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3292 				bad_error("scf_entry_create", scf_error());
3293 
3294 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3295 			return (stash_scferror(lcbdata));
3296 		}
3297 
3298 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3299 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3300 			switch (scf_error()) {
3301 			case SCF_ERROR_INVALID_ARGUMENT:
3302 				warn(gettext("Dependent of %s has invalid name "
3303 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3304 				    pgrp->sc_pgroup_name);
3305 				/* FALLTHROUGH */
3306 
3307 			case SCF_ERROR_DELETED:
3308 			case SCF_ERROR_CONNECTION_BROKEN:
3309 				scf_entry_destroy(e);
3310 				entity_destroy(dependent_cbdata.sc_parent,
3311 				    isservice);
3312 				return (stash_scferror(lcbdata));
3313 
3314 			case SCF_ERROR_EXISTS:
3315 				scf_entry_destroy(e);
3316 				entity_destroy(dependent_cbdata.sc_parent,
3317 				    isservice);
3318 				lcbdata->sc_err = EALREADY;
3319 				return (UU_WALK_ERROR);
3320 
3321 			case SCF_ERROR_NOT_BOUND:
3322 			case SCF_ERROR_HANDLE_MISMATCH:
3323 			case SCF_ERROR_NOT_SET:
3324 			default:
3325 				bad_error("scf_transaction_property_new",
3326 				    scf_error());
3327 			}
3328 		}
3329 
3330 		val = scf_value_create(lcbdata->sc_handle);
3331 		if (val == NULL) {
3332 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3333 				bad_error("scf_value_create", scf_error());
3334 
3335 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3336 			return (stash_scferror(lcbdata));
3337 		}
3338 
3339 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3340 		    pgrp->sc_pgroup_fmri) != 0)
3341 			/* invalid should have been caught above */
3342 			bad_error("scf_value_set_from_string", scf_error());
3343 
3344 		if (scf_entry_add_value(e, val) != 0)
3345 			bad_error("scf_entry_add_value", scf_error());
3346 	}
3347 
3348 	/* Add the property group to the target entity. */
3349 
3350 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3351 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3352 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3353 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3354 
3355 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3356 
3357 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3358 
3359 	if (ret == UU_WALK_NEXT)
3360 		return (ret);
3361 
3362 	if (ret != UU_WALK_ERROR)
3363 		bad_error("entity_pgroup_import", ret);
3364 
3365 	switch (dependent_cbdata.sc_err) {
3366 	case ECANCELED:
3367 		warn(gettext("%s deleted unexpectedly.\n"),
3368 		    pgrp->sc_pgroup_fmri);
3369 		lcbdata->sc_err = EBUSY;
3370 		break;
3371 
3372 	case EEXIST:
3373 		warn(gettext("Could not create \"%s\" dependency in %s "
3374 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3375 		    pgrp->sc_pgroup_fmri);
3376 		/* FALLTHROUGH */
3377 
3378 	default:
3379 		lcbdata->sc_err = dependent_cbdata.sc_err;
3380 	}
3381 
3382 	return (UU_WALK_ERROR);
3383 }
3384 
3385 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3386     const scf_snaplevel_t *, scf_transaction_t *);
3387 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3388     const pgroup_t *);
3389 
3390 /*
3391  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3392  * the current dependent targets from running (the snaplevel of a running
3393  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3394  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3395  * dependent targets and dependency properties from li_dpts_pg (the
3396  * "dependents" property group in snpl) and snpl (the snaplevel which
3397  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3398  * snpl doesn't have a "dependents" property group, and any dependents in ient
3399  * are new.
3400  *
3401  * Returns
3402  *   0 - success
3403  *   ECONNABORTED - repository connection broken
3404  *   ENOMEM - out of memory
3405  *   ENOSPC - configd is out of resources
3406  *   ECANCELED - ent was deleted
3407  *   ENODEV - the entity containing li_dpts_pg was deleted
3408  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3409  *	   - couldn't upgrade dependent (permission denied) (error printed)
3410  *	   - couldn't create dependent (permission denied) (error printed)
3411  *   EROFS - could not modify dependents pg (repository read-only)
3412  *	   - couldn't upgrade dependent (repository read-only)
3413  *	   - couldn't create dependent (repository read-only)
3414  *   EACCES - could not modify dependents pg (backend access denied)
3415  *	    - could not upgrade dependent (backend access denied)
3416  *	    - could not create dependent (backend access denied)
3417  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3418  *	   - dependent target deleted (error printed)
3419  *	   - dependent pg changed (error printed)
3420  *   EINVAL - new dependent is invalid (error printed)
3421  *   EBADF - snpl is corrupt (error printed)
3422  *	   - snpl has corrupt pg (error printed)
3423  *	   - dependency pg in target is corrupt (error printed)
3424  *	   - target has corrupt snapshot (error printed)
3425  *   EEXIST - dependency pg already existed in target service (error printed)
3426  */
3427 static int
3428 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3429     const scf_snaplevel_t *snpl, const entity_t *ient,
3430     const scf_snaplevel_t *running, void *ent)
3431 {
3432 	pgroup_t *new_dpt_pgroup;
3433 	scf_callback_t cbdata;
3434 	int r, unseen, tx_started = 0;
3435 	int have_cur_depts;
3436 
3437 	const char * const dependents = "dependents";
3438 
3439 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3440 
3441 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3442 		/* Nothing to do. */
3443 		return (0);
3444 
3445 	/* Fetch the current version of the "dependents" property group. */
3446 	have_cur_depts = 1;
3447 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3448 		switch (scf_error()) {
3449 		case SCF_ERROR_NOT_FOUND:
3450 			break;
3451 
3452 		case SCF_ERROR_DELETED:
3453 		case SCF_ERROR_CONNECTION_BROKEN:
3454 			return (scferror2errno(scf_error()));
3455 
3456 		case SCF_ERROR_NOT_SET:
3457 		case SCF_ERROR_INVALID_ARGUMENT:
3458 		case SCF_ERROR_HANDLE_MISMATCH:
3459 		case SCF_ERROR_NOT_BOUND:
3460 		default:
3461 			bad_error("entity_get_pg", scf_error());
3462 		}
3463 
3464 		have_cur_depts = 0;
3465 	}
3466 
3467 	/* Fetch the running version of the "dependents" property group. */
3468 	ud_run_dpts_pg_set = 0;
3469 	if (running != NULL)
3470 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3471 	else
3472 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3473 	if (r == 0) {
3474 		ud_run_dpts_pg_set = 1;
3475 	} else {
3476 		switch (scf_error()) {
3477 		case SCF_ERROR_NOT_FOUND:
3478 			break;
3479 
3480 		case SCF_ERROR_DELETED:
3481 		case SCF_ERROR_CONNECTION_BROKEN:
3482 			return (scferror2errno(scf_error()));
3483 
3484 		case SCF_ERROR_NOT_SET:
3485 		case SCF_ERROR_INVALID_ARGUMENT:
3486 		case SCF_ERROR_HANDLE_MISMATCH:
3487 		case SCF_ERROR_NOT_BOUND:
3488 		default:
3489 			bad_error(running ? "scf_snaplevel_get_pg" :
3490 			    "entity_get_pg", scf_error());
3491 		}
3492 	}
3493 
3494 	/*
3495 	 * Clear the seen fields of the dependents, so we can tell which ones
3496 	 * are new.
3497 	 */
3498 	if (uu_list_walk(ient->sc_dependents, clear_int,
3499 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3500 		bad_error("uu_list_walk", uu_error());
3501 
3502 	if (li_dpts_pg != NULL) {
3503 		/*
3504 		 * Each property in li_dpts_pg represents a dependent tag in
3505 		 * the old manifest.  For each, call upgrade_dependent(),
3506 		 * which will change ud_cur_depts_pg or dependencies in other
3507 		 * services as appropriate.  Note (a) that changes to
3508 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3509 		 * made en masse, and (b) it's ok if the entity doesn't have
3510 		 * a current version of the "dependents" property group,
3511 		 * because we'll just consider all dependents as customized
3512 		 * (by being deleted).
3513 		 */
3514 
3515 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3516 			switch (scf_error()) {
3517 			case SCF_ERROR_DELETED:
3518 				return (ENODEV);
3519 
3520 			case SCF_ERROR_CONNECTION_BROKEN:
3521 				return (ECONNABORTED);
3522 
3523 			case SCF_ERROR_HANDLE_MISMATCH:
3524 			case SCF_ERROR_NOT_BOUND:
3525 			case SCF_ERROR_NOT_SET:
3526 			default:
3527 				bad_error("scf_iter_pg_properties",
3528 				    scf_error());
3529 			}
3530 		}
3531 
3532 		if (have_cur_depts &&
3533 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3534 			switch (scf_error()) {
3535 			case SCF_ERROR_BACKEND_ACCESS:
3536 			case SCF_ERROR_BACKEND_READONLY:
3537 			case SCF_ERROR_CONNECTION_BROKEN:
3538 				return (scferror2errno(scf_error()));
3539 
3540 			case SCF_ERROR_DELETED:
3541 				warn(emsg_pg_deleted, ient->sc_fmri,
3542 				    dependents);
3543 				return (EBUSY);
3544 
3545 			case SCF_ERROR_PERMISSION_DENIED:
3546 				warn(emsg_pg_mod_perm, dependents,
3547 				    ient->sc_fmri);
3548 				return (scferror2errno(scf_error()));
3549 
3550 			case SCF_ERROR_HANDLE_MISMATCH:
3551 			case SCF_ERROR_IN_USE:
3552 			case SCF_ERROR_NOT_BOUND:
3553 			case SCF_ERROR_NOT_SET:
3554 			default:
3555 				bad_error("scf_transaction_start", scf_error());
3556 			}
3557 		}
3558 		tx_started = have_cur_depts;
3559 
3560 		for (;;) {
3561 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3562 			if (r == 0)
3563 				break;
3564 			if (r == 1) {
3565 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3566 				    tx_started ? ud_tx : NULL);
3567 				switch (r) {
3568 				case 0:
3569 					continue;
3570 
3571 				case ECONNABORTED:
3572 				case ENOMEM:
3573 				case ENOSPC:
3574 				case EBADF:
3575 				case EBUSY:
3576 				case EINVAL:
3577 				case EPERM:
3578 				case EROFS:
3579 				case EACCES:
3580 				case EEXIST:
3581 					break;
3582 
3583 				case ECANCELED:
3584 					r = ENODEV;
3585 					break;
3586 
3587 				default:
3588 					bad_error("upgrade_dependent", r);
3589 				}
3590 
3591 				if (tx_started)
3592 					scf_transaction_destroy_children(ud_tx);
3593 				return (r);
3594 			}
3595 			if (r != -1)
3596 				bad_error("scf_iter_next_property", r);
3597 
3598 			switch (scf_error()) {
3599 			case SCF_ERROR_DELETED:
3600 				r = ENODEV;
3601 				break;
3602 
3603 			case SCF_ERROR_CONNECTION_BROKEN:
3604 				r = ECONNABORTED;
3605 				break;
3606 
3607 			case SCF_ERROR_NOT_SET:
3608 			case SCF_ERROR_INVALID_ARGUMENT:
3609 			case SCF_ERROR_NOT_BOUND:
3610 			case SCF_ERROR_HANDLE_MISMATCH:
3611 			default:
3612 				bad_error("scf_iter_next_property",
3613 				    scf_error());
3614 			}
3615 
3616 			if (tx_started)
3617 				scf_transaction_destroy_children(ud_tx);
3618 			return (r);
3619 		}
3620 	}
3621 
3622 	/* import unseen dependents */
3623 	unseen = 0;
3624 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3625 	    new_dpt_pgroup != NULL;
3626 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3627 	    new_dpt_pgroup)) {
3628 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3629 			unseen = 1;
3630 			break;
3631 		}
3632 	}
3633 
3634 	/* If there are none, exit early. */
3635 	if (unseen == 0)
3636 		goto commit;
3637 
3638 	/* Set up for lscf_dependent_import() */
3639 	cbdata.sc_handle = g_hndl;
3640 	cbdata.sc_parent = ent;
3641 	cbdata.sc_service = issvc;
3642 	cbdata.sc_flags = 0;
3643 
3644 	if (!have_cur_depts) {
3645 		/*
3646 		 * We have new dependents to import, so we need a "dependents"
3647 		 * property group.
3648 		 */
3649 		if (issvc)
3650 			r = scf_service_add_pg(ent, dependents,
3651 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3652 		else
3653 			r = scf_instance_add_pg(ent, dependents,
3654 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3655 		if (r != 0) {
3656 			switch (scf_error()) {
3657 			case SCF_ERROR_DELETED:
3658 			case SCF_ERROR_CONNECTION_BROKEN:
3659 			case SCF_ERROR_BACKEND_READONLY:
3660 			case SCF_ERROR_BACKEND_ACCESS:
3661 			case SCF_ERROR_NO_RESOURCES:
3662 				return (scferror2errno(scf_error()));
3663 
3664 			case SCF_ERROR_EXISTS:
3665 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3666 				return (EBUSY);
3667 
3668 			case SCF_ERROR_PERMISSION_DENIED:
3669 				warn(emsg_pg_add_perm, dependents,
3670 				    ient->sc_fmri);
3671 				return (scferror2errno(scf_error()));
3672 
3673 			case SCF_ERROR_NOT_BOUND:
3674 			case SCF_ERROR_HANDLE_MISMATCH:
3675 			case SCF_ERROR_INVALID_ARGUMENT:
3676 			case SCF_ERROR_NOT_SET:
3677 			default:
3678 				bad_error("scf_service_add_pg", scf_error());
3679 			}
3680 		}
3681 	}
3682 
3683 	cbdata.sc_trans = ud_tx;
3684 
3685 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3686 		switch (scf_error()) {
3687 		case SCF_ERROR_CONNECTION_BROKEN:
3688 		case SCF_ERROR_BACKEND_ACCESS:
3689 		case SCF_ERROR_BACKEND_READONLY:
3690 			return (scferror2errno(scf_error()));
3691 
3692 		case SCF_ERROR_DELETED:
3693 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3694 			return (EBUSY);
3695 
3696 		case SCF_ERROR_PERMISSION_DENIED:
3697 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3698 			return (scferror2errno(scf_error()));
3699 
3700 		case SCF_ERROR_HANDLE_MISMATCH:
3701 		case SCF_ERROR_IN_USE:
3702 		case SCF_ERROR_NOT_BOUND:
3703 		case SCF_ERROR_NOT_SET:
3704 		default:
3705 			bad_error("scf_transaction_start", scf_error());
3706 		}
3707 	}
3708 	tx_started = 1;
3709 
3710 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3711 	    new_dpt_pgroup != NULL;
3712 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3713 	    new_dpt_pgroup)) {
3714 		if (new_dpt_pgroup->sc_pgroup_seen)
3715 			continue;
3716 
3717 		if (ud_run_dpts_pg_set) {
3718 			/*
3719 			 * If the dependent is already there, then we have
3720 			 * a conflict.
3721 			 */
3722 			if (scf_pg_get_property(ud_run_dpts_pg,
3723 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3724 				r = handle_dependent_conflict(ient, ud_prop,
3725 				    new_dpt_pgroup);
3726 				switch (r) {
3727 				case 0:
3728 					continue;
3729 
3730 				case ECONNABORTED:
3731 				case ENOMEM:
3732 				case EBUSY:
3733 				case EBADF:
3734 				case EINVAL:
3735 					scf_transaction_destroy_children(ud_tx);
3736 					return (r);
3737 
3738 				default:
3739 					bad_error("handle_dependent_conflict",
3740 					    r);
3741 				}
3742 			} else {
3743 				switch (scf_error()) {
3744 				case SCF_ERROR_NOT_FOUND:
3745 					break;
3746 
3747 				case SCF_ERROR_INVALID_ARGUMENT:
3748 					warn(emsg_fmri_invalid_pg_name,
3749 					    ient->sc_fmri,
3750 					    new_dpt_pgroup->sc_pgroup_name);
3751 					scf_transaction_destroy_children(ud_tx);
3752 					return (EINVAL);
3753 
3754 				case SCF_ERROR_DELETED:
3755 					warn(emsg_pg_deleted, ient->sc_fmri,
3756 					    new_dpt_pgroup->sc_pgroup_name);
3757 					scf_transaction_destroy_children(ud_tx);
3758 					return (EBUSY);
3759 
3760 				case SCF_ERROR_CONNECTION_BROKEN:
3761 					scf_transaction_destroy_children(ud_tx);
3762 					return (ECONNABORTED);
3763 
3764 				case SCF_ERROR_NOT_BOUND:
3765 				case SCF_ERROR_HANDLE_MISMATCH:
3766 				case SCF_ERROR_NOT_SET:
3767 				default:
3768 					bad_error("scf_pg_get_property",
3769 					    scf_error());
3770 				}
3771 			}
3772 		}
3773 
3774 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3775 		if (r != UU_WALK_NEXT) {
3776 			if (r != UU_WALK_ERROR)
3777 				bad_error("lscf_dependent_import", r);
3778 
3779 			if (cbdata.sc_err == EALREADY) {
3780 				/* Collisions were handled preemptively. */
3781 				bad_error("lscf_dependent_import",
3782 				    cbdata.sc_err);
3783 			}
3784 
3785 			scf_transaction_destroy_children(ud_tx);
3786 			return (cbdata.sc_err);
3787 		}
3788 	}
3789 
3790 commit:
3791 	if (!tx_started)
3792 		return (0);
3793 
3794 	r = scf_transaction_commit(ud_tx);
3795 
3796 	scf_transaction_destroy_children(ud_tx);
3797 
3798 	switch (r) {
3799 	case 1:
3800 		return (0);
3801 
3802 	case 0:
3803 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3804 		return (EBUSY);
3805 
3806 	case -1:
3807 		break;
3808 
3809 	default:
3810 		bad_error("scf_transaction_commit", r);
3811 	}
3812 
3813 	switch (scf_error()) {
3814 	case SCF_ERROR_CONNECTION_BROKEN:
3815 	case SCF_ERROR_BACKEND_READONLY:
3816 	case SCF_ERROR_BACKEND_ACCESS:
3817 	case SCF_ERROR_NO_RESOURCES:
3818 		return (scferror2errno(scf_error()));
3819 
3820 	case SCF_ERROR_DELETED:
3821 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3822 		return (EBUSY);
3823 
3824 	case SCF_ERROR_PERMISSION_DENIED:
3825 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3826 		return (scferror2errno(scf_error()));
3827 
3828 	case SCF_ERROR_NOT_BOUND:
3829 	case SCF_ERROR_INVALID_ARGUMENT:
3830 	case SCF_ERROR_NOT_SET:
3831 	default:
3832 		bad_error("scf_transaction_destroy", scf_error());
3833 		/* NOTREACHED */
3834 	}
3835 }
3836 
3837 /*
3838  * Used to add the manifests to the list of currently supported manifests.
3839  * We can modify the existing manifest list removing entries if the files
3840  * don't exist.
3841  *
3842  * Get the old list and the new file name
3843  * If the new file name is in the list return
3844  * If not then add the file to the list.
3845  * As we process the list check to see if the files in the old list exist
3846  * 	if not then remove the file from the list.
3847  * Commit the list of manifest file names.
3848  *
3849  */
3850 static int
3851 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3852     const scf_snaplevel_t *running, void *ent)
3853 {
3854 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3855 	scf_property_t *ud_prop = NULL;
3856 	scf_iter_t *ud_prop_iter;
3857 	scf_value_t *fname_value;
3858 	scf_callback_t cbdata;
3859 	pgroup_t *mfst_pgroup;
3860 	property_t *mfst_prop;
3861 	property_t *old_prop;
3862 	char *pname = malloc(MAXPATHLEN);
3863 	char *fval = NULL;
3864 	char *old_pname;
3865 	char *old_fval;
3866 	int no_upgrade_pg;
3867 	int mfst_seen;
3868 	int r;
3869 
3870 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3871 
3872 	/*
3873 	 * This should always be the service base on the code
3874 	 * path, and the fact that the manifests pg is a service
3875 	 * level property group only.
3876 	 */
3877 	ud_mfsts_pg = scf_pg_create(g_hndl);
3878 	ud_prop = scf_property_create(g_hndl);
3879 	ud_prop_iter = scf_iter_create(g_hndl);
3880 	fname_value = scf_value_create(g_hndl);
3881 
3882 	/* Fetch the "manifests" property group */
3883 	no_upgrade_pg = 0;
3884 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3885 	    ud_mfsts_pg);
3886 	if (r != 0) {
3887 		switch (scf_error()) {
3888 		case SCF_ERROR_NOT_FOUND:
3889 			no_upgrade_pg = 1;
3890 			break;
3891 
3892 		case SCF_ERROR_DELETED:
3893 		case SCF_ERROR_CONNECTION_BROKEN:
3894 			return (scferror2errno(scf_error()));
3895 
3896 		case SCF_ERROR_NOT_SET:
3897 		case SCF_ERROR_INVALID_ARGUMENT:
3898 		case SCF_ERROR_HANDLE_MISMATCH:
3899 		case SCF_ERROR_NOT_BOUND:
3900 		default:
3901 			bad_error(running ? "scf_snaplevel_get_pg" :
3902 			    "entity_get_pg", scf_error());
3903 		}
3904 	}
3905 
3906 	if (no_upgrade_pg) {
3907 		cbdata.sc_handle = g_hndl;
3908 		cbdata.sc_parent = ent;
3909 		cbdata.sc_service = issvc;
3910 		cbdata.sc_flags = SCI_FORCE;
3911 		cbdata.sc_source_fmri = ient->sc_fmri;
3912 		cbdata.sc_target_fmri = ient->sc_fmri;
3913 
3914 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3915 			return (cbdata.sc_err);
3916 
3917 		return (0);
3918 	}
3919 
3920 	/* Fetch the new manifests property group */
3921 	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3922 	    mfst_pgroup != NULL;
3923 	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3924 		if (strcmp(mfst_pgroup->sc_pgroup_name,
3925 		    SCF_PG_MANIFESTFILES) == 0)
3926 			break;
3927 	}
3928 
3929 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3930 	    SCF_SUCCESS)
3931 		return (-1);
3932 
3933 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3934 		mfst_seen = 0;
3935 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3936 			continue;
3937 
3938 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3939 		    mfst_prop != NULL;
3940 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3941 		    mfst_prop)) {
3942 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3943 				mfst_seen = 1;
3944 			}
3945 		}
3946 
3947 		/*
3948 		 * If the manifest is not seen then add it to the new mfst
3949 		 * property list to get proccessed into the repo.
3950 		 */
3951 		if (mfst_seen == 0) {
3952 			if (fval == NULL)
3953 				fval = malloc(MAXPATHLEN);
3954 
3955 			/*
3956 			 * If we cannot get the value then there is no
3957 			 * reason to attempt to attach the value to
3958 			 * the property group
3959 			 */
3960 			if (fval != NULL &&
3961 			    prop_get_val(ud_prop, fname_value) == 0 &&
3962 			    scf_value_get_astring(fname_value, fval,
3963 			    MAXPATHLEN) != -1)  {
3964 				old_pname = safe_strdup(pname);
3965 				old_fval = safe_strdup(fval);
3966 				old_prop = internal_property_create(old_pname,
3967 				    SCF_TYPE_ASTRING, 1, old_fval);
3968 
3969 				/*
3970 				 * Already checked to see if the property exists
3971 				 * in the group, and it does not.
3972 				 */
3973 				(void) internal_attach_property(mfst_pgroup,
3974 				    old_prop);
3975 			}
3976 		}
3977 	}
3978 	free(fval);
3979 
3980 	cbdata.sc_handle = g_hndl;
3981 	cbdata.sc_parent = ent;
3982 	cbdata.sc_service = issvc;
3983 	cbdata.sc_flags = SCI_FORCE;
3984 	cbdata.sc_source_fmri = ient->sc_fmri;
3985 	cbdata.sc_target_fmri = ient->sc_fmri;
3986 
3987 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
3988 		return (cbdata.sc_err);
3989 
3990 	return (r);
3991 }
3992 
3993 /*
3994  * prop is taken to be a property in the "dependents" property group of snpl,
3995  * which is taken to be the snaplevel of a last-import snapshot corresponding
3996  * to ient.  If prop is a valid dependents property, upgrade the dependent it
3997  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
3998  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
3999  * of the entity ient represents (possibly in the running snapshot).  If it
4000  * needs to be changed, an entry will be added to tx, if not NULL.
4001  *
4002  * Returns
4003  *   0 - success
4004  *   ECONNABORTED - repository connection broken
4005  *   ENOMEM - out of memory
4006  *   ENOSPC - configd was out of resources
4007  *   ECANCELED - snpl's entity was deleted
4008  *   EINVAL - dependent target is invalid (error printed)
4009  *	    - dependent is invalid (error printed)
4010  *   EBADF - snpl is corrupt (error printed)
4011  *	   - snpl has corrupt pg (error printed)
4012  *	   - dependency pg in target is corrupt (error printed)
4013  *	   - running snapshot in dependent is missing snaplevel (error printed)
4014  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4015  *	   - couldn't create dependent (permission denied) (error printed)
4016  *	   - couldn't modify dependent pg (permission denied) (error printed)
4017  *   EROFS - couldn't delete dependency pg (repository read-only)
4018  *	   - couldn't create dependent (repository read-only)
4019  *   EACCES - couldn't delete dependency pg (backend access denied)
4020  *	    - couldn't create dependent (backend access denied)
4021  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4022  *	   - tx's pg was deleted (error printed)
4023  *	   - dependent pg was changed or deleted (error printed)
4024  *   EEXIST - dependency pg already exists in new target (error printed)
4025  */
4026 static int
4027 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4028     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4029 {
4030 	pgroup_t pgrp;
4031 	scf_type_t ty;
4032 	pgroup_t *new_dpt_pgroup;
4033 	pgroup_t *old_dpt_pgroup = NULL;
4034 	pgroup_t *current_pg;
4035 	pgroup_t *dpt;
4036 	scf_callback_t cbdata;
4037 	int tissvc;
4038 	void *target_ent;
4039 	scf_error_t serr;
4040 	int r;
4041 	scf_transaction_entry_t *ent;
4042 
4043 	const char * const cf_inval = gettext("Conflict upgrading %s "
4044 	    "(dependent \"%s\" has invalid dependents property).\n");
4045 	const char * const cf_missing = gettext("Conflict upgrading %s "
4046 	    "(dependent \"%s\" is missing).\n");
4047 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4048 	    "(dependent \"%s\" has new dependency property group).\n");
4049 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4050 	    "(dependent \"%s\" has new target).\n");
4051 	const char * const li_corrupt =
4052 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4053 	const char * const upgrading =
4054 	    gettext("%s: Upgrading dependent \"%s\".\n");
4055 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4056 	    "corrupt (missing snaplevel).\n");
4057 
4058 	if (scf_property_type(prop, &ty) != 0) {
4059 		switch (scf_error()) {
4060 		case SCF_ERROR_DELETED:
4061 		case SCF_ERROR_CONNECTION_BROKEN:
4062 			return (scferror2errno(scf_error()));
4063 
4064 		case SCF_ERROR_NOT_BOUND:
4065 		case SCF_ERROR_NOT_SET:
4066 		default:
4067 			bad_error("scf_property_type", scf_error());
4068 		}
4069 	}
4070 
4071 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4072 		warn(li_corrupt, ient->sc_fmri);
4073 		return (EBADF);
4074 	}
4075 
4076 	/*
4077 	 * prop represents a dependent in the old manifest.  It is named after
4078 	 * the dependent.
4079 	 */
4080 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4081 		switch (scf_error()) {
4082 		case SCF_ERROR_DELETED:
4083 		case SCF_ERROR_CONNECTION_BROKEN:
4084 			return (scferror2errno(scf_error()));
4085 
4086 		case SCF_ERROR_NOT_BOUND:
4087 		case SCF_ERROR_NOT_SET:
4088 		default:
4089 			bad_error("scf_property_get_name", scf_error());
4090 		}
4091 	}
4092 
4093 	/* See if it's in the new manifest. */
4094 	pgrp.sc_pgroup_name = ud_name;
4095 	new_dpt_pgroup =
4096 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4097 
4098 	/* If it's not, delete it... if it hasn't been customized. */
4099 	if (new_dpt_pgroup == NULL) {
4100 		if (!ud_run_dpts_pg_set)
4101 			return (0);
4102 
4103 		if (scf_property_get_value(prop, ud_val) != 0) {
4104 			switch (scf_error()) {
4105 			case SCF_ERROR_NOT_FOUND:
4106 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4107 				warn(li_corrupt, ient->sc_fmri);
4108 				return (EBADF);
4109 
4110 			case SCF_ERROR_DELETED:
4111 			case SCF_ERROR_CONNECTION_BROKEN:
4112 				return (scferror2errno(scf_error()));
4113 
4114 			case SCF_ERROR_HANDLE_MISMATCH:
4115 			case SCF_ERROR_NOT_BOUND:
4116 			case SCF_ERROR_NOT_SET:
4117 			case SCF_ERROR_PERMISSION_DENIED:
4118 			default:
4119 				bad_error("scf_property_get_value",
4120 				    scf_error());
4121 			}
4122 		}
4123 
4124 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4125 		    max_scf_value_len + 1) < 0)
4126 			bad_error("scf_value_get_as_string", scf_error());
4127 
4128 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4129 		    0) {
4130 			switch (scf_error()) {
4131 			case SCF_ERROR_NOT_FOUND:
4132 				return (0);
4133 
4134 			case SCF_ERROR_CONNECTION_BROKEN:
4135 				return (scferror2errno(scf_error()));
4136 
4137 			case SCF_ERROR_DELETED:
4138 				warn(emsg_pg_deleted, ient->sc_fmri,
4139 				    "dependents");
4140 				return (EBUSY);
4141 
4142 			case SCF_ERROR_INVALID_ARGUMENT:
4143 			case SCF_ERROR_NOT_BOUND:
4144 			case SCF_ERROR_HANDLE_MISMATCH:
4145 			case SCF_ERROR_NOT_SET:
4146 			default:
4147 				bad_error("scf_pg_get_property", scf_error());
4148 			}
4149 		}
4150 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4151 			switch (scf_error()) {
4152 			case SCF_ERROR_NOT_FOUND:
4153 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4154 				warn(cf_inval, ient->sc_fmri, ud_name);
4155 				return (0);
4156 
4157 			case SCF_ERROR_DELETED:
4158 			case SCF_ERROR_CONNECTION_BROKEN:
4159 				return (scferror2errno(scf_error()));
4160 
4161 			case SCF_ERROR_HANDLE_MISMATCH:
4162 			case SCF_ERROR_NOT_BOUND:
4163 			case SCF_ERROR_NOT_SET:
4164 			case SCF_ERROR_PERMISSION_DENIED:
4165 			default:
4166 				bad_error("scf_property_get_value",
4167 				    scf_error());
4168 			}
4169 		}
4170 
4171 		ty = scf_value_type(ud_val);
4172 		assert(ty != SCF_TYPE_INVALID);
4173 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4174 			warn(cf_inval, ient->sc_fmri, ud_name);
4175 			return (0);
4176 		}
4177 
4178 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4179 		    max_scf_value_len + 1) < 0)
4180 			bad_error("scf_value_get_as_string", scf_error());
4181 
4182 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4183 		switch (r) {
4184 		case 1:
4185 			break;
4186 
4187 		case 0:
4188 		case -1:	/* warn? */
4189 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4190 			return (0);
4191 
4192 		case -2:
4193 			warn(li_corrupt, ient->sc_fmri);
4194 			return (EBADF);
4195 
4196 		default:
4197 			bad_error("fmri_equal", r);
4198 		}
4199 
4200 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4201 			switch (scf_error()) {
4202 			case SCF_ERROR_NOT_FOUND:
4203 				warn(li_corrupt, ient->sc_fmri);
4204 				return (EBADF);
4205 
4206 			case SCF_ERROR_DELETED:
4207 			case SCF_ERROR_CONNECTION_BROKEN:
4208 				return (scferror2errno(scf_error()));
4209 
4210 			case SCF_ERROR_NOT_BOUND:
4211 			case SCF_ERROR_HANDLE_MISMATCH:
4212 			case SCF_ERROR_INVALID_ARGUMENT:
4213 			case SCF_ERROR_NOT_SET:
4214 			default:
4215 				bad_error("scf_snaplevel_get_pg", scf_error());
4216 			}
4217 		}
4218 
4219 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4220 		    snap_lastimport);
4221 		switch (r) {
4222 		case 0:
4223 			break;
4224 
4225 		case ECANCELED:
4226 		case ECONNABORTED:
4227 		case ENOMEM:
4228 		case EBADF:
4229 			return (r);
4230 
4231 		case EACCES:
4232 		default:
4233 			bad_error("load_pg", r);
4234 		}
4235 
4236 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4237 		switch (serr) {
4238 		case SCF_ERROR_NONE:
4239 			break;
4240 
4241 		case SCF_ERROR_NO_MEMORY:
4242 			internal_pgroup_free(old_dpt_pgroup);
4243 			return (ENOMEM);
4244 
4245 		case SCF_ERROR_NOT_FOUND:
4246 			internal_pgroup_free(old_dpt_pgroup);
4247 			goto delprop;
4248 
4249 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4250 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4251 		default:
4252 			bad_error("fmri_to_entity", serr);
4253 		}
4254 
4255 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4256 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4257 		switch (r) {
4258 		case 0:
4259 			break;
4260 
4261 		case ECONNABORTED:
4262 			internal_pgroup_free(old_dpt_pgroup);
4263 			return (r);
4264 
4265 		case ECANCELED:
4266 		case ENOENT:
4267 			internal_pgroup_free(old_dpt_pgroup);
4268 			goto delprop;
4269 
4270 		case EBADF:
4271 			warn(r_no_lvl, ud_ctarg);
4272 			internal_pgroup_free(old_dpt_pgroup);
4273 			return (r);
4274 
4275 		case EINVAL:
4276 		default:
4277 			bad_error("entity_get_running_pg", r);
4278 		}
4279 
4280 		/* load it */
4281 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4282 		switch (r) {
4283 		case 0:
4284 			break;
4285 
4286 		case ECANCELED:
4287 			internal_pgroup_free(old_dpt_pgroup);
4288 			goto delprop;
4289 
4290 		case ECONNABORTED:
4291 		case ENOMEM:
4292 		case EBADF:
4293 			internal_pgroup_free(old_dpt_pgroup);
4294 			return (r);
4295 
4296 		case EACCES:
4297 		default:
4298 			bad_error("load_pg", r);
4299 		}
4300 
4301 		/* compare property groups */
4302 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4303 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4304 			internal_pgroup_free(old_dpt_pgroup);
4305 			internal_pgroup_free(current_pg);
4306 			return (0);
4307 		}
4308 
4309 		internal_pgroup_free(old_dpt_pgroup);
4310 		internal_pgroup_free(current_pg);
4311 
4312 		if (g_verbose)
4313 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4314 			    ient->sc_fmri, ud_name);
4315 
4316 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4317 			switch (scf_error()) {
4318 			case SCF_ERROR_NOT_FOUND:
4319 			case SCF_ERROR_DELETED:
4320 				internal_pgroup_free(old_dpt_pgroup);
4321 				goto delprop;
4322 
4323 			case SCF_ERROR_CONNECTION_BROKEN:
4324 				internal_pgroup_free(old_dpt_pgroup);
4325 				return (ECONNABORTED);
4326 
4327 			case SCF_ERROR_NOT_SET:
4328 			case SCF_ERROR_INVALID_ARGUMENT:
4329 			case SCF_ERROR_HANDLE_MISMATCH:
4330 			case SCF_ERROR_NOT_BOUND:
4331 			default:
4332 				bad_error("entity_get_pg", scf_error());
4333 			}
4334 		}
4335 
4336 		if (scf_pg_delete(ud_pg) != 0) {
4337 			switch (scf_error()) {
4338 			case SCF_ERROR_DELETED:
4339 				break;
4340 
4341 			case SCF_ERROR_CONNECTION_BROKEN:
4342 			case SCF_ERROR_BACKEND_READONLY:
4343 			case SCF_ERROR_BACKEND_ACCESS:
4344 				return (scferror2errno(scf_error()));
4345 
4346 			case SCF_ERROR_PERMISSION_DENIED:
4347 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4348 				return (scferror2errno(scf_error()));
4349 
4350 			case SCF_ERROR_NOT_SET:
4351 			default:
4352 				bad_error("scf_pg_delete", scf_error());
4353 			}
4354 		}
4355 
4356 		/*
4357 		 * This service was changed, so it must be refreshed.  But
4358 		 * since it's not mentioned in the new manifest, we have to
4359 		 * record its FMRI here for use later.  We record the name
4360 		 * & the entity (via sc_parent) in case we need to print error
4361 		 * messages during the refresh.
4362 		 */
4363 		dpt = internal_pgroup_new();
4364 		if (dpt == NULL)
4365 			return (ENOMEM);
4366 		dpt->sc_pgroup_name = strdup(ud_name);
4367 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4368 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4369 			return (ENOMEM);
4370 		dpt->sc_parent = (entity_t *)ient;
4371 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4372 			uu_die(gettext("libuutil error: %s\n"),
4373 			    uu_strerror(uu_error()));
4374 
4375 delprop:
4376 		if (tx == NULL)
4377 			return (0);
4378 
4379 		ent = scf_entry_create(g_hndl);
4380 		if (ent == NULL)
4381 			return (ENOMEM);
4382 
4383 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4384 			scf_entry_destroy(ent);
4385 			switch (scf_error()) {
4386 			case SCF_ERROR_DELETED:
4387 				warn(emsg_pg_deleted, ient->sc_fmri,
4388 				    "dependents");
4389 				return (EBUSY);
4390 
4391 			case SCF_ERROR_CONNECTION_BROKEN:
4392 				return (scferror2errno(scf_error()));
4393 
4394 			case SCF_ERROR_NOT_FOUND:
4395 				break;
4396 
4397 			case SCF_ERROR_HANDLE_MISMATCH:
4398 			case SCF_ERROR_NOT_BOUND:
4399 			case SCF_ERROR_INVALID_ARGUMENT:
4400 			case SCF_ERROR_NOT_SET:
4401 			default:
4402 				bad_error("scf_transaction_property_delete",
4403 				    scf_error());
4404 			}
4405 		}
4406 
4407 		return (0);
4408 	}
4409 
4410 	new_dpt_pgroup->sc_pgroup_seen = 1;
4411 
4412 	/*
4413 	 * Decide whether the dependent has changed in the manifest.
4414 	 */
4415 	/* Compare the target. */
4416 	if (scf_property_get_value(prop, ud_val) != 0) {
4417 		switch (scf_error()) {
4418 		case SCF_ERROR_NOT_FOUND:
4419 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4420 			warn(li_corrupt, ient->sc_fmri);
4421 			return (EBADF);
4422 
4423 		case SCF_ERROR_DELETED:
4424 		case SCF_ERROR_CONNECTION_BROKEN:
4425 			return (scferror2errno(scf_error()));
4426 
4427 		case SCF_ERROR_HANDLE_MISMATCH:
4428 		case SCF_ERROR_NOT_BOUND:
4429 		case SCF_ERROR_NOT_SET:
4430 		case SCF_ERROR_PERMISSION_DENIED:
4431 		default:
4432 			bad_error("scf_property_get_value", scf_error());
4433 		}
4434 	}
4435 
4436 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4437 	    0)
4438 		bad_error("scf_value_get_as_string", scf_error());
4439 
4440 	/*
4441 	 * If the fmri's are not equal then the old fmri will need to
4442 	 * be refreshed to ensure that the changes are properly updated
4443 	 * in that service.
4444 	 */
4445 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4446 	switch (r) {
4447 	case 0:
4448 		dpt = internal_pgroup_new();
4449 		if (dpt == NULL)
4450 			return (ENOMEM);
4451 		dpt->sc_pgroup_name = strdup(ud_name);
4452 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4453 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4454 			return (ENOMEM);
4455 		dpt->sc_parent = (entity_t *)ient;
4456 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4457 			uu_die(gettext("libuutil error: %s\n"),
4458 			    uu_strerror(uu_error()));
4459 		break;
4460 
4461 	case 1:
4462 		/* Compare the dependency pgs. */
4463 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4464 			switch (scf_error()) {
4465 			case SCF_ERROR_NOT_FOUND:
4466 				warn(li_corrupt, ient->sc_fmri);
4467 				return (EBADF);
4468 
4469 			case SCF_ERROR_DELETED:
4470 			case SCF_ERROR_CONNECTION_BROKEN:
4471 				return (scferror2errno(scf_error()));
4472 
4473 			case SCF_ERROR_NOT_BOUND:
4474 			case SCF_ERROR_HANDLE_MISMATCH:
4475 			case SCF_ERROR_INVALID_ARGUMENT:
4476 			case SCF_ERROR_NOT_SET:
4477 			default:
4478 				bad_error("scf_snaplevel_get_pg", scf_error());
4479 			}
4480 		}
4481 
4482 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4483 		    snap_lastimport);
4484 		switch (r) {
4485 		case 0:
4486 			break;
4487 
4488 		case ECANCELED:
4489 		case ECONNABORTED:
4490 		case ENOMEM:
4491 		case EBADF:
4492 			return (r);
4493 
4494 		case EACCES:
4495 		default:
4496 			bad_error("load_pg", r);
4497 		}
4498 
4499 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4500 			/* no change, leave customizations */
4501 			internal_pgroup_free(old_dpt_pgroup);
4502 			return (0);
4503 		}
4504 		break;
4505 
4506 	case -1:
4507 		warn(li_corrupt, ient->sc_fmri);
4508 		return (EBADF);
4509 
4510 	case -2:
4511 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4512 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4513 		return (EINVAL);
4514 
4515 	default:
4516 		bad_error("fmri_equal", r);
4517 	}
4518 
4519 	/*
4520 	 * The dependent has changed in the manifest.  Upgrade the current
4521 	 * properties if they haven't been customized.
4522 	 */
4523 
4524 	/*
4525 	 * If new_dpt_pgroup->sc_override, then act as though the property
4526 	 * group hasn't been customized.
4527 	 */
4528 	if (new_dpt_pgroup->sc_pgroup_override) {
4529 		(void) strcpy(ud_ctarg, ud_oldtarg);
4530 		goto nocust;
4531 	}
4532 
4533 	if (!ud_run_dpts_pg_set) {
4534 		warn(cf_missing, ient->sc_fmri, ud_name);
4535 		r = 0;
4536 		goto out;
4537 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4538 		switch (scf_error()) {
4539 		case SCF_ERROR_NOT_FOUND:
4540 			warn(cf_missing, ient->sc_fmri, ud_name);
4541 			r = 0;
4542 			goto out;
4543 
4544 		case SCF_ERROR_CONNECTION_BROKEN:
4545 			r = scferror2errno(scf_error());
4546 			goto out;
4547 
4548 		case SCF_ERROR_DELETED:
4549 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4550 			r = EBUSY;
4551 			goto out;
4552 
4553 		case SCF_ERROR_INVALID_ARGUMENT:
4554 		case SCF_ERROR_NOT_BOUND:
4555 		case SCF_ERROR_HANDLE_MISMATCH:
4556 		case SCF_ERROR_NOT_SET:
4557 		default:
4558 			bad_error("scf_pg_get_property", scf_error());
4559 		}
4560 	}
4561 
4562 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4563 		switch (scf_error()) {
4564 		case SCF_ERROR_NOT_FOUND:
4565 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4566 			warn(cf_inval, ient->sc_fmri, ud_name);
4567 			r = 0;
4568 			goto out;
4569 
4570 		case SCF_ERROR_DELETED:
4571 		case SCF_ERROR_CONNECTION_BROKEN:
4572 			r = scferror2errno(scf_error());
4573 			goto out;
4574 
4575 		case SCF_ERROR_HANDLE_MISMATCH:
4576 		case SCF_ERROR_NOT_BOUND:
4577 		case SCF_ERROR_NOT_SET:
4578 		case SCF_ERROR_PERMISSION_DENIED:
4579 		default:
4580 			bad_error("scf_property_get_value", scf_error());
4581 		}
4582 	}
4583 
4584 	ty = scf_value_type(ud_val);
4585 	assert(ty != SCF_TYPE_INVALID);
4586 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4587 		warn(cf_inval, ient->sc_fmri, ud_name);
4588 		r = 0;
4589 		goto out;
4590 	}
4591 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4592 	    0)
4593 		bad_error("scf_value_get_as_string", scf_error());
4594 
4595 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4596 	if (r == -1) {
4597 		warn(cf_inval, ient->sc_fmri, ud_name);
4598 		r = 0;
4599 		goto out;
4600 	} else if (r == -2) {
4601 		warn(li_corrupt, ient->sc_fmri);
4602 		r = EBADF;
4603 		goto out;
4604 	} else if (r == 0) {
4605 		/*
4606 		 * Target has been changed.  Only abort now if it's been
4607 		 * changed to something other than what's in the manifest.
4608 		 */
4609 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4610 		if (r == -1) {
4611 			warn(cf_inval, ient->sc_fmri, ud_name);
4612 			r = 0;
4613 			goto out;
4614 		} else if (r == 0) {
4615 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4616 			r = 0;
4617 			goto out;
4618 		} else if (r != 1) {
4619 			/* invalid sc_pgroup_fmri caught above */
4620 			bad_error("fmri_equal", r);
4621 		}
4622 
4623 		/*
4624 		 * Fetch the current dependency pg.  If it's what the manifest
4625 		 * says, then no problem.
4626 		 */
4627 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4628 		switch (serr) {
4629 		case SCF_ERROR_NONE:
4630 			break;
4631 
4632 		case SCF_ERROR_NOT_FOUND:
4633 			warn(cf_missing, ient->sc_fmri, ud_name);
4634 			r = 0;
4635 			goto out;
4636 
4637 		case SCF_ERROR_NO_MEMORY:
4638 			r = ENOMEM;
4639 			goto out;
4640 
4641 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4642 		case SCF_ERROR_INVALID_ARGUMENT:
4643 		default:
4644 			bad_error("fmri_to_entity", serr);
4645 		}
4646 
4647 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4648 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4649 		switch (r) {
4650 		case 0:
4651 			break;
4652 
4653 		case ECONNABORTED:
4654 			goto out;
4655 
4656 		case ECANCELED:
4657 		case ENOENT:
4658 			warn(cf_missing, ient->sc_fmri, ud_name);
4659 			r = 0;
4660 			goto out;
4661 
4662 		case EBADF:
4663 			warn(r_no_lvl, ud_ctarg);
4664 			goto out;
4665 
4666 		case EINVAL:
4667 		default:
4668 			bad_error("entity_get_running_pg", r);
4669 		}
4670 
4671 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4672 		switch (r) {
4673 		case 0:
4674 			break;
4675 
4676 		case ECANCELED:
4677 			warn(cf_missing, ient->sc_fmri, ud_name);
4678 			r = 0;
4679 			goto out;
4680 
4681 		case ECONNABORTED:
4682 		case ENOMEM:
4683 		case EBADF:
4684 			goto out;
4685 
4686 		case EACCES:
4687 		default:
4688 			bad_error("load_pg", r);
4689 		}
4690 
4691 		if (!pg_equal(current_pg, new_dpt_pgroup))
4692 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4693 		internal_pgroup_free(current_pg);
4694 		r = 0;
4695 		goto out;
4696 	} else if (r != 1) {
4697 		bad_error("fmri_equal", r);
4698 	}
4699 
4700 nocust:
4701 	/*
4702 	 * Target has not been customized.  Check the dependency property
4703 	 * group.
4704 	 */
4705 
4706 	if (old_dpt_pgroup == NULL) {
4707 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4708 		    ud_pg) != 0) {
4709 			switch (scf_error()) {
4710 			case SCF_ERROR_NOT_FOUND:
4711 				warn(li_corrupt, ient->sc_fmri);
4712 				return (EBADF);
4713 
4714 			case SCF_ERROR_DELETED:
4715 			case SCF_ERROR_CONNECTION_BROKEN:
4716 				return (scferror2errno(scf_error()));
4717 
4718 			case SCF_ERROR_NOT_BOUND:
4719 			case SCF_ERROR_HANDLE_MISMATCH:
4720 			case SCF_ERROR_INVALID_ARGUMENT:
4721 			case SCF_ERROR_NOT_SET:
4722 			default:
4723 				bad_error("scf_snaplevel_get_pg", scf_error());
4724 			}
4725 		}
4726 
4727 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4728 		    snap_lastimport);
4729 		switch (r) {
4730 		case 0:
4731 			break;
4732 
4733 		case ECANCELED:
4734 		case ECONNABORTED:
4735 		case ENOMEM:
4736 		case EBADF:
4737 			return (r);
4738 
4739 		case EACCES:
4740 		default:
4741 			bad_error("load_pg", r);
4742 		}
4743 	}
4744 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4745 	switch (serr) {
4746 	case SCF_ERROR_NONE:
4747 		break;
4748 
4749 	case SCF_ERROR_NOT_FOUND:
4750 		warn(cf_missing, ient->sc_fmri, ud_name);
4751 		r = 0;
4752 		goto out;
4753 
4754 	case SCF_ERROR_NO_MEMORY:
4755 		r = ENOMEM;
4756 		goto out;
4757 
4758 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4759 	case SCF_ERROR_INVALID_ARGUMENT:
4760 	default:
4761 		bad_error("fmri_to_entity", serr);
4762 	}
4763 
4764 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4765 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4766 	switch (r) {
4767 	case 0:
4768 		break;
4769 
4770 	case ECONNABORTED:
4771 		goto out;
4772 
4773 	case ECANCELED:
4774 	case ENOENT:
4775 		warn(cf_missing, ient->sc_fmri, ud_name);
4776 		r = 0;
4777 		goto out;
4778 
4779 	case EBADF:
4780 		warn(r_no_lvl, ud_ctarg);
4781 		goto out;
4782 
4783 	case EINVAL:
4784 	default:
4785 		bad_error("entity_get_running_pg", r);
4786 	}
4787 
4788 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4789 	switch (r) {
4790 	case 0:
4791 		break;
4792 
4793 	case ECANCELED:
4794 		warn(cf_missing, ient->sc_fmri, ud_name);
4795 		goto out;
4796 
4797 	case ECONNABORTED:
4798 	case ENOMEM:
4799 	case EBADF:
4800 		goto out;
4801 
4802 	case EACCES:
4803 	default:
4804 		bad_error("load_pg", r);
4805 	}
4806 
4807 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4808 		if (!pg_equal(current_pg, new_dpt_pgroup))
4809 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4810 		internal_pgroup_free(current_pg);
4811 		r = 0;
4812 		goto out;
4813 	}
4814 
4815 	/* Uncustomized.  Upgrade. */
4816 
4817 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4818 	switch (r) {
4819 	case 1:
4820 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4821 			/* Already upgraded. */
4822 			internal_pgroup_free(current_pg);
4823 			r = 0;
4824 			goto out;
4825 		}
4826 
4827 		internal_pgroup_free(current_pg);
4828 
4829 		/* upgrade current_pg */
4830 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4831 			switch (scf_error()) {
4832 			case SCF_ERROR_CONNECTION_BROKEN:
4833 				r = scferror2errno(scf_error());
4834 				goto out;
4835 
4836 			case SCF_ERROR_DELETED:
4837 				warn(cf_missing, ient->sc_fmri, ud_name);
4838 				r = 0;
4839 				goto out;
4840 
4841 			case SCF_ERROR_NOT_FOUND:
4842 				break;
4843 
4844 			case SCF_ERROR_INVALID_ARGUMENT:
4845 			case SCF_ERROR_NOT_BOUND:
4846 			case SCF_ERROR_NOT_SET:
4847 			case SCF_ERROR_HANDLE_MISMATCH:
4848 			default:
4849 				bad_error("entity_get_pg", scf_error());
4850 			}
4851 
4852 			if (tissvc)
4853 				r = scf_service_add_pg(target_ent, ud_name,
4854 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4855 			else
4856 				r = scf_instance_add_pg(target_ent, ud_name,
4857 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4858 			if (r != 0) {
4859 				switch (scf_error()) {
4860 				case SCF_ERROR_CONNECTION_BROKEN:
4861 				case SCF_ERROR_NO_RESOURCES:
4862 				case SCF_ERROR_BACKEND_READONLY:
4863 				case SCF_ERROR_BACKEND_ACCESS:
4864 					r = scferror2errno(scf_error());
4865 					goto out;
4866 
4867 				case SCF_ERROR_DELETED:
4868 					warn(cf_missing, ient->sc_fmri,
4869 					    ud_name);
4870 					r = 0;
4871 					goto out;
4872 
4873 				case SCF_ERROR_PERMISSION_DENIED:
4874 					warn(emsg_pg_deleted, ud_ctarg,
4875 					    ud_name);
4876 					r = EPERM;
4877 					goto out;
4878 
4879 				case SCF_ERROR_EXISTS:
4880 					warn(emsg_pg_added, ud_ctarg, ud_name);
4881 					r = EBUSY;
4882 					goto out;
4883 
4884 				case SCF_ERROR_NOT_BOUND:
4885 				case SCF_ERROR_HANDLE_MISMATCH:
4886 				case SCF_ERROR_INVALID_ARGUMENT:
4887 				case SCF_ERROR_NOT_SET:
4888 				default:
4889 					bad_error("entity_add_pg", scf_error());
4890 				}
4891 			}
4892 		}
4893 
4894 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4895 		switch (r) {
4896 		case 0:
4897 			break;
4898 
4899 		case ECANCELED:
4900 			warn(cf_missing, ient->sc_fmri, ud_name);
4901 			goto out;
4902 
4903 		case ECONNABORTED:
4904 		case ENOMEM:
4905 		case EBADF:
4906 			goto out;
4907 
4908 		case EACCES:
4909 		default:
4910 			bad_error("load_pg", r);
4911 		}
4912 
4913 		if (g_verbose)
4914 			warn(upgrading, ient->sc_fmri, ud_name);
4915 
4916 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4917 		    new_dpt_pgroup, 0, ient->sc_fmri);
4918 		switch (r) {
4919 		case 0:
4920 			break;
4921 
4922 		case ECANCELED:
4923 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4924 			r = EBUSY;
4925 			goto out;
4926 
4927 		case EPERM:
4928 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4929 			goto out;
4930 
4931 		case EBUSY:
4932 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4933 			goto out;
4934 
4935 		case ECONNABORTED:
4936 		case ENOMEM:
4937 		case ENOSPC:
4938 		case EROFS:
4939 		case EACCES:
4940 		case EINVAL:
4941 			goto out;
4942 
4943 		default:
4944 			bad_error("upgrade_pg", r);
4945 		}
4946 		break;
4947 
4948 	case 0: {
4949 		scf_transaction_entry_t *ent;
4950 		scf_value_t *val;
4951 
4952 		internal_pgroup_free(current_pg);
4953 
4954 		/* delete old pg */
4955 		if (g_verbose)
4956 			warn(upgrading, ient->sc_fmri, ud_name);
4957 
4958 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4959 			switch (scf_error()) {
4960 			case SCF_ERROR_CONNECTION_BROKEN:
4961 				r = scferror2errno(scf_error());
4962 				goto out;
4963 
4964 			case SCF_ERROR_DELETED:
4965 				warn(cf_missing, ient->sc_fmri, ud_name);
4966 				r = 0;
4967 				goto out;
4968 
4969 			case SCF_ERROR_NOT_FOUND:
4970 				break;
4971 
4972 			case SCF_ERROR_INVALID_ARGUMENT:
4973 			case SCF_ERROR_NOT_BOUND:
4974 			case SCF_ERROR_NOT_SET:
4975 			case SCF_ERROR_HANDLE_MISMATCH:
4976 			default:
4977 				bad_error("entity_get_pg", scf_error());
4978 			}
4979 		} else if (scf_pg_delete(ud_pg) != 0) {
4980 			switch (scf_error()) {
4981 			case SCF_ERROR_DELETED:
4982 				break;
4983 
4984 			case SCF_ERROR_CONNECTION_BROKEN:
4985 			case SCF_ERROR_BACKEND_READONLY:
4986 			case SCF_ERROR_BACKEND_ACCESS:
4987 				r = scferror2errno(scf_error());
4988 				goto out;
4989 
4990 			case SCF_ERROR_PERMISSION_DENIED:
4991 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4992 				r = scferror2errno(scf_error());
4993 				goto out;
4994 
4995 			case SCF_ERROR_NOT_SET:
4996 			default:
4997 				bad_error("scf_pg_delete", scf_error());
4998 			}
4999 		}
5000 
5001 		/* import new one */
5002 		cbdata.sc_handle = g_hndl;
5003 		cbdata.sc_trans = NULL;		/* handled below */
5004 		cbdata.sc_flags = 0;
5005 
5006 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5007 		if (r != UU_WALK_NEXT) {
5008 			if (r != UU_WALK_ERROR)
5009 				bad_error("lscf_dependent_import", r);
5010 
5011 			r = cbdata.sc_err;
5012 			goto out;
5013 		}
5014 
5015 		if (tx == NULL)
5016 			break;
5017 
5018 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5019 		    (val = scf_value_create(g_hndl)) == NULL) {
5020 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5021 				return (ENOMEM);
5022 
5023 			bad_error("scf_entry_create", scf_error());
5024 		}
5025 
5026 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5027 		    SCF_TYPE_FMRI) != 0) {
5028 			switch (scf_error()) {
5029 			case SCF_ERROR_CONNECTION_BROKEN:
5030 				r = scferror2errno(scf_error());
5031 				goto out;
5032 
5033 			case SCF_ERROR_DELETED:
5034 				warn(emsg_pg_deleted, ient->sc_fmri,
5035 				    "dependents");
5036 				r = EBUSY;
5037 				goto out;
5038 
5039 			case SCF_ERROR_NOT_FOUND:
5040 				break;
5041 
5042 			case SCF_ERROR_NOT_BOUND:
5043 			case SCF_ERROR_HANDLE_MISMATCH:
5044 			case SCF_ERROR_INVALID_ARGUMENT:
5045 			case SCF_ERROR_NOT_SET:
5046 			default:
5047 				bad_error("scf_transaction_property_"
5048 				    "change_type", scf_error());
5049 			}
5050 
5051 			if (scf_transaction_property_new(tx, ent, ud_name,
5052 			    SCF_TYPE_FMRI) != 0) {
5053 				switch (scf_error()) {
5054 				case SCF_ERROR_CONNECTION_BROKEN:
5055 					r = scferror2errno(scf_error());
5056 					goto out;
5057 
5058 				case SCF_ERROR_DELETED:
5059 					warn(emsg_pg_deleted, ient->sc_fmri,
5060 					    "dependents");
5061 					r = EBUSY;
5062 					goto out;
5063 
5064 				case SCF_ERROR_EXISTS:
5065 					warn(emsg_pg_changed, ient->sc_fmri,
5066 					    "dependents");
5067 					r = EBUSY;
5068 					goto out;
5069 
5070 				case SCF_ERROR_INVALID_ARGUMENT:
5071 				case SCF_ERROR_HANDLE_MISMATCH:
5072 				case SCF_ERROR_NOT_BOUND:
5073 				case SCF_ERROR_NOT_SET:
5074 				default:
5075 					bad_error("scf_transaction_property_"
5076 					    "new", scf_error());
5077 				}
5078 			}
5079 		}
5080 
5081 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5082 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5083 			/* invalid sc_pgroup_fmri caught above */
5084 			bad_error("scf_value_set_from_string",
5085 			    scf_error());
5086 
5087 		if (scf_entry_add_value(ent, val) != 0)
5088 			bad_error("scf_entry_add_value", scf_error());
5089 		break;
5090 	}
5091 
5092 	case -2:
5093 		warn(li_corrupt, ient->sc_fmri);
5094 		internal_pgroup_free(current_pg);
5095 		r = EBADF;
5096 		goto out;
5097 
5098 	case -1:
5099 	default:
5100 		/* invalid sc_pgroup_fmri caught above */
5101 		bad_error("fmri_equal", r);
5102 	}
5103 
5104 	r = 0;
5105 
5106 out:
5107 	if (old_dpt_pgroup != NULL)
5108 		internal_pgroup_free(old_dpt_pgroup);
5109 
5110 	return (r);
5111 }
5112 
5113 /*
5114  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5115  * would import it, except it seems to exist in the service anyway.  Compare
5116  * the existent dependent with the one we would import, and report any
5117  * differences (if there are none, be silent).  prop is the property which
5118  * represents the existent dependent (in the dependents property group) in the
5119  * entity corresponding to ient.
5120  *
5121  * Returns
5122  *   0 - success (Sort of.  At least, we can continue importing.)
5123  *   ECONNABORTED - repository connection broken
5124  *   EBUSY - ancestor of prop was deleted (error printed)
5125  *   ENOMEM - out of memory
5126  *   EBADF - corrupt property group (error printed)
5127  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5128  */
5129 static int
5130 handle_dependent_conflict(const entity_t * const ient,
5131     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5132 {
5133 	int r;
5134 	scf_type_t ty;
5135 	scf_error_t scfe;
5136 	void *tptr;
5137 	int tissvc;
5138 	pgroup_t *pgroup;
5139 
5140 	if (scf_property_get_value(prop, ud_val) != 0) {
5141 		switch (scf_error()) {
5142 		case SCF_ERROR_CONNECTION_BROKEN:
5143 			return (scferror2errno(scf_error()));
5144 
5145 		case SCF_ERROR_DELETED:
5146 			warn(emsg_pg_deleted, ient->sc_fmri,
5147 			    new_dpt_pgroup->sc_pgroup_name);
5148 			return (EBUSY);
5149 
5150 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5151 		case SCF_ERROR_NOT_FOUND:
5152 			warn(gettext("Conflict upgrading %s (not importing "
5153 			    "dependent \"%s\" because it already exists.)  "
5154 			    "Warning: The \"%s/%2$s\" property has more or "
5155 			    "fewer than one value)).\n"), ient->sc_fmri,
5156 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5157 			return (0);
5158 
5159 		case SCF_ERROR_HANDLE_MISMATCH:
5160 		case SCF_ERROR_NOT_BOUND:
5161 		case SCF_ERROR_NOT_SET:
5162 		case SCF_ERROR_PERMISSION_DENIED:
5163 		default:
5164 			bad_error("scf_property_get_value",
5165 			    scf_error());
5166 		}
5167 	}
5168 
5169 	ty = scf_value_type(ud_val);
5170 	assert(ty != SCF_TYPE_INVALID);
5171 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5172 		warn(gettext("Conflict upgrading %s (not importing dependent "
5173 		    "\"%s\" because it already exists).  Warning: The "
5174 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5175 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5176 		    scf_type_to_string(ty), "dependents");
5177 		return (0);
5178 	}
5179 
5180 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5181 	    0)
5182 		bad_error("scf_value_get_as_string", scf_error());
5183 
5184 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5185 	switch (r) {
5186 	case 0:
5187 		warn(gettext("Conflict upgrading %s (not importing dependent "
5188 		    "\"%s\" (target \"%s\") because it already exists with "
5189 		    "target \"%s\").\n"), ient->sc_fmri,
5190 		    new_dpt_pgroup->sc_pgroup_name,
5191 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5192 		return (0);
5193 
5194 	case 1:
5195 		break;
5196 
5197 	case -1:
5198 		warn(gettext("Conflict upgrading %s (not importing dependent "
5199 		    "\"%s\" because it already exists).  Warning: The current "
5200 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5201 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5202 		return (0);
5203 
5204 	case -2:
5205 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5206 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5207 		    new_dpt_pgroup->sc_pgroup_fmri);
5208 		return (EINVAL);
5209 
5210 	default:
5211 		bad_error("fmri_equal", r);
5212 	}
5213 
5214 	/* compare dependency pgs in target */
5215 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5216 	switch (scfe) {
5217 	case SCF_ERROR_NONE:
5218 		break;
5219 
5220 	case SCF_ERROR_NO_MEMORY:
5221 		return (ENOMEM);
5222 
5223 	case SCF_ERROR_NOT_FOUND:
5224 		warn(emsg_dpt_dangling, ient->sc_fmri,
5225 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5226 		return (0);
5227 
5228 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5229 	case SCF_ERROR_INVALID_ARGUMENT:
5230 	default:
5231 		bad_error("fmri_to_entity", scfe);
5232 	}
5233 
5234 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5235 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5236 	switch (r) {
5237 	case 0:
5238 		break;
5239 
5240 	case ECONNABORTED:
5241 		return (r);
5242 
5243 	case ECANCELED:
5244 		warn(emsg_dpt_dangling, ient->sc_fmri,
5245 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5246 		return (0);
5247 
5248 	case EBADF:
5249 		if (tissvc)
5250 			warn(gettext("%s has an instance with a \"%s\" "
5251 			    "snapshot which is missing a snaplevel.\n"),
5252 			    ud_ctarg, "running");
5253 		else
5254 			warn(gettext("%s has a \"%s\" snapshot which is "
5255 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5256 		/* FALLTHROUGH */
5257 
5258 	case ENOENT:
5259 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5260 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5261 		    new_dpt_pgroup->sc_pgroup_name);
5262 		return (0);
5263 
5264 	case EINVAL:
5265 	default:
5266 		bad_error("entity_get_running_pg", r);
5267 	}
5268 
5269 	pgroup = internal_pgroup_new();
5270 	if (pgroup == NULL)
5271 		return (ENOMEM);
5272 
5273 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5274 	switch (r) {
5275 	case 0:
5276 		break;
5277 
5278 	case ECONNABORTED:
5279 	case EBADF:
5280 	case ENOMEM:
5281 		internal_pgroup_free(pgroup);
5282 		return (r);
5283 
5284 	case ECANCELED:
5285 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5286 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5287 		    new_dpt_pgroup->sc_pgroup_name);
5288 		internal_pgroup_free(pgroup);
5289 		return (0);
5290 
5291 	case EACCES:
5292 	default:
5293 		bad_error("load_pg", r);
5294 	}
5295 
5296 	/* report differences */
5297 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5298 	internal_pgroup_free(pgroup);
5299 	return (0);
5300 }
5301 
5302 /*
5303  * lipg is a property group in the last-import snapshot of ent, which is an
5304  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5305  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5306  * in ents's property groups, compare and upgrade ent appropriately.
5307  *
5308  * Returns
5309  *   0 - success
5310  *   ECONNABORTED - repository connection broken
5311  *   ENOMEM - out of memory
5312  *   ENOSPC - configd is out of resources
5313  *   EINVAL - ient has invalid dependent (error printed)
5314  *	    - ient has invalid pgroup_t (error printed)
5315  *   ECANCELED - ent has been deleted
5316  *   ENODEV - entity containing lipg has been deleted
5317  *	    - entity containing running has been deleted
5318  *   EPERM - could not delete pg (permission denied) (error printed)
5319  *	   - couldn't upgrade dependents (permission denied) (error printed)
5320  *	   - couldn't import pg (permission denied) (error printed)
5321  *	   - couldn't upgrade pg (permission denied) (error printed)
5322  *   EROFS - could not delete pg (repository read-only)
5323  *	   - couldn't upgrade dependents (repository read-only)
5324  *	   - couldn't import pg (repository read-only)
5325  *	   - couldn't upgrade pg (repository read-only)
5326  *   EACCES - could not delete pg (backend access denied)
5327  *	    - couldn't upgrade dependents (backend access denied)
5328  *	    - couldn't import pg (backend access denied)
5329  *	    - couldn't upgrade pg (backend access denied)
5330  *	    - couldn't read property (backend access denied)
5331  *   EBUSY - property group was added (error printed)
5332  *	   - property group was deleted (error printed)
5333  *	   - property group changed (error printed)
5334  *	   - "dependents" pg was added, changed, or deleted (error printed)
5335  *	   - dependent target deleted (error printed)
5336  *	   - dependent pg changed (error printed)
5337  *   EBADF - imp_snpl is corrupt (error printed)
5338  *	   - ent has bad pg (error printed)
5339  *   EEXIST - dependent collision in target service (error printed)
5340  */
5341 static int
5342 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5343     const scf_snaplevel_t *running)
5344 {
5345 	int r;
5346 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5347 	scf_callback_t cbdata;
5348 
5349 	const char * const cf_pg_missing =
5350 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5351 	const char * const deleting =
5352 	    gettext("%s: Deleting property group \"%s\".\n");
5353 
5354 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5355 
5356 	/* Skip dependent property groups. */
5357 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5358 		switch (scf_error()) {
5359 		case SCF_ERROR_DELETED:
5360 			return (ENODEV);
5361 
5362 		case SCF_ERROR_CONNECTION_BROKEN:
5363 			return (ECONNABORTED);
5364 
5365 		case SCF_ERROR_NOT_SET:
5366 		case SCF_ERROR_NOT_BOUND:
5367 		default:
5368 			bad_error("scf_pg_get_type", scf_error());
5369 		}
5370 	}
5371 
5372 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5373 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5374 			return (0);
5375 
5376 		switch (scf_error()) {
5377 		case SCF_ERROR_NOT_FOUND:
5378 			break;
5379 
5380 		case SCF_ERROR_CONNECTION_BROKEN:
5381 			return (ECONNABORTED);
5382 
5383 		case SCF_ERROR_DELETED:
5384 			return (ENODEV);
5385 
5386 		case SCF_ERROR_INVALID_ARGUMENT:
5387 		case SCF_ERROR_NOT_BOUND:
5388 		case SCF_ERROR_HANDLE_MISMATCH:
5389 		case SCF_ERROR_NOT_SET:
5390 		default:
5391 			bad_error("scf_pg_get_property", scf_error());
5392 		}
5393 	}
5394 
5395 	/* lookup pg in new properties */
5396 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5397 		switch (scf_error()) {
5398 		case SCF_ERROR_DELETED:
5399 			return (ENODEV);
5400 
5401 		case SCF_ERROR_CONNECTION_BROKEN:
5402 			return (ECONNABORTED);
5403 
5404 		case SCF_ERROR_NOT_SET:
5405 		case SCF_ERROR_NOT_BOUND:
5406 		default:
5407 			bad_error("scf_pg_get_name", scf_error());
5408 		}
5409 	}
5410 
5411 	pgrp.sc_pgroup_name = imp_str;
5412 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5413 
5414 	if (mpg != NULL)
5415 		mpg->sc_pgroup_seen = 1;
5416 
5417 	/* Special handling for dependents */
5418 	if (strcmp(imp_str, "dependents") == 0)
5419 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5420 
5421 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5422 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5423 
5424 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5425 		/* property group was deleted from manifest */
5426 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5427 			switch (scf_error()) {
5428 			case SCF_ERROR_NOT_FOUND:
5429 				return (0);
5430 
5431 			case SCF_ERROR_DELETED:
5432 			case SCF_ERROR_CONNECTION_BROKEN:
5433 				return (scferror2errno(scf_error()));
5434 
5435 			case SCF_ERROR_INVALID_ARGUMENT:
5436 			case SCF_ERROR_HANDLE_MISMATCH:
5437 			case SCF_ERROR_NOT_BOUND:
5438 			case SCF_ERROR_NOT_SET:
5439 			default:
5440 				bad_error("entity_get_pg", scf_error());
5441 			}
5442 		}
5443 
5444 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5445 			if (g_verbose)
5446 				warn(deleting, ient->sc_fmri, imp_str);
5447 			if (scf_pg_delete(imp_pg2) == 0)
5448 				return (0);
5449 
5450 			switch (scf_error()) {
5451 			case SCF_ERROR_DELETED:
5452 				return (0);
5453 
5454 			case SCF_ERROR_CONNECTION_BROKEN:
5455 			case SCF_ERROR_BACKEND_READONLY:
5456 			case SCF_ERROR_BACKEND_ACCESS:
5457 				return (scferror2errno(scf_error()));
5458 
5459 			case SCF_ERROR_PERMISSION_DENIED:
5460 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5461 				return (scferror2errno(scf_error()));
5462 
5463 			case SCF_ERROR_NOT_SET:
5464 			default:
5465 				bad_error("scf_pg_delete", scf_error());
5466 			}
5467 		}
5468 
5469 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5470 		switch (r) {
5471 		case 0:
5472 			break;
5473 
5474 		case ECANCELED:
5475 			return (ENODEV);
5476 
5477 		case ECONNABORTED:
5478 		case ENOMEM:
5479 		case EBADF:
5480 		case EACCES:
5481 			return (r);
5482 
5483 		default:
5484 			bad_error("load_pg", r);
5485 		}
5486 
5487 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5488 		switch (r) {
5489 		case 0:
5490 			break;
5491 
5492 		case ECANCELED:
5493 		case ECONNABORTED:
5494 		case ENOMEM:
5495 		case EBADF:
5496 		case EACCES:
5497 			internal_pgroup_free(lipg_i);
5498 			return (r);
5499 
5500 		default:
5501 			bad_error("load_pg", r);
5502 		}
5503 
5504 		if (pg_equal(lipg_i, curpg_i)) {
5505 			if (g_verbose)
5506 				warn(deleting, ient->sc_fmri, imp_str);
5507 			if (scf_pg_delete(imp_pg2) != 0) {
5508 				switch (scf_error()) {
5509 				case SCF_ERROR_DELETED:
5510 					break;
5511 
5512 				case SCF_ERROR_CONNECTION_BROKEN:
5513 					internal_pgroup_free(lipg_i);
5514 					internal_pgroup_free(curpg_i);
5515 					return (ECONNABORTED);
5516 
5517 				case SCF_ERROR_NOT_SET:
5518 				case SCF_ERROR_NOT_BOUND:
5519 				default:
5520 					bad_error("scf_pg_delete", scf_error());
5521 				}
5522 			}
5523 		} else {
5524 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5525 		}
5526 
5527 		internal_pgroup_free(lipg_i);
5528 		internal_pgroup_free(curpg_i);
5529 
5530 		return (0);
5531 	}
5532 
5533 	/*
5534 	 * Only dependent pgs can have override set, and we skipped those
5535 	 * above.
5536 	 */
5537 	assert(!mpg->sc_pgroup_override);
5538 
5539 	/* compare */
5540 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5541 	switch (r) {
5542 	case 0:
5543 		break;
5544 
5545 	case ECANCELED:
5546 		return (ENODEV);
5547 
5548 	case ECONNABORTED:
5549 	case EBADF:
5550 	case ENOMEM:
5551 	case EACCES:
5552 		return (r);
5553 
5554 	default:
5555 		bad_error("load_pg", r);
5556 	}
5557 
5558 	if (pg_equal(mpg, lipg_i)) {
5559 		/* The manifest pg has not changed.  Move on. */
5560 		r = 0;
5561 		goto out;
5562 	}
5563 
5564 	/* upgrade current properties according to lipg & mpg */
5565 	if (running != NULL)
5566 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5567 	else
5568 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5569 	if (r != 0) {
5570 		switch (scf_error()) {
5571 		case SCF_ERROR_CONNECTION_BROKEN:
5572 			r = scferror2errno(scf_error());
5573 			goto out;
5574 
5575 		case SCF_ERROR_DELETED:
5576 			if (running != NULL)
5577 				r = ENODEV;
5578 			else
5579 				r = ECANCELED;
5580 			goto out;
5581 
5582 		case SCF_ERROR_NOT_FOUND:
5583 			break;
5584 
5585 		case SCF_ERROR_INVALID_ARGUMENT:
5586 		case SCF_ERROR_HANDLE_MISMATCH:
5587 		case SCF_ERROR_NOT_BOUND:
5588 		case SCF_ERROR_NOT_SET:
5589 		default:
5590 			bad_error("entity_get_pg", scf_error());
5591 		}
5592 
5593 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5594 
5595 		r = 0;
5596 		goto out;
5597 	}
5598 
5599 	r = load_pg_attrs(imp_pg2, &curpg_i);
5600 	switch (r) {
5601 	case 0:
5602 		break;
5603 
5604 	case ECANCELED:
5605 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5606 		r = 0;
5607 		goto out;
5608 
5609 	case ECONNABORTED:
5610 	case ENOMEM:
5611 		goto out;
5612 
5613 	default:
5614 		bad_error("load_pg_attrs", r);
5615 	}
5616 
5617 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5618 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5619 		internal_pgroup_free(curpg_i);
5620 		r = 0;
5621 		goto out;
5622 	}
5623 
5624 	internal_pgroup_free(curpg_i);
5625 
5626 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5627 	switch (r) {
5628 	case 0:
5629 		break;
5630 
5631 	case ECANCELED:
5632 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5633 		r = 0;
5634 		goto out;
5635 
5636 	case ECONNABORTED:
5637 	case EBADF:
5638 	case ENOMEM:
5639 	case EACCES:
5640 		goto out;
5641 
5642 	default:
5643 		bad_error("load_pg", r);
5644 	}
5645 
5646 	if (pg_equal(lipg_i, curpg_i) &&
5647 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5648 		int do_delete = 1;
5649 
5650 		if (g_verbose)
5651 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5652 			    ient->sc_fmri, mpg->sc_pgroup_name);
5653 
5654 		internal_pgroup_free(curpg_i);
5655 
5656 		if (running != NULL &&
5657 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5658 			switch (scf_error()) {
5659 			case SCF_ERROR_DELETED:
5660 				r = ECANCELED;
5661 				goto out;
5662 
5663 			case SCF_ERROR_NOT_FOUND:
5664 				do_delete = 0;
5665 				break;
5666 
5667 			case SCF_ERROR_CONNECTION_BROKEN:
5668 				r = scferror2errno(scf_error());
5669 				goto out;
5670 
5671 			case SCF_ERROR_HANDLE_MISMATCH:
5672 			case SCF_ERROR_INVALID_ARGUMENT:
5673 			case SCF_ERROR_NOT_SET:
5674 			case SCF_ERROR_NOT_BOUND:
5675 			default:
5676 				bad_error("entity_get_pg", scf_error());
5677 			}
5678 		}
5679 
5680 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5681 			switch (scf_error()) {
5682 			case SCF_ERROR_DELETED:
5683 				break;
5684 
5685 			case SCF_ERROR_CONNECTION_BROKEN:
5686 			case SCF_ERROR_BACKEND_READONLY:
5687 			case SCF_ERROR_BACKEND_ACCESS:
5688 				r = scferror2errno(scf_error());
5689 				goto out;
5690 
5691 			case SCF_ERROR_PERMISSION_DENIED:
5692 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5693 				    ient->sc_fmri);
5694 				r = scferror2errno(scf_error());
5695 				goto out;
5696 
5697 			case SCF_ERROR_NOT_SET:
5698 			case SCF_ERROR_NOT_BOUND:
5699 			default:
5700 				bad_error("scf_pg_delete", scf_error());
5701 			}
5702 		}
5703 
5704 		cbdata.sc_handle = g_hndl;
5705 		cbdata.sc_parent = ent;
5706 		cbdata.sc_service = issvc;
5707 		cbdata.sc_flags = 0;
5708 		cbdata.sc_source_fmri = ient->sc_fmri;
5709 		cbdata.sc_target_fmri = ient->sc_fmri;
5710 
5711 		r = entity_pgroup_import(mpg, &cbdata);
5712 		switch (r) {
5713 		case UU_WALK_NEXT:
5714 			r = 0;
5715 			goto out;
5716 
5717 		case UU_WALK_ERROR:
5718 			if (cbdata.sc_err == EEXIST) {
5719 				warn(emsg_pg_added, ient->sc_fmri,
5720 				    mpg->sc_pgroup_name);
5721 				r = EBUSY;
5722 			} else {
5723 				r = cbdata.sc_err;
5724 			}
5725 			goto out;
5726 
5727 		default:
5728 			bad_error("entity_pgroup_import", r);
5729 		}
5730 	}
5731 
5732 	if (running != NULL &&
5733 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5734 		switch (scf_error()) {
5735 		case SCF_ERROR_CONNECTION_BROKEN:
5736 		case SCF_ERROR_DELETED:
5737 			r = scferror2errno(scf_error());
5738 			goto out;
5739 
5740 		case SCF_ERROR_NOT_FOUND:
5741 			break;
5742 
5743 		case SCF_ERROR_HANDLE_MISMATCH:
5744 		case SCF_ERROR_INVALID_ARGUMENT:
5745 		case SCF_ERROR_NOT_SET:
5746 		case SCF_ERROR_NOT_BOUND:
5747 		default:
5748 			bad_error("entity_get_pg", scf_error());
5749 		}
5750 
5751 		cbdata.sc_handle = g_hndl;
5752 		cbdata.sc_parent = ent;
5753 		cbdata.sc_service = issvc;
5754 		cbdata.sc_flags = SCI_FORCE;
5755 		cbdata.sc_source_fmri = ient->sc_fmri;
5756 		cbdata.sc_target_fmri = ient->sc_fmri;
5757 
5758 		r = entity_pgroup_import(mpg, &cbdata);
5759 		switch (r) {
5760 		case UU_WALK_NEXT:
5761 			r = 0;
5762 			goto out;
5763 
5764 		case UU_WALK_ERROR:
5765 			if (cbdata.sc_err == EEXIST) {
5766 				warn(emsg_pg_added, ient->sc_fmri,
5767 				    mpg->sc_pgroup_name);
5768 				r = EBUSY;
5769 			} else {
5770 				r = cbdata.sc_err;
5771 			}
5772 			goto out;
5773 
5774 		default:
5775 			bad_error("entity_pgroup_import", r);
5776 		}
5777 	}
5778 
5779 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5780 	internal_pgroup_free(curpg_i);
5781 	switch (r) {
5782 	case 0:
5783 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5784 		break;
5785 
5786 	case ECANCELED:
5787 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5788 		r = EBUSY;
5789 		break;
5790 
5791 	case EPERM:
5792 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5793 		break;
5794 
5795 	case EBUSY:
5796 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5797 		break;
5798 
5799 	case ECONNABORTED:
5800 	case ENOMEM:
5801 	case ENOSPC:
5802 	case EROFS:
5803 	case EACCES:
5804 	case EINVAL:
5805 		break;
5806 
5807 	default:
5808 		bad_error("upgrade_pg", r);
5809 	}
5810 
5811 out:
5812 	internal_pgroup_free(lipg_i);
5813 	return (r);
5814 }
5815 
5816 /*
5817  * Upgrade the properties of ent according to snpl & ient.
5818  *
5819  * Returns
5820  *   0 - success
5821  *   ECONNABORTED - repository connection broken
5822  *   ENOMEM - out of memory
5823  *   ENOSPC - configd is out of resources
5824  *   ECANCELED - ent was deleted
5825  *   ENODEV - entity containing snpl was deleted
5826  *	    - entity containing running was deleted
5827  *   EBADF - imp_snpl is corrupt (error printed)
5828  *	   - ent has corrupt pg (error printed)
5829  *	   - dependent has corrupt pg (error printed)
5830  *	   - dependent target has a corrupt snapshot (error printed)
5831  *   EBUSY - pg was added, changed, or deleted (error printed)
5832  *	   - dependent target was deleted (error printed)
5833  *	   - dependent pg changed (error printed)
5834  *   EINVAL - invalid property group name (error printed)
5835  *	    - invalid property name (error printed)
5836  *	    - invalid value (error printed)
5837  *	    - ient has invalid pgroup or dependent (error printed)
5838  *   EPERM - could not create property group (permission denied) (error printed)
5839  *	   - could not modify property group (permission denied) (error printed)
5840  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5841  *   EROFS - could not create property group (repository read-only)
5842  *	   - couldn't delete, upgrade, or import pg or dependent
5843  *   EACCES - could not create property group (backend access denied)
5844  *	    - couldn't delete, upgrade, or import pg or dependent
5845  *   EEXIST - dependent collision in target service (error printed)
5846  */
5847 static int
5848 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5849     entity_t *ient)
5850 {
5851 	pgroup_t *pg, *rpg;
5852 	int r;
5853 	uu_list_t *pgs = ient->sc_pgroups;
5854 
5855 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5856 
5857 	/* clear sc_sceen for pgs */
5858 	if (uu_list_walk(pgs, clear_int,
5859 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5860 		bad_error("uu_list_walk", uu_error());
5861 
5862 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5863 		switch (scf_error()) {
5864 		case SCF_ERROR_DELETED:
5865 			return (ENODEV);
5866 
5867 		case SCF_ERROR_CONNECTION_BROKEN:
5868 			return (ECONNABORTED);
5869 
5870 		case SCF_ERROR_NOT_SET:
5871 		case SCF_ERROR_NOT_BOUND:
5872 		case SCF_ERROR_HANDLE_MISMATCH:
5873 		default:
5874 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5875 		}
5876 	}
5877 
5878 	for (;;) {
5879 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5880 		if (r == 0)
5881 			break;
5882 		if (r == 1) {
5883 			r = process_old_pg(imp_pg, ient, ent, running);
5884 			switch (r) {
5885 			case 0:
5886 				break;
5887 
5888 			case ECONNABORTED:
5889 			case ENOMEM:
5890 			case ENOSPC:
5891 			case ECANCELED:
5892 			case ENODEV:
5893 			case EPERM:
5894 			case EROFS:
5895 			case EACCES:
5896 			case EBADF:
5897 			case EBUSY:
5898 			case EINVAL:
5899 			case EEXIST:
5900 				return (r);
5901 
5902 			default:
5903 				bad_error("process_old_pg", r);
5904 			}
5905 			continue;
5906 		}
5907 		if (r != -1)
5908 			bad_error("scf_iter_next_pg", r);
5909 
5910 		switch (scf_error()) {
5911 		case SCF_ERROR_DELETED:
5912 			return (ENODEV);
5913 
5914 		case SCF_ERROR_CONNECTION_BROKEN:
5915 			return (ECONNABORTED);
5916 
5917 		case SCF_ERROR_HANDLE_MISMATCH:
5918 		case SCF_ERROR_NOT_BOUND:
5919 		case SCF_ERROR_NOT_SET:
5920 		case SCF_ERROR_INVALID_ARGUMENT:
5921 		default:
5922 			bad_error("scf_iter_next_pg", scf_error());
5923 		}
5924 	}
5925 
5926 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5927 		if (pg->sc_pgroup_seen)
5928 			continue;
5929 
5930 		/* pg is new */
5931 
5932 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5933 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5934 			    ent);
5935 			switch (r) {
5936 			case 0:
5937 				break;
5938 
5939 			case ECONNABORTED:
5940 			case ENOMEM:
5941 			case ENOSPC:
5942 			case ECANCELED:
5943 			case ENODEV:
5944 			case EBADF:
5945 			case EBUSY:
5946 			case EINVAL:
5947 			case EPERM:
5948 			case EROFS:
5949 			case EACCES:
5950 			case EEXIST:
5951 				return (r);
5952 
5953 			default:
5954 				bad_error("upgrade_dependents", r);
5955 			}
5956 			continue;
5957 		}
5958 
5959 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
5960 			r = upgrade_manifestfiles(pg, ient, running, ent);
5961 			switch (r) {
5962 			case 0:
5963 				break;
5964 
5965 			case ECONNABORTED:
5966 			case ENOMEM:
5967 			case ENOSPC:
5968 			case ECANCELED:
5969 			case ENODEV:
5970 			case EBADF:
5971 			case EBUSY:
5972 			case EINVAL:
5973 			case EPERM:
5974 			case EROFS:
5975 			case EACCES:
5976 			case EEXIST:
5977 				return (r);
5978 
5979 			default:
5980 				bad_error("upgrade_manifestfiles", r);
5981 			}
5982 			continue;
5983 		}
5984 
5985 		if (running != NULL) {
5986 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
5987 			    imp_pg);
5988 		} else {
5989 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
5990 			    imp_pg);
5991 		}
5992 		if (r != 0) {
5993 			scf_callback_t cbdata;
5994 
5995 			switch (scf_error()) {
5996 			case SCF_ERROR_NOT_FOUND:
5997 				break;
5998 
5999 			case SCF_ERROR_CONNECTION_BROKEN:
6000 				return (scferror2errno(scf_error()));
6001 
6002 			case SCF_ERROR_DELETED:
6003 				if (running != NULL)
6004 					return (ENODEV);
6005 				else
6006 					return (scferror2errno(scf_error()));
6007 
6008 			case SCF_ERROR_INVALID_ARGUMENT:
6009 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6010 				    pg->sc_pgroup_name);
6011 				return (EINVAL);
6012 
6013 			case SCF_ERROR_NOT_SET:
6014 			case SCF_ERROR_HANDLE_MISMATCH:
6015 			case SCF_ERROR_NOT_BOUND:
6016 			default:
6017 				bad_error("entity_get_pg", scf_error());
6018 			}
6019 
6020 			/* User doesn't have pg, so import it. */
6021 
6022 			cbdata.sc_handle = g_hndl;
6023 			cbdata.sc_parent = ent;
6024 			cbdata.sc_service = issvc;
6025 			cbdata.sc_flags = SCI_FORCE;
6026 			cbdata.sc_source_fmri = ient->sc_fmri;
6027 			cbdata.sc_target_fmri = ient->sc_fmri;
6028 
6029 			r = entity_pgroup_import(pg, &cbdata);
6030 			switch (r) {
6031 			case UU_WALK_NEXT:
6032 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6033 				continue;
6034 
6035 			case UU_WALK_ERROR:
6036 				if (cbdata.sc_err == EEXIST) {
6037 					warn(emsg_pg_added, ient->sc_fmri,
6038 					    pg->sc_pgroup_name);
6039 					return (EBUSY);
6040 				}
6041 				return (cbdata.sc_err);
6042 
6043 			default:
6044 				bad_error("entity_pgroup_import", r);
6045 			}
6046 		}
6047 
6048 		/* report differences between pg & current */
6049 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6050 		switch (r) {
6051 		case 0:
6052 			break;
6053 
6054 		case ECANCELED:
6055 			warn(emsg_pg_deleted, ient->sc_fmri,
6056 			    pg->sc_pgroup_name);
6057 			return (EBUSY);
6058 
6059 		case ECONNABORTED:
6060 		case EBADF:
6061 		case ENOMEM:
6062 		case EACCES:
6063 			return (r);
6064 
6065 		default:
6066 			bad_error("load_pg", r);
6067 		}
6068 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6069 		internal_pgroup_free(rpg);
6070 		rpg = NULL;
6071 	}
6072 
6073 	return (0);
6074 }
6075 
6076 /*
6077  * Import an instance.  If it doesn't exist, create it.  If it has
6078  * a last-import snapshot, upgrade its properties.  Finish by updating its
6079  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6080  * could have been created for a dependent tag in another manifest.  Import the
6081  * new properties.  If there's a conflict, don't override, like now?
6082  *
6083  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6084  * lcbdata->sc_err to
6085  *   ECONNABORTED - repository connection broken
6086  *   ENOMEM - out of memory
6087  *   ENOSPC - svc.configd is out of resources
6088  *   EEXIST - dependency collision in dependent service (error printed)
6089  *   EPERM - couldn't create temporary instance (permission denied)
6090  *	   - couldn't import into temporary instance (permission denied)
6091  *	   - couldn't take snapshot (permission denied)
6092  *	   - couldn't upgrade properties (permission denied)
6093  *	   - couldn't import properties (permission denied)
6094  *	   - couldn't import dependents (permission denied)
6095  *   EROFS - couldn't create temporary instance (repository read-only)
6096  *	   - couldn't import into temporary instance (repository read-only)
6097  *	   - couldn't upgrade properties (repository read-only)
6098  *	   - couldn't import properties (repository read-only)
6099  *	   - couldn't import dependents (repository read-only)
6100  *   EACCES - couldn't create temporary instance (backend access denied)
6101  *	    - couldn't import into temporary instance (backend access denied)
6102  *	    - couldn't upgrade properties (backend access denied)
6103  *	    - couldn't import properties (backend access denied)
6104  *	    - couldn't import dependents (backend access denied)
6105  *   EINVAL - invalid instance name (error printed)
6106  *	    - invalid pgroup_t's (error printed)
6107  *	    - invalid dependents (error printed)
6108  *   EBUSY - temporary service deleted (error printed)
6109  *	   - temporary instance deleted (error printed)
6110  *	   - temporary instance changed (error printed)
6111  *	   - temporary instance already exists (error printed)
6112  *	   - instance deleted (error printed)
6113  *   EBADF - instance has corrupt last-import snapshot (error printed)
6114  *	   - instance is corrupt (error printed)
6115  *	   - dependent has corrupt pg (error printed)
6116  *	   - dependent target has a corrupt snapshot (error printed)
6117  *   -1 - unknown libscf error (error printed)
6118  */
6119 static int
6120 lscf_instance_import(void *v, void *pvt)
6121 {
6122 	entity_t *inst = v;
6123 	scf_callback_t ctx;
6124 	scf_callback_t *lcbdata = pvt;
6125 	scf_service_t *rsvc = lcbdata->sc_parent;
6126 	int r;
6127 	scf_snaplevel_t *running;
6128 	int flags = lcbdata->sc_flags;
6129 
6130 	const char * const emsg_tdel =
6131 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6132 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6133 	    "changed unexpectedly.\n");
6134 	const char * const emsg_del = gettext("%s changed unexpectedly "
6135 	    "(instance \"%s\" was deleted.)\n");
6136 	const char * const emsg_badsnap = gettext(
6137 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6138 
6139 	/*
6140 	 * prepare last-import snapshot:
6141 	 * create temporary instance (service was precreated)
6142 	 * populate with properties from bundle
6143 	 * take snapshot
6144 	 */
6145 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6146 		switch (scf_error()) {
6147 		case SCF_ERROR_CONNECTION_BROKEN:
6148 		case SCF_ERROR_NO_RESOURCES:
6149 		case SCF_ERROR_BACKEND_READONLY:
6150 		case SCF_ERROR_BACKEND_ACCESS:
6151 			return (stash_scferror(lcbdata));
6152 
6153 		case SCF_ERROR_EXISTS:
6154 			warn(gettext("Temporary service svc:/%s "
6155 			    "changed unexpectedly (instance \"%s\" added).\n"),
6156 			    imp_tsname, inst->sc_name);
6157 			lcbdata->sc_err = EBUSY;
6158 			return (UU_WALK_ERROR);
6159 
6160 		case SCF_ERROR_DELETED:
6161 			warn(gettext("Temporary service svc:/%s "
6162 			    "was deleted unexpectedly.\n"), imp_tsname);
6163 			lcbdata->sc_err = EBUSY;
6164 			return (UU_WALK_ERROR);
6165 
6166 		case SCF_ERROR_INVALID_ARGUMENT:
6167 			warn(gettext("Invalid instance name \"%s\".\n"),
6168 			    inst->sc_name);
6169 			return (stash_scferror(lcbdata));
6170 
6171 		case SCF_ERROR_PERMISSION_DENIED:
6172 			warn(gettext("Could not create temporary instance "
6173 			    "\"%s\" in svc:/%s (permission denied).\n"),
6174 			    inst->sc_name, imp_tsname);
6175 			return (stash_scferror(lcbdata));
6176 
6177 		case SCF_ERROR_HANDLE_MISMATCH:
6178 		case SCF_ERROR_NOT_BOUND:
6179 		case SCF_ERROR_NOT_SET:
6180 		default:
6181 			bad_error("scf_service_add_instance", scf_error());
6182 		}
6183 	}
6184 
6185 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6186 	    inst->sc_name);
6187 	if (r < 0)
6188 		bad_error("snprintf", errno);
6189 
6190 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6191 	    lcbdata->sc_flags | SCI_NOENABLED);
6192 	switch (r) {
6193 	case 0:
6194 		break;
6195 
6196 	case ECANCELED:
6197 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6198 		lcbdata->sc_err = EBUSY;
6199 		r = UU_WALK_ERROR;
6200 		goto deltemp;
6201 
6202 	case EEXIST:
6203 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6204 		lcbdata->sc_err = EBUSY;
6205 		r = UU_WALK_ERROR;
6206 		goto deltemp;
6207 
6208 	case ECONNABORTED:
6209 		goto connaborted;
6210 
6211 	case ENOMEM:
6212 	case ENOSPC:
6213 	case EPERM:
6214 	case EROFS:
6215 	case EACCES:
6216 	case EINVAL:
6217 	case EBUSY:
6218 		lcbdata->sc_err = r;
6219 		r = UU_WALK_ERROR;
6220 		goto deltemp;
6221 
6222 	default:
6223 		bad_error("lscf_import_instance_pgs", r);
6224 	}
6225 
6226 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6227 	    inst->sc_name);
6228 	if (r < 0)
6229 		bad_error("snprintf", errno);
6230 
6231 	ctx.sc_handle = lcbdata->sc_handle;
6232 	ctx.sc_parent = imp_tinst;
6233 	ctx.sc_service = 0;
6234 	ctx.sc_source_fmri = inst->sc_fmri;
6235 	ctx.sc_target_fmri = imp_str;
6236 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6237 	    UU_DEFAULT) != 0) {
6238 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6239 			bad_error("uu_list_walk", uu_error());
6240 
6241 		switch (ctx.sc_err) {
6242 		case ECONNABORTED:
6243 			goto connaborted;
6244 
6245 		case ECANCELED:
6246 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6247 			lcbdata->sc_err = EBUSY;
6248 			break;
6249 
6250 		case EEXIST:
6251 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6252 			lcbdata->sc_err = EBUSY;
6253 			break;
6254 
6255 		default:
6256 			lcbdata->sc_err = ctx.sc_err;
6257 		}
6258 		r = UU_WALK_ERROR;
6259 		goto deltemp;
6260 	}
6261 
6262 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6263 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6264 		switch (scf_error()) {
6265 		case SCF_ERROR_CONNECTION_BROKEN:
6266 			goto connaborted;
6267 
6268 		case SCF_ERROR_NO_RESOURCES:
6269 			r = stash_scferror(lcbdata);
6270 			goto deltemp;
6271 
6272 		case SCF_ERROR_EXISTS:
6273 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6274 			lcbdata->sc_err = EBUSY;
6275 			r = UU_WALK_ERROR;
6276 			goto deltemp;
6277 
6278 		case SCF_ERROR_PERMISSION_DENIED:
6279 			warn(gettext("Could not take \"%s\" snapshot of %s "
6280 			    "(permission denied).\n"), snap_lastimport,
6281 			    imp_str);
6282 			r = stash_scferror(lcbdata);
6283 			goto deltemp;
6284 
6285 		default:
6286 			scfwarn();
6287 			lcbdata->sc_err = -1;
6288 			r = UU_WALK_ERROR;
6289 			goto deltemp;
6290 
6291 		case SCF_ERROR_HANDLE_MISMATCH:
6292 		case SCF_ERROR_INVALID_ARGUMENT:
6293 		case SCF_ERROR_NOT_SET:
6294 			bad_error("_scf_snapshot_take_new_named", scf_error());
6295 		}
6296 	}
6297 
6298 	if (lcbdata->sc_flags & SCI_FRESH)
6299 		goto fresh;
6300 
6301 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6302 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6303 		    imp_lisnap) != 0) {
6304 			switch (scf_error()) {
6305 			case SCF_ERROR_DELETED:
6306 				warn(emsg_del, inst->sc_parent->sc_fmri,
6307 				    inst->sc_name);
6308 				lcbdata->sc_err = EBUSY;
6309 				r = UU_WALK_ERROR;
6310 				goto deltemp;
6311 
6312 			case SCF_ERROR_NOT_FOUND:
6313 				flags |= SCI_FORCE;
6314 				goto nosnap;
6315 
6316 			case SCF_ERROR_CONNECTION_BROKEN:
6317 				goto connaborted;
6318 
6319 			case SCF_ERROR_INVALID_ARGUMENT:
6320 			case SCF_ERROR_HANDLE_MISMATCH:
6321 			case SCF_ERROR_NOT_BOUND:
6322 			case SCF_ERROR_NOT_SET:
6323 			default:
6324 				bad_error("scf_instance_get_snapshot",
6325 				    scf_error());
6326 			}
6327 		}
6328 
6329 		/* upgrade */
6330 
6331 		/*
6332 		 * compare new properties with last-import properties
6333 		 * upgrade current properties
6334 		 */
6335 		/* clear sc_sceen for pgs */
6336 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6337 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6338 		    0)
6339 			bad_error("uu_list_walk", uu_error());
6340 
6341 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6342 		switch (r) {
6343 		case 0:
6344 			break;
6345 
6346 		case ECONNABORTED:
6347 			goto connaborted;
6348 
6349 		case ECANCELED:
6350 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6351 			lcbdata->sc_err = EBUSY;
6352 			r = UU_WALK_ERROR;
6353 			goto deltemp;
6354 
6355 		case ENOENT:
6356 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6357 			lcbdata->sc_err = EBADF;
6358 			r = UU_WALK_ERROR;
6359 			goto deltemp;
6360 
6361 		default:
6362 			bad_error("get_snaplevel", r);
6363 		}
6364 
6365 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6366 		    imp_rsnap) != 0) {
6367 			switch (scf_error()) {
6368 			case SCF_ERROR_DELETED:
6369 				warn(emsg_del, inst->sc_parent->sc_fmri,
6370 				    inst->sc_name);
6371 				lcbdata->sc_err = EBUSY;
6372 				r = UU_WALK_ERROR;
6373 				goto deltemp;
6374 
6375 			case SCF_ERROR_NOT_FOUND:
6376 				break;
6377 
6378 			case SCF_ERROR_CONNECTION_BROKEN:
6379 				goto connaborted;
6380 
6381 			case SCF_ERROR_INVALID_ARGUMENT:
6382 			case SCF_ERROR_HANDLE_MISMATCH:
6383 			case SCF_ERROR_NOT_BOUND:
6384 			case SCF_ERROR_NOT_SET:
6385 			default:
6386 				bad_error("scf_instance_get_snapshot",
6387 				    scf_error());
6388 			}
6389 
6390 			running = NULL;
6391 		} else {
6392 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6393 			switch (r) {
6394 			case 0:
6395 				running = imp_rsnpl;
6396 				break;
6397 
6398 			case ECONNABORTED:
6399 				goto connaborted;
6400 
6401 			case ECANCELED:
6402 				warn(emsg_del, inst->sc_parent->sc_fmri,
6403 				    inst->sc_name);
6404 				lcbdata->sc_err = EBUSY;
6405 				r = UU_WALK_ERROR;
6406 				goto deltemp;
6407 
6408 			case ENOENT:
6409 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6410 				lcbdata->sc_err = EBADF;
6411 				r = UU_WALK_ERROR;
6412 				goto deltemp;
6413 
6414 			default:
6415 				bad_error("get_snaplevel", r);
6416 			}
6417 		}
6418 
6419 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6420 		switch (r) {
6421 		case 0:
6422 			break;
6423 
6424 		case ECANCELED:
6425 		case ENODEV:
6426 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6427 			lcbdata->sc_err = EBUSY;
6428 			r = UU_WALK_ERROR;
6429 			goto deltemp;
6430 
6431 		case ECONNABORTED:
6432 			goto connaborted;
6433 
6434 		case ENOMEM:
6435 		case ENOSPC:
6436 		case EBADF:
6437 		case EBUSY:
6438 		case EINVAL:
6439 		case EPERM:
6440 		case EROFS:
6441 		case EACCES:
6442 		case EEXIST:
6443 			lcbdata->sc_err = r;
6444 			r = UU_WALK_ERROR;
6445 			goto deltemp;
6446 
6447 		default:
6448 			bad_error("upgrade_props", r);
6449 		}
6450 
6451 		inst->sc_import_state = IMPORT_PROP_DONE;
6452 	} else {
6453 		switch (scf_error()) {
6454 		case SCF_ERROR_CONNECTION_BROKEN:
6455 			goto connaborted;
6456 
6457 		case SCF_ERROR_NOT_FOUND:
6458 			break;
6459 
6460 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6461 		case SCF_ERROR_HANDLE_MISMATCH:
6462 		case SCF_ERROR_NOT_BOUND:
6463 		case SCF_ERROR_NOT_SET:
6464 		default:
6465 			bad_error("scf_service_get_instance", scf_error());
6466 		}
6467 
6468 fresh:
6469 		/* create instance */
6470 		if (scf_service_add_instance(rsvc, inst->sc_name,
6471 		    imp_inst) != 0) {
6472 			switch (scf_error()) {
6473 			case SCF_ERROR_CONNECTION_BROKEN:
6474 				goto connaborted;
6475 
6476 			case SCF_ERROR_NO_RESOURCES:
6477 			case SCF_ERROR_BACKEND_READONLY:
6478 			case SCF_ERROR_BACKEND_ACCESS:
6479 				r = stash_scferror(lcbdata);
6480 				goto deltemp;
6481 
6482 			case SCF_ERROR_EXISTS:
6483 				warn(gettext("%s changed unexpectedly "
6484 				    "(instance \"%s\" added).\n"),
6485 				    inst->sc_parent->sc_fmri, inst->sc_name);
6486 				lcbdata->sc_err = EBUSY;
6487 				r = UU_WALK_ERROR;
6488 				goto deltemp;
6489 
6490 			case SCF_ERROR_PERMISSION_DENIED:
6491 				warn(gettext("Could not create \"%s\" instance "
6492 				    "in %s (permission denied).\n"),
6493 				    inst->sc_name, inst->sc_parent->sc_fmri);
6494 				r = stash_scferror(lcbdata);
6495 				goto deltemp;
6496 
6497 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6498 			case SCF_ERROR_HANDLE_MISMATCH:
6499 			case SCF_ERROR_NOT_BOUND:
6500 			case SCF_ERROR_NOT_SET:
6501 			default:
6502 				bad_error("scf_service_add_instance",
6503 				    scf_error());
6504 			}
6505 		}
6506 
6507 nosnap:
6508 		/*
6509 		 * Create a last-import snapshot to serve as an attachment
6510 		 * point for the real one from the temporary instance.  Since
6511 		 * the contents is irrelevant, take it now, while the instance
6512 		 * is empty, to minimize svc.configd's work.
6513 		 */
6514 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6515 		    imp_lisnap) != 0) {
6516 			switch (scf_error()) {
6517 			case SCF_ERROR_CONNECTION_BROKEN:
6518 				goto connaborted;
6519 
6520 			case SCF_ERROR_NO_RESOURCES:
6521 				r = stash_scferror(lcbdata);
6522 				goto deltemp;
6523 
6524 			case SCF_ERROR_EXISTS:
6525 				warn(gettext("%s changed unexpectedly "
6526 				    "(snapshot \"%s\" added).\n"),
6527 				    inst->sc_fmri, snap_lastimport);
6528 				lcbdata->sc_err = EBUSY;
6529 				r = UU_WALK_ERROR;
6530 				goto deltemp;
6531 
6532 			case SCF_ERROR_PERMISSION_DENIED:
6533 				warn(gettext("Could not take \"%s\" snapshot "
6534 				    "of %s (permission denied).\n"),
6535 				    snap_lastimport, inst->sc_fmri);
6536 				r = stash_scferror(lcbdata);
6537 				goto deltemp;
6538 
6539 			default:
6540 				scfwarn();
6541 				lcbdata->sc_err = -1;
6542 				r = UU_WALK_ERROR;
6543 				goto deltemp;
6544 
6545 			case SCF_ERROR_NOT_SET:
6546 			case SCF_ERROR_INTERNAL:
6547 			case SCF_ERROR_INVALID_ARGUMENT:
6548 			case SCF_ERROR_HANDLE_MISMATCH:
6549 				bad_error("_scf_snapshot_take_new",
6550 				    scf_error());
6551 			}
6552 		}
6553 
6554 		if (li_only)
6555 			goto lionly;
6556 
6557 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6558 
6559 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6560 		    flags);
6561 		switch (r) {
6562 		case 0:
6563 			break;
6564 
6565 		case ECONNABORTED:
6566 			goto connaborted;
6567 
6568 		case ECANCELED:
6569 			warn(gettext("%s changed unexpectedly "
6570 			    "(instance \"%s\" deleted).\n"),
6571 			    inst->sc_parent->sc_fmri, inst->sc_name);
6572 			lcbdata->sc_err = EBUSY;
6573 			r = UU_WALK_ERROR;
6574 			goto deltemp;
6575 
6576 		case EEXIST:
6577 			warn(gettext("%s changed unexpectedly "
6578 			    "(property group added).\n"), inst->sc_fmri);
6579 			lcbdata->sc_err = EBUSY;
6580 			r = UU_WALK_ERROR;
6581 			goto deltemp;
6582 
6583 		default:
6584 			lcbdata->sc_err = r;
6585 			r = UU_WALK_ERROR;
6586 			goto deltemp;
6587 
6588 		case EINVAL:	/* caught above */
6589 			bad_error("lscf_import_instance_pgs", r);
6590 		}
6591 
6592 		ctx.sc_parent = imp_inst;
6593 		ctx.sc_service = 0;
6594 		ctx.sc_trans = NULL;
6595 		ctx.sc_flags = 0;
6596 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6597 		    &ctx, UU_DEFAULT) != 0) {
6598 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6599 				bad_error("uu_list_walk", uu_error());
6600 
6601 			if (ctx.sc_err == ECONNABORTED)
6602 				goto connaborted;
6603 			lcbdata->sc_err = ctx.sc_err;
6604 			r = UU_WALK_ERROR;
6605 			goto deltemp;
6606 		}
6607 
6608 		inst->sc_import_state = IMPORT_PROP_DONE;
6609 
6610 		if (g_verbose)
6611 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6612 			    snap_initial, inst->sc_fmri);
6613 		r = take_snap(imp_inst, snap_initial, imp_snap);
6614 		switch (r) {
6615 		case 0:
6616 			break;
6617 
6618 		case ECONNABORTED:
6619 			goto connaborted;
6620 
6621 		case ENOSPC:
6622 		case -1:
6623 			lcbdata->sc_err = r;
6624 			r = UU_WALK_ERROR;
6625 			goto deltemp;
6626 
6627 		case ECANCELED:
6628 			warn(gettext("%s changed unexpectedly "
6629 			    "(instance %s deleted).\n"),
6630 			    inst->sc_parent->sc_fmri, inst->sc_name);
6631 			lcbdata->sc_err = r;
6632 			r = UU_WALK_ERROR;
6633 			goto deltemp;
6634 
6635 		case EPERM:
6636 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6637 			lcbdata->sc_err = r;
6638 			r = UU_WALK_ERROR;
6639 			goto deltemp;
6640 
6641 		default:
6642 			bad_error("take_snap", r);
6643 		}
6644 	}
6645 
6646 lionly:
6647 	if (lcbdata->sc_flags & SCI_NOSNAP)
6648 		goto deltemp;
6649 
6650 	/* transfer snapshot from temporary instance */
6651 	if (g_verbose)
6652 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6653 		    snap_lastimport, inst->sc_fmri);
6654 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6655 		switch (scf_error()) {
6656 		case SCF_ERROR_CONNECTION_BROKEN:
6657 			goto connaborted;
6658 
6659 		case SCF_ERROR_NO_RESOURCES:
6660 			r = stash_scferror(lcbdata);
6661 			goto deltemp;
6662 
6663 		case SCF_ERROR_PERMISSION_DENIED:
6664 			warn(gettext("Could not take \"%s\" snapshot for %s "
6665 			    "(permission denied).\n"), snap_lastimport,
6666 			    inst->sc_fmri);
6667 			r = stash_scferror(lcbdata);
6668 			goto deltemp;
6669 
6670 		case SCF_ERROR_NOT_SET:
6671 		case SCF_ERROR_HANDLE_MISMATCH:
6672 		default:
6673 			bad_error("_scf_snapshot_attach", scf_error());
6674 		}
6675 	}
6676 
6677 	inst->sc_import_state = IMPORT_COMPLETE;
6678 
6679 	r = UU_WALK_NEXT;
6680 
6681 deltemp:
6682 	/* delete temporary instance */
6683 	if (scf_instance_delete(imp_tinst) != 0) {
6684 		switch (scf_error()) {
6685 		case SCF_ERROR_DELETED:
6686 			break;
6687 
6688 		case SCF_ERROR_CONNECTION_BROKEN:
6689 			goto connaborted;
6690 
6691 		case SCF_ERROR_NOT_SET:
6692 		case SCF_ERROR_NOT_BOUND:
6693 		default:
6694 			bad_error("scf_instance_delete", scf_error());
6695 		}
6696 	}
6697 
6698 	return (r);
6699 
6700 connaborted:
6701 	warn(gettext("Could not delete svc:/%s:%s "
6702 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6703 	lcbdata->sc_err = ECONNABORTED;
6704 	return (UU_WALK_ERROR);
6705 }
6706 
6707 /*
6708  * If the service is missing, create it, import its properties, and import the
6709  * instances.  Since the service is brand new, it should be empty, and if we
6710  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6711  *
6712  * If the service exists, we want to upgrade its properties and import the
6713  * instances.  Upgrade requires a last-import snapshot, though, which are
6714  * children of instances, so first we'll have to go through the instances
6715  * looking for a last-import snapshot.  If we don't find one then we'll just
6716  * override-import the service properties (but don't delete existing
6717  * properties: another service might have declared us as a dependent).  Before
6718  * we change anything, though, we want to take the previous snapshots.  We
6719  * also give lscf_instance_import() a leg up on taking last-import snapshots
6720  * by importing the manifest's service properties into a temporary service.
6721  *
6722  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6723  * sets lcbdata->sc_err to
6724  *   ECONNABORTED - repository connection broken
6725  *   ENOMEM - out of memory
6726  *   ENOSPC - svc.configd is out of resources
6727  *   EPERM - couldn't create temporary service (error printed)
6728  *	   - couldn't import into temp service (error printed)
6729  *	   - couldn't create service (error printed)
6730  *	   - couldn't import dependent (error printed)
6731  *	   - couldn't take snapshot (error printed)
6732  *	   - couldn't create instance (error printed)
6733  *	   - couldn't create, modify, or delete pg (error printed)
6734  *	   - couldn't create, modify, or delete dependent (error printed)
6735  *	   - couldn't import instance (error printed)
6736  *   EROFS - couldn't create temporary service (repository read-only)
6737  *	   - couldn't import into temporary service (repository read-only)
6738  *	   - couldn't create service (repository read-only)
6739  *	   - couldn't import dependent (repository read-only)
6740  *	   - couldn't create instance (repository read-only)
6741  *	   - couldn't create, modify, or delete pg or dependent
6742  *	   - couldn't import instance (repository read-only)
6743  *   EACCES - couldn't create temporary service (backend access denied)
6744  *	    - couldn't import into temporary service (backend access denied)
6745  *	    - couldn't create service (backend access denied)
6746  *	    - couldn't import dependent (backend access denied)
6747  *	    - couldn't create instance (backend access denied)
6748  *	    - couldn't create, modify, or delete pg or dependent
6749  *	    - couldn't import instance (backend access denied)
6750  *   EINVAL - service name is invalid (error printed)
6751  *	    - service name is too long (error printed)
6752  *	    - s has invalid pgroup (error printed)
6753  *	    - s has invalid dependent (error printed)
6754  *	    - instance name is invalid (error printed)
6755  *	    - instance entity_t is invalid (error printed)
6756  *   EEXIST - couldn't create temporary service (already exists) (error printed)
6757  *	    - couldn't import dependent (dependency pg already exists) (printed)
6758  *	    - dependency collision in dependent service (error printed)
6759  *   EBUSY - temporary service deleted (error printed)
6760  *	   - property group added to temporary service (error printed)
6761  *	   - new property group changed or was deleted (error printed)
6762  *	   - service was added unexpectedly (error printed)
6763  *	   - service was deleted unexpectedly (error printed)
6764  *	   - property group added to new service (error printed)
6765  *	   - instance added unexpectedly (error printed)
6766  *	   - instance deleted unexpectedly (error printed)
6767  *	   - dependent service deleted unexpectedly (error printed)
6768  *	   - pg was added, changed, or deleted (error printed)
6769  *	   - dependent pg changed (error printed)
6770  *	   - temporary instance added, changed, or deleted (error printed)
6771  *   EBADF - a last-import snapshot is corrupt (error printed)
6772  *	   - the service is corrupt (error printed)
6773  *	   - a dependent is corrupt (error printed)
6774  *	   - an instance is corrupt (error printed)
6775  *	   - an instance has a corrupt last-import snapshot (error printed)
6776  *	   - dependent target has a corrupt snapshot (error printed)
6777  *   -1 - unknown libscf error (error printed)
6778  */
6779 static int
6780 lscf_service_import(void *v, void *pvt)
6781 {
6782 	entity_t *s = v;
6783 	scf_callback_t cbdata;
6784 	scf_callback_t *lcbdata = pvt;
6785 	scf_scope_t *scope = lcbdata->sc_parent;
6786 	entity_t *inst, linst;
6787 	int r;
6788 	int fresh = 0;
6789 	scf_snaplevel_t *running;
6790 	int have_ge = 0;
6791 
6792 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
6793 	    "was deleted unexpectedly.\n");
6794 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6795 	    "changed unexpectedly (property group added).\n");
6796 	const char * const s_deleted =
6797 	    gettext("%s was deleted unexpectedly.\n");
6798 	const char * const i_deleted =
6799 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6800 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6801 	    "is corrupt (missing service snaplevel).\n");
6802 	const char * const s_mfile_upd =
6803 	    gettext("Unable to update the manifest file connection "
6804 	    "for %s\n");
6805 
6806 	li_only = 0;
6807 	/* Validate the service name */
6808 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6809 		switch (scf_error()) {
6810 		case SCF_ERROR_CONNECTION_BROKEN:
6811 			return (stash_scferror(lcbdata));
6812 
6813 		case SCF_ERROR_INVALID_ARGUMENT:
6814 			warn(gettext("\"%s\" is an invalid service name.  "
6815 			    "Cannot import.\n"), s->sc_name);
6816 			return (stash_scferror(lcbdata));
6817 
6818 		case SCF_ERROR_NOT_FOUND:
6819 			break;
6820 
6821 		case SCF_ERROR_HANDLE_MISMATCH:
6822 		case SCF_ERROR_NOT_BOUND:
6823 		case SCF_ERROR_NOT_SET:
6824 		default:
6825 			bad_error("scf_scope_get_service", scf_error());
6826 		}
6827 	}
6828 
6829 	/* create temporary service */
6830 	/*
6831 	 * the size of the buffer was reduced to max_scf_name_len to prevent
6832 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6833 	 * should be restored to its original value (max_scf_name_len +1)
6834 	 */
6835 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6836 	if (r < 0)
6837 		bad_error("snprintf", errno);
6838 	if (r > max_scf_name_len) {
6839 		warn(gettext(
6840 		    "Service name \"%s\" is too long.  Cannot import.\n"),
6841 		    s->sc_name);
6842 		lcbdata->sc_err = EINVAL;
6843 		return (UU_WALK_ERROR);
6844 	}
6845 
6846 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6847 		switch (scf_error()) {
6848 		case SCF_ERROR_CONNECTION_BROKEN:
6849 		case SCF_ERROR_NO_RESOURCES:
6850 		case SCF_ERROR_BACKEND_READONLY:
6851 		case SCF_ERROR_BACKEND_ACCESS:
6852 			return (stash_scferror(lcbdata));
6853 
6854 		case SCF_ERROR_EXISTS:
6855 			warn(gettext(
6856 			    "Temporary service \"%s\" must be deleted before "
6857 			    "this manifest can be imported.\n"), imp_tsname);
6858 			return (stash_scferror(lcbdata));
6859 
6860 		case SCF_ERROR_PERMISSION_DENIED:
6861 			warn(gettext("Could not create temporary service "
6862 			    "\"%s\" (permission denied).\n"), imp_tsname);
6863 			return (stash_scferror(lcbdata));
6864 
6865 		case SCF_ERROR_INVALID_ARGUMENT:
6866 		case SCF_ERROR_HANDLE_MISMATCH:
6867 		case SCF_ERROR_NOT_BOUND:
6868 		case SCF_ERROR_NOT_SET:
6869 		default:
6870 			bad_error("scf_scope_add_service", scf_error());
6871 		}
6872 	}
6873 
6874 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6875 	if (r < 0)
6876 		bad_error("snprintf", errno);
6877 
6878 	cbdata.sc_handle = lcbdata->sc_handle;
6879 	cbdata.sc_parent = imp_tsvc;
6880 	cbdata.sc_service = 1;
6881 	cbdata.sc_source_fmri = s->sc_fmri;
6882 	cbdata.sc_target_fmri = imp_str;
6883 	cbdata.sc_flags = 0;
6884 
6885 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6886 	    UU_DEFAULT) != 0) {
6887 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6888 			bad_error("uu_list_walk", uu_error());
6889 
6890 		lcbdata->sc_err = cbdata.sc_err;
6891 		switch (cbdata.sc_err) {
6892 		case ECONNABORTED:
6893 			goto connaborted;
6894 
6895 		case ECANCELED:
6896 			warn(ts_deleted, imp_tsname);
6897 			lcbdata->sc_err = EBUSY;
6898 			return (UU_WALK_ERROR);
6899 
6900 		case EEXIST:
6901 			warn(ts_pg_added, imp_tsname);
6902 			lcbdata->sc_err = EBUSY;
6903 			return (UU_WALK_ERROR);
6904 		}
6905 
6906 		r = UU_WALK_ERROR;
6907 		goto deltemp;
6908 	}
6909 
6910 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6911 	    UU_DEFAULT) != 0) {
6912 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6913 			bad_error("uu_list_walk", uu_error());
6914 
6915 		lcbdata->sc_err = cbdata.sc_err;
6916 		switch (cbdata.sc_err) {
6917 		case ECONNABORTED:
6918 			goto connaborted;
6919 
6920 		case ECANCELED:
6921 			warn(ts_deleted, imp_tsname);
6922 			lcbdata->sc_err = EBUSY;
6923 			return (UU_WALK_ERROR);
6924 
6925 		case EEXIST:
6926 			warn(ts_pg_added, imp_tsname);
6927 			lcbdata->sc_err = EBUSY;
6928 			return (UU_WALK_ERROR);
6929 		}
6930 
6931 		r = UU_WALK_ERROR;
6932 		goto deltemp;
6933 	}
6934 
6935 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6936 		switch (scf_error()) {
6937 		case SCF_ERROR_NOT_FOUND:
6938 			break;
6939 
6940 		case SCF_ERROR_CONNECTION_BROKEN:
6941 			goto connaborted;
6942 
6943 		case SCF_ERROR_INVALID_ARGUMENT:
6944 		case SCF_ERROR_HANDLE_MISMATCH:
6945 		case SCF_ERROR_NOT_BOUND:
6946 		case SCF_ERROR_NOT_SET:
6947 		default:
6948 			bad_error("scf_scope_get_service", scf_error());
6949 		}
6950 
6951 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6952 			switch (scf_error()) {
6953 			case SCF_ERROR_CONNECTION_BROKEN:
6954 				goto connaborted;
6955 
6956 			case SCF_ERROR_NO_RESOURCES:
6957 			case SCF_ERROR_BACKEND_READONLY:
6958 			case SCF_ERROR_BACKEND_ACCESS:
6959 				r = stash_scferror(lcbdata);
6960 				goto deltemp;
6961 
6962 			case SCF_ERROR_EXISTS:
6963 				warn(gettext("Scope \"%s\" changed unexpectedly"
6964 				    " (service \"%s\" added).\n"),
6965 				    SCF_SCOPE_LOCAL, s->sc_name);
6966 				lcbdata->sc_err = EBUSY;
6967 				goto deltemp;
6968 
6969 			case SCF_ERROR_PERMISSION_DENIED:
6970 				warn(gettext("Could not create service \"%s\" "
6971 				    "(permission denied).\n"), s->sc_name);
6972 				goto deltemp;
6973 
6974 			case SCF_ERROR_INVALID_ARGUMENT:
6975 			case SCF_ERROR_HANDLE_MISMATCH:
6976 			case SCF_ERROR_NOT_BOUND:
6977 			case SCF_ERROR_NOT_SET:
6978 			default:
6979 				bad_error("scf_scope_add_service", scf_error());
6980 			}
6981 		}
6982 
6983 		s->sc_import_state = IMPORT_PROP_BEGUN;
6984 
6985 		/* import service properties */
6986 		cbdata.sc_handle = lcbdata->sc_handle;
6987 		cbdata.sc_parent = imp_svc;
6988 		cbdata.sc_service = 1;
6989 		cbdata.sc_flags = lcbdata->sc_flags;
6990 		cbdata.sc_source_fmri = s->sc_fmri;
6991 		cbdata.sc_target_fmri = s->sc_fmri;
6992 
6993 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6994 		    &cbdata, UU_DEFAULT) != 0) {
6995 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6996 				bad_error("uu_list_walk", uu_error());
6997 
6998 			lcbdata->sc_err = cbdata.sc_err;
6999 			switch (cbdata.sc_err) {
7000 			case ECONNABORTED:
7001 				goto connaborted;
7002 
7003 			case ECANCELED:
7004 				warn(s_deleted, s->sc_fmri);
7005 				lcbdata->sc_err = EBUSY;
7006 				return (UU_WALK_ERROR);
7007 
7008 			case EEXIST:
7009 				warn(gettext("%s changed unexpectedly "
7010 				    "(property group added).\n"), s->sc_fmri);
7011 				lcbdata->sc_err = EBUSY;
7012 				return (UU_WALK_ERROR);
7013 
7014 			case EINVAL:
7015 				/* caught above */
7016 				bad_error("entity_pgroup_import",
7017 				    cbdata.sc_err);
7018 			}
7019 
7020 			r = UU_WALK_ERROR;
7021 			goto deltemp;
7022 		}
7023 
7024 		cbdata.sc_trans = NULL;
7025 		cbdata.sc_flags = 0;
7026 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7027 		    &cbdata, UU_DEFAULT) != 0) {
7028 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7029 				bad_error("uu_list_walk", uu_error());
7030 
7031 			lcbdata->sc_err = cbdata.sc_err;
7032 			if (cbdata.sc_err == ECONNABORTED)
7033 				goto connaborted;
7034 			r = UU_WALK_ERROR;
7035 			goto deltemp;
7036 		}
7037 
7038 		s->sc_import_state = IMPORT_PROP_DONE;
7039 
7040 		/*
7041 		 * This is a new service, so we can't take previous snapshots
7042 		 * or upgrade service properties.
7043 		 */
7044 		fresh = 1;
7045 		goto instances;
7046 	}
7047 
7048 	/* Clear sc_seen for the instances. */
7049 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7050 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7051 		bad_error("uu_list_walk", uu_error());
7052 
7053 	/*
7054 	 * Take previous snapshots for all instances.  Even for ones not
7055 	 * mentioned in the bundle, since we might change their service
7056 	 * properties.
7057 	 */
7058 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7059 		switch (scf_error()) {
7060 		case SCF_ERROR_CONNECTION_BROKEN:
7061 			goto connaborted;
7062 
7063 		case SCF_ERROR_DELETED:
7064 			warn(s_deleted, s->sc_fmri);
7065 			lcbdata->sc_err = EBUSY;
7066 			r = UU_WALK_ERROR;
7067 			goto deltemp;
7068 
7069 		case SCF_ERROR_HANDLE_MISMATCH:
7070 		case SCF_ERROR_NOT_BOUND:
7071 		case SCF_ERROR_NOT_SET:
7072 		default:
7073 			bad_error("scf_iter_service_instances", scf_error());
7074 		}
7075 	}
7076 
7077 	for (;;) {
7078 		r = scf_iter_next_instance(imp_iter, imp_inst);
7079 		if (r == 0)
7080 			break;
7081 		if (r != 1) {
7082 			switch (scf_error()) {
7083 			case SCF_ERROR_DELETED:
7084 				warn(s_deleted, s->sc_fmri);
7085 				lcbdata->sc_err = EBUSY;
7086 				r = UU_WALK_ERROR;
7087 				goto deltemp;
7088 
7089 			case SCF_ERROR_CONNECTION_BROKEN:
7090 				goto connaborted;
7091 
7092 			case SCF_ERROR_NOT_BOUND:
7093 			case SCF_ERROR_HANDLE_MISMATCH:
7094 			case SCF_ERROR_INVALID_ARGUMENT:
7095 			case SCF_ERROR_NOT_SET:
7096 			default:
7097 				bad_error("scf_iter_next_instance",
7098 				    scf_error());
7099 			}
7100 		}
7101 
7102 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7103 			switch (scf_error()) {
7104 			case SCF_ERROR_DELETED:
7105 				continue;
7106 
7107 			case SCF_ERROR_CONNECTION_BROKEN:
7108 				goto connaborted;
7109 
7110 			case SCF_ERROR_NOT_SET:
7111 			case SCF_ERROR_NOT_BOUND:
7112 			default:
7113 				bad_error("scf_instance_get_name", scf_error());
7114 			}
7115 		}
7116 
7117 		if (g_verbose)
7118 			warn(gettext(
7119 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7120 			    snap_previous, s->sc_name, imp_str);
7121 
7122 		r = take_snap(imp_inst, snap_previous, imp_snap);
7123 		switch (r) {
7124 		case 0:
7125 			break;
7126 
7127 		case ECANCELED:
7128 			continue;
7129 
7130 		case ECONNABORTED:
7131 			goto connaborted;
7132 
7133 		case EPERM:
7134 			warn(gettext("Could not take \"%s\" snapshot of "
7135 			    "svc:/%s:%s (permission denied).\n"),
7136 			    snap_previous, s->sc_name, imp_str);
7137 			lcbdata->sc_err = r;
7138 			return (UU_WALK_ERROR);
7139 
7140 		case ENOSPC:
7141 		case -1:
7142 			lcbdata->sc_err = r;
7143 			r = UU_WALK_ERROR;
7144 			goto deltemp;
7145 
7146 		default:
7147 			bad_error("take_snap", r);
7148 		}
7149 
7150 		linst.sc_name = imp_str;
7151 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7152 		    &linst, NULL, NULL);
7153 		if (inst != NULL) {
7154 			inst->sc_import_state = IMPORT_PREVIOUS;
7155 			inst->sc_seen = 1;
7156 		}
7157 	}
7158 
7159 	/*
7160 	 * Create the new instances and take previous snapshots of
7161 	 * them.  This is not necessary, but it maximizes data preservation.
7162 	 */
7163 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7164 	    inst != NULL;
7165 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7166 	    inst)) {
7167 		if (inst->sc_seen)
7168 			continue;
7169 
7170 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7171 		    imp_inst) != 0) {
7172 			switch (scf_error()) {
7173 			case SCF_ERROR_CONNECTION_BROKEN:
7174 				goto connaborted;
7175 
7176 			case SCF_ERROR_BACKEND_READONLY:
7177 			case SCF_ERROR_BACKEND_ACCESS:
7178 			case SCF_ERROR_NO_RESOURCES:
7179 				r = stash_scferror(lcbdata);
7180 				goto deltemp;
7181 
7182 			case SCF_ERROR_EXISTS:
7183 				warn(gettext("%s changed unexpectedly "
7184 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7185 				    inst->sc_name);
7186 				lcbdata->sc_err = EBUSY;
7187 				r = UU_WALK_ERROR;
7188 				goto deltemp;
7189 
7190 			case SCF_ERROR_INVALID_ARGUMENT:
7191 				warn(gettext("Service \"%s\" has instance with "
7192 				    "invalid name \"%s\".\n"), s->sc_name,
7193 				    inst->sc_name);
7194 				r = stash_scferror(lcbdata);
7195 				goto deltemp;
7196 
7197 			case SCF_ERROR_PERMISSION_DENIED:
7198 				warn(gettext("Could not create instance \"%s\" "
7199 				    "in %s (permission denied).\n"),
7200 				    inst->sc_name, s->sc_fmri);
7201 				r = stash_scferror(lcbdata);
7202 				goto deltemp;
7203 
7204 			case SCF_ERROR_HANDLE_MISMATCH:
7205 			case SCF_ERROR_NOT_BOUND:
7206 			case SCF_ERROR_NOT_SET:
7207 			default:
7208 				bad_error("scf_service_add_instance",
7209 				    scf_error());
7210 			}
7211 		}
7212 
7213 		if (g_verbose)
7214 			warn(gettext("Taking \"%s\" snapshot for "
7215 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7216 		r = take_snap(imp_inst, snap_previous, imp_snap);
7217 		switch (r) {
7218 		case 0:
7219 			break;
7220 
7221 		case ECANCELED:
7222 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7223 			lcbdata->sc_err = EBUSY;
7224 			r = UU_WALK_ERROR;
7225 			goto deltemp;
7226 
7227 		case ECONNABORTED:
7228 			goto connaborted;
7229 
7230 		case EPERM:
7231 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7232 			lcbdata->sc_err = r;
7233 			r = UU_WALK_ERROR;
7234 			goto deltemp;
7235 
7236 		case ENOSPC:
7237 		case -1:
7238 			r = UU_WALK_ERROR;
7239 			goto deltemp;
7240 
7241 		default:
7242 			bad_error("take_snap", r);
7243 		}
7244 	}
7245 
7246 	s->sc_import_state = IMPORT_PREVIOUS;
7247 
7248 	/*
7249 	 * Upgrade service properties, if we can find a last-import snapshot.
7250 	 * Any will do because we don't support different service properties
7251 	 * in different manifests, so all snaplevels of the service in all of
7252 	 * the last-import snapshots of the instances should be the same.
7253 	 */
7254 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7255 		switch (scf_error()) {
7256 		case SCF_ERROR_CONNECTION_BROKEN:
7257 			goto connaborted;
7258 
7259 		case SCF_ERROR_DELETED:
7260 			warn(s_deleted, s->sc_fmri);
7261 			lcbdata->sc_err = EBUSY;
7262 			r = UU_WALK_ERROR;
7263 			goto deltemp;
7264 
7265 		case SCF_ERROR_HANDLE_MISMATCH:
7266 		case SCF_ERROR_NOT_BOUND:
7267 		case SCF_ERROR_NOT_SET:
7268 		default:
7269 			bad_error("scf_iter_service_instances", scf_error());
7270 		}
7271 	}
7272 
7273 	for (;;) {
7274 		r = scf_iter_next_instance(imp_iter, imp_inst);
7275 		if (r == -1) {
7276 			switch (scf_error()) {
7277 			case SCF_ERROR_DELETED:
7278 				warn(s_deleted, s->sc_fmri);
7279 				lcbdata->sc_err = EBUSY;
7280 				r = UU_WALK_ERROR;
7281 				goto deltemp;
7282 
7283 			case SCF_ERROR_CONNECTION_BROKEN:
7284 				goto connaborted;
7285 
7286 			case SCF_ERROR_NOT_BOUND:
7287 			case SCF_ERROR_HANDLE_MISMATCH:
7288 			case SCF_ERROR_INVALID_ARGUMENT:
7289 			case SCF_ERROR_NOT_SET:
7290 			default:
7291 				bad_error("scf_iter_next_instance",
7292 				    scf_error());
7293 			}
7294 		}
7295 
7296 		if (r == 0) {
7297 			/*
7298 			 * Didn't find any last-import snapshots.  Override-
7299 			 * import the properties.  Unless one of the instances
7300 			 * has a general/enabled property, in which case we're
7301 			 * probably running a last-import-capable svccfg for
7302 			 * the first time, and we should only take the
7303 			 * last-import snapshot.
7304 			 */
7305 			if (have_ge) {
7306 				pgroup_t *mfpg;
7307 				scf_callback_t mfcbdata;
7308 
7309 				li_only = 1;
7310 				no_refresh = 1;
7311 				/*
7312 				 * Need to go ahead and import the manifestfiles
7313 				 * pg if it exists. If the last-import snapshot
7314 				 * upgrade code is ever removed this code can
7315 				 * be removed as well.
7316 				 */
7317 				mfpg = internal_pgroup_find(s,
7318 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7319 
7320 				if (mfpg) {
7321 					mfcbdata.sc_handle = g_hndl;
7322 					mfcbdata.sc_parent = imp_svc;
7323 					mfcbdata.sc_service = 1;
7324 					mfcbdata.sc_flags = SCI_FORCE;
7325 					mfcbdata.sc_source_fmri = s->sc_fmri;
7326 					mfcbdata.sc_target_fmri = s->sc_fmri;
7327 					if (entity_pgroup_import(mfpg,
7328 					    &mfcbdata) != UU_WALK_NEXT) {
7329 						warn(s_mfile_upd, s->sc_fmri);
7330 						r = UU_WALK_ERROR;
7331 						goto deltemp;
7332 					}
7333 				}
7334 				break;
7335 			}
7336 
7337 			s->sc_import_state = IMPORT_PROP_BEGUN;
7338 
7339 			cbdata.sc_handle = g_hndl;
7340 			cbdata.sc_parent = imp_svc;
7341 			cbdata.sc_service = 1;
7342 			cbdata.sc_flags = SCI_FORCE;
7343 			cbdata.sc_source_fmri = s->sc_fmri;
7344 			cbdata.sc_target_fmri = s->sc_fmri;
7345 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7346 			    &cbdata, UU_DEFAULT) != 0) {
7347 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7348 					bad_error("uu_list_walk", uu_error());
7349 				lcbdata->sc_err = cbdata.sc_err;
7350 				switch (cbdata.sc_err) {
7351 				case ECONNABORTED:
7352 					goto connaborted;
7353 
7354 				case ECANCELED:
7355 					warn(s_deleted, s->sc_fmri);
7356 					lcbdata->sc_err = EBUSY;
7357 					break;
7358 
7359 				case EINVAL:	/* caught above */
7360 				case EEXIST:
7361 					bad_error("entity_pgroup_import",
7362 					    cbdata.sc_err);
7363 				}
7364 
7365 				r = UU_WALK_ERROR;
7366 				goto deltemp;
7367 			}
7368 
7369 			cbdata.sc_trans = NULL;
7370 			cbdata.sc_flags = 0;
7371 			if (uu_list_walk(s->sc_dependents,
7372 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7373 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7374 					bad_error("uu_list_walk", uu_error());
7375 				lcbdata->sc_err = cbdata.sc_err;
7376 				if (cbdata.sc_err == ECONNABORTED)
7377 					goto connaborted;
7378 				r = UU_WALK_ERROR;
7379 				goto deltemp;
7380 			}
7381 			break;
7382 		}
7383 
7384 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7385 		    imp_snap) != 0) {
7386 			switch (scf_error()) {
7387 			case SCF_ERROR_DELETED:
7388 				continue;
7389 
7390 			case SCF_ERROR_NOT_FOUND:
7391 				break;
7392 
7393 			case SCF_ERROR_CONNECTION_BROKEN:
7394 				goto connaborted;
7395 
7396 			case SCF_ERROR_HANDLE_MISMATCH:
7397 			case SCF_ERROR_NOT_BOUND:
7398 			case SCF_ERROR_INVALID_ARGUMENT:
7399 			case SCF_ERROR_NOT_SET:
7400 			default:
7401 				bad_error("scf_instance_get_snapshot",
7402 				    scf_error());
7403 			}
7404 
7405 			if (have_ge)
7406 				continue;
7407 
7408 			/*
7409 			 * Check for a general/enabled property.  This is how
7410 			 * we tell whether to import if there turn out to be
7411 			 * no last-import snapshots.
7412 			 */
7413 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7414 			    imp_pg) == 0) {
7415 				if (scf_pg_get_property(imp_pg,
7416 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7417 					have_ge = 1;
7418 				} else {
7419 					switch (scf_error()) {
7420 					case SCF_ERROR_DELETED:
7421 					case SCF_ERROR_NOT_FOUND:
7422 						continue;
7423 
7424 					case SCF_ERROR_INVALID_ARGUMENT:
7425 					case SCF_ERROR_HANDLE_MISMATCH:
7426 					case SCF_ERROR_CONNECTION_BROKEN:
7427 					case SCF_ERROR_NOT_BOUND:
7428 					case SCF_ERROR_NOT_SET:
7429 					default:
7430 						bad_error("scf_pg_get_property",
7431 						    scf_error());
7432 					}
7433 				}
7434 			} else {
7435 				switch (scf_error()) {
7436 				case SCF_ERROR_DELETED:
7437 				case SCF_ERROR_NOT_FOUND:
7438 					continue;
7439 
7440 				case SCF_ERROR_CONNECTION_BROKEN:
7441 					goto connaborted;
7442 
7443 				case SCF_ERROR_NOT_BOUND:
7444 				case SCF_ERROR_NOT_SET:
7445 				case SCF_ERROR_INVALID_ARGUMENT:
7446 				case SCF_ERROR_HANDLE_MISMATCH:
7447 				default:
7448 					bad_error("scf_instance_get_pg",
7449 					    scf_error());
7450 				}
7451 			}
7452 			continue;
7453 		}
7454 
7455 		/* find service snaplevel */
7456 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7457 		switch (r) {
7458 		case 0:
7459 			break;
7460 
7461 		case ECONNABORTED:
7462 			goto connaborted;
7463 
7464 		case ECANCELED:
7465 			continue;
7466 
7467 		case ENOENT:
7468 			if (scf_instance_get_name(imp_inst, imp_str,
7469 			    imp_str_sz) < 0)
7470 				(void) strcpy(imp_str, "?");
7471 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7472 			lcbdata->sc_err = EBADF;
7473 			r = UU_WALK_ERROR;
7474 			goto deltemp;
7475 
7476 		default:
7477 			bad_error("get_snaplevel", r);
7478 		}
7479 
7480 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7481 		    imp_rsnap) != 0) {
7482 			switch (scf_error()) {
7483 			case SCF_ERROR_DELETED:
7484 				continue;
7485 
7486 			case SCF_ERROR_NOT_FOUND:
7487 				break;
7488 
7489 			case SCF_ERROR_CONNECTION_BROKEN:
7490 				goto connaborted;
7491 
7492 			case SCF_ERROR_INVALID_ARGUMENT:
7493 			case SCF_ERROR_HANDLE_MISMATCH:
7494 			case SCF_ERROR_NOT_BOUND:
7495 			case SCF_ERROR_NOT_SET:
7496 			default:
7497 				bad_error("scf_instance_get_snapshot",
7498 				    scf_error());
7499 			}
7500 			running = NULL;
7501 		} else {
7502 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7503 			switch (r) {
7504 			case 0:
7505 				running = imp_rsnpl;
7506 				break;
7507 
7508 			case ECONNABORTED:
7509 				goto connaborted;
7510 
7511 			case ECANCELED:
7512 				continue;
7513 
7514 			case ENOENT:
7515 				if (scf_instance_get_name(imp_inst, imp_str,
7516 				    imp_str_sz) < 0)
7517 					(void) strcpy(imp_str, "?");
7518 				warn(badsnap, snap_running, s->sc_name,
7519 				    imp_str);
7520 				lcbdata->sc_err = EBADF;
7521 				r = UU_WALK_ERROR;
7522 				goto deltemp;
7523 
7524 			default:
7525 				bad_error("get_snaplevel", r);
7526 			}
7527 		}
7528 
7529 		if (g_verbose) {
7530 			if (scf_instance_get_name(imp_inst, imp_str,
7531 			    imp_str_sz) < 0)
7532 				(void) strcpy(imp_str, "?");
7533 			warn(gettext("Upgrading properties of %s according to "
7534 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7535 		}
7536 
7537 		/* upgrade service properties */
7538 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7539 		if (r == 0)
7540 			break;
7541 
7542 		switch (r) {
7543 		case ECONNABORTED:
7544 			goto connaborted;
7545 
7546 		case ECANCELED:
7547 			warn(s_deleted, s->sc_fmri);
7548 			lcbdata->sc_err = EBUSY;
7549 			break;
7550 
7551 		case ENODEV:
7552 			if (scf_instance_get_name(imp_inst, imp_str,
7553 			    imp_str_sz) < 0)
7554 				(void) strcpy(imp_str, "?");
7555 			warn(i_deleted, s->sc_fmri, imp_str);
7556 			lcbdata->sc_err = EBUSY;
7557 			break;
7558 
7559 		default:
7560 			lcbdata->sc_err = r;
7561 		}
7562 
7563 		r = UU_WALK_ERROR;
7564 		goto deltemp;
7565 	}
7566 
7567 	s->sc_import_state = IMPORT_PROP_DONE;
7568 
7569 instances:
7570 	/* import instances */
7571 	cbdata.sc_handle = lcbdata->sc_handle;
7572 	cbdata.sc_parent = imp_svc;
7573 	cbdata.sc_service = 1;
7574 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7575 	cbdata.sc_general = NULL;
7576 
7577 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7578 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7579 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7580 			bad_error("uu_list_walk", uu_error());
7581 
7582 		lcbdata->sc_err = cbdata.sc_err;
7583 		if (cbdata.sc_err == ECONNABORTED)
7584 			goto connaborted;
7585 		r = UU_WALK_ERROR;
7586 		goto deltemp;
7587 	}
7588 
7589 	s->sc_import_state = IMPORT_COMPLETE;
7590 	r = UU_WALK_NEXT;
7591 
7592 deltemp:
7593 	/* delete temporary service */
7594 	if (scf_service_delete(imp_tsvc) != 0) {
7595 		switch (scf_error()) {
7596 		case SCF_ERROR_DELETED:
7597 			break;
7598 
7599 		case SCF_ERROR_CONNECTION_BROKEN:
7600 			goto connaborted;
7601 
7602 		case SCF_ERROR_EXISTS:
7603 			warn(gettext(
7604 			    "Could not delete svc:/%s (instances exist).\n"),
7605 			    imp_tsname);
7606 			break;
7607 
7608 		case SCF_ERROR_NOT_SET:
7609 		case SCF_ERROR_NOT_BOUND:
7610 		default:
7611 			bad_error("scf_service_delete", scf_error());
7612 		}
7613 	}
7614 
7615 	return (r);
7616 
7617 connaborted:
7618 	warn(gettext("Could not delete svc:/%s "
7619 	    "(repository connection broken).\n"), imp_tsname);
7620 	lcbdata->sc_err = ECONNABORTED;
7621 	return (UU_WALK_ERROR);
7622 }
7623 
7624 static const char *
7625 import_progress(int st)
7626 {
7627 	switch (st) {
7628 	case 0:
7629 		return (gettext("not reached."));
7630 
7631 	case IMPORT_PREVIOUS:
7632 		return (gettext("previous snapshot taken."));
7633 
7634 	case IMPORT_PROP_BEGUN:
7635 		return (gettext("some properties imported."));
7636 
7637 	case IMPORT_PROP_DONE:
7638 		return (gettext("properties imported."));
7639 
7640 	case IMPORT_COMPLETE:
7641 		return (gettext("imported."));
7642 
7643 	case IMPORT_REFRESHED:
7644 		return (gettext("refresh requested."));
7645 
7646 	default:
7647 #ifndef NDEBUG
7648 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7649 		    __FILE__, __LINE__, st);
7650 #endif
7651 		abort();
7652 		/* NOTREACHED */
7653 	}
7654 }
7655 
7656 /*
7657  * Returns
7658  *   0 - success
7659  *     - fmri wasn't found (error printed)
7660  *     - entity was deleted (error printed)
7661  *     - backend denied access (error printed)
7662  *   ENOMEM - out of memory (error printed)
7663  *   ECONNABORTED - repository connection broken (error printed)
7664  *   EPERM - permission denied (error printed)
7665  *   -1 - unknown libscf error (error printed)
7666  */
7667 static int
7668 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7669 {
7670 	scf_error_t serr;
7671 	void *ent;
7672 	int issvc;
7673 	int r;
7674 
7675 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7676 	const char *dpt_deleted = gettext("Could not refresh %s "
7677 	    "(dependent \"%s\" of %s) (deleted).\n");
7678 
7679 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7680 	switch (serr) {
7681 	case SCF_ERROR_NONE:
7682 		break;
7683 
7684 	case SCF_ERROR_NO_MEMORY:
7685 		if (name == NULL)
7686 			warn(gettext("Could not refresh %s (out of memory).\n"),
7687 			    fmri);
7688 		else
7689 			warn(gettext("Could not refresh %s "
7690 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7691 			    fmri, name, d_fmri);
7692 		return (ENOMEM);
7693 
7694 	case SCF_ERROR_NOT_FOUND:
7695 		if (name == NULL)
7696 			warn(deleted, fmri);
7697 		else
7698 			warn(dpt_deleted, fmri, name, d_fmri);
7699 		return (0);
7700 
7701 	case SCF_ERROR_INVALID_ARGUMENT:
7702 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7703 	default:
7704 		bad_error("fmri_to_entity", serr);
7705 	}
7706 
7707 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7708 	switch (r) {
7709 	case 0:
7710 		break;
7711 
7712 	case ECONNABORTED:
7713 		if (name != NULL)
7714 			warn(gettext("Could not refresh %s "
7715 			    "(dependent \"%s\" of %s) "
7716 			    "(repository connection broken).\n"), fmri, name,
7717 			    d_fmri);
7718 		return (r);
7719 
7720 	case ECANCELED:
7721 		if (name == NULL)
7722 			warn(deleted, fmri);
7723 		else
7724 			warn(dpt_deleted, fmri, name, d_fmri);
7725 		return (0);
7726 
7727 	case EACCES:
7728 		if (!g_verbose)
7729 			return (0);
7730 		if (name == NULL)
7731 			warn(gettext("Could not refresh %s "
7732 			    "(backend access denied).\n"), fmri);
7733 		else
7734 			warn(gettext("Could not refresh %s "
7735 			    "(dependent \"%s\" of %s) "
7736 			    "(backend access denied).\n"), fmri, name, d_fmri);
7737 		return (0);
7738 
7739 	case EPERM:
7740 		if (name == NULL)
7741 			warn(gettext("Could not refresh %s "
7742 			    "(permission denied).\n"), fmri);
7743 		else
7744 			warn(gettext("Could not refresh %s "
7745 			    "(dependent \"%s\" of %s) "
7746 			    "(permission denied).\n"), fmri, name, d_fmri);
7747 		return (r);
7748 
7749 	case ENOSPC:
7750 		if (name == NULL)
7751 			warn(gettext("Could not refresh %s "
7752 			    "(repository server out of resources).\n"),
7753 			    fmri);
7754 		else
7755 			warn(gettext("Could not refresh %s "
7756 			    "(dependent \"%s\" of %s) "
7757 			    "(repository server out of resources).\n"),
7758 			    fmri, name, d_fmri);
7759 		return (r);
7760 
7761 	case -1:
7762 		scfwarn();
7763 		return (r);
7764 
7765 	default:
7766 		bad_error("refresh_entity", r);
7767 	}
7768 
7769 	if (issvc)
7770 		scf_service_destroy(ent);
7771 	else
7772 		scf_instance_destroy(ent);
7773 
7774 	return (0);
7775 }
7776 
7777 static int
7778 alloc_imp_globals()
7779 {
7780 	int r;
7781 
7782 	const char * const emsg_nomem = gettext("Out of memory.\n");
7783 	const char * const emsg_nores =
7784 	    gettext("svc.configd is out of resources.\n");
7785 
7786 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7787 	    max_scf_name_len : max_scf_fmri_len) + 1;
7788 
7789 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7790 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
7791 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7792 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7793 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7794 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7795 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7796 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7797 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7798 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7799 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7800 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7801 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7802 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7803 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7804 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7805 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7806 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7807 	    (imp_str = malloc(imp_str_sz)) == NULL ||
7808 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7809 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7810 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7811 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7812 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7813 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7814 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7815 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7816 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7817 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7818 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7819 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7820 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7821 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7822 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7823 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7824 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7825 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7826 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7827 			warn(emsg_nores);
7828 		else
7829 			warn(emsg_nomem);
7830 
7831 		return (-1);
7832 	}
7833 
7834 	r = load_init();
7835 	switch (r) {
7836 	case 0:
7837 		break;
7838 
7839 	case ENOMEM:
7840 		warn(emsg_nomem);
7841 		return (-1);
7842 
7843 	default:
7844 		bad_error("load_init", r);
7845 	}
7846 
7847 	return (0);
7848 }
7849 
7850 static void
7851 free_imp_globals()
7852 {
7853 	pgroup_t *old_dpt;
7854 	void *cookie;
7855 
7856 	load_fini();
7857 
7858 	free(ud_ctarg);
7859 	free(ud_oldtarg);
7860 	free(ud_name);
7861 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7862 
7863 	scf_transaction_destroy(ud_tx);
7864 	ud_tx = NULL;
7865 	scf_iter_destroy(ud_iter);
7866 	scf_iter_destroy(ud_iter2);
7867 	ud_iter = ud_iter2 = NULL;
7868 	scf_value_destroy(ud_val);
7869 	ud_val = NULL;
7870 	scf_property_destroy(ud_prop);
7871 	scf_property_destroy(ud_dpt_prop);
7872 	ud_prop = ud_dpt_prop = NULL;
7873 	scf_pg_destroy(ud_pg);
7874 	scf_pg_destroy(ud_cur_depts_pg);
7875 	scf_pg_destroy(ud_run_dpts_pg);
7876 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7877 	scf_snaplevel_destroy(ud_snpl);
7878 	ud_snpl = NULL;
7879 	scf_instance_destroy(ud_inst);
7880 	ud_inst = NULL;
7881 
7882 	free(imp_str);
7883 	free(imp_tsname);
7884 	free(imp_fe1);
7885 	free(imp_fe2);
7886 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7887 
7888 	cookie = NULL;
7889 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7890 	    NULL) {
7891 		free((char *)old_dpt->sc_pgroup_name);
7892 		free((char *)old_dpt->sc_pgroup_fmri);
7893 		internal_pgroup_free(old_dpt);
7894 	}
7895 	uu_list_destroy(imp_deleted_dpts);
7896 
7897 	scf_transaction_destroy(imp_tx);
7898 	imp_tx = NULL;
7899 	scf_iter_destroy(imp_iter);
7900 	scf_iter_destroy(imp_rpg_iter);
7901 	scf_iter_destroy(imp_up_iter);
7902 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7903 	scf_property_destroy(imp_prop);
7904 	imp_prop = NULL;
7905 	scf_pg_destroy(imp_pg);
7906 	scf_pg_destroy(imp_pg2);
7907 	imp_pg = imp_pg2 = NULL;
7908 	scf_snaplevel_destroy(imp_snpl);
7909 	scf_snaplevel_destroy(imp_rsnpl);
7910 	imp_snpl = imp_rsnpl = NULL;
7911 	scf_snapshot_destroy(imp_snap);
7912 	scf_snapshot_destroy(imp_lisnap);
7913 	scf_snapshot_destroy(imp_tlisnap);
7914 	scf_snapshot_destroy(imp_rsnap);
7915 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7916 	scf_instance_destroy(imp_inst);
7917 	scf_instance_destroy(imp_tinst);
7918 	imp_inst = imp_tinst = NULL;
7919 	scf_service_destroy(imp_svc);
7920 	scf_service_destroy(imp_tsvc);
7921 	imp_svc = imp_tsvc = NULL;
7922 	scf_scope_destroy(imp_scope);
7923 	imp_scope = NULL;
7924 
7925 	load_fini();
7926 }
7927 
7928 int
7929 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7930 {
7931 	scf_callback_t cbdata;
7932 	int result = 0;
7933 	entity_t *svc, *inst;
7934 	uu_list_t *insts;
7935 	int r;
7936 	pgroup_t *old_dpt;
7937 	int annotation_set = 0;
7938 
7939 	const char * const emsg_nomem = gettext("Out of memory.\n");
7940 	const char * const emsg_nores =
7941 	    gettext("svc.configd is out of resources.\n");
7942 
7943 	lscf_prep_hndl();
7944 
7945 	if (alloc_imp_globals())
7946 		goto out;
7947 
7948 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7949 		switch (scf_error()) {
7950 		case SCF_ERROR_CONNECTION_BROKEN:
7951 			warn(gettext("Repository connection broken.\n"));
7952 			repository_teardown();
7953 			result = -1;
7954 			goto out;
7955 
7956 		case SCF_ERROR_NOT_FOUND:
7957 		case SCF_ERROR_INVALID_ARGUMENT:
7958 		case SCF_ERROR_NOT_BOUND:
7959 		case SCF_ERROR_HANDLE_MISMATCH:
7960 		default:
7961 			bad_error("scf_handle_get_scope", scf_error());
7962 		}
7963 	}
7964 
7965 	/* Set up the auditing annotation. */
7966 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7967 		annotation_set = 1;
7968 	} else {
7969 		switch (scf_error()) {
7970 		case SCF_ERROR_CONNECTION_BROKEN:
7971 			warn(gettext("Repository connection broken.\n"));
7972 			repository_teardown();
7973 			result = -1;
7974 			goto out;
7975 
7976 		case SCF_ERROR_INVALID_ARGUMENT:
7977 		case SCF_ERROR_NOT_BOUND:
7978 		case SCF_ERROR_NO_RESOURCES:
7979 		case SCF_ERROR_INTERNAL:
7980 			bad_error("_scf_set_annotation", scf_error());
7981 			/* NOTREACHED */
7982 
7983 		default:
7984 			/*
7985 			 * Do not terminate import because of inability to
7986 			 * generate annotation audit event.
7987 			 */
7988 			warn(gettext("_scf_set_annotation() unexpectedly "
7989 			    "failed with return code of %d\n"), scf_error());
7990 			break;
7991 		}
7992 	}
7993 
7994 	/*
7995 	 * Clear the sc_import_state's of all services & instances so we can
7996 	 * report how far we got if we fail.
7997 	 */
7998 	for (svc = uu_list_first(bndl->sc_bundle_services);
7999 	    svc != NULL;
8000 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8001 		svc->sc_import_state = 0;
8002 
8003 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8004 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8005 		    UU_DEFAULT) != 0)
8006 			bad_error("uu_list_walk", uu_error());
8007 	}
8008 
8009 	cbdata.sc_handle = g_hndl;
8010 	cbdata.sc_parent = imp_scope;
8011 	cbdata.sc_flags = flags;
8012 	cbdata.sc_general = NULL;
8013 
8014 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8015 	    &cbdata, UU_DEFAULT) == 0) {
8016 		/* Success.  Refresh everything. */
8017 
8018 		if (flags & SCI_NOREFRESH || no_refresh) {
8019 			no_refresh = 0;
8020 			result = 0;
8021 			goto out;
8022 		}
8023 
8024 		for (svc = uu_list_first(bndl->sc_bundle_services);
8025 		    svc != NULL;
8026 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8027 			pgroup_t *dpt;
8028 
8029 			insts = svc->sc_u.sc_service.sc_service_instances;
8030 
8031 			for (inst = uu_list_first(insts);
8032 			    inst != NULL;
8033 			    inst = uu_list_next(insts, inst)) {
8034 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8035 				switch (r) {
8036 				case 0:
8037 					break;
8038 
8039 				case ENOMEM:
8040 				case ECONNABORTED:
8041 				case EPERM:
8042 				case -1:
8043 					goto progress;
8044 
8045 				default:
8046 					bad_error("imp_refresh_fmri", r);
8047 				}
8048 
8049 				inst->sc_import_state = IMPORT_REFRESHED;
8050 
8051 				for (dpt = uu_list_first(inst->sc_dependents);
8052 				    dpt != NULL;
8053 				    dpt = uu_list_next(inst->sc_dependents,
8054 				    dpt))
8055 					if (imp_refresh_fmri(
8056 					    dpt->sc_pgroup_fmri,
8057 					    dpt->sc_pgroup_name,
8058 					    inst->sc_fmri) != 0)
8059 						goto progress;
8060 			}
8061 
8062 			for (dpt = uu_list_first(svc->sc_dependents);
8063 			    dpt != NULL;
8064 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8065 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8066 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8067 					goto progress;
8068 		}
8069 
8070 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8071 		    old_dpt != NULL;
8072 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8073 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8074 			    old_dpt->sc_pgroup_name,
8075 			    old_dpt->sc_parent->sc_fmri) != 0)
8076 				goto progress;
8077 
8078 		result = 0;
8079 		goto out;
8080 	}
8081 
8082 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8083 		bad_error("uu_list_walk", uu_error());
8084 
8085 printerr:
8086 	/* If the error hasn't been printed yet, do so here. */
8087 	switch (cbdata.sc_err) {
8088 	case ECONNABORTED:
8089 		warn(gettext("Repository connection broken.\n"));
8090 		break;
8091 
8092 	case ENOMEM:
8093 		warn(emsg_nomem);
8094 		break;
8095 
8096 	case ENOSPC:
8097 		warn(emsg_nores);
8098 		break;
8099 
8100 	case EROFS:
8101 		warn(gettext("Repository is read-only.\n"));
8102 		break;
8103 
8104 	case EACCES:
8105 		warn(gettext("Repository backend denied access.\n"));
8106 		break;
8107 
8108 	case EPERM:
8109 	case EINVAL:
8110 	case EEXIST:
8111 	case EBUSY:
8112 	case EBADF:
8113 	case -1:
8114 		break;
8115 
8116 	default:
8117 		bad_error("lscf_service_import", cbdata.sc_err);
8118 	}
8119 
8120 progress:
8121 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8122 
8123 	for (svc = uu_list_first(bndl->sc_bundle_services);
8124 	    svc != NULL;
8125 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8126 		insts = svc->sc_u.sc_service.sc_service_instances;
8127 
8128 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8129 		    import_progress(svc->sc_import_state));
8130 
8131 		for (inst = uu_list_first(insts);
8132 		    inst != NULL;
8133 		    inst = uu_list_next(insts, inst))
8134 			warn(gettext("    Instance \"%s\": %s\n"),
8135 			    inst->sc_name,
8136 			    import_progress(inst->sc_import_state));
8137 	}
8138 
8139 	if (cbdata.sc_err == ECONNABORTED)
8140 		repository_teardown();
8141 
8142 
8143 	result = -1;
8144 
8145 out:
8146 	if (annotation_set != 0) {
8147 		/* Turn off annotation.  It is no longer needed. */
8148 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8149 	}
8150 
8151 	free_imp_globals();
8152 
8153 	return (result);
8154 }
8155 
8156 /*
8157  * _lscf_import_err() summarize the error handling returned by
8158  * lscf_import_{instance | service}_pgs
8159  * Return values are:
8160  * IMPORT_NEXT
8161  * IMPORT_OUT
8162  * IMPORT_BAD
8163  */
8164 
8165 #define	IMPORT_BAD	-1
8166 #define	IMPORT_NEXT	0
8167 #define	IMPORT_OUT	1
8168 
8169 static int
8170 _lscf_import_err(int err, const char *fmri)
8171 {
8172 	switch (err) {
8173 	case 0:
8174 		if (g_verbose)
8175 			warn(gettext("%s updated.\n"), fmri);
8176 		return (IMPORT_NEXT);
8177 
8178 	case ECONNABORTED:
8179 		warn(gettext("Could not update %s "
8180 		    "(repository connection broken).\n"), fmri);
8181 		return (IMPORT_OUT);
8182 
8183 	case ENOMEM:
8184 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8185 		return (IMPORT_OUT);
8186 
8187 	case ENOSPC:
8188 		warn(gettext("Could not update %s "
8189 		    "(repository server out of resources).\n"), fmri);
8190 		return (IMPORT_OUT);
8191 
8192 	case ECANCELED:
8193 		warn(gettext(
8194 		    "Could not update %s (deleted).\n"), fmri);
8195 		return (IMPORT_NEXT);
8196 
8197 	case EPERM:
8198 	case EINVAL:
8199 	case EBUSY:
8200 		return (IMPORT_NEXT);
8201 
8202 	case EROFS:
8203 		warn(gettext("Could not update %s (repository read-only).\n"),
8204 		    fmri);
8205 		return (IMPORT_OUT);
8206 
8207 	case EACCES:
8208 		warn(gettext("Could not update %s "
8209 		    "(backend access denied).\n"), fmri);
8210 		return (IMPORT_NEXT);
8211 
8212 	case EEXIST:
8213 	default:
8214 		return (IMPORT_BAD);
8215 	}
8216 
8217 	/*NOTREACHED*/
8218 }
8219 
8220 /*
8221  * The global imp_svc and imp_inst should be set by the caller in the
8222  * check to make sure the service and instance exist that the apply is
8223  * working on.
8224  */
8225 static int
8226 lscf_dependent_apply(void *dpg, void *e)
8227 {
8228 	scf_callback_t cb;
8229 	pgroup_t *dpt_pgroup = dpg;
8230 	pgroup_t *deldpt;
8231 	entity_t *ent = e;
8232 	int tissvc;
8233 	void *sc_ent, *tent;
8234 	scf_error_t serr;
8235 	int r;
8236 
8237 	const char * const dependents = "dependents";
8238 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8239 
8240 	if (issvc)
8241 		sc_ent = imp_svc;
8242 	else
8243 		sc_ent = imp_inst;
8244 
8245 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8246 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8247 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8248 	    imp_prop) != 0) {
8249 		switch (scf_error()) {
8250 		case SCF_ERROR_NOT_FOUND:
8251 		case SCF_ERROR_DELETED:
8252 			break;
8253 
8254 		case SCF_ERROR_CONNECTION_BROKEN:
8255 		case SCF_ERROR_NOT_SET:
8256 		case SCF_ERROR_INVALID_ARGUMENT:
8257 		case SCF_ERROR_HANDLE_MISMATCH:
8258 		case SCF_ERROR_NOT_BOUND:
8259 		default:
8260 			bad_error("entity_get_pg", scf_error());
8261 		}
8262 	} else {
8263 		/*
8264 		 * Found the dependents/<wip dep> so check to
8265 		 * see if the service is different.  If so
8266 		 * store the service for later refresh, and
8267 		 * delete the wip dependency from the service
8268 		 */
8269 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8270 			switch (scf_error()) {
8271 				case SCF_ERROR_DELETED:
8272 					break;
8273 
8274 				case SCF_ERROR_CONNECTION_BROKEN:
8275 				case SCF_ERROR_NOT_SET:
8276 				case SCF_ERROR_INVALID_ARGUMENT:
8277 				case SCF_ERROR_HANDLE_MISMATCH:
8278 				case SCF_ERROR_NOT_BOUND:
8279 				default:
8280 					bad_error("scf_property_get_value",
8281 					    scf_error());
8282 			}
8283 		}
8284 
8285 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8286 		    max_scf_value_len + 1) < 0)
8287 			bad_error("scf_value_get_as_string", scf_error());
8288 
8289 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8290 		switch (r) {
8291 		case 1:
8292 			break;
8293 		case 0:
8294 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8295 			    &tissvc)) != SCF_ERROR_NONE) {
8296 				if (serr == SCF_ERROR_NOT_FOUND) {
8297 					break;
8298 				} else {
8299 					bad_error("fmri_to_entity", serr);
8300 				}
8301 			}
8302 
8303 			if (entity_get_pg(tent, tissvc,
8304 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8305 				serr = scf_error();
8306 				if (serr == SCF_ERROR_NOT_FOUND ||
8307 				    serr == SCF_ERROR_DELETED) {
8308 					break;
8309 				} else {
8310 					bad_error("entity_get_pg", scf_error());
8311 				}
8312 			}
8313 
8314 			if (scf_pg_delete(imp_pg) != 0) {
8315 				serr = scf_error();
8316 				if (serr == SCF_ERROR_NOT_FOUND ||
8317 				    serr == SCF_ERROR_DELETED) {
8318 					break;
8319 				} else {
8320 					bad_error("scf_pg_delete", scf_error());
8321 				}
8322 			}
8323 
8324 			deldpt = internal_pgroup_new();
8325 			if (deldpt == NULL)
8326 				return (ENOMEM);
8327 			deldpt->sc_pgroup_name =
8328 			    strdup(dpt_pgroup->sc_pgroup_name);
8329 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8330 			if (deldpt->sc_pgroup_name == NULL ||
8331 			    deldpt->sc_pgroup_fmri == NULL)
8332 				return (ENOMEM);
8333 			deldpt->sc_parent = (entity_t *)ent;
8334 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8335 			    deldpt) != 0)
8336 				uu_die(gettext("libuutil error: %s\n"),
8337 				    uu_strerror(uu_error()));
8338 
8339 			break;
8340 		default:
8341 			bad_error("fmri_equal", r);
8342 		}
8343 	}
8344 
8345 	cb.sc_handle = g_hndl;
8346 	cb.sc_parent = ent;
8347 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8348 	cb.sc_source_fmri = ent->sc_fmri;
8349 	cb.sc_target_fmri = ent->sc_fmri;
8350 	cb.sc_trans = NULL;
8351 	cb.sc_flags = SCI_FORCE;
8352 
8353 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8354 		return (UU_WALK_ERROR);
8355 
8356 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8357 	switch (r) {
8358 	case 0:
8359 		break;
8360 
8361 	case ENOMEM:
8362 	case ECONNABORTED:
8363 	case EPERM:
8364 	case -1:
8365 		warn(gettext("Unable to refresh \"%s\"\n"),
8366 		    dpt_pgroup->sc_pgroup_fmri);
8367 		return (UU_WALK_ERROR);
8368 
8369 	default:
8370 		bad_error("imp_refresh_fmri", r);
8371 	}
8372 
8373 	return (UU_WALK_NEXT);
8374 }
8375 
8376 /*
8377  * Returns
8378  *   0 - success
8379  *   -1 - lscf_import_instance_pgs() failed.
8380  */
8381 int
8382 lscf_bundle_apply(bundle_t *bndl, const char *file)
8383 {
8384 	pgroup_t *old_dpt;
8385 	entity_t *svc, *inst;
8386 	int annotation_set = 0;
8387 	int ret = 0;
8388 	int r = 0;
8389 
8390 	lscf_prep_hndl();
8391 
8392 	if ((ret = alloc_imp_globals()))
8393 		goto out;
8394 
8395 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8396 		scfdie();
8397 
8398 	/*
8399 	 * Set the strings to be used for the security audit annotation
8400 	 * event.
8401 	 */
8402 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8403 		annotation_set = 1;
8404 	} else {
8405 		switch (scf_error()) {
8406 		case SCF_ERROR_CONNECTION_BROKEN:
8407 			warn(gettext("Repository connection broken.\n"));
8408 			goto out;
8409 
8410 		case SCF_ERROR_INVALID_ARGUMENT:
8411 		case SCF_ERROR_NOT_BOUND:
8412 		case SCF_ERROR_NO_RESOURCES:
8413 		case SCF_ERROR_INTERNAL:
8414 			bad_error("_scf_set_annotation", scf_error());
8415 			/* NOTREACHED */
8416 
8417 		default:
8418 			/*
8419 			 * Do not abort apply operation because of
8420 			 * inability to create annotation audit event.
8421 			 */
8422 			warn(gettext("_scf_set_annotation() unexpectedly "
8423 			    "failed with return code of %d\n"), scf_error());
8424 			break;
8425 		}
8426 	}
8427 
8428 	for (svc = uu_list_first(bndl->sc_bundle_services);
8429 	    svc != NULL;
8430 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8431 		int refresh = 0;
8432 
8433 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8434 		    imp_svc) != 0) {
8435 			switch (scf_error()) {
8436 			case SCF_ERROR_NOT_FOUND:
8437 				if (g_verbose)
8438 					warn(gettext("Ignoring nonexistent "
8439 					    "service %s.\n"), svc->sc_name);
8440 				continue;
8441 
8442 			default:
8443 				scfdie();
8444 			}
8445 		}
8446 
8447 		/*
8448 		 * If there were missing types in the profile, then need to
8449 		 * attempt to find the types.
8450 		 */
8451 		if (svc->sc_miss_type) {
8452 			if (uu_list_numnodes(svc->sc_pgroups) &&
8453 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8454 			    svc, UU_DEFAULT) != 0) {
8455 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8456 					bad_error("uu_list_walk", uu_error());
8457 
8458 				ret = -1;
8459 				continue;
8460 			}
8461 
8462 			for (inst = uu_list_first(
8463 			    svc->sc_u.sc_service.sc_service_instances);
8464 			    inst != NULL;
8465 			    inst = uu_list_next(
8466 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8467 				/*
8468 				 * If the instance doesn't exist just
8469 				 * skip to the next instance and let the
8470 				 * import note the missing instance.
8471 				 */
8472 				if (scf_service_get_instance(imp_svc,
8473 				    inst->sc_name, imp_inst) != 0)
8474 					continue;
8475 
8476 				if (uu_list_walk(inst->sc_pgroups,
8477 				    find_current_pg_type, inst,
8478 				    UU_DEFAULT) != 0) {
8479 					if (uu_error() !=
8480 					    UU_ERROR_CALLBACK_FAILED)
8481 						bad_error("uu_list_walk",
8482 						    uu_error());
8483 
8484 					ret = -1;
8485 					inst->sc_miss_type = B_TRUE;
8486 				}
8487 			}
8488 		}
8489 
8490 		/*
8491 		 * if we have pgs in the profile, we need to refresh ALL
8492 		 * instances of the service
8493 		 */
8494 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8495 			refresh = 1;
8496 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8497 			    SCI_FORCE | SCI_KEEP);
8498 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8499 			case IMPORT_NEXT:
8500 				break;
8501 
8502 			case IMPORT_OUT:
8503 				goto out;
8504 
8505 			case IMPORT_BAD:
8506 			default:
8507 				bad_error("lscf_import_service_pgs", r);
8508 			}
8509 		}
8510 
8511 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8512 			uu_list_walk(svc->sc_dependents,
8513 			    lscf_dependent_apply, svc, UU_DEFAULT);
8514 		}
8515 
8516 		for (inst = uu_list_first(
8517 		    svc->sc_u.sc_service.sc_service_instances);
8518 		    inst != NULL;
8519 		    inst = uu_list_next(
8520 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8521 			/*
8522 			 * This instance still has missing types
8523 			 * so skip it.
8524 			 */
8525 			if (inst->sc_miss_type) {
8526 				if (g_verbose)
8527 					warn(gettext("Ignoring instance "
8528 					    "%s:%s with missing types\n"),
8529 					    inst->sc_parent->sc_name,
8530 					    inst->sc_name);
8531 
8532 				continue;
8533 			}
8534 
8535 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8536 			    imp_inst) != 0) {
8537 				switch (scf_error()) {
8538 				case SCF_ERROR_NOT_FOUND:
8539 					if (g_verbose)
8540 						warn(gettext("Ignoring "
8541 						    "nonexistant instance "
8542 						    "%s:%s.\n"),
8543 						    inst->sc_parent->sc_name,
8544 						    inst->sc_name);
8545 					continue;
8546 
8547 				default:
8548 					scfdie();
8549 				}
8550 			}
8551 
8552 			/*
8553 			 * If the instance does not have a general/enabled
8554 			 * property and no last-import snapshot then the
8555 			 * instance is not a fully installed instance and
8556 			 * should not have a profile applied to it.
8557 			 *
8558 			 * This could happen if a service/instance declares
8559 			 * a dependent on behalf of another service/instance.
8560 			 *
8561 			 */
8562 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8563 			    imp_snap) != 0) {
8564 				if (scf_instance_get_pg(imp_inst,
8565 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8566 				    scf_pg_get_property(imp_pg,
8567 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8568 					if (g_verbose)
8569 						warn(gettext("Ignoreing "
8570 						    "partial instance "
8571 						    "%s:%s.\n"),
8572 						    inst->sc_parent->sc_name,
8573 						    inst->sc_name);
8574 					continue;
8575 				}
8576 			}
8577 
8578 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8579 			    inst, SCI_FORCE | SCI_KEEP);
8580 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8581 			case IMPORT_NEXT:
8582 				break;
8583 
8584 			case IMPORT_OUT:
8585 				goto out;
8586 
8587 			case IMPORT_BAD:
8588 			default:
8589 				bad_error("lscf_import_instance_pgs", r);
8590 			}
8591 
8592 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8593 				uu_list_walk(inst->sc_dependents,
8594 				    lscf_dependent_apply, inst, UU_DEFAULT);
8595 			}
8596 
8597 			/* refresh only if there is no pgs in the service */
8598 			if (refresh == 0)
8599 				(void) refresh_entity(0, imp_inst,
8600 				    inst->sc_fmri, NULL, NULL, NULL);
8601 		}
8602 
8603 		if (refresh == 1) {
8604 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8605 
8606 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8607 			    imp_inst, imp_iter, name_buf);
8608 			free(name_buf);
8609 		}
8610 
8611 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8612 		    old_dpt != NULL;
8613 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8614 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8615 			    old_dpt->sc_pgroup_name,
8616 			    old_dpt->sc_parent->sc_fmri) != 0) {
8617 				warn(gettext("Unable to refresh \"%s\"\n"),
8618 				    old_dpt->sc_pgroup_fmri);
8619 			}
8620 		}
8621 	}
8622 
8623 out:
8624 	if (annotation_set) {
8625 		/* Remove security audit annotation strings. */
8626 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8627 	}
8628 
8629 	free_imp_globals();
8630 	return (ret);
8631 }
8632 
8633 
8634 /*
8635  * Export.  These functions create and output an XML tree of a service
8636  * description from the repository.  This is largely the inverse of
8637  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8638  *
8639  * - We must include any properties which are not represented specifically by
8640  *   a service manifest, e.g., properties created by an admin post-import.  To
8641  *   do so we'll iterate through all properties and deal with each
8642  *   apropriately.
8643  *
8644  * - Children of services and instances must must be in the order set by the
8645  *   DTD, but we iterate over the properties in undefined order.  The elements
8646  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8647  *   number of classes of them, however, we'll keep the classes separate and
8648  *   assemble them in order.
8649  */
8650 
8651 /*
8652  * Convenience function to handle xmlSetProp errors (and type casting).
8653  */
8654 static void
8655 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8656 {
8657 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8658 		uu_die(gettext("Could not set XML property.\n"));
8659 }
8660 
8661 /*
8662  * Convenience function to set an XML attribute to the single value of an
8663  * astring property.  If the value happens to be the default, don't set the
8664  * attribute.  "dval" should be the default value supplied by the DTD, or
8665  * NULL for no default.
8666  */
8667 static int
8668 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8669     const char *name, const char *dval)
8670 {
8671 	scf_value_t *val;
8672 	ssize_t len;
8673 	char *str;
8674 
8675 	val = scf_value_create(g_hndl);
8676 	if (val == NULL)
8677 		scfdie();
8678 
8679 	if (prop_get_val(prop, val) != 0) {
8680 		scf_value_destroy(val);
8681 		return (-1);
8682 	}
8683 
8684 	len = scf_value_get_as_string(val, NULL, 0);
8685 	if (len < 0)
8686 		scfdie();
8687 
8688 	str = safe_malloc(len + 1);
8689 
8690 	if (scf_value_get_as_string(val, str, len + 1) < 0)
8691 		scfdie();
8692 
8693 	scf_value_destroy(val);
8694 
8695 	if (dval == NULL || strcmp(str, dval) != 0)
8696 		safe_setprop(n, name, str);
8697 
8698 	free(str);
8699 
8700 	return (0);
8701 }
8702 
8703 /*
8704  * As above, but the attribute is always set.
8705  */
8706 static int
8707 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
8708 {
8709 	return (set_attr_from_prop_default(prop, n, name, NULL));
8710 }
8711 
8712 /*
8713  * Dump the given document onto f, with "'s replaced by ''s.
8714  */
8715 static int
8716 write_service_bundle(xmlDocPtr doc, FILE *f)
8717 {
8718 	xmlChar *mem;
8719 	int sz, i;
8720 
8721 	mem = NULL;
8722 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
8723 
8724 	if (mem == NULL) {
8725 		semerr(gettext("Could not dump XML tree.\n"));
8726 		return (-1);
8727 	}
8728 
8729 	/*
8730 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
8731 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
8732 	 * &apos; code?!
8733 	 */
8734 	for (i = 0; i < sz; ++i) {
8735 		char c = (char)mem[i];
8736 
8737 		if (c == '"')
8738 			(void) fputc('\'', f);
8739 		else if (c == '\'')
8740 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
8741 		else
8742 			(void) fputc(c, f);
8743 	}
8744 
8745 	return (0);
8746 }
8747 
8748 /*
8749  * Create the DOM elements in elts necessary to (generically) represent prop
8750  * (i.e., a property or propval element).  If the name of the property is
8751  * known, it should be passed as name_arg.  Otherwise, pass NULL.
8752  */
8753 static void
8754 export_property(scf_property_t *prop, const char *name_arg,
8755     struct pg_elts *elts, int flags)
8756 {
8757 	const char *type;
8758 	scf_error_t err = 0;
8759 	xmlNodePtr pnode, lnode;
8760 	char *lnname;
8761 	int ret;
8762 
8763 	/* name */
8764 	if (name_arg != NULL) {
8765 		(void) strcpy(exp_str, name_arg);
8766 	} else {
8767 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8768 			scfdie();
8769 	}
8770 
8771 	/* type */
8772 	type = prop_to_typestr(prop);
8773 	if (type == NULL)
8774 		uu_die(gettext("Can't export property %s: unknown type.\n"),
8775 		    exp_str);
8776 
8777 	/* If we're exporting values, and there's just one, export it here. */
8778 	if (!(flags & SCE_ALL_VALUES))
8779 		goto empty;
8780 
8781 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8782 		xmlNodePtr n;
8783 
8784 		/* Single value, so use propval */
8785 		n = xmlNewNode(NULL, (xmlChar *)"propval");
8786 		if (n == NULL)
8787 			uu_die(emsg_create_xml);
8788 
8789 		safe_setprop(n, name_attr, exp_str);
8790 		safe_setprop(n, type_attr, type);
8791 
8792 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8793 			scfdie();
8794 		safe_setprop(n, value_attr, exp_str);
8795 
8796 		if (elts->propvals == NULL)
8797 			elts->propvals = n;
8798 		else
8799 			(void) xmlAddSibling(elts->propvals, n);
8800 
8801 		return;
8802 	}
8803 
8804 	err = scf_error();
8805 
8806 	if (err == SCF_ERROR_PERMISSION_DENIED) {
8807 		semerr(emsg_permission_denied);
8808 		return;
8809 	}
8810 
8811 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8812 	    err != SCF_ERROR_NOT_FOUND &&
8813 	    err != SCF_ERROR_PERMISSION_DENIED)
8814 		scfdie();
8815 
8816 empty:
8817 	/* Multiple (or no) values, so use property */
8818 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
8819 	if (pnode == NULL)
8820 		uu_die(emsg_create_xml);
8821 
8822 	safe_setprop(pnode, name_attr, exp_str);
8823 	safe_setprop(pnode, type_attr, type);
8824 
8825 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8826 		lnname = uu_msprintf("%s_list", type);
8827 		if (lnname == NULL)
8828 			uu_die(gettext("Could not create string"));
8829 
8830 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8831 		if (lnode == NULL)
8832 			uu_die(emsg_create_xml);
8833 
8834 		uu_free(lnname);
8835 
8836 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8837 			scfdie();
8838 
8839 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8840 		    1) {
8841 			xmlNodePtr vn;
8842 
8843 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8844 			    NULL);
8845 			if (vn == NULL)
8846 				uu_die(emsg_create_xml);
8847 
8848 			if (scf_value_get_as_string(exp_val, exp_str,
8849 			    exp_str_sz) < 0)
8850 				scfdie();
8851 			safe_setprop(vn, value_attr, exp_str);
8852 		}
8853 		if (ret != 0)
8854 			scfdie();
8855 	}
8856 
8857 	if (elts->properties == NULL)
8858 		elts->properties = pnode;
8859 	else
8860 		(void) xmlAddSibling(elts->properties, pnode);
8861 }
8862 
8863 /*
8864  * Add a property_group element for this property group to elts.
8865  */
8866 static void
8867 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8868 {
8869 	xmlNodePtr n;
8870 	struct pg_elts elts;
8871 	int ret;
8872 	boolean_t read_protected;
8873 
8874 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
8875 
8876 	/* name */
8877 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8878 		scfdie();
8879 	safe_setprop(n, name_attr, exp_str);
8880 
8881 	/* type */
8882 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8883 		scfdie();
8884 	safe_setprop(n, type_attr, exp_str);
8885 
8886 	/* properties */
8887 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8888 		scfdie();
8889 
8890 	(void) memset(&elts, 0, sizeof (elts));
8891 
8892 	/*
8893 	 * If this property group is not read protected, we always want to
8894 	 * output all the values.  Otherwise, we only output the values if the
8895 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8896 	 */
8897 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8898 		scfdie();
8899 
8900 	if (!read_protected)
8901 		flags |= SCE_ALL_VALUES;
8902 
8903 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8904 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8905 			scfdie();
8906 
8907 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8908 			xmlNodePtr m;
8909 
8910 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8911 			if (m == NULL)
8912 				uu_die(emsg_create_xml);
8913 
8914 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8915 				elts.stability = m;
8916 				continue;
8917 			}
8918 
8919 			xmlFreeNode(m);
8920 		}
8921 
8922 		export_property(exp_prop, NULL, &elts, flags);
8923 	}
8924 	if (ret == -1)
8925 		scfdie();
8926 
8927 	(void) xmlAddChild(n, elts.stability);
8928 	(void) xmlAddChildList(n, elts.propvals);
8929 	(void) xmlAddChildList(n, elts.properties);
8930 
8931 	if (eelts->property_groups == NULL)
8932 		eelts->property_groups = n;
8933 	else
8934 		(void) xmlAddSibling(eelts->property_groups, n);
8935 }
8936 
8937 /*
8938  * Create an XML node representing the dependency described by the given
8939  * property group and put it in eelts.  Unless the dependency is not valid, in
8940  * which case create a generic property_group element which represents it and
8941  * put it in eelts.
8942  */
8943 static void
8944 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8945 {
8946 	xmlNodePtr n;
8947 	int err = 0, ret;
8948 	struct pg_elts elts;
8949 
8950 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
8951 	if (n == NULL)
8952 		uu_die(emsg_create_xml);
8953 
8954 	/*
8955 	 * If the external flag is present, skip this dependency because it
8956 	 * should have been created by another manifest.
8957 	 */
8958 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
8959 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8960 		    prop_get_val(exp_prop, exp_val) == 0) {
8961 			uint8_t b;
8962 
8963 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
8964 				scfdie();
8965 
8966 			if (b)
8967 				return;
8968 		}
8969 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
8970 		scfdie();
8971 
8972 	/* Get the required attributes. */
8973 
8974 	/* name */
8975 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8976 		scfdie();
8977 	safe_setprop(n, name_attr, exp_str);
8978 
8979 	/* grouping */
8980 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8981 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8982 		err = 1;
8983 
8984 	/* restart_on */
8985 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8986 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8987 		err = 1;
8988 
8989 	/* type */
8990 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8991 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8992 		err = 1;
8993 
8994 	/*
8995 	 * entities: Not required, but if we create no children, it will be
8996 	 * created as empty on import, so fail if it's missing.
8997 	 */
8998 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8999 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9000 		scf_iter_t *eiter;
9001 		int ret2;
9002 
9003 		eiter = scf_iter_create(g_hndl);
9004 		if (eiter == NULL)
9005 			scfdie();
9006 
9007 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9008 			scfdie();
9009 
9010 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9011 			xmlNodePtr ch;
9012 
9013 			if (scf_value_get_astring(exp_val, exp_str,
9014 			    exp_str_sz) < 0)
9015 				scfdie();
9016 
9017 			/*
9018 			 * service_fmri's must be first, so we can add them
9019 			 * here.
9020 			 */
9021 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9022 			    NULL);
9023 			if (ch == NULL)
9024 				uu_die(emsg_create_xml);
9025 
9026 			safe_setprop(ch, value_attr, exp_str);
9027 		}
9028 		if (ret2 == -1)
9029 			scfdie();
9030 
9031 		scf_iter_destroy(eiter);
9032 	} else
9033 		err = 1;
9034 
9035 	if (err) {
9036 		xmlFreeNode(n);
9037 
9038 		export_pg(pg, eelts, 0);
9039 
9040 		return;
9041 	}
9042 
9043 	/* Iterate through the properties & handle each. */
9044 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9045 		scfdie();
9046 
9047 	(void) memset(&elts, 0, sizeof (elts));
9048 
9049 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9050 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9051 			scfdie();
9052 
9053 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9054 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9055 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9056 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9057 			continue;
9058 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9059 			xmlNodePtr m;
9060 
9061 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9062 			if (m == NULL)
9063 				uu_die(emsg_create_xml);
9064 
9065 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9066 				elts.stability = m;
9067 				continue;
9068 			}
9069 
9070 			xmlFreeNode(m);
9071 		}
9072 
9073 		export_property(exp_prop, exp_str, &elts, 0);
9074 	}
9075 	if (ret == -1)
9076 		scfdie();
9077 
9078 	(void) xmlAddChild(n, elts.stability);
9079 	(void) xmlAddChildList(n, elts.propvals);
9080 	(void) xmlAddChildList(n, elts.properties);
9081 
9082 	if (eelts->dependencies == NULL)
9083 		eelts->dependencies = n;
9084 	else
9085 		(void) xmlAddSibling(eelts->dependencies, n);
9086 }
9087 
9088 static xmlNodePtr
9089 export_method_environment(scf_propertygroup_t *pg)
9090 {
9091 	xmlNodePtr env;
9092 	int ret;
9093 	int children = 0;
9094 
9095 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9096 		return (NULL);
9097 
9098 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9099 	if (env == NULL)
9100 		uu_die(emsg_create_xml);
9101 
9102 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9103 		scfdie();
9104 
9105 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9106 		scfdie();
9107 
9108 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9109 		xmlNodePtr ev;
9110 		char *cp;
9111 
9112 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9113 			scfdie();
9114 
9115 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9116 			warn(gettext("Invalid environment variable \"%s\".\n"),
9117 			    exp_str);
9118 			continue;
9119 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9120 			warn(gettext("Invalid environment variable \"%s\"; "
9121 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9122 			continue;
9123 		}
9124 
9125 		*cp = '\0';
9126 		cp++;
9127 
9128 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9129 		if (ev == NULL)
9130 			uu_die(emsg_create_xml);
9131 
9132 		safe_setprop(ev, name_attr, exp_str);
9133 		safe_setprop(ev, value_attr, cp);
9134 		children++;
9135 	}
9136 
9137 	if (ret != 0)
9138 		scfdie();
9139 
9140 	if (children == 0) {
9141 		xmlFreeNode(env);
9142 		return (NULL);
9143 	}
9144 
9145 	return (env);
9146 }
9147 
9148 /*
9149  * As above, but for a method property group.
9150  */
9151 static void
9152 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9153 {
9154 	xmlNodePtr n, env;
9155 	char *str;
9156 	int err = 0, nonenv, ret;
9157 	uint8_t use_profile;
9158 	struct pg_elts elts;
9159 	xmlNodePtr ctxt = NULL;
9160 
9161 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9162 
9163 	/* Get the required attributes. */
9164 
9165 	/* name */
9166 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9167 		scfdie();
9168 	safe_setprop(n, name_attr, exp_str);
9169 
9170 	/* type */
9171 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9172 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9173 		err = 1;
9174 
9175 	/* exec */
9176 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9177 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9178 		err = 1;
9179 
9180 	/* timeout */
9181 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9182 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9183 	    prop_get_val(exp_prop, exp_val) == 0) {
9184 		uint64_t c;
9185 
9186 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9187 			scfdie();
9188 
9189 		str = uu_msprintf("%llu", c);
9190 		if (str == NULL)
9191 			uu_die(gettext("Could not create string"));
9192 
9193 		safe_setprop(n, "timeout_seconds", str);
9194 		free(str);
9195 	} else
9196 		err = 1;
9197 
9198 	if (err) {
9199 		xmlFreeNode(n);
9200 
9201 		export_pg(pg, eelts, 0);
9202 
9203 		return;
9204 	}
9205 
9206 
9207 	/*
9208 	 * If we're going to have a method_context child, we need to know
9209 	 * before we iterate through the properties.  Since method_context's
9210 	 * are optional, we don't want to complain about any properties
9211 	 * missing if none of them are there.  Thus we can't use the
9212 	 * convenience functions.
9213 	 */
9214 	nonenv =
9215 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9216 	    SCF_SUCCESS ||
9217 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9218 	    SCF_SUCCESS ||
9219 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9220 	    SCF_SUCCESS ||
9221 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9222 	    SCF_SUCCESS;
9223 
9224 	if (nonenv) {
9225 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9226 		if (ctxt == NULL)
9227 			uu_die(emsg_create_xml);
9228 
9229 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9230 		    0 &&
9231 		    set_attr_from_prop_default(exp_prop, ctxt,
9232 		    "working_directory", ":default") != 0)
9233 			err = 1;
9234 
9235 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9236 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9237 		    ":default") != 0)
9238 			err = 1;
9239 
9240 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9241 		    0 &&
9242 		    set_attr_from_prop_default(exp_prop, ctxt,
9243 		    "resource_pool", ":default") != 0)
9244 			err = 1;
9245 		/*
9246 		 * We only want to complain about profile or credential
9247 		 * properties if we will use them.  To determine that we must
9248 		 * examine USE_PROFILE.
9249 		 */
9250 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9251 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9252 		    prop_get_val(exp_prop, exp_val) == 0) {
9253 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9254 			    SCF_SUCCESS) {
9255 				scfdie();
9256 			}
9257 
9258 			if (use_profile) {
9259 				xmlNodePtr prof;
9260 
9261 				prof = xmlNewChild(ctxt, NULL,
9262 				    (xmlChar *)"method_profile", NULL);
9263 				if (prof == NULL)
9264 					uu_die(emsg_create_xml);
9265 
9266 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9267 				    exp_prop) != 0 ||
9268 				    set_attr_from_prop(exp_prop, prof,
9269 				    name_attr) != 0)
9270 					err = 1;
9271 			} else {
9272 				xmlNodePtr cred;
9273 
9274 				cred = xmlNewChild(ctxt, NULL,
9275 				    (xmlChar *)"method_credential", NULL);
9276 				if (cred == NULL)
9277 					uu_die(emsg_create_xml);
9278 
9279 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9280 				    exp_prop) != 0 ||
9281 				    set_attr_from_prop(exp_prop, cred,
9282 				    "user") != 0) {
9283 					err = 1;
9284 				}
9285 
9286 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9287 				    exp_prop) == 0 &&
9288 				    set_attr_from_prop_default(exp_prop, cred,
9289 				    "group", ":default") != 0)
9290 					err = 1;
9291 
9292 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9293 				    exp_prop) == 0 &&
9294 				    set_attr_from_prop_default(exp_prop, cred,
9295 				    "supp_groups", ":default") != 0)
9296 					err = 1;
9297 
9298 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9299 				    exp_prop) == 0 &&
9300 				    set_attr_from_prop_default(exp_prop, cred,
9301 				    "privileges", ":default") != 0)
9302 					err = 1;
9303 
9304 				if (pg_get_prop(pg,
9305 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9306 				    exp_prop) == 0 &&
9307 				    set_attr_from_prop_default(exp_prop, cred,
9308 				    "limit_privileges", ":default") != 0)
9309 					err = 1;
9310 			}
9311 		}
9312 	}
9313 
9314 	if ((env = export_method_environment(pg)) != NULL) {
9315 		if (ctxt == NULL) {
9316 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9317 			if (ctxt == NULL)
9318 				uu_die(emsg_create_xml);
9319 		}
9320 		(void) xmlAddChild(ctxt, env);
9321 	}
9322 
9323 	if (env != NULL || (nonenv && err == 0))
9324 		(void) xmlAddChild(n, ctxt);
9325 	else
9326 		xmlFreeNode(ctxt);
9327 
9328 	nonenv = (err == 0);
9329 
9330 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9331 		scfdie();
9332 
9333 	(void) memset(&elts, 0, sizeof (elts));
9334 
9335 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9336 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9337 			scfdie();
9338 
9339 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9340 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9341 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9342 			continue;
9343 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9344 			xmlNodePtr m;
9345 
9346 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9347 			if (m == NULL)
9348 				uu_die(emsg_create_xml);
9349 
9350 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9351 				elts.stability = m;
9352 				continue;
9353 			}
9354 
9355 			xmlFreeNode(m);
9356 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9357 		    0 ||
9358 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9359 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9360 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9361 			if (nonenv)
9362 				continue;
9363 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9364 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9365 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9366 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9367 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9368 			if (nonenv && !use_profile)
9369 				continue;
9370 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9371 			if (nonenv && use_profile)
9372 				continue;
9373 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9374 			if (env != NULL)
9375 				continue;
9376 		}
9377 
9378 		export_property(exp_prop, exp_str, &elts, 0);
9379 	}
9380 	if (ret == -1)
9381 		scfdie();
9382 
9383 	(void) xmlAddChild(n, elts.stability);
9384 	(void) xmlAddChildList(n, elts.propvals);
9385 	(void) xmlAddChildList(n, elts.properties);
9386 
9387 	if (eelts->exec_methods == NULL)
9388 		eelts->exec_methods = n;
9389 	else
9390 		(void) xmlAddSibling(eelts->exec_methods, n);
9391 }
9392 
9393 static void
9394 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9395     struct entity_elts *eelts)
9396 {
9397 	xmlNodePtr pgnode;
9398 
9399 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9400 	if (pgnode == NULL)
9401 		uu_die(emsg_create_xml);
9402 
9403 	safe_setprop(pgnode, name_attr, name);
9404 	safe_setprop(pgnode, type_attr, type);
9405 
9406 	(void) xmlAddChildList(pgnode, elts->propvals);
9407 	(void) xmlAddChildList(pgnode, elts->properties);
9408 
9409 	if (eelts->property_groups == NULL)
9410 		eelts->property_groups = pgnode;
9411 	else
9412 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9413 }
9414 
9415 /*
9416  * Process the general property group for a service.  This is the one with the
9417  * goodies.
9418  */
9419 static void
9420 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9421 {
9422 	struct pg_elts elts;
9423 	int ret;
9424 
9425 	/*
9426 	 * In case there are properties which don't correspond to child
9427 	 * entities of the service entity, we'll set up a pg_elts structure to
9428 	 * put them in.
9429 	 */
9430 	(void) memset(&elts, 0, sizeof (elts));
9431 
9432 	/* Walk the properties, looking for special ones. */
9433 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9434 		scfdie();
9435 
9436 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9437 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9438 			scfdie();
9439 
9440 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9441 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9442 			    prop_get_val(exp_prop, exp_val) == 0) {
9443 				uint8_t b;
9444 
9445 				if (scf_value_get_boolean(exp_val, &b) !=
9446 				    SCF_SUCCESS)
9447 					scfdie();
9448 
9449 				if (b) {
9450 					selts->single_instance =
9451 					    xmlNewNode(NULL,
9452 					    (xmlChar *)"single_instance");
9453 					if (selts->single_instance == NULL)
9454 						uu_die(emsg_create_xml);
9455 				}
9456 
9457 				continue;
9458 			}
9459 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9460 			xmlNodePtr rnode, sfnode;
9461 
9462 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9463 			if (rnode == NULL)
9464 				uu_die(emsg_create_xml);
9465 
9466 			sfnode = xmlNewChild(rnode, NULL,
9467 			    (xmlChar *)"service_fmri", NULL);
9468 			if (sfnode == NULL)
9469 				uu_die(emsg_create_xml);
9470 
9471 			if (set_attr_from_prop(exp_prop, sfnode,
9472 			    value_attr) == 0) {
9473 				selts->restarter = rnode;
9474 				continue;
9475 			}
9476 
9477 			xmlFreeNode(rnode);
9478 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9479 		    0) {
9480 			xmlNodePtr s;
9481 
9482 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9483 			if (s == NULL)
9484 				uu_die(emsg_create_xml);
9485 
9486 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9487 				selts->stability = s;
9488 				continue;
9489 			}
9490 
9491 			xmlFreeNode(s);
9492 		}
9493 
9494 		export_property(exp_prop, exp_str, &elts, 0);
9495 	}
9496 	if (ret == -1)
9497 		scfdie();
9498 
9499 	if (elts.propvals != NULL || elts.properties != NULL)
9500 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9501 		    selts);
9502 }
9503 
9504 static void
9505 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9506 {
9507 	xmlNodePtr n, prof, cred, env;
9508 	uint8_t use_profile;
9509 	int ret, err = 0;
9510 
9511 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9512 
9513 	env = export_method_environment(pg);
9514 
9515 	/* Need to know whether we'll use a profile or not. */
9516 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9517 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9518 	    prop_get_val(exp_prop, exp_val) == 0) {
9519 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9520 			scfdie();
9521 
9522 		if (use_profile)
9523 			prof =
9524 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9525 			    NULL);
9526 		else
9527 			cred =
9528 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9529 			    NULL);
9530 	}
9531 
9532 	if (env != NULL)
9533 		(void) xmlAddChild(n, env);
9534 
9535 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9536 		scfdie();
9537 
9538 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9539 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9540 			scfdie();
9541 
9542 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9543 			if (set_attr_from_prop(exp_prop, n,
9544 			    "working_directory") != 0)
9545 				err = 1;
9546 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9547 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9548 				err = 1;
9549 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9550 			if (set_attr_from_prop(exp_prop, n,
9551 			    "resource_pool") != 0)
9552 				err = 1;
9553 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9554 			/* EMPTY */
9555 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9556 			if (use_profile ||
9557 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9558 				err = 1;
9559 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9560 			if (use_profile ||
9561 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9562 				err = 1;
9563 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9564 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9565 			    "supp_groups") != 0)
9566 				err = 1;
9567 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9568 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9569 			    "privileges") != 0)
9570 				err = 1;
9571 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9572 		    0) {
9573 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9574 			    "limit_privileges") != 0)
9575 				err = 1;
9576 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9577 			if (!use_profile || set_attr_from_prop(exp_prop,
9578 			    prof, name_attr) != 0)
9579 				err = 1;
9580 		} else {
9581 			/* Can't have generic properties in method_context's */
9582 			err = 1;
9583 		}
9584 	}
9585 	if (ret == -1)
9586 		scfdie();
9587 
9588 	if (err && env == NULL) {
9589 		xmlFreeNode(n);
9590 		export_pg(pg, elts, 0);
9591 		return;
9592 	}
9593 
9594 	elts->method_context = n;
9595 }
9596 
9597 /*
9598  * Given a dependency property group in the tfmri entity (target fmri), return
9599  * a dependent element which represents it.
9600  */
9601 static xmlNodePtr
9602 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9603 {
9604 	uint8_t b;
9605 	xmlNodePtr n, sf;
9606 	int err = 0, ret;
9607 	struct pg_elts pgelts;
9608 
9609 	/*
9610 	 * If external isn't set to true then exporting the service will
9611 	 * export this as a normal dependency, so we should stop to avoid
9612 	 * duplication.
9613 	 */
9614 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9615 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9616 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9617 		if (g_verbose) {
9618 			warn(gettext("Dependent \"%s\" cannot be exported "
9619 			    "properly because the \"%s\" property of the "
9620 			    "\"%s\" dependency of %s is not set to true.\n"),
9621 			    name, scf_property_external, name, tfmri);
9622 		}
9623 
9624 		return (NULL);
9625 	}
9626 
9627 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9628 	if (n == NULL)
9629 		uu_die(emsg_create_xml);
9630 
9631 	safe_setprop(n, name_attr, name);
9632 
9633 	/* Get the required attributes */
9634 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9635 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9636 		err = 1;
9637 
9638 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9639 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9640 		err = 1;
9641 
9642 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9643 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9644 	    prop_get_val(exp_prop, exp_val) == 0) {
9645 		/* EMPTY */
9646 	} else
9647 		err = 1;
9648 
9649 	if (err) {
9650 		xmlFreeNode(n);
9651 		return (NULL);
9652 	}
9653 
9654 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9655 	if (sf == NULL)
9656 		uu_die(emsg_create_xml);
9657 
9658 	safe_setprop(sf, value_attr, tfmri);
9659 
9660 	/*
9661 	 * Now add elements for the other properties.
9662 	 */
9663 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9664 		scfdie();
9665 
9666 	(void) memset(&pgelts, 0, sizeof (pgelts));
9667 
9668 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9669 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9670 			scfdie();
9671 
9672 		if (strcmp(exp_str, scf_property_external) == 0 ||
9673 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9674 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9675 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9676 			continue;
9677 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9678 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9679 			    prop_get_val(exp_prop, exp_val) == 0) {
9680 				char type[sizeof ("service") + 1];
9681 
9682 				if (scf_value_get_astring(exp_val, type,
9683 				    sizeof (type)) < 0)
9684 					scfdie();
9685 
9686 				if (strcmp(type, "service") == 0)
9687 					continue;
9688 			}
9689 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9690 			xmlNodePtr s;
9691 
9692 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9693 			if (s == NULL)
9694 				uu_die(emsg_create_xml);
9695 
9696 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9697 				pgelts.stability = s;
9698 				continue;
9699 			}
9700 
9701 			xmlFreeNode(s);
9702 		}
9703 
9704 		export_property(exp_prop, exp_str, &pgelts, 0);
9705 	}
9706 	if (ret == -1)
9707 		scfdie();
9708 
9709 	(void) xmlAddChild(n, pgelts.stability);
9710 	(void) xmlAddChildList(n, pgelts.propvals);
9711 	(void) xmlAddChildList(n, pgelts.properties);
9712 
9713 	return (n);
9714 }
9715 
9716 static void
9717 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
9718 {
9719 	scf_propertygroup_t *opg;
9720 	scf_iter_t *iter;
9721 	char *type, *fmri;
9722 	int ret;
9723 	struct pg_elts pgelts;
9724 	xmlNodePtr n;
9725 	scf_error_t serr;
9726 
9727 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
9728 	    (iter = scf_iter_create(g_hndl)) == NULL)
9729 		scfdie();
9730 
9731 	/* Can't use exp_prop_iter due to export_dependent(). */
9732 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
9733 		scfdie();
9734 
9735 	type = safe_malloc(max_scf_pg_type_len + 1);
9736 
9737 	/* Get an extra byte so we can tell if values are too long. */
9738 	fmri = safe_malloc(max_scf_fmri_len + 2);
9739 
9740 	(void) memset(&pgelts, 0, sizeof (pgelts));
9741 
9742 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
9743 		void *entity;
9744 		int isservice;
9745 		scf_type_t ty;
9746 
9747 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
9748 			scfdie();
9749 
9750 		if ((ty != SCF_TYPE_ASTRING &&
9751 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
9752 		    prop_get_val(exp_prop, exp_val) != 0) {
9753 			export_property(exp_prop, NULL, &pgelts, 0);
9754 			continue;
9755 		}
9756 
9757 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9758 			scfdie();
9759 
9760 		if (scf_value_get_astring(exp_val, fmri,
9761 		    max_scf_fmri_len + 2) < 0)
9762 			scfdie();
9763 
9764 		/* Look for a dependency group in the target fmri. */
9765 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9766 		switch (serr) {
9767 		case SCF_ERROR_NONE:
9768 			break;
9769 
9770 		case SCF_ERROR_NO_MEMORY:
9771 			uu_die(gettext("Out of memory.\n"));
9772 			/* NOTREACHED */
9773 
9774 		case SCF_ERROR_INVALID_ARGUMENT:
9775 			if (g_verbose) {
9776 				if (scf_property_to_fmri(exp_prop, fmri,
9777 				    max_scf_fmri_len + 2) < 0)
9778 					scfdie();
9779 
9780 				warn(gettext("The value of %s is not a valid "
9781 				    "FMRI.\n"), fmri);
9782 			}
9783 
9784 			export_property(exp_prop, exp_str, &pgelts, 0);
9785 			continue;
9786 
9787 		case SCF_ERROR_CONSTRAINT_VIOLATED:
9788 			if (g_verbose) {
9789 				if (scf_property_to_fmri(exp_prop, fmri,
9790 				    max_scf_fmri_len + 2) < 0)
9791 					scfdie();
9792 
9793 				warn(gettext("The value of %s does not specify "
9794 				    "a service or an instance.\n"), fmri);
9795 			}
9796 
9797 			export_property(exp_prop, exp_str, &pgelts, 0);
9798 			continue;
9799 
9800 		case SCF_ERROR_NOT_FOUND:
9801 			if (g_verbose) {
9802 				if (scf_property_to_fmri(exp_prop, fmri,
9803 				    max_scf_fmri_len + 2) < 0)
9804 					scfdie();
9805 
9806 				warn(gettext("The entity specified by %s does "
9807 				    "not exist.\n"), fmri);
9808 			}
9809 
9810 			export_property(exp_prop, exp_str, &pgelts, 0);
9811 			continue;
9812 
9813 		default:
9814 #ifndef NDEBUG
9815 			(void) fprintf(stderr, "%s:%d: %s() failed with "
9816 			    "unexpected error %d.\n", __FILE__, __LINE__,
9817 			    "fmri_to_entity", serr);
9818 #endif
9819 			abort();
9820 		}
9821 
9822 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9823 			if (scf_error() != SCF_ERROR_NOT_FOUND)
9824 				scfdie();
9825 
9826 			warn(gettext("Entity %s is missing dependency property "
9827 			    "group %s.\n"), fmri, exp_str);
9828 
9829 			export_property(exp_prop, NULL, &pgelts, 0);
9830 			continue;
9831 		}
9832 
9833 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9834 			scfdie();
9835 
9836 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9837 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9838 				scfdie();
9839 
9840 			warn(gettext("Property group %s is not of "
9841 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9842 
9843 			export_property(exp_prop, NULL, &pgelts, 0);
9844 			continue;
9845 		}
9846 
9847 		n = export_dependent(opg, exp_str, fmri);
9848 		if (n == NULL)
9849 			export_property(exp_prop, exp_str, &pgelts, 0);
9850 		else {
9851 			if (eelts->dependents == NULL)
9852 				eelts->dependents = n;
9853 			else
9854 				(void) xmlAddSibling(eelts->dependents,
9855 				    n);
9856 		}
9857 	}
9858 	if (ret == -1)
9859 		scfdie();
9860 
9861 	free(fmri);
9862 	free(type);
9863 
9864 	scf_iter_destroy(iter);
9865 	scf_pg_destroy(opg);
9866 
9867 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9868 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9869 		    eelts);
9870 }
9871 
9872 static void
9873 make_node(xmlNodePtr *nodep, const char *name)
9874 {
9875 	if (*nodep == NULL) {
9876 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
9877 		if (*nodep == NULL)
9878 			uu_die(emsg_create_xml);
9879 	}
9880 }
9881 
9882 static xmlNodePtr
9883 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9884 {
9885 	int ret;
9886 	xmlNodePtr parent = NULL;
9887 	xmlNodePtr loctext = NULL;
9888 
9889 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9890 		scfdie();
9891 
9892 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9893 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9894 		    prop_get_val(exp_prop, exp_val) != 0)
9895 			continue;
9896 
9897 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9898 			scfdie();
9899 
9900 		make_node(&parent, parname);
9901 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9902 		    (xmlChar *)exp_str);
9903 		if (loctext == NULL)
9904 			uu_die(emsg_create_xml);
9905 
9906 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9907 			scfdie();
9908 
9909 		safe_setprop(loctext, "xml:lang", exp_str);
9910 	}
9911 
9912 	if (ret == -1)
9913 		scfdie();
9914 
9915 	return (parent);
9916 }
9917 
9918 static xmlNodePtr
9919 export_tm_manpage(scf_propertygroup_t *pg)
9920 {
9921 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9922 	if (manpage == NULL)
9923 		uu_die(emsg_create_xml);
9924 
9925 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9926 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9927 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9928 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9929 		xmlFreeNode(manpage);
9930 		return (NULL);
9931 	}
9932 
9933 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9934 		(void) set_attr_from_prop_default(exp_prop,
9935 		    manpage, "manpath", ":default");
9936 
9937 	return (manpage);
9938 }
9939 
9940 static xmlNodePtr
9941 export_tm_doc_link(scf_propertygroup_t *pg)
9942 {
9943 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9944 	if (doc_link == NULL)
9945 		uu_die(emsg_create_xml);
9946 
9947 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9948 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9949 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9950 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9951 		xmlFreeNode(doc_link);
9952 		return (NULL);
9953 	}
9954 	return (doc_link);
9955 }
9956 
9957 /*
9958  * Process template information for a service or instances.
9959  */
9960 static void
9961 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
9962     struct template_elts *telts)
9963 {
9964 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
9965 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
9966 	xmlNodePtr child = NULL;
9967 
9968 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
9969 		scfdie();
9970 
9971 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
9972 		telts->common_name = export_tm_loctext(pg, "common_name");
9973 		if (telts->common_name == NULL)
9974 			export_pg(pg, elts, 0);
9975 		return;
9976 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
9977 		telts->description = export_tm_loctext(pg, "description");
9978 		if (telts->description == NULL)
9979 			export_pg(pg, elts, 0);
9980 		return;
9981 	}
9982 
9983 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
9984 		child = export_tm_manpage(pg);
9985 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
9986 		child = export_tm_doc_link(pg);
9987 	}
9988 
9989 	if (child != NULL) {
9990 		make_node(&telts->documentation, "documentation");
9991 		(void) xmlAddChild(telts->documentation, child);
9992 	} else {
9993 		export_pg(pg, elts, 0);
9994 	}
9995 }
9996 
9997 /*
9998  * Process the general property group for an instance.
9999  */
10000 static void
10001 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10002     struct entity_elts *elts)
10003 {
10004 	uint8_t enabled;
10005 	struct pg_elts pgelts;
10006 	int ret;
10007 
10008 	/* enabled */
10009 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10010 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10011 	    prop_get_val(exp_prop, exp_val) == 0) {
10012 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10013 			scfdie();
10014 	} else {
10015 		enabled = 0;
10016 	}
10017 
10018 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10019 
10020 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10021 		scfdie();
10022 
10023 	(void) memset(&pgelts, 0, sizeof (pgelts));
10024 
10025 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10026 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10027 			scfdie();
10028 
10029 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10030 			continue;
10031 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10032 			xmlNodePtr rnode, sfnode;
10033 
10034 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10035 			if (rnode == NULL)
10036 				uu_die(emsg_create_xml);
10037 
10038 			sfnode = xmlNewChild(rnode, NULL,
10039 			    (xmlChar *)"service_fmri", NULL);
10040 			if (sfnode == NULL)
10041 				uu_die(emsg_create_xml);
10042 
10043 			if (set_attr_from_prop(exp_prop, sfnode,
10044 			    value_attr) == 0) {
10045 				elts->restarter = rnode;
10046 				continue;
10047 			}
10048 
10049 			xmlFreeNode(rnode);
10050 		}
10051 
10052 		export_property(exp_prop, exp_str, &pgelts, 0);
10053 	}
10054 	if (ret == -1)
10055 		scfdie();
10056 
10057 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10058 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10059 		    elts);
10060 }
10061 
10062 /*
10063  * Put an instance element for the given instance into selts.
10064  */
10065 static void
10066 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10067 {
10068 	xmlNodePtr n;
10069 	boolean_t isdefault;
10070 	struct entity_elts elts;
10071 	struct template_elts template_elts;
10072 	int ret;
10073 
10074 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10075 	if (n == NULL)
10076 		uu_die(emsg_create_xml);
10077 
10078 	/* name */
10079 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10080 		scfdie();
10081 	safe_setprop(n, name_attr, exp_str);
10082 	isdefault = strcmp(exp_str, "default") == 0;
10083 
10084 	/* check existance of general pg (since general/enabled is required) */
10085 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10086 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10087 			scfdie();
10088 
10089 		if (g_verbose) {
10090 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10091 				scfdie();
10092 
10093 			warn(gettext("Instance %s has no general property "
10094 			    "group; it will be marked disabled.\n"), exp_str);
10095 		}
10096 
10097 		safe_setprop(n, enabled_attr, false);
10098 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10099 	    strcmp(exp_str, scf_group_framework) != 0) {
10100 		if (g_verbose) {
10101 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10102 				scfdie();
10103 
10104 			warn(gettext("Property group %s is not of type "
10105 			    "framework; the instance will be marked "
10106 			    "disabled.\n"), exp_str);
10107 		}
10108 
10109 		safe_setprop(n, enabled_attr, false);
10110 	}
10111 
10112 	/* property groups */
10113 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10114 		scfdie();
10115 
10116 	(void) memset(&elts, 0, sizeof (elts));
10117 	(void) memset(&template_elts, 0, sizeof (template_elts));
10118 
10119 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10120 		uint32_t pgflags;
10121 
10122 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10123 			scfdie();
10124 
10125 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10126 			continue;
10127 
10128 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10129 			scfdie();
10130 
10131 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10132 			export_dependency(exp_pg, &elts);
10133 			continue;
10134 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10135 			export_method(exp_pg, &elts);
10136 			continue;
10137 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10138 			if (scf_pg_get_name(exp_pg, exp_str,
10139 			    max_scf_name_len + 1) < 0)
10140 				scfdie();
10141 
10142 			if (strcmp(exp_str, scf_pg_general) == 0) {
10143 				export_inst_general(exp_pg, n, &elts);
10144 				continue;
10145 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10146 			    0) {
10147 				export_method_context(exp_pg, &elts);
10148 				continue;
10149 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10150 				export_dependents(exp_pg, &elts);
10151 				continue;
10152 			}
10153 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10154 			export_template(exp_pg, &elts, &template_elts);
10155 			continue;
10156 		}
10157 
10158 		/* Ordinary pg. */
10159 		export_pg(exp_pg, &elts, flags);
10160 	}
10161 	if (ret == -1)
10162 		scfdie();
10163 
10164 	if (template_elts.common_name != NULL) {
10165 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10166 		(void) xmlAddChild(elts.template, template_elts.common_name);
10167 		(void) xmlAddChild(elts.template, template_elts.description);
10168 		(void) xmlAddChild(elts.template, template_elts.documentation);
10169 	} else {
10170 		xmlFreeNode(template_elts.description);
10171 		xmlFreeNode(template_elts.documentation);
10172 	}
10173 
10174 	if (isdefault && elts.restarter == NULL &&
10175 	    elts.dependencies == NULL && elts.method_context == NULL &&
10176 	    elts.exec_methods == NULL && elts.property_groups == NULL &&
10177 	    elts.template == NULL) {
10178 		xmlChar *eval;
10179 
10180 		/* This is a default instance */
10181 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10182 
10183 		xmlFreeNode(n);
10184 
10185 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10186 		if (n == NULL)
10187 			uu_die(emsg_create_xml);
10188 
10189 		safe_setprop(n, enabled_attr, (char *)eval);
10190 		xmlFree(eval);
10191 
10192 		selts->create_default_instance = n;
10193 	} else {
10194 		/* Assemble the children in order. */
10195 		(void) xmlAddChild(n, elts.restarter);
10196 		(void) xmlAddChildList(n, elts.dependencies);
10197 		(void) xmlAddChildList(n, elts.dependents);
10198 		(void) xmlAddChild(n, elts.method_context);
10199 		(void) xmlAddChildList(n, elts.exec_methods);
10200 		(void) xmlAddChildList(n, elts.property_groups);
10201 		(void) xmlAddChild(n, elts.template);
10202 
10203 		if (selts->instances == NULL)
10204 			selts->instances = n;
10205 		else
10206 			(void) xmlAddSibling(selts->instances, n);
10207 	}
10208 }
10209 
10210 /*
10211  * Return a service element for the given service.
10212  */
10213 static xmlNodePtr
10214 export_service(scf_service_t *svc, int flags)
10215 {
10216 	xmlNodePtr snode;
10217 	struct entity_elts elts;
10218 	struct template_elts template_elts;
10219 	int ret;
10220 
10221 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10222 	if (snode == NULL)
10223 		uu_die(emsg_create_xml);
10224 
10225 	/* Get & set name attribute */
10226 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10227 		scfdie();
10228 	safe_setprop(snode, name_attr, exp_str);
10229 
10230 	safe_setprop(snode, type_attr, "service");
10231 	safe_setprop(snode, "version", "0");
10232 
10233 	/* Acquire child elements. */
10234 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10235 		scfdie();
10236 
10237 	(void) memset(&elts, 0, sizeof (elts));
10238 	(void) memset(&template_elts, 0, sizeof (template_elts));
10239 
10240 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10241 		uint32_t pgflags;
10242 
10243 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10244 			scfdie();
10245 
10246 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10247 			continue;
10248 
10249 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10250 			scfdie();
10251 
10252 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10253 			export_dependency(exp_pg, &elts);
10254 			continue;
10255 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10256 			export_method(exp_pg, &elts);
10257 			continue;
10258 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10259 			if (scf_pg_get_name(exp_pg, exp_str,
10260 			    max_scf_name_len + 1) < 0)
10261 				scfdie();
10262 
10263 			if (strcmp(exp_str, scf_pg_general) == 0) {
10264 				export_svc_general(exp_pg, &elts);
10265 				continue;
10266 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10267 			    0) {
10268 				export_method_context(exp_pg, &elts);
10269 				continue;
10270 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10271 				export_dependents(exp_pg, &elts);
10272 				continue;
10273 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10274 				continue;
10275 			}
10276 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10277 			export_template(exp_pg, &elts, &template_elts);
10278 			continue;
10279 		}
10280 
10281 		export_pg(exp_pg, &elts, flags);
10282 	}
10283 	if (ret == -1)
10284 		scfdie();
10285 
10286 	if (template_elts.common_name != NULL) {
10287 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10288 		(void) xmlAddChild(elts.template, template_elts.common_name);
10289 		(void) xmlAddChild(elts.template, template_elts.description);
10290 		(void) xmlAddChild(elts.template, template_elts.documentation);
10291 	} else {
10292 		xmlFreeNode(template_elts.description);
10293 		xmlFreeNode(template_elts.documentation);
10294 	}
10295 
10296 	/* Iterate instances */
10297 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10298 		scfdie();
10299 
10300 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10301 		export_instance(exp_inst, &elts, flags);
10302 	if (ret == -1)
10303 		scfdie();
10304 
10305 	/* Now add all of the accumulated elements in order. */
10306 	(void) xmlAddChild(snode, elts.create_default_instance);
10307 	(void) xmlAddChild(snode, elts.single_instance);
10308 	(void) xmlAddChild(snode, elts.restarter);
10309 	(void) xmlAddChildList(snode, elts.dependencies);
10310 	(void) xmlAddChildList(snode, elts.dependents);
10311 	(void) xmlAddChild(snode, elts.method_context);
10312 	(void) xmlAddChildList(snode, elts.exec_methods);
10313 	(void) xmlAddChildList(snode, elts.property_groups);
10314 	(void) xmlAddChildList(snode, elts.instances);
10315 	(void) xmlAddChild(snode, elts.stability);
10316 	(void) xmlAddChild(snode, elts.template);
10317 
10318 	return (snode);
10319 }
10320 
10321 static int
10322 export_callback(void *data, scf_walkinfo_t *wip)
10323 {
10324 	FILE *f;
10325 	xmlDocPtr doc;
10326 	xmlNodePtr sb;
10327 	int result;
10328 	struct export_args *argsp = (struct export_args *)data;
10329 
10330 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10331 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10332 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10333 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10334 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10335 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10336 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10337 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10338 		scfdie();
10339 
10340 	exp_str_sz = max_scf_len + 1;
10341 	exp_str = safe_malloc(exp_str_sz);
10342 
10343 	if (argsp->filename != NULL) {
10344 		errno = 0;
10345 		f = fopen(argsp->filename, "wb");
10346 		if (f == NULL) {
10347 			if (errno == 0)
10348 				uu_die(gettext("Could not open \"%s\": no free "
10349 				    "stdio streams.\n"), argsp->filename);
10350 			else
10351 				uu_die(gettext("Could not open \"%s\""),
10352 				    argsp->filename);
10353 		}
10354 	} else
10355 		f = stdout;
10356 
10357 	doc = xmlNewDoc((xmlChar *)"1.0");
10358 	if (doc == NULL)
10359 		uu_die(gettext("Could not create XML document.\n"));
10360 
10361 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10362 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10363 		uu_die(emsg_create_xml);
10364 
10365 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10366 	if (sb == NULL)
10367 		uu_die(emsg_create_xml);
10368 	safe_setprop(sb, type_attr, "manifest");
10369 	safe_setprop(sb, name_attr, "export");
10370 	(void) xmlAddSibling(doc->children, sb);
10371 
10372 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10373 
10374 	result = write_service_bundle(doc, f);
10375 
10376 	free(exp_str);
10377 	scf_iter_destroy(exp_val_iter);
10378 	scf_iter_destroy(exp_prop_iter);
10379 	scf_iter_destroy(exp_pg_iter);
10380 	scf_iter_destroy(exp_inst_iter);
10381 	scf_value_destroy(exp_val);
10382 	scf_property_destroy(exp_prop);
10383 	scf_pg_destroy(exp_pg);
10384 	scf_instance_destroy(exp_inst);
10385 
10386 	xmlFreeDoc(doc);
10387 
10388 	if (f != stdout)
10389 		(void) fclose(f);
10390 
10391 	return (result);
10392 }
10393 
10394 /*
10395  * Get the service named by fmri, build an XML tree which represents it, and
10396  * dump it into filename (or stdout if filename is NULL).
10397  */
10398 int
10399 lscf_service_export(char *fmri, const char *filename, int flags)
10400 {
10401 	struct export_args args;
10402 	int ret, err;
10403 
10404 	lscf_prep_hndl();
10405 
10406 	bzero(&args, sizeof (args));
10407 	args.filename = filename;
10408 	args.flags = flags;
10409 
10410 	err = 0;
10411 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10412 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10413 	    &args, &err, semerr)) != 0) {
10414 		if (ret != -1)
10415 			semerr(gettext("Failed to walk instances: %s\n"),
10416 			    scf_strerror(ret));
10417 		return (-1);
10418 	}
10419 
10420 	/*
10421 	 * Error message has already been printed.
10422 	 */
10423 	if (err != 0)
10424 		return (-1);
10425 
10426 	return (0);
10427 }
10428 
10429 
10430 /*
10431  * Archive
10432  */
10433 
10434 static xmlNodePtr
10435 make_archive(int flags)
10436 {
10437 	xmlNodePtr sb;
10438 	scf_scope_t *scope;
10439 	scf_service_t *svc;
10440 	scf_iter_t *iter;
10441 	int r;
10442 
10443 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10444 	    (svc = scf_service_create(g_hndl)) == NULL ||
10445 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10446 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10447 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10448 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10449 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10450 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10451 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10452 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10453 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10454 		scfdie();
10455 
10456 	exp_str_sz = max_scf_len + 1;
10457 	exp_str = safe_malloc(exp_str_sz);
10458 
10459 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10460 	if (sb == NULL)
10461 		uu_die(emsg_create_xml);
10462 	safe_setprop(sb, type_attr, "archive");
10463 	safe_setprop(sb, name_attr, "none");
10464 
10465 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10466 		scfdie();
10467 	if (scf_iter_scope_services(iter, scope) != 0)
10468 		scfdie();
10469 
10470 	for (;;) {
10471 		r = scf_iter_next_service(iter, svc);
10472 		if (r == 0)
10473 			break;
10474 		if (r != 1)
10475 			scfdie();
10476 
10477 		if (scf_service_get_name(svc, exp_str,
10478 		    max_scf_name_len + 1) < 0)
10479 			scfdie();
10480 
10481 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10482 			continue;
10483 
10484 		(void) xmlAddChild(sb, export_service(svc, flags));
10485 	}
10486 
10487 	free(exp_str);
10488 
10489 	scf_iter_destroy(exp_val_iter);
10490 	scf_iter_destroy(exp_prop_iter);
10491 	scf_iter_destroy(exp_pg_iter);
10492 	scf_iter_destroy(exp_inst_iter);
10493 	scf_value_destroy(exp_val);
10494 	scf_property_destroy(exp_prop);
10495 	scf_pg_destroy(exp_pg);
10496 	scf_instance_destroy(exp_inst);
10497 	scf_iter_destroy(iter);
10498 	scf_service_destroy(svc);
10499 	scf_scope_destroy(scope);
10500 
10501 	return (sb);
10502 }
10503 
10504 int
10505 lscf_archive(const char *filename, int flags)
10506 {
10507 	FILE *f;
10508 	xmlDocPtr doc;
10509 	int result;
10510 
10511 	lscf_prep_hndl();
10512 
10513 	if (filename != NULL) {
10514 		errno = 0;
10515 		f = fopen(filename, "wb");
10516 		if (f == NULL) {
10517 			if (errno == 0)
10518 				uu_die(gettext("Could not open \"%s\": no free "
10519 				    "stdio streams.\n"), filename);
10520 			else
10521 				uu_die(gettext("Could not open \"%s\""),
10522 				    filename);
10523 		}
10524 	} else
10525 		f = stdout;
10526 
10527 	doc = xmlNewDoc((xmlChar *)"1.0");
10528 	if (doc == NULL)
10529 		uu_die(gettext("Could not create XML document.\n"));
10530 
10531 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10532 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10533 		uu_die(emsg_create_xml);
10534 
10535 	(void) xmlAddSibling(doc->children, make_archive(flags));
10536 
10537 	result = write_service_bundle(doc, f);
10538 
10539 	xmlFreeDoc(doc);
10540 
10541 	if (f != stdout)
10542 		(void) fclose(f);
10543 
10544 	return (result);
10545 }
10546 
10547 
10548 /*
10549  * "Extract" a profile.
10550  */
10551 int
10552 lscf_profile_extract(const char *filename)
10553 {
10554 	FILE *f;
10555 	xmlDocPtr doc;
10556 	xmlNodePtr sb, snode, inode;
10557 	scf_scope_t *scope;
10558 	scf_service_t *svc;
10559 	scf_instance_t *inst;
10560 	scf_propertygroup_t *pg;
10561 	scf_property_t *prop;
10562 	scf_value_t *val;
10563 	scf_iter_t *siter, *iiter;
10564 	int r, s;
10565 	char *namebuf;
10566 	uint8_t b;
10567 	int result;
10568 
10569 	lscf_prep_hndl();
10570 
10571 	if (filename != NULL) {
10572 		errno = 0;
10573 		f = fopen(filename, "wb");
10574 		if (f == NULL) {
10575 			if (errno == 0)
10576 				uu_die(gettext("Could not open \"%s\": no "
10577 				    "free stdio streams.\n"), filename);
10578 			else
10579 				uu_die(gettext("Could not open \"%s\""),
10580 				    filename);
10581 		}
10582 	} else
10583 		f = stdout;
10584 
10585 	doc = xmlNewDoc((xmlChar *)"1.0");
10586 	if (doc == NULL)
10587 		uu_die(gettext("Could not create XML document.\n"));
10588 
10589 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10590 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10591 		uu_die(emsg_create_xml);
10592 
10593 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10594 	if (sb == NULL)
10595 		uu_die(emsg_create_xml);
10596 	safe_setprop(sb, type_attr, "profile");
10597 	safe_setprop(sb, name_attr, "extract");
10598 	(void) xmlAddSibling(doc->children, sb);
10599 
10600 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10601 	    (svc = scf_service_create(g_hndl)) == NULL ||
10602 	    (inst = scf_instance_create(g_hndl)) == NULL ||
10603 	    (pg = scf_pg_create(g_hndl)) == NULL ||
10604 	    (prop = scf_property_create(g_hndl)) == NULL ||
10605 	    (val = scf_value_create(g_hndl)) == NULL ||
10606 	    (siter = scf_iter_create(g_hndl)) == NULL ||
10607 	    (iiter = scf_iter_create(g_hndl)) == NULL)
10608 		scfdie();
10609 
10610 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
10611 		scfdie();
10612 
10613 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
10614 		scfdie();
10615 
10616 	namebuf = safe_malloc(max_scf_name_len + 1);
10617 
10618 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
10619 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
10620 			scfdie();
10621 
10622 		snode = xmlNewNode(NULL, (xmlChar *)"service");
10623 		if (snode == NULL)
10624 			uu_die(emsg_create_xml);
10625 
10626 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
10627 		    0)
10628 			scfdie();
10629 
10630 		safe_setprop(snode, name_attr, namebuf);
10631 
10632 		safe_setprop(snode, type_attr, "service");
10633 		safe_setprop(snode, "version", "0");
10634 
10635 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
10636 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
10637 			    SCF_SUCCESS) {
10638 				if (scf_error() != SCF_ERROR_NOT_FOUND)
10639 					scfdie();
10640 
10641 				if (g_verbose) {
10642 					ssize_t len;
10643 					char *fmri;
10644 
10645 					len =
10646 					    scf_instance_to_fmri(inst, NULL, 0);
10647 					if (len < 0)
10648 						scfdie();
10649 
10650 					fmri = safe_malloc(len + 1);
10651 
10652 					if (scf_instance_to_fmri(inst, fmri,
10653 					    len + 1) < 0)
10654 						scfdie();
10655 
10656 					warn("Instance %s has no \"%s\" "
10657 					    "property group.\n", fmri,
10658 					    scf_pg_general);
10659 
10660 					free(fmri);
10661 				}
10662 
10663 				continue;
10664 			}
10665 
10666 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
10667 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
10668 			    prop_get_val(prop, val) != 0)
10669 				continue;
10670 
10671 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
10672 			    NULL);
10673 			if (inode == NULL)
10674 				uu_die(emsg_create_xml);
10675 
10676 			if (scf_instance_get_name(inst, namebuf,
10677 			    max_scf_name_len + 1) < 0)
10678 				scfdie();
10679 
10680 			safe_setprop(inode, name_attr, namebuf);
10681 
10682 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
10683 				scfdie();
10684 
10685 			safe_setprop(inode, enabled_attr, b ? true : false);
10686 		}
10687 		if (s < 0)
10688 			scfdie();
10689 
10690 		if (snode->children != NULL)
10691 			(void) xmlAddChild(sb, snode);
10692 		else
10693 			xmlFreeNode(snode);
10694 	}
10695 	if (r < 0)
10696 		scfdie();
10697 
10698 	free(namebuf);
10699 
10700 	result = write_service_bundle(doc, f);
10701 
10702 	xmlFreeDoc(doc);
10703 
10704 	if (f != stdout)
10705 		(void) fclose(f);
10706 
10707 	return (result);
10708 }
10709 
10710 
10711 /*
10712  * Entity manipulation commands
10713  */
10714 
10715 /*
10716  * Entity selection.  If no entity is selected, then the current scope is in
10717  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
10718  * only cur_inst is NULL, and when an instance is selected, none are NULL.
10719  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
10720  * cur_inst will be non-NULL.
10721  */
10722 
10723 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
10724 static int
10725 select_inst(const char *name)
10726 {
10727 	scf_instance_t *inst;
10728 	scf_error_t err;
10729 
10730 	assert(cur_svc != NULL);
10731 
10732 	inst = scf_instance_create(g_hndl);
10733 	if (inst == NULL)
10734 		scfdie();
10735 
10736 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10737 		cur_inst = inst;
10738 		return (0);
10739 	}
10740 
10741 	err = scf_error();
10742 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10743 		scfdie();
10744 
10745 	scf_instance_destroy(inst);
10746 	return (1);
10747 }
10748 
10749 /* Returns as above. */
10750 static int
10751 select_svc(const char *name)
10752 {
10753 	scf_service_t *svc;
10754 	scf_error_t err;
10755 
10756 	assert(cur_scope != NULL);
10757 
10758 	svc = scf_service_create(g_hndl);
10759 	if (svc == NULL)
10760 		scfdie();
10761 
10762 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10763 		cur_svc = svc;
10764 		return (0);
10765 	}
10766 
10767 	err = scf_error();
10768 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10769 		scfdie();
10770 
10771 	scf_service_destroy(svc);
10772 	return (1);
10773 }
10774 
10775 /* ARGSUSED */
10776 static int
10777 select_callback(void *unused, scf_walkinfo_t *wip)
10778 {
10779 	scf_instance_t *inst;
10780 	scf_service_t *svc;
10781 	scf_scope_t *scope;
10782 
10783 	if (wip->inst != NULL) {
10784 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10785 		    (svc = scf_service_create(g_hndl)) == NULL ||
10786 		    (inst = scf_instance_create(g_hndl)) == NULL)
10787 			scfdie();
10788 
10789 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10790 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10791 			scfdie();
10792 	} else {
10793 		assert(wip->svc != NULL);
10794 
10795 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10796 		    (svc = scf_service_create(g_hndl)) == NULL)
10797 			scfdie();
10798 
10799 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10800 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10801 			scfdie();
10802 
10803 		inst = NULL;
10804 	}
10805 
10806 	/* Clear out the current selection */
10807 	assert(cur_scope != NULL);
10808 	scf_scope_destroy(cur_scope);
10809 	scf_service_destroy(cur_svc);
10810 	scf_instance_destroy(cur_inst);
10811 
10812 	cur_scope = scope;
10813 	cur_svc = svc;
10814 	cur_inst = inst;
10815 
10816 	return (0);
10817 }
10818 
10819 static int
10820 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
10821 {
10822 	char **fmri = fmri_p;
10823 
10824 	*fmri = strdup(wip->fmri);
10825 	if (*fmri == NULL)
10826 		uu_die(gettext("Out of memory.\n"));
10827 
10828 	return (0);
10829 }
10830 
10831 /*
10832  * validate [fmri]
10833  * Perform the validation of an FMRI instance.
10834  */
10835 void
10836 lscf_validate_fmri(const char *fmri)
10837 {
10838 	int ret = 0;
10839 	size_t inst_sz;
10840 	char *inst_fmri = NULL;
10841 	scf_tmpl_errors_t *errs = NULL;
10842 	char *snapbuf = NULL;
10843 
10844 	lscf_prep_hndl();
10845 
10846 	if (fmri == NULL) {
10847 		inst_sz = max_scf_fmri_len + 1;
10848 		inst_fmri = safe_malloc(inst_sz);
10849 
10850 		if (cur_snap != NULL) {
10851 			snapbuf = safe_malloc(max_scf_name_len + 1);
10852 			if (scf_snapshot_get_name(cur_snap, snapbuf,
10853 			    max_scf_name_len + 1) < 0)
10854 				scfdie();
10855 		}
10856 		if (cur_inst == NULL) {
10857 			semerr(gettext("No instance selected\n"));
10858 			goto cleanup;
10859 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
10860 		    inst_sz) >= inst_sz) {
10861 			/* sanity check. Should never get here */
10862 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
10863 			    __FILE__, __LINE__);
10864 		}
10865 	} else {
10866 		scf_error_t scf_err;
10867 		int err = 0;
10868 
10869 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
10870 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
10871 			uu_warn("Failed to walk instances: %s\n",
10872 			    scf_strerror(scf_err));
10873 			goto cleanup;
10874 		}
10875 		if (err != 0) {
10876 			/* error message displayed by scf_walk_fmri */
10877 			goto cleanup;
10878 		}
10879 	}
10880 
10881 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
10882 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
10883 	if (ret == -1) {
10884 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
10885 			warn(gettext("Template data for %s is invalid. "
10886 			    "Consider reverting to a previous snapshot or "
10887 			    "restoring original configuration.\n"), inst_fmri);
10888 		} else {
10889 			uu_warn("%s: %s\n",
10890 			    gettext("Error validating the instance"),
10891 			    scf_strerror(scf_error()));
10892 		}
10893 	} else if (ret == 1 && errs != NULL) {
10894 		scf_tmpl_error_t *err = NULL;
10895 		char *msg;
10896 		size_t len = 256;	/* initial error buffer size */
10897 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
10898 		    SCF_TMPL_STRERROR_HUMAN : 0;
10899 
10900 		msg = safe_malloc(len);
10901 
10902 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
10903 			int ret;
10904 
10905 			if ((ret = scf_tmpl_strerror(err, msg, len,
10906 			    flag)) >= len) {
10907 				len = ret + 1;
10908 				msg = realloc(msg, len);
10909 				if (msg == NULL)
10910 					uu_die(gettext(
10911 					    "Out of memory.\n"));
10912 				(void) scf_tmpl_strerror(err, msg, len,
10913 				    flag);
10914 			}
10915 			(void) fprintf(stderr, "%s\n", msg);
10916 		}
10917 		if (msg != NULL)
10918 			free(msg);
10919 	}
10920 	if (errs != NULL)
10921 		scf_tmpl_errors_destroy(errs);
10922 
10923 cleanup:
10924 	free(inst_fmri);
10925 	free(snapbuf);
10926 }
10927 
10928 static void
10929 lscf_validate_file(const char *filename)
10930 {
10931 	tmpl_errors_t *errs;
10932 
10933 	bundle_t *b = internal_bundle_new();
10934 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
10935 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
10936 			tmpl_errors_print(stderr, errs, "");
10937 			semerr(gettext("Validation failed.\n"));
10938 		}
10939 		tmpl_errors_destroy(errs);
10940 	}
10941 	(void) internal_bundle_free(b);
10942 }
10943 
10944 /*
10945  * validate [fmri|file]
10946  */
10947 void
10948 lscf_validate(const char *arg)
10949 {
10950 	const char *str;
10951 
10952 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
10953 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
10954 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
10955 		lscf_validate_file(str);
10956 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
10957 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
10958 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
10959 		lscf_validate_fmri(str);
10960 	} else if (access(arg, R_OK | F_OK) == 0) {
10961 		lscf_validate_file(arg);
10962 	} else {
10963 		lscf_validate_fmri(arg);
10964 	}
10965 }
10966 
10967 void
10968 lscf_select(const char *fmri)
10969 {
10970 	int ret, err;
10971 
10972 	lscf_prep_hndl();
10973 
10974 	if (cur_snap != NULL) {
10975 		struct snaplevel *elt;
10976 		char *buf;
10977 
10978 		/* Error unless name is that of the next level. */
10979 		elt = uu_list_next(cur_levels, cur_elt);
10980 		if (elt == NULL) {
10981 			semerr(gettext("No children.\n"));
10982 			return;
10983 		}
10984 
10985 		buf = safe_malloc(max_scf_name_len + 1);
10986 
10987 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10988 		    max_scf_name_len + 1) < 0)
10989 			scfdie();
10990 
10991 		if (strcmp(buf, fmri) != 0) {
10992 			semerr(gettext("No such child.\n"));
10993 			free(buf);
10994 			return;
10995 		}
10996 
10997 		free(buf);
10998 
10999 		cur_elt = elt;
11000 		cur_level = elt->sl;
11001 		return;
11002 	}
11003 
11004 	/*
11005 	 * Special case for 'svc:', which takes the user to the scope level.
11006 	 */
11007 	if (strcmp(fmri, "svc:") == 0) {
11008 		scf_instance_destroy(cur_inst);
11009 		scf_service_destroy(cur_svc);
11010 		cur_inst = NULL;
11011 		cur_svc = NULL;
11012 		return;
11013 	}
11014 
11015 	/*
11016 	 * Special case for ':properties'.  This appears as part of 'list' but
11017 	 * can't be selected.  Give a more helpful error message in this case.
11018 	 */
11019 	if (strcmp(fmri, ":properties") == 0) {
11020 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11021 		    "to list properties.\n"));
11022 		return;
11023 	}
11024 
11025 	/*
11026 	 * First try the argument as relative to the current selection.
11027 	 */
11028 	if (cur_inst != NULL) {
11029 		/* EMPTY */;
11030 	} else if (cur_svc != NULL) {
11031 		if (select_inst(fmri) != 1)
11032 			return;
11033 	} else {
11034 		if (select_svc(fmri) != 1)
11035 			return;
11036 	}
11037 
11038 	err = 0;
11039 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11040 	    select_callback, NULL, &err, semerr)) != 0) {
11041 		semerr(gettext("Failed to walk instances: %s\n"),
11042 		    scf_strerror(ret));
11043 	}
11044 }
11045 
11046 void
11047 lscf_unselect(void)
11048 {
11049 	lscf_prep_hndl();
11050 
11051 	if (cur_snap != NULL) {
11052 		struct snaplevel *elt;
11053 
11054 		elt = uu_list_prev(cur_levels, cur_elt);
11055 		if (elt == NULL) {
11056 			semerr(gettext("No parent levels.\n"));
11057 		} else {
11058 			cur_elt = elt;
11059 			cur_level = elt->sl;
11060 		}
11061 	} else if (cur_inst != NULL) {
11062 		scf_instance_destroy(cur_inst);
11063 		cur_inst = NULL;
11064 	} else if (cur_svc != NULL) {
11065 		scf_service_destroy(cur_svc);
11066 		cur_svc = NULL;
11067 	} else {
11068 		semerr(gettext("Cannot unselect at scope level.\n"));
11069 	}
11070 }
11071 
11072 /*
11073  * Return the FMRI of the current selection, for the prompt.
11074  */
11075 void
11076 lscf_get_selection_str(char *buf, size_t bufsz)
11077 {
11078 	char *cp;
11079 	ssize_t fmrilen, szret;
11080 	boolean_t deleted = B_FALSE;
11081 
11082 	if (g_hndl == NULL) {
11083 		(void) strlcpy(buf, "svc:", bufsz);
11084 		return;
11085 	}
11086 
11087 	if (cur_level != NULL) {
11088 		assert(cur_snap != NULL);
11089 
11090 		/* [ snapshot ] FMRI [: instance ] */
11091 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11092 		    + 2 + max_scf_name_len + 1 + 1);
11093 
11094 		buf[0] = '[';
11095 
11096 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11097 		    max_scf_name_len + 1);
11098 		if (szret < 0) {
11099 			if (scf_error() != SCF_ERROR_DELETED)
11100 				scfdie();
11101 
11102 			goto snap_deleted;
11103 		}
11104 
11105 		(void) strcat(buf, "]svc:/");
11106 
11107 		cp = strchr(buf, '\0');
11108 
11109 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11110 		    max_scf_name_len + 1);
11111 		if (szret < 0) {
11112 			if (scf_error() != SCF_ERROR_DELETED)
11113 				scfdie();
11114 
11115 			goto snap_deleted;
11116 		}
11117 
11118 		cp = strchr(cp, '\0');
11119 
11120 		if (snaplevel_is_instance(cur_level)) {
11121 			*cp++ = ':';
11122 
11123 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11124 			    max_scf_name_len + 1) < 0) {
11125 				if (scf_error() != SCF_ERROR_DELETED)
11126 					scfdie();
11127 
11128 				goto snap_deleted;
11129 			}
11130 		} else {
11131 			*cp++ = '[';
11132 			*cp++ = ':';
11133 
11134 			if (scf_instance_get_name(cur_inst, cp,
11135 			    max_scf_name_len + 1) < 0) {
11136 				if (scf_error() != SCF_ERROR_DELETED)
11137 					scfdie();
11138 
11139 				goto snap_deleted;
11140 			}
11141 
11142 			(void) strcat(buf, "]");
11143 		}
11144 
11145 		return;
11146 
11147 snap_deleted:
11148 		deleted = B_TRUE;
11149 		free(buf);
11150 		unselect_cursnap();
11151 	}
11152 
11153 	assert(cur_snap == NULL);
11154 
11155 	if (cur_inst != NULL) {
11156 		assert(cur_svc != NULL);
11157 		assert(cur_scope != NULL);
11158 
11159 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11160 		if (fmrilen >= 0) {
11161 			assert(fmrilen < bufsz);
11162 			if (deleted)
11163 				warn(emsg_deleted);
11164 			return;
11165 		}
11166 
11167 		if (scf_error() != SCF_ERROR_DELETED)
11168 			scfdie();
11169 
11170 		deleted = B_TRUE;
11171 
11172 		scf_instance_destroy(cur_inst);
11173 		cur_inst = NULL;
11174 	}
11175 
11176 	if (cur_svc != NULL) {
11177 		assert(cur_scope != NULL);
11178 
11179 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11180 		if (szret >= 0) {
11181 			assert(szret < bufsz);
11182 			if (deleted)
11183 				warn(emsg_deleted);
11184 			return;
11185 		}
11186 
11187 		if (scf_error() != SCF_ERROR_DELETED)
11188 			scfdie();
11189 
11190 		deleted = B_TRUE;
11191 		scf_service_destroy(cur_svc);
11192 		cur_svc = NULL;
11193 	}
11194 
11195 	assert(cur_scope != NULL);
11196 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11197 
11198 	if (fmrilen < 0)
11199 		scfdie();
11200 
11201 	assert(fmrilen < bufsz);
11202 	if (deleted)
11203 		warn(emsg_deleted);
11204 }
11205 
11206 /*
11207  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11208  * :statistics) are listed for the current selection.
11209  */
11210 void
11211 lscf_list(const char *pattern)
11212 {
11213 	scf_iter_t *iter;
11214 	char *buf;
11215 	int ret;
11216 
11217 	lscf_prep_hndl();
11218 
11219 	if (cur_level != NULL) {
11220 		struct snaplevel *elt;
11221 
11222 		(void) fputs(COLON_NAMESPACES, stdout);
11223 
11224 		elt = uu_list_next(cur_levels, cur_elt);
11225 		if (elt == NULL)
11226 			return;
11227 
11228 		/*
11229 		 * For now, we know that the next level is an instance.  But
11230 		 * if we ever have multiple scopes, this could be complicated.
11231 		 */
11232 		buf = safe_malloc(max_scf_name_len + 1);
11233 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11234 		    max_scf_name_len + 1) >= 0) {
11235 			(void) puts(buf);
11236 		} else {
11237 			if (scf_error() != SCF_ERROR_DELETED)
11238 				scfdie();
11239 		}
11240 
11241 		free(buf);
11242 
11243 		return;
11244 	}
11245 
11246 	if (cur_inst != NULL) {
11247 		(void) fputs(COLON_NAMESPACES, stdout);
11248 		return;
11249 	}
11250 
11251 	iter = scf_iter_create(g_hndl);
11252 	if (iter == NULL)
11253 		scfdie();
11254 
11255 	buf = safe_malloc(max_scf_name_len + 1);
11256 
11257 	if (cur_svc != NULL) {
11258 		/* List the instances in this service. */
11259 		scf_instance_t *inst;
11260 
11261 		inst = scf_instance_create(g_hndl);
11262 		if (inst == NULL)
11263 			scfdie();
11264 
11265 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11266 			safe_printf(COLON_NAMESPACES);
11267 
11268 			for (;;) {
11269 				ret = scf_iter_next_instance(iter, inst);
11270 				if (ret == 0)
11271 					break;
11272 				if (ret != 1) {
11273 					if (scf_error() != SCF_ERROR_DELETED)
11274 						scfdie();
11275 
11276 					break;
11277 				}
11278 
11279 				if (scf_instance_get_name(inst, buf,
11280 				    max_scf_name_len + 1) >= 0) {
11281 					if (pattern == NULL ||
11282 					    fnmatch(pattern, buf, 0) == 0)
11283 						(void) puts(buf);
11284 				} else {
11285 					if (scf_error() != SCF_ERROR_DELETED)
11286 						scfdie();
11287 				}
11288 			}
11289 		} else {
11290 			if (scf_error() != SCF_ERROR_DELETED)
11291 				scfdie();
11292 		}
11293 
11294 		scf_instance_destroy(inst);
11295 	} else {
11296 		/* List the services in this scope. */
11297 		scf_service_t *svc;
11298 
11299 		assert(cur_scope != NULL);
11300 
11301 		svc = scf_service_create(g_hndl);
11302 		if (svc == NULL)
11303 			scfdie();
11304 
11305 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11306 			scfdie();
11307 
11308 		for (;;) {
11309 			ret = scf_iter_next_service(iter, svc);
11310 			if (ret == 0)
11311 				break;
11312 			if (ret != 1)
11313 				scfdie();
11314 
11315 			if (scf_service_get_name(svc, buf,
11316 			    max_scf_name_len + 1) >= 0) {
11317 				if (pattern == NULL ||
11318 				    fnmatch(pattern, buf, 0) == 0)
11319 					safe_printf("%s\n", buf);
11320 			} else {
11321 				if (scf_error() != SCF_ERROR_DELETED)
11322 					scfdie();
11323 			}
11324 		}
11325 
11326 		scf_service_destroy(svc);
11327 	}
11328 
11329 	free(buf);
11330 	scf_iter_destroy(iter);
11331 }
11332 
11333 /*
11334  * Entity addition.  Creates an empty entity in the current selection.
11335  */
11336 void
11337 lscf_add(const char *name)
11338 {
11339 	lscf_prep_hndl();
11340 
11341 	if (cur_snap != NULL) {
11342 		semerr(emsg_cant_modify_snapshots);
11343 	} else if (cur_inst != NULL) {
11344 		semerr(gettext("Cannot add entities to an instance.\n"));
11345 	} else if (cur_svc != NULL) {
11346 
11347 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11348 		    SCF_SUCCESS) {
11349 			switch (scf_error()) {
11350 			case SCF_ERROR_INVALID_ARGUMENT:
11351 				semerr(gettext("Invalid name.\n"));
11352 				break;
11353 
11354 			case SCF_ERROR_EXISTS:
11355 				semerr(gettext("Instance already exists.\n"));
11356 				break;
11357 
11358 			case SCF_ERROR_PERMISSION_DENIED:
11359 				semerr(emsg_permission_denied);
11360 				break;
11361 
11362 			default:
11363 				scfdie();
11364 			}
11365 		}
11366 	} else {
11367 		assert(cur_scope != NULL);
11368 
11369 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11370 		    SCF_SUCCESS) {
11371 			switch (scf_error()) {
11372 			case SCF_ERROR_INVALID_ARGUMENT:
11373 				semerr(gettext("Invalid name.\n"));
11374 				break;
11375 
11376 			case SCF_ERROR_EXISTS:
11377 				semerr(gettext("Service already exists.\n"));
11378 				break;
11379 
11380 			case SCF_ERROR_PERMISSION_DENIED:
11381 				semerr(emsg_permission_denied);
11382 				break;
11383 
11384 			case SCF_ERROR_BACKEND_READONLY:
11385 				semerr(emsg_read_only);
11386 				break;
11387 
11388 			default:
11389 				scfdie();
11390 			}
11391 		}
11392 	}
11393 }
11394 
11395 /* return 1 if the entity has no persistent pgs, else return 0 */
11396 static int
11397 entity_has_no_pgs(void *ent, int isservice)
11398 {
11399 	scf_iter_t *iter = NULL;
11400 	scf_propertygroup_t *pg = NULL;
11401 	uint32_t flags;
11402 	int err;
11403 	int ret = 1;
11404 
11405 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11406 	    (pg = scf_pg_create(g_hndl)) == NULL)
11407 		scfdie();
11408 
11409 	if (isservice) {
11410 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11411 			scfdie();
11412 	} else {
11413 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11414 			scfdie();
11415 	}
11416 
11417 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11418 		if (scf_pg_get_flags(pg, &flags) != 0)
11419 			scfdie();
11420 
11421 		/* skip nonpersistent pgs */
11422 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11423 			continue;
11424 
11425 		ret = 0;
11426 		break;
11427 	}
11428 
11429 	if (err == -1)
11430 		scfdie();
11431 
11432 	scf_pg_destroy(pg);
11433 	scf_iter_destroy(iter);
11434 
11435 	return (ret);
11436 }
11437 
11438 /* return 1 if the service has no instances, else return 0 */
11439 static int
11440 svc_has_no_insts(scf_service_t *svc)
11441 {
11442 	scf_instance_t *inst;
11443 	scf_iter_t *iter;
11444 	int r;
11445 	int ret = 1;
11446 
11447 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11448 	    (iter = scf_iter_create(g_hndl)) == NULL)
11449 		scfdie();
11450 
11451 	if (scf_iter_service_instances(iter, svc) != 0)
11452 		scfdie();
11453 
11454 	r = scf_iter_next_instance(iter, inst);
11455 	if (r == 1) {
11456 		ret = 0;
11457 	} else if (r == 0) {
11458 		ret = 1;
11459 	} else if (r == -1) {
11460 		scfdie();
11461 	} else {
11462 		bad_error("scf_iter_next_instance", r);
11463 	}
11464 
11465 	scf_iter_destroy(iter);
11466 	scf_instance_destroy(inst);
11467 
11468 	return (ret);
11469 }
11470 
11471 /*
11472  * Entity deletion.
11473  */
11474 
11475 /*
11476  * Delete the property group <fmri>/:properties/<name>.  Returns
11477  * SCF_ERROR_NONE on success (or if the entity is not found),
11478  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11479  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11480  * denied.
11481  */
11482 static scf_error_t
11483 delete_dependency_pg(const char *fmri, const char *name)
11484 {
11485 	void *entity = NULL;
11486 	int isservice;
11487 	scf_propertygroup_t *pg = NULL;
11488 	scf_error_t result;
11489 	char *pgty;
11490 	scf_service_t *svc = NULL;
11491 	scf_instance_t *inst = NULL;
11492 	scf_iter_t *iter = NULL;
11493 	char *name_buf = NULL;
11494 
11495 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11496 	switch (result) {
11497 	case SCF_ERROR_NONE:
11498 		break;
11499 
11500 	case SCF_ERROR_NO_MEMORY:
11501 		uu_die(gettext("Out of memory.\n"));
11502 		/* NOTREACHED */
11503 
11504 	case SCF_ERROR_INVALID_ARGUMENT:
11505 	case SCF_ERROR_CONSTRAINT_VIOLATED:
11506 		return (SCF_ERROR_INVALID_ARGUMENT);
11507 
11508 	case SCF_ERROR_NOT_FOUND:
11509 		result = SCF_ERROR_NONE;
11510 		goto out;
11511 
11512 	default:
11513 		bad_error("fmri_to_entity", result);
11514 	}
11515 
11516 	pg = scf_pg_create(g_hndl);
11517 	if (pg == NULL)
11518 		scfdie();
11519 
11520 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
11521 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11522 			scfdie();
11523 
11524 		result = SCF_ERROR_NONE;
11525 		goto out;
11526 	}
11527 
11528 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11529 
11530 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11531 		scfdie();
11532 
11533 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
11534 		result = SCF_ERROR_TYPE_MISMATCH;
11535 		free(pgty);
11536 		goto out;
11537 	}
11538 
11539 	free(pgty);
11540 
11541 	if (scf_pg_delete(pg) != 0) {
11542 		result = scf_error();
11543 		if (result != SCF_ERROR_PERMISSION_DENIED)
11544 			scfdie();
11545 		goto out;
11546 	}
11547 
11548 	/*
11549 	 * We have to handle the case where we've just deleted the last
11550 	 * property group of a "dummy" entity (instance or service).
11551 	 * A "dummy" entity is an entity only present to hold an
11552 	 * external dependency.
11553 	 * So, in the case we deleted the last property group then we
11554 	 * can also delete the entity. If the entity is an instance then
11555 	 * we must verify if this was the last instance for the service
11556 	 * and if it is, we can also delete the service if it doesn't
11557 	 * have any property group either.
11558 	 */
11559 
11560 	result = SCF_ERROR_NONE;
11561 
11562 	if (isservice) {
11563 		svc = (scf_service_t *)entity;
11564 
11565 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
11566 		    (iter = scf_iter_create(g_hndl)) == NULL)
11567 			scfdie();
11568 
11569 		name_buf = safe_malloc(max_scf_name_len + 1);
11570 	} else {
11571 		inst = (scf_instance_t *)entity;
11572 	}
11573 
11574 	/*
11575 	 * If the entity is an instance and we've just deleted its last
11576 	 * property group then we should delete it.
11577 	 */
11578 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
11579 		/* find the service before deleting the inst. - needed later */
11580 		if ((svc = scf_service_create(g_hndl)) == NULL)
11581 			scfdie();
11582 
11583 		if (scf_instance_get_parent(inst, svc) != 0)
11584 			scfdie();
11585 
11586 		/* delete the instance */
11587 		if (scf_instance_delete(inst) != 0) {
11588 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11589 				scfdie();
11590 
11591 			result = SCF_ERROR_PERMISSION_DENIED;
11592 			goto out;
11593 		}
11594 		/* no need to refresh the instance */
11595 		inst = NULL;
11596 	}
11597 
11598 	/*
11599 	 * If the service has no more instances and pgs or we just deleted the
11600 	 * last instance and the service doesn't have anymore propery groups
11601 	 * then the service should be deleted.
11602 	 */
11603 	if (svc != NULL &&
11604 	    svc_has_no_insts(svc) &&
11605 	    entity_has_no_pgs((void *)svc, 1)) {
11606 		if (scf_service_delete(svc) == 0) {
11607 			if (isservice) {
11608 				/* no need to refresh the service */
11609 				svc = NULL;
11610 			}
11611 
11612 			goto out;
11613 		}
11614 
11615 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11616 			scfdie();
11617 
11618 		result = SCF_ERROR_PERMISSION_DENIED;
11619 	}
11620 
11621 	/* if the entity has not been deleted, refresh it */
11622 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
11623 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
11624 		    name_buf);
11625 	}
11626 
11627 out:
11628 	if (isservice && (inst != NULL && iter != NULL)) {
11629 		free(name_buf);
11630 		scf_iter_destroy(iter);
11631 		scf_instance_destroy(inst);
11632 	}
11633 
11634 	if (!isservice && svc != NULL) {
11635 		scf_service_destroy(svc);
11636 	}
11637 
11638 	scf_pg_destroy(pg);
11639 	if (entity != NULL)
11640 		entity_destroy(entity, isservice);
11641 
11642 	return (result);
11643 }
11644 
11645 static int
11646 delete_dependents(scf_propertygroup_t *pg)
11647 {
11648 	char *pgty, *name, *fmri;
11649 	scf_property_t *prop;
11650 	scf_value_t *val;
11651 	scf_iter_t *iter;
11652 	int r;
11653 	scf_error_t err;
11654 
11655 	/* Verify that the pg has the correct type. */
11656 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11657 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11658 		scfdie();
11659 
11660 	if (strcmp(pgty, scf_group_framework) != 0) {
11661 		if (g_verbose) {
11662 			fmri = safe_malloc(max_scf_fmri_len + 1);
11663 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
11664 				scfdie();
11665 
11666 			warn(gettext("Property group %s is not of expected "
11667 			    "type %s.\n"), fmri, scf_group_framework);
11668 
11669 			free(fmri);
11670 		}
11671 
11672 		free(pgty);
11673 		return (-1);
11674 	}
11675 
11676 	free(pgty);
11677 
11678 	/* map delete_dependency_pg onto the properties. */
11679 	if ((prop = scf_property_create(g_hndl)) == NULL ||
11680 	    (val = scf_value_create(g_hndl)) == NULL ||
11681 	    (iter = scf_iter_create(g_hndl)) == NULL)
11682 		scfdie();
11683 
11684 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
11685 		scfdie();
11686 
11687 	name = safe_malloc(max_scf_name_len + 1);
11688 	fmri = safe_malloc(max_scf_fmri_len + 2);
11689 
11690 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
11691 		scf_type_t ty;
11692 
11693 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
11694 			scfdie();
11695 
11696 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11697 			scfdie();
11698 
11699 		if ((ty != SCF_TYPE_ASTRING &&
11700 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
11701 		    prop_get_val(prop, val) != 0)
11702 			continue;
11703 
11704 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
11705 			scfdie();
11706 
11707 		err = delete_dependency_pg(fmri, name);
11708 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
11709 			if (scf_property_to_fmri(prop, fmri,
11710 			    max_scf_fmri_len + 2) < 0)
11711 				scfdie();
11712 
11713 			warn(gettext("Value of %s is not a valid FMRI.\n"),
11714 			    fmri);
11715 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
11716 			warn(gettext("Property group \"%s\" of entity \"%s\" "
11717 			    "does not have dependency type.\n"), name, fmri);
11718 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
11719 			warn(gettext("Could not delete property group \"%s\" "
11720 			    "of entity \"%s\" (permission denied).\n"), name,
11721 			    fmri);
11722 		}
11723 	}
11724 	if (r == -1)
11725 		scfdie();
11726 
11727 	scf_value_destroy(val);
11728 	scf_property_destroy(prop);
11729 
11730 	return (0);
11731 }
11732 
11733 /*
11734  * Returns 1 if the instance may be running, and 0 otherwise.
11735  */
11736 static int
11737 inst_is_running(scf_instance_t *inst)
11738 {
11739 	scf_propertygroup_t *pg;
11740 	scf_property_t *prop;
11741 	scf_value_t *val;
11742 	char buf[MAX_SCF_STATE_STRING_SZ];
11743 	int ret = 0;
11744 	ssize_t szret;
11745 
11746 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11747 	    (prop = scf_property_create(g_hndl)) == NULL ||
11748 	    (val = scf_value_create(g_hndl)) == NULL)
11749 		scfdie();
11750 
11751 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
11752 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11753 			scfdie();
11754 		goto out;
11755 	}
11756 
11757 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
11758 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
11759 	    prop_get_val(prop, val) != 0)
11760 		goto out;
11761 
11762 	szret = scf_value_get_astring(val, buf, sizeof (buf));
11763 	assert(szret >= 0);
11764 
11765 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11766 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11767 
11768 out:
11769 	scf_value_destroy(val);
11770 	scf_property_destroy(prop);
11771 	scf_pg_destroy(pg);
11772 	return (ret);
11773 }
11774 
11775 static uint8_t
11776 pg_is_external_dependency(scf_propertygroup_t *pg)
11777 {
11778 	char *type;
11779 	scf_value_t *val;
11780 	scf_property_t *prop;
11781 	uint8_t b = B_FALSE;
11782 
11783 	type = safe_malloc(max_scf_pg_type_len + 1);
11784 
11785 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
11786 		scfdie();
11787 
11788 	if ((prop = scf_property_create(g_hndl)) == NULL ||
11789 	    (val = scf_value_create(g_hndl)) == NULL)
11790 		scfdie();
11791 
11792 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
11793 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
11794 			if (scf_property_get_value(prop, val) != 0)
11795 				scfdie();
11796 			if (scf_value_get_boolean(val, &b) != 0)
11797 				scfdie();
11798 		}
11799 	}
11800 
11801 	free(type);
11802 	(void) scf_value_destroy(val);
11803 	(void) scf_property_destroy(prop);
11804 
11805 	return (b);
11806 }
11807 
11808 #define	DELETE_FAILURE			-1
11809 #define	DELETE_SUCCESS_NOEXTDEPS	0
11810 #define	DELETE_SUCCESS_EXTDEPS		1
11811 
11812 /*
11813  * lscf_instance_delete() deletes an instance.  Before calling
11814  * scf_instance_delete(), though, we make sure the instance isn't
11815  * running and delete dependencies in other entities which the instance
11816  * declared as "dependents".  If there are dependencies which were
11817  * created for other entities, then instead of deleting the instance we
11818  * make it "empty" by deleting all other property groups and all
11819  * snapshots.
11820  *
11821  * lscf_instance_delete() verifies that there is no external dependency pgs
11822  * before suppressing the instance. If there is, then we must not remove them
11823  * now in case the instance is re-created otherwise the dependencies would be
11824  * lost. The external dependency pgs will be removed if the dependencies are
11825  * removed.
11826  *
11827  * Returns:
11828  *  DELETE_FAILURE		on failure
11829  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11830  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11831  */
11832 static int
11833 lscf_instance_delete(scf_instance_t *inst, int force)
11834 {
11835 	scf_propertygroup_t *pg;
11836 	scf_snapshot_t *snap;
11837 	scf_iter_t *iter;
11838 	int err;
11839 	int external = 0;
11840 
11841 	/* If we're not forcing and the instance is running, refuse. */
11842 	if (!force && inst_is_running(inst)) {
11843 		char *fmri;
11844 
11845 		fmri = safe_malloc(max_scf_fmri_len + 1);
11846 
11847 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
11848 			scfdie();
11849 
11850 		semerr(gettext("Instance %s may be running.  "
11851 		    "Use delete -f if it is not.\n"), fmri);
11852 
11853 		free(fmri);
11854 		return (DELETE_FAILURE);
11855 	}
11856 
11857 	pg = scf_pg_create(g_hndl);
11858 	if (pg == NULL)
11859 		scfdie();
11860 
11861 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
11862 		(void) delete_dependents(pg);
11863 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11864 		scfdie();
11865 
11866 	scf_pg_destroy(pg);
11867 
11868 	/*
11869 	 * If the instance has some external dependencies then we must
11870 	 * keep them in case the instance is reimported otherwise the
11871 	 * dependencies would be lost on reimport.
11872 	 */
11873 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11874 	    (pg = scf_pg_create(g_hndl)) == NULL)
11875 		scfdie();
11876 
11877 	if (scf_iter_instance_pgs(iter, inst) < 0)
11878 		scfdie();
11879 
11880 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11881 		if (pg_is_external_dependency(pg)) {
11882 			external = 1;
11883 			continue;
11884 		}
11885 
11886 		if (scf_pg_delete(pg) != 0) {
11887 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11888 				scfdie();
11889 			else {
11890 				semerr(emsg_permission_denied);
11891 
11892 				(void) scf_iter_destroy(iter);
11893 				(void) scf_pg_destroy(pg);
11894 				return (DELETE_FAILURE);
11895 			}
11896 		}
11897 	}
11898 
11899 	if (err == -1)
11900 		scfdie();
11901 
11902 	(void) scf_iter_destroy(iter);
11903 	(void) scf_pg_destroy(pg);
11904 
11905 	if (external) {
11906 		/*
11907 		 * All the pgs have been deleted for the instance except
11908 		 * the ones holding the external dependencies.
11909 		 * For the job to be complete, we must also delete the
11910 		 * snapshots associated with the instance.
11911 		 */
11912 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
11913 		    NULL)
11914 			scfdie();
11915 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
11916 			scfdie();
11917 
11918 		if (scf_iter_instance_snapshots(iter, inst) == -1)
11919 			scfdie();
11920 
11921 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
11922 			if (_scf_snapshot_delete(snap) != 0) {
11923 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11924 					scfdie();
11925 
11926 				semerr(emsg_permission_denied);
11927 
11928 				(void) scf_iter_destroy(iter);
11929 				(void) scf_snapshot_destroy(snap);
11930 				return (DELETE_FAILURE);
11931 			}
11932 		}
11933 
11934 		if (err == -1)
11935 			scfdie();
11936 
11937 		(void) scf_iter_destroy(iter);
11938 		(void) scf_snapshot_destroy(snap);
11939 		return (DELETE_SUCCESS_EXTDEPS);
11940 	}
11941 
11942 	if (scf_instance_delete(inst) != 0) {
11943 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11944 			scfdie();
11945 
11946 		semerr(emsg_permission_denied);
11947 
11948 		return (DELETE_FAILURE);
11949 	}
11950 
11951 	return (DELETE_SUCCESS_NOEXTDEPS);
11952 }
11953 
11954 /*
11955  * lscf_service_delete() deletes a service.  Before calling
11956  * scf_service_delete(), though, we call lscf_instance_delete() for
11957  * each of the instances and delete dependencies in other entities
11958  * which were created as "dependents" of this service.  If there are
11959  * dependencies which were created for other entities, then we delete
11960  * all other property groups in the service and leave it as "empty".
11961  *
11962  * lscf_service_delete() verifies that there is no external dependency
11963  * pgs at the instance & service level before suppressing the service.
11964  * If there is, then we must not remove them now in case the service
11965  * is re-imported otherwise the dependencies would be lost. The external
11966  * dependency pgs will be removed if the dependencies are removed.
11967  *
11968  * Returns:
11969  *   DELETE_FAILURE		on failure
11970  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11971  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11972  */
11973 static int
11974 lscf_service_delete(scf_service_t *svc, int force)
11975 {
11976 	int r;
11977 	scf_instance_t *inst;
11978 	scf_propertygroup_t *pg;
11979 	scf_iter_t *iter;
11980 	int ret;
11981 	int external = 0;
11982 
11983 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11984 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11985 	    (iter = scf_iter_create(g_hndl)) == NULL)
11986 		scfdie();
11987 
11988 	if (scf_iter_service_instances(iter, svc) != 0)
11989 		scfdie();
11990 
11991 	for (r = scf_iter_next_instance(iter, inst);
11992 	    r == 1;
11993 	    r = scf_iter_next_instance(iter, inst)) {
11994 
11995 		ret = lscf_instance_delete(inst, force);
11996 		if (ret == DELETE_FAILURE) {
11997 			scf_iter_destroy(iter);
11998 			scf_pg_destroy(pg);
11999 			scf_instance_destroy(inst);
12000 			return (DELETE_FAILURE);
12001 		}
12002 
12003 		/*
12004 		 * Record the fact that there is some external dependencies
12005 		 * at the instance level.
12006 		 */
12007 		if (ret == DELETE_SUCCESS_EXTDEPS)
12008 			external |= 1;
12009 	}
12010 
12011 	if (r != 0)
12012 		scfdie();
12013 
12014 	/* Delete dependency property groups in dependent services. */
12015 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12016 		(void) delete_dependents(pg);
12017 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12018 		scfdie();
12019 
12020 	scf_iter_destroy(iter);
12021 	scf_pg_destroy(pg);
12022 	scf_instance_destroy(inst);
12023 
12024 	/*
12025 	 * If the service has some external dependencies then we don't
12026 	 * want to remove them in case the service is re-imported.
12027 	 */
12028 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12029 	    (iter = scf_iter_create(g_hndl)) == NULL)
12030 		scfdie();
12031 
12032 	if (scf_iter_service_pgs(iter, svc) < 0)
12033 		scfdie();
12034 
12035 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12036 		if (pg_is_external_dependency(pg)) {
12037 			external |= 2;
12038 			continue;
12039 		}
12040 
12041 		if (scf_pg_delete(pg) != 0) {
12042 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12043 				scfdie();
12044 			else {
12045 				semerr(emsg_permission_denied);
12046 
12047 				(void) scf_iter_destroy(iter);
12048 				(void) scf_pg_destroy(pg);
12049 				return (DELETE_FAILURE);
12050 			}
12051 		}
12052 	}
12053 
12054 	if (r == -1)
12055 		scfdie();
12056 
12057 	(void) scf_iter_destroy(iter);
12058 	(void) scf_pg_destroy(pg);
12059 
12060 	if (external != 0)
12061 		return (DELETE_SUCCESS_EXTDEPS);
12062 
12063 	if (scf_service_delete(svc) == 0)
12064 		return (DELETE_SUCCESS_NOEXTDEPS);
12065 
12066 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12067 		scfdie();
12068 
12069 	semerr(emsg_permission_denied);
12070 	return (DELETE_FAILURE);
12071 }
12072 
12073 static int
12074 delete_callback(void *data, scf_walkinfo_t *wip)
12075 {
12076 	int force = (int)data;
12077 
12078 	if (wip->inst != NULL)
12079 		(void) lscf_instance_delete(wip->inst, force);
12080 	else
12081 		(void) lscf_service_delete(wip->svc, force);
12082 
12083 	return (0);
12084 }
12085 
12086 void
12087 lscf_delete(const char *fmri, int force)
12088 {
12089 	scf_service_t *svc;
12090 	scf_instance_t *inst;
12091 	int ret;
12092 
12093 	lscf_prep_hndl();
12094 
12095 	if (cur_snap != NULL) {
12096 		if (!snaplevel_is_instance(cur_level)) {
12097 			char *buf;
12098 
12099 			buf = safe_malloc(max_scf_name_len + 1);
12100 			if (scf_instance_get_name(cur_inst, buf,
12101 			    max_scf_name_len + 1) >= 0) {
12102 				if (strcmp(buf, fmri) == 0) {
12103 					semerr(emsg_cant_modify_snapshots);
12104 					free(buf);
12105 					return;
12106 				}
12107 			} else if (scf_error() != SCF_ERROR_DELETED) {
12108 				scfdie();
12109 			}
12110 			free(buf);
12111 		}
12112 	} else if (cur_inst != NULL) {
12113 		/* EMPTY */;
12114 	} else if (cur_svc != NULL) {
12115 		inst = scf_instance_create(g_hndl);
12116 		if (inst == NULL)
12117 			scfdie();
12118 
12119 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12120 		    SCF_SUCCESS) {
12121 			(void) lscf_instance_delete(inst, force);
12122 			scf_instance_destroy(inst);
12123 			return;
12124 		}
12125 
12126 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12127 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12128 			scfdie();
12129 
12130 		scf_instance_destroy(inst);
12131 	} else {
12132 		assert(cur_scope != NULL);
12133 
12134 		svc = scf_service_create(g_hndl);
12135 		if (svc == NULL)
12136 			scfdie();
12137 
12138 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12139 		    SCF_SUCCESS) {
12140 			(void) lscf_service_delete(svc, force);
12141 			scf_service_destroy(svc);
12142 			return;
12143 		}
12144 
12145 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12146 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12147 			scfdie();
12148 
12149 		scf_service_destroy(svc);
12150 	}
12151 
12152 	/*
12153 	 * Match FMRI to entity.
12154 	 */
12155 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12156 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12157 		semerr(gettext("Failed to walk instances: %s\n"),
12158 		    scf_strerror(ret));
12159 	}
12160 }
12161 
12162 
12163 
12164 /*
12165  * :properties commands.  These all end with "pg" or "prop" and generally
12166  * operate on the currently selected entity.
12167  */
12168 
12169 /*
12170  * Property listing.  List the property groups, properties, their types and
12171  * their values for the currently selected entity.
12172  */
12173 static void
12174 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12175 {
12176 	char *buf;
12177 	uint32_t flags;
12178 
12179 	buf = safe_malloc(max_scf_pg_type_len + 1);
12180 
12181 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12182 		scfdie();
12183 
12184 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12185 		scfdie();
12186 
12187 	safe_printf("%-*s  %s", namewidth, name, buf);
12188 
12189 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12190 		safe_printf("\tNONPERSISTENT");
12191 
12192 	safe_printf("\n");
12193 
12194 	free(buf);
12195 }
12196 
12197 static boolean_t
12198 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12199 {
12200 	if (scf_property_get_value(prop, val) == 0) {
12201 		return (B_FALSE);
12202 	} else {
12203 		switch (scf_error()) {
12204 		case SCF_ERROR_NOT_FOUND:
12205 			return (B_FALSE);
12206 		case SCF_ERROR_PERMISSION_DENIED:
12207 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12208 			return (B_TRUE);
12209 		default:
12210 			scfdie();
12211 			/*NOTREACHED*/
12212 		}
12213 	}
12214 }
12215 
12216 static void
12217 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12218 {
12219 	scf_iter_t *iter;
12220 	scf_value_t *val;
12221 	const char *type;
12222 	int multiple_strings = 0;
12223 	int ret;
12224 
12225 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12226 	    (val = scf_value_create(g_hndl)) == NULL)
12227 		scfdie();
12228 
12229 	type = prop_to_typestr(prop);
12230 	assert(type != NULL);
12231 
12232 	safe_printf("%-*s  %-7s ", len, name, type);
12233 
12234 	if (prop_has_multiple_values(prop, val) &&
12235 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12236 	    scf_value_type(val) == SCF_TYPE_USTRING))
12237 		multiple_strings = 1;
12238 
12239 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12240 		scfdie();
12241 
12242 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12243 		char *buf;
12244 		ssize_t vlen, szret;
12245 
12246 		vlen = scf_value_get_as_string(val, NULL, 0);
12247 		if (vlen < 0)
12248 			scfdie();
12249 
12250 		buf = safe_malloc(vlen + 1);
12251 
12252 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12253 		if (szret < 0)
12254 			scfdie();
12255 		assert(szret <= vlen);
12256 
12257 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12258 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12259 			safe_printf(" \"");
12260 			(void) quote_and_print(buf, stdout, 0);
12261 			(void) putchar('"');
12262 			if (ferror(stdout)) {
12263 				(void) putchar('\n');
12264 				uu_die(gettext("Error writing to stdout.\n"));
12265 			}
12266 		} else {
12267 			safe_printf(" %s", buf);
12268 		}
12269 
12270 		free(buf);
12271 	}
12272 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12273 		scfdie();
12274 
12275 	if (putchar('\n') != '\n')
12276 		uu_die(gettext("Could not output newline"));
12277 }
12278 
12279 /*
12280  * Outputs template property group info for the describe subcommand.
12281  * If 'templates' == 2, verbose output is printed in the format expected
12282  * for describe -v, which includes all templates fields.  If pg is
12283  * not NULL, we're describing the template data, not an existing property
12284  * group, and formatting should be appropriate for describe -t.
12285  */
12286 static void
12287 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12288 {
12289 	char *buf;
12290 	uint8_t required;
12291 	scf_property_t *stability_prop;
12292 	scf_value_t *stability_val;
12293 
12294 	if (templates == 0)
12295 		return;
12296 
12297 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12298 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12299 		scfdie();
12300 
12301 	if (templates == 2 && pg != NULL) {
12302 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12303 		    stability_prop) == 0) {
12304 			if (prop_check_type(stability_prop,
12305 			    SCF_TYPE_ASTRING) == 0 &&
12306 			    prop_get_val(stability_prop, stability_val) == 0) {
12307 				char *stability;
12308 
12309 				stability = safe_malloc(max_scf_value_len + 1);
12310 
12311 				if (scf_value_get_astring(stability_val,
12312 				    stability, max_scf_value_len + 1) == -1 &&
12313 				    scf_error() != SCF_ERROR_NOT_FOUND)
12314 					scfdie();
12315 
12316 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12317 				    gettext("stability"), stability);
12318 
12319 				free(stability);
12320 			}
12321 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12322 			scfdie();
12323 	}
12324 
12325 	scf_property_destroy(stability_prop);
12326 	scf_value_destroy(stability_val);
12327 
12328 	if (pgt == NULL)
12329 		return;
12330 
12331 	if (pg == NULL || templates == 2) {
12332 		/* print type info only if scf_tmpl_pg_name succeeds */
12333 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12334 			if (pg != NULL)
12335 				safe_printf("%s", TMPL_INDENT);
12336 			safe_printf("%s: ", gettext("name"));
12337 			safe_printf("%s\n", buf);
12338 			free(buf);
12339 		}
12340 
12341 		/* print type info only if scf_tmpl_pg_type succeeds */
12342 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12343 			if (pg != NULL)
12344 				safe_printf("%s", TMPL_INDENT);
12345 			safe_printf("%s: ", gettext("type"));
12346 			safe_printf("%s\n", buf);
12347 			free(buf);
12348 		}
12349 	}
12350 
12351 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12352 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12353 		    required ? "true" : "false");
12354 
12355 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12356 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12357 		    buf);
12358 		free(buf);
12359 	}
12360 
12361 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12362 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12363 		    buf);
12364 		free(buf);
12365 	}
12366 
12367 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12368 		if (templates == 2)
12369 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12370 			    gettext("description"), buf);
12371 		else
12372 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12373 		free(buf);
12374 	}
12375 
12376 }
12377 
12378 /*
12379  * With as_value set to true, indent as appropriate for the value level.
12380  * If false, indent to appropriate level for inclusion in constraint
12381  * or choice printout.
12382  */
12383 static void
12384 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12385     int as_value)
12386 {
12387 	char *buf;
12388 
12389 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12390 		if (as_value == 0)
12391 			safe_printf("%s", TMPL_CHOICE_INDENT);
12392 		else
12393 			safe_printf("%s", TMPL_INDENT);
12394 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12395 		free(buf);
12396 	}
12397 
12398 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12399 		if (as_value == 0)
12400 			safe_printf("%s", TMPL_CHOICE_INDENT);
12401 		else
12402 			safe_printf("%s", TMPL_INDENT);
12403 		safe_printf("%s: %s\n", gettext("value description"), buf);
12404 		free(buf);
12405 	}
12406 }
12407 
12408 static void
12409 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12410 {
12411 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12412 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12413 	safe_printf("%s\n", val_buf);
12414 
12415 	print_template_value_details(prt, val_buf, 1);
12416 }
12417 
12418 static void
12419 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12420 {
12421 	int i, printed = 0;
12422 	scf_values_t values;
12423 	scf_count_ranges_t c_ranges;
12424 	scf_int_ranges_t i_ranges;
12425 
12426 	printed = 0;
12427 	i = 0;
12428 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12429 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12430 		    gettext("value constraints"));
12431 		printed++;
12432 		for (i = 0; i < values.value_count; ++i) {
12433 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12434 			    gettext("value name"), values.values_as_strings[i]);
12435 			if (verbose == 1)
12436 				print_template_value_details(prt,
12437 				    values.values_as_strings[i], 0);
12438 		}
12439 
12440 		scf_values_destroy(&values);
12441 	}
12442 
12443 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12444 		if (printed++ == 0)
12445 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12446 			    gettext("value constraints"));
12447 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12448 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12449 			    gettext("range"), c_ranges.scr_min[i],
12450 			    c_ranges.scr_max[i]);
12451 		}
12452 		scf_count_ranges_destroy(&c_ranges);
12453 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12454 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12455 		if (printed++ == 0)
12456 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12457 			    gettext("value constraints"));
12458 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12459 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12460 			    gettext("range"), i_ranges.sir_min[i],
12461 			    i_ranges.sir_max[i]);
12462 		}
12463 		scf_int_ranges_destroy(&i_ranges);
12464 	}
12465 }
12466 
12467 static void
12468 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12469 {
12470 	int i = 0, printed = 0;
12471 	scf_values_t values;
12472 	scf_count_ranges_t c_ranges;
12473 	scf_int_ranges_t i_ranges;
12474 
12475 	printed = 0;
12476 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12477 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12478 		    gettext("value constraints"));
12479 		printed++;
12480 		for (i = 0; i < values.value_count; i++) {
12481 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12482 			    gettext("value name"), values.values_as_strings[i]);
12483 			if (verbose == 1)
12484 				print_template_value_details(prt,
12485 				    values.values_as_strings[i], 0);
12486 		}
12487 
12488 		scf_values_destroy(&values);
12489 	}
12490 
12491 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12492 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12493 			if (printed++ == 0)
12494 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12495 				    gettext("value choices"));
12496 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12497 			    gettext("range"), c_ranges.scr_min[i],
12498 			    c_ranges.scr_max[i]);
12499 		}
12500 		scf_count_ranges_destroy(&c_ranges);
12501 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12502 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12503 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12504 			if (printed++ == 0)
12505 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12506 				    gettext("value choices"));
12507 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12508 			    gettext("range"), i_ranges.sir_min[i],
12509 			    i_ranges.sir_max[i]);
12510 		}
12511 		scf_int_ranges_destroy(&i_ranges);
12512 	}
12513 }
12514 
12515 static void
12516 list_values_by_template(scf_prop_tmpl_t *prt)
12517 {
12518 	print_template_constraints(prt, 1);
12519 	print_template_choices(prt, 1);
12520 }
12521 
12522 static void
12523 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
12524 {
12525 	char *val_buf;
12526 	scf_iter_t *iter;
12527 	scf_value_t *val;
12528 	int ret;
12529 
12530 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12531 	    (val = scf_value_create(g_hndl)) == NULL)
12532 		scfdie();
12533 
12534 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12535 		scfdie();
12536 
12537 	val_buf = safe_malloc(max_scf_value_len + 1);
12538 
12539 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12540 		if (scf_value_get_as_string(val, val_buf,
12541 		    max_scf_value_len + 1) < 0)
12542 			scfdie();
12543 
12544 		print_template_value(prt, val_buf);
12545 	}
12546 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12547 		scfdie();
12548 	free(val_buf);
12549 
12550 	print_template_constraints(prt, 0);
12551 	print_template_choices(prt, 0);
12552 
12553 }
12554 
12555 /*
12556  * Outputs property info for the describe subcommand
12557  * Verbose output if templates == 2, -v option of svccfg describe
12558  * Displays template data if prop is not NULL, -t option of svccfg describe
12559  */
12560 static void
12561 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
12562 {
12563 	char *buf;
12564 	uint8_t u_buf;
12565 	int i;
12566 	uint64_t min, max;
12567 	scf_values_t values;
12568 
12569 	if (prt == NULL || templates == 0)
12570 		return;
12571 
12572 	if (prop == NULL) {
12573 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
12574 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
12575 			safe_printf("%s\n", buf);
12576 			free(buf);
12577 		} else
12578 			safe_printf("(%s)\n", gettext("any"));
12579 	}
12580 
12581 	if (prop == NULL || templates == 2) {
12582 		if (prop != NULL)
12583 			safe_printf("%s", TMPL_INDENT);
12584 		else
12585 			safe_printf("%s", TMPL_VALUE_INDENT);
12586 		safe_printf("%s: ", gettext("type"));
12587 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
12588 			safe_printf("%s\n", buf);
12589 			free(buf);
12590 		} else
12591 			safe_printf("(%s)\n", gettext("any"));
12592 	}
12593 
12594 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
12595 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12596 		    u_buf ? "true" : "false");
12597 
12598 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
12599 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12600 		    buf);
12601 		free(buf);
12602 	}
12603 
12604 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
12605 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
12606 		    buf);
12607 		free(buf);
12608 	}
12609 
12610 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
12611 		safe_printf("%s%s\n", TMPL_INDENT, buf);
12612 		free(buf);
12613 	}
12614 
12615 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
12616 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
12617 		    scf_tmpl_visibility_to_string(u_buf));
12618 
12619 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
12620 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12621 		    gettext("minimum number of values"), min);
12622 		if (max == ULLONG_MAX) {
12623 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12624 			    gettext("maximum number of values"),
12625 			    gettext("unlimited"));
12626 		} else {
12627 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12628 			    gettext("maximum number of values"), max);
12629 		}
12630 	}
12631 
12632 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
12633 		for (i = 0; i < values.value_count; i++) {
12634 			if (i == 0) {
12635 				safe_printf("%s%s:", TMPL_INDENT,
12636 				    gettext("internal separators"));
12637 			}
12638 			safe_printf(" \"%s\"", values.values_as_strings[i]);
12639 		}
12640 		safe_printf("\n");
12641 	}
12642 
12643 	if (templates != 2)
12644 		return;
12645 
12646 	if (prop != NULL)
12647 		list_values_tmpl(prt, prop);
12648 	else
12649 		list_values_by_template(prt);
12650 }
12651 
12652 static char *
12653 read_astring(scf_propertygroup_t *pg, const char *prop_name)
12654 {
12655 	char *rv;
12656 
12657 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
12658 	if (rv == NULL) {
12659 		switch (scf_error()) {
12660 		case SCF_ERROR_NOT_FOUND:
12661 			break;
12662 		default:
12663 			scfdie();
12664 		}
12665 	}
12666 	return (rv);
12667 }
12668 
12669 static void
12670 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
12671 {
12672 	size_t doc_len;
12673 	size_t man_len;
12674 	char *pg_name;
12675 	char *text = NULL;
12676 	int rv;
12677 
12678 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
12679 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
12680 	pg_name = safe_malloc(max_scf_name_len + 1);
12681 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
12682 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
12683 			scfdie();
12684 		}
12685 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
12686 			/* Display doc_link and and uri */
12687 			safe_printf("%s%s:\n", TMPL_INDENT,
12688 			    gettext("doc_link"));
12689 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
12690 			if (text != NULL) {
12691 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12692 				    TMPL_INDENT, gettext("name"), text);
12693 				uu_free(text);
12694 			}
12695 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
12696 			if (text != NULL) {
12697 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
12698 				    gettext("uri"), text);
12699 				uu_free(text);
12700 			}
12701 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
12702 		    man_len) == 0) {
12703 			/* Display manpage title, section and path */
12704 			safe_printf("%s%s:\n", TMPL_INDENT,
12705 			    gettext("manpage"));
12706 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
12707 			if (text != NULL) {
12708 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12709 				    TMPL_INDENT, gettext("title"), text);
12710 				uu_free(text);
12711 			}
12712 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
12713 			if (text != NULL) {
12714 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12715 				    TMPL_INDENT, gettext("section"), text);
12716 				uu_free(text);
12717 			}
12718 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
12719 			if (text != NULL) {
12720 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12721 				    TMPL_INDENT, gettext("manpath"), text);
12722 				uu_free(text);
12723 			}
12724 		}
12725 	}
12726 	if (rv == -1)
12727 		scfdie();
12728 
12729 done:
12730 	free(pg_name);
12731 }
12732 
12733 static void
12734 list_entity_tmpl(int templates)
12735 {
12736 	char *common_name = NULL;
12737 	char *description = NULL;
12738 	char *locale = NULL;
12739 	scf_iter_t *iter;
12740 	scf_propertygroup_t *pg;
12741 	scf_property_t *prop;
12742 	int r;
12743 	scf_value_t *val;
12744 
12745 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12746 	    (prop = scf_property_create(g_hndl)) == NULL ||
12747 	    (val = scf_value_create(g_hndl)) == NULL ||
12748 	    (iter = scf_iter_create(g_hndl)) == NULL)
12749 		scfdie();
12750 
12751 	locale = setlocale(LC_MESSAGES, NULL);
12752 
12753 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
12754 		common_name = safe_malloc(max_scf_value_len + 1);
12755 
12756 		/* Try both the current locale and the "C" locale. */
12757 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
12758 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
12759 		    scf_pg_get_property(pg, "C", prop) == 0)) {
12760 			if (prop_get_val(prop, val) == 0 &&
12761 			    scf_value_get_ustring(val, common_name,
12762 			    max_scf_value_len + 1) != -1) {
12763 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12764 				    gettext("common name"), common_name);
12765 			}
12766 		}
12767 	}
12768 
12769 	/*
12770 	 * Do description, manpages, and doc links if templates == 2.
12771 	 */
12772 	if (templates == 2) {
12773 		/* Get the description. */
12774 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12775 			description = safe_malloc(max_scf_value_len + 1);
12776 
12777 			/* Try both the current locale and the "C" locale. */
12778 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
12779 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
12780 			    scf_pg_get_property(pg, "C", prop) == 0)) {
12781 				if (prop_get_val(prop, val) == 0 &&
12782 				    scf_value_get_ustring(val, description,
12783 				    max_scf_value_len + 1) != -1) {
12784 					safe_printf("%s%s: %s\n", TMPL_INDENT,
12785 					    gettext("description"),
12786 					    description);
12787 				}
12788 			}
12789 		}
12790 
12791 		/* Process doc_link & manpage elements. */
12792 		if (cur_level != NULL) {
12793 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
12794 			    SCF_GROUP_TEMPLATE);
12795 		} else if (cur_inst != NULL) {
12796 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
12797 			    SCF_GROUP_TEMPLATE);
12798 		} else {
12799 			r = scf_iter_service_pgs_typed(iter, cur_svc,
12800 			    SCF_GROUP_TEMPLATE);
12801 		}
12802 		if (r == 0) {
12803 			display_documentation(iter, pg);
12804 		}
12805 	}
12806 
12807 	free(common_name);
12808 	free(description);
12809 	scf_pg_destroy(pg);
12810 	scf_property_destroy(prop);
12811 	scf_value_destroy(val);
12812 	scf_iter_destroy(iter);
12813 }
12814 
12815 static void
12816 listtmpl(const char *pattern, int templates)
12817 {
12818 	scf_pg_tmpl_t *pgt;
12819 	scf_prop_tmpl_t *prt;
12820 	char *snapbuf = NULL;
12821 	char *fmribuf;
12822 	char *pg_name = NULL, *prop_name = NULL;
12823 	ssize_t prop_name_size;
12824 	char *qual_prop_name;
12825 	char *search_name;
12826 	int listed = 0;
12827 
12828 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12829 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
12830 		scfdie();
12831 
12832 	fmribuf = safe_malloc(max_scf_name_len + 1);
12833 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
12834 
12835 	if (cur_snap != NULL) {
12836 		snapbuf = safe_malloc(max_scf_name_len + 1);
12837 		if (scf_snapshot_get_name(cur_snap, snapbuf,
12838 		    max_scf_name_len + 1) < 0)
12839 			scfdie();
12840 	}
12841 
12842 	if (cur_inst != NULL) {
12843 		if (scf_instance_to_fmri(cur_inst, fmribuf,
12844 		    max_scf_name_len + 1) < 0)
12845 			scfdie();
12846 	} else if (cur_svc != NULL) {
12847 		if (scf_service_to_fmri(cur_svc, fmribuf,
12848 		    max_scf_name_len + 1) < 0)
12849 			scfdie();
12850 	} else
12851 		abort();
12852 
12853 	/* If pattern is specified, we want to list only those items. */
12854 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
12855 		listed = 0;
12856 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
12857 		    fnmatch(pattern, pg_name, 0) == 0)) {
12858 			list_pg_tmpl(pgt, NULL, templates);
12859 			listed++;
12860 		}
12861 
12862 		scf_tmpl_prop_reset(prt);
12863 
12864 		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
12865 			search_name = NULL;
12866 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
12867 			if ((prop_name_size > 0) && (pg_name != NULL)) {
12868 				if (snprintf(qual_prop_name,
12869 				    max_scf_name_len + 1, "%s/%s",
12870 				    pg_name, prop_name) >=
12871 				    max_scf_name_len + 1) {
12872 					prop_name_size = -1;
12873 				} else {
12874 					search_name = qual_prop_name;
12875 				}
12876 			}
12877 			if (listed > 0 || pattern == NULL ||
12878 			    (prop_name_size > 0 &&
12879 			    fnmatch(pattern, search_name,
12880 			    FNM_PATHNAME) == 0))
12881 				list_prop_tmpl(prt, NULL, templates);
12882 			if (prop_name != NULL) {
12883 				free(prop_name);
12884 				prop_name = NULL;
12885 			}
12886 		}
12887 		if (pg_name != NULL) {
12888 			free(pg_name);
12889 			pg_name = NULL;
12890 		}
12891 	}
12892 
12893 	scf_tmpl_prop_destroy(prt);
12894 	scf_tmpl_pg_destroy(pgt);
12895 	free(snapbuf);
12896 	free(fmribuf);
12897 	free(qual_prop_name);
12898 }
12899 
12900 static void
12901 listprop(const char *pattern, int only_pgs, int templates)
12902 {
12903 	scf_propertygroup_t *pg;
12904 	scf_property_t *prop;
12905 	scf_iter_t *iter, *piter;
12906 	char *pgnbuf, *prnbuf, *ppnbuf;
12907 	scf_pg_tmpl_t *pgt, *pgtp;
12908 	scf_prop_tmpl_t *prt;
12909 
12910 	void **objects;
12911 	char **names;
12912 	void **tmpls;
12913 	int allocd, i;
12914 
12915 	int ret;
12916 	ssize_t pgnlen, prnlen, szret;
12917 	size_t max_len = 0;
12918 
12919 	if (cur_svc == NULL && cur_inst == NULL) {
12920 		semerr(emsg_entity_not_selected);
12921 		return;
12922 	}
12923 
12924 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12925 	    (prop = scf_property_create(g_hndl)) == NULL ||
12926 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12927 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12928 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12929 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
12930 		scfdie();
12931 
12932 	prnbuf = safe_malloc(max_scf_name_len + 1);
12933 
12934 	if (cur_level != NULL)
12935 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
12936 	else if (cur_inst != NULL)
12937 		ret = scf_iter_instance_pgs(iter, cur_inst);
12938 	else
12939 		ret = scf_iter_service_pgs(iter, cur_svc);
12940 	if (ret != 0) {
12941 		return;
12942 	}
12943 
12944 	/*
12945 	 * We want to only list items which match pattern, and we want the
12946 	 * second column to line up, so during the first pass we'll save
12947 	 * matching items, their names, and their templates in objects,
12948 	 * names, and tmpls, computing the maximum name length as we go,
12949 	 * and then we'll print them out.
12950 	 *
12951 	 * Note: We always keep an extra slot available so the array can be
12952 	 * NULL-terminated.
12953 	 */
12954 	i = 0;
12955 	allocd = 1;
12956 	objects = safe_malloc(sizeof (*objects));
12957 	names = safe_malloc(sizeof (*names));
12958 	tmpls = safe_malloc(sizeof (*tmpls));
12959 
12960 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12961 		int new_pg = 0;
12962 		int print_props = 0;
12963 		pgtp = NULL;
12964 
12965 		pgnlen = scf_pg_get_name(pg, NULL, 0);
12966 		if (pgnlen < 0)
12967 			scfdie();
12968 
12969 		pgnbuf = safe_malloc(pgnlen + 1);
12970 
12971 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
12972 		if (szret < 0)
12973 			scfdie();
12974 		assert(szret <= pgnlen);
12975 
12976 		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
12977 			if (scf_error() != SCF_ERROR_NOT_FOUND)
12978 				scfdie();
12979 			pgtp = NULL;
12980 		} else {
12981 			pgtp = pgt;
12982 		}
12983 
12984 		if (pattern == NULL ||
12985 		    fnmatch(pattern, pgnbuf, 0) == 0) {
12986 			if (i+1 >= allocd) {
12987 				allocd *= 2;
12988 				objects = realloc(objects,
12989 				    sizeof (*objects) * allocd);
12990 				names =
12991 				    realloc(names, sizeof (*names) * allocd);
12992 				tmpls = realloc(tmpls,
12993 				    sizeof (*tmpls) * allocd);
12994 				if (objects == NULL || names == NULL ||
12995 				    tmpls == NULL)
12996 					uu_die(gettext("Out of memory"));
12997 			}
12998 			objects[i] = pg;
12999 			names[i] = pgnbuf;
13000 
13001 			if (pgtp == NULL)
13002 				tmpls[i] = NULL;
13003 			else
13004 				tmpls[i] = pgt;
13005 
13006 			++i;
13007 
13008 			if (pgnlen > max_len)
13009 				max_len = pgnlen;
13010 
13011 			new_pg = 1;
13012 			print_props = 1;
13013 		}
13014 
13015 		if (only_pgs) {
13016 			if (new_pg) {
13017 				pg = scf_pg_create(g_hndl);
13018 				if (pg == NULL)
13019 					scfdie();
13020 				pgt = scf_tmpl_pg_create(g_hndl);
13021 				if (pgt == NULL)
13022 					scfdie();
13023 			} else
13024 				free(pgnbuf);
13025 
13026 			continue;
13027 		}
13028 
13029 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13030 			scfdie();
13031 
13032 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13033 			prnlen = scf_property_get_name(prop, prnbuf,
13034 			    max_scf_name_len + 1);
13035 			if (prnlen < 0)
13036 				scfdie();
13037 
13038 			/* Will prepend the property group name and a slash. */
13039 			prnlen += pgnlen + 1;
13040 
13041 			ppnbuf = safe_malloc(prnlen + 1);
13042 
13043 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13044 			    prnbuf) < 0)
13045 				uu_die("snprintf");
13046 
13047 			if (pattern == NULL || print_props == 1 ||
13048 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13049 				if (i+1 >= allocd) {
13050 					allocd *= 2;
13051 					objects = realloc(objects,
13052 					    sizeof (*objects) * allocd);
13053 					names = realloc(names,
13054 					    sizeof (*names) * allocd);
13055 					tmpls = realloc(tmpls,
13056 					    sizeof (*tmpls) * allocd);
13057 					if (objects == NULL || names == NULL ||
13058 					    tmpls == NULL)
13059 						uu_die(gettext(
13060 						    "Out of memory"));
13061 				}
13062 
13063 				objects[i] = prop;
13064 				names[i] = ppnbuf;
13065 
13066 				if (pgtp != NULL) {
13067 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13068 					    prt, NULL) < 0) {
13069 						if (scf_error() !=
13070 						    SCF_ERROR_NOT_FOUND)
13071 							scfdie();
13072 						tmpls[i] = NULL;
13073 					} else {
13074 						tmpls[i] = prt;
13075 					}
13076 				} else {
13077 					tmpls[i] = NULL;
13078 				}
13079 
13080 				++i;
13081 
13082 				if (prnlen > max_len)
13083 					max_len = prnlen;
13084 
13085 				prop = scf_property_create(g_hndl);
13086 				prt = scf_tmpl_prop_create(g_hndl);
13087 			} else {
13088 				free(ppnbuf);
13089 			}
13090 		}
13091 
13092 		if (new_pg) {
13093 			pg = scf_pg_create(g_hndl);
13094 			if (pg == NULL)
13095 				scfdie();
13096 			pgt = scf_tmpl_pg_create(g_hndl);
13097 			if (pgt == NULL)
13098 				scfdie();
13099 		} else
13100 			free(pgnbuf);
13101 	}
13102 	if (ret != 0)
13103 		scfdie();
13104 
13105 	objects[i] = NULL;
13106 
13107 	scf_pg_destroy(pg);
13108 	scf_tmpl_pg_destroy(pgt);
13109 	scf_property_destroy(prop);
13110 	scf_tmpl_prop_destroy(prt);
13111 
13112 	for (i = 0; objects[i] != NULL; ++i) {
13113 		if (strchr(names[i], '/') == NULL) {
13114 			/* property group */
13115 			pg = (scf_propertygroup_t *)objects[i];
13116 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13117 			list_pg_info(pg, names[i], max_len);
13118 			list_pg_tmpl(pgt, pg, templates);
13119 			free(names[i]);
13120 			scf_pg_destroy(pg);
13121 			if (pgt != NULL)
13122 				scf_tmpl_pg_destroy(pgt);
13123 		} else {
13124 			/* property */
13125 			prop = (scf_property_t *)objects[i];
13126 			prt = (scf_prop_tmpl_t *)tmpls[i];
13127 			list_prop_info(prop, names[i], max_len);
13128 			list_prop_tmpl(prt, prop, templates);
13129 			free(names[i]);
13130 			scf_property_destroy(prop);
13131 			if (prt != NULL)
13132 				scf_tmpl_prop_destroy(prt);
13133 		}
13134 	}
13135 
13136 	free(names);
13137 	free(objects);
13138 	free(tmpls);
13139 }
13140 
13141 void
13142 lscf_listpg(const char *pattern)
13143 {
13144 	lscf_prep_hndl();
13145 
13146 	listprop(pattern, 1, 0);
13147 }
13148 
13149 /*
13150  * Property group and property creation, setting, and deletion.  setprop (and
13151  * its alias, addprop) can either create a property group of a given type, or
13152  * it can create or set a property to a given type and list of values.
13153  */
13154 void
13155 lscf_addpg(const char *name, const char *type, const char *flags)
13156 {
13157 	scf_propertygroup_t *pg;
13158 	int ret;
13159 	uint32_t flgs = 0;
13160 	const char *cp;
13161 
13162 
13163 	lscf_prep_hndl();
13164 
13165 	if (cur_snap != NULL) {
13166 		semerr(emsg_cant_modify_snapshots);
13167 		return;
13168 	}
13169 
13170 	if (cur_inst == NULL && cur_svc == NULL) {
13171 		semerr(emsg_entity_not_selected);
13172 		return;
13173 	}
13174 
13175 	if (flags != NULL) {
13176 		for (cp = flags; *cp != '\0'; ++cp) {
13177 			switch (*cp) {
13178 			case 'P':
13179 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13180 				break;
13181 
13182 			case 'p':
13183 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13184 				break;
13185 
13186 			default:
13187 				semerr(gettext("Invalid property group flag "
13188 				    "%c."), *cp);
13189 				return;
13190 			}
13191 		}
13192 	}
13193 
13194 	pg = scf_pg_create(g_hndl);
13195 	if (pg == NULL)
13196 		scfdie();
13197 
13198 	if (cur_inst != NULL)
13199 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13200 	else
13201 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13202 
13203 	if (ret != SCF_SUCCESS) {
13204 		switch (scf_error()) {
13205 		case SCF_ERROR_INVALID_ARGUMENT:
13206 			semerr(gettext("Name, type, or flags are invalid.\n"));
13207 			break;
13208 
13209 		case SCF_ERROR_EXISTS:
13210 			semerr(gettext("Property group already exists.\n"));
13211 			break;
13212 
13213 		case SCF_ERROR_PERMISSION_DENIED:
13214 			semerr(emsg_permission_denied);
13215 			break;
13216 
13217 		case SCF_ERROR_BACKEND_ACCESS:
13218 			semerr(gettext("Backend refused access.\n"));
13219 			break;
13220 
13221 		default:
13222 			scfdie();
13223 		}
13224 	}
13225 
13226 	scf_pg_destroy(pg);
13227 
13228 	private_refresh();
13229 }
13230 
13231 void
13232 lscf_delpg(char *name)
13233 {
13234 	lscf_prep_hndl();
13235 
13236 	if (cur_snap != NULL) {
13237 		semerr(emsg_cant_modify_snapshots);
13238 		return;
13239 	}
13240 
13241 	if (cur_inst == NULL && cur_svc == NULL) {
13242 		semerr(emsg_entity_not_selected);
13243 		return;
13244 	}
13245 
13246 	if (strchr(name, '/') != NULL) {
13247 		semerr(emsg_invalid_pg_name, name);
13248 		return;
13249 	}
13250 
13251 	lscf_delprop(name);
13252 }
13253 
13254 /*
13255  * scf_delhash() is used to remove the property group related to the
13256  * hash entry for a specific manifest in the repository. pgname will be
13257  * constructed from the location of the manifest file. If deathrow isn't 0,
13258  * manifest file doesn't need to exist (manifest string will be used as
13259  * an absolute path).
13260  */
13261 void
13262 lscf_delhash(char *manifest, int deathrow)
13263 {
13264 	char *pgname;
13265 
13266 	if (cur_snap != NULL ||
13267 	    cur_inst != NULL || cur_svc != NULL) {
13268 		warn(gettext("error, an entity is selected\n"));
13269 		return;
13270 	}
13271 
13272 	/* select smf/manifest */
13273 	lscf_select(HASH_SVC);
13274 	/*
13275 	 * Translate the manifest file name to property name. In the deathrow
13276 	 * case, the manifest file does not need to exist.
13277 	 */
13278 	pgname = mhash_filename_to_propname(manifest,
13279 	    deathrow ? B_TRUE : B_FALSE);
13280 	if (pgname == NULL) {
13281 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13282 		return;
13283 	}
13284 	/* delete the hash property name */
13285 	lscf_delpg(pgname);
13286 }
13287 
13288 void
13289 lscf_listprop(const char *pattern)
13290 {
13291 	lscf_prep_hndl();
13292 
13293 	listprop(pattern, 0, 0);
13294 }
13295 
13296 int
13297 lscf_setprop(const char *pgname, const char *type, const char *value,
13298     const uu_list_t *values)
13299 {
13300 	scf_type_t ty, current_ty;
13301 	scf_service_t *svc;
13302 	scf_propertygroup_t *pg, *parent_pg;
13303 	scf_property_t *prop, *parent_prop;
13304 	scf_pg_tmpl_t *pgt;
13305 	scf_prop_tmpl_t *prt;
13306 	int ret, result = 0;
13307 	scf_transaction_t *tx;
13308 	scf_transaction_entry_t *e;
13309 	scf_value_t *v;
13310 	uu_list_walk_t *walk;
13311 	string_list_t *sp;
13312 	char *propname;
13313 	int req_quotes = 0;
13314 
13315 	lscf_prep_hndl();
13316 
13317 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13318 	    (svc = scf_service_create(g_hndl)) == NULL ||
13319 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13320 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13321 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13322 	    (prop = scf_property_create(g_hndl)) == NULL ||
13323 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13324 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13325 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13326 		scfdie();
13327 
13328 	if (cur_snap != NULL) {
13329 		semerr(emsg_cant_modify_snapshots);
13330 		goto fail;
13331 	}
13332 
13333 	if (cur_inst == NULL && cur_svc == NULL) {
13334 		semerr(emsg_entity_not_selected);
13335 		goto fail;
13336 	}
13337 
13338 	propname = strchr(pgname, '/');
13339 	if (propname == NULL) {
13340 		semerr(gettext("Property names must contain a `/'.\n"));
13341 		goto fail;
13342 	}
13343 
13344 	*propname = '\0';
13345 	++propname;
13346 
13347 	if (type != NULL) {
13348 		ty = string_to_type(type);
13349 		if (ty == SCF_TYPE_INVALID) {
13350 			semerr(gettext("Unknown type \"%s\".\n"), type);
13351 			goto fail;
13352 		}
13353 	}
13354 
13355 	if (cur_inst != NULL)
13356 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13357 	else
13358 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13359 	if (ret != SCF_SUCCESS) {
13360 		switch (scf_error()) {
13361 		case SCF_ERROR_NOT_FOUND:
13362 			semerr(emsg_no_such_pg, pgname);
13363 			goto fail;
13364 
13365 		case SCF_ERROR_INVALID_ARGUMENT:
13366 			semerr(emsg_invalid_pg_name, pgname);
13367 			goto fail;
13368 
13369 		default:
13370 			scfdie();
13371 			break;
13372 		}
13373 	}
13374 
13375 	do {
13376 		if (scf_pg_update(pg) == -1)
13377 			scfdie();
13378 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13379 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13380 				scfdie();
13381 
13382 			semerr(emsg_permission_denied);
13383 			goto fail;
13384 		}
13385 
13386 		ret = scf_pg_get_property(pg, propname, prop);
13387 		if (ret == SCF_SUCCESS) {
13388 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13389 				scfdie();
13390 
13391 			if (type == NULL)
13392 				ty = current_ty;
13393 			if (scf_transaction_property_change_type(tx, e,
13394 			    propname, ty) == -1)
13395 				scfdie();
13396 
13397 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13398 			/* Infer the type, if possible. */
13399 			if (type == NULL) {
13400 				/*
13401 				 * First check if we're an instance and the
13402 				 * property is set on the service.
13403 				 */
13404 				if (cur_inst != NULL &&
13405 				    scf_instance_get_parent(cur_inst,
13406 				    svc) == 0 &&
13407 				    scf_service_get_pg(cur_svc, pgname,
13408 				    parent_pg) == 0 &&
13409 				    scf_pg_get_property(parent_pg, propname,
13410 				    parent_prop) == 0 &&
13411 				    scf_property_type(parent_prop,
13412 				    &current_ty) == 0) {
13413 					ty = current_ty;
13414 
13415 				/* Then check for a type set in a template. */
13416 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13417 				    NULL) == 0 &&
13418 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13419 				    NULL) == 0 &&
13420 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13421 					ty = current_ty;
13422 
13423 				/* If type can't be inferred, fail. */
13424 				} else {
13425 					semerr(gettext("Type required for new "
13426 					    "properties.\n"));
13427 					goto fail;
13428 				}
13429 			}
13430 			if (scf_transaction_property_new(tx, e, propname,
13431 			    ty) == -1)
13432 				scfdie();
13433 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13434 			semerr(emsg_invalid_prop_name, propname);
13435 			goto fail;
13436 		} else {
13437 			scfdie();
13438 		}
13439 
13440 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13441 			req_quotes = 1;
13442 
13443 		if (value != NULL) {
13444 			v = string_to_value(value, ty, 0);
13445 
13446 			if (v == NULL)
13447 				goto fail;
13448 
13449 			ret = scf_entry_add_value(e, v);
13450 			assert(ret == SCF_SUCCESS);
13451 		} else {
13452 			assert(values != NULL);
13453 
13454 			walk = uu_list_walk_start((uu_list_t *)values,
13455 			    UU_DEFAULT);
13456 			if (walk == NULL)
13457 				uu_die(gettext("Could not walk list"));
13458 
13459 			for (sp = uu_list_walk_next(walk); sp != NULL;
13460 			    sp = uu_list_walk_next(walk)) {
13461 				v = string_to_value(sp->str, ty, req_quotes);
13462 
13463 				if (v == NULL) {
13464 					scf_entry_destroy_children(e);
13465 					goto fail;
13466 				}
13467 
13468 				ret = scf_entry_add_value(e, v);
13469 				assert(ret == SCF_SUCCESS);
13470 			}
13471 			uu_list_walk_end(walk);
13472 		}
13473 		result = scf_transaction_commit(tx);
13474 
13475 		scf_transaction_reset(tx);
13476 		scf_entry_destroy_children(e);
13477 	} while (result == 0);
13478 
13479 	if (result < 0) {
13480 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13481 			scfdie();
13482 
13483 		semerr(emsg_permission_denied);
13484 		goto fail;
13485 	}
13486 
13487 	ret = 0;
13488 
13489 	private_refresh();
13490 
13491 	goto cleanup;
13492 
13493 fail:
13494 	ret = -1;
13495 
13496 cleanup:
13497 	scf_transaction_destroy(tx);
13498 	scf_entry_destroy(e);
13499 	scf_service_destroy(svc);
13500 	scf_pg_destroy(parent_pg);
13501 	scf_pg_destroy(pg);
13502 	scf_property_destroy(parent_prop);
13503 	scf_property_destroy(prop);
13504 	scf_tmpl_pg_destroy(pgt);
13505 	scf_tmpl_prop_destroy(prt);
13506 
13507 	return (ret);
13508 }
13509 
13510 void
13511 lscf_delprop(char *pgn)
13512 {
13513 	char *slash, *pn;
13514 	scf_propertygroup_t *pg;
13515 	scf_transaction_t *tx;
13516 	scf_transaction_entry_t *e;
13517 	int ret;
13518 
13519 
13520 	lscf_prep_hndl();
13521 
13522 	if (cur_snap != NULL) {
13523 		semerr(emsg_cant_modify_snapshots);
13524 		return;
13525 	}
13526 
13527 	if (cur_inst == NULL && cur_svc == NULL) {
13528 		semerr(emsg_entity_not_selected);
13529 		return;
13530 	}
13531 
13532 	pg = scf_pg_create(g_hndl);
13533 	if (pg == NULL)
13534 		scfdie();
13535 
13536 	slash = strchr(pgn, '/');
13537 	if (slash == NULL) {
13538 		pn = NULL;
13539 	} else {
13540 		*slash = '\0';
13541 		pn = slash + 1;
13542 	}
13543 
13544 	if (cur_inst != NULL)
13545 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
13546 	else
13547 		ret = scf_service_get_pg(cur_svc, pgn, pg);
13548 	if (ret != SCF_SUCCESS) {
13549 		switch (scf_error()) {
13550 		case SCF_ERROR_NOT_FOUND:
13551 			semerr(emsg_no_such_pg, pgn);
13552 			break;
13553 
13554 		case SCF_ERROR_INVALID_ARGUMENT:
13555 			semerr(emsg_invalid_pg_name, pgn);
13556 			break;
13557 
13558 		default:
13559 			scfdie();
13560 		}
13561 
13562 		scf_pg_destroy(pg);
13563 
13564 		return;
13565 	}
13566 
13567 	if (pn == NULL) {
13568 		/* Try to delete the property group. */
13569 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
13570 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13571 				scfdie();
13572 
13573 			semerr(emsg_permission_denied);
13574 		} else {
13575 			private_refresh();
13576 		}
13577 
13578 		scf_pg_destroy(pg);
13579 		return;
13580 	}
13581 
13582 	e = scf_entry_create(g_hndl);
13583 	tx = scf_transaction_create(g_hndl);
13584 
13585 	do {
13586 		if (scf_pg_update(pg) == -1)
13587 			scfdie();
13588 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13589 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13590 				scfdie();
13591 
13592 			semerr(emsg_permission_denied);
13593 			break;
13594 		}
13595 
13596 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
13597 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
13598 				semerr(gettext("No such property %s/%s.\n"),
13599 				    pgn, pn);
13600 				break;
13601 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13602 				semerr(emsg_invalid_prop_name, pn);
13603 				break;
13604 			} else {
13605 				scfdie();
13606 			}
13607 		}
13608 
13609 		ret = scf_transaction_commit(tx);
13610 
13611 		if (ret == 0)
13612 			scf_transaction_reset(tx);
13613 	} while (ret == 0);
13614 
13615 	if (ret < 0) {
13616 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13617 			scfdie();
13618 
13619 		semerr(emsg_permission_denied);
13620 	} else {
13621 		private_refresh();
13622 	}
13623 
13624 	scf_transaction_destroy(tx);
13625 	scf_entry_destroy(e);
13626 	scf_pg_destroy(pg);
13627 }
13628 
13629 /*
13630  * Property editing.
13631  */
13632 
13633 static int
13634 write_edit_script(FILE *strm)
13635 {
13636 	char *fmribuf;
13637 	ssize_t fmrilen;
13638 
13639 	scf_propertygroup_t *pg;
13640 	scf_property_t *prop;
13641 	scf_value_t *val;
13642 	scf_type_t ty;
13643 	int ret, result = 0;
13644 	scf_iter_t *iter, *piter, *viter;
13645 	char *buf, *tybuf, *pname;
13646 	const char *emsg_write_error;
13647 
13648 
13649 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
13650 
13651 
13652 	/* select fmri */
13653 	if (cur_inst != NULL) {
13654 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
13655 		if (fmrilen < 0)
13656 			scfdie();
13657 		fmribuf = safe_malloc(fmrilen + 1);
13658 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
13659 			scfdie();
13660 	} else {
13661 		assert(cur_svc != NULL);
13662 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
13663 		if (fmrilen < 0)
13664 			scfdie();
13665 		fmribuf = safe_malloc(fmrilen + 1);
13666 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
13667 			scfdie();
13668 	}
13669 
13670 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
13671 		warn(emsg_write_error, strerror(errno));
13672 		free(fmribuf);
13673 		return (-1);
13674 	}
13675 
13676 	free(fmribuf);
13677 
13678 
13679 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13680 	    (prop = scf_property_create(g_hndl)) == NULL ||
13681 	    (val = scf_value_create(g_hndl)) == NULL ||
13682 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13683 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13684 	    (viter = scf_iter_create(g_hndl)) == NULL)
13685 		scfdie();
13686 
13687 	buf = safe_malloc(max_scf_name_len + 1);
13688 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
13689 	pname = safe_malloc(max_scf_name_len + 1);
13690 
13691 	if (cur_inst != NULL)
13692 		ret = scf_iter_instance_pgs(iter, cur_inst);
13693 	else
13694 		ret = scf_iter_service_pgs(iter, cur_svc);
13695 	if (ret != SCF_SUCCESS)
13696 		scfdie();
13697 
13698 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13699 		int ret2;
13700 
13701 		/*
13702 		 * # delprop pg
13703 		 * # addpg pg type
13704 		 */
13705 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
13706 			scfdie();
13707 
13708 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
13709 			scfdie();
13710 
13711 		if (fprintf(strm, "# Property group \"%s\"\n"
13712 		    "# delprop %s\n"
13713 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
13714 			warn(emsg_write_error, strerror(errno));
13715 			result = -1;
13716 			goto out;
13717 		}
13718 
13719 		/* # setprop pg/prop = (values) */
13720 
13721 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13722 			scfdie();
13723 
13724 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
13725 			int first = 1;
13726 			int ret3;
13727 			int multiple;
13728 			int is_str;
13729 			scf_type_t bty;
13730 
13731 			if (scf_property_get_name(prop, pname,
13732 			    max_scf_name_len + 1) < 0)
13733 				scfdie();
13734 
13735 			if (scf_property_type(prop, &ty) != 0)
13736 				scfdie();
13737 
13738 			multiple = prop_has_multiple_values(prop, val);
13739 
13740 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13741 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
13742 			    < 0) {
13743 				warn(emsg_write_error, strerror(errno));
13744 				result = -1;
13745 				goto out;
13746 			}
13747 
13748 			(void) scf_type_base_type(ty, &bty);
13749 			is_str = (bty == SCF_TYPE_ASTRING);
13750 
13751 			if (scf_iter_property_values(viter, prop) !=
13752 			    SCF_SUCCESS)
13753 				scfdie();
13754 
13755 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
13756 				char *buf;
13757 				ssize_t buflen;
13758 
13759 				buflen = scf_value_get_as_string(val, NULL, 0);
13760 				if (buflen < 0)
13761 					scfdie();
13762 
13763 				buf = safe_malloc(buflen + 1);
13764 
13765 				if (scf_value_get_as_string(val, buf,
13766 				    buflen + 1) < 0)
13767 					scfdie();
13768 
13769 				if (first)
13770 					first = 0;
13771 				else {
13772 					if (putc(' ', strm) != ' ') {
13773 						warn(emsg_write_error,
13774 						    strerror(errno));
13775 						result = -1;
13776 						goto out;
13777 					}
13778 				}
13779 
13780 				if ((is_str && multiple) ||
13781 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
13782 					(void) putc('"', strm);
13783 					(void) quote_and_print(buf, strm, 1);
13784 					(void) putc('"', strm);
13785 
13786 					if (ferror(strm)) {
13787 						warn(emsg_write_error,
13788 						    strerror(errno));
13789 						result = -1;
13790 						goto out;
13791 					}
13792 				} else {
13793 					if (fprintf(strm, "%s", buf) < 0) {
13794 						warn(emsg_write_error,
13795 						    strerror(errno));
13796 						result = -1;
13797 						goto out;
13798 					}
13799 				}
13800 
13801 				free(buf);
13802 			}
13803 			if (ret3 < 0 &&
13804 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
13805 				scfdie();
13806 
13807 			/* Write closing paren if mult-value property */
13808 			if ((multiple && putc(')', strm) == EOF) ||
13809 
13810 			    /* Write final newline */
13811 			    fputc('\n', strm) == EOF) {
13812 				warn(emsg_write_error, strerror(errno));
13813 				result = -1;
13814 				goto out;
13815 			}
13816 		}
13817 		if (ret2 < 0)
13818 			scfdie();
13819 
13820 		if (fputc('\n', strm) == EOF) {
13821 			warn(emsg_write_error, strerror(errno));
13822 			result = -1;
13823 			goto out;
13824 		}
13825 	}
13826 	if (ret < 0)
13827 		scfdie();
13828 
13829 out:
13830 	free(pname);
13831 	free(tybuf);
13832 	free(buf);
13833 	scf_iter_destroy(viter);
13834 	scf_iter_destroy(piter);
13835 	scf_iter_destroy(iter);
13836 	scf_value_destroy(val);
13837 	scf_property_destroy(prop);
13838 	scf_pg_destroy(pg);
13839 
13840 	if (result == 0) {
13841 		if (fflush(strm) != 0) {
13842 			warn(emsg_write_error, strerror(errno));
13843 			return (-1);
13844 		}
13845 	}
13846 
13847 	return (result);
13848 }
13849 
13850 int
13851 lscf_editprop()
13852 {
13853 	char *buf, *editor;
13854 	size_t bufsz;
13855 	int tmpfd;
13856 	char tempname[] = TEMP_FILE_PATTERN;
13857 
13858 	lscf_prep_hndl();
13859 
13860 	if (cur_snap != NULL) {
13861 		semerr(emsg_cant_modify_snapshots);
13862 		return (-1);
13863 	}
13864 
13865 	if (cur_svc == NULL && cur_inst == NULL) {
13866 		semerr(emsg_entity_not_selected);
13867 		return (-1);
13868 	}
13869 
13870 	tmpfd = mkstemp(tempname);
13871 	if (tmpfd == -1) {
13872 		semerr(gettext("Could not create temporary file.\n"));
13873 		return (-1);
13874 	}
13875 
13876 	(void) strcpy(tempfilename, tempname);
13877 
13878 	tempfile = fdopen(tmpfd, "r+");
13879 	if (tempfile == NULL) {
13880 		warn(gettext("Could not create temporary file.\n"));
13881 		if (close(tmpfd) == -1)
13882 			warn(gettext("Could not close temporary file: %s.\n"),
13883 			    strerror(errno));
13884 
13885 		remove_tempfile();
13886 
13887 		return (-1);
13888 	}
13889 
13890 	if (write_edit_script(tempfile) == -1) {
13891 		remove_tempfile();
13892 		return (-1);
13893 	}
13894 
13895 	editor = getenv("EDITOR");
13896 	if (editor == NULL)
13897 		editor = "vi";
13898 
13899 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
13900 	buf = safe_malloc(bufsz);
13901 
13902 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
13903 		uu_die(gettext("Error creating editor command"));
13904 
13905 	if (system(buf) == -1) {
13906 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
13907 		    strerror(errno));
13908 		free(buf);
13909 		remove_tempfile();
13910 		return (-1);
13911 	}
13912 
13913 	free(buf);
13914 
13915 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
13916 
13917 	remove_tempfile();
13918 
13919 	return (0);
13920 }
13921 
13922 static void
13923 add_string(uu_list_t *strlist, const char *str)
13924 {
13925 	string_list_t *elem;
13926 	elem = safe_malloc(sizeof (*elem));
13927 	uu_list_node_init(elem, &elem->node, string_pool);
13928 	elem->str = safe_strdup(str);
13929 	if (uu_list_append(strlist, elem) != 0)
13930 		uu_die(gettext("libuutil error: %s\n"),
13931 		    uu_strerror(uu_error()));
13932 }
13933 
13934 static int
13935 remove_string(uu_list_t *strlist, const char *str)
13936 {
13937 	uu_list_walk_t	*elems;
13938 	string_list_t	*sp;
13939 
13940 	/*
13941 	 * Find the element that needs to be removed.
13942 	 */
13943 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
13944 	while ((sp = uu_list_walk_next(elems)) != NULL) {
13945 		if (strcmp(sp->str, str) == 0)
13946 			break;
13947 	}
13948 	uu_list_walk_end(elems);
13949 
13950 	/*
13951 	 * Returning 1 here as the value was not found, this
13952 	 * might not be an error.  Leave it to the caller to
13953 	 * decide.
13954 	 */
13955 	if (sp == NULL) {
13956 		return (1);
13957 	}
13958 
13959 	uu_list_remove(strlist, sp);
13960 
13961 	free(sp->str);
13962 	free(sp);
13963 
13964 	return (0);
13965 }
13966 
13967 /*
13968  * Get all property values that don't match the given glob pattern,
13969  * if a pattern is specified.
13970  */
13971 static void
13972 get_prop_values(scf_property_t *prop, uu_list_t *values,
13973     const char *pattern)
13974 {
13975 	scf_iter_t *iter;
13976 	scf_value_t *val;
13977 	int ret;
13978 
13979 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13980 	    (val = scf_value_create(g_hndl)) == NULL)
13981 		scfdie();
13982 
13983 	if (scf_iter_property_values(iter, prop) != 0)
13984 		scfdie();
13985 
13986 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13987 		char *buf;
13988 		ssize_t vlen, szret;
13989 
13990 		vlen = scf_value_get_as_string(val, NULL, 0);
13991 		if (vlen < 0)
13992 			scfdie();
13993 
13994 		buf = safe_malloc(vlen + 1);
13995 
13996 		szret = scf_value_get_as_string(val, buf, vlen + 1);
13997 		if (szret < 0)
13998 			scfdie();
13999 		assert(szret <= vlen);
14000 
14001 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14002 			add_string(values, buf);
14003 
14004 		free(buf);
14005 	}
14006 
14007 	if (ret == -1)
14008 		scfdie();
14009 
14010 	scf_value_destroy(val);
14011 	scf_iter_destroy(iter);
14012 }
14013 
14014 static int
14015 lscf_setpropvalue(const char *pgname, const char *type,
14016     const char *arg, int isadd, int isnotfoundok)
14017 {
14018 	scf_type_t ty;
14019 	scf_propertygroup_t *pg;
14020 	scf_property_t *prop;
14021 	int ret, result = 0;
14022 	scf_transaction_t *tx;
14023 	scf_transaction_entry_t *e;
14024 	scf_value_t *v;
14025 	string_list_t *sp;
14026 	char *propname;
14027 	uu_list_t *values;
14028 	uu_list_walk_t *walk;
14029 	void *cookie = NULL;
14030 	char *pattern = NULL;
14031 
14032 	lscf_prep_hndl();
14033 
14034 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14035 		uu_die(gettext("Could not create property list: %s\n"),
14036 		    uu_strerror(uu_error()));
14037 
14038 	if (!isadd)
14039 		pattern = safe_strdup(arg);
14040 
14041 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14042 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14043 	    (prop = scf_property_create(g_hndl)) == NULL ||
14044 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14045 		scfdie();
14046 
14047 	if (cur_snap != NULL) {
14048 		semerr(emsg_cant_modify_snapshots);
14049 		goto fail;
14050 	}
14051 
14052 	if (cur_inst == NULL && cur_svc == NULL) {
14053 		semerr(emsg_entity_not_selected);
14054 		goto fail;
14055 	}
14056 
14057 	propname = strchr(pgname, '/');
14058 	if (propname == NULL) {
14059 		semerr(gettext("Property names must contain a `/'.\n"));
14060 		goto fail;
14061 	}
14062 
14063 	*propname = '\0';
14064 	++propname;
14065 
14066 	if (type != NULL) {
14067 		ty = string_to_type(type);
14068 		if (ty == SCF_TYPE_INVALID) {
14069 			semerr(gettext("Unknown type \"%s\".\n"), type);
14070 			goto fail;
14071 		}
14072 	}
14073 
14074 	if (cur_inst != NULL)
14075 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14076 	else
14077 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14078 	if (ret != 0) {
14079 		switch (scf_error()) {
14080 		case SCF_ERROR_NOT_FOUND:
14081 			if (isnotfoundok) {
14082 				result = 0;
14083 			} else {
14084 				semerr(emsg_no_such_pg, pgname);
14085 				result = -1;
14086 			}
14087 			goto out;
14088 
14089 		case SCF_ERROR_INVALID_ARGUMENT:
14090 			semerr(emsg_invalid_pg_name, pgname);
14091 			goto fail;
14092 
14093 		default:
14094 			scfdie();
14095 		}
14096 	}
14097 
14098 	do {
14099 		if (scf_pg_update(pg) == -1)
14100 			scfdie();
14101 		if (scf_transaction_start(tx, pg) != 0) {
14102 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14103 				scfdie();
14104 
14105 			semerr(emsg_permission_denied);
14106 			goto fail;
14107 		}
14108 
14109 		ret = scf_pg_get_property(pg, propname, prop);
14110 		if (ret == 0) {
14111 			scf_type_t ptype;
14112 			char *pat = pattern;
14113 
14114 			if (scf_property_type(prop, &ptype) != 0)
14115 				scfdie();
14116 
14117 			if (isadd) {
14118 				if (type != NULL && ptype != ty) {
14119 					semerr(gettext("Property \"%s\" is not "
14120 					    "of type \"%s\".\n"), propname,
14121 					    type);
14122 					goto fail;
14123 				}
14124 
14125 				pat = NULL;
14126 			} else {
14127 				size_t len = strlen(pat);
14128 				if (len > 0 && pat[len - 1] == '\"')
14129 					pat[len - 1] = '\0';
14130 				if (len > 0 && pat[0] == '\"')
14131 					pat++;
14132 			}
14133 
14134 			ty = ptype;
14135 
14136 			get_prop_values(prop, values, pat);
14137 
14138 			if (isadd)
14139 				add_string(values, arg);
14140 
14141 			if (scf_transaction_property_change(tx, e,
14142 			    propname, ty) == -1)
14143 				scfdie();
14144 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14145 			if (isadd) {
14146 				if (type == NULL) {
14147 					semerr(gettext("Type required "
14148 					    "for new properties.\n"));
14149 					goto fail;
14150 				}
14151 
14152 				add_string(values, arg);
14153 
14154 				if (scf_transaction_property_new(tx, e,
14155 				    propname, ty) == -1)
14156 					scfdie();
14157 			} else if (isnotfoundok) {
14158 				result = 0;
14159 				goto out;
14160 			} else {
14161 				semerr(gettext("No such property %s/%s.\n"),
14162 				    pgname, propname);
14163 				result = -1;
14164 				goto out;
14165 			}
14166 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14167 			semerr(emsg_invalid_prop_name, propname);
14168 			goto fail;
14169 		} else {
14170 			scfdie();
14171 		}
14172 
14173 		walk = uu_list_walk_start(values, UU_DEFAULT);
14174 		if (walk == NULL)
14175 			uu_die(gettext("Could not walk property list.\n"));
14176 
14177 		for (sp = uu_list_walk_next(walk); sp != NULL;
14178 		    sp = uu_list_walk_next(walk)) {
14179 			v = string_to_value(sp->str, ty, 0);
14180 
14181 			if (v == NULL) {
14182 				scf_entry_destroy_children(e);
14183 				goto fail;
14184 			}
14185 			ret = scf_entry_add_value(e, v);
14186 			assert(ret == 0);
14187 		}
14188 		uu_list_walk_end(walk);
14189 
14190 		result = scf_transaction_commit(tx);
14191 
14192 		scf_transaction_reset(tx);
14193 		scf_entry_destroy_children(e);
14194 	} while (result == 0);
14195 
14196 	if (result < 0) {
14197 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14198 			scfdie();
14199 
14200 		semerr(emsg_permission_denied);
14201 		goto fail;
14202 	}
14203 
14204 	result = 0;
14205 
14206 	private_refresh();
14207 
14208 out:
14209 	scf_transaction_destroy(tx);
14210 	scf_entry_destroy(e);
14211 	scf_pg_destroy(pg);
14212 	scf_property_destroy(prop);
14213 	free(pattern);
14214 
14215 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14216 		free(sp->str);
14217 		free(sp);
14218 	}
14219 
14220 	uu_list_destroy(values);
14221 
14222 	return (result);
14223 
14224 fail:
14225 	result = -1;
14226 	goto out;
14227 }
14228 
14229 int
14230 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14231 {
14232 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14233 }
14234 
14235 int
14236 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14237 {
14238 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14239 }
14240 
14241 /*
14242  * Look for a standard start method, first in the instance (if any),
14243  * then the service.
14244  */
14245 static const char *
14246 start_method_name(int *in_instance)
14247 {
14248 	scf_propertygroup_t *pg;
14249 	char **p;
14250 	int ret;
14251 	scf_instance_t *inst = cur_inst;
14252 
14253 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14254 		scfdie();
14255 
14256 again:
14257 	for (p = start_method_names; *p != NULL; p++) {
14258 		if (inst != NULL)
14259 			ret = scf_instance_get_pg(inst, *p, pg);
14260 		else
14261 			ret = scf_service_get_pg(cur_svc, *p, pg);
14262 
14263 		if (ret == 0) {
14264 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14265 			char *buf = safe_malloc(bufsz);
14266 
14267 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14268 				free(buf);
14269 				continue;
14270 			}
14271 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14272 				free(buf);
14273 				continue;
14274 			}
14275 
14276 			free(buf);
14277 			*in_instance = (inst != NULL);
14278 			scf_pg_destroy(pg);
14279 			return (*p);
14280 		}
14281 
14282 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14283 			continue;
14284 
14285 		scfdie();
14286 	}
14287 
14288 	if (inst != NULL) {
14289 		inst = NULL;
14290 		goto again;
14291 	}
14292 
14293 	scf_pg_destroy(pg);
14294 	return (NULL);
14295 }
14296 
14297 static int
14298 addpg(const char *name, const char *type)
14299 {
14300 	scf_propertygroup_t *pg;
14301 	int ret;
14302 
14303 	pg = scf_pg_create(g_hndl);
14304 	if (pg == NULL)
14305 		scfdie();
14306 
14307 	if (cur_inst != NULL)
14308 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14309 	else
14310 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14311 
14312 	if (ret != 0) {
14313 		switch (scf_error()) {
14314 		case SCF_ERROR_EXISTS:
14315 			ret = 0;
14316 			break;
14317 
14318 		case SCF_ERROR_PERMISSION_DENIED:
14319 			semerr(emsg_permission_denied);
14320 			break;
14321 
14322 		default:
14323 			scfdie();
14324 		}
14325 	}
14326 
14327 	scf_pg_destroy(pg);
14328 	return (ret);
14329 }
14330 
14331 int
14332 lscf_setenv(uu_list_t *args, int isunset)
14333 {
14334 	int ret = 0;
14335 	size_t i;
14336 	int argc;
14337 	char **argv = NULL;
14338 	string_list_t *slp;
14339 	char *pattern;
14340 	char *prop;
14341 	int do_service = 0;
14342 	int do_instance = 0;
14343 	const char *method = NULL;
14344 	const char *name = NULL;
14345 	const char *value = NULL;
14346 	scf_instance_t *saved_cur_inst = cur_inst;
14347 
14348 	lscf_prep_hndl();
14349 
14350 	argc = uu_list_numnodes(args);
14351 	if (argc < 1)
14352 		goto usage;
14353 
14354 	argv = calloc(argc + 1, sizeof (char *));
14355 	if (argv == NULL)
14356 		uu_die(gettext("Out of memory.\n"));
14357 
14358 	for (slp = uu_list_first(args), i = 0;
14359 	    slp != NULL;
14360 	    slp = uu_list_next(args, slp), ++i)
14361 		argv[i] = slp->str;
14362 
14363 	argv[i] = NULL;
14364 
14365 	opterr = 0;
14366 	optind = 0;
14367 	for (;;) {
14368 		ret = getopt(argc, argv, "sim:");
14369 		if (ret == -1)
14370 			break;
14371 
14372 		switch (ret) {
14373 		case 's':
14374 			do_service = 1;
14375 			cur_inst = NULL;
14376 			break;
14377 
14378 		case 'i':
14379 			do_instance = 1;
14380 			break;
14381 
14382 		case 'm':
14383 			method = optarg;
14384 			break;
14385 
14386 		case '?':
14387 			goto usage;
14388 
14389 		default:
14390 			bad_error("getopt", ret);
14391 		}
14392 	}
14393 
14394 	argc -= optind;
14395 	if ((do_service && do_instance) ||
14396 	    (isunset && argc != 1) ||
14397 	    (!isunset && argc != 2))
14398 		goto usage;
14399 
14400 	name = argv[optind];
14401 	if (!isunset)
14402 		value = argv[optind + 1];
14403 
14404 	if (cur_snap != NULL) {
14405 		semerr(emsg_cant_modify_snapshots);
14406 		ret = -1;
14407 		goto out;
14408 	}
14409 
14410 	if (cur_inst == NULL && cur_svc == NULL) {
14411 		semerr(emsg_entity_not_selected);
14412 		ret = -1;
14413 		goto out;
14414 	}
14415 
14416 	if (do_instance && cur_inst == NULL) {
14417 		semerr(gettext("No instance is selected.\n"));
14418 		ret = -1;
14419 		goto out;
14420 	}
14421 
14422 	if (do_service && cur_svc == NULL) {
14423 		semerr(gettext("No service is selected.\n"));
14424 		ret = -1;
14425 		goto out;
14426 	}
14427 
14428 	if (method == NULL) {
14429 		if (do_instance || do_service) {
14430 			method = "method_context";
14431 			if (!isunset) {
14432 				ret = addpg("method_context",
14433 				    SCF_GROUP_FRAMEWORK);
14434 				if (ret != 0)
14435 					goto out;
14436 			}
14437 		} else {
14438 			int in_instance;
14439 			method = start_method_name(&in_instance);
14440 			if (method == NULL) {
14441 				semerr(gettext(
14442 				    "Couldn't find start method; please "
14443 				    "specify a method with '-m'.\n"));
14444 				ret = -1;
14445 				goto out;
14446 			}
14447 			if (!in_instance)
14448 				cur_inst = NULL;
14449 		}
14450 	} else {
14451 		scf_propertygroup_t *pg;
14452 		size_t bufsz;
14453 		char *buf;
14454 		int ret;
14455 
14456 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14457 			scfdie();
14458 
14459 		if (cur_inst != NULL)
14460 			ret = scf_instance_get_pg(cur_inst, method, pg);
14461 		else
14462 			ret = scf_service_get_pg(cur_svc, method, pg);
14463 
14464 		if (ret != 0) {
14465 			scf_pg_destroy(pg);
14466 			switch (scf_error()) {
14467 			case SCF_ERROR_NOT_FOUND:
14468 				semerr(gettext("Couldn't find the method "
14469 				    "\"%s\".\n"), method);
14470 				goto out;
14471 
14472 			case SCF_ERROR_INVALID_ARGUMENT:
14473 				semerr(gettext("Invalid method name \"%s\".\n"),
14474 				    method);
14475 				goto out;
14476 
14477 			default:
14478 				scfdie();
14479 			}
14480 		}
14481 
14482 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
14483 		buf = safe_malloc(bufsz);
14484 
14485 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14486 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
14487 			semerr(gettext("Property group \"%s\" is not of type "
14488 			    "\"method\".\n"), method);
14489 			ret = -1;
14490 			free(buf);
14491 			scf_pg_destroy(pg);
14492 			goto out;
14493 		}
14494 
14495 		free(buf);
14496 		scf_pg_destroy(pg);
14497 	}
14498 
14499 	prop = uu_msprintf("%s/environment", method);
14500 	pattern = uu_msprintf("%s=*", name);
14501 
14502 	if (prop == NULL || pattern == NULL)
14503 		uu_die(gettext("Out of memory.\n"));
14504 
14505 	ret = lscf_delpropvalue(prop, pattern, !isunset);
14506 
14507 	if (ret == 0 && !isunset) {
14508 		uu_free(pattern);
14509 		uu_free(prop);
14510 		prop = uu_msprintf("%s/environment", method);
14511 		pattern = uu_msprintf("%s=%s", name, value);
14512 		if (prop == NULL || pattern == NULL)
14513 			uu_die(gettext("Out of memory.\n"));
14514 		ret = lscf_addpropvalue(prop, "astring:", pattern);
14515 	}
14516 	uu_free(pattern);
14517 	uu_free(prop);
14518 
14519 out:
14520 	cur_inst = saved_cur_inst;
14521 
14522 	free(argv);
14523 	return (ret);
14524 usage:
14525 	ret = -2;
14526 	goto out;
14527 }
14528 
14529 /*
14530  * Snapshot commands
14531  */
14532 
14533 void
14534 lscf_listsnap()
14535 {
14536 	scf_snapshot_t *snap;
14537 	scf_iter_t *iter;
14538 	char *nb;
14539 	int r;
14540 
14541 	lscf_prep_hndl();
14542 
14543 	if (cur_inst == NULL) {
14544 		semerr(gettext("Instance not selected.\n"));
14545 		return;
14546 	}
14547 
14548 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14549 	    (iter = scf_iter_create(g_hndl)) == NULL)
14550 		scfdie();
14551 
14552 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
14553 		scfdie();
14554 
14555 	nb = safe_malloc(max_scf_name_len + 1);
14556 
14557 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
14558 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
14559 			scfdie();
14560 
14561 		(void) puts(nb);
14562 	}
14563 	if (r < 0)
14564 		scfdie();
14565 
14566 	free(nb);
14567 	scf_iter_destroy(iter);
14568 	scf_snapshot_destroy(snap);
14569 }
14570 
14571 void
14572 lscf_selectsnap(const char *name)
14573 {
14574 	scf_snapshot_t *snap;
14575 	scf_snaplevel_t *level;
14576 
14577 	lscf_prep_hndl();
14578 
14579 	if (cur_inst == NULL) {
14580 		semerr(gettext("Instance not selected.\n"));
14581 		return;
14582 	}
14583 
14584 	if (cur_snap != NULL) {
14585 		if (name != NULL) {
14586 			char *cur_snap_name;
14587 			boolean_t nochange;
14588 
14589 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
14590 
14591 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
14592 			    max_scf_name_len + 1) < 0)
14593 				scfdie();
14594 
14595 			nochange = strcmp(name, cur_snap_name) == 0;
14596 
14597 			free(cur_snap_name);
14598 
14599 			if (nochange)
14600 				return;
14601 		}
14602 
14603 		unselect_cursnap();
14604 	}
14605 
14606 	if (name == NULL)
14607 		return;
14608 
14609 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14610 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
14611 		scfdie();
14612 
14613 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
14614 	    SCF_SUCCESS) {
14615 		switch (scf_error()) {
14616 		case SCF_ERROR_INVALID_ARGUMENT:
14617 			semerr(gettext("Invalid name \"%s\".\n"), name);
14618 			break;
14619 
14620 		case SCF_ERROR_NOT_FOUND:
14621 			semerr(gettext("No such snapshot \"%s\".\n"), name);
14622 			break;
14623 
14624 		default:
14625 			scfdie();
14626 		}
14627 
14628 		scf_snaplevel_destroy(level);
14629 		scf_snapshot_destroy(snap);
14630 		return;
14631 	}
14632 
14633 	/* Load the snaplevels into our list. */
14634 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
14635 	if (cur_levels == NULL)
14636 		uu_die(gettext("Could not create list: %s\n"),
14637 		    uu_strerror(uu_error()));
14638 
14639 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14640 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14641 			scfdie();
14642 
14643 		semerr(gettext("Snapshot has no snaplevels.\n"));
14644 
14645 		scf_snaplevel_destroy(level);
14646 		scf_snapshot_destroy(snap);
14647 		return;
14648 	}
14649 
14650 	cur_snap = snap;
14651 
14652 	for (;;) {
14653 		cur_elt = safe_malloc(sizeof (*cur_elt));
14654 		uu_list_node_init(cur_elt, &cur_elt->list_node,
14655 		    snaplevel_pool);
14656 		cur_elt->sl = level;
14657 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
14658 			uu_die(gettext("libuutil error: %s\n"),
14659 			    uu_strerror(uu_error()));
14660 
14661 		level = scf_snaplevel_create(g_hndl);
14662 		if (level == NULL)
14663 			scfdie();
14664 
14665 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
14666 		    level) != SCF_SUCCESS) {
14667 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14668 				scfdie();
14669 
14670 			scf_snaplevel_destroy(level);
14671 			break;
14672 		}
14673 	}
14674 
14675 	cur_elt = uu_list_last(cur_levels);
14676 	cur_level = cur_elt->sl;
14677 }
14678 
14679 /*
14680  * Copies the properties & values in src to dst.  Assumes src won't change.
14681  * Returns -1 if permission is denied, -2 if another transaction interrupts,
14682  * and 0 on success.
14683  *
14684  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
14685  * property, if it is copied and has type boolean.  (See comment in
14686  * lscf_revert()).
14687  */
14688 static int
14689 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
14690     uint8_t enabled)
14691 {
14692 	scf_transaction_t *tx;
14693 	scf_iter_t *iter, *viter;
14694 	scf_property_t *prop;
14695 	scf_value_t *v;
14696 	char *nbuf;
14697 	int r;
14698 
14699 	tx = scf_transaction_create(g_hndl);
14700 	if (tx == NULL)
14701 		scfdie();
14702 
14703 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
14704 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14705 			scfdie();
14706 
14707 		scf_transaction_destroy(tx);
14708 
14709 		return (-1);
14710 	}
14711 
14712 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14713 	    (prop = scf_property_create(g_hndl)) == NULL ||
14714 	    (viter = scf_iter_create(g_hndl)) == NULL)
14715 		scfdie();
14716 
14717 	nbuf = safe_malloc(max_scf_name_len + 1);
14718 
14719 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
14720 		scfdie();
14721 
14722 	for (;;) {
14723 		scf_transaction_entry_t *e;
14724 		scf_type_t ty;
14725 
14726 		r = scf_iter_next_property(iter, prop);
14727 		if (r == -1)
14728 			scfdie();
14729 		if (r == 0)
14730 			break;
14731 
14732 		e = scf_entry_create(g_hndl);
14733 		if (e == NULL)
14734 			scfdie();
14735 
14736 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14737 			scfdie();
14738 
14739 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14740 			scfdie();
14741 
14742 		if (scf_transaction_property_new(tx, e, nbuf,
14743 		    ty) != SCF_SUCCESS)
14744 			scfdie();
14745 
14746 		if ((enabled == 0 || enabled == 1) &&
14747 		    strcmp(nbuf, scf_property_enabled) == 0 &&
14748 		    ty == SCF_TYPE_BOOLEAN) {
14749 			v = scf_value_create(g_hndl);
14750 			if (v == NULL)
14751 				scfdie();
14752 
14753 			scf_value_set_boolean(v, enabled);
14754 
14755 			if (scf_entry_add_value(e, v) != 0)
14756 				scfdie();
14757 		} else {
14758 			if (scf_iter_property_values(viter, prop) != 0)
14759 				scfdie();
14760 
14761 			for (;;) {
14762 				v = scf_value_create(g_hndl);
14763 				if (v == NULL)
14764 					scfdie();
14765 
14766 				r = scf_iter_next_value(viter, v);
14767 				if (r == -1)
14768 					scfdie();
14769 				if (r == 0) {
14770 					scf_value_destroy(v);
14771 					break;
14772 				}
14773 
14774 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14775 					scfdie();
14776 			}
14777 		}
14778 	}
14779 
14780 	free(nbuf);
14781 	scf_iter_destroy(viter);
14782 	scf_property_destroy(prop);
14783 	scf_iter_destroy(iter);
14784 
14785 	r = scf_transaction_commit(tx);
14786 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
14787 		scfdie();
14788 
14789 	scf_transaction_destroy_children(tx);
14790 	scf_transaction_destroy(tx);
14791 
14792 	switch (r) {
14793 	case 1:		return (0);
14794 	case 0:		return (-2);
14795 	case -1:	return (-1);
14796 
14797 	default:
14798 		abort();
14799 	}
14800 
14801 	/* NOTREACHED */
14802 }
14803 
14804 void
14805 lscf_revert(const char *snapname)
14806 {
14807 	scf_snapshot_t *snap, *prev;
14808 	scf_snaplevel_t *level, *nlevel;
14809 	scf_iter_t *iter;
14810 	scf_propertygroup_t *pg, *npg;
14811 	scf_property_t *prop;
14812 	scf_value_t *val;
14813 	char *nbuf, *tbuf;
14814 	uint8_t enabled;
14815 
14816 	lscf_prep_hndl();
14817 
14818 	if (cur_inst == NULL) {
14819 		semerr(gettext("Instance not selected.\n"));
14820 		return;
14821 	}
14822 
14823 	if (snapname != NULL) {
14824 		snap = scf_snapshot_create(g_hndl);
14825 		if (snap == NULL)
14826 			scfdie();
14827 
14828 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
14829 		    SCF_SUCCESS) {
14830 			switch (scf_error()) {
14831 			case SCF_ERROR_INVALID_ARGUMENT:
14832 				semerr(gettext("Invalid snapshot name "
14833 				    "\"%s\".\n"), snapname);
14834 				break;
14835 
14836 			case SCF_ERROR_NOT_FOUND:
14837 				semerr(gettext("No such snapshot.\n"));
14838 				break;
14839 
14840 			default:
14841 				scfdie();
14842 			}
14843 
14844 			scf_snapshot_destroy(snap);
14845 			return;
14846 		}
14847 	} else {
14848 		if (cur_snap != NULL) {
14849 			snap = cur_snap;
14850 		} else {
14851 			semerr(gettext("No snapshot selected.\n"));
14852 			return;
14853 		}
14854 	}
14855 
14856 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
14857 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
14858 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14859 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14860 	    (npg = scf_pg_create(g_hndl)) == NULL ||
14861 	    (prop = scf_property_create(g_hndl)) == NULL ||
14862 	    (val = scf_value_create(g_hndl)) == NULL)
14863 		scfdie();
14864 
14865 	nbuf = safe_malloc(max_scf_name_len + 1);
14866 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
14867 
14868 	/* Take the "previous" snapshot before we blow away the properties. */
14869 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
14870 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
14871 			scfdie();
14872 	} else {
14873 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14874 			scfdie();
14875 
14876 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
14877 			scfdie();
14878 	}
14879 
14880 	/* Save general/enabled, since we're probably going to replace it. */
14881 	enabled = 2;
14882 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
14883 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
14884 	    scf_property_get_value(prop, val) == 0)
14885 		(void) scf_value_get_boolean(val, &enabled);
14886 
14887 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14888 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14889 			scfdie();
14890 
14891 		goto out;
14892 	}
14893 
14894 	for (;;) {
14895 		boolean_t isinst;
14896 		uint32_t flags;
14897 		int r;
14898 
14899 		/* Clear the properties from the corresponding entity. */
14900 		isinst = snaplevel_is_instance(level);
14901 
14902 		if (!isinst)
14903 			r = scf_iter_service_pgs(iter, cur_svc);
14904 		else
14905 			r = scf_iter_instance_pgs(iter, cur_inst);
14906 		if (r != SCF_SUCCESS)
14907 			scfdie();
14908 
14909 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14910 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14911 				scfdie();
14912 
14913 			/* Skip nonpersistent pgs. */
14914 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
14915 				continue;
14916 
14917 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
14918 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14919 					scfdie();
14920 
14921 				semerr(emsg_permission_denied);
14922 				goto out;
14923 			}
14924 		}
14925 		if (r == -1)
14926 			scfdie();
14927 
14928 		/* Copy the properties to the corresponding entity. */
14929 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
14930 			scfdie();
14931 
14932 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14933 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
14934 				scfdie();
14935 
14936 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
14937 			    0)
14938 				scfdie();
14939 
14940 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14941 				scfdie();
14942 
14943 			if (!isinst)
14944 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
14945 				    flags, npg);
14946 			else
14947 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
14948 				    flags, npg);
14949 			if (r != SCF_SUCCESS) {
14950 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14951 					scfdie();
14952 
14953 				semerr(emsg_permission_denied);
14954 				goto out;
14955 			}
14956 
14957 			if ((enabled == 0 || enabled == 1) &&
14958 			    strcmp(nbuf, scf_pg_general) == 0)
14959 				r = pg_copy(pg, npg, enabled);
14960 			else
14961 				r = pg_copy(pg, npg, 2);
14962 
14963 			switch (r) {
14964 			case 0:
14965 				break;
14966 
14967 			case -1:
14968 				semerr(emsg_permission_denied);
14969 				goto out;
14970 
14971 			case -2:
14972 				semerr(gettext(
14973 				    "Interrupted by another change.\n"));
14974 				goto out;
14975 
14976 			default:
14977 				abort();
14978 			}
14979 		}
14980 		if (r == -1)
14981 			scfdie();
14982 
14983 		/* Get next level. */
14984 		nlevel = scf_snaplevel_create(g_hndl);
14985 		if (nlevel == NULL)
14986 			scfdie();
14987 
14988 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
14989 		    SCF_SUCCESS) {
14990 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14991 				scfdie();
14992 
14993 			scf_snaplevel_destroy(nlevel);
14994 			break;
14995 		}
14996 
14997 		scf_snaplevel_destroy(level);
14998 		level = nlevel;
14999 	}
15000 
15001 	if (snapname == NULL) {
15002 		lscf_selectsnap(NULL);
15003 		snap = NULL;		/* cur_snap has been destroyed */
15004 	}
15005 
15006 out:
15007 	free(tbuf);
15008 	free(nbuf);
15009 	scf_value_destroy(val);
15010 	scf_property_destroy(prop);
15011 	scf_pg_destroy(npg);
15012 	scf_pg_destroy(pg);
15013 	scf_iter_destroy(iter);
15014 	scf_snaplevel_destroy(level);
15015 	scf_snapshot_destroy(prev);
15016 	if (snap != cur_snap)
15017 		scf_snapshot_destroy(snap);
15018 }
15019 
15020 void
15021 lscf_refresh(void)
15022 {
15023 	ssize_t fmrilen;
15024 	size_t bufsz;
15025 	char *fmribuf;
15026 	int r;
15027 
15028 	lscf_prep_hndl();
15029 
15030 	if (cur_inst == NULL) {
15031 		semerr(gettext("Instance not selected.\n"));
15032 		return;
15033 	}
15034 
15035 	bufsz = max_scf_fmri_len + 1;
15036 	fmribuf = safe_malloc(bufsz);
15037 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15038 	if (fmrilen < 0) {
15039 		free(fmribuf);
15040 		if (scf_error() != SCF_ERROR_DELETED)
15041 			scfdie();
15042 		scf_instance_destroy(cur_inst);
15043 		cur_inst = NULL;
15044 		warn(emsg_deleted);
15045 		return;
15046 	}
15047 	assert(fmrilen < bufsz);
15048 
15049 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15050 	switch (r) {
15051 	case 0:
15052 		break;
15053 
15054 	case ECONNABORTED:
15055 		warn(gettext("Could not refresh %s "
15056 		    "(repository connection broken).\n"), fmribuf);
15057 		break;
15058 
15059 	case ECANCELED:
15060 		warn(emsg_deleted);
15061 		break;
15062 
15063 	case EPERM:
15064 		warn(gettext("Could not refresh %s "
15065 		    "(permission denied).\n"), fmribuf);
15066 		break;
15067 
15068 	case ENOSPC:
15069 		warn(gettext("Could not refresh %s "
15070 		    "(repository server out of resources).\n"),
15071 		    fmribuf);
15072 		break;
15073 
15074 	case EACCES:
15075 	default:
15076 		bad_error("refresh_entity", scf_error());
15077 	}
15078 
15079 	free(fmribuf);
15080 }
15081 
15082 /*
15083  * describe [-v] [-t] [pg/prop]
15084  */
15085 int
15086 lscf_describe(uu_list_t *args, int hasargs)
15087 {
15088 	int ret = 0;
15089 	size_t i;
15090 	int argc;
15091 	char **argv = NULL;
15092 	string_list_t *slp;
15093 	int do_verbose = 0;
15094 	int do_templates = 0;
15095 	char *pattern = NULL;
15096 
15097 	lscf_prep_hndl();
15098 
15099 	if (hasargs != 0)  {
15100 		argc = uu_list_numnodes(args);
15101 		if (argc < 1)
15102 			goto usage;
15103 
15104 		argv = calloc(argc + 1, sizeof (char *));
15105 		if (argv == NULL)
15106 			uu_die(gettext("Out of memory.\n"));
15107 
15108 		for (slp = uu_list_first(args), i = 0;
15109 		    slp != NULL;
15110 		    slp = uu_list_next(args, slp), ++i)
15111 			argv[i] = slp->str;
15112 
15113 		argv[i] = NULL;
15114 
15115 		/*
15116 		 * We start optind = 0 because our list of arguments
15117 		 * starts at argv[0]
15118 		 */
15119 		optind = 0;
15120 		opterr = 0;
15121 		for (;;) {
15122 			ret = getopt(argc, argv, "vt");
15123 			if (ret == -1)
15124 				break;
15125 
15126 			switch (ret) {
15127 			case 'v':
15128 				do_verbose = 1;
15129 				break;
15130 
15131 			case 't':
15132 				do_templates = 1;
15133 				break;
15134 
15135 			case '?':
15136 				goto usage;
15137 
15138 			default:
15139 				bad_error("getopt", ret);
15140 			}
15141 		}
15142 
15143 		pattern = argv[optind];
15144 	}
15145 
15146 	if (cur_inst == NULL && cur_svc == NULL) {
15147 		semerr(emsg_entity_not_selected);
15148 		ret = -1;
15149 		goto out;
15150 	}
15151 
15152 	/*
15153 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15154 	 * output if their last parameter is set to 2.  Less information is
15155 	 * produced if the parameter is set to 1.
15156 	 */
15157 	if (pattern == NULL) {
15158 		if (do_verbose == 1)
15159 			list_entity_tmpl(2);
15160 		else
15161 			list_entity_tmpl(1);
15162 	}
15163 
15164 	if (do_templates == 0) {
15165 		if (do_verbose == 1)
15166 			listprop(pattern, 0, 2);
15167 		else
15168 			listprop(pattern, 0, 1);
15169 	} else {
15170 		if (do_verbose == 1)
15171 			listtmpl(pattern, 2);
15172 		else
15173 			listtmpl(pattern, 1);
15174 	}
15175 
15176 	ret = 0;
15177 out:
15178 	if (argv != NULL)
15179 		free(argv);
15180 	return (ret);
15181 usage:
15182 	ret = -2;
15183 	goto out;
15184 }
15185 
15186 /*
15187  * Creates a list of instance name strings associated with a service. If
15188  * wohandcrafted flag is set, get only instances that have a last-import
15189  * snapshot, instances that were imported via svccfg.
15190  */
15191 static uu_list_t *
15192 create_instance_list(scf_service_t *svc, int wohandcrafted)
15193 {
15194 	scf_snapshot_t  *snap = NULL;
15195 	scf_instance_t  *inst;
15196 	scf_iter_t	*inst_iter;
15197 	uu_list_t	*instances;
15198 	char		*instname;
15199 	int		r;
15200 
15201 	inst_iter = scf_iter_create(g_hndl);
15202 	inst = scf_instance_create(g_hndl);
15203 	if (inst_iter == NULL || inst == NULL) {
15204 		uu_warn(gettext("Could not create instance or iterator\n"));
15205 		scfdie();
15206 	}
15207 
15208 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
15209 		return (instances);
15210 
15211 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
15212 		switch (scf_error()) {
15213 		case SCF_ERROR_CONNECTION_BROKEN:
15214 		case SCF_ERROR_DELETED:
15215 			uu_list_destroy(instances);
15216 			instances = NULL;
15217 			goto out;
15218 
15219 		case SCF_ERROR_HANDLE_MISMATCH:
15220 		case SCF_ERROR_NOT_BOUND:
15221 		case SCF_ERROR_NOT_SET:
15222 		default:
15223 			bad_error("scf_iter_service_instances", scf_error());
15224 		}
15225 	}
15226 
15227 	instname = safe_malloc(max_scf_name_len + 1);
15228 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
15229 		if (r == -1) {
15230 			(void) uu_warn(gettext("Unable to iterate through "
15231 			    "instances to create instance list : %s\n"),
15232 			    scf_strerror(scf_error()));
15233 
15234 			uu_list_destroy(instances);
15235 			instances = NULL;
15236 			goto out;
15237 		}
15238 
15239 		/*
15240 		 * If the instance does not have a last-import snapshot
15241 		 * then do not add it to the list as it is a hand-crafted
15242 		 * instance that should not be managed.
15243 		 */
15244 		if (wohandcrafted) {
15245 			if (snap == NULL &&
15246 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
15247 				uu_warn(gettext("Unable to create snapshot "
15248 				    "entity\n"));
15249 				scfdie();
15250 			}
15251 
15252 			if (scf_instance_get_snapshot(inst,
15253 			    snap_lastimport, snap) != 0) {
15254 				switch (scf_error()) {
15255 				case SCF_ERROR_NOT_FOUND :
15256 				case SCF_ERROR_DELETED:
15257 					continue;
15258 
15259 				case SCF_ERROR_CONNECTION_BROKEN:
15260 					uu_list_destroy(instances);
15261 					instances = NULL;
15262 					goto out;
15263 
15264 				case SCF_ERROR_HANDLE_MISMATCH:
15265 				case SCF_ERROR_NOT_BOUND:
15266 				case SCF_ERROR_NOT_SET:
15267 				default:
15268 					bad_error("scf_iter_service_instances",
15269 					    scf_error());
15270 				}
15271 			}
15272 		}
15273 
15274 		if (scf_instance_get_name(inst, instname,
15275 		    max_scf_name_len + 1) < 0) {
15276 			switch (scf_error()) {
15277 			case SCF_ERROR_NOT_FOUND :
15278 				continue;
15279 
15280 			case SCF_ERROR_CONNECTION_BROKEN:
15281 			case SCF_ERROR_DELETED:
15282 				uu_list_destroy(instances);
15283 				instances = NULL;
15284 				goto out;
15285 
15286 			case SCF_ERROR_HANDLE_MISMATCH:
15287 			case SCF_ERROR_NOT_BOUND:
15288 			case SCF_ERROR_NOT_SET:
15289 			default:
15290 				bad_error("scf_iter_service_instances",
15291 				    scf_error());
15292 			}
15293 		}
15294 
15295 		add_string(instances, instname);
15296 	}
15297 
15298 out:
15299 	if (snap)
15300 		scf_snapshot_destroy(snap);
15301 
15302 	scf_instance_destroy(inst);
15303 	scf_iter_destroy(inst_iter);
15304 	free(instname);
15305 	return (instances);
15306 }
15307 
15308 /*
15309  * disable an instance but wait for the instance to
15310  * move out of the running state.
15311  *
15312  * Returns 0 : if the instance did not disable
15313  * Returns non-zero : if the instance disabled.
15314  *
15315  */
15316 static int
15317 disable_instance(scf_instance_t *instance)
15318 {
15319 	char	*fmribuf;
15320 	int	enabled = 10000;
15321 
15322 	if (inst_is_running(instance)) {
15323 		fmribuf = safe_malloc(max_scf_name_len + 1);
15324 		if (scf_instance_to_fmri(instance, fmribuf,
15325 		    max_scf_name_len + 1) < 0) {
15326 			free(fmribuf);
15327 			return (0);
15328 		}
15329 
15330 		/*
15331 		 * If the instance cannot be disabled then return
15332 		 * failure to disable and let the caller decide
15333 		 * if that is of importance.
15334 		 */
15335 		if (smf_disable_instance(fmribuf, 0) != 0) {
15336 			free(fmribuf);
15337 			return (0);
15338 		}
15339 
15340 		while (enabled) {
15341 			if (!inst_is_running(instance))
15342 				break;
15343 
15344 			(void) poll(NULL, 0, 5);
15345 			enabled = enabled - 5;
15346 		}
15347 
15348 		free(fmribuf);
15349 	}
15350 
15351 	return (enabled);
15352 }
15353 
15354 /*
15355  * Function to compare two service_manifest structures.
15356  */
15357 /* ARGSUSED2 */
15358 static int
15359 service_manifest_compare(const void *left, const void *right, void *unused)
15360 {
15361 	service_manifest_t *l = (service_manifest_t *)left;
15362 	service_manifest_t *r = (service_manifest_t *)right;
15363 	int rc;
15364 
15365 	rc = strcmp(l->servicename, r->servicename);
15366 
15367 	return (rc);
15368 }
15369 
15370 /*
15371  * Look for the provided service in the service to manifest
15372  * tree.  If the service exists, and a manifest was provided
15373  * then add the manifest to that service.  If the service
15374  * does not exist, then add the service and manifest to the
15375  * list.
15376  *
15377  * If the manifest is NULL, return the element if found.  If
15378  * the service is not found return NULL.
15379  */
15380 service_manifest_t *
15381 find_add_svc_mfst(const char *svnbuf, const char *mfst)
15382 {
15383 	service_manifest_t	elem;
15384 	service_manifest_t	*fnelem;
15385 	uu_avl_index_t		marker;
15386 
15387 	elem.servicename = svnbuf;
15388 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
15389 
15390 	if (mfst) {
15391 		if (fnelem) {
15392 			add_string(fnelem->mfstlist, strdup(mfst));
15393 		} else {
15394 			fnelem = safe_malloc(sizeof (*fnelem));
15395 			fnelem->servicename = safe_strdup(svnbuf);
15396 			if ((fnelem->mfstlist =
15397 			    uu_list_create(string_pool, NULL, 0)) == NULL)
15398 				uu_die(gettext("Could not create property "
15399 				    "list: %s\n"), uu_strerror(uu_error()));
15400 
15401 			add_string(fnelem->mfstlist, safe_strdup(mfst));
15402 
15403 			uu_avl_insert(service_manifest_tree, fnelem, marker);
15404 		}
15405 	}
15406 
15407 	return (fnelem);
15408 }
15409 
15410 /*
15411  * Create the service to manifest avl tree.
15412  *
15413  * Walk each of the manifests currently installed in the supported
15414  * directories, /lib/svc/manifests and /var/svc/manifests.  For
15415  * each of the manifests, inventory the services and add them to
15416  * the tree.
15417  *
15418  * Code that calls this function should make sure fileystem/minimal is online,
15419  * /var is available, since this function walks the /var/svc/manifest directory.
15420  */
15421 static void
15422 create_manifest_tree(void)
15423 {
15424 	manifest_info_t **entry;
15425 	manifest_info_t **manifests;
15426 	uu_list_walk_t	*svcs;
15427 	bundle_t	*b;
15428 	entity_t	*mfsvc;
15429 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
15430 	int		c, status;
15431 
15432 	if (service_manifest_pool)
15433 		return;
15434 
15435 	/*
15436 	 * Create the list pool for the service manifest list
15437 	 */
15438 	service_manifest_pool = uu_avl_pool_create("service_manifest",
15439 	    sizeof (service_manifest_t),
15440 	    offsetof(service_manifest_t, svcmfst_node),
15441 	    service_manifest_compare, UU_DEFAULT);
15442 	if (service_manifest_pool == NULL)
15443 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
15444 		    uu_strerror(uu_error()));
15445 
15446 	/*
15447 	 * Create the list
15448 	 */
15449 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
15450 	    UU_DEFAULT);
15451 	if (service_manifest_tree == NULL)
15452 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
15453 		    uu_strerror(uu_error()));
15454 
15455 	/*
15456 	 * Walk the manifests adding the service(s) from each manifest.
15457 	 *
15458 	 * If a service already exists add the manifest to the manifest
15459 	 * list for that service.  This covers the case of a service that
15460 	 * is supported by multiple manifest files.
15461 	 */
15462 	for (c = 0; dirs[c]; c++) {
15463 		status = find_manifests(dirs[c], &manifests, CHECKEXT);
15464 		if (status < 0) {
15465 			uu_warn(gettext("file tree walk of %s encountered "
15466 			    "error %s\n"), dirs[c], strerror(errno));
15467 
15468 			uu_avl_destroy(service_manifest_tree);
15469 			service_manifest_tree = NULL;
15470 			return;
15471 		}
15472 
15473 		/*
15474 		 * If a manifest that was in the list is not found
15475 		 * then skip and go to the next manifest file.
15476 		 */
15477 		if (manifests != NULL) {
15478 			for (entry = manifests; *entry != NULL; entry++) {
15479 				b = internal_bundle_new();
15480 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
15481 				    SVCCFG_OP_IMPORT) != 0) {
15482 					internal_bundle_free(b);
15483 					continue;
15484 				}
15485 
15486 				svcs = uu_list_walk_start(b->sc_bundle_services,
15487 				    0);
15488 				if (svcs == NULL) {
15489 					internal_bundle_free(b);
15490 					continue;
15491 				}
15492 
15493 				while ((mfsvc = uu_list_walk_next(svcs)) !=
15494 				    NULL) {
15495 					/* Add manifest to service */
15496 					(void) find_add_svc_mfst(mfsvc->sc_name,
15497 					    (*entry)->mi_path);
15498 				}
15499 
15500 				uu_list_walk_end(svcs);
15501 				internal_bundle_free(b);
15502 			}
15503 
15504 			free_manifest_array(manifests);
15505 		}
15506 	}
15507 }
15508 
15509 /*
15510  * Check the manifest history file to see
15511  * if the service was ever installed from
15512  * one of the supported directories.
15513  *
15514  * Return Values :
15515  * 	-1 - if there's error reading manifest history file
15516  *	 1 - if the service is not found
15517  *	 0 - if the service is found
15518  */
15519 static int
15520 check_mfst_history(const char *svcname)
15521 {
15522 	struct stat	st;
15523 	caddr_t		mfsthist_start;
15524 	char		*svnbuf;
15525 	int		fd;
15526 	int		r = 1;
15527 
15528 	fd = open(MFSTHISTFILE, O_RDONLY);
15529 	if (fd == -1) {
15530 		uu_warn(gettext("Unable to open the history file\n"));
15531 		return (-1);
15532 	}
15533 
15534 	if (fstat(fd, &st) == -1) {
15535 		uu_warn(gettext("Unable to stat the history file\n"));
15536 		return (-1);
15537 	}
15538 
15539 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
15540 	    MAP_PRIVATE, fd, 0);
15541 
15542 	(void) close(fd);
15543 	if (mfsthist_start == MAP_FAILED ||
15544 	    *(mfsthist_start + st.st_size) != '\0') {
15545 		(void) munmap(mfsthist_start, st.st_size);
15546 		return (-1);
15547 	}
15548 
15549 	/*
15550 	 * The manifest history file is a space delimited list
15551 	 * of service and instance to manifest linkage.  Adding
15552 	 * a space to the end of the service name so to get only
15553 	 * the service that is being searched for.
15554 	 */
15555 	svnbuf = uu_msprintf("%s ", svcname);
15556 	if (svnbuf == NULL)
15557 		uu_die(gettext("Out of memory"));
15558 
15559 	if (strstr(mfsthist_start, svnbuf) != NULL)
15560 		r = 0;
15561 
15562 	(void) munmap(mfsthist_start, st.st_size);
15563 	uu_free(svnbuf);
15564 	return (r);
15565 }
15566 
15567 /*
15568  * Take down each of the instances in the service
15569  * and remove them, then delete the service.
15570  */
15571 static void
15572 teardown_service(scf_service_t *svc, const char *svnbuf)
15573 {
15574 	scf_instance_t	*instance;
15575 	scf_iter_t	*iter;
15576 	int		r;
15577 
15578 	safe_printf(gettext("Delete service %s as there are no "
15579 	    "supporting manifests\n"), svnbuf);
15580 
15581 	instance = scf_instance_create(g_hndl);
15582 	iter = scf_iter_create(g_hndl);
15583 	if (iter == NULL || instance == NULL) {
15584 		uu_warn(gettext("Unable to create supporting entities to "
15585 		    "teardown the service\n"));
15586 		uu_warn(gettext("scf error is : %s\n"),
15587 		    scf_strerror(scf_error()));
15588 		scfdie();
15589 	}
15590 
15591 	if (scf_iter_service_instances(iter, svc) != 0) {
15592 		switch (scf_error()) {
15593 		case SCF_ERROR_CONNECTION_BROKEN:
15594 		case SCF_ERROR_DELETED:
15595 			goto out;
15596 
15597 		case SCF_ERROR_HANDLE_MISMATCH:
15598 		case SCF_ERROR_NOT_BOUND:
15599 		case SCF_ERROR_NOT_SET:
15600 		default:
15601 			bad_error("scf_iter_service_instances",
15602 			    scf_error());
15603 		}
15604 	}
15605 
15606 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
15607 		if (r == -1) {
15608 			uu_warn(gettext("Error - %s\n"),
15609 			    scf_strerror(scf_error()));
15610 			goto out;
15611 		}
15612 
15613 		(void) disable_instance(instance);
15614 	}
15615 
15616 	/*
15617 	 * Delete the service... forcing the deletion in case
15618 	 * any of the instances did not disable.
15619 	 */
15620 	(void) lscf_service_delete(svc, 1);
15621 out:
15622 	scf_instance_destroy(instance);
15623 	scf_iter_destroy(iter);
15624 }
15625 
15626 /*
15627  * Get the list of instances supported by the manifest
15628  * file.
15629  *
15630  * Return 0 if there are no instances.
15631  *
15632  * Return -1 if there are errors attempting to collect instances.
15633  *
15634  * Return the count of instances found if there are no errors.
15635  *
15636  */
15637 static int
15638 check_instance_support(char *mfstfile, const char *svcname,
15639     uu_list_t *instances)
15640 {
15641 	uu_list_walk_t	*svcs, *insts;
15642 	uu_list_t	*ilist;
15643 	bundle_t	*b;
15644 	entity_t	*mfsvc, *mfinst;
15645 	const char	*svcn;
15646 	int		rminstcnt = 0;
15647 
15648 
15649 	b = internal_bundle_new();
15650 
15651 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
15652 		/*
15653 		 * Unable to process the manifest file for
15654 		 * instance support, so just return as
15655 		 * don't want to remove instances that could
15656 		 * not be accounted for that might exist here.
15657 		 */
15658 		internal_bundle_free(b);
15659 		return (0);
15660 	}
15661 
15662 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
15663 	if (svcs == NULL) {
15664 		internal_bundle_free(b);
15665 		return (0);
15666 	}
15667 
15668 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
15669 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
15670 
15671 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
15672 		if (strcmp(mfsvc->sc_name, svcn) == 0)
15673 			break;
15674 	}
15675 	uu_list_walk_end(svcs);
15676 
15677 	if (mfsvc == NULL) {
15678 		internal_bundle_free(b);
15679 		return (-1);
15680 	}
15681 
15682 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
15683 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
15684 		internal_bundle_free(b);
15685 		return (0);
15686 	}
15687 
15688 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
15689 		/*
15690 		 * Remove the instance from the instances list.
15691 		 * The unaccounted for instances will be removed
15692 		 * from the service once all manifests are
15693 		 * processed.
15694 		 */
15695 		(void) remove_string(instances,
15696 		    mfinst->sc_name);
15697 		rminstcnt++;
15698 	}
15699 
15700 	uu_list_walk_end(insts);
15701 	internal_bundle_free(b);
15702 
15703 	return (rminstcnt);
15704 }
15705 
15706 /*
15707  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
15708  * 'false' to indicate there's no manifest file(s) found for the service.
15709  */
15710 static void
15711 svc_add_no_support(scf_service_t *svc)
15712 {
15713 	char	*pname;
15714 
15715 	/* Add no support */
15716 	cur_svc = svc;
15717 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
15718 		return;
15719 
15720 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
15721 	if (pname == NULL)
15722 		uu_die(gettext("Out of memory.\n"));
15723 
15724 	(void) lscf_addpropvalue(pname, "boolean:", "0");
15725 
15726 	uu_free(pname);
15727 	cur_svc = NULL;
15728 }
15729 
15730 /*
15731  * This function handles all upgrade scenarios for a service that doesn't have
15732  * SCF_PG_MANIFESTFILES pg. The function creates and populates
15733  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
15734  * manifest(s) mapping. Manifests under supported directories are inventoried
15735  * and a property is added for each file that delivers configuration to the
15736  * service.  A service that has no corresponding manifest files (deleted) are
15737  * removed from repository.
15738  *
15739  * Unsupported services:
15740  *
15741  * A service is considered unsupported if there is no corresponding manifest
15742  * in the supported directories for that service and the service isn't in the
15743  * history file list.  The history file, MFSTHISTFILE, contains a list of all
15744  * services and instances that were delivered by Solaris before the introduction
15745  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
15746  * the path to the manifest file that defined the service or instance.
15747  *
15748  * Another type of unsupported services is 'handcrafted' services,
15749  * programmatically created services or services created by dependent entries
15750  * in other manifests. A handcrafted service is identified by its lack of any
15751  * instance containing last-import snapshot which is created during svccfg
15752  * import.
15753  *
15754  * This function sets a flag for unsupported services by setting services'
15755  * SCF_PG_MANIFESTFILES/support property to false.
15756  */
15757 static void
15758 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
15759 {
15760 	service_manifest_t	*elem;
15761 	uu_list_walk_t		*mfwalk;
15762 	string_list_t		*mfile;
15763 	uu_list_t		*instances;
15764 	const char		*sname;
15765 	char			*pname;
15766 	int			r;
15767 
15768 	/*
15769 	 * Since there's no guarantee manifests under /var are available during
15770 	 * early import, don't perform any upgrade during early import.
15771 	 */
15772 	if (IGNORE_VAR)
15773 		return;
15774 
15775 	if (service_manifest_tree == NULL) {
15776 		create_manifest_tree();
15777 	}
15778 
15779 	/*
15780 	 * Find service's supporting manifest(s) after
15781 	 * stripping off the svc:/ prefix that is part
15782 	 * of the fmri that is not used in the service
15783 	 * manifest bundle list.
15784 	 */
15785 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
15786 	    strlen(SCF_FMRI_SERVICE_PREFIX);
15787 	elem = find_add_svc_mfst(sname, NULL);
15788 	if (elem == NULL) {
15789 
15790 		/*
15791 		 * A handcrafted service, one that has no instance containing
15792 		 * last-import snapshot, should get unsupported flag.
15793 		 */
15794 		instances = create_instance_list(svc, 1);
15795 		if (instances == NULL) {
15796 			uu_warn(gettext("Unable to create instance list %s\n"),
15797 			    svcname);
15798 			return;
15799 		}
15800 
15801 		if (uu_list_numnodes(instances) == 0) {
15802 			svc_add_no_support(svc);
15803 			return;
15804 		}
15805 
15806 		/*
15807 		 * If the service is in the history file, and its supporting
15808 		 * manifests are not found, we can safely delete the service
15809 		 * because its manifests are removed from the system.
15810 		 *
15811 		 * Services not found in the history file are not delivered by
15812 		 * Solaris and/or delivered outside supported directories, set
15813 		 * unsupported flag for these services.
15814 		 */
15815 		r = check_mfst_history(svcname);
15816 		if (r == -1)
15817 			return;
15818 
15819 		if (r) {
15820 			/* Set unsupported flag for service  */
15821 			svc_add_no_support(svc);
15822 		} else {
15823 			/* Delete the service */
15824 			teardown_service(svc, svcname);
15825 		}
15826 
15827 		return;
15828 	}
15829 
15830 	/*
15831 	 * Walk through the list of manifests and add them
15832 	 * to the service.
15833 	 *
15834 	 * Create a manifestfiles pg and add the property.
15835 	 */
15836 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
15837 	if (mfwalk == NULL)
15838 		return;
15839 
15840 	cur_svc = svc;
15841 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
15842 	if (r != 0) {
15843 		cur_svc = NULL;
15844 		return;
15845 	}
15846 
15847 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
15848 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
15849 		    mhash_filename_to_propname(mfile->str, 0));
15850 		if (pname == NULL)
15851 			uu_die(gettext("Out of memory.\n"));
15852 
15853 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
15854 		uu_free(pname);
15855 	}
15856 	uu_list_walk_end(mfwalk);
15857 
15858 	cur_svc = NULL;
15859 }
15860 
15861 /*
15862  * Take a service and process the manifest file entires to see if
15863  * there is continued support for the service and instances.  If
15864  * not cleanup as appropriate.
15865  *
15866  * If a service does not have a manifest files entry flag it for
15867  * upgrade and return.
15868  *
15869  * For each manifestfiles property check if the manifest file is
15870  * under the supported /lib/svc/manifest or /var/svc/manifest path
15871  * and if not then return immediately as this service is not supported
15872  * by the cleanup mechanism and should be ignored.
15873  *
15874  * For each manifest file that is supported, check to see if the
15875  * file exists.  If not then remove the manifest file property
15876  * from the service and the smf/manifest hash table.  If the manifest
15877  * file exists then verify that it supports the instances that are
15878  * part of the service.
15879  *
15880  * Once all manifest files have been accounted for remove any instances
15881  * that are no longer supported in the service.
15882  *
15883  * Return values :
15884  * 0 - Successfully processed the service
15885  * non-zero - failed to process the service
15886  *
15887  * On most errors, will just return to wait and get the next service,
15888  * unless in case of unable to create the needed structures which is
15889  * most likely a fatal error that is not going to be recoverable.
15890  */
15891 int
15892 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
15893 {
15894 	struct mpg_mfile	*mpntov;
15895 	struct mpg_mfile	**mpvarry = NULL;
15896 	scf_service_t		*svc;
15897 	scf_propertygroup_t	*mpg;
15898 	scf_property_t		*mp;
15899 	scf_value_t		*mv;
15900 	scf_iter_t		*mi;
15901 	scf_instance_t		*instance;
15902 	uu_list_walk_t		*insts;
15903 	uu_list_t		*instances = NULL;
15904 	boolean_t		activity = (boolean_t)act;
15905 	char			*mpnbuf;
15906 	char			*mpvbuf;
15907 	char			*pgpropbuf;
15908 	int			mfstcnt, rminstct, instct, mfstmax;
15909 	int			index;
15910 	int			r = 0;
15911 
15912 	assert(g_hndl != NULL);
15913 	assert(wip->svc != NULL);
15914 	assert(wip->fmri != NULL);
15915 
15916 	svc = wip->svc;
15917 
15918 	mpg = scf_pg_create(g_hndl);
15919 	mp = scf_property_create(g_hndl);
15920 	mi = scf_iter_create(g_hndl);
15921 	mv = scf_value_create(g_hndl);
15922 	instance = scf_instance_create(g_hndl);
15923 
15924 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
15925 	    instance == NULL) {
15926 		uu_warn(gettext("Unable to create the supporting entities\n"));
15927 		uu_warn(gettext("scf error is : %s\n"),
15928 		    scf_strerror(scf_error()));
15929 		scfdie();
15930 	}
15931 
15932 	/*
15933 	 * Get the manifestfiles property group to be parsed for
15934 	 * files existence.
15935 	 */
15936 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
15937 		switch (scf_error()) {
15938 		case SCF_ERROR_NOT_FOUND:
15939 			upgrade_svc_mfst_connection(svc, wip->fmri);
15940 			break;
15941 		case SCF_ERROR_DELETED:
15942 		case SCF_ERROR_CONNECTION_BROKEN:
15943 			goto out;
15944 
15945 		case SCF_ERROR_HANDLE_MISMATCH:
15946 		case SCF_ERROR_NOT_BOUND:
15947 		case SCF_ERROR_NOT_SET:
15948 		default:
15949 			bad_error("scf_iter_pg_properties",
15950 			    scf_error());
15951 		}
15952 
15953 		goto out;
15954 	}
15955 
15956 	/*
15957 	 * Iterate through each of the manifestfiles properties
15958 	 * to determine what manifestfiles are available.
15959 	 *
15960 	 * If a manifest file is supported then increment the
15961 	 * count and therefore the service is safe.
15962 	 */
15963 	if (scf_iter_pg_properties(mi, mpg) != 0) {
15964 		switch (scf_error()) {
15965 		case SCF_ERROR_DELETED:
15966 		case SCF_ERROR_CONNECTION_BROKEN:
15967 			goto out;
15968 
15969 		case SCF_ERROR_HANDLE_MISMATCH:
15970 		case SCF_ERROR_NOT_BOUND:
15971 		case SCF_ERROR_NOT_SET:
15972 		default:
15973 			bad_error("scf_iter_pg_properties",
15974 			    scf_error());
15975 		}
15976 	}
15977 
15978 	mfstcnt = 0;
15979 	mfstmax = MFSTFILE_MAX;
15980 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
15981 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
15982 		if (r == -1)
15983 			bad_error(gettext("Unable to iterate through "
15984 			    "manifestfiles properties : %s"),
15985 			    scf_error());
15986 
15987 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
15988 		mpnbuf = safe_malloc(max_scf_name_len + 1);
15989 		mpvbuf = safe_malloc(max_scf_value_len + 1);
15990 		mpntov->mpg = mpnbuf;
15991 		mpntov->mfile = mpvbuf;
15992 		mpntov->access = 1;
15993 		if (scf_property_get_name(mp, mpnbuf,
15994 		    max_scf_name_len + 1) < 0) {
15995 			uu_warn(gettext("Unable to get manifest file "
15996 			    "property : %s\n"),
15997 			    scf_strerror(scf_error()));
15998 
15999 			switch (scf_error()) {
16000 			case SCF_ERROR_DELETED:
16001 			case SCF_ERROR_CONNECTION_BROKEN:
16002 				r = scferror2errno(scf_error());
16003 				goto out_free;
16004 
16005 			case SCF_ERROR_HANDLE_MISMATCH:
16006 			case SCF_ERROR_NOT_BOUND:
16007 			case SCF_ERROR_NOT_SET:
16008 			default:
16009 				bad_error("scf_iter_pg_properties",
16010 				    scf_error());
16011 			}
16012 		}
16013 
16014 		/*
16015 		 * The support property is a boolean value that indicates
16016 		 * if the service is supported for manifest file deletion.
16017 		 * Currently at this time there is no code that sets this
16018 		 * value to true.  So while we could just let this be caught
16019 		 * by the support check below, in the future this by be set
16020 		 * to true and require processing.  So for that, go ahead
16021 		 * and check here, and just return if false.  Otherwise,
16022 		 * fall through expecting that other support checks will
16023 		 * handle the entries.
16024 		 */
16025 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
16026 			uint8_t	support;
16027 
16028 			if (scf_property_get_value(mp, mv) != 0 ||
16029 			    scf_value_get_boolean(mv, &support) != 0) {
16030 				uu_warn(gettext("Unable to get the manifest "
16031 				    "support value: %s\n"),
16032 				    scf_strerror(scf_error()));
16033 
16034 				switch (scf_error()) {
16035 				case SCF_ERROR_DELETED:
16036 				case SCF_ERROR_CONNECTION_BROKEN:
16037 					r = scferror2errno(scf_error());
16038 					goto out_free;
16039 
16040 				case SCF_ERROR_HANDLE_MISMATCH:
16041 				case SCF_ERROR_NOT_BOUND:
16042 				case SCF_ERROR_NOT_SET:
16043 				default:
16044 					bad_error("scf_iter_pg_properties",
16045 					    scf_error());
16046 				}
16047 			}
16048 
16049 			if (support == B_FALSE)
16050 				goto out_free;
16051 		}
16052 
16053 		/*
16054 		 * Anything with a manifest outside of the supported
16055 		 * directories, immediately bail out because that makes
16056 		 * this service non-supported.  We don't even want
16057 		 * to do instance processing in this case because the
16058 		 * instances could be part of the non-supported manifest.
16059 		 */
16060 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
16061 			/*
16062 			 * Manifest is not in /lib/svc, so we need to
16063 			 * consider the /var/svc case.
16064 			 */
16065 			if (strncmp(mpnbuf, VARSVC_PR,
16066 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
16067 				/*
16068 				 * Either the manifest is not in /var/svc or
16069 				 * /var is not yet mounted.  We ignore the
16070 				 * manifest either because it is not in a
16071 				 * standard location or because we cannot
16072 				 * currently access the manifest.
16073 				 */
16074 				goto out_free;
16075 			}
16076 		}
16077 
16078 		/*
16079 		 * Get the value to of the manifest file for this entry
16080 		 * for access verification and instance support
16081 		 * verification if it still exists.
16082 		 *
16083 		 * During Early Manifest Import if the manifest is in
16084 		 * /var/svc then it may not yet be available for checking
16085 		 * so we must determine if /var/svc is available.  If not
16086 		 * then defer until Late Manifest Import to cleanup.
16087 		 */
16088 		if (scf_property_get_value(mp, mv) != 0) {
16089 			uu_warn(gettext("Unable to get the manifest file "
16090 			    "value: %s\n"),
16091 			    scf_strerror(scf_error()));
16092 
16093 			switch (scf_error()) {
16094 			case SCF_ERROR_DELETED:
16095 			case SCF_ERROR_CONNECTION_BROKEN:
16096 				r = scferror2errno(scf_error());
16097 				goto out_free;
16098 
16099 			case SCF_ERROR_HANDLE_MISMATCH:
16100 			case SCF_ERROR_NOT_BOUND:
16101 			case SCF_ERROR_NOT_SET:
16102 			default:
16103 				bad_error("scf_property_get_value",
16104 				    scf_error());
16105 			}
16106 		}
16107 
16108 		if (scf_value_get_astring(mv, mpvbuf,
16109 		    max_scf_value_len + 1) < 0) {
16110 			uu_warn(gettext("Unable to get the manifest "
16111 			    "file : %s\n"),
16112 			    scf_strerror(scf_error()));
16113 
16114 			switch (scf_error()) {
16115 			case SCF_ERROR_DELETED:
16116 			case SCF_ERROR_CONNECTION_BROKEN:
16117 				r = scferror2errno(scf_error());
16118 				goto out_free;
16119 
16120 			case SCF_ERROR_HANDLE_MISMATCH:
16121 			case SCF_ERROR_NOT_BOUND:
16122 			case SCF_ERROR_NOT_SET:
16123 			default:
16124 				bad_error("scf_value_get_astring",
16125 				    scf_error());
16126 			}
16127 		}
16128 
16129 		mpvarry[mfstcnt] = mpntov;
16130 		mfstcnt++;
16131 
16132 		/*
16133 		 * Check for the need to reallocate array
16134 		 */
16135 		if (mfstcnt >= (mfstmax - 1)) {
16136 			struct mpg_mfile **newmpvarry;
16137 
16138 			mfstmax = mfstmax * 2;
16139 			newmpvarry = realloc(mpvarry,
16140 			    sizeof (struct mpg_mfile *) * mfstmax);
16141 
16142 			if (newmpvarry == NULL)
16143 				goto out_free;
16144 
16145 			mpvarry = newmpvarry;
16146 		}
16147 
16148 		mpvarry[mfstcnt] = NULL;
16149 	}
16150 
16151 	for (index = 0; mpvarry[index]; index++) {
16152 		mpntov = mpvarry[index];
16153 
16154 		/*
16155 		 * Check to see if the manifestfile is accessable, if so hand
16156 		 * this service and manifestfile off to be processed for
16157 		 * instance support.
16158 		 */
16159 		mpnbuf = mpntov->mpg;
16160 		mpvbuf = mpntov->mfile;
16161 		if (access(mpvbuf, F_OK) != 0) {
16162 			mpntov->access = 0;
16163 			activity++;
16164 			mfstcnt--;
16165 			/* Remove the entry from the service */
16166 			cur_svc = svc;
16167 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16168 			    mpnbuf);
16169 			if (pgpropbuf == NULL)
16170 				uu_die(gettext("Out of memory.\n"));
16171 
16172 			lscf_delprop(pgpropbuf);
16173 			cur_svc = NULL;
16174 
16175 			uu_free(pgpropbuf);
16176 		}
16177 	}
16178 
16179 	/*
16180 	 * If mfstcnt is 0, none of the manifests that supported the service
16181 	 * existed so remove the service.
16182 	 */
16183 	if (mfstcnt == 0) {
16184 		teardown_service(svc, wip->fmri);
16185 
16186 		goto out_free;
16187 	}
16188 
16189 	if (activity) {
16190 		int	nosvcsupport = 0;
16191 
16192 		/*
16193 		 * If the list of service instances is NULL then
16194 		 * create the list.
16195 		 */
16196 		instances = create_instance_list(svc, 1);
16197 		if (instances == NULL) {
16198 			uu_warn(gettext("Unable to create instance list %s\n"),
16199 			    wip->fmri);
16200 			goto out_free;
16201 		}
16202 
16203 		rminstct = uu_list_numnodes(instances);
16204 		instct = rminstct;
16205 
16206 		for (index = 0; mpvarry[index]; index++) {
16207 			mpntov = mpvarry[index];
16208 			if (mpntov->access == 0)
16209 				continue;
16210 
16211 			mpnbuf = mpntov->mpg;
16212 			mpvbuf = mpntov->mfile;
16213 			r = check_instance_support(mpvbuf, wip->fmri,
16214 			    instances);
16215 			if (r == -1) {
16216 				nosvcsupport++;
16217 			} else {
16218 				rminstct -= r;
16219 			}
16220 		}
16221 
16222 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
16223 			teardown_service(svc, wip->fmri);
16224 
16225 			goto out_free;
16226 		}
16227 	}
16228 
16229 	/*
16230 	 * If there are instances left on the instance list, then
16231 	 * we must remove them.
16232 	 */
16233 	if (instances != NULL && uu_list_numnodes(instances)) {
16234 		string_list_t *sp;
16235 
16236 		insts = uu_list_walk_start(instances, 0);
16237 		while ((sp = uu_list_walk_next(insts)) != NULL) {
16238 			/*
16239 			 * Remove the instance from the instances list.
16240 			 */
16241 			safe_printf(gettext("Delete instance %s from "
16242 			    "service %s\n"), sp->str, wip->fmri);
16243 			if (scf_service_get_instance(svc, sp->str,
16244 			    instance) != SCF_SUCCESS) {
16245 				(void) uu_warn("scf_error - %s\n",
16246 				    scf_strerror(scf_error()));
16247 
16248 				continue;
16249 			}
16250 
16251 			(void) disable_instance(instance);
16252 
16253 			(void) lscf_instance_delete(instance, 1);
16254 		}
16255 		scf_instance_destroy(instance);
16256 		uu_list_walk_end(insts);
16257 	}
16258 
16259 out_free:
16260 	if (mpvarry) {
16261 		struct mpg_mfile *fmpntov;
16262 
16263 		for (index = 0; mpvarry[index]; index++) {
16264 			fmpntov  = mpvarry[index];
16265 			if (fmpntov->mpg == mpnbuf)
16266 				mpnbuf = NULL;
16267 			free(fmpntov->mpg);
16268 
16269 			if (fmpntov->mfile == mpvbuf)
16270 				mpvbuf = NULL;
16271 			free(fmpntov->mfile);
16272 
16273 			if (fmpntov == mpntov)
16274 				mpntov = NULL;
16275 			free(fmpntov);
16276 		}
16277 		if (mpnbuf)
16278 			free(mpnbuf);
16279 		if (mpvbuf)
16280 			free(mpvbuf);
16281 		if (mpntov)
16282 			free(mpntov);
16283 
16284 		free(mpvarry);
16285 	}
16286 out:
16287 	scf_pg_destroy(mpg);
16288 	scf_property_destroy(mp);
16289 	scf_iter_destroy(mi);
16290 	scf_value_destroy(mv);
16291 
16292 	return (0);
16293 }
16294 
16295 /*
16296  * Take the service and search for the manifestfiles property
16297  * in each of the property groups.  If the manifest file
16298  * associated with the property does not exist then remove
16299  * the property group.
16300  */
16301 int
16302 lscf_hash_cleanup()
16303 {
16304 	scf_service_t		*svc;
16305 	scf_scope_t		*scope;
16306 	scf_propertygroup_t	*pg;
16307 	scf_property_t		*prop;
16308 	scf_value_t		*val;
16309 	scf_iter_t		*iter;
16310 	char			*pgname;
16311 	char			*mfile;
16312 	int			r;
16313 
16314 	svc = scf_service_create(g_hndl);
16315 	scope = scf_scope_create(g_hndl);
16316 	pg = scf_pg_create(g_hndl);
16317 	prop = scf_property_create(g_hndl);
16318 	val = scf_value_create(g_hndl);
16319 	iter = scf_iter_create(g_hndl);
16320 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
16321 	    svc == NULL || scope == NULL) {
16322 		uu_warn(gettext("Unable to create a property group, or "
16323 		    "property\n"));
16324 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
16325 		    "pg is not NULL");
16326 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
16327 		    "prop is not NULL");
16328 		uu_warn("%s\n", val == NULL ? "val is NULL" :
16329 		    "val is not NULL");
16330 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
16331 		    "iter is not NULL");
16332 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
16333 		    "svc is not NULL");
16334 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
16335 		    "scope is not NULL");
16336 		uu_warn(gettext("scf error is : %s\n"),
16337 		    scf_strerror(scf_error()));
16338 		scfdie();
16339 	}
16340 
16341 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
16342 		switch (scf_error()) {
16343 		case SCF_ERROR_CONNECTION_BROKEN:
16344 		case SCF_ERROR_NOT_FOUND:
16345 			goto out;
16346 
16347 		case SCF_ERROR_HANDLE_MISMATCH:
16348 		case SCF_ERROR_NOT_BOUND:
16349 		case SCF_ERROR_INVALID_ARGUMENT:
16350 		default:
16351 			bad_error("scf_handle_get_scope", scf_error());
16352 		}
16353 	}
16354 
16355 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
16356 		uu_warn(gettext("Unable to process the hash service, %s\n"),
16357 		    HASH_SVC);
16358 		goto out;
16359 	}
16360 
16361 	pgname = safe_malloc(max_scf_name_len + 1);
16362 	mfile = safe_malloc(max_scf_value_len + 1);
16363 
16364 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
16365 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
16366 		    scf_strerror(scf_error()));
16367 		goto out;
16368 	}
16369 
16370 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
16371 		if (r == -1)
16372 			goto out;
16373 
16374 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
16375 			switch (scf_error()) {
16376 			case SCF_ERROR_DELETED:
16377 				return (ENODEV);
16378 
16379 			case SCF_ERROR_CONNECTION_BROKEN:
16380 				return (ECONNABORTED);
16381 
16382 			case SCF_ERROR_NOT_SET:
16383 			case SCF_ERROR_NOT_BOUND:
16384 			default:
16385 				bad_error("scf_pg_get_name", scf_error());
16386 			}
16387 		}
16388 		if (IGNORE_VAR) {
16389 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
16390 				continue;
16391 		}
16392 
16393 		/*
16394 		 * If unable to get the property continue as this is an
16395 		 * entry that has no location to check against.
16396 		 */
16397 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
16398 			continue;
16399 		}
16400 
16401 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
16402 			uu_warn(gettext("Unable to get value from %s\n"),
16403 			    pgname);
16404 			goto error_handle;
16405 		}
16406 
16407 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) ==
16408 		    -1) {
16409 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
16410 			    pgname, scf_strerror(scf_error()));
16411 			goto error_handle;
16412 		}
16413 
16414 		if (access(mfile, F_OK) == 0)
16415 			continue;
16416 
16417 		(void) scf_pg_delete(pg);
16418 
16419 error_handle:
16420 		switch (scf_error()) {
16421 		case SCF_ERROR_DELETED:
16422 		case SCF_ERROR_CONSTRAINT_VIOLATED:
16423 		case SCF_ERROR_NOT_FOUND:
16424 		case SCF_ERROR_NOT_SET:
16425 			continue;
16426 
16427 		case SCF_ERROR_CONNECTION_BROKEN:
16428 			r = scferror2errno(scf_error());
16429 			goto out;
16430 
16431 		case SCF_ERROR_HANDLE_MISMATCH:
16432 		case SCF_ERROR_NOT_BOUND:
16433 		default:
16434 			bad_error("scf_value_get_astring",
16435 			    scf_error());
16436 		}
16437 	}
16438 
16439 out:
16440 	scf_scope_destroy(scope);
16441 	scf_service_destroy(svc);
16442 	scf_pg_destroy(pg);
16443 	scf_property_destroy(prop);
16444 	scf_value_destroy(val);
16445 	scf_iter_destroy(iter);
16446 	free(pgname);
16447 	free(mfile);
16448 
16449 	return (0);
16450 }
16451 
16452 #ifndef NATIVE_BUILD
16453 /* ARGSUSED */
16454 CPL_MATCH_FN(complete_select)
16455 {
16456 	const char *arg0, *arg1, *arg1end;
16457 	int word_start, err = 0, r;
16458 	size_t len;
16459 	char *buf;
16460 
16461 	lscf_prep_hndl();
16462 
16463 	arg0 = line + strspn(line, " \t");
16464 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
16465 
16466 	arg1 = arg0 + sizeof ("select") - 1;
16467 	arg1 += strspn(arg1, " \t");
16468 	word_start = arg1 - line;
16469 
16470 	arg1end = arg1 + strcspn(arg1, " \t");
16471 	if (arg1end < line + word_end)
16472 		return (0);
16473 
16474 	len = line + word_end - arg1;
16475 
16476 	buf = safe_malloc(max_scf_name_len + 1);
16477 
16478 	if (cur_snap != NULL) {
16479 		return (0);
16480 	} else if (cur_inst != NULL) {
16481 		return (0);
16482 	} else if (cur_svc != NULL) {
16483 		scf_instance_t *inst;
16484 		scf_iter_t *iter;
16485 
16486 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
16487 		    (iter = scf_iter_create(g_hndl)) == NULL)
16488 			scfdie();
16489 
16490 		if (scf_iter_service_instances(iter, cur_svc) != 0)
16491 			scfdie();
16492 
16493 		for (;;) {
16494 			r = scf_iter_next_instance(iter, inst);
16495 			if (r == 0)
16496 				break;
16497 			if (r != 1)
16498 				scfdie();
16499 
16500 			if (scf_instance_get_name(inst, buf,
16501 			    max_scf_name_len + 1) < 0)
16502 				scfdie();
16503 
16504 			if (strncmp(buf, arg1, len) == 0) {
16505 				err = cpl_add_completion(cpl, line, word_start,
16506 				    word_end, buf + len, "", " ");
16507 				if (err != 0)
16508 					break;
16509 			}
16510 		}
16511 
16512 		scf_iter_destroy(iter);
16513 		scf_instance_destroy(inst);
16514 
16515 		return (err);
16516 	} else {
16517 		scf_service_t *svc;
16518 		scf_iter_t *iter;
16519 
16520 		assert(cur_scope != NULL);
16521 
16522 		if ((svc = scf_service_create(g_hndl)) == NULL ||
16523 		    (iter = scf_iter_create(g_hndl)) == NULL)
16524 			scfdie();
16525 
16526 		if (scf_iter_scope_services(iter, cur_scope) != 0)
16527 			scfdie();
16528 
16529 		for (;;) {
16530 			r = scf_iter_next_service(iter, svc);
16531 			if (r == 0)
16532 				break;
16533 			if (r != 1)
16534 				scfdie();
16535 
16536 			if (scf_service_get_name(svc, buf,
16537 			    max_scf_name_len + 1) < 0)
16538 				scfdie();
16539 
16540 			if (strncmp(buf, arg1, len) == 0) {
16541 				err = cpl_add_completion(cpl, line, word_start,
16542 				    word_end, buf + len, "", " ");
16543 				if (err != 0)
16544 					break;
16545 			}
16546 		}
16547 
16548 		scf_iter_destroy(iter);
16549 		scf_service_destroy(svc);
16550 
16551 		return (err);
16552 	}
16553 }
16554 
16555 /* ARGSUSED */
16556 CPL_MATCH_FN(complete_command)
16557 {
16558 	uint32_t scope = 0;
16559 
16560 	if (cur_snap != NULL)
16561 		scope = CS_SNAP;
16562 	else if (cur_inst != NULL)
16563 		scope = CS_INST;
16564 	else if (cur_svc != NULL)
16565 		scope = CS_SVC;
16566 	else
16567 		scope = CS_SCOPE;
16568 
16569 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
16570 }
16571 #endif	/* NATIVE_BUILD */
16572