xref: /titanic_50/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision e6eb57e72471348376359efe9105d50bf487a312)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <alloca.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <door.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <fnmatch.h>
35 #include <inttypes.h>
36 #include <libintl.h>
37 #include <libscf.h>
38 #include <libscf_priv.h>
39 #include <libtecla.h>
40 #include <libuutil.h>
41 #include <limits.h>
42 #include <locale.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <strings.h>
46 #include <unistd.h>
47 #include <wait.h>
48 
49 #include <libxml/tree.h>
50 
51 #include "svccfg.h"
52 #include "manifest_hash.h"
53 
54 /* The colon namespaces in each entity (each followed by a newline). */
55 #define	COLON_NAMESPACES	":properties\n"
56 
57 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
58 
59 /* These are characters which the lexer requires to be in double-quotes. */
60 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
61 
62 #define	HASH_SIZE		16
63 #define	HASH_SVC		"smf/manifest"
64 #define	HASH_PG_TYPE		"framework"
65 #define	HASH_PG_FLAGS		0
66 #define	HASH_PROP		"md5sum"
67 
68 /*
69  * Indentation used in the output of the describe subcommand.
70  */
71 #define	TMPL_VALUE_INDENT	"  "
72 #define	TMPL_INDENT		"    "
73 #define	TMPL_INDENT_2X		"        "
74 #define	TMPL_CHOICE_INDENT	"      "
75 
76 /*
77  * These are the classes of elements which may appear as children of service
78  * or instance elements in XML manifests.
79  */
80 struct entity_elts {
81 	xmlNodePtr	create_default_instance;
82 	xmlNodePtr	single_instance;
83 	xmlNodePtr	restarter;
84 	xmlNodePtr	dependencies;
85 	xmlNodePtr	dependents;
86 	xmlNodePtr	method_context;
87 	xmlNodePtr	exec_methods;
88 	xmlNodePtr	property_groups;
89 	xmlNodePtr	instances;
90 	xmlNodePtr	stability;
91 	xmlNodePtr	template;
92 };
93 
94 /*
95  * Likewise for property_group elements.
96  */
97 struct pg_elts {
98 	xmlNodePtr	stability;
99 	xmlNodePtr	propvals;
100 	xmlNodePtr	properties;
101 };
102 
103 /*
104  * Likewise for template elements.
105  */
106 struct template_elts {
107 	xmlNodePtr	common_name;
108 	xmlNodePtr	description;
109 	xmlNodePtr	documentation;
110 };
111 
112 /*
113  * This structure is for snaplevel lists.  They are convenient because libscf
114  * only allows traversing snaplevels in one direction.
115  */
116 struct snaplevel {
117 	uu_list_node_t	list_node;
118 	scf_snaplevel_t	*sl;
119 };
120 
121 /*
122  * This is used for communication between lscf_service_export and
123  * export_callback.
124  */
125 struct export_args {
126 	const char	*filename;
127 	int 		flags;
128 };
129 
130 const char * const scf_pg_general = SCF_PG_GENERAL;
131 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
132 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
133 const char * const scf_property_external = "external";
134 
135 const char * const snap_initial = "initial";
136 const char * const snap_lastimport = "last-import";
137 const char * const snap_previous = "previous";
138 const char * const snap_running = "running";
139 
140 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
141 
142 ssize_t max_scf_fmri_len;
143 ssize_t max_scf_name_len;
144 ssize_t max_scf_pg_type_len;
145 ssize_t max_scf_value_len;
146 static size_t max_scf_len;
147 
148 static scf_scope_t *cur_scope;
149 static scf_service_t *cur_svc = NULL;
150 static scf_instance_t *cur_inst = NULL;
151 static scf_snapshot_t *cur_snap = NULL;
152 static scf_snaplevel_t *cur_level = NULL;
153 
154 static uu_list_pool_t *snaplevel_pool;
155 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
156 static uu_list_t *cur_levels;
157 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
158 
159 static FILE *tempfile = NULL;
160 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
161 
162 static const char *emsg_entity_not_selected;
163 static const char *emsg_permission_denied;
164 static const char *emsg_create_xml;
165 static const char *emsg_cant_modify_snapshots;
166 static const char *emsg_read_only;
167 static const char *emsg_deleted;
168 static const char *emsg_invalid_pg_name;
169 static const char *emsg_invalid_prop_name;
170 static const char *emsg_no_such_pg;
171 static const char *emsg_fmri_invalid_pg_name;
172 static const char *emsg_fmri_invalid_pg_name_type;
173 static const char *emsg_pg_added;
174 static const char *emsg_pg_changed;
175 static const char *emsg_pg_deleted;
176 static const char *emsg_pg_mod_perm;
177 static const char *emsg_pg_add_perm;
178 static const char *emsg_pg_del_perm;
179 static const char *emsg_snap_perm;
180 static const char *emsg_dpt_dangling;
181 static const char *emsg_dpt_no_dep;
182 
183 static int li_only;
184 static int no_refresh = 0;
185 
186 /* import globals, to minimize allocations */
187 static scf_scope_t *imp_scope = NULL;
188 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
189 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
190 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
191 static scf_snapshot_t *imp_rsnap = NULL;
192 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
193 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
194 static scf_property_t *imp_prop = NULL;
195 static scf_iter_t *imp_iter = NULL;
196 static scf_iter_t *imp_rpg_iter = NULL;
197 static scf_iter_t *imp_up_iter = NULL;
198 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
199 static char *imp_str = NULL;
200 static size_t imp_str_sz;
201 static char *imp_tsname = NULL;
202 static char *imp_fe1 = NULL;		/* for fmri_equal() */
203 static char *imp_fe2 = NULL;
204 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
205 
206 /* upgrade_dependents() globals */
207 static scf_instance_t *ud_inst = NULL;
208 static scf_snaplevel_t *ud_snpl = NULL;
209 static scf_propertygroup_t *ud_pg = NULL;
210 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
211 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
212 static int ud_run_dpts_pg_set = 0;
213 static scf_property_t *ud_prop = NULL;
214 static scf_property_t *ud_dpt_prop = NULL;
215 static scf_value_t *ud_val = NULL;
216 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
217 static scf_transaction_t *ud_tx = NULL;
218 static char *ud_ctarg = NULL;
219 static char *ud_oldtarg = NULL;
220 static char *ud_name = NULL;
221 
222 /* export globals */
223 static scf_instance_t *exp_inst;
224 static scf_propertygroup_t *exp_pg;
225 static scf_property_t *exp_prop;
226 static scf_value_t *exp_val;
227 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
228 static char *exp_str;
229 static size_t exp_str_sz;
230 
231 static void scfdie_lineno(int lineno) __NORETURN;
232 
233 static char *start_method_names[] = {
234 	"start",
235 	"inetd_start",
236 	NULL
237 };
238 
239 static void
240 safe_printf(const char *fmt, ...)
241 {
242 	va_list va;
243 
244 	va_start(va, fmt);
245 	if (vprintf(fmt, va) < 0)
246 		uu_die(gettext("Error writing to stdout"));
247 	va_end(va);
248 }
249 
250 /*
251  * For unexpected libscf errors.
252  */
253 #ifdef NDEBUG
254 
255 static void scfdie(void) __NORETURN;
256 
257 static void
258 scfdie(void)
259 {
260 	scf_error_t err = scf_error();
261 
262 	if (err == SCF_ERROR_CONNECTION_BROKEN)
263 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
264 
265 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
266 	    scf_strerror(err));
267 }
268 
269 #else
270 
271 #define	scfdie()	scfdie_lineno(__LINE__)
272 
273 static void
274 scfdie_lineno(int lineno)
275 {
276 	scf_error_t err = scf_error();
277 
278 	if (err == SCF_ERROR_CONNECTION_BROKEN)
279 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
280 
281 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
282 	    ": %s.\n"), lineno, scf_strerror(err));
283 }
284 
285 #endif
286 
287 static void
288 scfwarn(void)
289 {
290 	warn(gettext("Unexpected libscf error: %s.\n"),
291 	    scf_strerror(scf_error()));
292 }
293 
294 /*
295  * Clear a field of a structure.
296  */
297 static int
298 clear_int(void *a, void *b)
299 {
300 	/* LINTED */
301 	*(int *)((char *)a + (size_t)b) = 0;
302 
303 	return (UU_WALK_NEXT);
304 }
305 
306 static int
307 scferror2errno(scf_error_t err)
308 {
309 	switch (err) {
310 	case SCF_ERROR_BACKEND_ACCESS:
311 		return (EACCES);
312 
313 	case SCF_ERROR_BACKEND_READONLY:
314 		return (EROFS);
315 
316 	case SCF_ERROR_CONNECTION_BROKEN:
317 		return (ECONNABORTED);
318 
319 	case SCF_ERROR_CONSTRAINT_VIOLATED:
320 	case SCF_ERROR_INVALID_ARGUMENT:
321 		return (EINVAL);
322 
323 	case SCF_ERROR_DELETED:
324 		return (ECANCELED);
325 
326 	case SCF_ERROR_EXISTS:
327 		return (EEXIST);
328 
329 	case SCF_ERROR_NO_MEMORY:
330 		return (ENOMEM);
331 
332 	case SCF_ERROR_NO_RESOURCES:
333 		return (ENOSPC);
334 
335 	case SCF_ERROR_NOT_FOUND:
336 		return (ENOENT);
337 
338 	case SCF_ERROR_PERMISSION_DENIED:
339 		return (EPERM);
340 
341 	default:
342 #ifndef NDEBUG
343 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
344 		    __FILE__, __LINE__, err);
345 #else
346 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
347 #endif
348 		abort();
349 		/* NOTREACHED */
350 	}
351 }
352 
353 static int
354 entity_get_pg(void *ent, int issvc, const char *name,
355     scf_propertygroup_t *pg)
356 {
357 	if (issvc)
358 		return (scf_service_get_pg(ent, name, pg));
359 	else
360 		return (scf_instance_get_pg(ent, name, pg));
361 }
362 
363 static void
364 entity_destroy(void *ent, int issvc)
365 {
366 	if (issvc)
367 		scf_service_destroy(ent);
368 	else
369 		scf_instance_destroy(ent);
370 }
371 
372 static int
373 get_pg(const char *pg_name, scf_propertygroup_t *pg)
374 {
375 	int ret;
376 
377 	if (cur_level != NULL)
378 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
379 	else if (cur_inst != NULL)
380 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
381 	else
382 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
383 
384 	return (ret);
385 }
386 
387 /*
388  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
389  * snaplevel.  Otherwise find the instance snaplevel.
390  *
391  * Returns
392  *   0 - success
393  *   ECONNABORTED - repository connection broken
394  *   ECANCELED - instance containing snap was deleted
395  *   ENOENT - snap has no snaplevels
396  *	    - requested snaplevel not found
397  */
398 static int
399 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
400 {
401 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
402 		switch (scf_error()) {
403 		case SCF_ERROR_CONNECTION_BROKEN:
404 		case SCF_ERROR_DELETED:
405 		case SCF_ERROR_NOT_FOUND:
406 			return (scferror2errno(scf_error()));
407 
408 		case SCF_ERROR_HANDLE_MISMATCH:
409 		case SCF_ERROR_NOT_BOUND:
410 		case SCF_ERROR_NOT_SET:
411 		default:
412 			bad_error("scf_snapshot_get_base_snaplevel",
413 			    scf_error());
414 		}
415 	}
416 
417 	for (;;) {
418 		ssize_t ssz;
419 
420 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
421 		if (ssz >= 0) {
422 			if (!get_svc)
423 				return (0);
424 		} else {
425 			switch (scf_error()) {
426 			case SCF_ERROR_CONSTRAINT_VIOLATED:
427 				if (get_svc)
428 					return (0);
429 				break;
430 
431 			case SCF_ERROR_DELETED:
432 			case SCF_ERROR_CONNECTION_BROKEN:
433 				return (scferror2errno(scf_error()));
434 
435 			case SCF_ERROR_NOT_SET:
436 			case SCF_ERROR_NOT_BOUND:
437 			default:
438 				bad_error("scf_snaplevel_get_instance_name",
439 				    scf_error());
440 			}
441 		}
442 
443 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
444 			switch (scf_error()) {
445 			case SCF_ERROR_NOT_FOUND:
446 			case SCF_ERROR_CONNECTION_BROKEN:
447 			case SCF_ERROR_DELETED:
448 				return (scferror2errno(scf_error()));
449 
450 			case SCF_ERROR_HANDLE_MISMATCH:
451 			case SCF_ERROR_NOT_BOUND:
452 			case SCF_ERROR_NOT_SET:
453 			case SCF_ERROR_INVALID_ARGUMENT:
454 			default:
455 				bad_error("scf_snaplevel_get_next_snaplevel",
456 				    scf_error());
457 			}
458 		}
459 	}
460 }
461 
462 /*
463  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
464  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
465  * the property group named name in it.  If it doesn't have a running
466  * snapshot, set pg to the instance's current property group named name.
467  *
468  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
469  * its instances.  If one has a running snapshot with a service snaplevel, set
470  * pg to the property group named name in it.  If no such snaplevel could be
471  * found, set pg to the service's current property group named name.
472  *
473  * iter, inst, snap, and snpl are required scratch objects.
474  *
475  * Returns
476  *   0 - success
477  *   ECONNABORTED - repository connection broken
478  *   ECANCELED - ent was deleted
479  *   ENOENT - no such property group
480  *   EINVAL - name is an invalid property group name
481  *   EBADF - found running snapshot is missing a snaplevel
482  */
483 static int
484 entity_get_running_pg(void *ent, int issvc, const char *name,
485     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
486     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
487 {
488 	int r;
489 
490 	if (issvc) {
491 		/* Search for an instance with a running snapshot. */
492 		if (scf_iter_service_instances(iter, ent) != 0) {
493 			switch (scf_error()) {
494 			case SCF_ERROR_DELETED:
495 			case SCF_ERROR_CONNECTION_BROKEN:
496 				return (scferror2errno(scf_error()));
497 
498 			case SCF_ERROR_NOT_SET:
499 			case SCF_ERROR_NOT_BOUND:
500 			case SCF_ERROR_HANDLE_MISMATCH:
501 			default:
502 				bad_error("scf_iter_service_instances",
503 				    scf_error());
504 			}
505 		}
506 
507 		for (;;) {
508 			r = scf_iter_next_instance(iter, inst);
509 			if (r == 0) {
510 				if (scf_service_get_pg(ent, name, pg) == 0)
511 					return (0);
512 
513 				switch (scf_error()) {
514 				case SCF_ERROR_DELETED:
515 				case SCF_ERROR_NOT_FOUND:
516 				case SCF_ERROR_INVALID_ARGUMENT:
517 				case SCF_ERROR_CONNECTION_BROKEN:
518 					return (scferror2errno(scf_error()));
519 
520 				case SCF_ERROR_NOT_BOUND:
521 				case SCF_ERROR_HANDLE_MISMATCH:
522 				case SCF_ERROR_NOT_SET:
523 				default:
524 					bad_error("scf_service_get_pg",
525 					    scf_error());
526 				}
527 			}
528 			if (r != 1) {
529 				switch (scf_error()) {
530 				case SCF_ERROR_DELETED:
531 				case SCF_ERROR_CONNECTION_BROKEN:
532 					return (scferror2errno(scf_error()));
533 
534 				case SCF_ERROR_INVALID_ARGUMENT:
535 				case SCF_ERROR_NOT_SET:
536 				case SCF_ERROR_NOT_BOUND:
537 				case SCF_ERROR_HANDLE_MISMATCH:
538 				default:
539 					bad_error("scf_iter_next_instance",
540 					    scf_error());
541 				}
542 			}
543 
544 			if (scf_instance_get_snapshot(inst, snap_running,
545 			    snap) == 0)
546 				break;
547 
548 			switch (scf_error()) {
549 			case SCF_ERROR_NOT_FOUND:
550 			case SCF_ERROR_DELETED:
551 				continue;
552 
553 			case SCF_ERROR_CONNECTION_BROKEN:
554 				return (ECONNABORTED);
555 
556 			case SCF_ERROR_HANDLE_MISMATCH:
557 			case SCF_ERROR_INVALID_ARGUMENT:
558 			case SCF_ERROR_NOT_SET:
559 			case SCF_ERROR_NOT_BOUND:
560 			default:
561 				bad_error("scf_instance_get_snapshot",
562 				    scf_error());
563 			}
564 		}
565 	} else {
566 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
567 			switch (scf_error()) {
568 			case SCF_ERROR_NOT_FOUND:
569 				break;
570 
571 			case SCF_ERROR_DELETED:
572 			case SCF_ERROR_CONNECTION_BROKEN:
573 				return (scferror2errno(scf_error()));
574 
575 			case SCF_ERROR_NOT_BOUND:
576 			case SCF_ERROR_HANDLE_MISMATCH:
577 			case SCF_ERROR_INVALID_ARGUMENT:
578 			case SCF_ERROR_NOT_SET:
579 			default:
580 				bad_error("scf_instance_get_snapshot",
581 				    scf_error());
582 			}
583 
584 			if (scf_instance_get_pg(ent, name, pg) == 0)
585 				return (0);
586 
587 			switch (scf_error()) {
588 			case SCF_ERROR_DELETED:
589 			case SCF_ERROR_NOT_FOUND:
590 			case SCF_ERROR_INVALID_ARGUMENT:
591 			case SCF_ERROR_CONNECTION_BROKEN:
592 				return (scferror2errno(scf_error()));
593 
594 			case SCF_ERROR_NOT_BOUND:
595 			case SCF_ERROR_HANDLE_MISMATCH:
596 			case SCF_ERROR_NOT_SET:
597 			default:
598 				bad_error("scf_instance_get_pg", scf_error());
599 			}
600 		}
601 	}
602 
603 	r = get_snaplevel(snap, issvc, snpl);
604 	switch (r) {
605 	case 0:
606 		break;
607 
608 	case ECONNABORTED:
609 	case ECANCELED:
610 		return (r);
611 
612 	case ENOENT:
613 		return (EBADF);
614 
615 	default:
616 		bad_error("get_snaplevel", r);
617 	}
618 
619 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
620 		return (0);
621 
622 	switch (scf_error()) {
623 	case SCF_ERROR_DELETED:
624 	case SCF_ERROR_INVALID_ARGUMENT:
625 	case SCF_ERROR_CONNECTION_BROKEN:
626 	case SCF_ERROR_NOT_FOUND:
627 		return (scferror2errno(scf_error()));
628 
629 	case SCF_ERROR_NOT_BOUND:
630 	case SCF_ERROR_HANDLE_MISMATCH:
631 	case SCF_ERROR_NOT_SET:
632 	default:
633 		bad_error("scf_snaplevel_get_pg", scf_error());
634 		/* NOTREACHED */
635 	}
636 }
637 
638 
639 /*
640  * To be registered with atexit().
641  */
642 static void
643 remove_tempfile(void)
644 {
645 	int ret;
646 
647 	if (tempfile != NULL) {
648 		if (fclose(tempfile) == EOF)
649 			warn(gettext("Could not close temporary file"));
650 		tempfile = NULL;
651 	}
652 
653 	if (tempfilename[0] != '\0') {
654 		do {
655 			ret = remove(tempfilename);
656 		} while (ret == -1 && errno == EINTR);
657 		if (ret == -1)
658 			warn(gettext("Could not remove temporary file"));
659 		tempfilename[0] = '\0';
660 	}
661 }
662 
663 /*
664  * Launch private svc.configd(1M) for manipulating alternate repositories.
665  */
666 static void
667 start_private_repository(engine_state_t *est)
668 {
669 	int fd, stat;
670 	struct door_info info;
671 	pid_t pid;
672 
673 	/*
674 	 * 1.  Create a temporary file for the door.
675 	 */
676 	if (est->sc_repo_doorname != NULL)
677 		free((void *)est->sc_repo_doorname);
678 
679 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
680 	if (est->sc_repo_doorname == NULL)
681 		uu_die(gettext("Could not acquire temporary filename"));
682 
683 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
684 	if (fd < 0)
685 		uu_die(gettext("Could not create temporary file for "
686 		    "repository server"));
687 
688 	(void) close(fd);
689 
690 	/*
691 	 * 2.  Launch a configd with that door, using the specified
692 	 * repository.
693 	 */
694 	if ((est->sc_repo_pid = fork()) == 0) {
695 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
696 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
697 		    NULL);
698 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
699 	} else if (est->sc_repo_pid == -1)
700 		uu_die(gettext("Attempt to fork failed"));
701 
702 	do {
703 		pid = waitpid(est->sc_repo_pid, &stat, 0);
704 	} while (pid == -1 && errno == EINTR);
705 
706 	if (pid == -1)
707 		uu_die(gettext("Could not waitpid() for repository server"));
708 
709 	if (!WIFEXITED(stat)) {
710 		uu_die(gettext("Repository server failed (status %d).\n"),
711 		    stat);
712 	} else if (WEXITSTATUS(stat) != 0) {
713 		uu_die(gettext("Repository server failed (exit %d).\n"),
714 		    WEXITSTATUS(stat));
715 	}
716 
717 	/*
718 	 * See if it was successful by checking if the door is a door.
719 	 */
720 
721 	fd = open(est->sc_repo_doorname, O_RDWR);
722 	if (fd < 0)
723 		uu_die(gettext("Could not open door \"%s\""),
724 		    est->sc_repo_doorname);
725 
726 	if (door_info(fd, &info) < 0)
727 		uu_die(gettext("Unexpected door_info() error"));
728 
729 	if (close(fd) == -1)
730 		warn(gettext("Could not close repository door"),
731 		    strerror(errno));
732 
733 	est->sc_repo_pid = info.di_target;
734 }
735 
736 void
737 lscf_cleanup(void)
738 {
739 	/*
740 	 * In the case where we've launched a private svc.configd(1M)
741 	 * instance, we must terminate our child and remove the temporary
742 	 * rendezvous point.
743 	 */
744 	if (est->sc_repo_pid > 0) {
745 		(void) kill(est->sc_repo_pid, SIGTERM);
746 		(void) waitpid(est->sc_repo_pid, NULL, 0);
747 		(void) unlink(est->sc_repo_doorname);
748 
749 		est->sc_repo_pid = 0;
750 	}
751 }
752 
753 void
754 unselect_cursnap(void)
755 {
756 	void *cookie;
757 
758 	cur_level = NULL;
759 
760 	cookie = NULL;
761 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
762 		scf_snaplevel_destroy(cur_elt->sl);
763 		free(cur_elt);
764 	}
765 
766 	scf_snapshot_destroy(cur_snap);
767 	cur_snap = NULL;
768 }
769 
770 void
771 lscf_prep_hndl(void)
772 {
773 	if (g_hndl != NULL)
774 		return;
775 
776 	g_hndl = scf_handle_create(SCF_VERSION);
777 	if (g_hndl == NULL)
778 		scfdie();
779 
780 	if (est->sc_repo_filename != NULL)
781 		start_private_repository(est);
782 
783 	if (est->sc_repo_doorname != NULL) {
784 		scf_value_t *repo_value;
785 		int ret;
786 
787 		repo_value = scf_value_create(g_hndl);
788 		if (repo_value == NULL)
789 			scfdie();
790 
791 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
792 		assert(ret == SCF_SUCCESS);
793 
794 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
795 		    SCF_SUCCESS)
796 			scfdie();
797 
798 		scf_value_destroy(repo_value);
799 	}
800 
801 	if (scf_handle_bind(g_hndl) != 0)
802 		uu_die(gettext("Could not connect to repository server: %s.\n"),
803 		    scf_strerror(scf_error()));
804 
805 	cur_scope = scf_scope_create(g_hndl);
806 	if (cur_scope == NULL)
807 		scfdie();
808 
809 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
810 		scfdie();
811 }
812 
813 static void
814 repository_teardown(void)
815 {
816 	if (g_hndl != NULL) {
817 		if (cur_snap != NULL)
818 			unselect_cursnap();
819 		scf_instance_destroy(cur_inst);
820 		scf_service_destroy(cur_svc);
821 		scf_scope_destroy(cur_scope);
822 		scf_handle_destroy(g_hndl);
823 		cur_inst = NULL;
824 		cur_svc = NULL;
825 		cur_scope = NULL;
826 		g_hndl = NULL;
827 		lscf_cleanup();
828 	}
829 }
830 
831 void
832 lscf_set_repository(const char *repfile, int force)
833 {
834 	repository_teardown();
835 
836 	if (est->sc_repo_filename != NULL) {
837 		free((void *)est->sc_repo_filename);
838 		est->sc_repo_filename = NULL;
839 	}
840 
841 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
842 		/*
843 		 * Repository file does not exist
844 		 * or has no read permission.
845 		 */
846 		warn(gettext("Cannot access \"%s\": %s\n"),
847 		    repfile, strerror(errno));
848 	} else {
849 		est->sc_repo_filename = safe_strdup(repfile);
850 	}
851 
852 	lscf_prep_hndl();
853 }
854 
855 void
856 lscf_init()
857 {
858 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
859 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
860 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
861 	    0 ||
862 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
863 		scfdie();
864 
865 	max_scf_len = max_scf_fmri_len;
866 	if (max_scf_name_len > max_scf_len)
867 		max_scf_len = max_scf_name_len;
868 	if (max_scf_pg_type_len > max_scf_len)
869 		max_scf_len = max_scf_pg_type_len;
870 	if (max_scf_value_len > max_scf_len)
871 		max_scf_len = max_scf_value_len;
872 
873 	if (atexit(remove_tempfile) != 0)
874 		uu_die(gettext("Could not register atexit() function"));
875 
876 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
877 	emsg_permission_denied = gettext("Permission denied.\n");
878 	emsg_create_xml = gettext("Could not create XML node.\n");
879 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
880 	emsg_read_only = gettext("Backend read-only.\n");
881 	emsg_deleted = gettext("Current selection has been deleted.\n");
882 	emsg_invalid_pg_name =
883 	    gettext("Invalid property group name \"%s\".\n");
884 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
885 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
886 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
887 	    "with invalid name \"%s\".\n");
888 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
889 	    "group with invalid name \"%s\" or type \"%s\".\n");
890 	emsg_pg_added = gettext("%s changed unexpectedly "
891 	    "(property group \"%s\" added).\n");
892 	emsg_pg_changed = gettext("%s changed unexpectedly "
893 	    "(property group \"%s\" changed).\n");
894 	emsg_pg_deleted = gettext("%s changed unexpectedly "
895 	    "(property group \"%s\" or an ancestor was deleted).\n");
896 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
897 	    "in %s (permission denied).\n");
898 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
899 	    "in %s (permission denied).\n");
900 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
901 	    "in %s (permission denied).\n");
902 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
903 	    "(permission denied).\n");
904 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
905 	    "new dependent \"%s\" because it already exists).  Warning: The "
906 	    "current dependent's target (%s) does not exist.\n");
907 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
908 	    "dependent \"%s\" because it already exists).  Warning: The "
909 	    "current dependent's target (%s) does not have a dependency named "
910 	    "\"%s\" as expected.\n");
911 
912 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
913 	    offsetof(string_list_t, node), NULL, 0);
914 	snaplevel_pool = uu_list_pool_create("snaplevels",
915 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
916 	    NULL, 0);
917 }
918 
919 
920 static const char *
921 prop_to_typestr(const scf_property_t *prop)
922 {
923 	scf_type_t ty;
924 
925 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
926 		scfdie();
927 
928 	return (scf_type_to_string(ty));
929 }
930 
931 static scf_type_t
932 string_to_type(const char *type)
933 {
934 	size_t len = strlen(type);
935 	char *buf;
936 
937 	if (len == 0 || type[len - 1] != ':')
938 		return (SCF_TYPE_INVALID);
939 
940 	buf = (char *)alloca(len + 1);
941 	(void) strlcpy(buf, type, len + 1);
942 	buf[len - 1] = 0;
943 
944 	return (scf_string_to_type(buf));
945 }
946 
947 static scf_value_t *
948 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
949 {
950 	scf_value_t *v;
951 	char *dup, *nstr;
952 	size_t len;
953 
954 	v = scf_value_create(g_hndl);
955 	if (v == NULL)
956 		scfdie();
957 
958 	len = strlen(str);
959 	if (require_quotes &&
960 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
961 		semerr(gettext("Multiple string values or string values "
962 		    "with spaces must be quoted with '\"'.\n"));
963 		scf_value_destroy(v);
964 		return (NULL);
965 	}
966 
967 	nstr = dup = safe_strdup(str);
968 	if (dup[0] == '\"') {
969 		/*
970 		 * Strip out the first and the last quote.
971 		 */
972 		dup[len - 1] = '\0';
973 		nstr = dup + 1;
974 	}
975 
976 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
977 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
978 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
979 		    scf_type_to_string(ty), nstr);
980 		scf_value_destroy(v);
981 		v = NULL;
982 	}
983 	free(dup);
984 	return (v);
985 }
986 
987 /*
988  * Print str to strm, quoting double-quotes and backslashes with backslashes.
989  * Optionally append a comment prefix ('#') to newlines ('\n').
990  */
991 static int
992 quote_and_print(const char *str, FILE *strm, int commentnl)
993 {
994 	const char *cp;
995 
996 	for (cp = str; *cp != '\0'; ++cp) {
997 		if (*cp == '"' || *cp == '\\')
998 			(void) putc('\\', strm);
999 
1000 		(void) putc(*cp, strm);
1001 
1002 		if (commentnl && *cp == '\n') {
1003 			(void) putc('#', strm);
1004 		}
1005 	}
1006 
1007 	return (ferror(strm));
1008 }
1009 
1010 /*
1011  * These wrappers around lowlevel functions provide consistent error checking
1012  * and warnings.
1013  */
1014 static int
1015 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1016 {
1017 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1018 		return (0);
1019 
1020 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1021 		scfdie();
1022 
1023 	if (g_verbose) {
1024 		ssize_t len;
1025 		char *fmri;
1026 
1027 		len = scf_pg_to_fmri(pg, NULL, 0);
1028 		if (len < 0)
1029 			scfdie();
1030 
1031 		fmri = safe_malloc(len + 1);
1032 
1033 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1034 			scfdie();
1035 
1036 		warn(gettext("Expected property %s of property group %s is "
1037 		    "missing.\n"), propname, fmri);
1038 
1039 		free(fmri);
1040 	}
1041 
1042 	return (-1);
1043 }
1044 
1045 static int
1046 prop_check_type(scf_property_t *prop, scf_type_t ty)
1047 {
1048 	scf_type_t pty;
1049 
1050 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1051 		scfdie();
1052 
1053 	if (ty == pty)
1054 		return (0);
1055 
1056 	if (g_verbose) {
1057 		ssize_t len;
1058 		char *fmri;
1059 		const char *tystr;
1060 
1061 		len = scf_property_to_fmri(prop, NULL, 0);
1062 		if (len < 0)
1063 			scfdie();
1064 
1065 		fmri = safe_malloc(len + 1);
1066 
1067 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1068 			scfdie();
1069 
1070 		tystr = scf_type_to_string(ty);
1071 		if (tystr == NULL)
1072 			tystr = "?";
1073 
1074 		warn(gettext("Property %s is not of expected type %s.\n"),
1075 		    fmri, tystr);
1076 
1077 		free(fmri);
1078 	}
1079 
1080 	return (-1);
1081 }
1082 
1083 static int
1084 prop_get_val(scf_property_t *prop, scf_value_t *val)
1085 {
1086 	scf_error_t err;
1087 
1088 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1089 		return (0);
1090 
1091 	err = scf_error();
1092 
1093 	if (err != SCF_ERROR_NOT_FOUND &&
1094 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1095 	    err != SCF_ERROR_PERMISSION_DENIED)
1096 		scfdie();
1097 
1098 	if (g_verbose) {
1099 		ssize_t len;
1100 		char *fmri, *emsg;
1101 
1102 		len = scf_property_to_fmri(prop, NULL, 0);
1103 		if (len < 0)
1104 			scfdie();
1105 
1106 		fmri = safe_malloc(len + 1);
1107 
1108 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1109 			scfdie();
1110 
1111 		if (err == SCF_ERROR_NOT_FOUND)
1112 			emsg = gettext("Property %s has no values; expected "
1113 			    "one.\n");
1114 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1115 			emsg = gettext("Property %s has multiple values; "
1116 			    "expected one.\n");
1117 		else
1118 			emsg = gettext("No permission to read property %s.\n");
1119 
1120 		warn(emsg, fmri);
1121 
1122 		free(fmri);
1123 	}
1124 
1125 	return (-1);
1126 }
1127 
1128 
1129 static boolean_t
1130 snaplevel_is_instance(const scf_snaplevel_t *level)
1131 {
1132 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1133 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1134 			scfdie();
1135 		return (0);
1136 	} else {
1137 		return (1);
1138 	}
1139 }
1140 
1141 /*
1142  * Decode FMRI into a service or instance, and put the result in *ep.  If
1143  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1144  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1145  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1146  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1147  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1148  * whether *ep is a service.
1149  */
1150 static scf_error_t
1151 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1152 {
1153 	char *fmri_copy;
1154 	const char *sstr, *istr, *pgstr;
1155 	scf_service_t *svc;
1156 	scf_instance_t *inst;
1157 
1158 	fmri_copy = strdup(fmri);
1159 	if (fmri_copy == NULL)
1160 		return (SCF_ERROR_NO_MEMORY);
1161 
1162 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1163 	    SCF_SUCCESS) {
1164 		free(fmri_copy);
1165 		return (SCF_ERROR_INVALID_ARGUMENT);
1166 	}
1167 
1168 	free(fmri_copy);
1169 
1170 	if (sstr == NULL || pgstr != NULL)
1171 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1172 
1173 	if (istr == NULL) {
1174 		svc = scf_service_create(h);
1175 		if (svc == NULL)
1176 			return (SCF_ERROR_NO_MEMORY);
1177 
1178 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1179 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1180 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1181 				scfdie();
1182 
1183 			return (SCF_ERROR_NOT_FOUND);
1184 		}
1185 
1186 		*ep = svc;
1187 		*isservice = 1;
1188 	} else {
1189 		inst = scf_instance_create(h);
1190 		if (inst == NULL)
1191 			return (SCF_ERROR_NO_MEMORY);
1192 
1193 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1194 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1195 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1196 				scfdie();
1197 
1198 			return (SCF_ERROR_NOT_FOUND);
1199 		}
1200 
1201 		*ep = inst;
1202 		*isservice = 0;
1203 	}
1204 
1205 	return (SCF_ERROR_NONE);
1206 }
1207 
1208 /*
1209  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1210  * *ep, and set or clear *isservicep if it is a service or an instance.
1211  * Returns
1212  *   SCF_ERROR_NONE - success
1213  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1214  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1215  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1216  *   SCF_ERROR_NOT_FOUND - no such scope
1217  *   SCF_ERROR_PERMISSION_DENIED
1218  *   SCF_ERROR_BACKEND_READONLY
1219  *   SCF_ERROR_BACKEND_ACCESS
1220  */
1221 static scf_error_t
1222 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1223 {
1224 	char *fmri_copy;
1225 	const char *scstr, *sstr, *istr, *pgstr;
1226 	scf_scope_t *scope = NULL;
1227 	scf_service_t *svc = NULL;
1228 	scf_instance_t *inst = NULL;
1229 	scf_error_t scfe;
1230 
1231 	fmri_copy = safe_strdup(fmri);
1232 
1233 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1234 	    0) {
1235 		free(fmri_copy);
1236 		return (SCF_ERROR_INVALID_ARGUMENT);
1237 	}
1238 
1239 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1240 		free(fmri_copy);
1241 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1242 	}
1243 
1244 	*ep = NULL;
1245 
1246 	if ((scope = scf_scope_create(h)) == NULL ||
1247 	    (svc = scf_service_create(h)) == NULL ||
1248 	    (inst = scf_instance_create(h)) == NULL) {
1249 		scfe = SCF_ERROR_NO_MEMORY;
1250 		goto out;
1251 	}
1252 
1253 get_scope:
1254 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1255 		switch (scf_error()) {
1256 		case SCF_ERROR_CONNECTION_BROKEN:
1257 			scfdie();
1258 			/* NOTREACHED */
1259 
1260 		case SCF_ERROR_NOT_FOUND:
1261 			scfe = SCF_ERROR_NOT_FOUND;
1262 			goto out;
1263 
1264 		case SCF_ERROR_HANDLE_MISMATCH:
1265 		case SCF_ERROR_NOT_BOUND:
1266 		case SCF_ERROR_INVALID_ARGUMENT:
1267 		default:
1268 			bad_error("scf_handle_get_scope", scf_error());
1269 		}
1270 	}
1271 
1272 get_svc:
1273 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1274 		switch (scf_error()) {
1275 		case SCF_ERROR_CONNECTION_BROKEN:
1276 			scfdie();
1277 			/* NOTREACHED */
1278 
1279 		case SCF_ERROR_DELETED:
1280 			goto get_scope;
1281 
1282 		case SCF_ERROR_NOT_FOUND:
1283 			break;
1284 
1285 		case SCF_ERROR_HANDLE_MISMATCH:
1286 		case SCF_ERROR_INVALID_ARGUMENT:
1287 		case SCF_ERROR_NOT_BOUND:
1288 		case SCF_ERROR_NOT_SET:
1289 		default:
1290 			bad_error("scf_scope_get_service", scf_error());
1291 		}
1292 
1293 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1294 			switch (scf_error()) {
1295 			case SCF_ERROR_CONNECTION_BROKEN:
1296 				scfdie();
1297 				/* NOTREACHED */
1298 
1299 			case SCF_ERROR_DELETED:
1300 				goto get_scope;
1301 
1302 			case SCF_ERROR_PERMISSION_DENIED:
1303 			case SCF_ERROR_BACKEND_READONLY:
1304 			case SCF_ERROR_BACKEND_ACCESS:
1305 				scfe = scf_error();
1306 				goto out;
1307 
1308 			case SCF_ERROR_HANDLE_MISMATCH:
1309 			case SCF_ERROR_INVALID_ARGUMENT:
1310 			case SCF_ERROR_NOT_BOUND:
1311 			case SCF_ERROR_NOT_SET:
1312 			default:
1313 				bad_error("scf_scope_get_service", scf_error());
1314 			}
1315 		}
1316 	}
1317 
1318 	if (istr == NULL) {
1319 		scfe = SCF_ERROR_NONE;
1320 		*ep = svc;
1321 		*isservicep = 1;
1322 		goto out;
1323 	}
1324 
1325 get_inst:
1326 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1327 		switch (scf_error()) {
1328 		case SCF_ERROR_CONNECTION_BROKEN:
1329 			scfdie();
1330 			/* NOTREACHED */
1331 
1332 		case SCF_ERROR_DELETED:
1333 			goto get_svc;
1334 
1335 		case SCF_ERROR_NOT_FOUND:
1336 			break;
1337 
1338 		case SCF_ERROR_HANDLE_MISMATCH:
1339 		case SCF_ERROR_INVALID_ARGUMENT:
1340 		case SCF_ERROR_NOT_BOUND:
1341 		case SCF_ERROR_NOT_SET:
1342 		default:
1343 			bad_error("scf_service_get_instance", scf_error());
1344 		}
1345 
1346 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1347 			switch (scf_error()) {
1348 			case SCF_ERROR_CONNECTION_BROKEN:
1349 				scfdie();
1350 				/* NOTREACHED */
1351 
1352 			case SCF_ERROR_DELETED:
1353 				goto get_svc;
1354 
1355 			case SCF_ERROR_PERMISSION_DENIED:
1356 			case SCF_ERROR_BACKEND_READONLY:
1357 			case SCF_ERROR_BACKEND_ACCESS:
1358 				scfe = scf_error();
1359 				goto out;
1360 
1361 			case SCF_ERROR_HANDLE_MISMATCH:
1362 			case SCF_ERROR_INVALID_ARGUMENT:
1363 			case SCF_ERROR_NOT_BOUND:
1364 			case SCF_ERROR_NOT_SET:
1365 			default:
1366 				bad_error("scf_service_add_instance",
1367 				    scf_error());
1368 			}
1369 		}
1370 	}
1371 
1372 	scfe = SCF_ERROR_NONE;
1373 	*ep = inst;
1374 	*isservicep = 0;
1375 
1376 out:
1377 	if (*ep != inst)
1378 		scf_instance_destroy(inst);
1379 	if (*ep != svc)
1380 		scf_service_destroy(svc);
1381 	scf_scope_destroy(scope);
1382 	free(fmri_copy);
1383 	return (scfe);
1384 }
1385 
1386 /*
1387  * Create or update a snapshot of inst.  snap is a required scratch object.
1388  *
1389  * Returns
1390  *   0 - success
1391  *   ECONNABORTED - repository connection broken
1392  *   EPERM - permission denied
1393  *   ENOSPC - configd is out of resources
1394  *   ECANCELED - inst was deleted
1395  *   -1 - unknown libscf error (message printed)
1396  */
1397 static int
1398 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1399 {
1400 again:
1401 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1402 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1403 			switch (scf_error()) {
1404 			case SCF_ERROR_CONNECTION_BROKEN:
1405 			case SCF_ERROR_PERMISSION_DENIED:
1406 			case SCF_ERROR_NO_RESOURCES:
1407 				return (scferror2errno(scf_error()));
1408 
1409 			case SCF_ERROR_NOT_SET:
1410 			case SCF_ERROR_INVALID_ARGUMENT:
1411 			default:
1412 				bad_error("_scf_snapshot_take_attach",
1413 				    scf_error());
1414 			}
1415 		}
1416 	} else {
1417 		switch (scf_error()) {
1418 		case SCF_ERROR_NOT_FOUND:
1419 			break;
1420 
1421 		case SCF_ERROR_DELETED:
1422 		case SCF_ERROR_CONNECTION_BROKEN:
1423 			return (scferror2errno(scf_error()));
1424 
1425 		case SCF_ERROR_HANDLE_MISMATCH:
1426 		case SCF_ERROR_NOT_BOUND:
1427 		case SCF_ERROR_INVALID_ARGUMENT:
1428 		case SCF_ERROR_NOT_SET:
1429 		default:
1430 			bad_error("scf_instance_get_snapshot", scf_error());
1431 		}
1432 
1433 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1434 			switch (scf_error()) {
1435 			case SCF_ERROR_EXISTS:
1436 				goto again;
1437 
1438 			case SCF_ERROR_CONNECTION_BROKEN:
1439 			case SCF_ERROR_NO_RESOURCES:
1440 			case SCF_ERROR_PERMISSION_DENIED:
1441 				return (scferror2errno(scf_error()));
1442 
1443 			default:
1444 				scfwarn();
1445 				return (-1);
1446 
1447 			case SCF_ERROR_NOT_SET:
1448 			case SCF_ERROR_INTERNAL:
1449 			case SCF_ERROR_INVALID_ARGUMENT:
1450 			case SCF_ERROR_HANDLE_MISMATCH:
1451 				bad_error("_scf_snapshot_take_new",
1452 				    scf_error());
1453 			}
1454 		}
1455 	}
1456 
1457 	return (0);
1458 }
1459 
1460 static int
1461 refresh_running_snapshot(void *entity)
1462 {
1463 	scf_snapshot_t *snap;
1464 	int r;
1465 
1466 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1467 		scfdie();
1468 	r = take_snap(entity, snap_running, snap);
1469 	scf_snapshot_destroy(snap);
1470 
1471 	return (r);
1472 }
1473 
1474 /*
1475  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1476  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1477  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1478  * for scratch space.  Returns
1479  *   0 - success
1480  *   ECONNABORTED - repository connection broken
1481  *   ECANCELED - entity was deleted
1482  *   EACCES - backend denied access
1483  *   EPERM - permission denied
1484  *   ENOSPC - repository server out of resources
1485  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1486  */
1487 static int
1488 refresh_entity(int isservice, void *entity, const char *fmri,
1489     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1490 {
1491 	scf_error_t scfe;
1492 	int r;
1493 
1494 	if (!isservice) {
1495 		if (est->sc_repo_filename == NULL &&
1496 		    est->sc_repo_doorname == NULL) {
1497 			if (_smf_refresh_instance_i(entity) == 0) {
1498 				if (g_verbose)
1499 					warn(gettext("Refreshed %s.\n"), fmri);
1500 				return (0);
1501 			}
1502 
1503 			switch (scf_error()) {
1504 			case SCF_ERROR_BACKEND_ACCESS:
1505 				return (EACCES);
1506 
1507 			case SCF_ERROR_PERMISSION_DENIED:
1508 				return (EPERM);
1509 
1510 			default:
1511 				return (-1);
1512 			}
1513 		} else {
1514 			r = refresh_running_snapshot(entity);
1515 			switch (r) {
1516 			case 0:
1517 				break;
1518 
1519 			case ECONNABORTED:
1520 			case ECANCELED:
1521 			case EPERM:
1522 			case ENOSPC:
1523 				break;
1524 
1525 			default:
1526 				bad_error("refresh_running_snapshot",
1527 				    scf_error());
1528 			}
1529 
1530 			return (r);
1531 		}
1532 	}
1533 
1534 	if (scf_iter_service_instances(iter, entity) != 0) {
1535 		switch (scf_error()) {
1536 		case SCF_ERROR_CONNECTION_BROKEN:
1537 			return (ECONNABORTED);
1538 
1539 		case SCF_ERROR_DELETED:
1540 			return (ECANCELED);
1541 
1542 		case SCF_ERROR_HANDLE_MISMATCH:
1543 		case SCF_ERROR_NOT_BOUND:
1544 		case SCF_ERROR_NOT_SET:
1545 		default:
1546 			bad_error("scf_iter_service_instances", scf_error());
1547 		}
1548 	}
1549 
1550 	for (;;) {
1551 		r = scf_iter_next_instance(iter, inst);
1552 		if (r == 0)
1553 			break;
1554 		if (r != 1) {
1555 			switch (scf_error()) {
1556 			case SCF_ERROR_CONNECTION_BROKEN:
1557 				return (ECONNABORTED);
1558 
1559 			case SCF_ERROR_DELETED:
1560 				return (ECANCELED);
1561 
1562 			case SCF_ERROR_HANDLE_MISMATCH:
1563 			case SCF_ERROR_NOT_BOUND:
1564 			case SCF_ERROR_NOT_SET:
1565 			case SCF_ERROR_INVALID_ARGUMENT:
1566 			default:
1567 				bad_error("scf_iter_next_instance",
1568 				    scf_error());
1569 			}
1570 		}
1571 
1572 		if (est->sc_repo_filename != NULL ||
1573 		    est->sc_repo_doorname != NULL) {
1574 			r = refresh_running_snapshot(inst);
1575 			switch (r) {
1576 			case 0:
1577 				continue;
1578 
1579 			case ECONNABORTED:
1580 			case ECANCELED:
1581 			case EPERM:
1582 			case ENOSPC:
1583 				break;
1584 			default:
1585 				bad_error("refresh_running_snapshot",
1586 				    scf_error());
1587 			}
1588 
1589 			return (r);
1590 
1591 		}
1592 
1593 		if (_smf_refresh_instance_i(inst) == 0) {
1594 			if (g_verbose) {
1595 				if (scf_instance_get_name(inst, name_buf,
1596 				    max_scf_name_len + 1) < 0)
1597 					(void) strcpy(name_buf, "?");
1598 
1599 				warn(gettext("Refreshed %s:%s.\n"),
1600 				    fmri, name_buf);
1601 			}
1602 		} else {
1603 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1604 			    g_verbose) {
1605 				scfe = scf_error();
1606 
1607 				if (scf_instance_to_fmri(inst, name_buf,
1608 				    max_scf_name_len + 1) < 0)
1609 					(void) strcpy(name_buf, "?");
1610 
1611 				warn(gettext(
1612 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1613 				    name_buf, scf_strerror(scfe));
1614 			}
1615 		}
1616 	}
1617 
1618 	return (0);
1619 }
1620 
1621 static void
1622 private_refresh(void)
1623 {
1624 	scf_instance_t *pinst = NULL;
1625 	scf_iter_t *piter = NULL;
1626 	ssize_t fmrilen;
1627 	size_t bufsz;
1628 	char *fmribuf;
1629 	void *ent;
1630 	int issvc;
1631 	int r;
1632 
1633 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1634 		return;
1635 
1636 	assert(cur_svc != NULL);
1637 
1638 	bufsz = max_scf_fmri_len + 1;
1639 	fmribuf = safe_malloc(bufsz);
1640 	if (cur_inst) {
1641 		issvc = 0;
1642 		ent = cur_inst;
1643 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1644 	} else {
1645 		issvc = 1;
1646 		ent = cur_svc;
1647 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1648 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1649 			scfdie();
1650 
1651 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1652 			scfdie();
1653 	}
1654 	if (fmrilen < 0) {
1655 		free(fmribuf);
1656 		if (scf_error() != SCF_ERROR_DELETED)
1657 			scfdie();
1658 
1659 		warn(emsg_deleted);
1660 		return;
1661 	}
1662 	assert(fmrilen < bufsz);
1663 
1664 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1665 	switch (r) {
1666 	case 0:
1667 		break;
1668 
1669 	case ECONNABORTED:
1670 		warn(gettext("Could not refresh %s "
1671 		    "(repository connection broken).\n"), fmribuf);
1672 		break;
1673 
1674 	case ECANCELED:
1675 		warn(emsg_deleted);
1676 		break;
1677 
1678 	case EPERM:
1679 		warn(gettext("Could not refresh %s "
1680 		    "(permission denied).\n"), fmribuf);
1681 		break;
1682 
1683 	case ENOSPC:
1684 		warn(gettext("Could not refresh %s "
1685 		    "(repository server out of resources).\n"),
1686 		    fmribuf);
1687 		break;
1688 
1689 	case EACCES:
1690 	default:
1691 		bad_error("refresh_entity", scf_error());
1692 	}
1693 
1694 	if (issvc) {
1695 		scf_instance_destroy(pinst);
1696 		scf_iter_destroy(piter);
1697 	}
1698 
1699 	free(fmribuf);
1700 }
1701 
1702 
1703 static int
1704 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1705 {
1706 	cbp->sc_err = scferror2errno(err);
1707 	return (UU_WALK_ERROR);
1708 }
1709 
1710 static int
1711 stash_scferror(scf_callback_t *cbp)
1712 {
1713 	return (stash_scferror_err(cbp, scf_error()));
1714 }
1715 
1716 /*
1717  * Import.  These functions import a bundle into the repository.
1718  */
1719 
1720 /*
1721  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
1722  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
1723  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1724  * lcbdata->sc_err to
1725  *   ENOMEM - out of memory
1726  *   ECONNABORTED - repository connection broken
1727  *   ECANCELED - sc_trans's property group was deleted
1728  *   EINVAL - p's name is invalid (error printed)
1729  *	    - p has an invalid value (error printed)
1730  */
1731 static int
1732 lscf_property_import(void *v, void *pvt)
1733 {
1734 	property_t *p = v;
1735 	scf_callback_t *lcbdata = pvt;
1736 	value_t *vp;
1737 	scf_transaction_t *trans = lcbdata->sc_trans;
1738 	scf_transaction_entry_t *entr;
1739 	scf_value_t *val;
1740 	scf_type_t tp;
1741 
1742 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
1743 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
1744 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
1745 		lcbdata->sc_enable = p;
1746 		return (UU_WALK_NEXT);
1747 	}
1748 
1749 	entr = scf_entry_create(lcbdata->sc_handle);
1750 	if (entr == NULL) {
1751 		switch (scf_error()) {
1752 		case SCF_ERROR_NO_MEMORY:
1753 			return (stash_scferror(lcbdata));
1754 
1755 		case SCF_ERROR_INVALID_ARGUMENT:
1756 		default:
1757 			bad_error("scf_entry_create", scf_error());
1758 		}
1759 	}
1760 
1761 	tp = p->sc_value_type;
1762 
1763 	if (scf_transaction_property_new(trans, entr,
1764 	    p->sc_property_name, tp) != 0) {
1765 		switch (scf_error()) {
1766 		case SCF_ERROR_INVALID_ARGUMENT:
1767 			semerr(emsg_invalid_prop_name, p->sc_property_name);
1768 			scf_entry_destroy(entr);
1769 			return (stash_scferror(lcbdata));
1770 
1771 		case SCF_ERROR_EXISTS:
1772 			break;
1773 
1774 		case SCF_ERROR_DELETED:
1775 		case SCF_ERROR_CONNECTION_BROKEN:
1776 			scf_entry_destroy(entr);
1777 			return (stash_scferror(lcbdata));
1778 
1779 		case SCF_ERROR_NOT_BOUND:
1780 		case SCF_ERROR_HANDLE_MISMATCH:
1781 		case SCF_ERROR_NOT_SET:
1782 		default:
1783 			bad_error("scf_transaction_property_new", scf_error());
1784 		}
1785 
1786 		if (scf_transaction_property_change_type(trans, entr,
1787 		    p->sc_property_name, tp) != 0) {
1788 			switch (scf_error()) {
1789 			case SCF_ERROR_DELETED:
1790 			case SCF_ERROR_CONNECTION_BROKEN:
1791 				scf_entry_destroy(entr);
1792 				return (stash_scferror(lcbdata));
1793 
1794 			case SCF_ERROR_INVALID_ARGUMENT:
1795 				semerr(emsg_invalid_prop_name,
1796 				    p->sc_property_name);
1797 				scf_entry_destroy(entr);
1798 				return (stash_scferror(lcbdata));
1799 
1800 			case SCF_ERROR_NOT_FOUND:
1801 			case SCF_ERROR_NOT_SET:
1802 			case SCF_ERROR_HANDLE_MISMATCH:
1803 			case SCF_ERROR_NOT_BOUND:
1804 			default:
1805 				bad_error(
1806 				    "scf_transaction_property_change_type",
1807 				    scf_error());
1808 			}
1809 		}
1810 	}
1811 
1812 	for (vp = uu_list_first(p->sc_property_values);
1813 	    vp != NULL;
1814 	    vp = uu_list_next(p->sc_property_values, vp)) {
1815 		val = scf_value_create(g_hndl);
1816 		if (val == NULL) {
1817 			switch (scf_error()) {
1818 			case SCF_ERROR_NO_MEMORY:
1819 				return (stash_scferror(lcbdata));
1820 
1821 			case SCF_ERROR_INVALID_ARGUMENT:
1822 			default:
1823 				bad_error("scf_value_create", scf_error());
1824 			}
1825 		}
1826 
1827 		switch (tp) {
1828 		case SCF_TYPE_BOOLEAN:
1829 			scf_value_set_boolean(val, vp->sc_u.sc_count);
1830 			break;
1831 		case SCF_TYPE_COUNT:
1832 			scf_value_set_count(val, vp->sc_u.sc_count);
1833 			break;
1834 		case SCF_TYPE_INTEGER:
1835 			scf_value_set_integer(val, vp->sc_u.sc_integer);
1836 			break;
1837 		default:
1838 			assert(vp->sc_u.sc_string != NULL);
1839 			if (scf_value_set_from_string(val, tp,
1840 			    vp->sc_u.sc_string) != 0) {
1841 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
1842 					bad_error("scf_value_set_from_string",
1843 					    scf_error());
1844 
1845 				warn(gettext("Value \"%s\" is not a valid "
1846 				    "%s.\n"), vp->sc_u.sc_string,
1847 				    scf_type_to_string(tp));
1848 				scf_value_destroy(val);
1849 				return (stash_scferror(lcbdata));
1850 			}
1851 			break;
1852 		}
1853 
1854 		if (scf_entry_add_value(entr, val) != 0)
1855 			bad_error("scf_entry_add_value", scf_error());
1856 	}
1857 
1858 	return (UU_WALK_NEXT);
1859 }
1860 
1861 /*
1862  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
1863  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
1864  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
1865  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1866  * lcbdata->sc_err to
1867  *   ECONNABORTED - repository connection broken
1868  *   ENOMEM - out of memory
1869  *   ENOSPC - svc.configd is out of resources
1870  *   ECANCELED - sc_parent was deleted
1871  *   EPERM - could not create property group (permission denied) (error printed)
1872  *	   - could not modify property group (permission denied) (error printed)
1873  *	   - could not delete property group (permission denied) (error	printed)
1874  *   EROFS - could not create property group (repository is read-only)
1875  *	   - could not delete property group (repository is read-only)
1876  *   EACCES - could not create property group (backend access denied)
1877  *	    - could not delete property group (backend access denied)
1878  *   EEXIST - could not create property group (already exists)
1879  *   EINVAL - invalid property group name (error printed)
1880  *	    - invalid property name (error printed)
1881  *	    - invalid value (error printed)
1882  *   EBUSY - new property group deleted (error printed)
1883  *	   - new property group changed (error printed)
1884  *	   - property group added (error printed)
1885  *	   - property group deleted (error printed)
1886  */
1887 static int
1888 entity_pgroup_import(void *v, void *pvt)
1889 {
1890 	pgroup_t *p = v;
1891 	scf_callback_t cbdata;
1892 	scf_callback_t *lcbdata = pvt;
1893 	void *ent = lcbdata->sc_parent;
1894 	int issvc = lcbdata->sc_service;
1895 	int r;
1896 
1897 	const char * const pg_changed = gettext("%s changed unexpectedly "
1898 	    "(new property group \"%s\" changed).\n");
1899 
1900 	/* Never import deleted property groups. */
1901 	if (p->sc_pgroup_delete)
1902 		return (UU_WALK_NEXT);
1903 
1904 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
1905 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
1906 		lcbdata->sc_general = p;
1907 		return (UU_WALK_NEXT);
1908 	}
1909 
1910 add_pg:
1911 	if (issvc)
1912 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
1913 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1914 	else
1915 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
1916 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1917 	if (r != 0) {
1918 		switch (scf_error()) {
1919 		case SCF_ERROR_DELETED:
1920 		case SCF_ERROR_CONNECTION_BROKEN:
1921 		case SCF_ERROR_BACKEND_READONLY:
1922 		case SCF_ERROR_BACKEND_ACCESS:
1923 		case SCF_ERROR_NO_RESOURCES:
1924 			return (stash_scferror(lcbdata));
1925 
1926 		case SCF_ERROR_EXISTS:
1927 			if (lcbdata->sc_flags & SCI_FORCE)
1928 				break;
1929 			return (stash_scferror(lcbdata));
1930 
1931 		case SCF_ERROR_INVALID_ARGUMENT:
1932 			warn(emsg_fmri_invalid_pg_name_type,
1933 			    lcbdata->sc_source_fmri,
1934 			    p->sc_pgroup_name, p->sc_pgroup_type);
1935 			return (stash_scferror(lcbdata));
1936 
1937 		case SCF_ERROR_PERMISSION_DENIED:
1938 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
1939 			    lcbdata->sc_target_fmri);
1940 			return (stash_scferror(lcbdata));
1941 
1942 		case SCF_ERROR_NOT_BOUND:
1943 		case SCF_ERROR_HANDLE_MISMATCH:
1944 		case SCF_ERROR_NOT_SET:
1945 		default:
1946 			bad_error("scf_service_add_pg", scf_error());
1947 		}
1948 
1949 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
1950 			switch (scf_error()) {
1951 			case SCF_ERROR_CONNECTION_BROKEN:
1952 			case SCF_ERROR_DELETED:
1953 				return (stash_scferror(lcbdata));
1954 
1955 			case SCF_ERROR_INVALID_ARGUMENT:
1956 				warn(emsg_fmri_invalid_pg_name,
1957 				    lcbdata->sc_source_fmri,
1958 				    p->sc_pgroup_name);
1959 				return (stash_scferror(lcbdata));
1960 
1961 			case SCF_ERROR_NOT_FOUND:
1962 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
1963 				    p->sc_pgroup_name);
1964 				lcbdata->sc_err = EBUSY;
1965 				return (UU_WALK_ERROR);
1966 
1967 			case SCF_ERROR_NOT_BOUND:
1968 			case SCF_ERROR_HANDLE_MISMATCH:
1969 			case SCF_ERROR_NOT_SET:
1970 			default:
1971 				bad_error("entity_get_pg", scf_error());
1972 			}
1973 		}
1974 
1975 		if (lcbdata->sc_flags & SCI_KEEP)
1976 			goto props;
1977 
1978 		if (scf_pg_delete(imp_pg) != 0) {
1979 			switch (scf_error()) {
1980 			case SCF_ERROR_DELETED:
1981 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
1982 				    p->sc_pgroup_name);
1983 				lcbdata->sc_err = EBUSY;
1984 				return (UU_WALK_ERROR);
1985 
1986 			case SCF_ERROR_PERMISSION_DENIED:
1987 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
1988 				    lcbdata->sc_target_fmri);
1989 				return (stash_scferror(lcbdata));
1990 
1991 			case SCF_ERROR_BACKEND_READONLY:
1992 			case SCF_ERROR_BACKEND_ACCESS:
1993 			case SCF_ERROR_CONNECTION_BROKEN:
1994 				return (stash_scferror(lcbdata));
1995 
1996 			case SCF_ERROR_NOT_SET:
1997 			default:
1998 				bad_error("scf_pg_delete", scf_error());
1999 			}
2000 		}
2001 
2002 		goto add_pg;
2003 	}
2004 
2005 props:
2006 
2007 	/*
2008 	 * Add properties to property group, if any.
2009 	 */
2010 	cbdata.sc_handle = lcbdata->sc_handle;
2011 	cbdata.sc_parent = imp_pg;
2012 	cbdata.sc_flags = lcbdata->sc_flags;
2013 	cbdata.sc_trans = imp_tx;
2014 	cbdata.sc_enable = NULL;
2015 
2016 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2017 		switch (scf_error()) {
2018 		case SCF_ERROR_BACKEND_ACCESS:
2019 		case SCF_ERROR_BACKEND_READONLY:
2020 		case SCF_ERROR_CONNECTION_BROKEN:
2021 			return (stash_scferror(lcbdata));
2022 
2023 		case SCF_ERROR_DELETED:
2024 			warn(pg_changed, lcbdata->sc_target_fmri,
2025 			    p->sc_pgroup_name);
2026 			lcbdata->sc_err = EBUSY;
2027 			return (UU_WALK_ERROR);
2028 
2029 		case SCF_ERROR_PERMISSION_DENIED:
2030 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2031 			    lcbdata->sc_target_fmri);
2032 			return (stash_scferror(lcbdata));
2033 
2034 		case SCF_ERROR_NOT_BOUND:
2035 		case SCF_ERROR_NOT_SET:
2036 		case SCF_ERROR_IN_USE:
2037 		case SCF_ERROR_HANDLE_MISMATCH:
2038 		default:
2039 			bad_error("scf_transaction_start", scf_error());
2040 		}
2041 	}
2042 
2043 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2044 	    UU_DEFAULT) != 0) {
2045 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2046 			bad_error("uu_list_walk", uu_error());
2047 		scf_transaction_reset(imp_tx);
2048 
2049 		lcbdata->sc_err = cbdata.sc_err;
2050 		if (cbdata.sc_err == ECANCELED) {
2051 			warn(pg_changed, lcbdata->sc_target_fmri,
2052 			    p->sc_pgroup_name);
2053 			lcbdata->sc_err = EBUSY;
2054 		}
2055 		return (UU_WALK_ERROR);
2056 	}
2057 
2058 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2059 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2060 
2061 		/*
2062 		 * take the snapshot running snapshot then
2063 		 * import the stored general/enable property
2064 		 */
2065 		r = take_snap(ent, snap_running, imp_rsnap);
2066 		switch (r) {
2067 		case 0:
2068 			break;
2069 
2070 		case ECONNABORTED:
2071 			warn(gettext("Could not take %s snapshot on import "
2072 			    "(repository connection broken).\n"),
2073 			    snap_running);
2074 			lcbdata->sc_err = r;
2075 			return (UU_WALK_ERROR);
2076 		case ECANCELED:
2077 			warn(emsg_deleted);
2078 			lcbdata->sc_err = r;
2079 			return (UU_WALK_ERROR);
2080 
2081 		case EPERM:
2082 			warn(gettext("Could not take %s snapshot "
2083 			    "(permission denied).\n"), snap_running);
2084 			lcbdata->sc_err = r;
2085 			return (UU_WALK_ERROR);
2086 
2087 		case ENOSPC:
2088 			warn(gettext("Could not take %s snapshot"
2089 			    "(repository server out of resources).\n"),
2090 			    snap_running);
2091 			lcbdata->sc_err = r;
2092 			return (UU_WALK_ERROR);
2093 
2094 		default:
2095 			bad_error("take_snap", r);
2096 		}
2097 
2098 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2099 		if (r != UU_WALK_NEXT) {
2100 			if (r != UU_WALK_ERROR)
2101 				bad_error("lscf_property_import", r);
2102 			return (EINVAL);
2103 		}
2104 	}
2105 
2106 	r = scf_transaction_commit(imp_tx);
2107 	switch (r) {
2108 	case 1:
2109 		r = UU_WALK_NEXT;
2110 		break;
2111 
2112 	case 0:
2113 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2114 		lcbdata->sc_err = EBUSY;
2115 		r = UU_WALK_ERROR;
2116 		break;
2117 
2118 	case -1:
2119 		switch (scf_error()) {
2120 		case SCF_ERROR_BACKEND_READONLY:
2121 		case SCF_ERROR_BACKEND_ACCESS:
2122 		case SCF_ERROR_CONNECTION_BROKEN:
2123 		case SCF_ERROR_NO_RESOURCES:
2124 			r = stash_scferror(lcbdata);
2125 			break;
2126 
2127 		case SCF_ERROR_DELETED:
2128 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2129 			    p->sc_pgroup_name);
2130 			lcbdata->sc_err = EBUSY;
2131 			r = UU_WALK_ERROR;
2132 			break;
2133 
2134 		case SCF_ERROR_PERMISSION_DENIED:
2135 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2136 			    lcbdata->sc_target_fmri);
2137 			r = stash_scferror(lcbdata);
2138 			break;
2139 
2140 		case SCF_ERROR_NOT_SET:
2141 		case SCF_ERROR_INVALID_ARGUMENT:
2142 		case SCF_ERROR_NOT_BOUND:
2143 		default:
2144 			bad_error("scf_transaction_commit", scf_error());
2145 		}
2146 
2147 	default:
2148 		bad_error("scf_transaction_commit", r);
2149 	}
2150 
2151 	scf_transaction_destroy_children(imp_tx);
2152 
2153 	return (r);
2154 }
2155 
2156 /*
2157  * Returns
2158  *   0 - success
2159  *   ECONNABORTED - repository connection broken
2160  *   ENOMEM - out of memory
2161  *   ENOSPC - svc.configd is out of resources
2162  *   ECANCELED - inst was deleted
2163  *   EPERM - could not create property group (permission denied) (error printed)
2164  *	   - could not modify property group (permission denied) (error printed)
2165  *   EROFS - could not create property group (repository is read-only)
2166  *   EACCES - could not create property group (backend access denied)
2167  *   EEXIST - could not create property group (already exists)
2168  *   EINVAL - invalid property group name (error printed)
2169  *	    - invalid property name (error printed)
2170  *	    - invalid value (error printed)
2171  *   EBUSY - new property group changed (error printed)
2172  */
2173 static int
2174 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2175     const entity_t *iinst, int flags)
2176 {
2177 	scf_callback_t cbdata;
2178 
2179 	cbdata.sc_handle = scf_instance_handle(inst);
2180 	cbdata.sc_parent = inst;
2181 	cbdata.sc_service = 0;
2182 	cbdata.sc_general = NULL;
2183 	cbdata.sc_enable = NULL;
2184 	cbdata.sc_flags = flags;
2185 	cbdata.sc_source_fmri = iinst->sc_fmri;
2186 	cbdata.sc_target_fmri = target_fmri;
2187 
2188 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2189 	    UU_DEFAULT) != 0) {
2190 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2191 			bad_error("uu_list_walk", uu_error());
2192 
2193 		return (cbdata.sc_err);
2194 	}
2195 
2196 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2197 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2198 		/*
2199 		 * If importing with the SCI_NOENABLED flag then
2200 		 * skip the delay, but if not then add the delay
2201 		 * of the enable property.
2202 		 */
2203 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2204 			cbdata.sc_flags |= SCI_DELAYENABLE;
2205 		}
2206 
2207 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2208 		    != UU_WALK_NEXT)
2209 			return (cbdata.sc_err);
2210 	}
2211 
2212 	return (0);
2213 }
2214 
2215 /*
2216  * Report the reasons why we can't upgrade pg2 to pg1.
2217  */
2218 static void
2219 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2220     int new)
2221 {
2222 	property_t *p1, *p2;
2223 
2224 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2225 
2226 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2227 		return;
2228 
2229 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2230 	    p1 != NULL;
2231 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2232 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2233 		if (p2 != NULL) {
2234 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2235 			    new);
2236 			continue;
2237 		}
2238 
2239 		if (new)
2240 			warn(gettext("Conflict upgrading %s (new property "
2241 			    "group \"%s\" is missing property \"%s\").\n"),
2242 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2243 		else
2244 			warn(gettext("Conflict upgrading %s (property "
2245 			    "\"%s/%s\" is missing).\n"), fmri,
2246 			    pg1->sc_pgroup_name, p1->sc_property_name);
2247 	}
2248 
2249 	/*
2250 	 * Since pg1 should be from the manifest, any properties in pg2 which
2251 	 * aren't in pg1 shouldn't be reported as conflicts.
2252 	 */
2253 }
2254 
2255 /*
2256  * Add transaction entries to tx which will upgrade cur's pg according to old
2257  * & new.
2258  *
2259  * Returns
2260  *   0 - success
2261  *   EINVAL - new has a property with an invalid name or value (message emitted)
2262  *   ENOMEM - out of memory
2263  */
2264 static int
2265 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2266     pgroup_t *cur, int speak, const char *fmri)
2267 {
2268 	property_t *p, *new_p, *cur_p;
2269 	scf_transaction_entry_t *e;
2270 	int r;
2271 	int is_general;
2272 	int is_protected;
2273 
2274 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2275 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2276 		bad_error("uu_list_walk", uu_error());
2277 
2278 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2279 
2280 	for (p = uu_list_first(old->sc_pgroup_props);
2281 	    p != NULL;
2282 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2283 		/* p is a property in the old property group. */
2284 
2285 		/* Protect live properties. */
2286 		is_protected = 0;
2287 		if (is_general) {
2288 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2289 			    0 ||
2290 			    strcmp(p->sc_property_name,
2291 			    SCF_PROPERTY_RESTARTER) == 0)
2292 				is_protected = 1;
2293 		}
2294 
2295 		/* Look for the same property in the new properties. */
2296 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2297 		if (new_p != NULL) {
2298 			new_p->sc_seen = 1;
2299 
2300 			/*
2301 			 * If the new property is the same as the old, don't do
2302 			 * anything (leave any user customizations).
2303 			 */
2304 			if (prop_equal(p, new_p, NULL, NULL, 0))
2305 				continue;
2306 
2307 			if (new_p->sc_property_override)
2308 				goto upgrade;
2309 		}
2310 
2311 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2312 		if (cur_p == NULL) {
2313 			/*
2314 			 * p has been deleted from the repository.  If we were
2315 			 * going to delete it anyway, do nothing.  Otherwise
2316 			 * report a conflict.
2317 			 */
2318 			if (new_p == NULL)
2319 				continue;
2320 
2321 			if (is_protected)
2322 				continue;
2323 
2324 			warn(gettext("Conflict upgrading %s "
2325 			    "(property \"%s/%s\" is missing).\n"), fmri,
2326 			    old->sc_pgroup_name, p->sc_property_name);
2327 			continue;
2328 		}
2329 
2330 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2331 			/*
2332 			 * Conflict.  Don't warn if the property is already the
2333 			 * way we want it, though.
2334 			 */
2335 			if (is_protected)
2336 				continue;
2337 
2338 			if (new_p == NULL)
2339 				(void) prop_equal(p, cur_p, fmri,
2340 				    old->sc_pgroup_name, 0);
2341 			else
2342 				(void) prop_equal(cur_p, new_p, fmri,
2343 				    old->sc_pgroup_name, 0);
2344 			continue;
2345 		}
2346 
2347 		if (is_protected) {
2348 			if (speak)
2349 				warn(gettext("%s: Refusing to upgrade "
2350 				    "\"%s/%s\" (live property).\n"), fmri,
2351 				    old->sc_pgroup_name, p->sc_property_name);
2352 			continue;
2353 		}
2354 
2355 upgrade:
2356 		/* p hasn't been customized in the repository.  Upgrade it. */
2357 		if (new_p == NULL) {
2358 			/* p was deleted.  Delete from cur if unchanged. */
2359 			if (speak)
2360 				warn(gettext(
2361 				    "%s: Deleting property \"%s/%s\".\n"),
2362 				    fmri, old->sc_pgroup_name,
2363 				    p->sc_property_name);
2364 
2365 			e = scf_entry_create(g_hndl);
2366 			if (e == NULL)
2367 				return (ENOMEM);
2368 
2369 			if (scf_transaction_property_delete(tx, e,
2370 			    p->sc_property_name) != 0) {
2371 				switch (scf_error()) {
2372 				case SCF_ERROR_DELETED:
2373 					scf_entry_destroy(e);
2374 					return (ECANCELED);
2375 
2376 				case SCF_ERROR_CONNECTION_BROKEN:
2377 					scf_entry_destroy(e);
2378 					return (ECONNABORTED);
2379 
2380 				case SCF_ERROR_NOT_FOUND:
2381 					/*
2382 					 * This can happen if cur is from the
2383 					 * running snapshot (and it differs
2384 					 * from the live properties).
2385 					 */
2386 					scf_entry_destroy(e);
2387 					break;
2388 
2389 				case SCF_ERROR_HANDLE_MISMATCH:
2390 				case SCF_ERROR_NOT_BOUND:
2391 				case SCF_ERROR_NOT_SET:
2392 				case SCF_ERROR_INVALID_ARGUMENT:
2393 				default:
2394 					bad_error(
2395 					    "scf_transaction_property_delete",
2396 					    scf_error());
2397 				}
2398 			}
2399 		} else {
2400 			scf_callback_t ctx;
2401 
2402 			if (speak)
2403 				warn(gettext(
2404 				    "%s: Upgrading property \"%s/%s\".\n"),
2405 				    fmri, old->sc_pgroup_name,
2406 				    p->sc_property_name);
2407 
2408 			ctx.sc_handle = g_hndl;
2409 			ctx.sc_trans = tx;
2410 			ctx.sc_flags = 0;
2411 
2412 			r = lscf_property_import(new_p, &ctx);
2413 			if (r != UU_WALK_NEXT) {
2414 				if (r != UU_WALK_ERROR)
2415 					bad_error("lscf_property_import", r);
2416 				return (EINVAL);
2417 			}
2418 		}
2419 	}
2420 
2421 	/* Go over the properties which were added. */
2422 	for (new_p = uu_list_first(new->sc_pgroup_props);
2423 	    new_p != NULL;
2424 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
2425 		if (new_p->sc_seen)
2426 			continue;
2427 
2428 		/* This is a new property. */
2429 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
2430 		if (cur_p == NULL) {
2431 			scf_callback_t ctx;
2432 
2433 			ctx.sc_handle = g_hndl;
2434 			ctx.sc_trans = tx;
2435 			ctx.sc_flags = 0;
2436 
2437 			r = lscf_property_import(new_p, &ctx);
2438 			if (r != UU_WALK_NEXT) {
2439 				if (r != UU_WALK_ERROR)
2440 					bad_error("lscf_property_import", r);
2441 				return (EINVAL);
2442 			}
2443 			continue;
2444 		}
2445 
2446 		/*
2447 		 * Report a conflict if the new property differs from the
2448 		 * current one.  Unless it's general/enabled, since that's
2449 		 * never in the last-import snapshot.
2450 		 */
2451 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2452 		    0 &&
2453 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
2454 			continue;
2455 
2456 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
2457 	}
2458 
2459 	return (0);
2460 }
2461 
2462 /*
2463  * Upgrade pg according to old & new.
2464  *
2465  * Returns
2466  *   0 - success
2467  *   ECONNABORTED - repository connection broken
2468  *   ENOMEM - out of memory
2469  *   ENOSPC - svc.configd is out of resources
2470  *   ECANCELED - pg was deleted
2471  *   EPERM - couldn't modify pg (permission denied)
2472  *   EROFS - couldn't modify pg (backend read-only)
2473  *   EACCES - couldn't modify pg (backend access denied)
2474  *   EINVAL - new has a property with invalid name or value (error printed)
2475  *   EBUSY - pg changed unexpectedly
2476  */
2477 static int
2478 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
2479     pgroup_t *new, int speak, const char *fmri)
2480 {
2481 	int r;
2482 
2483 	if (scf_transaction_start(imp_tx, pg) != 0) {
2484 		switch (scf_error()) {
2485 		case SCF_ERROR_CONNECTION_BROKEN:
2486 		case SCF_ERROR_DELETED:
2487 		case SCF_ERROR_PERMISSION_DENIED:
2488 		case SCF_ERROR_BACKEND_READONLY:
2489 		case SCF_ERROR_BACKEND_ACCESS:
2490 			return (scferror2errno(scf_error()));
2491 
2492 		case SCF_ERROR_HANDLE_MISMATCH:
2493 		case SCF_ERROR_IN_USE:
2494 		case SCF_ERROR_NOT_BOUND:
2495 		case SCF_ERROR_NOT_SET:
2496 		default:
2497 			bad_error("scf_transaction_start", scf_error());
2498 		}
2499 	}
2500 
2501 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
2502 	switch (r) {
2503 	case 0:
2504 		break;
2505 
2506 	case EINVAL:
2507 	case ENOMEM:
2508 		scf_transaction_destroy_children(imp_tx);
2509 		return (r);
2510 
2511 	default:
2512 		bad_error("add_upgrade_entries", r);
2513 	}
2514 
2515 	r = scf_transaction_commit(imp_tx);
2516 
2517 	scf_transaction_destroy_children(imp_tx);
2518 
2519 	switch (r) {
2520 	case 1:
2521 		break;
2522 
2523 	case 0:
2524 		return (EBUSY);
2525 
2526 	case -1:
2527 		switch (scf_error()) {
2528 		case SCF_ERROR_CONNECTION_BROKEN:
2529 		case SCF_ERROR_NO_RESOURCES:
2530 		case SCF_ERROR_PERMISSION_DENIED:
2531 		case SCF_ERROR_BACKEND_READONLY:
2532 		case SCF_ERROR_BACKEND_ACCESS:
2533 		case SCF_ERROR_DELETED:
2534 			return (scferror2errno(scf_error()));
2535 
2536 		case SCF_ERROR_NOT_BOUND:
2537 		case SCF_ERROR_INVALID_ARGUMENT:
2538 		case SCF_ERROR_NOT_SET:
2539 		default:
2540 			bad_error("scf_transaction_commit", scf_error());
2541 		}
2542 
2543 	default:
2544 		bad_error("scf_transaction_commit", r);
2545 	}
2546 
2547 	return (0);
2548 }
2549 
2550 /*
2551  * Compares two entity FMRIs.  Returns
2552  *
2553  *   1 - equal
2554  *   0 - not equal
2555  *   -1 - f1 is invalid or not an entity
2556  *   -2 - f2 is invalid or not an entity
2557  */
2558 static int
2559 fmri_equal(const char *f1, const char *f2)
2560 {
2561 	int r;
2562 	const char *s1, *i1, *pg1;
2563 	const char *s2, *i2, *pg2;
2564 
2565 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2566 		return (-1);
2567 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
2568 		return (-1);
2569 
2570 	if (s1 == NULL || pg1 != NULL)
2571 		return (-1);
2572 
2573 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2574 		return (-2);
2575 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
2576 		return (-2);
2577 
2578 	if (s2 == NULL || pg2 != NULL)
2579 		return (-2);
2580 
2581 	r = strcmp(s1, s2);
2582 	if (r != 0)
2583 		return (0);
2584 
2585 	if (i1 == NULL && i2 == NULL)
2586 		return (1);
2587 
2588 	if (i1 == NULL || i2 == NULL)
2589 		return (0);
2590 
2591 	return (strcmp(i1, i2) == 0);
2592 }
2593 
2594 /*
2595  * Import a dependent by creating a dependency property group in the dependent
2596  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
2597  * dependents pg, and add an entry to create a new property for this
2598  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
2599  *
2600  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
2601  * lcbdata->sc_err to
2602  *   ECONNABORTED - repository connection broken
2603  *   ENOMEM - out of memory
2604  *   ENOSPC - configd is out of resources
2605  *   EINVAL - target is invalid (error printed)
2606  *	    - target is not an entity (error printed)
2607  *	    - dependent has invalid name (error printed)
2608  *	    - invalid property name (error printed)
2609  *	    - invalid value (error printed)
2610  *	    - scope of target does not exist (error printed)
2611  *   EPERM - couldn't create target (permission denied) (error printed)
2612  *	   - couldn't create dependency pg (permission denied) (error printed)
2613  *	   - couldn't modify dependency pg (permission denied) (error printed)
2614  *   EROFS - couldn't create target (repository read-only)
2615  *	   - couldn't create dependency pg (repository read-only)
2616  *   EACCES - couldn't create target (backend access denied)
2617  *	    - couldn't create dependency pg (backend access denied)
2618  *   ECANCELED - sc_trans's pg was deleted
2619  *   EALREADY - property for dependent already exists in sc_trans's pg
2620  *   EEXIST - dependency pg already exists in target (error printed)
2621  *   EBUSY - target deleted (error printed)
2622  *         - property group changed during import (error printed)
2623  */
2624 static int
2625 lscf_dependent_import(void *a1, void *pvt)
2626 {
2627 	pgroup_t *pgrp = a1;
2628 	scf_callback_t *lcbdata = pvt;
2629 
2630 	int isservice;
2631 	int ret;
2632 	scf_transaction_entry_t *e;
2633 	scf_value_t *val;
2634 	scf_callback_t dependent_cbdata;
2635 	scf_error_t scfe;
2636 
2637 	/*
2638 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
2639 	 * it's invalid, we fail before modifying the repository.
2640 	 */
2641 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2642 	    &dependent_cbdata.sc_parent, &isservice);
2643 	switch (scfe) {
2644 	case SCF_ERROR_NONE:
2645 		break;
2646 
2647 	case SCF_ERROR_NO_MEMORY:
2648 		return (stash_scferror_err(lcbdata, scfe));
2649 
2650 	case SCF_ERROR_INVALID_ARGUMENT:
2651 		semerr(gettext("The FMRI for the \"%s\" dependent is "
2652 		    "invalid.\n"), pgrp->sc_pgroup_name);
2653 		return (stash_scferror_err(lcbdata, scfe));
2654 
2655 	case SCF_ERROR_CONSTRAINT_VIOLATED:
2656 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
2657 		    "specifies neither a service nor an instance.\n"),
2658 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2659 		return (stash_scferror_err(lcbdata, scfe));
2660 
2661 	case SCF_ERROR_NOT_FOUND:
2662 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2663 		    &dependent_cbdata.sc_parent, &isservice);
2664 		switch (scfe) {
2665 		case SCF_ERROR_NONE:
2666 			break;
2667 
2668 		case SCF_ERROR_NO_MEMORY:
2669 		case SCF_ERROR_BACKEND_READONLY:
2670 		case SCF_ERROR_BACKEND_ACCESS:
2671 			return (stash_scferror_err(lcbdata, scfe));
2672 
2673 		case SCF_ERROR_NOT_FOUND:
2674 			semerr(gettext("The scope in FMRI \"%s\" for the "
2675 			    "\"%s\" dependent does not exist.\n"),
2676 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2677 			lcbdata->sc_err = EINVAL;
2678 			return (UU_WALK_ERROR);
2679 
2680 		case SCF_ERROR_PERMISSION_DENIED:
2681 			warn(gettext(
2682 			    "Could not create %s (permission denied).\n"),
2683 			    pgrp->sc_pgroup_fmri);
2684 			return (stash_scferror_err(lcbdata, scfe));
2685 
2686 		case SCF_ERROR_INVALID_ARGUMENT:
2687 		case SCF_ERROR_CONSTRAINT_VIOLATED:
2688 		default:
2689 			bad_error("create_entity", scfe);
2690 		}
2691 		break;
2692 
2693 	default:
2694 		bad_error("fmri_to_entity", scfe);
2695 	}
2696 
2697 	if (lcbdata->sc_trans != NULL) {
2698 		e = scf_entry_create(lcbdata->sc_handle);
2699 		if (e == NULL) {
2700 			if (scf_error() != SCF_ERROR_NO_MEMORY)
2701 				bad_error("scf_entry_create", scf_error());
2702 
2703 			entity_destroy(dependent_cbdata.sc_parent, isservice);
2704 			return (stash_scferror(lcbdata));
2705 		}
2706 
2707 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
2708 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
2709 			switch (scf_error()) {
2710 			case SCF_ERROR_INVALID_ARGUMENT:
2711 				warn(gettext("Dependent of %s has invalid name "
2712 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
2713 				    pgrp->sc_pgroup_name);
2714 				/* FALLTHROUGH */
2715 
2716 			case SCF_ERROR_DELETED:
2717 			case SCF_ERROR_CONNECTION_BROKEN:
2718 				scf_entry_destroy(e);
2719 				entity_destroy(dependent_cbdata.sc_parent,
2720 				    isservice);
2721 				return (stash_scferror(lcbdata));
2722 
2723 			case SCF_ERROR_EXISTS:
2724 				scf_entry_destroy(e);
2725 				entity_destroy(dependent_cbdata.sc_parent,
2726 				    isservice);
2727 				lcbdata->sc_err = EALREADY;
2728 				return (UU_WALK_ERROR);
2729 
2730 			case SCF_ERROR_NOT_BOUND:
2731 			case SCF_ERROR_HANDLE_MISMATCH:
2732 			case SCF_ERROR_NOT_SET:
2733 			default:
2734 				bad_error("scf_transaction_property_new",
2735 				    scf_error());
2736 			}
2737 		}
2738 
2739 		val = scf_value_create(lcbdata->sc_handle);
2740 		if (val == NULL) {
2741 			if (scf_error() != SCF_ERROR_NO_MEMORY)
2742 				bad_error("scf_value_create", scf_error());
2743 
2744 			entity_destroy(dependent_cbdata.sc_parent, isservice);
2745 			return (stash_scferror(lcbdata));
2746 		}
2747 
2748 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
2749 		    pgrp->sc_pgroup_fmri) != 0)
2750 			/* invalid should have been caught above */
2751 			bad_error("scf_value_set_from_string", scf_error());
2752 
2753 		if (scf_entry_add_value(e, val) != 0)
2754 			bad_error("scf_entry_add_value", scf_error());
2755 	}
2756 
2757 	/* Add the property group to the target entity. */
2758 
2759 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
2760 	dependent_cbdata.sc_flags = 0;
2761 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
2762 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
2763 
2764 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
2765 
2766 	entity_destroy(dependent_cbdata.sc_parent, isservice);
2767 
2768 	if (ret == UU_WALK_NEXT)
2769 		return (ret);
2770 
2771 	if (ret != UU_WALK_ERROR)
2772 		bad_error("entity_pgroup_import", ret);
2773 
2774 	switch (dependent_cbdata.sc_err) {
2775 	case ECANCELED:
2776 		warn(gettext("%s deleted unexpectedly.\n"),
2777 		    pgrp->sc_pgroup_fmri);
2778 		lcbdata->sc_err = EBUSY;
2779 		break;
2780 
2781 	case EEXIST:
2782 		warn(gettext("Could not create \"%s\" dependency in %s "
2783 		    "(already exists).\n"), pgrp->sc_pgroup_name,
2784 		    pgrp->sc_pgroup_fmri);
2785 		/* FALLTHROUGH */
2786 
2787 	default:
2788 		lcbdata->sc_err = dependent_cbdata.sc_err;
2789 	}
2790 
2791 	return (UU_WALK_ERROR);
2792 }
2793 
2794 static int upgrade_dependent(const scf_property_t *, const entity_t *,
2795     const scf_snaplevel_t *, scf_transaction_t *);
2796 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
2797     const pgroup_t *);
2798 
2799 /*
2800  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
2801  * the current dependent targets from running (the snaplevel of a running
2802  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
2803  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
2804  * dependent targets and dependency properties from li_dpts_pg (the
2805  * "dependents" property group in snpl) and snpl (the snaplevel which
2806  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
2807  * snpl doesn't have a "dependents" property group, and any dependents in ient
2808  * are new.
2809  *
2810  * Returns
2811  *   0 - success
2812  *   ECONNABORTED - repository connection broken
2813  *   ENOMEM - out of memory
2814  *   ENOSPC - configd is out of resources
2815  *   ECANCELED - ent was deleted
2816  *   ENODEV - the entity containing li_dpts_pg was deleted
2817  *   EPERM - could not modify dependents pg (permission denied) (error printed)
2818  *	   - couldn't upgrade dependent (permission denied) (error printed)
2819  *	   - couldn't create dependent (permission denied) (error printed)
2820  *   EROFS - could not modify dependents pg (repository read-only)
2821  *	   - couldn't upgrade dependent (repository read-only)
2822  *	   - couldn't create dependent (repository read-only)
2823  *   EACCES - could not modify dependents pg (backend access denied)
2824  *	    - could not upgrade dependent (backend access denied)
2825  *	    - could not create dependent (backend access denied)
2826  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
2827  *	   - dependent target deleted (error printed)
2828  *	   - dependent pg changed (error printed)
2829  *   EINVAL - new dependent is invalid (error printed)
2830  *   EBADF - snpl is corrupt (error printed)
2831  *	   - snpl has corrupt pg (error printed)
2832  *	   - dependency pg in target is corrupt (error printed)
2833  *	   - target has corrupt snapshot (error printed)
2834  *   EEXIST - dependency pg already existed in target service (error printed)
2835  */
2836 static int
2837 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
2838     const scf_snaplevel_t *snpl, const entity_t *ient,
2839     const scf_snaplevel_t *running, void *ent)
2840 {
2841 	pgroup_t *new_dpt_pgroup;
2842 	scf_callback_t cbdata;
2843 	int r, unseen, tx_started = 0;
2844 	int have_cur_depts;
2845 
2846 	const char * const dependents = "dependents";
2847 
2848 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
2849 
2850 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
2851 		/* Nothing to do. */
2852 		return (0);
2853 
2854 	/* Fetch the current version of the "dependents" property group. */
2855 	have_cur_depts = 1;
2856 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
2857 		switch (scf_error()) {
2858 		case SCF_ERROR_NOT_FOUND:
2859 			break;
2860 
2861 		case SCF_ERROR_DELETED:
2862 		case SCF_ERROR_CONNECTION_BROKEN:
2863 			return (scferror2errno(scf_error()));
2864 
2865 		case SCF_ERROR_NOT_SET:
2866 		case SCF_ERROR_INVALID_ARGUMENT:
2867 		case SCF_ERROR_HANDLE_MISMATCH:
2868 		case SCF_ERROR_NOT_BOUND:
2869 		default:
2870 			bad_error("entity_get_pg", scf_error());
2871 		}
2872 
2873 		have_cur_depts = 0;
2874 	}
2875 
2876 	/* Fetch the running version of the "dependents" property group. */
2877 	ud_run_dpts_pg_set = 0;
2878 	if (running != NULL)
2879 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
2880 	else
2881 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
2882 	if (r == 0) {
2883 		ud_run_dpts_pg_set = 1;
2884 	} else {
2885 		switch (scf_error()) {
2886 		case SCF_ERROR_NOT_FOUND:
2887 			break;
2888 
2889 		case SCF_ERROR_DELETED:
2890 		case SCF_ERROR_CONNECTION_BROKEN:
2891 			return (scferror2errno(scf_error()));
2892 
2893 		case SCF_ERROR_NOT_SET:
2894 		case SCF_ERROR_INVALID_ARGUMENT:
2895 		case SCF_ERROR_HANDLE_MISMATCH:
2896 		case SCF_ERROR_NOT_BOUND:
2897 		default:
2898 			bad_error(running ? "scf_snaplevel_get_pg" :
2899 			    "entity_get_pg", scf_error());
2900 		}
2901 	}
2902 
2903 	/*
2904 	 * Clear the seen fields of the dependents, so we can tell which ones
2905 	 * are new.
2906 	 */
2907 	if (uu_list_walk(ient->sc_dependents, clear_int,
2908 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
2909 		bad_error("uu_list_walk", uu_error());
2910 
2911 	if (li_dpts_pg != NULL) {
2912 		/*
2913 		 * Each property in li_dpts_pg represents a dependent tag in
2914 		 * the old manifest.  For each, call upgrade_dependent(),
2915 		 * which will change ud_cur_depts_pg or dependencies in other
2916 		 * services as appropriate.  Note (a) that changes to
2917 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
2918 		 * made en masse, and (b) it's ok if the entity doesn't have
2919 		 * a current version of the "dependents" property group,
2920 		 * because we'll just consider all dependents as customized
2921 		 * (by being deleted).
2922 		 */
2923 
2924 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
2925 			switch (scf_error()) {
2926 			case SCF_ERROR_DELETED:
2927 				return (ENODEV);
2928 
2929 			case SCF_ERROR_CONNECTION_BROKEN:
2930 				return (ECONNABORTED);
2931 
2932 			case SCF_ERROR_HANDLE_MISMATCH:
2933 			case SCF_ERROR_NOT_BOUND:
2934 			case SCF_ERROR_NOT_SET:
2935 			default:
2936 				bad_error("scf_iter_pg_properties",
2937 				    scf_error());
2938 			}
2939 		}
2940 
2941 		if (have_cur_depts &&
2942 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
2943 			switch (scf_error()) {
2944 			case SCF_ERROR_BACKEND_ACCESS:
2945 			case SCF_ERROR_BACKEND_READONLY:
2946 			case SCF_ERROR_CONNECTION_BROKEN:
2947 				return (scferror2errno(scf_error()));
2948 
2949 			case SCF_ERROR_DELETED:
2950 				warn(emsg_pg_deleted, ient->sc_fmri,
2951 				    dependents);
2952 				return (EBUSY);
2953 
2954 			case SCF_ERROR_PERMISSION_DENIED:
2955 				warn(emsg_pg_mod_perm, dependents,
2956 				    ient->sc_fmri);
2957 				return (scferror2errno(scf_error()));
2958 
2959 			case SCF_ERROR_HANDLE_MISMATCH:
2960 			case SCF_ERROR_IN_USE:
2961 			case SCF_ERROR_NOT_BOUND:
2962 			case SCF_ERROR_NOT_SET:
2963 			default:
2964 				bad_error("scf_transaction_start", scf_error());
2965 			}
2966 		}
2967 		tx_started = have_cur_depts;
2968 
2969 		for (;;) {
2970 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
2971 			if (r == 0)
2972 				break;
2973 			if (r == 1) {
2974 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
2975 				    tx_started ? ud_tx : NULL);
2976 				switch (r) {
2977 				case 0:
2978 					continue;
2979 
2980 				case ECONNABORTED:
2981 				case ENOMEM:
2982 				case ENOSPC:
2983 				case EBADF:
2984 				case EBUSY:
2985 				case EINVAL:
2986 				case EPERM:
2987 				case EROFS:
2988 				case EACCES:
2989 				case EEXIST:
2990 					break;
2991 
2992 				case ECANCELED:
2993 					r = ENODEV;
2994 					break;
2995 
2996 				default:
2997 					bad_error("upgrade_dependent", r);
2998 				}
2999 
3000 				if (tx_started)
3001 					scf_transaction_destroy_children(ud_tx);
3002 				return (r);
3003 			}
3004 			if (r != -1)
3005 				bad_error("scf_iter_next_property", r);
3006 
3007 			switch (scf_error()) {
3008 			case SCF_ERROR_DELETED:
3009 				r = ENODEV;
3010 				break;
3011 
3012 			case SCF_ERROR_CONNECTION_BROKEN:
3013 				r = ECONNABORTED;
3014 				break;
3015 
3016 			case SCF_ERROR_NOT_SET:
3017 			case SCF_ERROR_INVALID_ARGUMENT:
3018 			case SCF_ERROR_NOT_BOUND:
3019 			case SCF_ERROR_HANDLE_MISMATCH:
3020 			default:
3021 				bad_error("scf_iter_next_property",
3022 				    scf_error());
3023 			}
3024 
3025 			if (tx_started)
3026 				scf_transaction_destroy_children(ud_tx);
3027 			return (r);
3028 		}
3029 	}
3030 
3031 	/* import unseen dependents */
3032 	unseen = 0;
3033 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3034 	    new_dpt_pgroup != NULL;
3035 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3036 	    new_dpt_pgroup)) {
3037 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3038 			unseen = 1;
3039 			break;
3040 		}
3041 	}
3042 
3043 	/* If there are none, exit early. */
3044 	if (unseen == 0)
3045 		goto commit;
3046 
3047 	/* Set up for lscf_dependent_import() */
3048 	cbdata.sc_handle = g_hndl;
3049 	cbdata.sc_parent = ent;
3050 	cbdata.sc_service = issvc;
3051 	cbdata.sc_flags = 0;
3052 
3053 	if (!have_cur_depts) {
3054 		/*
3055 		 * We have new dependents to import, so we need a "dependents"
3056 		 * property group.
3057 		 */
3058 		if (issvc)
3059 			r = scf_service_add_pg(ent, dependents,
3060 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3061 		else
3062 			r = scf_instance_add_pg(ent, dependents,
3063 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3064 		if (r != 0) {
3065 			switch (scf_error()) {
3066 			case SCF_ERROR_DELETED:
3067 			case SCF_ERROR_CONNECTION_BROKEN:
3068 			case SCF_ERROR_BACKEND_READONLY:
3069 			case SCF_ERROR_BACKEND_ACCESS:
3070 			case SCF_ERROR_NO_RESOURCES:
3071 				return (scferror2errno(scf_error()));
3072 
3073 			case SCF_ERROR_EXISTS:
3074 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3075 				return (EBUSY);
3076 
3077 			case SCF_ERROR_PERMISSION_DENIED:
3078 				warn(emsg_pg_add_perm, dependents,
3079 				    ient->sc_fmri);
3080 				return (scferror2errno(scf_error()));
3081 
3082 			case SCF_ERROR_NOT_BOUND:
3083 			case SCF_ERROR_HANDLE_MISMATCH:
3084 			case SCF_ERROR_INVALID_ARGUMENT:
3085 			case SCF_ERROR_NOT_SET:
3086 			default:
3087 				bad_error("scf_service_add_pg", scf_error());
3088 			}
3089 		}
3090 	}
3091 
3092 	cbdata.sc_trans = ud_tx;
3093 
3094 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3095 		switch (scf_error()) {
3096 		case SCF_ERROR_CONNECTION_BROKEN:
3097 		case SCF_ERROR_BACKEND_ACCESS:
3098 		case SCF_ERROR_BACKEND_READONLY:
3099 			return (scferror2errno(scf_error()));
3100 
3101 		case SCF_ERROR_DELETED:
3102 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3103 			return (EBUSY);
3104 
3105 		case SCF_ERROR_PERMISSION_DENIED:
3106 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3107 			return (scferror2errno(scf_error()));
3108 
3109 		case SCF_ERROR_HANDLE_MISMATCH:
3110 		case SCF_ERROR_IN_USE:
3111 		case SCF_ERROR_NOT_BOUND:
3112 		case SCF_ERROR_NOT_SET:
3113 		default:
3114 			bad_error("scf_transaction_start", scf_error());
3115 		}
3116 	}
3117 	tx_started = 1;
3118 
3119 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3120 	    new_dpt_pgroup != NULL;
3121 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3122 	    new_dpt_pgroup)) {
3123 		if (new_dpt_pgroup->sc_pgroup_seen)
3124 			continue;
3125 
3126 		if (ud_run_dpts_pg_set) {
3127 			/*
3128 			 * If the dependent is already there, then we have
3129 			 * a conflict.
3130 			 */
3131 			if (scf_pg_get_property(ud_run_dpts_pg,
3132 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3133 				r = handle_dependent_conflict(ient, ud_prop,
3134 				    new_dpt_pgroup);
3135 				switch (r) {
3136 				case 0:
3137 					continue;
3138 
3139 				case ECONNABORTED:
3140 				case ENOMEM:
3141 				case EBUSY:
3142 				case EBADF:
3143 				case EINVAL:
3144 					scf_transaction_destroy_children(ud_tx);
3145 					return (r);
3146 
3147 				default:
3148 					bad_error("handle_dependent_conflict",
3149 					    r);
3150 				}
3151 			} else {
3152 				switch (scf_error()) {
3153 				case SCF_ERROR_NOT_FOUND:
3154 					break;
3155 
3156 				case SCF_ERROR_INVALID_ARGUMENT:
3157 					warn(emsg_fmri_invalid_pg_name,
3158 					    ient->sc_fmri,
3159 					    new_dpt_pgroup->sc_pgroup_name);
3160 					scf_transaction_destroy_children(ud_tx);
3161 					return (EINVAL);
3162 
3163 				case SCF_ERROR_DELETED:
3164 					warn(emsg_pg_deleted, ient->sc_fmri,
3165 					    new_dpt_pgroup->sc_pgroup_name);
3166 					scf_transaction_destroy_children(ud_tx);
3167 					return (EBUSY);
3168 
3169 				case SCF_ERROR_CONNECTION_BROKEN:
3170 					scf_transaction_destroy_children(ud_tx);
3171 					return (ECONNABORTED);
3172 
3173 				case SCF_ERROR_NOT_BOUND:
3174 				case SCF_ERROR_HANDLE_MISMATCH:
3175 				case SCF_ERROR_NOT_SET:
3176 				default:
3177 					bad_error("scf_pg_get_property",
3178 					    scf_error());
3179 				}
3180 			}
3181 		}
3182 
3183 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3184 		if (r != UU_WALK_NEXT) {
3185 			if (r != UU_WALK_ERROR)
3186 				bad_error("lscf_dependent_import", r);
3187 
3188 			if (cbdata.sc_err == EALREADY) {
3189 				/* Collisions were handled preemptively. */
3190 				bad_error("lscf_dependent_import",
3191 				    cbdata.sc_err);
3192 			}
3193 
3194 			scf_transaction_destroy_children(ud_tx);
3195 			return (cbdata.sc_err);
3196 		}
3197 	}
3198 
3199 commit:
3200 	if (!tx_started)
3201 		return (0);
3202 
3203 	r = scf_transaction_commit(ud_tx);
3204 
3205 	scf_transaction_destroy_children(ud_tx);
3206 
3207 	switch (r) {
3208 	case 1:
3209 		return (0);
3210 
3211 	case 0:
3212 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3213 		return (EBUSY);
3214 
3215 	case -1:
3216 		break;
3217 
3218 	default:
3219 		bad_error("scf_transaction_commit", r);
3220 	}
3221 
3222 	switch (scf_error()) {
3223 	case SCF_ERROR_CONNECTION_BROKEN:
3224 	case SCF_ERROR_BACKEND_READONLY:
3225 	case SCF_ERROR_BACKEND_ACCESS:
3226 	case SCF_ERROR_NO_RESOURCES:
3227 		return (scferror2errno(scf_error()));
3228 
3229 	case SCF_ERROR_DELETED:
3230 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3231 		return (EBUSY);
3232 
3233 	case SCF_ERROR_PERMISSION_DENIED:
3234 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3235 		return (scferror2errno(scf_error()));
3236 
3237 	case SCF_ERROR_NOT_BOUND:
3238 	case SCF_ERROR_INVALID_ARGUMENT:
3239 	case SCF_ERROR_NOT_SET:
3240 	default:
3241 		bad_error("scf_transaction_destroy", scf_error());
3242 		/* NOTREACHED */
3243 	}
3244 }
3245 
3246 /*
3247  * prop is taken to be a property in the "dependents" property group of snpl,
3248  * which is taken to be the snaplevel of a last-import snapshot corresponding
3249  * to ient.  If prop is a valid dependents property, upgrade the dependent it
3250  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
3251  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
3252  * of the entity ient represents (possibly in the running snapshot).  If it
3253  * needs to be changed, an entry will be added to tx, if not NULL.
3254  *
3255  * Returns
3256  *   0 - success
3257  *   ECONNABORTED - repository connection broken
3258  *   ENOMEM - out of memory
3259  *   ENOSPC - configd was out of resources
3260  *   ECANCELED - snpl's entity was deleted
3261  *   EINVAL - dependent target is invalid (error printed)
3262  *	    - dependent is invalid (error printed)
3263  *   EBADF - snpl is corrupt (error printed)
3264  *	   - snpl has corrupt pg (error printed)
3265  *	   - dependency pg in target is corrupt (error printed)
3266  *	   - running snapshot in dependent is missing snaplevel (error printed)
3267  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
3268  *	   - couldn't create dependent (permission denied) (error printed)
3269  *	   - couldn't modify dependent pg (permission denied) (error printed)
3270  *   EROFS - couldn't delete dependency pg (repository read-only)
3271  *	   - couldn't create dependent (repository read-only)
3272  *   EACCES - couldn't delete dependency pg (backend access denied)
3273  *	    - couldn't create dependent (backend access denied)
3274  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
3275  *	   - tx's pg was deleted (error printed)
3276  *	   - dependent pg was changed or deleted (error printed)
3277  *   EEXIST - dependency pg already exists in new target (error printed)
3278  */
3279 static int
3280 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
3281     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
3282 {
3283 	pgroup_t pgrp;
3284 	scf_type_t ty;
3285 	pgroup_t *new_dpt_pgroup;
3286 	pgroup_t *old_dpt_pgroup = NULL;
3287 	pgroup_t *current_pg;
3288 	scf_callback_t cbdata;
3289 	int tissvc;
3290 	void *target_ent;
3291 	scf_error_t serr;
3292 	int r;
3293 	scf_transaction_entry_t *ent;
3294 
3295 	const char * const cf_inval = gettext("Conflict upgrading %s "
3296 	    "(dependent \"%s\" has invalid dependents property).\n");
3297 	const char * const cf_missing = gettext("Conflict upgrading %s "
3298 	    "(dependent \"%s\" is missing).\n");
3299 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
3300 	    "(dependent \"%s\" has new dependency property group).\n");
3301 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
3302 	    "(dependent \"%s\" has new target).\n");
3303 	const char * const li_corrupt =
3304 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
3305 	const char * const upgrading =
3306 	    gettext("%s: Upgrading dependent \"%s\".\n");
3307 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
3308 	    "corrupt (missing snaplevel).\n");
3309 
3310 	if (scf_property_type(prop, &ty) != 0) {
3311 		switch (scf_error()) {
3312 		case SCF_ERROR_DELETED:
3313 		case SCF_ERROR_CONNECTION_BROKEN:
3314 			return (scferror2errno(scf_error()));
3315 
3316 		case SCF_ERROR_NOT_BOUND:
3317 		case SCF_ERROR_NOT_SET:
3318 		default:
3319 			bad_error("scf_property_type", scf_error());
3320 		}
3321 	}
3322 
3323 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3324 		warn(li_corrupt, ient->sc_fmri);
3325 		return (EBADF);
3326 	}
3327 
3328 	/*
3329 	 * prop represents a dependent in the old manifest.  It is named after
3330 	 * the dependent.
3331 	 */
3332 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
3333 		switch (scf_error()) {
3334 		case SCF_ERROR_DELETED:
3335 		case SCF_ERROR_CONNECTION_BROKEN:
3336 			return (scferror2errno(scf_error()));
3337 
3338 		case SCF_ERROR_NOT_BOUND:
3339 		case SCF_ERROR_NOT_SET:
3340 		default:
3341 			bad_error("scf_property_get_name", scf_error());
3342 		}
3343 	}
3344 
3345 	/* See if it's in the new manifest. */
3346 	pgrp.sc_pgroup_name = ud_name;
3347 	new_dpt_pgroup =
3348 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
3349 
3350 	/* If it's not, delete it... if it hasn't been customized. */
3351 	if (new_dpt_pgroup == NULL) {
3352 		pgroup_t *dpt;
3353 
3354 		if (!ud_run_dpts_pg_set)
3355 			return (0);
3356 
3357 		if (scf_property_get_value(prop, ud_val) != 0) {
3358 			switch (scf_error()) {
3359 			case SCF_ERROR_NOT_FOUND:
3360 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3361 				warn(li_corrupt, ient->sc_fmri);
3362 				return (EBADF);
3363 
3364 			case SCF_ERROR_DELETED:
3365 			case SCF_ERROR_CONNECTION_BROKEN:
3366 				return (scferror2errno(scf_error()));
3367 
3368 			case SCF_ERROR_HANDLE_MISMATCH:
3369 			case SCF_ERROR_NOT_BOUND:
3370 			case SCF_ERROR_NOT_SET:
3371 			case SCF_ERROR_PERMISSION_DENIED:
3372 			default:
3373 				bad_error("scf_property_get_value",
3374 				    scf_error());
3375 			}
3376 		}
3377 
3378 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
3379 		    max_scf_value_len + 1) < 0)
3380 			bad_error("scf_value_get_as_string", scf_error());
3381 
3382 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
3383 		    0) {
3384 			switch (scf_error()) {
3385 			case SCF_ERROR_NOT_FOUND:
3386 				return (0);
3387 
3388 			case SCF_ERROR_CONNECTION_BROKEN:
3389 				return (scferror2errno(scf_error()));
3390 
3391 			case SCF_ERROR_DELETED:
3392 				warn(emsg_pg_deleted, ient->sc_fmri,
3393 				    "dependents");
3394 				return (EBUSY);
3395 
3396 			case SCF_ERROR_INVALID_ARGUMENT:
3397 			case SCF_ERROR_NOT_BOUND:
3398 			case SCF_ERROR_HANDLE_MISMATCH:
3399 			case SCF_ERROR_NOT_SET:
3400 			default:
3401 				bad_error("scf_pg_get_property", scf_error());
3402 			}
3403 		}
3404 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
3405 			switch (scf_error()) {
3406 			case SCF_ERROR_NOT_FOUND:
3407 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3408 				warn(cf_inval, ient->sc_fmri, ud_name);
3409 				return (0);
3410 
3411 			case SCF_ERROR_DELETED:
3412 			case SCF_ERROR_CONNECTION_BROKEN:
3413 				return (scferror2errno(scf_error()));
3414 
3415 			case SCF_ERROR_HANDLE_MISMATCH:
3416 			case SCF_ERROR_NOT_BOUND:
3417 			case SCF_ERROR_NOT_SET:
3418 			case SCF_ERROR_PERMISSION_DENIED:
3419 			default:
3420 				bad_error("scf_property_get_value",
3421 				    scf_error());
3422 			}
3423 		}
3424 
3425 		ty = scf_value_type(ud_val);
3426 		assert(ty != SCF_TYPE_INVALID);
3427 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3428 			warn(cf_inval, ient->sc_fmri, ud_name);
3429 			return (0);
3430 		}
3431 
3432 		if (scf_value_get_as_string(ud_val, ud_ctarg,
3433 		    max_scf_value_len + 1) < 0)
3434 			bad_error("scf_value_get_as_string", scf_error());
3435 
3436 		r = fmri_equal(ud_ctarg, ud_oldtarg);
3437 		switch (r) {
3438 		case 1:
3439 			break;
3440 
3441 		case 0:
3442 		case -1:	/* warn? */
3443 			warn(cf_newtarg, ient->sc_fmri, ud_name);
3444 			return (0);
3445 
3446 		case -2:
3447 			warn(li_corrupt, ient->sc_fmri);
3448 			return (EBADF);
3449 
3450 		default:
3451 			bad_error("fmri_equal", r);
3452 		}
3453 
3454 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3455 			switch (scf_error()) {
3456 			case SCF_ERROR_NOT_FOUND:
3457 				warn(li_corrupt, ient->sc_fmri);
3458 				return (EBADF);
3459 
3460 			case SCF_ERROR_DELETED:
3461 			case SCF_ERROR_CONNECTION_BROKEN:
3462 				return (scferror2errno(scf_error()));
3463 
3464 			case SCF_ERROR_NOT_BOUND:
3465 			case SCF_ERROR_HANDLE_MISMATCH:
3466 			case SCF_ERROR_INVALID_ARGUMENT:
3467 			case SCF_ERROR_NOT_SET:
3468 			default:
3469 				bad_error("scf_snaplevel_get_pg", scf_error());
3470 			}
3471 		}
3472 
3473 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3474 		    snap_lastimport);
3475 		switch (r) {
3476 		case 0:
3477 			break;
3478 
3479 		case ECANCELED:
3480 		case ECONNABORTED:
3481 		case ENOMEM:
3482 		case EBADF:
3483 			return (r);
3484 
3485 		case EACCES:
3486 		default:
3487 			bad_error("load_pg", r);
3488 		}
3489 
3490 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3491 		switch (serr) {
3492 		case SCF_ERROR_NONE:
3493 			break;
3494 
3495 		case SCF_ERROR_NO_MEMORY:
3496 			internal_pgroup_free(old_dpt_pgroup);
3497 			return (ENOMEM);
3498 
3499 		case SCF_ERROR_NOT_FOUND:
3500 			internal_pgroup_free(old_dpt_pgroup);
3501 			goto delprop;
3502 
3503 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
3504 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
3505 		default:
3506 			bad_error("fmri_to_entity", serr);
3507 		}
3508 
3509 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
3510 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
3511 		switch (r) {
3512 		case 0:
3513 			break;
3514 
3515 		case ECONNABORTED:
3516 			internal_pgroup_free(old_dpt_pgroup);
3517 			return (r);
3518 
3519 		case ECANCELED:
3520 		case ENOENT:
3521 			internal_pgroup_free(old_dpt_pgroup);
3522 			goto delprop;
3523 
3524 		case EBADF:
3525 			warn(r_no_lvl, ud_ctarg);
3526 			internal_pgroup_free(old_dpt_pgroup);
3527 			return (r);
3528 
3529 		case EINVAL:
3530 		default:
3531 			bad_error("entity_get_running_pg", r);
3532 		}
3533 
3534 		/* load it */
3535 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
3536 		switch (r) {
3537 		case 0:
3538 			break;
3539 
3540 		case ECANCELED:
3541 			internal_pgroup_free(old_dpt_pgroup);
3542 			goto delprop;
3543 
3544 		case ECONNABORTED:
3545 		case ENOMEM:
3546 		case EBADF:
3547 			internal_pgroup_free(old_dpt_pgroup);
3548 			return (r);
3549 
3550 		case EACCES:
3551 		default:
3552 			bad_error("load_pg", r);
3553 		}
3554 
3555 		/* compare property groups */
3556 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
3557 			warn(cf_newdpg, ient->sc_fmri, ud_name);
3558 			internal_pgroup_free(old_dpt_pgroup);
3559 			internal_pgroup_free(current_pg);
3560 			return (0);
3561 		}
3562 
3563 		internal_pgroup_free(old_dpt_pgroup);
3564 		internal_pgroup_free(current_pg);
3565 
3566 		if (g_verbose)
3567 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
3568 			    ient->sc_fmri, ud_name);
3569 
3570 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
3571 			switch (scf_error()) {
3572 			case SCF_ERROR_NOT_FOUND:
3573 			case SCF_ERROR_DELETED:
3574 				internal_pgroup_free(old_dpt_pgroup);
3575 				goto delprop;
3576 
3577 			case SCF_ERROR_CONNECTION_BROKEN:
3578 				internal_pgroup_free(old_dpt_pgroup);
3579 				return (ECONNABORTED);
3580 
3581 			case SCF_ERROR_NOT_SET:
3582 			case SCF_ERROR_INVALID_ARGUMENT:
3583 			case SCF_ERROR_HANDLE_MISMATCH:
3584 			case SCF_ERROR_NOT_BOUND:
3585 			default:
3586 				bad_error("entity_get_pg", scf_error());
3587 			}
3588 		}
3589 
3590 		if (scf_pg_delete(ud_pg) != 0) {
3591 			switch (scf_error()) {
3592 			case SCF_ERROR_DELETED:
3593 				break;
3594 
3595 			case SCF_ERROR_CONNECTION_BROKEN:
3596 			case SCF_ERROR_BACKEND_READONLY:
3597 			case SCF_ERROR_BACKEND_ACCESS:
3598 				return (scferror2errno(scf_error()));
3599 
3600 			case SCF_ERROR_PERMISSION_DENIED:
3601 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
3602 				return (scferror2errno(scf_error()));
3603 
3604 			case SCF_ERROR_NOT_SET:
3605 			default:
3606 				bad_error("scf_pg_delete", scf_error());
3607 			}
3608 		}
3609 
3610 		/*
3611 		 * This service was changed, so it must be refreshed.  But
3612 		 * since it's not mentioned in the new manifest, we have to
3613 		 * record its FMRI here for use later.  We record the name
3614 		 * & the entity (via sc_parent) in case we need to print error
3615 		 * messages during the refresh.
3616 		 */
3617 		dpt = internal_pgroup_new();
3618 		if (dpt == NULL)
3619 			return (ENOMEM);
3620 		dpt->sc_pgroup_name = strdup(ud_name);
3621 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
3622 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
3623 			return (ENOMEM);
3624 		dpt->sc_parent = (entity_t *)ient;
3625 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
3626 			uu_die(gettext("libuutil error: %s\n"),
3627 			    uu_strerror(uu_error()));
3628 
3629 delprop:
3630 		if (tx == NULL)
3631 			return (0);
3632 
3633 		ent = scf_entry_create(g_hndl);
3634 		if (ent == NULL)
3635 			return (ENOMEM);
3636 
3637 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
3638 			scf_entry_destroy(ent);
3639 			switch (scf_error()) {
3640 			case SCF_ERROR_DELETED:
3641 				warn(emsg_pg_deleted, ient->sc_fmri,
3642 				    "dependents");
3643 				return (EBUSY);
3644 
3645 			case SCF_ERROR_CONNECTION_BROKEN:
3646 				return (scferror2errno(scf_error()));
3647 
3648 			case SCF_ERROR_NOT_FOUND:
3649 				break;
3650 
3651 			case SCF_ERROR_HANDLE_MISMATCH:
3652 			case SCF_ERROR_NOT_BOUND:
3653 			case SCF_ERROR_INVALID_ARGUMENT:
3654 			case SCF_ERROR_NOT_SET:
3655 			default:
3656 				bad_error("scf_transaction_property_delete",
3657 				    scf_error());
3658 			}
3659 		}
3660 
3661 		return (0);
3662 	}
3663 
3664 	new_dpt_pgroup->sc_pgroup_seen = 1;
3665 
3666 	/*
3667 	 * Decide whether the dependent has changed in the manifest.
3668 	 */
3669 	/* Compare the target. */
3670 	if (scf_property_get_value(prop, ud_val) != 0) {
3671 		switch (scf_error()) {
3672 		case SCF_ERROR_NOT_FOUND:
3673 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3674 			warn(li_corrupt, ient->sc_fmri);
3675 			return (EBADF);
3676 
3677 		case SCF_ERROR_DELETED:
3678 		case SCF_ERROR_CONNECTION_BROKEN:
3679 			return (scferror2errno(scf_error()));
3680 
3681 		case SCF_ERROR_HANDLE_MISMATCH:
3682 		case SCF_ERROR_NOT_BOUND:
3683 		case SCF_ERROR_NOT_SET:
3684 		case SCF_ERROR_PERMISSION_DENIED:
3685 		default:
3686 			bad_error("scf_property_get_value", scf_error());
3687 		}
3688 	}
3689 
3690 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
3691 	    0)
3692 		bad_error("scf_value_get_as_string", scf_error());
3693 
3694 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
3695 	switch (r) {
3696 	case 0:
3697 		break;
3698 
3699 	case 1:
3700 		/* Compare the dependency pgs. */
3701 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3702 			switch (scf_error()) {
3703 			case SCF_ERROR_NOT_FOUND:
3704 				warn(li_corrupt, ient->sc_fmri);
3705 				return (EBADF);
3706 
3707 			case SCF_ERROR_DELETED:
3708 			case SCF_ERROR_CONNECTION_BROKEN:
3709 				return (scferror2errno(scf_error()));
3710 
3711 			case SCF_ERROR_NOT_BOUND:
3712 			case SCF_ERROR_HANDLE_MISMATCH:
3713 			case SCF_ERROR_INVALID_ARGUMENT:
3714 			case SCF_ERROR_NOT_SET:
3715 			default:
3716 				bad_error("scf_snaplevel_get_pg", scf_error());
3717 			}
3718 		}
3719 
3720 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3721 		    snap_lastimport);
3722 		switch (r) {
3723 		case 0:
3724 			break;
3725 
3726 		case ECANCELED:
3727 		case ECONNABORTED:
3728 		case ENOMEM:
3729 		case EBADF:
3730 			return (r);
3731 
3732 		case EACCES:
3733 		default:
3734 			bad_error("load_pg", r);
3735 		}
3736 
3737 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
3738 			/* no change, leave customizations */
3739 			internal_pgroup_free(old_dpt_pgroup);
3740 			return (0);
3741 		}
3742 		break;
3743 
3744 	case -1:
3745 		warn(li_corrupt, ient->sc_fmri);
3746 		return (EBADF);
3747 
3748 	case -2:
3749 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
3750 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
3751 		return (EINVAL);
3752 
3753 	default:
3754 		bad_error("fmri_equal", r);
3755 	}
3756 
3757 	/*
3758 	 * The dependent has changed in the manifest.  Upgrade the current
3759 	 * properties if they haven't been customized.
3760 	 */
3761 
3762 	/*
3763 	 * If new_dpt_pgroup->sc_override, then act as though the property
3764 	 * group hasn't been customized.
3765 	 */
3766 	if (new_dpt_pgroup->sc_pgroup_override)
3767 		goto nocust;
3768 
3769 	if (!ud_run_dpts_pg_set) {
3770 		warn(cf_missing, ient->sc_fmri, ud_name);
3771 		r = 0;
3772 		goto out;
3773 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
3774 		switch (scf_error()) {
3775 		case SCF_ERROR_NOT_FOUND:
3776 			warn(cf_missing, ient->sc_fmri, ud_name);
3777 			r = 0;
3778 			goto out;
3779 
3780 		case SCF_ERROR_CONNECTION_BROKEN:
3781 			r = scferror2errno(scf_error());
3782 			goto out;
3783 
3784 		case SCF_ERROR_DELETED:
3785 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
3786 			r = EBUSY;
3787 			goto out;
3788 
3789 		case SCF_ERROR_INVALID_ARGUMENT:
3790 		case SCF_ERROR_NOT_BOUND:
3791 		case SCF_ERROR_HANDLE_MISMATCH:
3792 		case SCF_ERROR_NOT_SET:
3793 		default:
3794 			bad_error("scf_pg_get_property", scf_error());
3795 		}
3796 	}
3797 
3798 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
3799 		switch (scf_error()) {
3800 		case SCF_ERROR_NOT_FOUND:
3801 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3802 			warn(cf_inval, ient->sc_fmri, ud_name);
3803 			r = 0;
3804 			goto out;
3805 
3806 		case SCF_ERROR_DELETED:
3807 		case SCF_ERROR_CONNECTION_BROKEN:
3808 			r = scferror2errno(scf_error());
3809 			goto out;
3810 
3811 		case SCF_ERROR_HANDLE_MISMATCH:
3812 		case SCF_ERROR_NOT_BOUND:
3813 		case SCF_ERROR_NOT_SET:
3814 		case SCF_ERROR_PERMISSION_DENIED:
3815 		default:
3816 			bad_error("scf_property_get_value", scf_error());
3817 		}
3818 	}
3819 
3820 	ty = scf_value_type(ud_val);
3821 	assert(ty != SCF_TYPE_INVALID);
3822 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3823 		warn(cf_inval, ient->sc_fmri, ud_name);
3824 		r = 0;
3825 		goto out;
3826 	}
3827 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
3828 	    0)
3829 		bad_error("scf_value_get_as_string", scf_error());
3830 
3831 	r = fmri_equal(ud_ctarg, ud_oldtarg);
3832 	if (r == -1) {
3833 		warn(cf_inval, ient->sc_fmri, ud_name);
3834 		r = 0;
3835 		goto out;
3836 	} else if (r == -2) {
3837 		warn(li_corrupt, ient->sc_fmri);
3838 		r = EBADF;
3839 		goto out;
3840 	} else if (r == 0) {
3841 		/*
3842 		 * Target has been changed.  Only abort now if it's been
3843 		 * changed to something other than what's in the manifest.
3844 		 */
3845 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
3846 		if (r == -1) {
3847 			warn(cf_inval, ient->sc_fmri, ud_name);
3848 			r = 0;
3849 			goto out;
3850 		} else if (r == 0) {
3851 			warn(cf_newtarg, ient->sc_fmri, ud_name);
3852 			r = 0;
3853 			goto out;
3854 		} else if (r != 1) {
3855 			/* invalid sc_pgroup_fmri caught above */
3856 			bad_error("fmri_equal", r);
3857 		}
3858 
3859 		/*
3860 		 * Fetch the current dependency pg.  If it's what the manifest
3861 		 * says, then no problem.
3862 		 */
3863 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3864 		switch (serr) {
3865 		case SCF_ERROR_NONE:
3866 			break;
3867 
3868 		case SCF_ERROR_NOT_FOUND:
3869 			warn(cf_missing, ient->sc_fmri, ud_name);
3870 			r = 0;
3871 			goto out;
3872 
3873 		case SCF_ERROR_NO_MEMORY:
3874 			r = ENOMEM;
3875 			goto out;
3876 
3877 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3878 		case SCF_ERROR_INVALID_ARGUMENT:
3879 		default:
3880 			bad_error("fmri_to_entity", serr);
3881 		}
3882 
3883 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
3884 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
3885 		switch (r) {
3886 		case 0:
3887 			break;
3888 
3889 		case ECONNABORTED:
3890 			goto out;
3891 
3892 		case ECANCELED:
3893 		case ENOENT:
3894 			warn(cf_missing, ient->sc_fmri, ud_name);
3895 			r = 0;
3896 			goto out;
3897 
3898 		case EBADF:
3899 			warn(r_no_lvl, ud_ctarg);
3900 			goto out;
3901 
3902 		case EINVAL:
3903 		default:
3904 			bad_error("entity_get_running_pg", r);
3905 		}
3906 
3907 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
3908 		switch (r) {
3909 		case 0:
3910 			break;
3911 
3912 		case ECANCELED:
3913 			warn(cf_missing, ient->sc_fmri, ud_name);
3914 			r = 0;
3915 			goto out;
3916 
3917 		case ECONNABORTED:
3918 		case ENOMEM:
3919 		case EBADF:
3920 			goto out;
3921 
3922 		case EACCES:
3923 		default:
3924 			bad_error("load_pg", r);
3925 		}
3926 
3927 		if (!pg_equal(current_pg, new_dpt_pgroup))
3928 			warn(cf_newdpg, ient->sc_fmri, ud_name);
3929 		internal_pgroup_free(current_pg);
3930 		r = 0;
3931 		goto out;
3932 	} else if (r != 1) {
3933 		bad_error("fmri_equal", r);
3934 	}
3935 
3936 nocust:
3937 	/*
3938 	 * Target has not been customized.  Check the dependency property
3939 	 * group.
3940 	 */
3941 
3942 	if (old_dpt_pgroup == NULL) {
3943 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
3944 		    ud_pg) != 0) {
3945 			switch (scf_error()) {
3946 			case SCF_ERROR_NOT_FOUND:
3947 				warn(li_corrupt, ient->sc_fmri);
3948 				return (EBADF);
3949 
3950 			case SCF_ERROR_DELETED:
3951 			case SCF_ERROR_CONNECTION_BROKEN:
3952 				return (scferror2errno(scf_error()));
3953 
3954 			case SCF_ERROR_NOT_BOUND:
3955 			case SCF_ERROR_HANDLE_MISMATCH:
3956 			case SCF_ERROR_INVALID_ARGUMENT:
3957 			case SCF_ERROR_NOT_SET:
3958 			default:
3959 				bad_error("scf_snaplevel_get_pg", scf_error());
3960 			}
3961 		}
3962 
3963 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3964 		    snap_lastimport);
3965 		switch (r) {
3966 		case 0:
3967 			break;
3968 
3969 		case ECANCELED:
3970 		case ECONNABORTED:
3971 		case ENOMEM:
3972 		case EBADF:
3973 			return (r);
3974 
3975 		case EACCES:
3976 		default:
3977 			bad_error("load_pg", r);
3978 		}
3979 	}
3980 
3981 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3982 	switch (serr) {
3983 	case SCF_ERROR_NONE:
3984 		break;
3985 
3986 	case SCF_ERROR_NOT_FOUND:
3987 		warn(cf_missing, ient->sc_fmri, ud_name);
3988 		r = 0;
3989 		goto out;
3990 
3991 	case SCF_ERROR_NO_MEMORY:
3992 		r = ENOMEM;
3993 		goto out;
3994 
3995 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3996 	case SCF_ERROR_INVALID_ARGUMENT:
3997 	default:
3998 		bad_error("fmri_to_entity", serr);
3999 	}
4000 
4001 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4002 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4003 	switch (r) {
4004 	case 0:
4005 		break;
4006 
4007 	case ECONNABORTED:
4008 		goto out;
4009 
4010 	case ECANCELED:
4011 	case ENOENT:
4012 		warn(cf_missing, ient->sc_fmri, ud_name);
4013 		r = 0;
4014 		goto out;
4015 
4016 	case EBADF:
4017 		warn(r_no_lvl, ud_ctarg);
4018 		goto out;
4019 
4020 	case EINVAL:
4021 	default:
4022 		bad_error("entity_get_running_pg", r);
4023 	}
4024 
4025 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4026 	switch (r) {
4027 	case 0:
4028 		break;
4029 
4030 	case ECANCELED:
4031 		warn(cf_missing, ient->sc_fmri, ud_name);
4032 		goto out;
4033 
4034 	case ECONNABORTED:
4035 	case ENOMEM:
4036 	case EBADF:
4037 		goto out;
4038 
4039 	case EACCES:
4040 	default:
4041 		bad_error("load_pg", r);
4042 	}
4043 
4044 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4045 		if (!pg_equal(current_pg, new_dpt_pgroup))
4046 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4047 		internal_pgroup_free(current_pg);
4048 		r = 0;
4049 		goto out;
4050 	}
4051 
4052 	/* Uncustomized.  Upgrade. */
4053 
4054 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4055 	switch (r) {
4056 	case 1:
4057 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4058 			/* Already upgraded. */
4059 			internal_pgroup_free(current_pg);
4060 			r = 0;
4061 			goto out;
4062 		}
4063 
4064 		internal_pgroup_free(current_pg);
4065 
4066 		/* upgrade current_pg */
4067 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4068 			switch (scf_error()) {
4069 			case SCF_ERROR_CONNECTION_BROKEN:
4070 				r = scferror2errno(scf_error());
4071 				goto out;
4072 
4073 			case SCF_ERROR_DELETED:
4074 				warn(cf_missing, ient->sc_fmri, ud_name);
4075 				r = 0;
4076 				goto out;
4077 
4078 			case SCF_ERROR_NOT_FOUND:
4079 				break;
4080 
4081 			case SCF_ERROR_INVALID_ARGUMENT:
4082 			case SCF_ERROR_NOT_BOUND:
4083 			case SCF_ERROR_NOT_SET:
4084 			case SCF_ERROR_HANDLE_MISMATCH:
4085 			default:
4086 				bad_error("entity_get_pg", scf_error());
4087 			}
4088 
4089 			if (tissvc)
4090 				r = scf_service_add_pg(target_ent, ud_name,
4091 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4092 			else
4093 				r = scf_instance_add_pg(target_ent, ud_name,
4094 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4095 			if (r != 0) {
4096 				switch (scf_error()) {
4097 				case SCF_ERROR_CONNECTION_BROKEN:
4098 				case SCF_ERROR_NO_RESOURCES:
4099 				case SCF_ERROR_BACKEND_READONLY:
4100 				case SCF_ERROR_BACKEND_ACCESS:
4101 					r = scferror2errno(scf_error());
4102 					goto out;
4103 
4104 				case SCF_ERROR_DELETED:
4105 					warn(cf_missing, ient->sc_fmri,
4106 					    ud_name);
4107 					r = 0;
4108 					goto out;
4109 
4110 				case SCF_ERROR_PERMISSION_DENIED:
4111 					warn(emsg_pg_deleted, ud_ctarg,
4112 					    ud_name);
4113 					r = EPERM;
4114 					goto out;
4115 
4116 				case SCF_ERROR_EXISTS:
4117 					warn(emsg_pg_added, ud_ctarg, ud_name);
4118 					r = EBUSY;
4119 					goto out;
4120 
4121 				case SCF_ERROR_NOT_BOUND:
4122 				case SCF_ERROR_HANDLE_MISMATCH:
4123 				case SCF_ERROR_INVALID_ARGUMENT:
4124 				case SCF_ERROR_NOT_SET:
4125 				default:
4126 					bad_error("entity_add_pg", scf_error());
4127 				}
4128 			}
4129 		}
4130 
4131 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4132 		switch (r) {
4133 		case 0:
4134 			break;
4135 
4136 		case ECANCELED:
4137 			warn(cf_missing, ient->sc_fmri, ud_name);
4138 			goto out;
4139 
4140 		case ECONNABORTED:
4141 		case ENOMEM:
4142 		case EBADF:
4143 			goto out;
4144 
4145 		case EACCES:
4146 		default:
4147 			bad_error("load_pg", r);
4148 		}
4149 
4150 		if (g_verbose)
4151 			warn(upgrading, ient->sc_fmri, ud_name);
4152 
4153 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4154 		    new_dpt_pgroup, 0, ient->sc_fmri);
4155 		switch (r) {
4156 		case 0:
4157 			break;
4158 
4159 		case ECANCELED:
4160 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4161 			r = EBUSY;
4162 			goto out;
4163 
4164 		case EPERM:
4165 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4166 			goto out;
4167 
4168 		case EBUSY:
4169 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4170 			goto out;
4171 
4172 		case ECONNABORTED:
4173 		case ENOMEM:
4174 		case ENOSPC:
4175 		case EROFS:
4176 		case EACCES:
4177 		case EINVAL:
4178 			goto out;
4179 
4180 		default:
4181 			bad_error("upgrade_pg", r);
4182 		}
4183 		break;
4184 
4185 	case 0: {
4186 		scf_transaction_entry_t *ent;
4187 		scf_value_t *val;
4188 
4189 		internal_pgroup_free(current_pg);
4190 
4191 		/* delete old pg */
4192 		if (g_verbose)
4193 			warn(upgrading, ient->sc_fmri, ud_name);
4194 
4195 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4196 			switch (scf_error()) {
4197 			case SCF_ERROR_CONNECTION_BROKEN:
4198 				r = scferror2errno(scf_error());
4199 				goto out;
4200 
4201 			case SCF_ERROR_DELETED:
4202 				warn(cf_missing, ient->sc_fmri, ud_name);
4203 				r = 0;
4204 				goto out;
4205 
4206 			case SCF_ERROR_NOT_FOUND:
4207 				break;
4208 
4209 			case SCF_ERROR_INVALID_ARGUMENT:
4210 			case SCF_ERROR_NOT_BOUND:
4211 			case SCF_ERROR_NOT_SET:
4212 			case SCF_ERROR_HANDLE_MISMATCH:
4213 			default:
4214 				bad_error("entity_get_pg", scf_error());
4215 			}
4216 		} else if (scf_pg_delete(ud_pg) != 0) {
4217 			switch (scf_error()) {
4218 			case SCF_ERROR_DELETED:
4219 				break;
4220 
4221 			case SCF_ERROR_CONNECTION_BROKEN:
4222 			case SCF_ERROR_BACKEND_READONLY:
4223 			case SCF_ERROR_BACKEND_ACCESS:
4224 				r = scferror2errno(scf_error());
4225 				goto out;
4226 
4227 			case SCF_ERROR_PERMISSION_DENIED:
4228 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4229 				r = scferror2errno(scf_error());
4230 				goto out;
4231 
4232 			case SCF_ERROR_NOT_SET:
4233 			default:
4234 				bad_error("scf_pg_delete", scf_error());
4235 			}
4236 		}
4237 
4238 		/* import new one */
4239 		cbdata.sc_handle = g_hndl;
4240 		cbdata.sc_trans = NULL;		/* handled below */
4241 
4242 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
4243 		if (r != UU_WALK_NEXT) {
4244 			if (r != UU_WALK_ERROR)
4245 				bad_error("lscf_dependent_import", r);
4246 
4247 			r = cbdata.sc_err;
4248 			goto out;
4249 		}
4250 
4251 		if (tx == NULL)
4252 			break;
4253 
4254 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
4255 		    (val = scf_value_create(g_hndl)) == NULL) {
4256 			if (scf_error() == SCF_ERROR_NO_MEMORY)
4257 				return (ENOMEM);
4258 
4259 			bad_error("scf_entry_create", scf_error());
4260 		}
4261 
4262 		if (scf_transaction_property_change_type(tx, ent, ud_name,
4263 		    SCF_TYPE_FMRI) != 0) {
4264 			switch (scf_error()) {
4265 			case SCF_ERROR_CONNECTION_BROKEN:
4266 				r = scferror2errno(scf_error());
4267 				goto out;
4268 
4269 			case SCF_ERROR_DELETED:
4270 				warn(emsg_pg_deleted, ient->sc_fmri,
4271 				    "dependents");
4272 				r = EBUSY;
4273 				goto out;
4274 
4275 			case SCF_ERROR_NOT_FOUND:
4276 				break;
4277 
4278 			case SCF_ERROR_NOT_BOUND:
4279 			case SCF_ERROR_HANDLE_MISMATCH:
4280 			case SCF_ERROR_INVALID_ARGUMENT:
4281 			case SCF_ERROR_NOT_SET:
4282 			default:
4283 				bad_error("scf_transaction_property_"
4284 				    "change_type", scf_error());
4285 			}
4286 
4287 			if (scf_transaction_property_new(tx, ent, ud_name,
4288 			    SCF_TYPE_FMRI) != 0) {
4289 				switch (scf_error()) {
4290 				case SCF_ERROR_CONNECTION_BROKEN:
4291 					r = scferror2errno(scf_error());
4292 					goto out;
4293 
4294 				case SCF_ERROR_DELETED:
4295 					warn(emsg_pg_deleted, ient->sc_fmri,
4296 					    "dependents");
4297 					r = EBUSY;
4298 					goto out;
4299 
4300 				case SCF_ERROR_EXISTS:
4301 					warn(emsg_pg_changed, ient->sc_fmri,
4302 					    "dependents");
4303 					r = EBUSY;
4304 					goto out;
4305 
4306 				case SCF_ERROR_INVALID_ARGUMENT:
4307 				case SCF_ERROR_HANDLE_MISMATCH:
4308 				case SCF_ERROR_NOT_BOUND:
4309 				case SCF_ERROR_NOT_SET:
4310 				default:
4311 					bad_error("scf_transaction_property_"
4312 					    "new", scf_error());
4313 				}
4314 			}
4315 		}
4316 
4317 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
4318 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
4319 			/* invalid sc_pgroup_fmri caught above */
4320 			bad_error("scf_value_set_from_string",
4321 			    scf_error());
4322 
4323 		if (scf_entry_add_value(ent, val) != 0)
4324 			bad_error("scf_entry_add_value", scf_error());
4325 		break;
4326 	}
4327 
4328 	case -2:
4329 		warn(li_corrupt, ient->sc_fmri);
4330 		internal_pgroup_free(current_pg);
4331 		r = EBADF;
4332 		goto out;
4333 
4334 	case -1:
4335 	default:
4336 		/* invalid sc_pgroup_fmri caught above */
4337 		bad_error("fmri_equal", r);
4338 	}
4339 
4340 	r = 0;
4341 
4342 out:
4343 	if (old_dpt_pgroup != NULL)
4344 		internal_pgroup_free(old_dpt_pgroup);
4345 
4346 	return (r);
4347 }
4348 
4349 /*
4350  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
4351  * would import it, except it seems to exist in the service anyway.  Compare
4352  * the existent dependent with the one we would import, and report any
4353  * differences (if there are none, be silent).  prop is the property which
4354  * represents the existent dependent (in the dependents property group) in the
4355  * entity corresponding to ient.
4356  *
4357  * Returns
4358  *   0 - success (Sort of.  At least, we can continue importing.)
4359  *   ECONNABORTED - repository connection broken
4360  *   EBUSY - ancestor of prop was deleted (error printed)
4361  *   ENOMEM - out of memory
4362  *   EBADF - corrupt property group (error printed)
4363  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
4364  */
4365 static int
4366 handle_dependent_conflict(const entity_t * const ient,
4367     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
4368 {
4369 	int r;
4370 	scf_type_t ty;
4371 	scf_error_t scfe;
4372 	void *tptr;
4373 	int tissvc;
4374 	pgroup_t *pgroup;
4375 
4376 	if (scf_property_get_value(prop, ud_val) != 0) {
4377 		switch (scf_error()) {
4378 		case SCF_ERROR_CONNECTION_BROKEN:
4379 			return (scferror2errno(scf_error()));
4380 
4381 		case SCF_ERROR_DELETED:
4382 			warn(emsg_pg_deleted, ient->sc_fmri,
4383 			    new_dpt_pgroup->sc_pgroup_name);
4384 			return (EBUSY);
4385 
4386 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4387 		case SCF_ERROR_NOT_FOUND:
4388 			warn(gettext("Conflict upgrading %s (not importing "
4389 			    "dependent \"%s\" because it already exists.)  "
4390 			    "Warning: The \"%s/%2$s\" property has more or "
4391 			    "fewer than one value)).\n"), ient->sc_fmri,
4392 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
4393 			return (0);
4394 
4395 		case SCF_ERROR_HANDLE_MISMATCH:
4396 		case SCF_ERROR_NOT_BOUND:
4397 		case SCF_ERROR_NOT_SET:
4398 		case SCF_ERROR_PERMISSION_DENIED:
4399 		default:
4400 			bad_error("scf_property_get_value",
4401 			    scf_error());
4402 		}
4403 	}
4404 
4405 	ty = scf_value_type(ud_val);
4406 	assert(ty != SCF_TYPE_INVALID);
4407 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4408 		warn(gettext("Conflict upgrading %s (not importing dependent "
4409 		    "\"%s\" because it already exists).  Warning: The "
4410 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
4411 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
4412 		    scf_type_to_string(ty), "dependents");
4413 		return (0);
4414 	}
4415 
4416 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4417 	    0)
4418 		bad_error("scf_value_get_as_string", scf_error());
4419 
4420 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4421 	switch (r) {
4422 	case 0:
4423 		warn(gettext("Conflict upgrading %s (not importing dependent "
4424 		    "\"%s\" (target \"%s\") because it already exists with "
4425 		    "target \"%s\").\n"), ient->sc_fmri,
4426 		    new_dpt_pgroup->sc_pgroup_name,
4427 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
4428 		return (0);
4429 
4430 	case 1:
4431 		break;
4432 
4433 	case -1:
4434 		warn(gettext("Conflict upgrading %s (not importing dependent "
4435 		    "\"%s\" because it already exists).  Warning: The current "
4436 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
4437 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4438 		return (0);
4439 
4440 	case -2:
4441 		warn(gettext("Dependent \"%s\" of %s has invalid target "
4442 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
4443 		    new_dpt_pgroup->sc_pgroup_fmri);
4444 		return (EINVAL);
4445 
4446 	default:
4447 		bad_error("fmri_equal", r);
4448 	}
4449 
4450 	/* compare dependency pgs in target */
4451 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
4452 	switch (scfe) {
4453 	case SCF_ERROR_NONE:
4454 		break;
4455 
4456 	case SCF_ERROR_NO_MEMORY:
4457 		return (ENOMEM);
4458 
4459 	case SCF_ERROR_NOT_FOUND:
4460 		warn(emsg_dpt_dangling, ient->sc_fmri,
4461 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4462 		return (0);
4463 
4464 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4465 	case SCF_ERROR_INVALID_ARGUMENT:
4466 	default:
4467 		bad_error("fmri_to_entity", scfe);
4468 	}
4469 
4470 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
4471 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
4472 	switch (r) {
4473 	case 0:
4474 		break;
4475 
4476 	case ECONNABORTED:
4477 		return (r);
4478 
4479 	case ECANCELED:
4480 		warn(emsg_dpt_dangling, ient->sc_fmri,
4481 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4482 		return (0);
4483 
4484 	case EBADF:
4485 		if (tissvc)
4486 			warn(gettext("%s has an instance with a \"%s\" "
4487 			    "snapshot which is missing a snaplevel.\n"),
4488 			    ud_ctarg, "running");
4489 		else
4490 			warn(gettext("%s has a \"%s\" snapshot which is "
4491 			    "missing a snaplevel.\n"), ud_ctarg, "running");
4492 		/* FALLTHROUGH */
4493 
4494 	case ENOENT:
4495 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4496 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4497 		    new_dpt_pgroup->sc_pgroup_name);
4498 		return (0);
4499 
4500 	case EINVAL:
4501 	default:
4502 		bad_error("entity_get_running_pg", r);
4503 	}
4504 
4505 	pgroup = internal_pgroup_new();
4506 	if (pgroup == NULL)
4507 		return (ENOMEM);
4508 
4509 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
4510 	switch (r) {
4511 	case 0:
4512 		break;
4513 
4514 	case ECONNABORTED:
4515 	case EBADF:
4516 	case ENOMEM:
4517 		internal_pgroup_free(pgroup);
4518 		return (r);
4519 
4520 	case ECANCELED:
4521 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4522 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4523 		    new_dpt_pgroup->sc_pgroup_name);
4524 		internal_pgroup_free(pgroup);
4525 		return (0);
4526 
4527 	case EACCES:
4528 	default:
4529 		bad_error("load_pg", r);
4530 	}
4531 
4532 	/* report differences */
4533 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
4534 	internal_pgroup_free(pgroup);
4535 	return (0);
4536 }
4537 
4538 /*
4539  * lipg is a property group in the last-import snapshot of ent, which is an
4540  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
4541  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
4542  * in ents's property groups, compare and upgrade ent appropriately.
4543  *
4544  * Returns
4545  *   0 - success
4546  *   ECONNABORTED - repository connection broken
4547  *   ENOMEM - out of memory
4548  *   ENOSPC - configd is out of resources
4549  *   EINVAL - ient has invalid dependent (error printed)
4550  *	    - ient has invalid pgroup_t (error printed)
4551  *   ECANCELED - ent has been deleted
4552  *   ENODEV - entity containing lipg has been deleted
4553  *	    - entity containing running has been deleted
4554  *   EPERM - could not delete pg (permission denied) (error printed)
4555  *	   - couldn't upgrade dependents (permission denied) (error printed)
4556  *	   - couldn't import pg (permission denied) (error printed)
4557  *	   - couldn't upgrade pg (permission denied) (error printed)
4558  *   EROFS - could not delete pg (repository read-only)
4559  *	   - couldn't upgrade dependents (repository read-only)
4560  *	   - couldn't import pg (repository read-only)
4561  *	   - couldn't upgrade pg (repository read-only)
4562  *   EACCES - could not delete pg (backend access denied)
4563  *	    - couldn't upgrade dependents (backend access denied)
4564  *	    - couldn't import pg (backend access denied)
4565  *	    - couldn't upgrade pg (backend access denied)
4566  *	    - couldn't read property (backend access denied)
4567  *   EBUSY - property group was added (error printed)
4568  *	   - property group was deleted (error printed)
4569  *	   - property group changed (error printed)
4570  *	   - "dependents" pg was added, changed, or deleted (error printed)
4571  *	   - dependent target deleted (error printed)
4572  *	   - dependent pg changed (error printed)
4573  *   EBADF - imp_snpl is corrupt (error printed)
4574  *	   - ent has bad pg (error printed)
4575  *   EEXIST - dependent collision in target service (error printed)
4576  */
4577 static int
4578 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
4579     const scf_snaplevel_t *running)
4580 {
4581 	int r;
4582 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
4583 	scf_callback_t cbdata;
4584 
4585 	const char * const cf_pg_missing =
4586 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
4587 	const char * const deleting =
4588 	    gettext("%s: Deleting property group \"%s\".\n");
4589 
4590 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
4591 
4592 	/* Skip dependent property groups. */
4593 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
4594 		switch (scf_error()) {
4595 		case SCF_ERROR_DELETED:
4596 			return (ENODEV);
4597 
4598 		case SCF_ERROR_CONNECTION_BROKEN:
4599 			return (ECONNABORTED);
4600 
4601 		case SCF_ERROR_NOT_SET:
4602 		case SCF_ERROR_NOT_BOUND:
4603 		default:
4604 			bad_error("scf_pg_get_type", scf_error());
4605 		}
4606 	}
4607 
4608 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
4609 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
4610 			return (0);
4611 
4612 		switch (scf_error()) {
4613 		case SCF_ERROR_NOT_FOUND:
4614 			break;
4615 
4616 		case SCF_ERROR_CONNECTION_BROKEN:
4617 			return (ECONNABORTED);
4618 
4619 		case SCF_ERROR_DELETED:
4620 			return (ENODEV);
4621 
4622 		case SCF_ERROR_INVALID_ARGUMENT:
4623 		case SCF_ERROR_NOT_BOUND:
4624 		case SCF_ERROR_HANDLE_MISMATCH:
4625 		case SCF_ERROR_NOT_SET:
4626 		default:
4627 			bad_error("scf_pg_get_property", scf_error());
4628 		}
4629 	}
4630 
4631 	/* lookup pg in new properties */
4632 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
4633 		switch (scf_error()) {
4634 		case SCF_ERROR_DELETED:
4635 			return (ENODEV);
4636 
4637 		case SCF_ERROR_CONNECTION_BROKEN:
4638 			return (ECONNABORTED);
4639 
4640 		case SCF_ERROR_NOT_SET:
4641 		case SCF_ERROR_NOT_BOUND:
4642 		default:
4643 			bad_error("scf_pg_get_name", scf_error());
4644 		}
4645 	}
4646 
4647 	pgrp.sc_pgroup_name = imp_str;
4648 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
4649 
4650 	if (mpg != NULL)
4651 		mpg->sc_pgroup_seen = 1;
4652 
4653 	/* Special handling for dependents */
4654 	if (strcmp(imp_str, "dependents") == 0)
4655 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
4656 
4657 	if (mpg == NULL || mpg->sc_pgroup_delete) {
4658 		/* property group was deleted from manifest */
4659 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4660 			switch (scf_error()) {
4661 			case SCF_ERROR_NOT_FOUND:
4662 				return (0);
4663 
4664 			case SCF_ERROR_DELETED:
4665 			case SCF_ERROR_CONNECTION_BROKEN:
4666 				return (scferror2errno(scf_error()));
4667 
4668 			case SCF_ERROR_INVALID_ARGUMENT:
4669 			case SCF_ERROR_HANDLE_MISMATCH:
4670 			case SCF_ERROR_NOT_BOUND:
4671 			case SCF_ERROR_NOT_SET:
4672 			default:
4673 				bad_error("entity_get_pg", scf_error());
4674 			}
4675 		}
4676 
4677 		if (mpg != NULL && mpg->sc_pgroup_delete) {
4678 			if (g_verbose)
4679 				warn(deleting, ient->sc_fmri, imp_str);
4680 			if (scf_pg_delete(imp_pg2) == 0)
4681 				return (0);
4682 
4683 			switch (scf_error()) {
4684 			case SCF_ERROR_DELETED:
4685 				return (0);
4686 
4687 			case SCF_ERROR_CONNECTION_BROKEN:
4688 			case SCF_ERROR_BACKEND_READONLY:
4689 			case SCF_ERROR_BACKEND_ACCESS:
4690 				return (scferror2errno(scf_error()));
4691 
4692 			case SCF_ERROR_PERMISSION_DENIED:
4693 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
4694 				return (scferror2errno(scf_error()));
4695 
4696 			case SCF_ERROR_NOT_SET:
4697 			default:
4698 				bad_error("scf_pg_delete", scf_error());
4699 			}
4700 		}
4701 
4702 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4703 		switch (r) {
4704 		case 0:
4705 			break;
4706 
4707 		case ECANCELED:
4708 			return (ENODEV);
4709 
4710 		case ECONNABORTED:
4711 		case ENOMEM:
4712 		case EBADF:
4713 		case EACCES:
4714 			return (r);
4715 
4716 		default:
4717 			bad_error("load_pg", r);
4718 		}
4719 
4720 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
4721 		switch (r) {
4722 		case 0:
4723 			break;
4724 
4725 		case ECANCELED:
4726 		case ECONNABORTED:
4727 		case ENOMEM:
4728 		case EBADF:
4729 		case EACCES:
4730 			internal_pgroup_free(lipg_i);
4731 			return (r);
4732 
4733 		default:
4734 			bad_error("load_pg", r);
4735 		}
4736 
4737 		if (pg_equal(lipg_i, curpg_i)) {
4738 			if (g_verbose)
4739 				warn(deleting, ient->sc_fmri, imp_str);
4740 			if (scf_pg_delete(imp_pg2) != 0) {
4741 				switch (scf_error()) {
4742 				case SCF_ERROR_DELETED:
4743 					break;
4744 
4745 				case SCF_ERROR_CONNECTION_BROKEN:
4746 					internal_pgroup_free(lipg_i);
4747 					internal_pgroup_free(curpg_i);
4748 					return (ECONNABORTED);
4749 
4750 				case SCF_ERROR_NOT_SET:
4751 				case SCF_ERROR_NOT_BOUND:
4752 				default:
4753 					bad_error("scf_pg_delete", scf_error());
4754 				}
4755 			}
4756 		} else {
4757 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
4758 		}
4759 
4760 		internal_pgroup_free(lipg_i);
4761 		internal_pgroup_free(curpg_i);
4762 
4763 		return (0);
4764 	}
4765 
4766 	/*
4767 	 * Only dependent pgs can have override set, and we skipped those
4768 	 * above.
4769 	 */
4770 	assert(!mpg->sc_pgroup_override);
4771 
4772 	/* compare */
4773 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4774 	switch (r) {
4775 	case 0:
4776 		break;
4777 
4778 	case ECANCELED:
4779 		return (ENODEV);
4780 
4781 	case ECONNABORTED:
4782 	case EBADF:
4783 	case ENOMEM:
4784 	case EACCES:
4785 		return (r);
4786 
4787 	default:
4788 		bad_error("load_pg", r);
4789 	}
4790 
4791 	if (pg_equal(mpg, lipg_i)) {
4792 		/* The manifest pg has not changed.  Move on. */
4793 		r = 0;
4794 		goto out;
4795 	}
4796 
4797 	/* upgrade current properties according to lipg & mpg */
4798 	if (running != NULL)
4799 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
4800 	else
4801 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
4802 	if (r != 0) {
4803 		switch (scf_error()) {
4804 		case SCF_ERROR_CONNECTION_BROKEN:
4805 			r = scferror2errno(scf_error());
4806 			goto out;
4807 
4808 		case SCF_ERROR_DELETED:
4809 			if (running != NULL)
4810 				r = ENODEV;
4811 			else
4812 				r = ECANCELED;
4813 			goto out;
4814 
4815 		case SCF_ERROR_NOT_FOUND:
4816 			break;
4817 
4818 		case SCF_ERROR_INVALID_ARGUMENT:
4819 		case SCF_ERROR_HANDLE_MISMATCH:
4820 		case SCF_ERROR_NOT_BOUND:
4821 		case SCF_ERROR_NOT_SET:
4822 		default:
4823 			bad_error("entity_get_pg", scf_error());
4824 		}
4825 
4826 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
4827 
4828 		r = 0;
4829 		goto out;
4830 	}
4831 
4832 	r = load_pg_attrs(imp_pg2, &curpg_i);
4833 	switch (r) {
4834 	case 0:
4835 		break;
4836 
4837 	case ECANCELED:
4838 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
4839 		r = 0;
4840 		goto out;
4841 
4842 	case ECONNABORTED:
4843 	case ENOMEM:
4844 		goto out;
4845 
4846 	default:
4847 		bad_error("load_pg_attrs", r);
4848 	}
4849 
4850 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
4851 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
4852 		internal_pgroup_free(curpg_i);
4853 		r = 0;
4854 		goto out;
4855 	}
4856 
4857 	internal_pgroup_free(curpg_i);
4858 
4859 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
4860 	switch (r) {
4861 	case 0:
4862 		break;
4863 
4864 	case ECANCELED:
4865 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
4866 		r = 0;
4867 		goto out;
4868 
4869 	case ECONNABORTED:
4870 	case EBADF:
4871 	case ENOMEM:
4872 	case EACCES:
4873 		goto out;
4874 
4875 	default:
4876 		bad_error("load_pg", r);
4877 	}
4878 
4879 	if (pg_equal(lipg_i, curpg_i) &&
4880 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
4881 		int do_delete = 1;
4882 
4883 		if (g_verbose)
4884 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
4885 			    ient->sc_fmri, mpg->sc_pgroup_name);
4886 
4887 		internal_pgroup_free(curpg_i);
4888 
4889 		if (running != NULL &&
4890 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4891 			switch (scf_error()) {
4892 			case SCF_ERROR_DELETED:
4893 				r = ECANCELED;
4894 				goto out;
4895 
4896 			case SCF_ERROR_NOT_FOUND:
4897 				do_delete = 0;
4898 				break;
4899 
4900 			case SCF_ERROR_CONNECTION_BROKEN:
4901 				r = scferror2errno(scf_error());
4902 				goto out;
4903 
4904 			case SCF_ERROR_HANDLE_MISMATCH:
4905 			case SCF_ERROR_INVALID_ARGUMENT:
4906 			case SCF_ERROR_NOT_SET:
4907 			case SCF_ERROR_NOT_BOUND:
4908 			default:
4909 				bad_error("entity_get_pg", scf_error());
4910 			}
4911 		}
4912 
4913 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
4914 			switch (scf_error()) {
4915 			case SCF_ERROR_DELETED:
4916 				break;
4917 
4918 			case SCF_ERROR_CONNECTION_BROKEN:
4919 			case SCF_ERROR_BACKEND_READONLY:
4920 			case SCF_ERROR_BACKEND_ACCESS:
4921 				r = scferror2errno(scf_error());
4922 				goto out;
4923 
4924 			case SCF_ERROR_PERMISSION_DENIED:
4925 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
4926 				    ient->sc_fmri);
4927 				r = scferror2errno(scf_error());
4928 				goto out;
4929 
4930 			case SCF_ERROR_NOT_SET:
4931 			case SCF_ERROR_NOT_BOUND:
4932 			default:
4933 				bad_error("scf_pg_delete", scf_error());
4934 			}
4935 		}
4936 
4937 		cbdata.sc_handle = g_hndl;
4938 		cbdata.sc_parent = ent;
4939 		cbdata.sc_service = issvc;
4940 		cbdata.sc_flags = 0;
4941 		cbdata.sc_source_fmri = ient->sc_fmri;
4942 		cbdata.sc_target_fmri = ient->sc_fmri;
4943 
4944 		r = entity_pgroup_import(mpg, &cbdata);
4945 		switch (r) {
4946 		case UU_WALK_NEXT:
4947 			r = 0;
4948 			goto out;
4949 
4950 		case UU_WALK_ERROR:
4951 			if (cbdata.sc_err == EEXIST) {
4952 				warn(emsg_pg_added, ient->sc_fmri,
4953 				    mpg->sc_pgroup_name);
4954 				r = EBUSY;
4955 			} else {
4956 				r = cbdata.sc_err;
4957 			}
4958 			goto out;
4959 
4960 		default:
4961 			bad_error("entity_pgroup_import", r);
4962 		}
4963 	}
4964 
4965 	if (running != NULL &&
4966 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4967 		switch (scf_error()) {
4968 		case SCF_ERROR_CONNECTION_BROKEN:
4969 		case SCF_ERROR_DELETED:
4970 			r = scferror2errno(scf_error());
4971 			goto out;
4972 
4973 		case SCF_ERROR_NOT_FOUND:
4974 			break;
4975 
4976 		case SCF_ERROR_HANDLE_MISMATCH:
4977 		case SCF_ERROR_INVALID_ARGUMENT:
4978 		case SCF_ERROR_NOT_SET:
4979 		case SCF_ERROR_NOT_BOUND:
4980 		default:
4981 			bad_error("entity_get_pg", scf_error());
4982 		}
4983 
4984 		cbdata.sc_handle = g_hndl;
4985 		cbdata.sc_parent = ent;
4986 		cbdata.sc_service = issvc;
4987 		cbdata.sc_flags = SCI_FORCE;
4988 		cbdata.sc_source_fmri = ient->sc_fmri;
4989 		cbdata.sc_target_fmri = ient->sc_fmri;
4990 
4991 		r = entity_pgroup_import(mpg, &cbdata);
4992 		switch (r) {
4993 		case UU_WALK_NEXT:
4994 			r = 0;
4995 			goto out;
4996 
4997 		case UU_WALK_ERROR:
4998 			if (cbdata.sc_err == EEXIST) {
4999 				warn(emsg_pg_added, ient->sc_fmri,
5000 				    mpg->sc_pgroup_name);
5001 				r = EBUSY;
5002 			} else {
5003 				r = cbdata.sc_err;
5004 			}
5005 			goto out;
5006 
5007 		default:
5008 			bad_error("entity_pgroup_import", r);
5009 		}
5010 	}
5011 
5012 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5013 	internal_pgroup_free(curpg_i);
5014 	switch (r) {
5015 	case 0:
5016 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5017 		break;
5018 
5019 	case ECANCELED:
5020 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5021 		r = EBUSY;
5022 		break;
5023 
5024 	case EPERM:
5025 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5026 		break;
5027 
5028 	case EBUSY:
5029 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5030 		break;
5031 
5032 	case ECONNABORTED:
5033 	case ENOMEM:
5034 	case ENOSPC:
5035 	case EROFS:
5036 	case EACCES:
5037 	case EINVAL:
5038 		break;
5039 
5040 	default:
5041 		bad_error("upgrade_pg", r);
5042 	}
5043 
5044 out:
5045 	internal_pgroup_free(lipg_i);
5046 	return (r);
5047 }
5048 
5049 /*
5050  * Upgrade the properties of ent according to snpl & ient.
5051  *
5052  * Returns
5053  *   0 - success
5054  *   ECONNABORTED - repository connection broken
5055  *   ENOMEM - out of memory
5056  *   ENOSPC - configd is out of resources
5057  *   ECANCELED - ent was deleted
5058  *   ENODEV - entity containing snpl was deleted
5059  *	    - entity containing running was deleted
5060  *   EBADF - imp_snpl is corrupt (error printed)
5061  *	   - ent has corrupt pg (error printed)
5062  *	   - dependent has corrupt pg (error printed)
5063  *	   - dependent target has a corrupt snapshot (error printed)
5064  *   EBUSY - pg was added, changed, or deleted (error printed)
5065  *	   - dependent target was deleted (error printed)
5066  *	   - dependent pg changed (error printed)
5067  *   EINVAL - invalid property group name (error printed)
5068  *	    - invalid property name (error printed)
5069  *	    - invalid value (error printed)
5070  *	    - ient has invalid pgroup or dependent (error printed)
5071  *   EPERM - could not create property group (permission denied) (error printed)
5072  *	   - could not modify property group (permission denied) (error printed)
5073  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5074  *   EROFS - could not create property group (repository read-only)
5075  *	   - couldn't delete, upgrade, or import pg or dependent
5076  *   EACCES - could not create property group (backend access denied)
5077  *	    - couldn't delete, upgrade, or import pg or dependent
5078  *   EEXIST - dependent collision in target service (error printed)
5079  */
5080 static int
5081 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5082     entity_t *ient)
5083 {
5084 	pgroup_t *pg, *rpg;
5085 	int r;
5086 	uu_list_t *pgs = ient->sc_pgroups;
5087 
5088 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5089 
5090 	/* clear sc_sceen for pgs */
5091 	if (uu_list_walk(pgs, clear_int,
5092 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5093 		bad_error("uu_list_walk", uu_error());
5094 
5095 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5096 		switch (scf_error()) {
5097 		case SCF_ERROR_DELETED:
5098 			return (ENODEV);
5099 
5100 		case SCF_ERROR_CONNECTION_BROKEN:
5101 			return (ECONNABORTED);
5102 
5103 		case SCF_ERROR_NOT_SET:
5104 		case SCF_ERROR_NOT_BOUND:
5105 		case SCF_ERROR_HANDLE_MISMATCH:
5106 		default:
5107 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5108 		}
5109 	}
5110 
5111 	for (;;) {
5112 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5113 		if (r == 0)
5114 			break;
5115 		if (r == 1) {
5116 			r = process_old_pg(imp_pg, ient, ent, running);
5117 			switch (r) {
5118 			case 0:
5119 				break;
5120 
5121 			case ECONNABORTED:
5122 			case ENOMEM:
5123 			case ENOSPC:
5124 			case ECANCELED:
5125 			case ENODEV:
5126 			case EPERM:
5127 			case EROFS:
5128 			case EACCES:
5129 			case EBADF:
5130 			case EBUSY:
5131 			case EINVAL:
5132 			case EEXIST:
5133 				return (r);
5134 
5135 			default:
5136 				bad_error("process_old_pg", r);
5137 			}
5138 			continue;
5139 		}
5140 		if (r != -1)
5141 			bad_error("scf_iter_next_pg", r);
5142 
5143 		switch (scf_error()) {
5144 		case SCF_ERROR_DELETED:
5145 			return (ENODEV);
5146 
5147 		case SCF_ERROR_CONNECTION_BROKEN:
5148 			return (ECONNABORTED);
5149 
5150 		case SCF_ERROR_HANDLE_MISMATCH:
5151 		case SCF_ERROR_NOT_BOUND:
5152 		case SCF_ERROR_NOT_SET:
5153 		case SCF_ERROR_INVALID_ARGUMENT:
5154 		default:
5155 			bad_error("scf_iter_next_pg", scf_error());
5156 		}
5157 	}
5158 
5159 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5160 		if (pg->sc_pgroup_seen)
5161 			continue;
5162 
5163 		/* pg is new */
5164 
5165 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5166 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5167 			    ent);
5168 			switch (r) {
5169 			case 0:
5170 				break;
5171 
5172 			case ECONNABORTED:
5173 			case ENOMEM:
5174 			case ENOSPC:
5175 			case ECANCELED:
5176 			case ENODEV:
5177 			case EBADF:
5178 			case EBUSY:
5179 			case EINVAL:
5180 			case EPERM:
5181 			case EROFS:
5182 			case EACCES:
5183 			case EEXIST:
5184 				return (r);
5185 
5186 			default:
5187 				bad_error("upgrade_dependents", r);
5188 			}
5189 			continue;
5190 		}
5191 
5192 		if (running != NULL)
5193 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
5194 			    imp_pg);
5195 		else
5196 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
5197 			    imp_pg);
5198 		if (r != 0) {
5199 			scf_callback_t cbdata;
5200 
5201 			switch (scf_error()) {
5202 			case SCF_ERROR_NOT_FOUND:
5203 				break;
5204 
5205 			case SCF_ERROR_CONNECTION_BROKEN:
5206 				return (scferror2errno(scf_error()));
5207 
5208 			case SCF_ERROR_DELETED:
5209 				if (running != NULL)
5210 					return (ENODEV);
5211 				else
5212 					return (scferror2errno(scf_error()));
5213 
5214 			case SCF_ERROR_INVALID_ARGUMENT:
5215 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
5216 				    pg->sc_pgroup_name);
5217 				return (EINVAL);
5218 
5219 			case SCF_ERROR_NOT_SET:
5220 			case SCF_ERROR_HANDLE_MISMATCH:
5221 			case SCF_ERROR_NOT_BOUND:
5222 			default:
5223 				bad_error("entity_get_pg", scf_error());
5224 			}
5225 
5226 			/* User doesn't have pg, so import it. */
5227 
5228 			cbdata.sc_handle = g_hndl;
5229 			cbdata.sc_parent = ent;
5230 			cbdata.sc_service = issvc;
5231 			cbdata.sc_flags = SCI_FORCE;
5232 			cbdata.sc_source_fmri = ient->sc_fmri;
5233 			cbdata.sc_target_fmri = ient->sc_fmri;
5234 
5235 			r = entity_pgroup_import(pg, &cbdata);
5236 			switch (r) {
5237 			case UU_WALK_NEXT:
5238 				ient->sc_import_state = IMPORT_PROP_BEGUN;
5239 				continue;
5240 
5241 			case UU_WALK_ERROR:
5242 				if (cbdata.sc_err == EEXIST) {
5243 					warn(emsg_pg_added, ient->sc_fmri,
5244 					    pg->sc_pgroup_name);
5245 					return (EBUSY);
5246 				}
5247 				return (cbdata.sc_err);
5248 
5249 			default:
5250 				bad_error("entity_pgroup_import", r);
5251 			}
5252 		}
5253 
5254 		/* report differences between pg & current */
5255 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
5256 		switch (r) {
5257 		case 0:
5258 			break;
5259 
5260 		case ECANCELED:
5261 			warn(emsg_pg_deleted, ient->sc_fmri,
5262 			    pg->sc_pgroup_name);
5263 			return (EBUSY);
5264 
5265 		case ECONNABORTED:
5266 		case EBADF:
5267 		case ENOMEM:
5268 		case EACCES:
5269 			return (r);
5270 
5271 		default:
5272 			bad_error("load_pg", r);
5273 		}
5274 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
5275 		internal_pgroup_free(rpg);
5276 		rpg = NULL;
5277 	}
5278 
5279 	return (0);
5280 }
5281 
5282 /*
5283  * Import an instance.  If it doesn't exist, create it.  If it has
5284  * a last-import snapshot, upgrade its properties.  Finish by updating its
5285  * last-import snapshot.  If it doesn't have a last-import snapshot then it
5286  * could have been created for a dependent tag in another manifest.  Import the
5287  * new properties.  If there's a conflict, don't override, like now?
5288  *
5289  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
5290  * lcbdata->sc_err to
5291  *   ECONNABORTED - repository connection broken
5292  *   ENOMEM - out of memory
5293  *   ENOSPC - svc.configd is out of resources
5294  *   EEXIST - dependency collision in dependent service (error printed)
5295  *   EPERM - couldn't create temporary instance (permission denied)
5296  *	   - couldn't import into temporary instance (permission denied)
5297  *	   - couldn't take snapshot (permission denied)
5298  *	   - couldn't upgrade properties (permission denied)
5299  *	   - couldn't import properties (permission denied)
5300  *	   - couldn't import dependents (permission denied)
5301  *   EROFS - couldn't create temporary instance (repository read-only)
5302  *	   - couldn't import into temporary instance (repository read-only)
5303  *	   - couldn't upgrade properties (repository read-only)
5304  *	   - couldn't import properties (repository read-only)
5305  *	   - couldn't import dependents (repository read-only)
5306  *   EACCES - couldn't create temporary instance (backend access denied)
5307  *	    - couldn't import into temporary instance (backend access denied)
5308  *	    - couldn't upgrade properties (backend access denied)
5309  *	    - couldn't import properties (backend access denied)
5310  *	    - couldn't import dependents (backend access denied)
5311  *   EINVAL - invalid instance name (error printed)
5312  *	    - invalid pgroup_t's (error printed)
5313  *	    - invalid dependents (error printed)
5314  *   EBUSY - temporary service deleted (error printed)
5315  *	   - temporary instance deleted (error printed)
5316  *	   - temporary instance changed (error printed)
5317  *	   - temporary instance already exists (error printed)
5318  *	   - instance deleted (error printed)
5319  *   EBADF - instance has corrupt last-import snapshot (error printed)
5320  *	   - instance is corrupt (error printed)
5321  *	   - dependent has corrupt pg (error printed)
5322  *	   - dependent target has a corrupt snapshot (error printed)
5323  *   -1 - unknown libscf error (error printed)
5324  */
5325 static int
5326 lscf_instance_import(void *v, void *pvt)
5327 {
5328 	entity_t *inst = v;
5329 	scf_callback_t ctx;
5330 	scf_callback_t *lcbdata = pvt;
5331 	scf_service_t *rsvc = lcbdata->sc_parent;
5332 	int r;
5333 	scf_snaplevel_t *running;
5334 	int flags = lcbdata->sc_flags;
5335 
5336 	const char * const emsg_tdel =
5337 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
5338 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
5339 	    "changed unexpectedly.\n");
5340 	const char * const emsg_del = gettext("%s changed unexpectedly "
5341 	    "(instance \"%s\" was deleted.)\n");
5342 	const char * const emsg_badsnap = gettext(
5343 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
5344 
5345 	/*
5346 	 * prepare last-import snapshot:
5347 	 * create temporary instance (service was precreated)
5348 	 * populate with properties from bundle
5349 	 * take snapshot
5350 	 */
5351 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
5352 		switch (scf_error()) {
5353 		case SCF_ERROR_CONNECTION_BROKEN:
5354 		case SCF_ERROR_NO_RESOURCES:
5355 		case SCF_ERROR_BACKEND_READONLY:
5356 		case SCF_ERROR_BACKEND_ACCESS:
5357 			return (stash_scferror(lcbdata));
5358 
5359 		case SCF_ERROR_EXISTS:
5360 			warn(gettext("Temporary service svc:/%s "
5361 			    "changed unexpectedly (instance \"%s\" added).\n"),
5362 			    imp_tsname, inst->sc_name);
5363 			lcbdata->sc_err = EBUSY;
5364 			return (UU_WALK_ERROR);
5365 
5366 		case SCF_ERROR_DELETED:
5367 			warn(gettext("Temporary service svc:/%s "
5368 			    "was deleted unexpectedly.\n"), imp_tsname);
5369 			lcbdata->sc_err = EBUSY;
5370 			return (UU_WALK_ERROR);
5371 
5372 		case SCF_ERROR_INVALID_ARGUMENT:
5373 			warn(gettext("Invalid instance name \"%s\".\n"),
5374 			    inst->sc_name);
5375 			return (stash_scferror(lcbdata));
5376 
5377 		case SCF_ERROR_PERMISSION_DENIED:
5378 			warn(gettext("Could not create temporary instance "
5379 			    "\"%s\" in svc:/%s (permission denied).\n"),
5380 			    inst->sc_name, imp_tsname);
5381 			return (stash_scferror(lcbdata));
5382 
5383 		case SCF_ERROR_HANDLE_MISMATCH:
5384 		case SCF_ERROR_NOT_BOUND:
5385 		case SCF_ERROR_NOT_SET:
5386 		default:
5387 			bad_error("scf_service_add_instance", scf_error());
5388 		}
5389 	}
5390 
5391 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5392 	    inst->sc_name);
5393 	if (r < 0)
5394 		bad_error("snprintf", errno);
5395 
5396 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
5397 	    lcbdata->sc_flags | SCI_NOENABLED);
5398 	switch (r) {
5399 	case 0:
5400 		break;
5401 
5402 	case ECANCELED:
5403 		warn(emsg_tdel, imp_tsname, inst->sc_name);
5404 		lcbdata->sc_err = EBUSY;
5405 		r = UU_WALK_ERROR;
5406 		goto deltemp;
5407 
5408 	case EEXIST:
5409 		warn(emsg_tchg, imp_tsname, inst->sc_name);
5410 		lcbdata->sc_err = EBUSY;
5411 		r = UU_WALK_ERROR;
5412 		goto deltemp;
5413 
5414 	case ECONNABORTED:
5415 		goto connaborted;
5416 
5417 	case ENOMEM:
5418 	case ENOSPC:
5419 	case EPERM:
5420 	case EROFS:
5421 	case EACCES:
5422 	case EINVAL:
5423 	case EBUSY:
5424 		lcbdata->sc_err = r;
5425 		r = UU_WALK_ERROR;
5426 		goto deltemp;
5427 
5428 	default:
5429 		bad_error("lscf_import_instance_pgs", r);
5430 	}
5431 
5432 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5433 	    inst->sc_name);
5434 	if (r < 0)
5435 		bad_error("snprintf", errno);
5436 
5437 	ctx.sc_handle = lcbdata->sc_handle;
5438 	ctx.sc_parent = imp_tinst;
5439 	ctx.sc_service = 0;
5440 	ctx.sc_source_fmri = inst->sc_fmri;
5441 	ctx.sc_target_fmri = imp_str;
5442 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
5443 	    UU_DEFAULT) != 0) {
5444 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5445 			bad_error("uu_list_walk", uu_error());
5446 
5447 		switch (ctx.sc_err) {
5448 		case ECONNABORTED:
5449 			goto connaborted;
5450 
5451 		case ECANCELED:
5452 			warn(emsg_tdel, imp_tsname, inst->sc_name);
5453 			lcbdata->sc_err = EBUSY;
5454 			break;
5455 
5456 		case EEXIST:
5457 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5458 			lcbdata->sc_err = EBUSY;
5459 			break;
5460 
5461 		default:
5462 			lcbdata->sc_err = ctx.sc_err;
5463 		}
5464 		r = UU_WALK_ERROR;
5465 		goto deltemp;
5466 	}
5467 
5468 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
5469 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
5470 		switch (scf_error()) {
5471 		case SCF_ERROR_CONNECTION_BROKEN:
5472 			goto connaborted;
5473 
5474 		case SCF_ERROR_NO_RESOURCES:
5475 			r = stash_scferror(lcbdata);
5476 			goto deltemp;
5477 
5478 		case SCF_ERROR_EXISTS:
5479 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5480 			lcbdata->sc_err = EBUSY;
5481 			r = UU_WALK_ERROR;
5482 			goto deltemp;
5483 
5484 		case SCF_ERROR_PERMISSION_DENIED:
5485 			warn(gettext("Could not take \"%s\" snapshot of %s "
5486 			    "(permission denied).\n"), snap_lastimport,
5487 			    imp_str);
5488 			r = stash_scferror(lcbdata);
5489 			goto deltemp;
5490 
5491 		default:
5492 			scfwarn();
5493 			lcbdata->sc_err = -1;
5494 			r = UU_WALK_ERROR;
5495 			goto deltemp;
5496 
5497 		case SCF_ERROR_HANDLE_MISMATCH:
5498 		case SCF_ERROR_INVALID_ARGUMENT:
5499 		case SCF_ERROR_NOT_SET:
5500 			bad_error("_scf_snapshot_take_new_named", scf_error());
5501 		}
5502 	}
5503 
5504 	if (lcbdata->sc_flags & SCI_FRESH)
5505 		goto fresh;
5506 
5507 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
5508 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
5509 		    imp_lisnap) != 0) {
5510 			switch (scf_error()) {
5511 			case SCF_ERROR_DELETED:
5512 				warn(emsg_del, inst->sc_parent->sc_fmri,
5513 				    inst->sc_name);
5514 				lcbdata->sc_err = EBUSY;
5515 				r = UU_WALK_ERROR;
5516 				goto deltemp;
5517 
5518 			case SCF_ERROR_NOT_FOUND:
5519 				flags |= SCI_FORCE;
5520 				goto nosnap;
5521 
5522 			case SCF_ERROR_CONNECTION_BROKEN:
5523 				goto connaborted;
5524 
5525 			case SCF_ERROR_INVALID_ARGUMENT:
5526 			case SCF_ERROR_HANDLE_MISMATCH:
5527 			case SCF_ERROR_NOT_BOUND:
5528 			case SCF_ERROR_NOT_SET:
5529 			default:
5530 				bad_error("scf_instance_get_snapshot",
5531 				    scf_error());
5532 			}
5533 		}
5534 
5535 		/* upgrade */
5536 
5537 		/*
5538 		 * compare new properties with last-import properties
5539 		 * upgrade current properties
5540 		 */
5541 		/* clear sc_sceen for pgs */
5542 		if (uu_list_walk(inst->sc_pgroups, clear_int,
5543 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
5544 		    0)
5545 			bad_error("uu_list_walk", uu_error());
5546 
5547 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
5548 		switch (r) {
5549 		case 0:
5550 			break;
5551 
5552 		case ECONNABORTED:
5553 			goto connaborted;
5554 
5555 		case ECANCELED:
5556 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5557 			lcbdata->sc_err = EBUSY;
5558 			r = UU_WALK_ERROR;
5559 			goto deltemp;
5560 
5561 		case ENOENT:
5562 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
5563 			lcbdata->sc_err = EBADF;
5564 			r = UU_WALK_ERROR;
5565 			goto deltemp;
5566 
5567 		default:
5568 			bad_error("get_snaplevel", r);
5569 		}
5570 
5571 		if (scf_instance_get_snapshot(imp_inst, snap_running,
5572 		    imp_rsnap) != 0) {
5573 			switch (scf_error()) {
5574 			case SCF_ERROR_DELETED:
5575 				warn(emsg_del, inst->sc_parent->sc_fmri,
5576 				    inst->sc_name);
5577 				lcbdata->sc_err = EBUSY;
5578 				r = UU_WALK_ERROR;
5579 				goto deltemp;
5580 
5581 			case SCF_ERROR_NOT_FOUND:
5582 				break;
5583 
5584 			case SCF_ERROR_CONNECTION_BROKEN:
5585 				goto connaborted;
5586 
5587 			case SCF_ERROR_INVALID_ARGUMENT:
5588 			case SCF_ERROR_HANDLE_MISMATCH:
5589 			case SCF_ERROR_NOT_BOUND:
5590 			case SCF_ERROR_NOT_SET:
5591 			default:
5592 				bad_error("scf_instance_get_snapshot",
5593 				    scf_error());
5594 			}
5595 
5596 			running = NULL;
5597 		} else {
5598 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
5599 			switch (r) {
5600 			case 0:
5601 				running = imp_rsnpl;
5602 				break;
5603 
5604 			case ECONNABORTED:
5605 				goto connaborted;
5606 
5607 			case ECANCELED:
5608 				warn(emsg_del, inst->sc_parent->sc_fmri,
5609 				    inst->sc_name);
5610 				lcbdata->sc_err = EBUSY;
5611 				r = UU_WALK_ERROR;
5612 				goto deltemp;
5613 
5614 			case ENOENT:
5615 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
5616 				lcbdata->sc_err = EBADF;
5617 				r = UU_WALK_ERROR;
5618 				goto deltemp;
5619 
5620 			default:
5621 				bad_error("get_snaplevel", r);
5622 			}
5623 		}
5624 
5625 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
5626 		switch (r) {
5627 		case 0:
5628 			break;
5629 
5630 		case ECANCELED:
5631 		case ENODEV:
5632 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5633 			lcbdata->sc_err = EBUSY;
5634 			r = UU_WALK_ERROR;
5635 			goto deltemp;
5636 
5637 		case ECONNABORTED:
5638 			goto connaborted;
5639 
5640 		case ENOMEM:
5641 		case ENOSPC:
5642 		case EBADF:
5643 		case EBUSY:
5644 		case EINVAL:
5645 		case EPERM:
5646 		case EROFS:
5647 		case EACCES:
5648 		case EEXIST:
5649 			lcbdata->sc_err = r;
5650 			r = UU_WALK_ERROR;
5651 			goto deltemp;
5652 
5653 		default:
5654 			bad_error("upgrade_props", r);
5655 		}
5656 
5657 		inst->sc_import_state = IMPORT_PROP_DONE;
5658 	} else {
5659 		switch (scf_error()) {
5660 		case SCF_ERROR_CONNECTION_BROKEN:
5661 			goto connaborted;
5662 
5663 		case SCF_ERROR_NOT_FOUND:
5664 			break;
5665 
5666 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
5667 		case SCF_ERROR_HANDLE_MISMATCH:
5668 		case SCF_ERROR_NOT_BOUND:
5669 		case SCF_ERROR_NOT_SET:
5670 		default:
5671 			bad_error("scf_service_get_instance", scf_error());
5672 		}
5673 
5674 fresh:
5675 		/* create instance */
5676 		if (scf_service_add_instance(rsvc, inst->sc_name,
5677 		    imp_inst) != 0) {
5678 			switch (scf_error()) {
5679 			case SCF_ERROR_CONNECTION_BROKEN:
5680 				goto connaborted;
5681 
5682 			case SCF_ERROR_NO_RESOURCES:
5683 			case SCF_ERROR_BACKEND_READONLY:
5684 			case SCF_ERROR_BACKEND_ACCESS:
5685 				r = stash_scferror(lcbdata);
5686 				goto deltemp;
5687 
5688 			case SCF_ERROR_EXISTS:
5689 				warn(gettext("%s changed unexpectedly "
5690 				    "(instance \"%s\" added).\n"),
5691 				    inst->sc_parent->sc_fmri, inst->sc_name);
5692 				lcbdata->sc_err = EBUSY;
5693 				r = UU_WALK_ERROR;
5694 				goto deltemp;
5695 
5696 			case SCF_ERROR_PERMISSION_DENIED:
5697 				warn(gettext("Could not create \"%s\" instance "
5698 				    "in %s (permission denied).\n"),
5699 				    inst->sc_name, inst->sc_parent->sc_fmri);
5700 				r = stash_scferror(lcbdata);
5701 				goto deltemp;
5702 
5703 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
5704 			case SCF_ERROR_HANDLE_MISMATCH:
5705 			case SCF_ERROR_NOT_BOUND:
5706 			case SCF_ERROR_NOT_SET:
5707 			default:
5708 				bad_error("scf_service_add_instance",
5709 				    scf_error());
5710 			}
5711 		}
5712 
5713 nosnap:
5714 		/*
5715 		 * Create a last-import snapshot to serve as an attachment
5716 		 * point for the real one from the temporary instance.  Since
5717 		 * the contents is irrelevant, take it now, while the instance
5718 		 * is empty, to minimize svc.configd's work.
5719 		 */
5720 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
5721 		    imp_lisnap) != 0) {
5722 			switch (scf_error()) {
5723 			case SCF_ERROR_CONNECTION_BROKEN:
5724 				goto connaborted;
5725 
5726 			case SCF_ERROR_NO_RESOURCES:
5727 				r = stash_scferror(lcbdata);
5728 				goto deltemp;
5729 
5730 			case SCF_ERROR_EXISTS:
5731 				warn(gettext("%s changed unexpectedly "
5732 				    "(snapshot \"%s\" added).\n"),
5733 				    inst->sc_fmri, snap_lastimport);
5734 				lcbdata->sc_err = EBUSY;
5735 				r = UU_WALK_ERROR;
5736 				goto deltemp;
5737 
5738 			case SCF_ERROR_PERMISSION_DENIED:
5739 				warn(gettext("Could not take \"%s\" snapshot "
5740 				    "of %s (permission denied).\n"),
5741 				    snap_lastimport, inst->sc_fmri);
5742 				r = stash_scferror(lcbdata);
5743 				goto deltemp;
5744 
5745 			default:
5746 				scfwarn();
5747 				lcbdata->sc_err = -1;
5748 				r = UU_WALK_ERROR;
5749 				goto deltemp;
5750 
5751 			case SCF_ERROR_NOT_SET:
5752 			case SCF_ERROR_INTERNAL:
5753 			case SCF_ERROR_INVALID_ARGUMENT:
5754 			case SCF_ERROR_HANDLE_MISMATCH:
5755 				bad_error("_scf_snapshot_take_new",
5756 				    scf_error());
5757 			}
5758 		}
5759 
5760 		if (li_only)
5761 			goto lionly;
5762 
5763 		inst->sc_import_state = IMPORT_PROP_BEGUN;
5764 
5765 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
5766 		    flags);
5767 		switch (r) {
5768 		case 0:
5769 			break;
5770 
5771 		case ECONNABORTED:
5772 			goto connaborted;
5773 
5774 		case ECANCELED:
5775 			warn(gettext("%s changed unexpectedly "
5776 			    "(instance \"%s\" deleted).\n"),
5777 			    inst->sc_parent->sc_fmri, inst->sc_name);
5778 			lcbdata->sc_err = EBUSY;
5779 			r = UU_WALK_ERROR;
5780 			goto deltemp;
5781 
5782 		case EEXIST:
5783 			warn(gettext("%s changed unexpectedly "
5784 			    "(property group added).\n"), inst->sc_fmri);
5785 			lcbdata->sc_err = EBUSY;
5786 			r = UU_WALK_ERROR;
5787 			goto deltemp;
5788 
5789 		default:
5790 			lcbdata->sc_err = r;
5791 			r = UU_WALK_ERROR;
5792 			goto deltemp;
5793 
5794 		case EINVAL:	/* caught above */
5795 			bad_error("lscf_import_instance_pgs", r);
5796 		}
5797 
5798 		ctx.sc_parent = imp_inst;
5799 		ctx.sc_service = 0;
5800 		ctx.sc_trans = NULL;
5801 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
5802 		    &ctx, UU_DEFAULT) != 0) {
5803 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5804 				bad_error("uu_list_walk", uu_error());
5805 
5806 			if (ctx.sc_err == ECONNABORTED)
5807 				goto connaborted;
5808 			lcbdata->sc_err = ctx.sc_err;
5809 			r = UU_WALK_ERROR;
5810 			goto deltemp;
5811 		}
5812 
5813 		inst->sc_import_state = IMPORT_PROP_DONE;
5814 
5815 		if (g_verbose)
5816 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
5817 			    snap_initial, inst->sc_fmri);
5818 		r = take_snap(imp_inst, snap_initial, imp_snap);
5819 		switch (r) {
5820 		case 0:
5821 			break;
5822 
5823 		case ECONNABORTED:
5824 			goto connaborted;
5825 
5826 		case ENOSPC:
5827 		case -1:
5828 			lcbdata->sc_err = r;
5829 			r = UU_WALK_ERROR;
5830 			goto deltemp;
5831 
5832 		case ECANCELED:
5833 			warn(gettext("%s changed unexpectedly "
5834 			    "(instance %s deleted).\n"),
5835 			    inst->sc_parent->sc_fmri, inst->sc_name);
5836 			lcbdata->sc_err = r;
5837 			r = UU_WALK_ERROR;
5838 			goto deltemp;
5839 
5840 		case EPERM:
5841 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
5842 			lcbdata->sc_err = r;
5843 			r = UU_WALK_ERROR;
5844 			goto deltemp;
5845 
5846 		default:
5847 			bad_error("take_snap", r);
5848 		}
5849 	}
5850 
5851 lionly:
5852 	if (lcbdata->sc_flags & SCI_NOSNAP)
5853 		goto deltemp;
5854 
5855 	/* transfer snapshot from temporary instance */
5856 	if (g_verbose)
5857 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
5858 		    snap_lastimport, inst->sc_fmri);
5859 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
5860 		switch (scf_error()) {
5861 		case SCF_ERROR_CONNECTION_BROKEN:
5862 			goto connaborted;
5863 
5864 		case SCF_ERROR_NO_RESOURCES:
5865 			r = stash_scferror(lcbdata);
5866 			goto deltemp;
5867 
5868 		case SCF_ERROR_PERMISSION_DENIED:
5869 			warn(gettext("Could not take \"%s\" snapshot for %s "
5870 			    "(permission denied).\n"), snap_lastimport,
5871 			    inst->sc_fmri);
5872 			r = stash_scferror(lcbdata);
5873 			goto deltemp;
5874 
5875 		case SCF_ERROR_NOT_SET:
5876 		case SCF_ERROR_HANDLE_MISMATCH:
5877 		default:
5878 			bad_error("_scf_snapshot_attach", scf_error());
5879 		}
5880 	}
5881 
5882 	inst->sc_import_state = IMPORT_COMPLETE;
5883 
5884 	r = UU_WALK_NEXT;
5885 
5886 deltemp:
5887 	/* delete temporary instance */
5888 	if (scf_instance_delete(imp_tinst) != 0) {
5889 		switch (scf_error()) {
5890 		case SCF_ERROR_DELETED:
5891 			break;
5892 
5893 		case SCF_ERROR_CONNECTION_BROKEN:
5894 			goto connaborted;
5895 
5896 		case SCF_ERROR_NOT_SET:
5897 		case SCF_ERROR_NOT_BOUND:
5898 		default:
5899 			bad_error("scf_instance_delete", scf_error());
5900 		}
5901 	}
5902 
5903 	return (r);
5904 
5905 connaborted:
5906 	warn(gettext("Could not delete svc:/%s:%s "
5907 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
5908 	lcbdata->sc_err = ECONNABORTED;
5909 	return (UU_WALK_ERROR);
5910 }
5911 
5912 /*
5913  * If the service is missing, create it, import its properties, and import the
5914  * instances.  Since the service is brand new, it should be empty, and if we
5915  * run into any existing entities (SCF_ERROR_EXISTS), abort.
5916  *
5917  * If the service exists, we want to upgrade its properties and import the
5918  * instances.  Upgrade requires a last-import snapshot, though, which are
5919  * children of instances, so first we'll have to go through the instances
5920  * looking for a last-import snapshot.  If we don't find one then we'll just
5921  * override-import the service properties (but don't delete existing
5922  * properties: another service might have declared us as a dependent).  Before
5923  * we change anything, though, we want to take the previous snapshots.  We
5924  * also give lscf_instance_import() a leg up on taking last-import snapshots
5925  * by importing the manifest's service properties into a temporary service.
5926  *
5927  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
5928  * sets lcbdata->sc_err to
5929  *   ECONNABORTED - repository connection broken
5930  *   ENOMEM - out of memory
5931  *   ENOSPC - svc.configd is out of resources
5932  *   EPERM - couldn't create temporary service (error printed)
5933  *	   - couldn't import into temp service (error printed)
5934  *	   - couldn't create service (error printed)
5935  *	   - couldn't import dependent (error printed)
5936  *	   - couldn't take snapshot (error printed)
5937  *	   - couldn't create instance (error printed)
5938  *	   - couldn't create, modify, or delete pg (error printed)
5939  *	   - couldn't create, modify, or delete dependent (error printed)
5940  *	   - couldn't import instance (error printed)
5941  *   EROFS - couldn't create temporary service (repository read-only)
5942  *	   - couldn't import into temporary service (repository read-only)
5943  *	   - couldn't create service (repository read-only)
5944  *	   - couldn't import dependent (repository read-only)
5945  *	   - couldn't create instance (repository read-only)
5946  *	   - couldn't create, modify, or delete pg or dependent
5947  *	   - couldn't import instance (repository read-only)
5948  *   EACCES - couldn't create temporary service (backend access denied)
5949  *	    - couldn't import into temporary service (backend access denied)
5950  *	    - couldn't create service (backend access denied)
5951  *	    - couldn't import dependent (backend access denied)
5952  *	    - couldn't create instance (backend access denied)
5953  *	    - couldn't create, modify, or delete pg or dependent
5954  *	    - couldn't import instance (backend access denied)
5955  *   EINVAL - service name is invalid (error printed)
5956  *	    - service name is too long (error printed)
5957  *	    - s has invalid pgroup (error printed)
5958  *	    - s has invalid dependent (error printed)
5959  *	    - instance name is invalid (error printed)
5960  *	    - instance entity_t is invalid (error printed)
5961  *   EEXIST - couldn't create temporary service (already exists) (error printed)
5962  *	    - couldn't import dependent (dependency pg already exists) (printed)
5963  *	    - dependency collision in dependent service (error printed)
5964  *   EBUSY - temporary service deleted (error printed)
5965  *	   - property group added to temporary service (error printed)
5966  *	   - new property group changed or was deleted (error printed)
5967  *	   - service was added unexpectedly (error printed)
5968  *	   - service was deleted unexpectedly (error printed)
5969  *	   - property group added to new service (error printed)
5970  *	   - instance added unexpectedly (error printed)
5971  *	   - instance deleted unexpectedly (error printed)
5972  *	   - dependent service deleted unexpectedly (error printed)
5973  *	   - pg was added, changed, or deleted (error printed)
5974  *	   - dependent pg changed (error printed)
5975  *	   - temporary instance added, changed, or deleted (error printed)
5976  *   EBADF - a last-import snapshot is corrupt (error printed)
5977  *	   - the service is corrupt (error printed)
5978  *	   - a dependent is corrupt (error printed)
5979  *	   - an instance is corrupt (error printed)
5980  *	   - an instance has a corrupt last-import snapshot (error printed)
5981  *	   - dependent target has a corrupt snapshot (error printed)
5982  *   -1 - unknown libscf error (error printed)
5983  */
5984 static int
5985 lscf_service_import(void *v, void *pvt)
5986 {
5987 	entity_t *s = v;
5988 	scf_callback_t cbdata;
5989 	scf_callback_t *lcbdata = pvt;
5990 	scf_scope_t *scope = lcbdata->sc_parent;
5991 	entity_t *inst, linst;
5992 	int r;
5993 	int fresh = 0;
5994 	scf_snaplevel_t *running;
5995 	int have_ge;
5996 
5997 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
5998 	    "was deleted unexpectedly.\n");
5999 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6000 	    "changed unexpectedly (property group added).\n");
6001 	const char * const s_deleted =
6002 	    gettext("%s was deleted unexpectedly.\n");
6003 	const char * const i_deleted =
6004 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6005 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6006 	    "is corrupt (missing service snaplevel).\n");
6007 
6008 	/* Validate the service name */
6009 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6010 		switch (scf_error()) {
6011 		case SCF_ERROR_CONNECTION_BROKEN:
6012 			return (stash_scferror(lcbdata));
6013 
6014 		case SCF_ERROR_INVALID_ARGUMENT:
6015 			warn(gettext("\"%s\" is an invalid service name.  "
6016 			    "Cannot import.\n"), s->sc_name);
6017 			return (stash_scferror(lcbdata));
6018 
6019 		case SCF_ERROR_NOT_FOUND:
6020 			break;
6021 
6022 		case SCF_ERROR_HANDLE_MISMATCH:
6023 		case SCF_ERROR_NOT_BOUND:
6024 		case SCF_ERROR_NOT_SET:
6025 		default:
6026 			bad_error("scf_scope_get_service", scf_error());
6027 		}
6028 	}
6029 
6030 	/* create temporary service */
6031 	/*
6032 	 * the size of the buffer was reduced to max_scf_name_len to prevent
6033 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6034 	 * should be restored to its original value (max_scf_name_len +1)
6035 	 */
6036 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6037 	if (r < 0)
6038 		bad_error("snprintf", errno);
6039 	if (r > max_scf_name_len) {
6040 		warn(gettext(
6041 		    "Service name \"%s\" is too long.  Cannot import.\n"),
6042 		    s->sc_name);
6043 		lcbdata->sc_err = EINVAL;
6044 		return (UU_WALK_ERROR);
6045 	}
6046 
6047 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6048 		switch (scf_error()) {
6049 		case SCF_ERROR_CONNECTION_BROKEN:
6050 		case SCF_ERROR_NO_RESOURCES:
6051 		case SCF_ERROR_BACKEND_READONLY:
6052 		case SCF_ERROR_BACKEND_ACCESS:
6053 			return (stash_scferror(lcbdata));
6054 
6055 		case SCF_ERROR_EXISTS:
6056 			warn(gettext(
6057 			    "Temporary service \"%s\" must be deleted before "
6058 			    "this manifest can be imported.\n"), imp_tsname);
6059 			return (stash_scferror(lcbdata));
6060 
6061 		case SCF_ERROR_PERMISSION_DENIED:
6062 			warn(gettext("Could not create temporary service "
6063 			    "\"%s\" (permission denied).\n"), imp_tsname);
6064 			return (stash_scferror(lcbdata));
6065 
6066 		case SCF_ERROR_INVALID_ARGUMENT:
6067 		case SCF_ERROR_HANDLE_MISMATCH:
6068 		case SCF_ERROR_NOT_BOUND:
6069 		case SCF_ERROR_NOT_SET:
6070 		default:
6071 			bad_error("scf_scope_add_service", scf_error());
6072 		}
6073 	}
6074 
6075 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6076 	if (r < 0)
6077 		bad_error("snprintf", errno);
6078 
6079 	cbdata.sc_handle = lcbdata->sc_handle;
6080 	cbdata.sc_parent = imp_tsvc;
6081 	cbdata.sc_service = 1;
6082 	cbdata.sc_source_fmri = s->sc_fmri;
6083 	cbdata.sc_target_fmri = imp_str;
6084 	cbdata.sc_flags = 0;
6085 
6086 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6087 	    UU_DEFAULT) != 0) {
6088 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6089 			bad_error("uu_list_walk", uu_error());
6090 
6091 		lcbdata->sc_err = cbdata.sc_err;
6092 		switch (cbdata.sc_err) {
6093 		case ECONNABORTED:
6094 			goto connaborted;
6095 
6096 		case ECANCELED:
6097 			warn(ts_deleted, imp_tsname);
6098 			lcbdata->sc_err = EBUSY;
6099 			return (UU_WALK_ERROR);
6100 
6101 		case EEXIST:
6102 			warn(ts_pg_added, imp_tsname);
6103 			lcbdata->sc_err = EBUSY;
6104 			return (UU_WALK_ERROR);
6105 		}
6106 
6107 		r = UU_WALK_ERROR;
6108 		goto deltemp;
6109 	}
6110 
6111 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6112 	    UU_DEFAULT) != 0) {
6113 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6114 			bad_error("uu_list_walk", uu_error());
6115 
6116 		lcbdata->sc_err = cbdata.sc_err;
6117 		switch (cbdata.sc_err) {
6118 		case ECONNABORTED:
6119 			goto connaborted;
6120 
6121 		case ECANCELED:
6122 			warn(ts_deleted, imp_tsname);
6123 			lcbdata->sc_err = EBUSY;
6124 			return (UU_WALK_ERROR);
6125 
6126 		case EEXIST:
6127 			warn(ts_pg_added, imp_tsname);
6128 			lcbdata->sc_err = EBUSY;
6129 			return (UU_WALK_ERROR);
6130 		}
6131 
6132 		r = UU_WALK_ERROR;
6133 		goto deltemp;
6134 	}
6135 
6136 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6137 		switch (scf_error()) {
6138 		case SCF_ERROR_NOT_FOUND:
6139 			break;
6140 
6141 		case SCF_ERROR_CONNECTION_BROKEN:
6142 			goto connaborted;
6143 
6144 		case SCF_ERROR_INVALID_ARGUMENT:
6145 		case SCF_ERROR_HANDLE_MISMATCH:
6146 		case SCF_ERROR_NOT_BOUND:
6147 		case SCF_ERROR_NOT_SET:
6148 		default:
6149 			bad_error("scf_scope_get_service", scf_error());
6150 		}
6151 
6152 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6153 			switch (scf_error()) {
6154 			case SCF_ERROR_CONNECTION_BROKEN:
6155 				goto connaborted;
6156 
6157 			case SCF_ERROR_NO_RESOURCES:
6158 			case SCF_ERROR_BACKEND_READONLY:
6159 			case SCF_ERROR_BACKEND_ACCESS:
6160 				r = stash_scferror(lcbdata);
6161 				goto deltemp;
6162 
6163 			case SCF_ERROR_EXISTS:
6164 				warn(gettext("Scope \"%s\" changed unexpectedly"
6165 				    " (service \"%s\" added).\n"),
6166 				    SCF_SCOPE_LOCAL, s->sc_name);
6167 				lcbdata->sc_err = EBUSY;
6168 				goto deltemp;
6169 
6170 			case SCF_ERROR_PERMISSION_DENIED:
6171 				warn(gettext("Could not create service \"%s\" "
6172 				    "(permission denied).\n"), s->sc_name);
6173 				goto deltemp;
6174 
6175 			case SCF_ERROR_INVALID_ARGUMENT:
6176 			case SCF_ERROR_HANDLE_MISMATCH:
6177 			case SCF_ERROR_NOT_BOUND:
6178 			case SCF_ERROR_NOT_SET:
6179 			default:
6180 				bad_error("scf_scope_add_service", scf_error());
6181 			}
6182 		}
6183 
6184 		s->sc_import_state = IMPORT_PROP_BEGUN;
6185 
6186 		/* import service properties */
6187 		cbdata.sc_handle = lcbdata->sc_handle;
6188 		cbdata.sc_parent = imp_svc;
6189 		cbdata.sc_service = 1;
6190 		cbdata.sc_flags = lcbdata->sc_flags;
6191 		cbdata.sc_source_fmri = s->sc_fmri;
6192 		cbdata.sc_target_fmri = s->sc_fmri;
6193 
6194 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6195 		    &cbdata, UU_DEFAULT) != 0) {
6196 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6197 				bad_error("uu_list_walk", uu_error());
6198 
6199 			lcbdata->sc_err = cbdata.sc_err;
6200 			switch (cbdata.sc_err) {
6201 			case ECONNABORTED:
6202 				goto connaborted;
6203 
6204 			case ECANCELED:
6205 				warn(s_deleted, s->sc_fmri);
6206 				lcbdata->sc_err = EBUSY;
6207 				return (UU_WALK_ERROR);
6208 
6209 			case EEXIST:
6210 				warn(gettext("%s changed unexpectedly "
6211 				    "(property group added).\n"), s->sc_fmri);
6212 				lcbdata->sc_err = EBUSY;
6213 				return (UU_WALK_ERROR);
6214 
6215 			case EINVAL:
6216 				/* caught above */
6217 				bad_error("entity_pgroup_import",
6218 				    cbdata.sc_err);
6219 			}
6220 
6221 			r = UU_WALK_ERROR;
6222 			goto deltemp;
6223 		}
6224 
6225 		cbdata.sc_trans = NULL;
6226 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
6227 		    &cbdata, UU_DEFAULT) != 0) {
6228 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6229 				bad_error("uu_list_walk", uu_error());
6230 
6231 			lcbdata->sc_err = cbdata.sc_err;
6232 			if (cbdata.sc_err == ECONNABORTED)
6233 				goto connaborted;
6234 			r = UU_WALK_ERROR;
6235 			goto deltemp;
6236 		}
6237 
6238 		s->sc_import_state = IMPORT_PROP_DONE;
6239 
6240 		/*
6241 		 * This is a new service, so we can't take previous snapshots
6242 		 * or upgrade service properties.
6243 		 */
6244 		fresh = 1;
6245 		goto instances;
6246 	}
6247 
6248 	/* Clear sc_seen for the instances. */
6249 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
6250 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
6251 		bad_error("uu_list_walk", uu_error());
6252 
6253 	/*
6254 	 * Take previous snapshots for all instances.  Even for ones not
6255 	 * mentioned in the bundle, since we might change their service
6256 	 * properties.
6257 	 */
6258 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6259 		switch (scf_error()) {
6260 		case SCF_ERROR_CONNECTION_BROKEN:
6261 			goto connaborted;
6262 
6263 		case SCF_ERROR_DELETED:
6264 			warn(s_deleted, s->sc_fmri);
6265 			lcbdata->sc_err = EBUSY;
6266 			r = UU_WALK_ERROR;
6267 			goto deltemp;
6268 
6269 		case SCF_ERROR_HANDLE_MISMATCH:
6270 		case SCF_ERROR_NOT_BOUND:
6271 		case SCF_ERROR_NOT_SET:
6272 		default:
6273 			bad_error("scf_iter_service_instances", scf_error());
6274 		}
6275 	}
6276 
6277 	for (;;) {
6278 		r = scf_iter_next_instance(imp_iter, imp_inst);
6279 		if (r == 0)
6280 			break;
6281 		if (r != 1) {
6282 			switch (scf_error()) {
6283 			case SCF_ERROR_DELETED:
6284 				warn(s_deleted, s->sc_fmri);
6285 				lcbdata->sc_err = EBUSY;
6286 				r = UU_WALK_ERROR;
6287 				goto deltemp;
6288 
6289 			case SCF_ERROR_CONNECTION_BROKEN:
6290 				goto connaborted;
6291 
6292 			case SCF_ERROR_NOT_BOUND:
6293 			case SCF_ERROR_HANDLE_MISMATCH:
6294 			case SCF_ERROR_INVALID_ARGUMENT:
6295 			case SCF_ERROR_NOT_SET:
6296 			default:
6297 				bad_error("scf_iter_next_instance",
6298 				    scf_error());
6299 			}
6300 		}
6301 
6302 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
6303 			switch (scf_error()) {
6304 			case SCF_ERROR_DELETED:
6305 				continue;
6306 
6307 			case SCF_ERROR_CONNECTION_BROKEN:
6308 				goto connaborted;
6309 
6310 			case SCF_ERROR_NOT_SET:
6311 			case SCF_ERROR_NOT_BOUND:
6312 			default:
6313 				bad_error("scf_instance_get_name", scf_error());
6314 			}
6315 		}
6316 
6317 		if (g_verbose)
6318 			warn(gettext(
6319 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
6320 			    snap_previous, s->sc_name, imp_str);
6321 
6322 		r = take_snap(imp_inst, snap_previous, imp_snap);
6323 		switch (r) {
6324 		case 0:
6325 			break;
6326 
6327 		case ECANCELED:
6328 			continue;
6329 
6330 		case ECONNABORTED:
6331 			goto connaborted;
6332 
6333 		case EPERM:
6334 			warn(gettext("Could not take \"%s\" snapshot of "
6335 			    "svc:/%s:%s (permission denied).\n"),
6336 			    snap_previous, s->sc_name, imp_str);
6337 			lcbdata->sc_err = r;
6338 			return (UU_WALK_ERROR);
6339 
6340 		case ENOSPC:
6341 		case -1:
6342 			lcbdata->sc_err = r;
6343 			r = UU_WALK_ERROR;
6344 			goto deltemp;
6345 
6346 		default:
6347 			bad_error("take_snap", r);
6348 		}
6349 
6350 		linst.sc_name = imp_str;
6351 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
6352 		    &linst, NULL, NULL);
6353 		if (inst != NULL) {
6354 			inst->sc_import_state = IMPORT_PREVIOUS;
6355 			inst->sc_seen = 1;
6356 		}
6357 	}
6358 
6359 	/*
6360 	 * Create the new instances and take previous snapshots of
6361 	 * them.  This is not necessary, but it maximizes data preservation.
6362 	 */
6363 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
6364 	    inst != NULL;
6365 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
6366 	    inst)) {
6367 		if (inst->sc_seen)
6368 			continue;
6369 
6370 		if (scf_service_add_instance(imp_svc, inst->sc_name,
6371 		    imp_inst) != 0) {
6372 			switch (scf_error()) {
6373 			case SCF_ERROR_CONNECTION_BROKEN:
6374 				goto connaborted;
6375 
6376 			case SCF_ERROR_BACKEND_READONLY:
6377 			case SCF_ERROR_BACKEND_ACCESS:
6378 			case SCF_ERROR_NO_RESOURCES:
6379 				r = stash_scferror(lcbdata);
6380 				goto deltemp;
6381 
6382 			case SCF_ERROR_EXISTS:
6383 				warn(gettext("%s changed unexpectedly "
6384 				    "(instance \"%s\" added).\n"), s->sc_fmri,
6385 				    inst->sc_name);
6386 				lcbdata->sc_err = EBUSY;
6387 				r = UU_WALK_ERROR;
6388 				goto deltemp;
6389 
6390 			case SCF_ERROR_INVALID_ARGUMENT:
6391 				warn(gettext("Service \"%s\" has instance with "
6392 				    "invalid name \"%s\".\n"), s->sc_name,
6393 				    inst->sc_name);
6394 				r = stash_scferror(lcbdata);
6395 				goto deltemp;
6396 
6397 			case SCF_ERROR_PERMISSION_DENIED:
6398 				warn(gettext("Could not create instance \"%s\" "
6399 				    "in %s (permission denied).\n"),
6400 				    inst->sc_name, s->sc_fmri);
6401 				r = stash_scferror(lcbdata);
6402 				goto deltemp;
6403 
6404 			case SCF_ERROR_HANDLE_MISMATCH:
6405 			case SCF_ERROR_NOT_BOUND:
6406 			case SCF_ERROR_NOT_SET:
6407 			default:
6408 				bad_error("scf_service_add_instance",
6409 				    scf_error());
6410 			}
6411 		}
6412 
6413 		if (g_verbose)
6414 			warn(gettext("Taking \"%s\" snapshot for "
6415 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
6416 		r = take_snap(imp_inst, snap_previous, imp_snap);
6417 		switch (r) {
6418 		case 0:
6419 			break;
6420 
6421 		case ECANCELED:
6422 			warn(i_deleted, s->sc_fmri, inst->sc_name);
6423 			lcbdata->sc_err = EBUSY;
6424 			r = UU_WALK_ERROR;
6425 			goto deltemp;
6426 
6427 		case ECONNABORTED:
6428 			goto connaborted;
6429 
6430 		case EPERM:
6431 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
6432 			lcbdata->sc_err = r;
6433 			r = UU_WALK_ERROR;
6434 			goto deltemp;
6435 
6436 		case ENOSPC:
6437 		case -1:
6438 			r = UU_WALK_ERROR;
6439 			goto deltemp;
6440 
6441 		default:
6442 			bad_error("take_snap", r);
6443 		}
6444 	}
6445 
6446 	s->sc_import_state = IMPORT_PREVIOUS;
6447 
6448 	/*
6449 	 * Upgrade service properties, if we can find a last-import snapshot.
6450 	 * Any will do because we don't support different service properties
6451 	 * in different manifests, so all snaplevels of the service in all of
6452 	 * the last-import snapshots of the instances should be the same.
6453 	 */
6454 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6455 		switch (scf_error()) {
6456 		case SCF_ERROR_CONNECTION_BROKEN:
6457 			goto connaborted;
6458 
6459 		case SCF_ERROR_DELETED:
6460 			warn(s_deleted, s->sc_fmri);
6461 			lcbdata->sc_err = EBUSY;
6462 			r = UU_WALK_ERROR;
6463 			goto deltemp;
6464 
6465 		case SCF_ERROR_HANDLE_MISMATCH:
6466 		case SCF_ERROR_NOT_BOUND:
6467 		case SCF_ERROR_NOT_SET:
6468 		default:
6469 			bad_error("scf_iter_service_instances", scf_error());
6470 		}
6471 	}
6472 
6473 	have_ge = 0;
6474 	li_only = 0;
6475 
6476 	for (;;) {
6477 		r = scf_iter_next_instance(imp_iter, imp_inst);
6478 		if (r == -1) {
6479 			switch (scf_error()) {
6480 			case SCF_ERROR_DELETED:
6481 				warn(s_deleted, s->sc_fmri);
6482 				lcbdata->sc_err = EBUSY;
6483 				r = UU_WALK_ERROR;
6484 				goto deltemp;
6485 
6486 			case SCF_ERROR_CONNECTION_BROKEN:
6487 				goto connaborted;
6488 
6489 			case SCF_ERROR_NOT_BOUND:
6490 			case SCF_ERROR_HANDLE_MISMATCH:
6491 			case SCF_ERROR_INVALID_ARGUMENT:
6492 			case SCF_ERROR_NOT_SET:
6493 			default:
6494 				bad_error("scf_iter_next_instance",
6495 				    scf_error());
6496 			}
6497 		}
6498 
6499 		if (r == 0) {
6500 			/*
6501 			 * Didn't find any last-import snapshots.  Override-
6502 			 * import the properties.  Unless one of the instances
6503 			 * has a general/enabled property, in which case we're
6504 			 * probably running a last-import-capable svccfg for
6505 			 * the first time, and we should only take the
6506 			 * last-import snapshot.
6507 			 */
6508 			if (have_ge) {
6509 				li_only = 1;
6510 				no_refresh = 1;
6511 				break;
6512 			}
6513 
6514 			s->sc_import_state = IMPORT_PROP_BEGUN;
6515 
6516 			cbdata.sc_handle = g_hndl;
6517 			cbdata.sc_parent = imp_svc;
6518 			cbdata.sc_service = 1;
6519 			cbdata.sc_flags = SCI_FORCE;
6520 			cbdata.sc_source_fmri = s->sc_fmri;
6521 			cbdata.sc_target_fmri = s->sc_fmri;
6522 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6523 			    &cbdata, UU_DEFAULT) != 0) {
6524 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6525 					bad_error("uu_list_walk", uu_error());
6526 				lcbdata->sc_err = cbdata.sc_err;
6527 				switch (cbdata.sc_err) {
6528 				case ECONNABORTED:
6529 					goto connaborted;
6530 
6531 				case ECANCELED:
6532 					warn(s_deleted, s->sc_fmri);
6533 					lcbdata->sc_err = EBUSY;
6534 					break;
6535 
6536 				case EINVAL:	/* caught above */
6537 				case EEXIST:
6538 					bad_error("entity_pgroup_import",
6539 					    cbdata.sc_err);
6540 				}
6541 
6542 				r = UU_WALK_ERROR;
6543 				goto deltemp;
6544 			}
6545 
6546 			cbdata.sc_trans = NULL;
6547 			if (uu_list_walk(s->sc_dependents,
6548 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
6549 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6550 					bad_error("uu_list_walk", uu_error());
6551 				lcbdata->sc_err = cbdata.sc_err;
6552 				if (cbdata.sc_err == ECONNABORTED)
6553 					goto connaborted;
6554 				r = UU_WALK_ERROR;
6555 				goto deltemp;
6556 			}
6557 			break;
6558 		}
6559 
6560 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6561 		    imp_snap) != 0) {
6562 			switch (scf_error()) {
6563 			case SCF_ERROR_DELETED:
6564 				continue;
6565 
6566 			case SCF_ERROR_NOT_FOUND:
6567 				break;
6568 
6569 			case SCF_ERROR_CONNECTION_BROKEN:
6570 				goto connaborted;
6571 
6572 			case SCF_ERROR_HANDLE_MISMATCH:
6573 			case SCF_ERROR_NOT_BOUND:
6574 			case SCF_ERROR_INVALID_ARGUMENT:
6575 			case SCF_ERROR_NOT_SET:
6576 			default:
6577 				bad_error("scf_instance_get_snapshot",
6578 				    scf_error());
6579 			}
6580 
6581 			if (have_ge)
6582 				continue;
6583 
6584 			/*
6585 			 * Check for a general/enabled property.  This is how
6586 			 * we tell whether to import if there turn out to be
6587 			 * no last-import snapshots.
6588 			 */
6589 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
6590 			    imp_pg) == 0) {
6591 				if (scf_pg_get_property(imp_pg,
6592 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
6593 					have_ge = 1;
6594 				} else {
6595 					switch (scf_error()) {
6596 					case SCF_ERROR_DELETED:
6597 					case SCF_ERROR_NOT_FOUND:
6598 						continue;
6599 
6600 					case SCF_ERROR_INVALID_ARGUMENT:
6601 					case SCF_ERROR_HANDLE_MISMATCH:
6602 					case SCF_ERROR_CONNECTION_BROKEN:
6603 					case SCF_ERROR_NOT_BOUND:
6604 					case SCF_ERROR_NOT_SET:
6605 					default:
6606 						bad_error("scf_pg_get_property",
6607 						    scf_error());
6608 					}
6609 				}
6610 			} else {
6611 				switch (scf_error()) {
6612 				case SCF_ERROR_DELETED:
6613 				case SCF_ERROR_NOT_FOUND:
6614 					continue;
6615 
6616 				case SCF_ERROR_CONNECTION_BROKEN:
6617 					goto connaborted;
6618 
6619 				case SCF_ERROR_NOT_BOUND:
6620 				case SCF_ERROR_NOT_SET:
6621 				case SCF_ERROR_INVALID_ARGUMENT:
6622 				case SCF_ERROR_HANDLE_MISMATCH:
6623 				default:
6624 					bad_error("scf_instance_get_pg",
6625 					    scf_error());
6626 				}
6627 			}
6628 			continue;
6629 		}
6630 
6631 		/* find service snaplevel */
6632 		r = get_snaplevel(imp_snap, 1, imp_snpl);
6633 		switch (r) {
6634 		case 0:
6635 			break;
6636 
6637 		case ECONNABORTED:
6638 			goto connaborted;
6639 
6640 		case ECANCELED:
6641 			continue;
6642 
6643 		case ENOENT:
6644 			if (scf_instance_get_name(imp_inst, imp_str,
6645 			    imp_str_sz) < 0)
6646 				(void) strcpy(imp_str, "?");
6647 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
6648 			lcbdata->sc_err = EBADF;
6649 			r = UU_WALK_ERROR;
6650 			goto deltemp;
6651 
6652 		default:
6653 			bad_error("get_snaplevel", r);
6654 		}
6655 
6656 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6657 		    imp_rsnap) != 0) {
6658 			switch (scf_error()) {
6659 			case SCF_ERROR_DELETED:
6660 				continue;
6661 
6662 			case SCF_ERROR_NOT_FOUND:
6663 				break;
6664 
6665 			case SCF_ERROR_CONNECTION_BROKEN:
6666 				goto connaborted;
6667 
6668 			case SCF_ERROR_INVALID_ARGUMENT:
6669 			case SCF_ERROR_HANDLE_MISMATCH:
6670 			case SCF_ERROR_NOT_BOUND:
6671 			case SCF_ERROR_NOT_SET:
6672 			default:
6673 				bad_error("scf_instance_get_snapshot",
6674 				    scf_error());
6675 			}
6676 			running = NULL;
6677 		} else {
6678 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
6679 			switch (r) {
6680 			case 0:
6681 				running = imp_rsnpl;
6682 				break;
6683 
6684 			case ECONNABORTED:
6685 				goto connaborted;
6686 
6687 			case ECANCELED:
6688 				continue;
6689 
6690 			case ENOENT:
6691 				if (scf_instance_get_name(imp_inst, imp_str,
6692 				    imp_str_sz) < 0)
6693 					(void) strcpy(imp_str, "?");
6694 				warn(badsnap, snap_running, s->sc_name,
6695 				    imp_str);
6696 				lcbdata->sc_err = EBADF;
6697 				r = UU_WALK_ERROR;
6698 				goto deltemp;
6699 
6700 			default:
6701 				bad_error("get_snaplevel", r);
6702 			}
6703 		}
6704 
6705 		if (g_verbose) {
6706 			if (scf_instance_get_name(imp_inst, imp_str,
6707 			    imp_str_sz) < 0)
6708 				(void) strcpy(imp_str, "?");
6709 			warn(gettext("Upgrading properties of %s according to "
6710 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
6711 		}
6712 
6713 		/* upgrade service properties */
6714 		r = upgrade_props(imp_svc, running, imp_snpl, s);
6715 		if (r == 0)
6716 			break;
6717 
6718 		switch (r) {
6719 		case ECONNABORTED:
6720 			goto connaborted;
6721 
6722 		case ECANCELED:
6723 			warn(s_deleted, s->sc_fmri);
6724 			lcbdata->sc_err = EBUSY;
6725 			break;
6726 
6727 		case ENODEV:
6728 			if (scf_instance_get_name(imp_inst, imp_str,
6729 			    imp_str_sz) < 0)
6730 				(void) strcpy(imp_str, "?");
6731 			warn(i_deleted, s->sc_fmri, imp_str);
6732 			lcbdata->sc_err = EBUSY;
6733 			break;
6734 
6735 		default:
6736 			lcbdata->sc_err = r;
6737 		}
6738 
6739 		r = UU_WALK_ERROR;
6740 		goto deltemp;
6741 	}
6742 
6743 	s->sc_import_state = IMPORT_PROP_DONE;
6744 
6745 instances:
6746 	/* import instances */
6747 	cbdata.sc_handle = lcbdata->sc_handle;
6748 	cbdata.sc_parent = imp_svc;
6749 	cbdata.sc_service = 1;
6750 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
6751 	cbdata.sc_general = NULL;
6752 
6753 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
6754 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
6755 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6756 			bad_error("uu_list_walk", uu_error());
6757 
6758 		lcbdata->sc_err = cbdata.sc_err;
6759 		if (cbdata.sc_err == ECONNABORTED)
6760 			goto connaborted;
6761 		r = UU_WALK_ERROR;
6762 		goto deltemp;
6763 	}
6764 
6765 	s->sc_import_state = IMPORT_COMPLETE;
6766 	r = UU_WALK_NEXT;
6767 
6768 deltemp:
6769 	/* delete temporary service */
6770 	if (scf_service_delete(imp_tsvc) != 0) {
6771 		switch (scf_error()) {
6772 		case SCF_ERROR_DELETED:
6773 			break;
6774 
6775 		case SCF_ERROR_CONNECTION_BROKEN:
6776 			goto connaborted;
6777 
6778 		case SCF_ERROR_EXISTS:
6779 			warn(gettext(
6780 			    "Could not delete svc:/%s (instances exist).\n"),
6781 			    imp_tsname);
6782 			break;
6783 
6784 		case SCF_ERROR_NOT_SET:
6785 		case SCF_ERROR_NOT_BOUND:
6786 		default:
6787 			bad_error("scf_service_delete", scf_error());
6788 		}
6789 	}
6790 
6791 	return (r);
6792 
6793 connaborted:
6794 	warn(gettext("Could not delete svc:/%s "
6795 	    "(repository connection broken).\n"), imp_tsname);
6796 	lcbdata->sc_err = ECONNABORTED;
6797 	return (UU_WALK_ERROR);
6798 }
6799 
6800 static const char *
6801 import_progress(int st)
6802 {
6803 	switch (st) {
6804 	case 0:
6805 		return (gettext("not reached."));
6806 
6807 	case IMPORT_PREVIOUS:
6808 		return (gettext("previous snapshot taken."));
6809 
6810 	case IMPORT_PROP_BEGUN:
6811 		return (gettext("some properties imported."));
6812 
6813 	case IMPORT_PROP_DONE:
6814 		return (gettext("properties imported."));
6815 
6816 	case IMPORT_COMPLETE:
6817 		return (gettext("imported."));
6818 
6819 	case IMPORT_REFRESHED:
6820 		return (gettext("refresh requested."));
6821 
6822 	default:
6823 #ifndef NDEBUG
6824 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
6825 		    __FILE__, __LINE__, st);
6826 #endif
6827 		abort();
6828 		/* NOTREACHED */
6829 	}
6830 }
6831 
6832 /*
6833  * Returns
6834  *   0 - success
6835  *     - fmri wasn't found (error printed)
6836  *     - entity was deleted (error printed)
6837  *     - backend denied access (error printed)
6838  *   ENOMEM - out of memory (error printed)
6839  *   ECONNABORTED - repository connection broken (error printed)
6840  *   EPERM - permission denied (error printed)
6841  *   -1 - unknown libscf error (error printed)
6842  */
6843 static int
6844 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
6845 {
6846 	scf_error_t serr;
6847 	void *ent;
6848 	int issvc;
6849 	int r;
6850 
6851 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
6852 	const char *dpt_deleted = gettext("Could not refresh %s "
6853 	    "(dependent \"%s\" of %s) (deleted).\n");
6854 
6855 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
6856 	switch (serr) {
6857 	case SCF_ERROR_NONE:
6858 		break;
6859 
6860 	case SCF_ERROR_NO_MEMORY:
6861 		if (name == NULL)
6862 			warn(gettext("Could not refresh %s (out of memory).\n"),
6863 			    fmri);
6864 		else
6865 			warn(gettext("Could not refresh %s "
6866 			    "(dependent \"%s\" of %s) (out of memory).\n"),
6867 			    fmri, name, d_fmri);
6868 		return (ENOMEM);
6869 
6870 	case SCF_ERROR_NOT_FOUND:
6871 		if (name == NULL)
6872 			warn(deleted, fmri);
6873 		else
6874 			warn(dpt_deleted, fmri, name, d_fmri);
6875 		return (0);
6876 
6877 	case SCF_ERROR_INVALID_ARGUMENT:
6878 	case SCF_ERROR_CONSTRAINT_VIOLATED:
6879 	default:
6880 		bad_error("fmri_to_entity", serr);
6881 	}
6882 
6883 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
6884 	switch (r) {
6885 	case 0:
6886 		break;
6887 
6888 	case ECONNABORTED:
6889 		if (name != NULL)
6890 			warn(gettext("Could not refresh %s "
6891 			    "(dependent \"%s\" of %s) "
6892 			    "(repository connection broken).\n"), fmri, name,
6893 			    d_fmri);
6894 		return (r);
6895 
6896 	case ECANCELED:
6897 		if (name == NULL)
6898 			warn(deleted, fmri);
6899 		else
6900 			warn(dpt_deleted, fmri, name, d_fmri);
6901 		return (0);
6902 
6903 	case EACCES:
6904 		if (!g_verbose)
6905 			return (0);
6906 		if (name == NULL)
6907 			warn(gettext("Could not refresh %s "
6908 			    "(backend access denied).\n"), fmri);
6909 		else
6910 			warn(gettext("Could not refresh %s "
6911 			    "(dependent \"%s\" of %s) "
6912 			    "(backend access denied).\n"), fmri, name, d_fmri);
6913 		return (0);
6914 
6915 	case EPERM:
6916 		if (name == NULL)
6917 			warn(gettext("Could not refresh %s "
6918 			    "(permission denied).\n"), fmri);
6919 		else
6920 			warn(gettext("Could not refresh %s "
6921 			    "(dependent \"%s\" of %s) "
6922 			    "(permission denied).\n"), fmri, name, d_fmri);
6923 		return (r);
6924 
6925 	case ENOSPC:
6926 		if (name == NULL)
6927 			warn(gettext("Could not refresh %s "
6928 			    "(repository server out of resources).\n"),
6929 			    fmri);
6930 		else
6931 			warn(gettext("Could not refresh %s "
6932 			    "(dependent \"%s\" of %s) "
6933 			    "(repository server out of resources).\n"),
6934 			    fmri, name, d_fmri);
6935 		return (r);
6936 
6937 	case -1:
6938 		scfwarn();
6939 		return (r);
6940 
6941 	default:
6942 		bad_error("refresh_entity", r);
6943 	}
6944 
6945 	if (issvc)
6946 		scf_service_destroy(ent);
6947 	else
6948 		scf_instance_destroy(ent);
6949 
6950 	return (0);
6951 }
6952 
6953 int
6954 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
6955 {
6956 	scf_callback_t cbdata;
6957 	int result = 0;
6958 	entity_t *svc, *inst;
6959 	uu_list_t *insts;
6960 	int r;
6961 	pgroup_t *old_dpt;
6962 	void *cookie;
6963 	int annotation_set = 0;
6964 
6965 	const char * const emsg_nomem = gettext("Out of memory.\n");
6966 	const char * const emsg_nores =
6967 	    gettext("svc.configd is out of resources.\n");
6968 
6969 	lscf_prep_hndl();
6970 
6971 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
6972 	    max_scf_name_len : max_scf_fmri_len) + 1;
6973 
6974 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
6975 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
6976 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
6977 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
6978 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
6979 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
6980 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
6981 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
6982 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
6983 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
6984 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
6985 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
6986 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
6987 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
6988 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
6989 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
6990 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
6991 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
6992 	    (imp_str = malloc(imp_str_sz)) == NULL ||
6993 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
6994 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
6995 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
6996 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
6997 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
6998 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
6999 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7000 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7001 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7002 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7003 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7004 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7005 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7006 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7007 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7008 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7009 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7010 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7011 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7012 			warn(emsg_nores);
7013 		else
7014 			warn(emsg_nomem);
7015 		result = -1;
7016 		goto out;
7017 	}
7018 
7019 	r = load_init();
7020 	switch (r) {
7021 	case 0:
7022 		break;
7023 
7024 	case ENOMEM:
7025 		warn(emsg_nomem);
7026 		result = -1;
7027 		goto out;
7028 
7029 	default:
7030 		bad_error("load_init", r);
7031 	}
7032 
7033 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7034 		switch (scf_error()) {
7035 		case SCF_ERROR_CONNECTION_BROKEN:
7036 			warn(gettext("Repository connection broken.\n"));
7037 			repository_teardown();
7038 			result = -1;
7039 			goto out;
7040 
7041 		case SCF_ERROR_NOT_FOUND:
7042 		case SCF_ERROR_INVALID_ARGUMENT:
7043 		case SCF_ERROR_NOT_BOUND:
7044 		case SCF_ERROR_HANDLE_MISMATCH:
7045 		default:
7046 			bad_error("scf_handle_get_scope", scf_error());
7047 		}
7048 	}
7049 
7050 	/* Set up the auditing annotation. */
7051 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7052 		annotation_set = 1;
7053 	} else {
7054 		switch (scf_error()) {
7055 		case SCF_ERROR_CONNECTION_BROKEN:
7056 			warn(gettext("Repository connection broken.\n"));
7057 			repository_teardown();
7058 			result = -1;
7059 			goto out;
7060 
7061 		case SCF_ERROR_INVALID_ARGUMENT:
7062 		case SCF_ERROR_NOT_BOUND:
7063 		case SCF_ERROR_NO_RESOURCES:
7064 		case SCF_ERROR_INTERNAL:
7065 			bad_error("_scf_set_annotation", scf_error());
7066 			/* NOTREACHED */
7067 
7068 		default:
7069 			/*
7070 			 * Do not terminate import because of inability to
7071 			 * generate annotation audit event.
7072 			 */
7073 			warn(gettext("_scf_set_annotation() unexpectedly "
7074 			    "failed with return code of %d\n"), scf_error());
7075 			break;
7076 		}
7077 	}
7078 
7079 	/*
7080 	 * Clear the sc_import_state's of all services & instances so we can
7081 	 * report how far we got if we fail.
7082 	 */
7083 	for (svc = uu_list_first(bndl->sc_bundle_services);
7084 	    svc != NULL;
7085 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7086 		svc->sc_import_state = 0;
7087 
7088 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
7089 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
7090 		    UU_DEFAULT) != 0)
7091 			bad_error("uu_list_walk", uu_error());
7092 	}
7093 
7094 	cbdata.sc_handle = g_hndl;
7095 	cbdata.sc_parent = imp_scope;
7096 	cbdata.sc_flags = flags;
7097 	cbdata.sc_general = NULL;
7098 
7099 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
7100 	    &cbdata, UU_DEFAULT) == 0) {
7101 		/* Success.  Refresh everything. */
7102 
7103 		if (flags & SCI_NOREFRESH || no_refresh) {
7104 			result = 0;
7105 			goto out;
7106 		}
7107 
7108 		for (svc = uu_list_first(bndl->sc_bundle_services);
7109 		    svc != NULL;
7110 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7111 			pgroup_t *dpt;
7112 
7113 			insts = svc->sc_u.sc_service.sc_service_instances;
7114 
7115 			for (inst = uu_list_first(insts);
7116 			    inst != NULL;
7117 			    inst = uu_list_next(insts, inst)) {
7118 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
7119 				switch (r) {
7120 				case 0:
7121 					break;
7122 
7123 				case ENOMEM:
7124 				case ECONNABORTED:
7125 				case EPERM:
7126 				case -1:
7127 					goto progress;
7128 
7129 				default:
7130 					bad_error("imp_refresh_fmri", r);
7131 				}
7132 
7133 				inst->sc_import_state = IMPORT_REFRESHED;
7134 
7135 				for (dpt = uu_list_first(inst->sc_dependents);
7136 				    dpt != NULL;
7137 				    dpt = uu_list_next(inst->sc_dependents,
7138 				    dpt))
7139 					if (imp_refresh_fmri(
7140 					    dpt->sc_pgroup_fmri,
7141 					    dpt->sc_pgroup_name,
7142 					    inst->sc_fmri) != 0)
7143 						goto progress;
7144 			}
7145 
7146 			for (dpt = uu_list_first(svc->sc_dependents);
7147 			    dpt != NULL;
7148 			    dpt = uu_list_next(svc->sc_dependents, dpt))
7149 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
7150 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
7151 					goto progress;
7152 		}
7153 
7154 		for (old_dpt = uu_list_first(imp_deleted_dpts);
7155 		    old_dpt != NULL;
7156 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
7157 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
7158 			    old_dpt->sc_pgroup_name,
7159 			    old_dpt->sc_parent->sc_fmri) != 0)
7160 				goto progress;
7161 
7162 		result = 0;
7163 		goto out;
7164 	}
7165 
7166 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7167 		bad_error("uu_list_walk", uu_error());
7168 
7169 printerr:
7170 	/* If the error hasn't been printed yet, do so here. */
7171 	switch (cbdata.sc_err) {
7172 	case ECONNABORTED:
7173 		warn(gettext("Repository connection broken.\n"));
7174 		break;
7175 
7176 	case ENOMEM:
7177 		warn(emsg_nomem);
7178 		break;
7179 
7180 	case ENOSPC:
7181 		warn(emsg_nores);
7182 		break;
7183 
7184 	case EROFS:
7185 		warn(gettext("Repository is read-only.\n"));
7186 		break;
7187 
7188 	case EACCES:
7189 		warn(gettext("Repository backend denied access.\n"));
7190 		break;
7191 
7192 	case EPERM:
7193 	case EINVAL:
7194 	case EEXIST:
7195 	case EBUSY:
7196 	case EBADF:
7197 	case -1:
7198 		break;
7199 
7200 	default:
7201 		bad_error("lscf_service_import", cbdata.sc_err);
7202 	}
7203 
7204 progress:
7205 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
7206 
7207 	for (svc = uu_list_first(bndl->sc_bundle_services);
7208 	    svc != NULL;
7209 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7210 		insts = svc->sc_u.sc_service.sc_service_instances;
7211 
7212 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
7213 		    import_progress(svc->sc_import_state));
7214 
7215 		for (inst = uu_list_first(insts);
7216 		    inst != NULL;
7217 		    inst = uu_list_next(insts, inst))
7218 			warn(gettext("    Instance \"%s\": %s\n"),
7219 			    inst->sc_name,
7220 			    import_progress(inst->sc_import_state));
7221 	}
7222 
7223 	if (cbdata.sc_err == ECONNABORTED)
7224 		repository_teardown();
7225 
7226 
7227 	result = -1;
7228 
7229 out:
7230 	if (annotation_set != 0) {
7231 		/* Turn off annotation.  It is no longer needed. */
7232 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7233 	}
7234 	load_fini();
7235 
7236 	free(ud_ctarg);
7237 	free(ud_oldtarg);
7238 	free(ud_name);
7239 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7240 
7241 	scf_transaction_destroy(ud_tx);
7242 	ud_tx = NULL;
7243 	scf_iter_destroy(ud_iter);
7244 	scf_iter_destroy(ud_iter2);
7245 	ud_iter = ud_iter2 = NULL;
7246 	scf_value_destroy(ud_val);
7247 	ud_val = NULL;
7248 	scf_property_destroy(ud_prop);
7249 	scf_property_destroy(ud_dpt_prop);
7250 	ud_prop = ud_dpt_prop = NULL;
7251 	scf_pg_destroy(ud_pg);
7252 	scf_pg_destroy(ud_cur_depts_pg);
7253 	scf_pg_destroy(ud_run_dpts_pg);
7254 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7255 	scf_snaplevel_destroy(ud_snpl);
7256 	ud_snpl = NULL;
7257 	scf_instance_destroy(ud_inst);
7258 	ud_inst = NULL;
7259 
7260 	free(imp_str);
7261 	free(imp_tsname);
7262 	free(imp_fe1);
7263 	free(imp_fe2);
7264 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7265 
7266 	cookie = NULL;
7267 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7268 	    NULL) {
7269 		free((char *)old_dpt->sc_pgroup_name);
7270 		free((char *)old_dpt->sc_pgroup_fmri);
7271 		internal_pgroup_free(old_dpt);
7272 	}
7273 	uu_list_destroy(imp_deleted_dpts);
7274 
7275 	scf_transaction_destroy(imp_tx);
7276 	imp_tx = NULL;
7277 	scf_iter_destroy(imp_iter);
7278 	scf_iter_destroy(imp_rpg_iter);
7279 	scf_iter_destroy(imp_up_iter);
7280 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7281 	scf_property_destroy(imp_prop);
7282 	imp_prop = NULL;
7283 	scf_pg_destroy(imp_pg);
7284 	scf_pg_destroy(imp_pg2);
7285 	imp_pg = imp_pg2 = NULL;
7286 	scf_snaplevel_destroy(imp_snpl);
7287 	scf_snaplevel_destroy(imp_rsnpl);
7288 	imp_snpl = imp_rsnpl = NULL;
7289 	scf_snapshot_destroy(imp_snap);
7290 	scf_snapshot_destroy(imp_lisnap);
7291 	scf_snapshot_destroy(imp_tlisnap);
7292 	scf_snapshot_destroy(imp_rsnap);
7293 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7294 	scf_instance_destroy(imp_inst);
7295 	scf_instance_destroy(imp_tinst);
7296 	imp_inst = imp_tinst = NULL;
7297 	scf_service_destroy(imp_svc);
7298 	scf_service_destroy(imp_tsvc);
7299 	imp_svc = imp_tsvc = NULL;
7300 	scf_scope_destroy(imp_scope);
7301 	imp_scope = NULL;
7302 
7303 	return (result);
7304 }
7305 
7306 
7307 /*
7308  * Returns
7309  *   0 - success
7310  *   -1 - lscf_import_instance_pgs() failed.
7311  */
7312 int
7313 lscf_bundle_apply(bundle_t *bndl, const char *file)
7314 {
7315 	entity_t *svc, *inst;
7316 	scf_scope_t *rscope;
7317 	scf_service_t *rsvc;
7318 	scf_instance_t *rinst;
7319 	int annotation_set = 0;
7320 	int r;
7321 
7322 	lscf_prep_hndl();
7323 
7324 	if ((rscope = scf_scope_create(g_hndl)) == NULL ||
7325 	    (rsvc = scf_service_create(g_hndl)) == NULL ||
7326 	    (rinst = scf_instance_create(g_hndl)) == NULL ||
7327 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7328 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL)
7329 		scfdie();
7330 
7331 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0)
7332 		scfdie();
7333 
7334 	/*
7335 	 * Set the strings to be used for the security audit annotation
7336 	 * event.
7337 	 */
7338 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
7339 		annotation_set = 1;
7340 	} else {
7341 		switch (scf_error()) {
7342 		case SCF_ERROR_CONNECTION_BROKEN:
7343 			warn(gettext("Repository connection broken.\n"));
7344 			goto out;
7345 
7346 		case SCF_ERROR_INVALID_ARGUMENT:
7347 		case SCF_ERROR_NOT_BOUND:
7348 		case SCF_ERROR_NO_RESOURCES:
7349 		case SCF_ERROR_INTERNAL:
7350 			bad_error("_scf_set_annotation", scf_error());
7351 			/* NOTREACHED */
7352 
7353 		default:
7354 			/*
7355 			 * Do not abort apply operation because of
7356 			 * inability to create annotation audit event.
7357 			 */
7358 			warn(gettext("_scf_set_annotation() unexpectedly "
7359 			    "failed with return code of %d\n"), scf_error());
7360 			break;
7361 		}
7362 	}
7363 
7364 	for (svc = uu_list_first(bndl->sc_bundle_services);
7365 	    svc != NULL;
7366 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7367 		if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) {
7368 			switch (scf_error()) {
7369 			case SCF_ERROR_NOT_FOUND:
7370 				if (g_verbose)
7371 					warn(gettext("Ignoring nonexistent "
7372 					    "service %s.\n"), svc->sc_name);
7373 				continue;
7374 
7375 			default:
7376 				scfdie();
7377 			}
7378 		}
7379 
7380 		for (inst = uu_list_first(
7381 		    svc->sc_u.sc_service.sc_service_instances);
7382 		    inst != NULL;
7383 		    inst = uu_list_next(
7384 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
7385 			if (scf_service_get_instance(rsvc, inst->sc_name,
7386 			    rinst) != 0) {
7387 				switch (scf_error()) {
7388 				case SCF_ERROR_NOT_FOUND:
7389 					if (g_verbose)
7390 						warn(gettext("Ignoring "
7391 						    "nonexistant instance "
7392 						    "%s:%s.\n"),
7393 						    inst->sc_parent->sc_name,
7394 						    inst->sc_name);
7395 					continue;
7396 
7397 				default:
7398 					scfdie();
7399 				}
7400 			}
7401 
7402 			r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst,
7403 			    SCI_FORCE | SCI_KEEP);
7404 			switch (r) {
7405 			case 0:
7406 				if (g_verbose)
7407 					warn(gettext("%s updated.\n"),
7408 					    inst->sc_fmri);
7409 				break;
7410 
7411 			case ECONNABORTED:
7412 				warn(gettext("Could not update %s "
7413 				    "(repository connection broken).\n"),
7414 				    inst->sc_fmri);
7415 				goto out;
7416 
7417 			case ENOMEM:
7418 				warn(gettext("Could not update %s "
7419 				    "(out of memory).\n"), inst->sc_fmri);
7420 				goto out;
7421 
7422 			case ENOSPC:
7423 				warn(gettext("Could not update %s "
7424 				    "(repository server out of resources).\n"),
7425 				    inst->sc_fmri);
7426 				goto out;
7427 
7428 			case ECANCELED:
7429 				warn(gettext(
7430 				    "Could not update %s (deleted).\n"),
7431 				    inst->sc_fmri);
7432 				break;
7433 
7434 			case EPERM:
7435 			case EINVAL:
7436 			case EBUSY:
7437 				break;
7438 
7439 			case EROFS:
7440 				warn(gettext("Could not update %s "
7441 				    "(repository read-only).\n"),
7442 				    inst->sc_fmri);
7443 				goto out;
7444 
7445 			case EACCES:
7446 				warn(gettext("Could not update %s "
7447 				    "(backend access denied).\n"),
7448 				    inst->sc_fmri);
7449 				break;
7450 
7451 			case EEXIST:
7452 			default:
7453 				bad_error("lscf_import_instance_pgs", r);
7454 			}
7455 		}
7456 	}
7457 
7458 out:
7459 	if (annotation_set) {
7460 		/* Remove security audit annotation strings. */
7461 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7462 	}
7463 
7464 	scf_transaction_destroy(imp_tx);
7465 	imp_tx = NULL;
7466 	scf_pg_destroy(imp_pg);
7467 	imp_pg = NULL;
7468 
7469 	scf_instance_destroy(rinst);
7470 	scf_service_destroy(rsvc);
7471 	scf_scope_destroy(rscope);
7472 	return (0);
7473 }
7474 
7475 
7476 /*
7477  * Export.  These functions create and output an XML tree of a service
7478  * description from the repository.  This is largely the inverse of
7479  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
7480  *
7481  * - We must include any properties which are not represented specifically by
7482  *   a service manifest, e.g., properties created by an admin post-import.  To
7483  *   do so we'll iterate through all properties and deal with each
7484  *   apropriately.
7485  *
7486  * - Children of services and instances must must be in the order set by the
7487  *   DTD, but we iterate over the properties in undefined order.  The elements
7488  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
7489  *   number of classes of them, however, we'll keep the classes separate and
7490  *   assemble them in order.
7491  */
7492 
7493 /*
7494  * Convenience function to handle xmlSetProp errors (and type casting).
7495  */
7496 static void
7497 safe_setprop(xmlNodePtr n, const char *name, const char *val)
7498 {
7499 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
7500 		uu_die(gettext("Could not set XML property.\n"));
7501 }
7502 
7503 /*
7504  * Convenience function to set an XML attribute to the single value of an
7505  * astring property.  If the value happens to be the default, don't set the
7506  * attribute.  "dval" should be the default value supplied by the DTD, or
7507  * NULL for no default.
7508  */
7509 static int
7510 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
7511     const char *name, const char *dval)
7512 {
7513 	scf_value_t *val;
7514 	ssize_t len;
7515 	char *str;
7516 
7517 	val = scf_value_create(g_hndl);
7518 	if (val == NULL)
7519 		scfdie();
7520 
7521 	if (prop_get_val(prop, val) != 0) {
7522 		scf_value_destroy(val);
7523 		return (-1);
7524 	}
7525 
7526 	len = scf_value_get_as_string(val, NULL, 0);
7527 	if (len < 0)
7528 		scfdie();
7529 
7530 	str = safe_malloc(len + 1);
7531 
7532 	if (scf_value_get_as_string(val, str, len + 1) < 0)
7533 		scfdie();
7534 
7535 	scf_value_destroy(val);
7536 
7537 	if (dval == NULL || strcmp(str, dval) != 0)
7538 		safe_setprop(n, name, str);
7539 
7540 	free(str);
7541 
7542 	return (0);
7543 }
7544 
7545 /*
7546  * As above, but the attribute is always set.
7547  */
7548 static int
7549 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
7550 {
7551 	return (set_attr_from_prop_default(prop, n, name, NULL));
7552 }
7553 
7554 /*
7555  * Dump the given document onto f, with "'s replaced by ''s.
7556  */
7557 static int
7558 write_service_bundle(xmlDocPtr doc, FILE *f)
7559 {
7560 	xmlChar *mem;
7561 	int sz, i;
7562 
7563 	mem = NULL;
7564 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
7565 
7566 	if (mem == NULL) {
7567 		semerr(gettext("Could not dump XML tree.\n"));
7568 		return (-1);
7569 	}
7570 
7571 	/*
7572 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
7573 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
7574 	 * &apos; code?!
7575 	 */
7576 	for (i = 0; i < sz; ++i) {
7577 		char c = (char)mem[i];
7578 
7579 		if (c == '"')
7580 			(void) fputc('\'', f);
7581 		else if (c == '\'')
7582 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
7583 		else
7584 			(void) fputc(c, f);
7585 	}
7586 
7587 	return (0);
7588 }
7589 
7590 /*
7591  * Create the DOM elements in elts necessary to (generically) represent prop
7592  * (i.e., a property or propval element).  If the name of the property is
7593  * known, it should be passed as name_arg.  Otherwise, pass NULL.
7594  */
7595 static void
7596 export_property(scf_property_t *prop, const char *name_arg,
7597     struct pg_elts *elts, int flags)
7598 {
7599 	const char *type;
7600 	scf_error_t err = 0;
7601 	xmlNodePtr pnode, lnode;
7602 	char *lnname;
7603 	int ret;
7604 
7605 	/* name */
7606 	if (name_arg != NULL) {
7607 		(void) strcpy(exp_str, name_arg);
7608 	} else {
7609 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
7610 			scfdie();
7611 	}
7612 
7613 	/* type */
7614 	type = prop_to_typestr(prop);
7615 	if (type == NULL)
7616 		uu_die(gettext("Can't export property %s: unknown type.\n"),
7617 		    exp_str);
7618 
7619 	/* If we're exporting values, and there's just one, export it here. */
7620 	if (!(flags & SCE_ALL_VALUES))
7621 		goto empty;
7622 
7623 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
7624 		xmlNodePtr n;
7625 
7626 		/* Single value, so use propval */
7627 		n = xmlNewNode(NULL, (xmlChar *)"propval");
7628 		if (n == NULL)
7629 			uu_die(emsg_create_xml);
7630 
7631 		safe_setprop(n, name_attr, exp_str);
7632 		safe_setprop(n, type_attr, type);
7633 
7634 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
7635 			scfdie();
7636 		safe_setprop(n, value_attr, exp_str);
7637 
7638 		if (elts->propvals == NULL)
7639 			elts->propvals = n;
7640 		else
7641 			(void) xmlAddSibling(elts->propvals, n);
7642 
7643 		return;
7644 	}
7645 
7646 	err = scf_error();
7647 
7648 	if (err == SCF_ERROR_PERMISSION_DENIED) {
7649 		semerr(emsg_permission_denied);
7650 		return;
7651 	}
7652 
7653 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
7654 	    err != SCF_ERROR_NOT_FOUND &&
7655 	    err != SCF_ERROR_PERMISSION_DENIED)
7656 		scfdie();
7657 
7658 empty:
7659 	/* Multiple (or no) values, so use property */
7660 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
7661 	if (pnode == NULL)
7662 		uu_die(emsg_create_xml);
7663 
7664 	safe_setprop(pnode, name_attr, exp_str);
7665 	safe_setprop(pnode, type_attr, type);
7666 
7667 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
7668 		lnname = uu_msprintf("%s_list", type);
7669 		if (lnname == NULL)
7670 			uu_die(gettext("Could not create string"));
7671 
7672 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
7673 		if (lnode == NULL)
7674 			uu_die(emsg_create_xml);
7675 
7676 		uu_free(lnname);
7677 
7678 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
7679 			scfdie();
7680 
7681 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
7682 		    1) {
7683 			xmlNodePtr vn;
7684 
7685 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
7686 			    NULL);
7687 			if (vn == NULL)
7688 				uu_die(emsg_create_xml);
7689 
7690 			if (scf_value_get_as_string(exp_val, exp_str,
7691 			    exp_str_sz) < 0)
7692 				scfdie();
7693 			safe_setprop(vn, value_attr, exp_str);
7694 		}
7695 		if (ret != 0)
7696 			scfdie();
7697 	}
7698 
7699 	if (elts->properties == NULL)
7700 		elts->properties = pnode;
7701 	else
7702 		(void) xmlAddSibling(elts->properties, pnode);
7703 }
7704 
7705 /*
7706  * Add a property_group element for this property group to elts.
7707  */
7708 static void
7709 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
7710 {
7711 	xmlNodePtr n;
7712 	struct pg_elts elts;
7713 	int ret;
7714 	boolean_t read_protected;
7715 
7716 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
7717 
7718 	/* name */
7719 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
7720 		scfdie();
7721 	safe_setprop(n, name_attr, exp_str);
7722 
7723 	/* type */
7724 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
7725 		scfdie();
7726 	safe_setprop(n, type_attr, exp_str);
7727 
7728 	/* properties */
7729 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
7730 		scfdie();
7731 
7732 	(void) memset(&elts, 0, sizeof (elts));
7733 
7734 	/*
7735 	 * If this property group is not read protected, we always want to
7736 	 * output all the values.  Otherwise, we only output the values if the
7737 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
7738 	 */
7739 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
7740 		scfdie();
7741 
7742 	if (!read_protected)
7743 		flags |= SCE_ALL_VALUES;
7744 
7745 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
7746 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
7747 			scfdie();
7748 
7749 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
7750 			xmlNodePtr m;
7751 
7752 			m = xmlNewNode(NULL, (xmlChar *)"stability");
7753 			if (m == NULL)
7754 				uu_die(emsg_create_xml);
7755 
7756 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
7757 				elts.stability = m;
7758 				continue;
7759 			}
7760 
7761 			xmlFreeNode(m);
7762 		}
7763 
7764 		export_property(exp_prop, NULL, &elts, flags);
7765 	}
7766 	if (ret == -1)
7767 		scfdie();
7768 
7769 	(void) xmlAddChild(n, elts.stability);
7770 	(void) xmlAddChildList(n, elts.propvals);
7771 	(void) xmlAddChildList(n, elts.properties);
7772 
7773 	if (eelts->property_groups == NULL)
7774 		eelts->property_groups = n;
7775 	else
7776 		(void) xmlAddSibling(eelts->property_groups, n);
7777 }
7778 
7779 /*
7780  * Create an XML node representing the dependency described by the given
7781  * property group and put it in eelts.  Unless the dependency is not valid, in
7782  * which case create a generic property_group element which represents it and
7783  * put it in eelts.
7784  */
7785 static void
7786 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
7787 {
7788 	xmlNodePtr n;
7789 	int err = 0, ret;
7790 	struct pg_elts elts;
7791 
7792 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
7793 	if (n == NULL)
7794 		uu_die(emsg_create_xml);
7795 
7796 	/*
7797 	 * If the external flag is present, skip this dependency because it
7798 	 * should have been created by another manifest.
7799 	 */
7800 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
7801 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
7802 		    prop_get_val(exp_prop, exp_val) == 0) {
7803 			uint8_t b;
7804 
7805 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
7806 				scfdie();
7807 
7808 			if (b)
7809 				return;
7810 		}
7811 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
7812 		scfdie();
7813 
7814 	/* Get the required attributes. */
7815 
7816 	/* name */
7817 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
7818 		scfdie();
7819 	safe_setprop(n, name_attr, exp_str);
7820 
7821 	/* grouping */
7822 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
7823 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
7824 		err = 1;
7825 
7826 	/* restart_on */
7827 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
7828 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
7829 		err = 1;
7830 
7831 	/* type */
7832 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
7833 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
7834 		err = 1;
7835 
7836 	/*
7837 	 * entities: Not required, but if we create no children, it will be
7838 	 * created as empty on import, so fail if it's missing.
7839 	 */
7840 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
7841 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
7842 		scf_iter_t *eiter;
7843 		int ret2;
7844 
7845 		eiter = scf_iter_create(g_hndl);
7846 		if (eiter == NULL)
7847 			scfdie();
7848 
7849 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
7850 			scfdie();
7851 
7852 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
7853 			xmlNodePtr ch;
7854 
7855 			if (scf_value_get_astring(exp_val, exp_str,
7856 			    exp_str_sz) < 0)
7857 				scfdie();
7858 
7859 			/*
7860 			 * service_fmri's must be first, so we can add them
7861 			 * here.
7862 			 */
7863 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
7864 			    NULL);
7865 			if (ch == NULL)
7866 				uu_die(emsg_create_xml);
7867 
7868 			safe_setprop(ch, value_attr, exp_str);
7869 		}
7870 		if (ret2 == -1)
7871 			scfdie();
7872 
7873 		scf_iter_destroy(eiter);
7874 	} else
7875 		err = 1;
7876 
7877 	if (err) {
7878 		xmlFreeNode(n);
7879 
7880 		export_pg(pg, eelts, 0);
7881 
7882 		return;
7883 	}
7884 
7885 	/* Iterate through the properties & handle each. */
7886 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
7887 		scfdie();
7888 
7889 	(void) memset(&elts, 0, sizeof (elts));
7890 
7891 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
7892 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
7893 			scfdie();
7894 
7895 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
7896 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
7897 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
7898 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
7899 			continue;
7900 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
7901 			xmlNodePtr m;
7902 
7903 			m = xmlNewNode(NULL, (xmlChar *)"stability");
7904 			if (m == NULL)
7905 				uu_die(emsg_create_xml);
7906 
7907 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
7908 				elts.stability = m;
7909 				continue;
7910 			}
7911 
7912 			xmlFreeNode(m);
7913 		}
7914 
7915 		export_property(exp_prop, exp_str, &elts, 0);
7916 	}
7917 	if (ret == -1)
7918 		scfdie();
7919 
7920 	(void) xmlAddChild(n, elts.stability);
7921 	(void) xmlAddChildList(n, elts.propvals);
7922 	(void) xmlAddChildList(n, elts.properties);
7923 
7924 	if (eelts->dependencies == NULL)
7925 		eelts->dependencies = n;
7926 	else
7927 		(void) xmlAddSibling(eelts->dependencies, n);
7928 }
7929 
7930 static xmlNodePtr
7931 export_method_environment(scf_propertygroup_t *pg)
7932 {
7933 	xmlNodePtr env;
7934 	int ret;
7935 	int children = 0;
7936 
7937 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
7938 		return (NULL);
7939 
7940 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
7941 	if (env == NULL)
7942 		uu_die(emsg_create_xml);
7943 
7944 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
7945 		scfdie();
7946 
7947 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
7948 		scfdie();
7949 
7950 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
7951 		xmlNodePtr ev;
7952 		char *cp;
7953 
7954 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
7955 			scfdie();
7956 
7957 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
7958 			warn(gettext("Invalid environment variable \"%s\".\n"),
7959 			    exp_str);
7960 			continue;
7961 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
7962 			warn(gettext("Invalid environment variable \"%s\"; "
7963 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
7964 			continue;
7965 		}
7966 
7967 		*cp = '\0';
7968 		cp++;
7969 
7970 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
7971 		if (ev == NULL)
7972 			uu_die(emsg_create_xml);
7973 
7974 		safe_setprop(ev, name_attr, exp_str);
7975 		safe_setprop(ev, value_attr, cp);
7976 		children++;
7977 	}
7978 
7979 	if (ret != 0)
7980 		scfdie();
7981 
7982 	if (children == 0) {
7983 		xmlFreeNode(env);
7984 		return (NULL);
7985 	}
7986 
7987 	return (env);
7988 }
7989 
7990 /*
7991  * As above, but for a method property group.
7992  */
7993 static void
7994 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
7995 {
7996 	xmlNodePtr n, env;
7997 	char *str;
7998 	int err = 0, nonenv, ret;
7999 	uint8_t use_profile;
8000 	struct pg_elts elts;
8001 	xmlNodePtr ctxt = NULL;
8002 
8003 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
8004 
8005 	/* Get the required attributes. */
8006 
8007 	/* name */
8008 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8009 		scfdie();
8010 	safe_setprop(n, name_attr, exp_str);
8011 
8012 	/* type */
8013 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8014 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8015 		err = 1;
8016 
8017 	/* exec */
8018 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
8019 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
8020 		err = 1;
8021 
8022 	/* timeout */
8023 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
8024 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
8025 	    prop_get_val(exp_prop, exp_val) == 0) {
8026 		uint64_t c;
8027 
8028 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
8029 			scfdie();
8030 
8031 		str = uu_msprintf("%llu", c);
8032 		if (str == NULL)
8033 			uu_die(gettext("Could not create string"));
8034 
8035 		safe_setprop(n, "timeout_seconds", str);
8036 		free(str);
8037 	} else
8038 		err = 1;
8039 
8040 	if (err) {
8041 		xmlFreeNode(n);
8042 
8043 		export_pg(pg, eelts, 0);
8044 
8045 		return;
8046 	}
8047 
8048 
8049 	/*
8050 	 * If we're going to have a method_context child, we need to know
8051 	 * before we iterate through the properties.  Since method_context's
8052 	 * are optional, we don't want to complain about any properties
8053 	 * missing if none of them are there.  Thus we can't use the
8054 	 * convenience functions.
8055 	 */
8056 	nonenv =
8057 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
8058 	    SCF_SUCCESS ||
8059 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
8060 	    SCF_SUCCESS ||
8061 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
8062 	    SCF_SUCCESS ||
8063 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
8064 	    SCF_SUCCESS;
8065 
8066 	if (nonenv) {
8067 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8068 		if (ctxt == NULL)
8069 			uu_die(emsg_create_xml);
8070 
8071 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
8072 		    0 &&
8073 		    set_attr_from_prop_default(exp_prop, ctxt,
8074 		    "working_directory", ":default") != 0)
8075 			err = 1;
8076 
8077 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
8078 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
8079 		    ":default") != 0)
8080 			err = 1;
8081 
8082 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
8083 		    0 &&
8084 		    set_attr_from_prop_default(exp_prop, ctxt,
8085 		    "resource_pool", ":default") != 0)
8086 			err = 1;
8087 		/*
8088 		 * We only want to complain about profile or credential
8089 		 * properties if we will use them.  To determine that we must
8090 		 * examine USE_PROFILE.
8091 		 */
8092 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8093 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8094 		    prop_get_val(exp_prop, exp_val) == 0) {
8095 			if (scf_value_get_boolean(exp_val, &use_profile) !=
8096 			    SCF_SUCCESS) {
8097 				scfdie();
8098 			}
8099 
8100 			if (use_profile) {
8101 				xmlNodePtr prof;
8102 
8103 				prof = xmlNewChild(ctxt, NULL,
8104 				    (xmlChar *)"method_profile", NULL);
8105 				if (prof == NULL)
8106 					uu_die(emsg_create_xml);
8107 
8108 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
8109 				    exp_prop) != 0 ||
8110 				    set_attr_from_prop(exp_prop, prof,
8111 				    name_attr) != 0)
8112 					err = 1;
8113 			} else {
8114 				xmlNodePtr cred;
8115 
8116 				cred = xmlNewChild(ctxt, NULL,
8117 				    (xmlChar *)"method_credential", NULL);
8118 				if (cred == NULL)
8119 					uu_die(emsg_create_xml);
8120 
8121 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
8122 				    exp_prop) != 0 ||
8123 				    set_attr_from_prop(exp_prop, cred,
8124 				    "user") != 0) {
8125 					err = 1;
8126 				}
8127 
8128 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
8129 				    exp_prop) == 0 &&
8130 				    set_attr_from_prop_default(exp_prop, cred,
8131 				    "group", ":default") != 0)
8132 					err = 1;
8133 
8134 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
8135 				    exp_prop) == 0 &&
8136 				    set_attr_from_prop_default(exp_prop, cred,
8137 				    "supp_groups", ":default") != 0)
8138 					err = 1;
8139 
8140 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
8141 				    exp_prop) == 0 &&
8142 				    set_attr_from_prop_default(exp_prop, cred,
8143 				    "privileges", ":default") != 0)
8144 					err = 1;
8145 
8146 				if (pg_get_prop(pg,
8147 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
8148 				    exp_prop) == 0 &&
8149 				    set_attr_from_prop_default(exp_prop, cred,
8150 				    "limit_privileges", ":default") != 0)
8151 					err = 1;
8152 			}
8153 		}
8154 	}
8155 
8156 	if ((env = export_method_environment(pg)) != NULL) {
8157 		if (ctxt == NULL) {
8158 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8159 			if (ctxt == NULL)
8160 				uu_die(emsg_create_xml);
8161 		}
8162 		(void) xmlAddChild(ctxt, env);
8163 	}
8164 
8165 	if (env != NULL || (nonenv && err == 0))
8166 		(void) xmlAddChild(n, ctxt);
8167 	else
8168 		xmlFreeNode(ctxt);
8169 
8170 	nonenv = (err == 0);
8171 
8172 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8173 		scfdie();
8174 
8175 	(void) memset(&elts, 0, sizeof (elts));
8176 
8177 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8178 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8179 			scfdie();
8180 
8181 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8182 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
8183 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
8184 			continue;
8185 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8186 			xmlNodePtr m;
8187 
8188 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8189 			if (m == NULL)
8190 				uu_die(emsg_create_xml);
8191 
8192 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8193 				elts.stability = m;
8194 				continue;
8195 			}
8196 
8197 			xmlFreeNode(m);
8198 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
8199 		    0 ||
8200 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
8201 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
8202 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8203 			if (nonenv)
8204 				continue;
8205 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
8206 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
8207 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
8208 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
8209 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
8210 			if (nonenv && !use_profile)
8211 				continue;
8212 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8213 			if (nonenv && use_profile)
8214 				continue;
8215 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
8216 			if (env != NULL)
8217 				continue;
8218 		}
8219 
8220 		export_property(exp_prop, exp_str, &elts, 0);
8221 	}
8222 	if (ret == -1)
8223 		scfdie();
8224 
8225 	(void) xmlAddChild(n, elts.stability);
8226 	(void) xmlAddChildList(n, elts.propvals);
8227 	(void) xmlAddChildList(n, elts.properties);
8228 
8229 	if (eelts->exec_methods == NULL)
8230 		eelts->exec_methods = n;
8231 	else
8232 		(void) xmlAddSibling(eelts->exec_methods, n);
8233 }
8234 
8235 static void
8236 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
8237     struct entity_elts *eelts)
8238 {
8239 	xmlNodePtr pgnode;
8240 
8241 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
8242 	if (pgnode == NULL)
8243 		uu_die(emsg_create_xml);
8244 
8245 	safe_setprop(pgnode, name_attr, name);
8246 	safe_setprop(pgnode, type_attr, type);
8247 
8248 	(void) xmlAddChildList(pgnode, elts->propvals);
8249 	(void) xmlAddChildList(pgnode, elts->properties);
8250 
8251 	if (eelts->property_groups == NULL)
8252 		eelts->property_groups = pgnode;
8253 	else
8254 		(void) xmlAddSibling(eelts->property_groups, pgnode);
8255 }
8256 
8257 /*
8258  * Process the general property group for a service.  This is the one with the
8259  * goodies.
8260  */
8261 static void
8262 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
8263 {
8264 	struct pg_elts elts;
8265 	int ret;
8266 
8267 	/*
8268 	 * In case there are properties which don't correspond to child
8269 	 * entities of the service entity, we'll set up a pg_elts structure to
8270 	 * put them in.
8271 	 */
8272 	(void) memset(&elts, 0, sizeof (elts));
8273 
8274 	/* Walk the properties, looking for special ones. */
8275 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8276 		scfdie();
8277 
8278 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8279 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8280 			scfdie();
8281 
8282 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
8283 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8284 			    prop_get_val(exp_prop, exp_val) == 0) {
8285 				uint8_t b;
8286 
8287 				if (scf_value_get_boolean(exp_val, &b) !=
8288 				    SCF_SUCCESS)
8289 					scfdie();
8290 
8291 				if (b) {
8292 					selts->single_instance =
8293 					    xmlNewNode(NULL,
8294 					    (xmlChar *)"single_instance");
8295 					if (selts->single_instance == NULL)
8296 						uu_die(emsg_create_xml);
8297 				}
8298 
8299 				continue;
8300 			}
8301 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8302 			xmlNodePtr rnode, sfnode;
8303 
8304 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8305 			if (rnode == NULL)
8306 				uu_die(emsg_create_xml);
8307 
8308 			sfnode = xmlNewChild(rnode, NULL,
8309 			    (xmlChar *)"service_fmri", NULL);
8310 			if (sfnode == NULL)
8311 				uu_die(emsg_create_xml);
8312 
8313 			if (set_attr_from_prop(exp_prop, sfnode,
8314 			    value_attr) == 0) {
8315 				selts->restarter = rnode;
8316 				continue;
8317 			}
8318 
8319 			xmlFreeNode(rnode);
8320 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
8321 		    0) {
8322 			xmlNodePtr s;
8323 
8324 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8325 			if (s == NULL)
8326 				uu_die(emsg_create_xml);
8327 
8328 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8329 				selts->stability = s;
8330 				continue;
8331 			}
8332 
8333 			xmlFreeNode(s);
8334 		}
8335 
8336 		export_property(exp_prop, exp_str, &elts, 0);
8337 	}
8338 	if (ret == -1)
8339 		scfdie();
8340 
8341 	if (elts.propvals != NULL || elts.properties != NULL)
8342 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
8343 		    selts);
8344 }
8345 
8346 static void
8347 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
8348 {
8349 	xmlNodePtr n, prof, cred, env;
8350 	uint8_t use_profile;
8351 	int ret, err = 0;
8352 
8353 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
8354 
8355 	env = export_method_environment(pg);
8356 
8357 	/* Need to know whether we'll use a profile or not. */
8358 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8359 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8360 	    prop_get_val(exp_prop, exp_val) == 0) {
8361 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
8362 			scfdie();
8363 
8364 		if (use_profile)
8365 			prof =
8366 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
8367 			    NULL);
8368 		else
8369 			cred =
8370 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
8371 			    NULL);
8372 	}
8373 
8374 	if (env != NULL)
8375 		(void) xmlAddChild(n, env);
8376 
8377 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8378 		scfdie();
8379 
8380 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8381 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8382 			scfdie();
8383 
8384 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
8385 			if (set_attr_from_prop(exp_prop, n,
8386 			    "working_directory") != 0)
8387 				err = 1;
8388 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
8389 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
8390 				err = 1;
8391 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
8392 			if (set_attr_from_prop(exp_prop, n,
8393 			    "resource_pool") != 0)
8394 				err = 1;
8395 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8396 			/* EMPTY */
8397 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
8398 			if (use_profile ||
8399 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
8400 				err = 1;
8401 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
8402 			if (use_profile ||
8403 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
8404 				err = 1;
8405 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
8406 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8407 			    "supp_groups") != 0)
8408 				err = 1;
8409 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
8410 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8411 			    "privileges") != 0)
8412 				err = 1;
8413 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
8414 		    0) {
8415 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8416 			    "limit_privileges") != 0)
8417 				err = 1;
8418 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8419 			if (!use_profile || set_attr_from_prop(exp_prop,
8420 			    prof, name_attr) != 0)
8421 				err = 1;
8422 		} else {
8423 			/* Can't have generic properties in method_context's */
8424 			err = 1;
8425 		}
8426 	}
8427 	if (ret == -1)
8428 		scfdie();
8429 
8430 	if (err && env == NULL) {
8431 		xmlFreeNode(n);
8432 		export_pg(pg, elts, 0);
8433 		return;
8434 	}
8435 
8436 	elts->method_context = n;
8437 }
8438 
8439 /*
8440  * Given a dependency property group in the tfmri entity (target fmri), return
8441  * a dependent element which represents it.
8442  */
8443 static xmlNodePtr
8444 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
8445 {
8446 	uint8_t b;
8447 	xmlNodePtr n, sf;
8448 	int err = 0, ret;
8449 	struct pg_elts pgelts;
8450 
8451 	/*
8452 	 * If external isn't set to true then exporting the service will
8453 	 * export this as a normal dependency, so we should stop to avoid
8454 	 * duplication.
8455 	 */
8456 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
8457 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
8458 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
8459 		if (g_verbose) {
8460 			warn(gettext("Dependent \"%s\" cannot be exported "
8461 			    "properly because the \"%s\" property of the "
8462 			    "\"%s\" dependency of %s is not set to true.\n"),
8463 			    name, scf_property_external, name, tfmri);
8464 		}
8465 
8466 		return (NULL);
8467 	}
8468 
8469 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
8470 	if (n == NULL)
8471 		uu_die(emsg_create_xml);
8472 
8473 	safe_setprop(n, name_attr, name);
8474 
8475 	/* Get the required attributes */
8476 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8477 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8478 		err = 1;
8479 
8480 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8481 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8482 		err = 1;
8483 
8484 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8485 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
8486 	    prop_get_val(exp_prop, exp_val) == 0) {
8487 		/* EMPTY */
8488 	} else
8489 		err = 1;
8490 
8491 	if (err) {
8492 		xmlFreeNode(n);
8493 		return (NULL);
8494 	}
8495 
8496 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
8497 	if (sf == NULL)
8498 		uu_die(emsg_create_xml);
8499 
8500 	safe_setprop(sf, value_attr, tfmri);
8501 
8502 	/*
8503 	 * Now add elements for the other properties.
8504 	 */
8505 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8506 		scfdie();
8507 
8508 	(void) memset(&pgelts, 0, sizeof (pgelts));
8509 
8510 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8511 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8512 			scfdie();
8513 
8514 		if (strcmp(exp_str, scf_property_external) == 0 ||
8515 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8516 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8517 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8518 			continue;
8519 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
8520 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
8521 			    prop_get_val(exp_prop, exp_val) == 0) {
8522 				char type[sizeof ("service") + 1];
8523 
8524 				if (scf_value_get_astring(exp_val, type,
8525 				    sizeof (type)) < 0)
8526 					scfdie();
8527 
8528 				if (strcmp(type, "service") == 0)
8529 					continue;
8530 			}
8531 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8532 			xmlNodePtr s;
8533 
8534 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8535 			if (s == NULL)
8536 				uu_die(emsg_create_xml);
8537 
8538 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8539 				pgelts.stability = s;
8540 				continue;
8541 			}
8542 
8543 			xmlFreeNode(s);
8544 		}
8545 
8546 		export_property(exp_prop, exp_str, &pgelts, 0);
8547 	}
8548 	if (ret == -1)
8549 		scfdie();
8550 
8551 	(void) xmlAddChild(n, pgelts.stability);
8552 	(void) xmlAddChildList(n, pgelts.propvals);
8553 	(void) xmlAddChildList(n, pgelts.properties);
8554 
8555 	return (n);
8556 }
8557 
8558 static void
8559 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
8560 {
8561 	scf_propertygroup_t *opg;
8562 	scf_iter_t *iter;
8563 	char *type, *fmri;
8564 	int ret;
8565 	struct pg_elts pgelts;
8566 	xmlNodePtr n;
8567 	scf_error_t serr;
8568 
8569 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
8570 	    (iter = scf_iter_create(g_hndl)) == NULL)
8571 		scfdie();
8572 
8573 	/* Can't use exp_prop_iter due to export_dependent(). */
8574 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
8575 		scfdie();
8576 
8577 	type = safe_malloc(max_scf_pg_type_len + 1);
8578 
8579 	/* Get an extra byte so we can tell if values are too long. */
8580 	fmri = safe_malloc(max_scf_fmri_len + 2);
8581 
8582 	(void) memset(&pgelts, 0, sizeof (pgelts));
8583 
8584 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
8585 		void *entity;
8586 		int isservice;
8587 		scf_type_t ty;
8588 
8589 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
8590 			scfdie();
8591 
8592 		if ((ty != SCF_TYPE_ASTRING &&
8593 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
8594 		    prop_get_val(exp_prop, exp_val) != 0) {
8595 			export_property(exp_prop, NULL, &pgelts, 0);
8596 			continue;
8597 		}
8598 
8599 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8600 			scfdie();
8601 
8602 		if (scf_value_get_astring(exp_val, fmri,
8603 		    max_scf_fmri_len + 2) < 0)
8604 			scfdie();
8605 
8606 		/* Look for a dependency group in the target fmri. */
8607 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
8608 		switch (serr) {
8609 		case SCF_ERROR_NONE:
8610 			break;
8611 
8612 		case SCF_ERROR_NO_MEMORY:
8613 			uu_die(gettext("Out of memory.\n"));
8614 			/* NOTREACHED */
8615 
8616 		case SCF_ERROR_INVALID_ARGUMENT:
8617 			if (g_verbose) {
8618 				if (scf_property_to_fmri(exp_prop, fmri,
8619 				    max_scf_fmri_len + 2) < 0)
8620 					scfdie();
8621 
8622 				warn(gettext("The value of %s is not a valid "
8623 				    "FMRI.\n"), fmri);
8624 			}
8625 
8626 			export_property(exp_prop, exp_str, &pgelts, 0);
8627 			continue;
8628 
8629 		case SCF_ERROR_CONSTRAINT_VIOLATED:
8630 			if (g_verbose) {
8631 				if (scf_property_to_fmri(exp_prop, fmri,
8632 				    max_scf_fmri_len + 2) < 0)
8633 					scfdie();
8634 
8635 				warn(gettext("The value of %s does not specify "
8636 				    "a service or an instance.\n"), fmri);
8637 			}
8638 
8639 			export_property(exp_prop, exp_str, &pgelts, 0);
8640 			continue;
8641 
8642 		case SCF_ERROR_NOT_FOUND:
8643 			if (g_verbose) {
8644 				if (scf_property_to_fmri(exp_prop, fmri,
8645 				    max_scf_fmri_len + 2) < 0)
8646 					scfdie();
8647 
8648 				warn(gettext("The entity specified by %s does "
8649 				    "not exist.\n"), fmri);
8650 			}
8651 
8652 			export_property(exp_prop, exp_str, &pgelts, 0);
8653 			continue;
8654 
8655 		default:
8656 #ifndef NDEBUG
8657 			(void) fprintf(stderr, "%s:%d: %s() failed with "
8658 			    "unexpected error %d.\n", __FILE__, __LINE__,
8659 			    "fmri_to_entity", serr);
8660 #endif
8661 			abort();
8662 		}
8663 
8664 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
8665 			if (scf_error() != SCF_ERROR_NOT_FOUND)
8666 				scfdie();
8667 
8668 			warn(gettext("Entity %s is missing dependency property "
8669 			    "group %s.\n"), fmri, exp_str);
8670 
8671 			export_property(exp_prop, NULL, &pgelts, 0);
8672 			continue;
8673 		}
8674 
8675 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
8676 			scfdie();
8677 
8678 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
8679 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
8680 				scfdie();
8681 
8682 			warn(gettext("Property group %s is not of "
8683 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
8684 
8685 			export_property(exp_prop, NULL, &pgelts, 0);
8686 			continue;
8687 		}
8688 
8689 		n = export_dependent(opg, exp_str, fmri);
8690 		if (n == NULL)
8691 			export_property(exp_prop, exp_str, &pgelts, 0);
8692 		else {
8693 			if (eelts->dependents == NULL)
8694 				eelts->dependents = n;
8695 			else
8696 				(void) xmlAddSibling(eelts->dependents,
8697 				    n);
8698 		}
8699 	}
8700 	if (ret == -1)
8701 		scfdie();
8702 
8703 	free(fmri);
8704 	free(type);
8705 
8706 	scf_iter_destroy(iter);
8707 	scf_pg_destroy(opg);
8708 
8709 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
8710 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
8711 		    eelts);
8712 }
8713 
8714 static void
8715 make_node(xmlNodePtr *nodep, const char *name)
8716 {
8717 	if (*nodep == NULL) {
8718 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
8719 		if (*nodep == NULL)
8720 			uu_die(emsg_create_xml);
8721 	}
8722 }
8723 
8724 static xmlNodePtr
8725 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
8726 {
8727 	int ret;
8728 	xmlNodePtr parent = NULL;
8729 	xmlNodePtr loctext = NULL;
8730 
8731 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8732 		scfdie();
8733 
8734 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8735 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
8736 		    prop_get_val(exp_prop, exp_val) != 0)
8737 			continue;
8738 
8739 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
8740 			scfdie();
8741 
8742 		make_node(&parent, parname);
8743 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
8744 		    (xmlChar *)exp_str);
8745 		if (loctext == NULL)
8746 			uu_die(emsg_create_xml);
8747 
8748 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8749 			scfdie();
8750 
8751 		safe_setprop(loctext, "xml:lang", exp_str);
8752 	}
8753 
8754 	if (ret == -1)
8755 		scfdie();
8756 
8757 	return (parent);
8758 }
8759 
8760 static xmlNodePtr
8761 export_tm_manpage(scf_propertygroup_t *pg)
8762 {
8763 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
8764 	if (manpage == NULL)
8765 		uu_die(emsg_create_xml);
8766 
8767 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
8768 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
8769 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
8770 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
8771 		xmlFreeNode(manpage);
8772 		return (NULL);
8773 	}
8774 
8775 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
8776 		(void) set_attr_from_prop_default(exp_prop,
8777 		    manpage, "manpath", ":default");
8778 
8779 	return (manpage);
8780 }
8781 
8782 static xmlNodePtr
8783 export_tm_doc_link(scf_propertygroup_t *pg)
8784 {
8785 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
8786 	if (doc_link == NULL)
8787 		uu_die(emsg_create_xml);
8788 
8789 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
8790 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
8791 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
8792 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
8793 		xmlFreeNode(doc_link);
8794 		return (NULL);
8795 	}
8796 	return (doc_link);
8797 }
8798 
8799 /*
8800  * Process template information for a service or instances.
8801  */
8802 static void
8803 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
8804     struct template_elts *telts)
8805 {
8806 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
8807 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
8808 	xmlNodePtr child = NULL;
8809 
8810 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
8811 		scfdie();
8812 
8813 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
8814 		telts->common_name = export_tm_loctext(pg, "common_name");
8815 		if (telts->common_name == NULL)
8816 			export_pg(pg, elts, 0);
8817 		return;
8818 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
8819 		telts->description = export_tm_loctext(pg, "description");
8820 		if (telts->description == NULL)
8821 			export_pg(pg, elts, 0);
8822 		return;
8823 	}
8824 
8825 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
8826 		child = export_tm_manpage(pg);
8827 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
8828 		child = export_tm_doc_link(pg);
8829 	}
8830 
8831 	if (child != NULL) {
8832 		make_node(&telts->documentation, "documentation");
8833 		(void) xmlAddChild(telts->documentation, child);
8834 	} else {
8835 		export_pg(pg, elts, 0);
8836 	}
8837 }
8838 
8839 /*
8840  * Process the general property group for an instance.
8841  */
8842 static void
8843 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
8844     struct entity_elts *elts)
8845 {
8846 	uint8_t enabled;
8847 	struct pg_elts pgelts;
8848 	int ret;
8849 
8850 	/* enabled */
8851 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
8852 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8853 	    prop_get_val(exp_prop, exp_val) == 0) {
8854 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
8855 			scfdie();
8856 	} else {
8857 		enabled = 0;
8858 	}
8859 
8860 	safe_setprop(inode, enabled_attr, enabled ? true : false);
8861 
8862 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8863 		scfdie();
8864 
8865 	(void) memset(&pgelts, 0, sizeof (pgelts));
8866 
8867 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8868 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8869 			scfdie();
8870 
8871 		if (strcmp(exp_str, scf_property_enabled) == 0) {
8872 			continue;
8873 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8874 			xmlNodePtr rnode, sfnode;
8875 
8876 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8877 			if (rnode == NULL)
8878 				uu_die(emsg_create_xml);
8879 
8880 			sfnode = xmlNewChild(rnode, NULL,
8881 			    (xmlChar *)"service_fmri", NULL);
8882 			if (sfnode == NULL)
8883 				uu_die(emsg_create_xml);
8884 
8885 			if (set_attr_from_prop(exp_prop, sfnode,
8886 			    value_attr) == 0) {
8887 				elts->restarter = rnode;
8888 				continue;
8889 			}
8890 
8891 			xmlFreeNode(rnode);
8892 		}
8893 
8894 		export_property(exp_prop, exp_str, &pgelts, 0);
8895 	}
8896 	if (ret == -1)
8897 		scfdie();
8898 
8899 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
8900 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
8901 		    elts);
8902 }
8903 
8904 /*
8905  * Put an instance element for the given instance into selts.
8906  */
8907 static void
8908 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
8909 {
8910 	xmlNodePtr n;
8911 	boolean_t isdefault;
8912 	struct entity_elts elts;
8913 	struct template_elts template_elts;
8914 	int ret;
8915 
8916 	n = xmlNewNode(NULL, (xmlChar *)"instance");
8917 	if (n == NULL)
8918 		uu_die(emsg_create_xml);
8919 
8920 	/* name */
8921 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
8922 		scfdie();
8923 	safe_setprop(n, name_attr, exp_str);
8924 	isdefault = strcmp(exp_str, "default") == 0;
8925 
8926 	/* check existance of general pg (since general/enabled is required) */
8927 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
8928 		if (scf_error() != SCF_ERROR_NOT_FOUND)
8929 			scfdie();
8930 
8931 		if (g_verbose) {
8932 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
8933 				scfdie();
8934 
8935 			warn(gettext("Instance %s has no general property "
8936 			    "group; it will be marked disabled.\n"), exp_str);
8937 		}
8938 
8939 		safe_setprop(n, enabled_attr, false);
8940 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
8941 	    strcmp(exp_str, scf_group_framework) != 0) {
8942 		if (g_verbose) {
8943 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
8944 				scfdie();
8945 
8946 			warn(gettext("Property group %s is not of type "
8947 			    "framework; the instance will be marked "
8948 			    "disabled.\n"), exp_str);
8949 		}
8950 
8951 		safe_setprop(n, enabled_attr, false);
8952 	}
8953 
8954 	/* property groups */
8955 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
8956 		scfdie();
8957 
8958 	(void) memset(&elts, 0, sizeof (elts));
8959 	(void) memset(&template_elts, 0, sizeof (template_elts));
8960 
8961 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
8962 		uint32_t pgflags;
8963 
8964 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
8965 			scfdie();
8966 
8967 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
8968 			continue;
8969 
8970 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
8971 			scfdie();
8972 
8973 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
8974 			export_dependency(exp_pg, &elts);
8975 			continue;
8976 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
8977 			export_method(exp_pg, &elts);
8978 			continue;
8979 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
8980 			if (scf_pg_get_name(exp_pg, exp_str,
8981 			    max_scf_name_len + 1) < 0)
8982 				scfdie();
8983 
8984 			if (strcmp(exp_str, scf_pg_general) == 0) {
8985 				export_inst_general(exp_pg, n, &elts);
8986 				continue;
8987 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
8988 			    0) {
8989 				export_method_context(exp_pg, &elts);
8990 				continue;
8991 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
8992 				export_dependents(exp_pg, &elts);
8993 				continue;
8994 			}
8995 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
8996 			export_template(exp_pg, &elts, &template_elts);
8997 			continue;
8998 		}
8999 
9000 		/* Ordinary pg. */
9001 		export_pg(exp_pg, &elts, flags);
9002 	}
9003 	if (ret == -1)
9004 		scfdie();
9005 
9006 	if (template_elts.common_name != NULL) {
9007 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9008 		(void) xmlAddChild(elts.template, template_elts.common_name);
9009 		(void) xmlAddChild(elts.template, template_elts.description);
9010 		(void) xmlAddChild(elts.template, template_elts.documentation);
9011 	} else {
9012 		xmlFreeNode(template_elts.description);
9013 		xmlFreeNode(template_elts.documentation);
9014 	}
9015 
9016 	if (isdefault && elts.restarter == NULL &&
9017 	    elts.dependencies == NULL && elts.method_context == NULL &&
9018 	    elts.exec_methods == NULL && elts.property_groups == NULL &&
9019 	    elts.template == NULL) {
9020 		xmlChar *eval;
9021 
9022 		/* This is a default instance */
9023 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
9024 
9025 		xmlFreeNode(n);
9026 
9027 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
9028 		if (n == NULL)
9029 			uu_die(emsg_create_xml);
9030 
9031 		safe_setprop(n, enabled_attr, (char *)eval);
9032 		xmlFree(eval);
9033 
9034 		selts->create_default_instance = n;
9035 	} else {
9036 		/* Assemble the children in order. */
9037 		(void) xmlAddChild(n, elts.restarter);
9038 		(void) xmlAddChildList(n, elts.dependencies);
9039 		(void) xmlAddChildList(n, elts.dependents);
9040 		(void) xmlAddChild(n, elts.method_context);
9041 		(void) xmlAddChildList(n, elts.exec_methods);
9042 		(void) xmlAddChildList(n, elts.property_groups);
9043 		(void) xmlAddChild(n, elts.template);
9044 
9045 		if (selts->instances == NULL)
9046 			selts->instances = n;
9047 		else
9048 			(void) xmlAddSibling(selts->instances, n);
9049 	}
9050 }
9051 
9052 /*
9053  * Return a service element for the given service.
9054  */
9055 static xmlNodePtr
9056 export_service(scf_service_t *svc, int flags)
9057 {
9058 	xmlNodePtr snode;
9059 	struct entity_elts elts;
9060 	struct template_elts template_elts;
9061 	int ret;
9062 
9063 	snode = xmlNewNode(NULL, (xmlChar *)"service");
9064 	if (snode == NULL)
9065 		uu_die(emsg_create_xml);
9066 
9067 	/* Get & set name attribute */
9068 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
9069 		scfdie();
9070 	safe_setprop(snode, name_attr, exp_str);
9071 
9072 	safe_setprop(snode, type_attr, "service");
9073 	safe_setprop(snode, "version", "0");
9074 
9075 	/* Acquire child elements. */
9076 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
9077 		scfdie();
9078 
9079 	(void) memset(&elts, 0, sizeof (elts));
9080 	(void) memset(&template_elts, 0, sizeof (template_elts));
9081 
9082 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9083 		uint32_t pgflags;
9084 
9085 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9086 			scfdie();
9087 
9088 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9089 			continue;
9090 
9091 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9092 			scfdie();
9093 
9094 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9095 			export_dependency(exp_pg, &elts);
9096 			continue;
9097 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9098 			export_method(exp_pg, &elts);
9099 			continue;
9100 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9101 			if (scf_pg_get_name(exp_pg, exp_str,
9102 			    max_scf_name_len + 1) < 0)
9103 				scfdie();
9104 
9105 			if (strcmp(exp_str, scf_pg_general) == 0) {
9106 				export_svc_general(exp_pg, &elts);
9107 				continue;
9108 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9109 			    0) {
9110 				export_method_context(exp_pg, &elts);
9111 				continue;
9112 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9113 				export_dependents(exp_pg, &elts);
9114 				continue;
9115 			}
9116 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9117 			export_template(exp_pg, &elts, &template_elts);
9118 			continue;
9119 		}
9120 
9121 		export_pg(exp_pg, &elts, flags);
9122 	}
9123 	if (ret == -1)
9124 		scfdie();
9125 
9126 	if (template_elts.common_name != NULL) {
9127 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9128 		(void) xmlAddChild(elts.template, template_elts.common_name);
9129 		(void) xmlAddChild(elts.template, template_elts.description);
9130 		(void) xmlAddChild(elts.template, template_elts.documentation);
9131 	} else {
9132 		xmlFreeNode(template_elts.description);
9133 		xmlFreeNode(template_elts.documentation);
9134 	}
9135 
9136 	/* Iterate instances */
9137 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
9138 		scfdie();
9139 
9140 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
9141 		export_instance(exp_inst, &elts, flags);
9142 	if (ret == -1)
9143 		scfdie();
9144 
9145 	/* Now add all of the accumulated elements in order. */
9146 	(void) xmlAddChild(snode, elts.create_default_instance);
9147 	(void) xmlAddChild(snode, elts.single_instance);
9148 	(void) xmlAddChild(snode, elts.restarter);
9149 	(void) xmlAddChildList(snode, elts.dependencies);
9150 	(void) xmlAddChildList(snode, elts.dependents);
9151 	(void) xmlAddChild(snode, elts.method_context);
9152 	(void) xmlAddChildList(snode, elts.exec_methods);
9153 	(void) xmlAddChildList(snode, elts.property_groups);
9154 	(void) xmlAddChildList(snode, elts.instances);
9155 	(void) xmlAddChild(snode, elts.stability);
9156 	(void) xmlAddChild(snode, elts.template);
9157 
9158 	return (snode);
9159 }
9160 
9161 static int
9162 export_callback(void *data, scf_walkinfo_t *wip)
9163 {
9164 	FILE *f;
9165 	xmlDocPtr doc;
9166 	xmlNodePtr sb;
9167 	int result;
9168 	struct export_args *argsp = (struct export_args *)data;
9169 
9170 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
9171 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9172 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9173 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9174 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9175 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9176 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9177 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9178 		scfdie();
9179 
9180 	exp_str_sz = max_scf_len + 1;
9181 	exp_str = safe_malloc(exp_str_sz);
9182 
9183 	if (argsp->filename != NULL) {
9184 		errno = 0;
9185 		f = fopen(argsp->filename, "wb");
9186 		if (f == NULL) {
9187 			if (errno == 0)
9188 				uu_die(gettext("Could not open \"%s\": no free "
9189 				    "stdio streams.\n"), argsp->filename);
9190 			else
9191 				uu_die(gettext("Could not open \"%s\""),
9192 				    argsp->filename);
9193 		}
9194 	} else
9195 		f = stdout;
9196 
9197 	doc = xmlNewDoc((xmlChar *)"1.0");
9198 	if (doc == NULL)
9199 		uu_die(gettext("Could not create XML document.\n"));
9200 
9201 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9202 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9203 		uu_die(emsg_create_xml);
9204 
9205 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9206 	if (sb == NULL)
9207 		uu_die(emsg_create_xml);
9208 	safe_setprop(sb, type_attr, "manifest");
9209 	safe_setprop(sb, name_attr, "export");
9210 	(void) xmlAddSibling(doc->children, sb);
9211 
9212 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
9213 
9214 	result = write_service_bundle(doc, f);
9215 
9216 	free(exp_str);
9217 	scf_iter_destroy(exp_val_iter);
9218 	scf_iter_destroy(exp_prop_iter);
9219 	scf_iter_destroy(exp_pg_iter);
9220 	scf_iter_destroy(exp_inst_iter);
9221 	scf_value_destroy(exp_val);
9222 	scf_property_destroy(exp_prop);
9223 	scf_pg_destroy(exp_pg);
9224 	scf_instance_destroy(exp_inst);
9225 
9226 	xmlFreeDoc(doc);
9227 
9228 	if (f != stdout)
9229 		(void) fclose(f);
9230 
9231 	return (result);
9232 }
9233 
9234 /*
9235  * Get the service named by fmri, build an XML tree which represents it, and
9236  * dump it into filename (or stdout if filename is NULL).
9237  */
9238 int
9239 lscf_service_export(char *fmri, const char *filename, int flags)
9240 {
9241 	struct export_args args;
9242 	int ret, err;
9243 
9244 	lscf_prep_hndl();
9245 
9246 	bzero(&args, sizeof (args));
9247 	args.filename = filename;
9248 	args.flags = flags;
9249 
9250 	err = 0;
9251 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
9252 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
9253 	    &args, &err, semerr)) != 0) {
9254 		if (ret != -1)
9255 			semerr(gettext("Failed to walk instances: %s\n"),
9256 			    scf_strerror(ret));
9257 		return (-1);
9258 	}
9259 
9260 	/*
9261 	 * Error message has already been printed.
9262 	 */
9263 	if (err != 0)
9264 		return (-1);
9265 
9266 	return (0);
9267 }
9268 
9269 
9270 /*
9271  * Archive
9272  */
9273 
9274 static xmlNodePtr
9275 make_archive(int flags)
9276 {
9277 	xmlNodePtr sb;
9278 	scf_scope_t *scope;
9279 	scf_service_t *svc;
9280 	scf_iter_t *iter;
9281 	int r;
9282 
9283 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9284 	    (svc = scf_service_create(g_hndl)) == NULL ||
9285 	    (iter = scf_iter_create(g_hndl)) == NULL ||
9286 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
9287 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9288 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9289 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9290 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9291 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9292 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9293 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9294 		scfdie();
9295 
9296 	exp_str_sz = max_scf_len + 1;
9297 	exp_str = safe_malloc(exp_str_sz);
9298 
9299 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9300 	if (sb == NULL)
9301 		uu_die(emsg_create_xml);
9302 	safe_setprop(sb, type_attr, "archive");
9303 	safe_setprop(sb, name_attr, "none");
9304 
9305 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
9306 		scfdie();
9307 	if (scf_iter_scope_services(iter, scope) != 0)
9308 		scfdie();
9309 
9310 	for (;;) {
9311 		r = scf_iter_next_service(iter, svc);
9312 		if (r == 0)
9313 			break;
9314 		if (r != 1)
9315 			scfdie();
9316 
9317 		if (scf_service_get_name(svc, exp_str,
9318 		    max_scf_name_len + 1) < 0)
9319 			scfdie();
9320 
9321 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
9322 			continue;
9323 
9324 		xmlAddChild(sb, export_service(svc, flags));
9325 	}
9326 
9327 	free(exp_str);
9328 
9329 	scf_iter_destroy(exp_val_iter);
9330 	scf_iter_destroy(exp_prop_iter);
9331 	scf_iter_destroy(exp_pg_iter);
9332 	scf_iter_destroy(exp_inst_iter);
9333 	scf_value_destroy(exp_val);
9334 	scf_property_destroy(exp_prop);
9335 	scf_pg_destroy(exp_pg);
9336 	scf_instance_destroy(exp_inst);
9337 	scf_iter_destroy(iter);
9338 	scf_service_destroy(svc);
9339 	scf_scope_destroy(scope);
9340 
9341 	return (sb);
9342 }
9343 
9344 int
9345 lscf_archive(const char *filename, int flags)
9346 {
9347 	FILE *f;
9348 	xmlDocPtr doc;
9349 	int result;
9350 
9351 	lscf_prep_hndl();
9352 
9353 	if (filename != NULL) {
9354 		errno = 0;
9355 		f = fopen(filename, "wb");
9356 		if (f == NULL) {
9357 			if (errno == 0)
9358 				uu_die(gettext("Could not open \"%s\": no free "
9359 				    "stdio streams.\n"), filename);
9360 			else
9361 				uu_die(gettext("Could not open \"%s\""),
9362 				    filename);
9363 		}
9364 	} else
9365 		f = stdout;
9366 
9367 	doc = xmlNewDoc((xmlChar *)"1.0");
9368 	if (doc == NULL)
9369 		uu_die(gettext("Could not create XML document.\n"));
9370 
9371 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9372 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9373 		uu_die(emsg_create_xml);
9374 
9375 	(void) xmlAddSibling(doc->children, make_archive(flags));
9376 
9377 	result = write_service_bundle(doc, f);
9378 
9379 	xmlFreeDoc(doc);
9380 
9381 	if (f != stdout)
9382 		(void) fclose(f);
9383 
9384 	return (result);
9385 }
9386 
9387 
9388 /*
9389  * "Extract" a profile.
9390  */
9391 int
9392 lscf_profile_extract(const char *filename)
9393 {
9394 	FILE *f;
9395 	xmlDocPtr doc;
9396 	xmlNodePtr sb, snode, inode;
9397 	scf_scope_t *scope;
9398 	scf_service_t *svc;
9399 	scf_instance_t *inst;
9400 	scf_propertygroup_t *pg;
9401 	scf_property_t *prop;
9402 	scf_value_t *val;
9403 	scf_iter_t *siter, *iiter;
9404 	int r, s;
9405 	char *namebuf;
9406 	uint8_t b;
9407 	int result;
9408 
9409 	lscf_prep_hndl();
9410 
9411 	if (filename != NULL) {
9412 		errno = 0;
9413 		f = fopen(filename, "wb");
9414 		if (f == NULL) {
9415 			if (errno == 0)
9416 				uu_die(gettext("Could not open \"%s\": no "
9417 				    "free stdio streams.\n"), filename);
9418 			else
9419 				uu_die(gettext("Could not open \"%s\""),
9420 				    filename);
9421 		}
9422 	} else
9423 		f = stdout;
9424 
9425 	doc = xmlNewDoc((xmlChar *)"1.0");
9426 	if (doc == NULL)
9427 		uu_die(gettext("Could not create XML document.\n"));
9428 
9429 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9430 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9431 		uu_die(emsg_create_xml);
9432 
9433 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9434 	if (sb == NULL)
9435 		uu_die(emsg_create_xml);
9436 	safe_setprop(sb, type_attr, "profile");
9437 	safe_setprop(sb, name_attr, "extract");
9438 	(void) xmlAddSibling(doc->children, sb);
9439 
9440 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9441 	    (svc = scf_service_create(g_hndl)) == NULL ||
9442 	    (inst = scf_instance_create(g_hndl)) == NULL ||
9443 	    (pg = scf_pg_create(g_hndl)) == NULL ||
9444 	    (prop = scf_property_create(g_hndl)) == NULL ||
9445 	    (val = scf_value_create(g_hndl)) == NULL ||
9446 	    (siter = scf_iter_create(g_hndl)) == NULL ||
9447 	    (iiter = scf_iter_create(g_hndl)) == NULL)
9448 		scfdie();
9449 
9450 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
9451 		scfdie();
9452 
9453 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
9454 		scfdie();
9455 
9456 	namebuf = safe_malloc(max_scf_name_len + 1);
9457 
9458 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
9459 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
9460 			scfdie();
9461 
9462 		snode = xmlNewNode(NULL, (xmlChar *)"service");
9463 		if (snode == NULL)
9464 			uu_die(emsg_create_xml);
9465 
9466 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
9467 		    0)
9468 			scfdie();
9469 
9470 		safe_setprop(snode, name_attr, namebuf);
9471 
9472 		safe_setprop(snode, type_attr, "service");
9473 		safe_setprop(snode, "version", "0");
9474 
9475 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
9476 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
9477 			    SCF_SUCCESS) {
9478 				if (scf_error() != SCF_ERROR_NOT_FOUND)
9479 					scfdie();
9480 
9481 				if (g_verbose) {
9482 					ssize_t len;
9483 					char *fmri;
9484 
9485 					len =
9486 					    scf_instance_to_fmri(inst, NULL, 0);
9487 					if (len < 0)
9488 						scfdie();
9489 
9490 					fmri = safe_malloc(len + 1);
9491 
9492 					if (scf_instance_to_fmri(inst, fmri,
9493 					    len + 1) < 0)
9494 						scfdie();
9495 
9496 					warn("Instance %s has no \"%s\" "
9497 					    "property group.\n", fmri,
9498 					    scf_pg_general);
9499 
9500 					free(fmri);
9501 				}
9502 
9503 				continue;
9504 			}
9505 
9506 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
9507 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
9508 			    prop_get_val(prop, val) != 0)
9509 				continue;
9510 
9511 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
9512 			    NULL);
9513 			if (inode == NULL)
9514 				uu_die(emsg_create_xml);
9515 
9516 			if (scf_instance_get_name(inst, namebuf,
9517 			    max_scf_name_len + 1) < 0)
9518 				scfdie();
9519 
9520 			safe_setprop(inode, name_attr, namebuf);
9521 
9522 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
9523 				scfdie();
9524 
9525 			safe_setprop(inode, enabled_attr, b ? true : false);
9526 		}
9527 		if (s < 0)
9528 			scfdie();
9529 
9530 		if (snode->children != NULL)
9531 			xmlAddChild(sb, snode);
9532 		else
9533 			xmlFreeNode(snode);
9534 	}
9535 	if (r < 0)
9536 		scfdie();
9537 
9538 	free(namebuf);
9539 
9540 	result = write_service_bundle(doc, f);
9541 
9542 	xmlFreeDoc(doc);
9543 
9544 	if (f != stdout)
9545 		(void) fclose(f);
9546 
9547 	return (result);
9548 }
9549 
9550 
9551 /*
9552  * Entity manipulation commands
9553  */
9554 
9555 /*
9556  * Entity selection.  If no entity is selected, then the current scope is in
9557  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
9558  * only cur_inst is NULL, and when an instance is selected, none are NULL.
9559  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
9560  * cur_inst will be non-NULL.
9561  */
9562 
9563 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
9564 static int
9565 select_inst(const char *name)
9566 {
9567 	scf_instance_t *inst;
9568 	scf_error_t err;
9569 
9570 	assert(cur_svc != NULL);
9571 
9572 	inst = scf_instance_create(g_hndl);
9573 	if (inst == NULL)
9574 		scfdie();
9575 
9576 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
9577 		cur_inst = inst;
9578 		return (0);
9579 	}
9580 
9581 	err = scf_error();
9582 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9583 		scfdie();
9584 
9585 	scf_instance_destroy(inst);
9586 	return (1);
9587 }
9588 
9589 /* Returns as above. */
9590 static int
9591 select_svc(const char *name)
9592 {
9593 	scf_service_t *svc;
9594 	scf_error_t err;
9595 
9596 	assert(cur_scope != NULL);
9597 
9598 	svc = scf_service_create(g_hndl);
9599 	if (svc == NULL)
9600 		scfdie();
9601 
9602 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
9603 		cur_svc = svc;
9604 		return (0);
9605 	}
9606 
9607 	err = scf_error();
9608 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9609 		scfdie();
9610 
9611 	scf_service_destroy(svc);
9612 	return (1);
9613 }
9614 
9615 /* ARGSUSED */
9616 static int
9617 select_callback(void *unused, scf_walkinfo_t *wip)
9618 {
9619 	scf_instance_t *inst;
9620 	scf_service_t *svc;
9621 	scf_scope_t *scope;
9622 
9623 	if (wip->inst != NULL) {
9624 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9625 		    (svc = scf_service_create(g_hndl)) == NULL ||
9626 		    (inst = scf_instance_create(g_hndl)) == NULL)
9627 			scfdie();
9628 
9629 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9630 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9631 			scfdie();
9632 	} else {
9633 		assert(wip->svc != NULL);
9634 
9635 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9636 		    (svc = scf_service_create(g_hndl)) == NULL)
9637 			scfdie();
9638 
9639 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9640 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9641 			scfdie();
9642 
9643 		inst = NULL;
9644 	}
9645 
9646 	/* Clear out the current selection */
9647 	assert(cur_scope != NULL);
9648 	scf_scope_destroy(cur_scope);
9649 	scf_service_destroy(cur_svc);
9650 	scf_instance_destroy(cur_inst);
9651 
9652 	cur_scope = scope;
9653 	cur_svc = svc;
9654 	cur_inst = inst;
9655 
9656 	return (0);
9657 }
9658 
9659 static int
9660 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
9661 {
9662 	char **fmri = fmri_p;
9663 
9664 	*fmri = strdup(wip->fmri);
9665 	if (*fmri == NULL)
9666 		uu_die(gettext("Out of memory.\n"));
9667 
9668 	return (0);
9669 }
9670 
9671 /*
9672  * validate [fmri]
9673  * Perform the validation of an FMRI instance.
9674  */
9675 void
9676 lscf_validate_fmri(const char *fmri)
9677 {
9678 	int ret = 0;
9679 	size_t inst_sz;
9680 	char *inst_fmri = NULL;
9681 	scf_tmpl_errors_t *errs = NULL;
9682 	char *snapbuf = NULL;
9683 
9684 	lscf_prep_hndl();
9685 
9686 	if (fmri == NULL) {
9687 		inst_sz = max_scf_fmri_len + 1;
9688 		inst_fmri = safe_malloc(inst_sz);
9689 
9690 		if (cur_snap != NULL) {
9691 			snapbuf = safe_malloc(max_scf_name_len + 1);
9692 			if (scf_snapshot_get_name(cur_snap, snapbuf,
9693 			    max_scf_name_len + 1) < 0)
9694 				scfdie();
9695 		}
9696 		if (cur_inst == NULL) {
9697 			semerr(gettext("No instance selected\n"));
9698 			goto cleanup;
9699 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
9700 		    inst_sz) >= inst_sz) {
9701 			/* sanity check. Should never get here */
9702 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
9703 			    __FILE__, __LINE__);
9704 		}
9705 	} else {
9706 		scf_error_t scf_err;
9707 		int err = 0;
9708 
9709 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
9710 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
9711 			uu_warn("Failed to walk instances: %s\n",
9712 			    scf_strerror(scf_err));
9713 			goto cleanup;
9714 		}
9715 		if (err != 0) {
9716 			/* error message displayed by scf_walk_fmri */
9717 			goto cleanup;
9718 		}
9719 	}
9720 
9721 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
9722 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
9723 	if (ret == -1) {
9724 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
9725 			warn(gettext("Template data for %s is invalid. "
9726 			    "Consider reverting to a previous snapshot or "
9727 			    "restoring original configuration.\n"), inst_fmri);
9728 		} else {
9729 			uu_warn("%s: %s\n",
9730 			    gettext("Error validating the instance"),
9731 			    scf_strerror(scf_error()));
9732 		}
9733 	} else if (ret == 1 && errs != NULL) {
9734 		scf_tmpl_error_t *err = NULL;
9735 		char *msg;
9736 		size_t len = 256;	/* initial error buffer size */
9737 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
9738 		    SCF_TMPL_STRERROR_HUMAN : 0;
9739 
9740 		msg = safe_malloc(len);
9741 
9742 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
9743 			int ret;
9744 
9745 			if ((ret = scf_tmpl_strerror(err, msg, len,
9746 			    flag)) >= len) {
9747 				len = ret + 1;
9748 				msg = realloc(msg, len);
9749 				if (msg == NULL)
9750 					uu_die(gettext(
9751 					    "Out of memory.\n"));
9752 				(void) scf_tmpl_strerror(err, msg, len,
9753 				    flag);
9754 			}
9755 			(void) fprintf(stderr, "%s\n", msg);
9756 		}
9757 		if (msg != NULL)
9758 			free(msg);
9759 	}
9760 	if (errs != NULL)
9761 		scf_tmpl_errors_destroy(errs);
9762 
9763 cleanup:
9764 	free(inst_fmri);
9765 	free(snapbuf);
9766 }
9767 
9768 static void
9769 lscf_validate_file(const char *filename)
9770 {
9771 	tmpl_errors_t *errs;
9772 
9773 	bundle_t *b = internal_bundle_new();
9774 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
9775 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
9776 			tmpl_errors_print(stderr, errs, "");
9777 			semerr(gettext("Validation failed.\n"));
9778 		}
9779 		tmpl_errors_destroy(errs);
9780 	}
9781 	(void) internal_bundle_free(b);
9782 }
9783 
9784 /*
9785  * validate [fmri|file]
9786  */
9787 void
9788 lscf_validate(const char *arg)
9789 {
9790 	const char *str;
9791 
9792 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
9793 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
9794 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
9795 		lscf_validate_file(str);
9796 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
9797 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
9798 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
9799 		lscf_validate_fmri(str);
9800 	} else if (access(arg, R_OK | F_OK) == 0) {
9801 		lscf_validate_file(arg);
9802 	} else {
9803 		lscf_validate_fmri(arg);
9804 	}
9805 }
9806 
9807 void
9808 lscf_select(const char *fmri)
9809 {
9810 	int ret, err;
9811 
9812 	lscf_prep_hndl();
9813 
9814 	if (cur_snap != NULL) {
9815 		struct snaplevel *elt;
9816 		char *buf;
9817 
9818 		/* Error unless name is that of the next level. */
9819 		elt = uu_list_next(cur_levels, cur_elt);
9820 		if (elt == NULL) {
9821 			semerr(gettext("No children.\n"));
9822 			return;
9823 		}
9824 
9825 		buf = safe_malloc(max_scf_name_len + 1);
9826 
9827 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
9828 		    max_scf_name_len + 1) < 0)
9829 			scfdie();
9830 
9831 		if (strcmp(buf, fmri) != 0) {
9832 			semerr(gettext("No such child.\n"));
9833 			free(buf);
9834 			return;
9835 		}
9836 
9837 		free(buf);
9838 
9839 		cur_elt = elt;
9840 		cur_level = elt->sl;
9841 		return;
9842 	}
9843 
9844 	/*
9845 	 * Special case for 'svc:', which takes the user to the scope level.
9846 	 */
9847 	if (strcmp(fmri, "svc:") == 0) {
9848 		scf_instance_destroy(cur_inst);
9849 		scf_service_destroy(cur_svc);
9850 		cur_inst = NULL;
9851 		cur_svc = NULL;
9852 		return;
9853 	}
9854 
9855 	/*
9856 	 * Special case for ':properties'.  This appears as part of 'list' but
9857 	 * can't be selected.  Give a more helpful error message in this case.
9858 	 */
9859 	if (strcmp(fmri, ":properties") == 0) {
9860 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
9861 		    "to list properties.\n"));
9862 		return;
9863 	}
9864 
9865 	/*
9866 	 * First try the argument as relative to the current selection.
9867 	 */
9868 	if (cur_inst != NULL) {
9869 		/* EMPTY */;
9870 	} else if (cur_svc != NULL) {
9871 		if (select_inst(fmri) != 1)
9872 			return;
9873 	} else {
9874 		if (select_svc(fmri) != 1)
9875 			return;
9876 	}
9877 
9878 	err = 0;
9879 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
9880 	    select_callback, NULL, &err, semerr)) != 0) {
9881 		semerr(gettext("Failed to walk instances: %s\n"),
9882 		    scf_strerror(ret));
9883 	}
9884 }
9885 
9886 void
9887 lscf_unselect(void)
9888 {
9889 	lscf_prep_hndl();
9890 
9891 	if (cur_snap != NULL) {
9892 		struct snaplevel *elt;
9893 
9894 		elt = uu_list_prev(cur_levels, cur_elt);
9895 		if (elt == NULL) {
9896 			semerr(gettext("No parent levels.\n"));
9897 		} else {
9898 			cur_elt = elt;
9899 			cur_level = elt->sl;
9900 		}
9901 	} else if (cur_inst != NULL) {
9902 		scf_instance_destroy(cur_inst);
9903 		cur_inst = NULL;
9904 	} else if (cur_svc != NULL) {
9905 		scf_service_destroy(cur_svc);
9906 		cur_svc = NULL;
9907 	} else {
9908 		semerr(gettext("Cannot unselect at scope level.\n"));
9909 	}
9910 }
9911 
9912 /*
9913  * Return the FMRI of the current selection, for the prompt.
9914  */
9915 void
9916 lscf_get_selection_str(char *buf, size_t bufsz)
9917 {
9918 	char *cp;
9919 	ssize_t fmrilen, szret;
9920 	boolean_t deleted = B_FALSE;
9921 
9922 	if (g_hndl == NULL) {
9923 		(void) strlcpy(buf, "svc:", bufsz);
9924 		return;
9925 	}
9926 
9927 	if (cur_level != NULL) {
9928 		assert(cur_snap != NULL);
9929 
9930 		/* [ snapshot ] FMRI [: instance ] */
9931 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
9932 		    + 2 + max_scf_name_len + 1 + 1);
9933 
9934 		buf[0] = '[';
9935 
9936 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
9937 		    max_scf_name_len + 1);
9938 		if (szret < 0) {
9939 			if (scf_error() != SCF_ERROR_DELETED)
9940 				scfdie();
9941 
9942 			goto snap_deleted;
9943 		}
9944 
9945 		(void) strcat(buf, "]svc:/");
9946 
9947 		cp = strchr(buf, '\0');
9948 
9949 		szret = scf_snaplevel_get_service_name(cur_level, cp,
9950 		    max_scf_name_len + 1);
9951 		if (szret < 0) {
9952 			if (scf_error() != SCF_ERROR_DELETED)
9953 				scfdie();
9954 
9955 			goto snap_deleted;
9956 		}
9957 
9958 		cp = strchr(cp, '\0');
9959 
9960 		if (snaplevel_is_instance(cur_level)) {
9961 			*cp++ = ':';
9962 
9963 			if (scf_snaplevel_get_instance_name(cur_level, cp,
9964 			    max_scf_name_len + 1) < 0) {
9965 				if (scf_error() != SCF_ERROR_DELETED)
9966 					scfdie();
9967 
9968 				goto snap_deleted;
9969 			}
9970 		} else {
9971 			*cp++ = '[';
9972 			*cp++ = ':';
9973 
9974 			if (scf_instance_get_name(cur_inst, cp,
9975 			    max_scf_name_len + 1) < 0) {
9976 				if (scf_error() != SCF_ERROR_DELETED)
9977 					scfdie();
9978 
9979 				goto snap_deleted;
9980 			}
9981 
9982 			(void) strcat(buf, "]");
9983 		}
9984 
9985 		return;
9986 
9987 snap_deleted:
9988 		deleted = B_TRUE;
9989 		free(buf);
9990 		unselect_cursnap();
9991 	}
9992 
9993 	assert(cur_snap == NULL);
9994 
9995 	if (cur_inst != NULL) {
9996 		assert(cur_svc != NULL);
9997 		assert(cur_scope != NULL);
9998 
9999 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
10000 		if (fmrilen >= 0) {
10001 			assert(fmrilen < bufsz);
10002 			if (deleted)
10003 				warn(emsg_deleted);
10004 			return;
10005 		}
10006 
10007 		if (scf_error() != SCF_ERROR_DELETED)
10008 			scfdie();
10009 
10010 		deleted = B_TRUE;
10011 
10012 		scf_instance_destroy(cur_inst);
10013 		cur_inst = NULL;
10014 	}
10015 
10016 	if (cur_svc != NULL) {
10017 		assert(cur_scope != NULL);
10018 
10019 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
10020 		if (szret >= 0) {
10021 			assert(szret < bufsz);
10022 			if (deleted)
10023 				warn(emsg_deleted);
10024 			return;
10025 		}
10026 
10027 		if (scf_error() != SCF_ERROR_DELETED)
10028 			scfdie();
10029 
10030 		deleted = B_TRUE;
10031 		scf_service_destroy(cur_svc);
10032 		cur_svc = NULL;
10033 	}
10034 
10035 	assert(cur_scope != NULL);
10036 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
10037 
10038 	if (fmrilen < 0)
10039 		scfdie();
10040 
10041 	assert(fmrilen < bufsz);
10042 	if (deleted)
10043 		warn(emsg_deleted);
10044 }
10045 
10046 /*
10047  * Entity listing.  Entities and colon namespaces (e.g., :properties and
10048  * :statistics) are listed for the current selection.
10049  */
10050 void
10051 lscf_list(const char *pattern)
10052 {
10053 	scf_iter_t *iter;
10054 	char *buf;
10055 	int ret;
10056 
10057 	lscf_prep_hndl();
10058 
10059 	if (cur_level != NULL) {
10060 		struct snaplevel *elt;
10061 
10062 		(void) fputs(COLON_NAMESPACES, stdout);
10063 
10064 		elt = uu_list_next(cur_levels, cur_elt);
10065 		if (elt == NULL)
10066 			return;
10067 
10068 		/*
10069 		 * For now, we know that the next level is an instance.  But
10070 		 * if we ever have multiple scopes, this could be complicated.
10071 		 */
10072 		buf = safe_malloc(max_scf_name_len + 1);
10073 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10074 		    max_scf_name_len + 1) >= 0) {
10075 			(void) puts(buf);
10076 		} else {
10077 			if (scf_error() != SCF_ERROR_DELETED)
10078 				scfdie();
10079 		}
10080 
10081 		free(buf);
10082 
10083 		return;
10084 	}
10085 
10086 	if (cur_inst != NULL) {
10087 		(void) fputs(COLON_NAMESPACES, stdout);
10088 		return;
10089 	}
10090 
10091 	iter = scf_iter_create(g_hndl);
10092 	if (iter == NULL)
10093 		scfdie();
10094 
10095 	buf = safe_malloc(max_scf_name_len + 1);
10096 
10097 	if (cur_svc != NULL) {
10098 		/* List the instances in this service. */
10099 		scf_instance_t *inst;
10100 
10101 		inst = scf_instance_create(g_hndl);
10102 		if (inst == NULL)
10103 			scfdie();
10104 
10105 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
10106 			safe_printf(COLON_NAMESPACES);
10107 
10108 			for (;;) {
10109 				ret = scf_iter_next_instance(iter, inst);
10110 				if (ret == 0)
10111 					break;
10112 				if (ret != 1) {
10113 					if (scf_error() != SCF_ERROR_DELETED)
10114 						scfdie();
10115 
10116 					break;
10117 				}
10118 
10119 				if (scf_instance_get_name(inst, buf,
10120 				    max_scf_name_len + 1) >= 0) {
10121 					if (pattern == NULL ||
10122 					    fnmatch(pattern, buf, 0) == 0)
10123 						(void) puts(buf);
10124 				} else {
10125 					if (scf_error() != SCF_ERROR_DELETED)
10126 						scfdie();
10127 				}
10128 			}
10129 		} else {
10130 			if (scf_error() != SCF_ERROR_DELETED)
10131 				scfdie();
10132 		}
10133 
10134 		scf_instance_destroy(inst);
10135 	} else {
10136 		/* List the services in this scope. */
10137 		scf_service_t *svc;
10138 
10139 		assert(cur_scope != NULL);
10140 
10141 		svc = scf_service_create(g_hndl);
10142 		if (svc == NULL)
10143 			scfdie();
10144 
10145 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
10146 			scfdie();
10147 
10148 		for (;;) {
10149 			ret = scf_iter_next_service(iter, svc);
10150 			if (ret == 0)
10151 				break;
10152 			if (ret != 1)
10153 				scfdie();
10154 
10155 			if (scf_service_get_name(svc, buf,
10156 			    max_scf_name_len + 1) >= 0) {
10157 				if (pattern == NULL ||
10158 				    fnmatch(pattern, buf, 0) == 0)
10159 					safe_printf("%s\n", buf);
10160 			} else {
10161 				if (scf_error() != SCF_ERROR_DELETED)
10162 					scfdie();
10163 			}
10164 		}
10165 
10166 		scf_service_destroy(svc);
10167 	}
10168 
10169 	free(buf);
10170 	scf_iter_destroy(iter);
10171 }
10172 
10173 /*
10174  * Entity addition.  Creates an empty entity in the current selection.
10175  */
10176 void
10177 lscf_add(const char *name)
10178 {
10179 	lscf_prep_hndl();
10180 
10181 	if (cur_snap != NULL) {
10182 		semerr(emsg_cant_modify_snapshots);
10183 	} else if (cur_inst != NULL) {
10184 		semerr(gettext("Cannot add entities to an instance.\n"));
10185 	} else if (cur_svc != NULL) {
10186 
10187 		if (scf_service_add_instance(cur_svc, name, NULL) !=
10188 		    SCF_SUCCESS) {
10189 			switch (scf_error()) {
10190 			case SCF_ERROR_INVALID_ARGUMENT:
10191 				semerr(gettext("Invalid name.\n"));
10192 				break;
10193 
10194 			case SCF_ERROR_EXISTS:
10195 				semerr(gettext("Instance already exists.\n"));
10196 				break;
10197 
10198 			case SCF_ERROR_PERMISSION_DENIED:
10199 				semerr(emsg_permission_denied);
10200 				break;
10201 
10202 			default:
10203 				scfdie();
10204 			}
10205 		}
10206 	} else {
10207 		assert(cur_scope != NULL);
10208 
10209 		if (scf_scope_add_service(cur_scope, name, NULL) !=
10210 		    SCF_SUCCESS) {
10211 			switch (scf_error()) {
10212 			case SCF_ERROR_INVALID_ARGUMENT:
10213 				semerr(gettext("Invalid name.\n"));
10214 				break;
10215 
10216 			case SCF_ERROR_EXISTS:
10217 				semerr(gettext("Service already exists.\n"));
10218 				break;
10219 
10220 			case SCF_ERROR_PERMISSION_DENIED:
10221 				semerr(emsg_permission_denied);
10222 				break;
10223 
10224 			case SCF_ERROR_BACKEND_READONLY:
10225 				semerr(emsg_read_only);
10226 				break;
10227 
10228 			default:
10229 				scfdie();
10230 			}
10231 		}
10232 	}
10233 }
10234 
10235 /* return 1 if the entity has no persistent pgs, else return 0 */
10236 static int
10237 entity_has_no_pgs(void *ent, int isservice)
10238 {
10239 	scf_iter_t *iter = NULL;
10240 	scf_propertygroup_t *pg = NULL;
10241 	uint32_t flags;
10242 	int err;
10243 	int ret = 1;
10244 
10245 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10246 	    (pg = scf_pg_create(g_hndl)) == NULL)
10247 		scfdie();
10248 
10249 	if (isservice) {
10250 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
10251 			scfdie();
10252 	} else {
10253 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
10254 			scfdie();
10255 	}
10256 
10257 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10258 		if (scf_pg_get_flags(pg, &flags) != 0)
10259 			scfdie();
10260 
10261 		/* skip nonpersistent pgs */
10262 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
10263 			continue;
10264 
10265 		ret = 0;
10266 		break;
10267 	}
10268 
10269 	if (err == -1)
10270 		scfdie();
10271 
10272 	scf_pg_destroy(pg);
10273 	scf_iter_destroy(iter);
10274 
10275 	return (ret);
10276 }
10277 
10278 /* return 1 if the service has no instances, else return 0 */
10279 static int
10280 svc_has_no_insts(scf_service_t *svc)
10281 {
10282 	scf_instance_t *inst;
10283 	scf_iter_t *iter;
10284 	int r;
10285 	int ret = 1;
10286 
10287 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10288 	    (iter = scf_iter_create(g_hndl)) == NULL)
10289 		scfdie();
10290 
10291 	if (scf_iter_service_instances(iter, svc) != 0)
10292 		scfdie();
10293 
10294 	r = scf_iter_next_instance(iter, inst);
10295 	if (r == 1) {
10296 		ret = 0;
10297 	} else if (r == 0) {
10298 		ret = 1;
10299 	} else if (r == -1) {
10300 		scfdie();
10301 	} else {
10302 		bad_error("scf_iter_next_instance", r);
10303 	}
10304 
10305 	scf_iter_destroy(iter);
10306 	scf_instance_destroy(inst);
10307 
10308 	return (ret);
10309 }
10310 
10311 /*
10312  * Entity deletion.
10313  */
10314 
10315 /*
10316  * Delete the property group <fmri>/:properties/<name>.  Returns
10317  * SCF_ERROR_NONE on success (or if the entity is not found),
10318  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
10319  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
10320  * denied.
10321  */
10322 static scf_error_t
10323 delete_dependency_pg(const char *fmri, const char *name)
10324 {
10325 	void *entity = NULL;
10326 	int isservice;
10327 	scf_propertygroup_t *pg = NULL;
10328 	scf_error_t result;
10329 	char *pgty;
10330 	scf_service_t *svc = NULL;
10331 	scf_instance_t *inst = NULL;
10332 	scf_iter_t *iter = NULL;
10333 	char *name_buf = NULL;
10334 
10335 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10336 	switch (result) {
10337 	case SCF_ERROR_NONE:
10338 		break;
10339 
10340 	case SCF_ERROR_NO_MEMORY:
10341 		uu_die(gettext("Out of memory.\n"));
10342 		/* NOTREACHED */
10343 
10344 	case SCF_ERROR_INVALID_ARGUMENT:
10345 	case SCF_ERROR_CONSTRAINT_VIOLATED:
10346 		return (SCF_ERROR_INVALID_ARGUMENT);
10347 
10348 	case SCF_ERROR_NOT_FOUND:
10349 		result = SCF_ERROR_NONE;
10350 		goto out;
10351 
10352 	default:
10353 		bad_error("fmri_to_entity", result);
10354 	}
10355 
10356 	pg = scf_pg_create(g_hndl);
10357 	if (pg == NULL)
10358 		scfdie();
10359 
10360 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
10361 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10362 			scfdie();
10363 
10364 		result = SCF_ERROR_NONE;
10365 		goto out;
10366 	}
10367 
10368 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10369 
10370 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10371 		scfdie();
10372 
10373 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
10374 		result = SCF_ERROR_TYPE_MISMATCH;
10375 		free(pgty);
10376 		goto out;
10377 	}
10378 
10379 	free(pgty);
10380 
10381 	if (scf_pg_delete(pg) != 0) {
10382 		result = scf_error();
10383 		if (result != SCF_ERROR_PERMISSION_DENIED)
10384 			scfdie();
10385 		goto out;
10386 	}
10387 
10388 	/*
10389 	 * We have to handle the case where we've just deleted the last
10390 	 * property group of a "dummy" entity (instance or service).
10391 	 * A "dummy" entity is an entity only present to hold an
10392 	 * external dependency.
10393 	 * So, in the case we deleted the last property group then we
10394 	 * can also delete the entity. If the entity is an instance then
10395 	 * we must verify if this was the last instance for the service
10396 	 * and if it is, we can also delete the service if it doesn't
10397 	 * have any property group either.
10398 	 */
10399 
10400 	result = SCF_ERROR_NONE;
10401 
10402 	if (isservice) {
10403 		svc = (scf_service_t *)entity;
10404 
10405 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
10406 		    (iter = scf_iter_create(g_hndl)) == NULL)
10407 			scfdie();
10408 
10409 		name_buf = safe_malloc(max_scf_name_len + 1);
10410 	} else {
10411 		inst = (scf_instance_t *)entity;
10412 	}
10413 
10414 	/*
10415 	 * If the entity is an instance and we've just deleted its last
10416 	 * property group then we should delete it.
10417 	 */
10418 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
10419 		/* find the service before deleting the inst. - needed later */
10420 		if ((svc = scf_service_create(g_hndl)) == NULL)
10421 			scfdie();
10422 
10423 		if (scf_instance_get_parent(inst, svc) != 0)
10424 			scfdie();
10425 
10426 		/* delete the instance */
10427 		if (scf_instance_delete(inst) != 0) {
10428 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10429 				scfdie();
10430 
10431 			result = SCF_ERROR_PERMISSION_DENIED;
10432 			goto out;
10433 		}
10434 		/* no need to refresh the instance */
10435 		inst = NULL;
10436 	}
10437 
10438 	/*
10439 	 * If the service has no more instances and pgs or we just deleted the
10440 	 * last instance and the service doesn't have anymore propery groups
10441 	 * then the service should be deleted.
10442 	 */
10443 	if (svc != NULL &&
10444 	    svc_has_no_insts(svc) &&
10445 	    entity_has_no_pgs((void *)svc, 1)) {
10446 		if (scf_service_delete(svc) == 0) {
10447 			if (isservice) {
10448 				/* no need to refresh the service */
10449 				svc = NULL;
10450 			}
10451 
10452 			goto out;
10453 		}
10454 
10455 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10456 			scfdie();
10457 
10458 		result = SCF_ERROR_PERMISSION_DENIED;
10459 	}
10460 
10461 	/* if the entity has not been deleted, refresh it */
10462 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
10463 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
10464 		    name_buf);
10465 	}
10466 
10467 out:
10468 	if (isservice && (inst != NULL && iter != NULL)) {
10469 		free(name_buf);
10470 		scf_iter_destroy(iter);
10471 		scf_instance_destroy(inst);
10472 	}
10473 
10474 	if (!isservice && svc != NULL) {
10475 		scf_service_destroy(svc);
10476 	}
10477 
10478 	scf_pg_destroy(pg);
10479 	if (entity != NULL)
10480 		entity_destroy(entity, isservice);
10481 
10482 	return (result);
10483 }
10484 
10485 static int
10486 delete_dependents(scf_propertygroup_t *pg)
10487 {
10488 	char *pgty, *name, *fmri;
10489 	scf_property_t *prop;
10490 	scf_value_t *val;
10491 	scf_iter_t *iter;
10492 	int r;
10493 	scf_error_t err;
10494 
10495 	/* Verify that the pg has the correct type. */
10496 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10497 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10498 		scfdie();
10499 
10500 	if (strcmp(pgty, scf_group_framework) != 0) {
10501 		if (g_verbose) {
10502 			fmri = safe_malloc(max_scf_fmri_len + 1);
10503 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
10504 				scfdie();
10505 
10506 			warn(gettext("Property group %s is not of expected "
10507 			    "type %s.\n"), fmri, scf_group_framework);
10508 
10509 			free(fmri);
10510 		}
10511 
10512 		free(pgty);
10513 		return (-1);
10514 	}
10515 
10516 	free(pgty);
10517 
10518 	/* map delete_dependency_pg onto the properties. */
10519 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10520 	    (val = scf_value_create(g_hndl)) == NULL ||
10521 	    (iter = scf_iter_create(g_hndl)) == NULL)
10522 		scfdie();
10523 
10524 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10525 		scfdie();
10526 
10527 	name = safe_malloc(max_scf_name_len + 1);
10528 	fmri = safe_malloc(max_scf_fmri_len + 2);
10529 
10530 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
10531 		scf_type_t ty;
10532 
10533 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
10534 			scfdie();
10535 
10536 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
10537 			scfdie();
10538 
10539 		if ((ty != SCF_TYPE_ASTRING &&
10540 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
10541 		    prop_get_val(prop, val) != 0)
10542 			continue;
10543 
10544 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
10545 			scfdie();
10546 
10547 		err = delete_dependency_pg(fmri, name);
10548 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
10549 			if (scf_property_to_fmri(prop, fmri,
10550 			    max_scf_fmri_len + 2) < 0)
10551 				scfdie();
10552 
10553 			warn(gettext("Value of %s is not a valid FMRI.\n"),
10554 			    fmri);
10555 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
10556 			warn(gettext("Property group \"%s\" of entity \"%s\" "
10557 			    "does not have dependency type.\n"), name, fmri);
10558 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
10559 			warn(gettext("Could not delete property group \"%s\" "
10560 			    "of entity \"%s\" (permission denied).\n"), name,
10561 			    fmri);
10562 		}
10563 	}
10564 	if (r == -1)
10565 		scfdie();
10566 
10567 	scf_value_destroy(val);
10568 	scf_property_destroy(prop);
10569 
10570 	return (0);
10571 }
10572 
10573 /*
10574  * Returns 1 if the instance may be running, and 0 otherwise.
10575  */
10576 static int
10577 inst_is_running(scf_instance_t *inst)
10578 {
10579 	scf_propertygroup_t *pg;
10580 	scf_property_t *prop;
10581 	scf_value_t *val;
10582 	char buf[MAX_SCF_STATE_STRING_SZ];
10583 	int ret = 0;
10584 	ssize_t szret;
10585 
10586 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10587 	    (prop = scf_property_create(g_hndl)) == NULL ||
10588 	    (val = scf_value_create(g_hndl)) == NULL)
10589 		scfdie();
10590 
10591 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
10592 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10593 			scfdie();
10594 		goto out;
10595 	}
10596 
10597 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
10598 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
10599 	    prop_get_val(prop, val) != 0)
10600 		goto out;
10601 
10602 	szret = scf_value_get_astring(val, buf, sizeof (buf));
10603 	assert(szret >= 0);
10604 
10605 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
10606 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
10607 
10608 out:
10609 	scf_value_destroy(val);
10610 	scf_property_destroy(prop);
10611 	scf_pg_destroy(pg);
10612 	return (ret);
10613 }
10614 
10615 static uint8_t
10616 pg_is_external_dependency(scf_propertygroup_t *pg)
10617 {
10618 	char *type;
10619 	scf_value_t *val;
10620 	scf_property_t *prop;
10621 	uint8_t b = B_FALSE;
10622 
10623 	type = safe_malloc(max_scf_pg_type_len + 1);
10624 
10625 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
10626 		scfdie();
10627 
10628 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10629 	    (val = scf_value_create(g_hndl)) == NULL)
10630 		scfdie();
10631 
10632 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
10633 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
10634 			if (scf_property_get_value(prop, val) != 0)
10635 				scfdie();
10636 			if (scf_value_get_boolean(val, &b) != 0)
10637 				scfdie();
10638 		}
10639 	}
10640 
10641 	free(type);
10642 	(void) scf_value_destroy(val);
10643 	(void) scf_property_destroy(prop);
10644 
10645 	return (b);
10646 }
10647 
10648 #define	DELETE_FAILURE			-1
10649 #define	DELETE_SUCCESS_NOEXTDEPS	0
10650 #define	DELETE_SUCCESS_EXTDEPS		1
10651 
10652 /*
10653  * lscf_instance_delete() deletes an instance.  Before calling
10654  * scf_instance_delete(), though, we make sure the instance isn't
10655  * running and delete dependencies in other entities which the instance
10656  * declared as "dependents".  If there are dependencies which were
10657  * created for other entities, then instead of deleting the instance we
10658  * make it "empty" by deleting all other property groups and all
10659  * snapshots.
10660  *
10661  * lscf_instance_delete() verifies that there is no external dependency pgs
10662  * before suppressing the instance. If there is, then we must not remove them
10663  * now in case the instance is re-created otherwise the dependencies would be
10664  * lost. The external dependency pgs will be removed if the dependencies are
10665  * removed.
10666  *
10667  * Returns:
10668  *  DELETE_FAILURE		on failure
10669  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
10670  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
10671  */
10672 static int
10673 lscf_instance_delete(scf_instance_t *inst, int force)
10674 {
10675 	scf_propertygroup_t *pg;
10676 	scf_snapshot_t *snap;
10677 	scf_iter_t *iter;
10678 	int err;
10679 	int external = 0;
10680 
10681 	/* If we're not forcing and the instance is running, refuse. */
10682 	if (!force && inst_is_running(inst)) {
10683 		char *fmri;
10684 
10685 		fmri = safe_malloc(max_scf_fmri_len + 1);
10686 
10687 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
10688 			scfdie();
10689 
10690 		semerr(gettext("Instance %s may be running.  "
10691 		    "Use delete -f if it is not.\n"), fmri);
10692 
10693 		free(fmri);
10694 		return (DELETE_FAILURE);
10695 	}
10696 
10697 	pg = scf_pg_create(g_hndl);
10698 	if (pg == NULL)
10699 		scfdie();
10700 
10701 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
10702 		(void) delete_dependents(pg);
10703 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
10704 		scfdie();
10705 
10706 	scf_pg_destroy(pg);
10707 
10708 	/*
10709 	 * If the instance has some external dependencies then we must
10710 	 * keep them in case the instance is reimported otherwise the
10711 	 * dependencies would be lost on reimport.
10712 	 */
10713 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10714 	    (pg = scf_pg_create(g_hndl)) == NULL)
10715 		scfdie();
10716 
10717 	if (scf_iter_instance_pgs(iter, inst) < 0)
10718 		scfdie();
10719 
10720 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10721 		if (pg_is_external_dependency(pg)) {
10722 			external = 1;
10723 			continue;
10724 		}
10725 
10726 		if (scf_pg_delete(pg) != 0) {
10727 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10728 				scfdie();
10729 			else {
10730 				semerr(emsg_permission_denied);
10731 
10732 				(void) scf_iter_destroy(iter);
10733 				(void) scf_pg_destroy(pg);
10734 				return (DELETE_FAILURE);
10735 			}
10736 		}
10737 	}
10738 
10739 	if (err == -1)
10740 		scfdie();
10741 
10742 	(void) scf_iter_destroy(iter);
10743 	(void) scf_pg_destroy(pg);
10744 
10745 	if (external) {
10746 		/*
10747 		 * All the pgs have been deleted for the instance except
10748 		 * the ones holding the external dependencies.
10749 		 * For the job to be complete, we must also delete the
10750 		 * snapshots associated with the instance.
10751 		 */
10752 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
10753 		    NULL)
10754 			scfdie();
10755 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
10756 			scfdie();
10757 
10758 		if (scf_iter_instance_snapshots(iter, inst) == -1)
10759 			scfdie();
10760 
10761 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
10762 			if (_scf_snapshot_delete(snap) != 0) {
10763 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10764 					scfdie();
10765 
10766 				semerr(emsg_permission_denied);
10767 
10768 				(void) scf_iter_destroy(iter);
10769 				(void) scf_snapshot_destroy(snap);
10770 				return (DELETE_FAILURE);
10771 			}
10772 		}
10773 
10774 		if (err == -1)
10775 			scfdie();
10776 
10777 		(void) scf_iter_destroy(iter);
10778 		(void) scf_snapshot_destroy(snap);
10779 		return (DELETE_SUCCESS_EXTDEPS);
10780 	}
10781 
10782 	if (scf_instance_delete(inst) != 0) {
10783 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10784 			scfdie();
10785 
10786 		semerr(emsg_permission_denied);
10787 
10788 		return (DELETE_FAILURE);
10789 	}
10790 
10791 	return (DELETE_SUCCESS_NOEXTDEPS);
10792 }
10793 
10794 /*
10795  * lscf_service_delete() deletes a service.  Before calling
10796  * scf_service_delete(), though, we call lscf_instance_delete() for
10797  * each of the instances and delete dependencies in other entities
10798  * which were created as "dependents" of this service.  If there are
10799  * dependencies which were created for other entities, then we delete
10800  * all other property groups in the service and leave it as "empty".
10801  *
10802  * lscf_service_delete() verifies that there is no external dependency
10803  * pgs at the instance & service level before suppressing the service.
10804  * If there is, then we must not remove them now in case the service
10805  * is re-imported otherwise the dependencies would be lost. The external
10806  * dependency pgs will be removed if the dependencies are removed.
10807  *
10808  * Returns:
10809  *   DELETE_FAILURE		on failure
10810  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
10811  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
10812  */
10813 static int
10814 lscf_service_delete(scf_service_t *svc, int force)
10815 {
10816 	int r;
10817 	scf_instance_t *inst;
10818 	scf_propertygroup_t *pg;
10819 	scf_iter_t *iter;
10820 	int ret;
10821 	int external = 0;
10822 
10823 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10824 	    (pg = scf_pg_create(g_hndl)) == NULL ||
10825 	    (iter = scf_iter_create(g_hndl)) == NULL)
10826 		scfdie();
10827 
10828 	if (scf_iter_service_instances(iter, svc) != 0)
10829 		scfdie();
10830 
10831 	for (r = scf_iter_next_instance(iter, inst);
10832 	    r == 1;
10833 	    r = scf_iter_next_instance(iter, inst)) {
10834 
10835 		ret = lscf_instance_delete(inst, force);
10836 		if (ret == DELETE_FAILURE) {
10837 			scf_iter_destroy(iter);
10838 			scf_pg_destroy(pg);
10839 			scf_instance_destroy(inst);
10840 			return (DELETE_FAILURE);
10841 		}
10842 
10843 		/*
10844 		 * Record the fact that there is some external dependencies
10845 		 * at the instance level.
10846 		 */
10847 		if (ret == DELETE_SUCCESS_EXTDEPS)
10848 			external |= 1;
10849 	}
10850 
10851 	if (r != 0)
10852 		scfdie();
10853 
10854 	/* Delete dependency property groups in dependent services. */
10855 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
10856 		(void) delete_dependents(pg);
10857 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
10858 		scfdie();
10859 
10860 	scf_iter_destroy(iter);
10861 	scf_pg_destroy(pg);
10862 	scf_instance_destroy(inst);
10863 
10864 	/*
10865 	 * If the service has some external dependencies then we don't
10866 	 * want to remove them in case the service is re-imported.
10867 	 */
10868 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10869 	    (iter = scf_iter_create(g_hndl)) == NULL)
10870 		scfdie();
10871 
10872 	if (scf_iter_service_pgs(iter, svc) < 0)
10873 		scfdie();
10874 
10875 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
10876 		if (pg_is_external_dependency(pg)) {
10877 			external |= 2;
10878 			continue;
10879 		}
10880 
10881 		if (scf_pg_delete(pg) != 0) {
10882 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10883 				scfdie();
10884 			else {
10885 				semerr(emsg_permission_denied);
10886 
10887 				(void) scf_iter_destroy(iter);
10888 				(void) scf_pg_destroy(pg);
10889 				return (DELETE_FAILURE);
10890 			}
10891 		}
10892 	}
10893 
10894 	if (r == -1)
10895 		scfdie();
10896 
10897 	(void) scf_iter_destroy(iter);
10898 	(void) scf_pg_destroy(pg);
10899 
10900 	if (external != 0)
10901 		return (DELETE_SUCCESS_EXTDEPS);
10902 
10903 	if (scf_service_delete(svc) == 0)
10904 		return (DELETE_SUCCESS_NOEXTDEPS);
10905 
10906 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10907 		scfdie();
10908 
10909 	semerr(emsg_permission_denied);
10910 	return (DELETE_FAILURE);
10911 }
10912 
10913 static int
10914 delete_callback(void *data, scf_walkinfo_t *wip)
10915 {
10916 	int force = (int)data;
10917 
10918 	if (wip->inst != NULL)
10919 		(void) lscf_instance_delete(wip->inst, force);
10920 	else
10921 		(void) lscf_service_delete(wip->svc, force);
10922 
10923 	return (0);
10924 }
10925 
10926 void
10927 lscf_delete(const char *fmri, int force)
10928 {
10929 	scf_service_t *svc;
10930 	scf_instance_t *inst;
10931 	int ret;
10932 
10933 	lscf_prep_hndl();
10934 
10935 	if (cur_snap != NULL) {
10936 		if (!snaplevel_is_instance(cur_level)) {
10937 			char *buf;
10938 
10939 			buf = safe_malloc(max_scf_name_len + 1);
10940 			if (scf_instance_get_name(cur_inst, buf,
10941 			    max_scf_name_len + 1) >= 0) {
10942 				if (strcmp(buf, fmri) == 0) {
10943 					semerr(emsg_cant_modify_snapshots);
10944 					free(buf);
10945 					return;
10946 				}
10947 			} else if (scf_error() != SCF_ERROR_DELETED) {
10948 				scfdie();
10949 			}
10950 			free(buf);
10951 		}
10952 	} else if (cur_inst != NULL) {
10953 		/* EMPTY */;
10954 	} else if (cur_svc != NULL) {
10955 		inst = scf_instance_create(g_hndl);
10956 		if (inst == NULL)
10957 			scfdie();
10958 
10959 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
10960 		    SCF_SUCCESS) {
10961 			(void) lscf_instance_delete(inst, force);
10962 			scf_instance_destroy(inst);
10963 			return;
10964 		}
10965 
10966 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
10967 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
10968 			scfdie();
10969 
10970 		scf_instance_destroy(inst);
10971 	} else {
10972 		assert(cur_scope != NULL);
10973 
10974 		svc = scf_service_create(g_hndl);
10975 		if (svc == NULL)
10976 			scfdie();
10977 
10978 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
10979 		    SCF_SUCCESS) {
10980 			(void) lscf_service_delete(svc, force);
10981 			scf_service_destroy(svc);
10982 			return;
10983 		}
10984 
10985 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
10986 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
10987 			scfdie();
10988 
10989 		scf_service_destroy(svc);
10990 	}
10991 
10992 	/*
10993 	 * Match FMRI to entity.
10994 	 */
10995 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
10996 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
10997 		semerr(gettext("Failed to walk instances: %s\n"),
10998 		    scf_strerror(ret));
10999 	}
11000 }
11001 
11002 
11003 
11004 /*
11005  * :properties commands.  These all end with "pg" or "prop" and generally
11006  * operate on the currently selected entity.
11007  */
11008 
11009 /*
11010  * Property listing.  List the property groups, properties, their types and
11011  * their values for the currently selected entity.
11012  */
11013 static void
11014 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
11015 {
11016 	char *buf;
11017 	uint32_t flags;
11018 
11019 	buf = safe_malloc(max_scf_pg_type_len + 1);
11020 
11021 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
11022 		scfdie();
11023 
11024 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
11025 		scfdie();
11026 
11027 	safe_printf("%-*s  %s", namewidth, name, buf);
11028 
11029 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
11030 		safe_printf("\tNONPERSISTENT");
11031 
11032 	safe_printf("\n");
11033 
11034 	free(buf);
11035 }
11036 
11037 static boolean_t
11038 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
11039 {
11040 	if (scf_property_get_value(prop, val) == 0) {
11041 		return (B_FALSE);
11042 	} else {
11043 		switch (scf_error()) {
11044 		case SCF_ERROR_NOT_FOUND:
11045 			return (B_FALSE);
11046 		case SCF_ERROR_PERMISSION_DENIED:
11047 		case SCF_ERROR_CONSTRAINT_VIOLATED:
11048 			return (B_TRUE);
11049 		default:
11050 			scfdie();
11051 			/*NOTREACHED*/
11052 		}
11053 	}
11054 }
11055 
11056 static void
11057 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
11058 {
11059 	scf_iter_t *iter;
11060 	scf_value_t *val;
11061 	const char *type;
11062 	int multiple_strings = 0;
11063 	int ret;
11064 
11065 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11066 	    (val = scf_value_create(g_hndl)) == NULL)
11067 		scfdie();
11068 
11069 	type = prop_to_typestr(prop);
11070 	assert(type != NULL);
11071 
11072 	safe_printf("%-*s  %-7s ", len, name, type);
11073 
11074 	if (prop_has_multiple_values(prop, val) &&
11075 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
11076 	    scf_value_type(val) == SCF_TYPE_USTRING))
11077 		multiple_strings = 1;
11078 
11079 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11080 		scfdie();
11081 
11082 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11083 		char *buf;
11084 		ssize_t vlen, szret;
11085 
11086 		vlen = scf_value_get_as_string(val, NULL, 0);
11087 		if (vlen < 0)
11088 			scfdie();
11089 
11090 		buf = safe_malloc(vlen + 1);
11091 
11092 		szret = scf_value_get_as_string(val, buf, vlen + 1);
11093 		if (szret < 0)
11094 			scfdie();
11095 		assert(szret <= vlen);
11096 
11097 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11098 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
11099 			safe_printf(" \"");
11100 			(void) quote_and_print(buf, stdout, 0);
11101 			(void) putchar('"');
11102 			if (ferror(stdout)) {
11103 				(void) putchar('\n');
11104 				uu_die(gettext("Error writing to stdout.\n"));
11105 			}
11106 		} else {
11107 			safe_printf(" %s", buf);
11108 		}
11109 
11110 		free(buf);
11111 	}
11112 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11113 		scfdie();
11114 
11115 	if (putchar('\n') != '\n')
11116 		uu_die(gettext("Could not output newline"));
11117 }
11118 
11119 /*
11120  * Outputs template property group info for the describe subcommand.
11121  * If 'templates' == 2, verbose output is printed in the format expected
11122  * for describe -v, which includes all templates fields.  If pg is
11123  * not NULL, we're describing the template data, not an existing property
11124  * group, and formatting should be appropriate for describe -t.
11125  */
11126 static void
11127 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
11128 {
11129 	char *buf;
11130 	uint8_t required;
11131 	scf_property_t *stability_prop;
11132 	scf_value_t *stability_val;
11133 
11134 	if (templates == 0)
11135 		return;
11136 
11137 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
11138 	    (stability_val = scf_value_create(g_hndl)) == NULL)
11139 		scfdie();
11140 
11141 	if (templates == 2 && pg != NULL) {
11142 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
11143 		    stability_prop) == 0) {
11144 			if (prop_check_type(stability_prop,
11145 			    SCF_TYPE_ASTRING) == 0 &&
11146 			    prop_get_val(stability_prop, stability_val) == 0) {
11147 				char *stability;
11148 
11149 				stability = safe_malloc(max_scf_value_len + 1);
11150 
11151 				if (scf_value_get_astring(stability_val,
11152 				    stability, max_scf_value_len + 1) == -1 &&
11153 				    scf_error() != SCF_ERROR_NOT_FOUND)
11154 					scfdie();
11155 
11156 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11157 				    gettext("stability"), stability);
11158 
11159 				free(stability);
11160 			}
11161 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
11162 			scfdie();
11163 	}
11164 
11165 	scf_property_destroy(stability_prop);
11166 	scf_value_destroy(stability_val);
11167 
11168 	if (pgt == NULL)
11169 		return;
11170 
11171 	if (pg == NULL || templates == 2) {
11172 		/* print type info only if scf_tmpl_pg_name succeeds */
11173 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
11174 			if (pg != NULL)
11175 				safe_printf("%s", TMPL_INDENT);
11176 			safe_printf("%s: ", gettext("name"));
11177 			safe_printf("%s\n", buf);
11178 			free(buf);
11179 		}
11180 
11181 		/* print type info only if scf_tmpl_pg_type succeeds */
11182 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
11183 			if (pg != NULL)
11184 				safe_printf("%s", TMPL_INDENT);
11185 			safe_printf("%s: ", gettext("type"));
11186 			safe_printf("%s\n", buf);
11187 			free(buf);
11188 		}
11189 	}
11190 
11191 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
11192 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11193 		    required ? "true" : "false");
11194 
11195 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
11196 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
11197 		    buf);
11198 		free(buf);
11199 	}
11200 
11201 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
11202 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11203 		    buf);
11204 		free(buf);
11205 	}
11206 
11207 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
11208 		if (templates == 2)
11209 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11210 			    gettext("description"), buf);
11211 		else
11212 			safe_printf("%s%s\n", TMPL_INDENT, buf);
11213 		free(buf);
11214 	}
11215 
11216 }
11217 
11218 /*
11219  * With as_value set to true, indent as appropriate for the value level.
11220  * If false, indent to appropriate level for inclusion in constraint
11221  * or choice printout.
11222  */
11223 static void
11224 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
11225     int as_value)
11226 {
11227 	char *buf;
11228 
11229 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
11230 		if (as_value == 0)
11231 			safe_printf("%s", TMPL_CHOICE_INDENT);
11232 		else
11233 			safe_printf("%s", TMPL_INDENT);
11234 		safe_printf("%s: %s\n", gettext("value common name"), buf);
11235 		free(buf);
11236 	}
11237 
11238 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
11239 		if (as_value == 0)
11240 			safe_printf("%s", TMPL_CHOICE_INDENT);
11241 		else
11242 			safe_printf("%s", TMPL_INDENT);
11243 		safe_printf("%s: %s\n", gettext("value description"), buf);
11244 		free(buf);
11245 	}
11246 }
11247 
11248 static void
11249 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
11250 {
11251 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
11252 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11253 	safe_printf("%s\n", val_buf);
11254 
11255 	print_template_value_details(prt, val_buf, 1);
11256 }
11257 
11258 static void
11259 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
11260 {
11261 	int i, printed = 0;
11262 	scf_values_t values;
11263 	scf_count_ranges_t c_ranges;
11264 	scf_int_ranges_t i_ranges;
11265 
11266 	printed = 0;
11267 	i = 0;
11268 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
11269 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11270 		    gettext("value constraints"));
11271 		printed++;
11272 		for (i = 0; i < values.value_count; ++i) {
11273 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11274 			    gettext("value name"), values.values_as_strings[i]);
11275 			if (verbose == 1)
11276 				print_template_value_details(prt,
11277 				    values.values_as_strings[i], 0);
11278 		}
11279 
11280 		scf_values_destroy(&values);
11281 	}
11282 
11283 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
11284 		if (printed++ == 0)
11285 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11286 			    gettext("value constraints"));
11287 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11288 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11289 			    gettext("range"), c_ranges.scr_min[i],
11290 			    c_ranges.scr_max[i]);
11291 		}
11292 		scf_count_ranges_destroy(&c_ranges);
11293 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11294 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
11295 		if (printed++ == 0)
11296 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11297 			    gettext("value constraints"));
11298 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11299 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11300 			    gettext("range"), i_ranges.sir_min[i],
11301 			    i_ranges.sir_max[i]);
11302 		}
11303 		scf_int_ranges_destroy(&i_ranges);
11304 	}
11305 }
11306 
11307 static void
11308 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
11309 {
11310 	int i = 0, printed = 0;
11311 	scf_values_t values;
11312 	scf_count_ranges_t c_ranges;
11313 	scf_int_ranges_t i_ranges;
11314 
11315 	printed = 0;
11316 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
11317 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11318 		    gettext("value constraints"));
11319 		printed++;
11320 		for (i = 0; i < values.value_count; i++) {
11321 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11322 			    gettext("value name"), values.values_as_strings[i]);
11323 			if (verbose == 1)
11324 				print_template_value_details(prt,
11325 				    values.values_as_strings[i], 0);
11326 		}
11327 
11328 		scf_values_destroy(&values);
11329 	}
11330 
11331 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
11332 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11333 			if (printed++ == 0)
11334 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11335 				    gettext("value choices"));
11336 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11337 			    gettext("range"), c_ranges.scr_min[i],
11338 			    c_ranges.scr_max[i]);
11339 		}
11340 		scf_count_ranges_destroy(&c_ranges);
11341 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11342 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
11343 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11344 			if (printed++ == 0)
11345 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11346 				    gettext("value choices"));
11347 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11348 			    gettext("range"), i_ranges.sir_min[i],
11349 			    i_ranges.sir_max[i]);
11350 		}
11351 		scf_int_ranges_destroy(&i_ranges);
11352 	}
11353 }
11354 
11355 static void
11356 list_values_by_template(scf_prop_tmpl_t *prt)
11357 {
11358 	print_template_constraints(prt, 1);
11359 	print_template_choices(prt, 1);
11360 }
11361 
11362 static void
11363 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
11364 {
11365 	char *val_buf;
11366 	scf_iter_t *iter;
11367 	scf_value_t *val;
11368 	int ret;
11369 
11370 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11371 	    (val = scf_value_create(g_hndl)) == NULL)
11372 		scfdie();
11373 
11374 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11375 		scfdie();
11376 
11377 	val_buf = safe_malloc(max_scf_value_len + 1);
11378 
11379 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11380 		if (scf_value_get_as_string(val, val_buf,
11381 		    max_scf_value_len + 1) < 0)
11382 			scfdie();
11383 
11384 		print_template_value(prt, val_buf);
11385 	}
11386 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11387 		scfdie();
11388 	free(val_buf);
11389 
11390 	print_template_constraints(prt, 0);
11391 	print_template_choices(prt, 0);
11392 
11393 }
11394 
11395 /*
11396  * Outputs property info for the describe subcommand
11397  * Verbose output if templates == 2, -v option of svccfg describe
11398  * Displays template data if prop is not NULL, -t option of svccfg describe
11399  */
11400 static void
11401 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
11402 {
11403 	char *buf;
11404 	uint8_t u_buf;
11405 	int i;
11406 	uint64_t min, max;
11407 	scf_values_t values;
11408 
11409 	if (prt == NULL || templates == 0)
11410 		return;
11411 
11412 	if (prop == NULL) {
11413 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
11414 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
11415 			safe_printf("%s\n", buf);
11416 			free(buf);
11417 		} else
11418 			safe_printf("(%s)\n", gettext("any"));
11419 	}
11420 
11421 	if (prop == NULL || templates == 2) {
11422 		if (prop != NULL)
11423 			safe_printf("%s", TMPL_INDENT);
11424 		else
11425 			safe_printf("%s", TMPL_VALUE_INDENT);
11426 		safe_printf("%s: ", gettext("type"));
11427 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
11428 			safe_printf("%s\n", buf);
11429 			free(buf);
11430 		} else
11431 			safe_printf("(%s)\n", gettext("any"));
11432 	}
11433 
11434 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
11435 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11436 		    u_buf ? "true" : "false");
11437 
11438 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
11439 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11440 		    buf);
11441 		free(buf);
11442 	}
11443 
11444 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
11445 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
11446 		    buf);
11447 		free(buf);
11448 	}
11449 
11450 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
11451 		safe_printf("%s%s\n", TMPL_INDENT, buf);
11452 		free(buf);
11453 	}
11454 
11455 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
11456 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
11457 		    scf_tmpl_visibility_to_string(u_buf));
11458 
11459 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
11460 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11461 		    gettext("minimum number of values"), min);
11462 		if (max == ULLONG_MAX) {
11463 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11464 			    gettext("maximum number of values"),
11465 			    gettext("unlimited"));
11466 		} else {
11467 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11468 			    gettext("maximum number of values"), max);
11469 		}
11470 	}
11471 
11472 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
11473 		for (i = 0; i < values.value_count; i++) {
11474 			if (i == 0) {
11475 				safe_printf("%s%s:", TMPL_INDENT,
11476 				    gettext("internal separators"));
11477 			}
11478 			safe_printf(" \"%s\"", values.values_as_strings[i]);
11479 		}
11480 		safe_printf("\n");
11481 	}
11482 
11483 	if (templates != 2)
11484 		return;
11485 
11486 	if (prop != NULL)
11487 		list_values_tmpl(prt, prop);
11488 	else
11489 		list_values_by_template(prt);
11490 }
11491 
11492 static char *
11493 read_astring(scf_propertygroup_t *pg, const char *prop_name)
11494 {
11495 	char *rv;
11496 
11497 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
11498 	if (rv == NULL) {
11499 		switch (scf_error()) {
11500 		case SCF_ERROR_NOT_FOUND:
11501 			break;
11502 		default:
11503 			scfdie();
11504 		}
11505 	}
11506 	return (rv);
11507 }
11508 
11509 static void
11510 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
11511 {
11512 	size_t doc_len;
11513 	size_t man_len;
11514 	char *pg_name;
11515 	char *text = NULL;
11516 	int rv;
11517 
11518 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
11519 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
11520 	pg_name = safe_malloc(max_scf_name_len + 1);
11521 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
11522 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
11523 			scfdie();
11524 		}
11525 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
11526 			/* Display doc_link and and uri */
11527 			safe_printf("%s%s:\n", TMPL_INDENT,
11528 			    gettext("doc_link"));
11529 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
11530 			if (text != NULL) {
11531 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11532 				    TMPL_INDENT, gettext("name"), text);
11533 				uu_free(text);
11534 			}
11535 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
11536 			if (text != NULL) {
11537 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
11538 				    gettext("uri"), text);
11539 				uu_free(text);
11540 			}
11541 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
11542 		    man_len) == 0) {
11543 			/* Display manpage title, section and path */
11544 			safe_printf("%s%s:\n", TMPL_INDENT,
11545 			    gettext("manpage"));
11546 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
11547 			if (text != NULL) {
11548 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11549 				    TMPL_INDENT, gettext("title"), text);
11550 				uu_free(text);
11551 			}
11552 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
11553 			if (text != NULL) {
11554 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11555 				    TMPL_INDENT, gettext("section"), text);
11556 				uu_free(text);
11557 			}
11558 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
11559 			if (text != NULL) {
11560 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11561 				    TMPL_INDENT, gettext("manpath"), text);
11562 				uu_free(text);
11563 			}
11564 		}
11565 	}
11566 	if (rv == -1)
11567 		scfdie();
11568 
11569 done:
11570 	free(pg_name);
11571 }
11572 
11573 static void
11574 list_entity_tmpl(int templates)
11575 {
11576 	char *common_name = NULL;
11577 	char *description = NULL;
11578 	char *locale = NULL;
11579 	scf_iter_t *iter;
11580 	scf_propertygroup_t *pg;
11581 	scf_property_t *prop;
11582 	int r;
11583 	scf_value_t *val;
11584 
11585 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11586 	    (prop = scf_property_create(g_hndl)) == NULL ||
11587 	    (val = scf_value_create(g_hndl)) == NULL ||
11588 	    (iter = scf_iter_create(g_hndl)) == NULL)
11589 		scfdie();
11590 
11591 	locale = setlocale(LC_MESSAGES, NULL);
11592 
11593 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
11594 		common_name = safe_malloc(max_scf_value_len + 1);
11595 
11596 		/* Try both the current locale and the "C" locale. */
11597 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
11598 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
11599 		    scf_pg_get_property(pg, "C", prop) == 0)) {
11600 			if (prop_get_val(prop, val) == 0 &&
11601 			    scf_value_get_ustring(val, common_name,
11602 			    max_scf_value_len + 1) != -1) {
11603 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11604 				    gettext("common name"), common_name);
11605 			}
11606 		}
11607 	}
11608 
11609 	/*
11610 	 * Do description, manpages, and doc links if templates == 2.
11611 	 */
11612 	if (templates == 2) {
11613 		/* Get the description. */
11614 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
11615 			description = safe_malloc(max_scf_value_len + 1);
11616 
11617 			/* Try both the current locale and the "C" locale. */
11618 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
11619 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
11620 			    scf_pg_get_property(pg, "C", prop) == 0)) {
11621 				if (prop_get_val(prop, val) == 0 &&
11622 				    scf_value_get_ustring(val, description,
11623 				    max_scf_value_len + 1) != -1) {
11624 					safe_printf("%s%s: %s\n", TMPL_INDENT,
11625 					    gettext("description"),
11626 					    description);
11627 				}
11628 			}
11629 		}
11630 
11631 		/* Process doc_link & manpage elements. */
11632 		if (cur_level != NULL) {
11633 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
11634 			    SCF_GROUP_TEMPLATE);
11635 		} else if (cur_inst != NULL) {
11636 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
11637 			    SCF_GROUP_TEMPLATE);
11638 		} else {
11639 			r = scf_iter_service_pgs_typed(iter, cur_svc,
11640 			    SCF_GROUP_TEMPLATE);
11641 		}
11642 		if (r == 0) {
11643 			display_documentation(iter, pg);
11644 		}
11645 	}
11646 
11647 	free(common_name);
11648 	free(description);
11649 	scf_pg_destroy(pg);
11650 	scf_property_destroy(prop);
11651 	scf_value_destroy(val);
11652 	scf_iter_destroy(iter);
11653 }
11654 
11655 static void
11656 listtmpl(const char *pattern, int templates)
11657 {
11658 	scf_pg_tmpl_t *pgt;
11659 	scf_prop_tmpl_t *prt;
11660 	char *snapbuf = NULL;
11661 	char *fmribuf;
11662 	char *pg_name = NULL, *prop_name = NULL;
11663 	ssize_t prop_name_size;
11664 	char *qual_prop_name;
11665 	char *search_name;
11666 	int listed = 0;
11667 
11668 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
11669 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
11670 		scfdie();
11671 
11672 	fmribuf = safe_malloc(max_scf_name_len + 1);
11673 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
11674 
11675 	if (cur_snap != NULL) {
11676 		snapbuf = safe_malloc(max_scf_name_len + 1);
11677 		if (scf_snapshot_get_name(cur_snap, snapbuf,
11678 		    max_scf_name_len + 1) < 0)
11679 			scfdie();
11680 	}
11681 
11682 	if (cur_inst != NULL) {
11683 		if (scf_instance_to_fmri(cur_inst, fmribuf,
11684 		    max_scf_name_len + 1) < 0)
11685 			scfdie();
11686 	} else if (cur_svc != NULL) {
11687 		if (scf_service_to_fmri(cur_svc, fmribuf,
11688 		    max_scf_name_len + 1) < 0)
11689 			scfdie();
11690 	} else
11691 		abort();
11692 
11693 	/* If pattern is specified, we want to list only those items. */
11694 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
11695 		listed = 0;
11696 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
11697 		    fnmatch(pattern, pg_name, 0) == 0)) {
11698 			list_pg_tmpl(pgt, NULL, templates);
11699 			listed++;
11700 		}
11701 
11702 		scf_tmpl_prop_reset(prt);
11703 
11704 		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
11705 			search_name = NULL;
11706 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
11707 			if ((prop_name_size > 0) && (pg_name != NULL)) {
11708 				if (snprintf(qual_prop_name,
11709 				    max_scf_name_len + 1, "%s/%s",
11710 				    pg_name, prop_name) >=
11711 				    max_scf_name_len + 1) {
11712 					prop_name_size = -1;
11713 				} else {
11714 					search_name = qual_prop_name;
11715 				}
11716 			}
11717 			if (listed > 0 || pattern == NULL ||
11718 			    (prop_name_size > 0 &&
11719 			    fnmatch(pattern, search_name,
11720 			    FNM_PATHNAME) == 0))
11721 				list_prop_tmpl(prt, NULL, templates);
11722 			if (prop_name != NULL) {
11723 				free(prop_name);
11724 				prop_name = NULL;
11725 			}
11726 		}
11727 		if (pg_name != NULL) {
11728 			free(pg_name);
11729 			pg_name = NULL;
11730 		}
11731 	}
11732 
11733 	scf_tmpl_prop_destroy(prt);
11734 	scf_tmpl_pg_destroy(pgt);
11735 	free(snapbuf);
11736 	free(fmribuf);
11737 	free(qual_prop_name);
11738 }
11739 
11740 static void
11741 listprop(const char *pattern, int only_pgs, int templates)
11742 {
11743 	scf_propertygroup_t *pg;
11744 	scf_property_t *prop;
11745 	scf_iter_t *iter, *piter;
11746 	char *pgnbuf, *prnbuf, *ppnbuf;
11747 	scf_pg_tmpl_t *pgt, *pgtp;
11748 	scf_prop_tmpl_t *prt;
11749 
11750 	void **objects;
11751 	char **names;
11752 	void **tmpls;
11753 	int allocd, i;
11754 
11755 	int ret;
11756 	ssize_t pgnlen, prnlen, szret;
11757 	size_t max_len = 0;
11758 
11759 	if (cur_svc == NULL && cur_inst == NULL) {
11760 		semerr(emsg_entity_not_selected);
11761 		return;
11762 	}
11763 
11764 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11765 	    (prop = scf_property_create(g_hndl)) == NULL ||
11766 	    (iter = scf_iter_create(g_hndl)) == NULL ||
11767 	    (piter = scf_iter_create(g_hndl)) == NULL ||
11768 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
11769 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
11770 		scfdie();
11771 
11772 	prnbuf = safe_malloc(max_scf_name_len + 1);
11773 
11774 	if (cur_level != NULL)
11775 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
11776 	else if (cur_inst != NULL)
11777 		ret = scf_iter_instance_pgs(iter, cur_inst);
11778 	else
11779 		ret = scf_iter_service_pgs(iter, cur_svc);
11780 	if (ret != 0) {
11781 		return;
11782 	}
11783 
11784 	/*
11785 	 * We want to only list items which match pattern, and we want the
11786 	 * second column to line up, so during the first pass we'll save
11787 	 * matching items, their names, and their templates in objects,
11788 	 * names, and tmpls, computing the maximum name length as we go,
11789 	 * and then we'll print them out.
11790 	 *
11791 	 * Note: We always keep an extra slot available so the array can be
11792 	 * NULL-terminated.
11793 	 */
11794 	i = 0;
11795 	allocd = 1;
11796 	objects = safe_malloc(sizeof (*objects));
11797 	names = safe_malloc(sizeof (*names));
11798 	tmpls = safe_malloc(sizeof (*tmpls));
11799 
11800 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
11801 		int new_pg = 0;
11802 		int print_props = 0;
11803 		pgtp = NULL;
11804 
11805 		pgnlen = scf_pg_get_name(pg, NULL, 0);
11806 		if (pgnlen < 0)
11807 			scfdie();
11808 
11809 		pgnbuf = safe_malloc(pgnlen + 1);
11810 
11811 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
11812 		if (szret < 0)
11813 			scfdie();
11814 		assert(szret <= pgnlen);
11815 
11816 		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
11817 			if (scf_error() != SCF_ERROR_NOT_FOUND)
11818 				scfdie();
11819 			pgtp = NULL;
11820 		} else {
11821 			pgtp = pgt;
11822 		}
11823 
11824 		if (pattern == NULL ||
11825 		    fnmatch(pattern, pgnbuf, 0) == 0) {
11826 			if (i+1 >= allocd) {
11827 				allocd *= 2;
11828 				objects = realloc(objects,
11829 				    sizeof (*objects) * allocd);
11830 				names =
11831 				    realloc(names, sizeof (*names) * allocd);
11832 				tmpls = realloc(tmpls,
11833 				    sizeof (*tmpls) * allocd);
11834 				if (objects == NULL || names == NULL ||
11835 				    tmpls == NULL)
11836 					uu_die(gettext("Out of memory"));
11837 			}
11838 			objects[i] = pg;
11839 			names[i] = pgnbuf;
11840 
11841 			if (pgtp == NULL)
11842 				tmpls[i] = NULL;
11843 			else
11844 				tmpls[i] = pgt;
11845 
11846 			++i;
11847 
11848 			if (pgnlen > max_len)
11849 				max_len = pgnlen;
11850 
11851 			new_pg = 1;
11852 			print_props = 1;
11853 		}
11854 
11855 		if (only_pgs) {
11856 			if (new_pg) {
11857 				pg = scf_pg_create(g_hndl);
11858 				if (pg == NULL)
11859 					scfdie();
11860 				pgt = scf_tmpl_pg_create(g_hndl);
11861 				if (pgt == NULL)
11862 					scfdie();
11863 			} else
11864 				free(pgnbuf);
11865 
11866 			continue;
11867 		}
11868 
11869 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
11870 			scfdie();
11871 
11872 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
11873 			prnlen = scf_property_get_name(prop, prnbuf,
11874 			    max_scf_name_len + 1);
11875 			if (prnlen < 0)
11876 				scfdie();
11877 
11878 			/* Will prepend the property group name and a slash. */
11879 			prnlen += pgnlen + 1;
11880 
11881 			ppnbuf = safe_malloc(prnlen + 1);
11882 
11883 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
11884 			    prnbuf) < 0)
11885 				uu_die("snprintf");
11886 
11887 			if (pattern == NULL || print_props == 1 ||
11888 			    fnmatch(pattern, ppnbuf, 0) == 0) {
11889 				if (i+1 >= allocd) {
11890 					allocd *= 2;
11891 					objects = realloc(objects,
11892 					    sizeof (*objects) * allocd);
11893 					names = realloc(names,
11894 					    sizeof (*names) * allocd);
11895 					tmpls = realloc(tmpls,
11896 					    sizeof (*tmpls) * allocd);
11897 					if (objects == NULL || names == NULL ||
11898 					    tmpls == NULL)
11899 						uu_die(gettext(
11900 						    "Out of memory"));
11901 				}
11902 
11903 				objects[i] = prop;
11904 				names[i] = ppnbuf;
11905 
11906 				if (pgtp != NULL) {
11907 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
11908 					    prt, NULL) < 0) {
11909 						if (scf_error() !=
11910 						    SCF_ERROR_NOT_FOUND)
11911 							scfdie();
11912 						tmpls[i] = NULL;
11913 					} else {
11914 						tmpls[i] = prt;
11915 					}
11916 				} else {
11917 					tmpls[i] = NULL;
11918 				}
11919 
11920 				++i;
11921 
11922 				if (prnlen > max_len)
11923 					max_len = prnlen;
11924 
11925 				prop = scf_property_create(g_hndl);
11926 				prt = scf_tmpl_prop_create(g_hndl);
11927 			} else {
11928 				free(ppnbuf);
11929 			}
11930 		}
11931 
11932 		if (new_pg) {
11933 			pg = scf_pg_create(g_hndl);
11934 			if (pg == NULL)
11935 				scfdie();
11936 			pgt = scf_tmpl_pg_create(g_hndl);
11937 			if (pgt == NULL)
11938 				scfdie();
11939 		} else
11940 			free(pgnbuf);
11941 	}
11942 	if (ret != 0)
11943 		scfdie();
11944 
11945 	objects[i] = NULL;
11946 
11947 	scf_pg_destroy(pg);
11948 	scf_tmpl_pg_destroy(pgt);
11949 	scf_property_destroy(prop);
11950 	scf_tmpl_prop_destroy(prt);
11951 
11952 	for (i = 0; objects[i] != NULL; ++i) {
11953 		if (strchr(names[i], '/') == NULL) {
11954 			/* property group */
11955 			pg = (scf_propertygroup_t *)objects[i];
11956 			pgt = (scf_pg_tmpl_t *)tmpls[i];
11957 			list_pg_info(pg, names[i], max_len);
11958 			list_pg_tmpl(pgt, pg, templates);
11959 			free(names[i]);
11960 			scf_pg_destroy(pg);
11961 			if (pgt != NULL)
11962 				scf_tmpl_pg_destroy(pgt);
11963 		} else {
11964 			/* property */
11965 			prop = (scf_property_t *)objects[i];
11966 			prt = (scf_prop_tmpl_t *)tmpls[i];
11967 			list_prop_info(prop, names[i], max_len);
11968 			list_prop_tmpl(prt, prop, templates);
11969 			free(names[i]);
11970 			scf_property_destroy(prop);
11971 			if (prt != NULL)
11972 				scf_tmpl_prop_destroy(prt);
11973 		}
11974 	}
11975 
11976 	free(names);
11977 	free(objects);
11978 	free(tmpls);
11979 }
11980 
11981 void
11982 lscf_listpg(const char *pattern)
11983 {
11984 	lscf_prep_hndl();
11985 
11986 	listprop(pattern, 1, 0);
11987 }
11988 
11989 /*
11990  * Property group and property creation, setting, and deletion.  setprop (and
11991  * its alias, addprop) can either create a property group of a given type, or
11992  * it can create or set a property to a given type and list of values.
11993  */
11994 void
11995 lscf_addpg(const char *name, const char *type, const char *flags)
11996 {
11997 	scf_propertygroup_t *pg;
11998 	int ret;
11999 	uint32_t flgs = 0;
12000 	const char *cp;
12001 
12002 
12003 	lscf_prep_hndl();
12004 
12005 	if (cur_snap != NULL) {
12006 		semerr(emsg_cant_modify_snapshots);
12007 		return;
12008 	}
12009 
12010 	if (cur_inst == NULL && cur_svc == NULL) {
12011 		semerr(emsg_entity_not_selected);
12012 		return;
12013 	}
12014 
12015 	if (flags != NULL) {
12016 		for (cp = flags; *cp != '\0'; ++cp) {
12017 			switch (*cp) {
12018 			case 'P':
12019 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
12020 				break;
12021 
12022 			case 'p':
12023 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
12024 				break;
12025 
12026 			default:
12027 				semerr(gettext("Invalid property group flag "
12028 				    "%c."), *cp);
12029 				return;
12030 			}
12031 		}
12032 	}
12033 
12034 	pg = scf_pg_create(g_hndl);
12035 	if (pg == NULL)
12036 		scfdie();
12037 
12038 	if (cur_inst != NULL)
12039 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
12040 	else
12041 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
12042 
12043 	if (ret != SCF_SUCCESS) {
12044 		switch (scf_error()) {
12045 		case SCF_ERROR_INVALID_ARGUMENT:
12046 			semerr(gettext("Name, type, or flags are invalid.\n"));
12047 			break;
12048 
12049 		case SCF_ERROR_EXISTS:
12050 			semerr(gettext("Property group already exists.\n"));
12051 			break;
12052 
12053 		case SCF_ERROR_PERMISSION_DENIED:
12054 			semerr(emsg_permission_denied);
12055 			break;
12056 
12057 		case SCF_ERROR_BACKEND_ACCESS:
12058 			semerr(gettext("Backend refused access.\n"));
12059 			break;
12060 
12061 		default:
12062 			scfdie();
12063 		}
12064 	}
12065 
12066 	scf_pg_destroy(pg);
12067 
12068 	private_refresh();
12069 }
12070 
12071 void
12072 lscf_delpg(char *name)
12073 {
12074 	lscf_prep_hndl();
12075 
12076 	if (cur_snap != NULL) {
12077 		semerr(emsg_cant_modify_snapshots);
12078 		return;
12079 	}
12080 
12081 	if (cur_inst == NULL && cur_svc == NULL) {
12082 		semerr(emsg_entity_not_selected);
12083 		return;
12084 	}
12085 
12086 	if (strchr(name, '/') != NULL) {
12087 		semerr(emsg_invalid_pg_name, name);
12088 		return;
12089 	}
12090 
12091 	lscf_delprop(name);
12092 }
12093 
12094 /*
12095  * scf_delhash() is used to remove the property group related to the
12096  * hash entry for a specific manifest in the repository. pgname will be
12097  * constructed from the location of the manifest file. If deathrow isn't 0,
12098  * manifest file doesn't need to exist (manifest string will be used as
12099  * an absolute path).
12100  */
12101 void
12102 lscf_delhash(char *manifest, int deathrow)
12103 {
12104 	char *pgname;
12105 
12106 	if (cur_snap != NULL ||
12107 	    cur_inst != NULL || cur_svc != NULL) {
12108 		warn(gettext("error, an entity is selected\n"));
12109 		return;
12110 	}
12111 
12112 	/* select smf/manifest */
12113 	lscf_select("smf/manifest");
12114 	/*
12115 	 * Translate the manifest file name to property name. In the deathrow
12116 	 * case, the manifest file does not need to exist.
12117 	 */
12118 	pgname = mhash_filename_to_propname(manifest,
12119 	    deathrow ? B_TRUE : B_FALSE);
12120 	if (pgname == NULL) {
12121 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
12122 		return;
12123 	}
12124 	/* delete the hash property name */
12125 	lscf_delpg(pgname);
12126 }
12127 
12128 void
12129 lscf_listprop(const char *pattern)
12130 {
12131 	lscf_prep_hndl();
12132 
12133 	listprop(pattern, 0, 0);
12134 }
12135 
12136 int
12137 lscf_setprop(const char *pgname, const char *type, const char *value,
12138     const uu_list_t *values)
12139 {
12140 	scf_type_t ty, current_ty;
12141 	scf_service_t *svc;
12142 	scf_propertygroup_t *pg, *parent_pg;
12143 	scf_property_t *prop, *parent_prop;
12144 	scf_pg_tmpl_t *pgt;
12145 	scf_prop_tmpl_t *prt;
12146 	int ret, result = 0;
12147 	scf_transaction_t *tx;
12148 	scf_transaction_entry_t *e;
12149 	scf_value_t *v;
12150 	uu_list_walk_t *walk;
12151 	string_list_t *sp;
12152 	char *propname;
12153 	int req_quotes = 0;
12154 
12155 	lscf_prep_hndl();
12156 
12157 	if ((e = scf_entry_create(g_hndl)) == NULL ||
12158 	    (svc = scf_service_create(g_hndl)) == NULL ||
12159 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
12160 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12161 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
12162 	    (prop = scf_property_create(g_hndl)) == NULL ||
12163 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12164 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12165 	    (tx = scf_transaction_create(g_hndl)) == NULL)
12166 		scfdie();
12167 
12168 	if (cur_snap != NULL) {
12169 		semerr(emsg_cant_modify_snapshots);
12170 		goto fail;
12171 	}
12172 
12173 	if (cur_inst == NULL && cur_svc == NULL) {
12174 		semerr(emsg_entity_not_selected);
12175 		goto fail;
12176 	}
12177 
12178 	propname = strchr(pgname, '/');
12179 	if (propname == NULL) {
12180 		semerr(gettext("Property names must contain a `/'.\n"));
12181 		goto fail;
12182 	}
12183 
12184 	*propname = '\0';
12185 	++propname;
12186 
12187 	if (type != NULL) {
12188 		ty = string_to_type(type);
12189 		if (ty == SCF_TYPE_INVALID) {
12190 			semerr(gettext("Unknown type \"%s\".\n"), type);
12191 			goto fail;
12192 		}
12193 	}
12194 
12195 	if (cur_inst != NULL)
12196 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12197 	else
12198 		ret = scf_service_get_pg(cur_svc, pgname, pg);
12199 	if (ret != SCF_SUCCESS) {
12200 		switch (scf_error()) {
12201 		case SCF_ERROR_NOT_FOUND:
12202 			semerr(emsg_no_such_pg, pgname);
12203 			goto fail;
12204 
12205 		case SCF_ERROR_INVALID_ARGUMENT:
12206 			semerr(emsg_invalid_pg_name, pgname);
12207 			goto fail;
12208 
12209 		default:
12210 			scfdie();
12211 			break;
12212 		}
12213 	}
12214 
12215 	do {
12216 		if (scf_pg_update(pg) == -1)
12217 			scfdie();
12218 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12219 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12220 				scfdie();
12221 
12222 			semerr(emsg_permission_denied);
12223 			goto fail;
12224 		}
12225 
12226 		ret = scf_pg_get_property(pg, propname, prop);
12227 		if (ret == SCF_SUCCESS) {
12228 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
12229 				scfdie();
12230 
12231 			if (type == NULL)
12232 				ty = current_ty;
12233 			if (scf_transaction_property_change_type(tx, e,
12234 			    propname, ty) == -1)
12235 				scfdie();
12236 
12237 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12238 			/* Infer the type, if possible. */
12239 			if (type == NULL) {
12240 				/*
12241 				 * First check if we're an instance and the
12242 				 * property is set on the service.
12243 				 */
12244 				if (cur_inst != NULL &&
12245 				    scf_instance_get_parent(cur_inst,
12246 				    svc) == 0 &&
12247 				    scf_service_get_pg(cur_svc, pgname,
12248 				    parent_pg) == 0 &&
12249 				    scf_pg_get_property(parent_pg, propname,
12250 				    parent_prop) == 0 &&
12251 				    scf_property_type(parent_prop,
12252 				    &current_ty) == 0) {
12253 					ty = current_ty;
12254 
12255 				/* Then check for a type set in a template. */
12256 				} else if (scf_tmpl_get_by_pg(pg, pgt,
12257 				    NULL) == 0 &&
12258 				    scf_tmpl_get_by_prop(pgt, propname, prt,
12259 				    NULL) == 0 &&
12260 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
12261 					ty = current_ty;
12262 
12263 				/* If type can't be inferred, fail. */
12264 				} else {
12265 					semerr(gettext("Type required for new "
12266 					    "properties.\n"));
12267 					goto fail;
12268 				}
12269 			}
12270 			if (scf_transaction_property_new(tx, e, propname,
12271 			    ty) == -1)
12272 				scfdie();
12273 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12274 			semerr(emsg_invalid_prop_name, propname);
12275 			goto fail;
12276 		} else {
12277 			scfdie();
12278 		}
12279 
12280 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
12281 			req_quotes = 1;
12282 
12283 		if (value != NULL) {
12284 			v = string_to_value(value, ty, 0);
12285 
12286 			if (v == NULL)
12287 				goto fail;
12288 
12289 			ret = scf_entry_add_value(e, v);
12290 			assert(ret == SCF_SUCCESS);
12291 		} else {
12292 			assert(values != NULL);
12293 
12294 			walk = uu_list_walk_start((uu_list_t *)values,
12295 			    UU_DEFAULT);
12296 			if (walk == NULL)
12297 				uu_die(gettext("Could not walk list"));
12298 
12299 			for (sp = uu_list_walk_next(walk); sp != NULL;
12300 			    sp = uu_list_walk_next(walk)) {
12301 				v = string_to_value(sp->str, ty, req_quotes);
12302 
12303 				if (v == NULL) {
12304 					scf_entry_destroy_children(e);
12305 					goto fail;
12306 				}
12307 
12308 				ret = scf_entry_add_value(e, v);
12309 				assert(ret == SCF_SUCCESS);
12310 			}
12311 			uu_list_walk_end(walk);
12312 		}
12313 		result = scf_transaction_commit(tx);
12314 
12315 		scf_transaction_reset(tx);
12316 		scf_entry_destroy_children(e);
12317 	} while (result == 0);
12318 
12319 	if (result < 0) {
12320 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12321 			scfdie();
12322 
12323 		semerr(emsg_permission_denied);
12324 		goto fail;
12325 	}
12326 
12327 	ret = 0;
12328 
12329 	private_refresh();
12330 
12331 	goto cleanup;
12332 
12333 fail:
12334 	ret = -1;
12335 
12336 cleanup:
12337 	scf_transaction_destroy(tx);
12338 	scf_entry_destroy(e);
12339 	scf_service_destroy(svc);
12340 	scf_pg_destroy(parent_pg);
12341 	scf_pg_destroy(pg);
12342 	scf_property_destroy(parent_prop);
12343 	scf_property_destroy(prop);
12344 	scf_tmpl_pg_destroy(pgt);
12345 	scf_tmpl_prop_destroy(prt);
12346 
12347 	return (ret);
12348 }
12349 
12350 void
12351 lscf_delprop(char *pgn)
12352 {
12353 	char *slash, *pn;
12354 	scf_propertygroup_t *pg;
12355 	scf_transaction_t *tx;
12356 	scf_transaction_entry_t *e;
12357 	int ret;
12358 
12359 
12360 	lscf_prep_hndl();
12361 
12362 	if (cur_snap != NULL) {
12363 		semerr(emsg_cant_modify_snapshots);
12364 		return;
12365 	}
12366 
12367 	if (cur_inst == NULL && cur_svc == NULL) {
12368 		semerr(emsg_entity_not_selected);
12369 		return;
12370 	}
12371 
12372 	pg = scf_pg_create(g_hndl);
12373 	if (pg == NULL)
12374 		scfdie();
12375 
12376 	slash = strchr(pgn, '/');
12377 	if (slash == NULL) {
12378 		pn = NULL;
12379 	} else {
12380 		*slash = '\0';
12381 		pn = slash + 1;
12382 	}
12383 
12384 	if (cur_inst != NULL)
12385 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
12386 	else
12387 		ret = scf_service_get_pg(cur_svc, pgn, pg);
12388 	if (ret != SCF_SUCCESS) {
12389 		switch (scf_error()) {
12390 		case SCF_ERROR_NOT_FOUND:
12391 			semerr(emsg_no_such_pg, pgn);
12392 			break;
12393 
12394 		case SCF_ERROR_INVALID_ARGUMENT:
12395 			semerr(emsg_invalid_pg_name, pgn);
12396 			break;
12397 
12398 		default:
12399 			scfdie();
12400 		}
12401 
12402 		scf_pg_destroy(pg);
12403 
12404 		return;
12405 	}
12406 
12407 	if (pn == NULL) {
12408 		/* Try to delete the property group. */
12409 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
12410 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12411 				scfdie();
12412 
12413 			semerr(emsg_permission_denied);
12414 		} else {
12415 			private_refresh();
12416 		}
12417 
12418 		scf_pg_destroy(pg);
12419 		return;
12420 	}
12421 
12422 	e = scf_entry_create(g_hndl);
12423 	tx = scf_transaction_create(g_hndl);
12424 
12425 	do {
12426 		if (scf_pg_update(pg) == -1)
12427 			scfdie();
12428 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12429 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12430 				scfdie();
12431 
12432 			semerr(emsg_permission_denied);
12433 			break;
12434 		}
12435 
12436 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
12437 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
12438 				semerr(gettext("No such property %s/%s.\n"),
12439 				    pgn, pn);
12440 				break;
12441 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12442 				semerr(emsg_invalid_prop_name, pn);
12443 				break;
12444 			} else {
12445 				scfdie();
12446 			}
12447 		}
12448 
12449 		ret = scf_transaction_commit(tx);
12450 
12451 		if (ret == 0)
12452 			scf_transaction_reset(tx);
12453 	} while (ret == 0);
12454 
12455 	if (ret < 0) {
12456 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12457 			scfdie();
12458 
12459 		semerr(emsg_permission_denied);
12460 	} else {
12461 		private_refresh();
12462 	}
12463 
12464 	scf_transaction_destroy(tx);
12465 	scf_entry_destroy(e);
12466 	scf_pg_destroy(pg);
12467 }
12468 
12469 /*
12470  * Property editing.
12471  */
12472 
12473 static int
12474 write_edit_script(FILE *strm)
12475 {
12476 	char *fmribuf;
12477 	ssize_t fmrilen;
12478 
12479 	scf_propertygroup_t *pg;
12480 	scf_property_t *prop;
12481 	scf_value_t *val;
12482 	scf_type_t ty;
12483 	int ret, result = 0;
12484 	scf_iter_t *iter, *piter, *viter;
12485 	char *buf, *tybuf, *pname;
12486 	const char *emsg_write_error;
12487 
12488 
12489 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
12490 
12491 
12492 	/* select fmri */
12493 	if (cur_inst != NULL) {
12494 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
12495 		if (fmrilen < 0)
12496 			scfdie();
12497 		fmribuf = safe_malloc(fmrilen + 1);
12498 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
12499 			scfdie();
12500 	} else {
12501 		assert(cur_svc != NULL);
12502 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
12503 		if (fmrilen < 0)
12504 			scfdie();
12505 		fmribuf = safe_malloc(fmrilen + 1);
12506 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
12507 			scfdie();
12508 	}
12509 
12510 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
12511 		warn(emsg_write_error, strerror(errno));
12512 		free(fmribuf);
12513 		return (-1);
12514 	}
12515 
12516 	free(fmribuf);
12517 
12518 
12519 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12520 	    (prop = scf_property_create(g_hndl)) == NULL ||
12521 	    (val = scf_value_create(g_hndl)) == NULL ||
12522 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12523 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12524 	    (viter = scf_iter_create(g_hndl)) == NULL)
12525 		scfdie();
12526 
12527 	buf = safe_malloc(max_scf_name_len + 1);
12528 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
12529 	pname = safe_malloc(max_scf_name_len + 1);
12530 
12531 	if (cur_inst != NULL)
12532 		ret = scf_iter_instance_pgs(iter, cur_inst);
12533 	else
12534 		ret = scf_iter_service_pgs(iter, cur_svc);
12535 	if (ret != SCF_SUCCESS)
12536 		scfdie();
12537 
12538 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12539 		int ret2;
12540 
12541 		/*
12542 		 * # delprop pg
12543 		 * # addpg pg type
12544 		 */
12545 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
12546 			scfdie();
12547 
12548 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
12549 			scfdie();
12550 
12551 		if (fprintf(strm, "# Property group \"%s\"\n"
12552 		    "# delprop %s\n"
12553 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
12554 			warn(emsg_write_error, strerror(errno));
12555 			result = -1;
12556 			goto out;
12557 		}
12558 
12559 		/* # setprop pg/prop = (values) */
12560 
12561 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12562 			scfdie();
12563 
12564 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
12565 			int first = 1;
12566 			int ret3;
12567 			int multiple;
12568 			int is_str;
12569 			scf_type_t bty;
12570 
12571 			if (scf_property_get_name(prop, pname,
12572 			    max_scf_name_len + 1) < 0)
12573 				scfdie();
12574 
12575 			if (scf_property_type(prop, &ty) != 0)
12576 				scfdie();
12577 
12578 			multiple = prop_has_multiple_values(prop, val);
12579 
12580 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
12581 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
12582 			    < 0) {
12583 				warn(emsg_write_error, strerror(errno));
12584 				result = -1;
12585 				goto out;
12586 			}
12587 
12588 			(void) scf_type_base_type(ty, &bty);
12589 			is_str = (bty == SCF_TYPE_ASTRING);
12590 
12591 			if (scf_iter_property_values(viter, prop) !=
12592 			    SCF_SUCCESS)
12593 				scfdie();
12594 
12595 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
12596 				char *buf;
12597 				ssize_t buflen;
12598 
12599 				buflen = scf_value_get_as_string(val, NULL, 0);
12600 				if (buflen < 0)
12601 					scfdie();
12602 
12603 				buf = safe_malloc(buflen + 1);
12604 
12605 				if (scf_value_get_as_string(val, buf,
12606 				    buflen + 1) < 0)
12607 					scfdie();
12608 
12609 				if (first)
12610 					first = 0;
12611 				else {
12612 					if (putc(' ', strm) != ' ') {
12613 						warn(emsg_write_error,
12614 						    strerror(errno));
12615 						result = -1;
12616 						goto out;
12617 					}
12618 				}
12619 
12620 				if ((is_str && multiple) ||
12621 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
12622 					(void) putc('"', strm);
12623 					(void) quote_and_print(buf, strm, 1);
12624 					(void) putc('"', strm);
12625 
12626 					if (ferror(strm)) {
12627 						warn(emsg_write_error,
12628 						    strerror(errno));
12629 						result = -1;
12630 						goto out;
12631 					}
12632 				} else {
12633 					if (fprintf(strm, "%s", buf) < 0) {
12634 						warn(emsg_write_error,
12635 						    strerror(errno));
12636 						result = -1;
12637 						goto out;
12638 					}
12639 				}
12640 
12641 				free(buf);
12642 			}
12643 			if (ret3 < 0 &&
12644 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
12645 				scfdie();
12646 
12647 			/* Write closing paren if mult-value property */
12648 			if ((multiple && putc(')', strm) == EOF) ||
12649 
12650 			    /* Write final newline */
12651 			    fputc('\n', strm) == EOF) {
12652 				warn(emsg_write_error, strerror(errno));
12653 				result = -1;
12654 				goto out;
12655 			}
12656 		}
12657 		if (ret2 < 0)
12658 			scfdie();
12659 
12660 		if (fputc('\n', strm) == EOF) {
12661 			warn(emsg_write_error, strerror(errno));
12662 			result = -1;
12663 			goto out;
12664 		}
12665 	}
12666 	if (ret < 0)
12667 		scfdie();
12668 
12669 out:
12670 	free(pname);
12671 	free(tybuf);
12672 	free(buf);
12673 	scf_iter_destroy(viter);
12674 	scf_iter_destroy(piter);
12675 	scf_iter_destroy(iter);
12676 	scf_value_destroy(val);
12677 	scf_property_destroy(prop);
12678 	scf_pg_destroy(pg);
12679 
12680 	if (result == 0) {
12681 		if (fflush(strm) != 0) {
12682 			warn(emsg_write_error, strerror(errno));
12683 			return (-1);
12684 		}
12685 	}
12686 
12687 	return (result);
12688 }
12689 
12690 int
12691 lscf_editprop()
12692 {
12693 	char *buf, *editor;
12694 	size_t bufsz;
12695 	int tmpfd;
12696 	char tempname[] = TEMP_FILE_PATTERN;
12697 
12698 	lscf_prep_hndl();
12699 
12700 	if (cur_snap != NULL) {
12701 		semerr(emsg_cant_modify_snapshots);
12702 		return (-1);
12703 	}
12704 
12705 	if (cur_svc == NULL && cur_inst == NULL) {
12706 		semerr(emsg_entity_not_selected);
12707 		return (-1);
12708 	}
12709 
12710 	tmpfd = mkstemp(tempname);
12711 	if (tmpfd == -1) {
12712 		semerr(gettext("Could not create temporary file.\n"));
12713 		return (-1);
12714 	}
12715 
12716 	(void) strcpy(tempfilename, tempname);
12717 
12718 	tempfile = fdopen(tmpfd, "r+");
12719 	if (tempfile == NULL) {
12720 		warn(gettext("Could not create temporary file.\n"));
12721 		if (close(tmpfd) == -1)
12722 			warn(gettext("Could not close temporary file: %s.\n"),
12723 			    strerror(errno));
12724 
12725 		remove_tempfile();
12726 
12727 		return (-1);
12728 	}
12729 
12730 	if (write_edit_script(tempfile) == -1) {
12731 		remove_tempfile();
12732 		return (-1);
12733 	}
12734 
12735 	editor = getenv("EDITOR");
12736 	if (editor == NULL)
12737 		editor = "vi";
12738 
12739 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
12740 	buf = safe_malloc(bufsz);
12741 
12742 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
12743 		uu_die(gettext("Error creating editor command"));
12744 
12745 	if (system(buf) == -1) {
12746 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
12747 		    strerror(errno));
12748 		free(buf);
12749 		remove_tempfile();
12750 		return (-1);
12751 	}
12752 
12753 	free(buf);
12754 
12755 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
12756 
12757 	remove_tempfile();
12758 
12759 	return (0);
12760 }
12761 
12762 static void
12763 add_string(uu_list_t *strlist, const char *str)
12764 {
12765 	string_list_t *elem;
12766 	elem = safe_malloc(sizeof (*elem));
12767 	uu_list_node_init(elem, &elem->node, string_pool);
12768 	elem->str = safe_strdup(str);
12769 	if (uu_list_append(strlist, elem) != 0)
12770 		uu_die(gettext("libuutil error: %s\n"),
12771 		    uu_strerror(uu_error()));
12772 }
12773 
12774 /*
12775  * Get all property values that don't match the given glob pattern,
12776  * if a pattern is specified.
12777  */
12778 static void
12779 get_prop_values(scf_property_t *prop, uu_list_t *values,
12780     const char *pattern)
12781 {
12782 	scf_iter_t *iter;
12783 	scf_value_t *val;
12784 	int ret;
12785 
12786 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12787 	    (val = scf_value_create(g_hndl)) == NULL)
12788 		scfdie();
12789 
12790 	if (scf_iter_property_values(iter, prop) != 0)
12791 		scfdie();
12792 
12793 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12794 		char *buf;
12795 		ssize_t vlen, szret;
12796 
12797 		vlen = scf_value_get_as_string(val, NULL, 0);
12798 		if (vlen < 0)
12799 			scfdie();
12800 
12801 		buf = safe_malloc(vlen + 1);
12802 
12803 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12804 		if (szret < 0)
12805 			scfdie();
12806 		assert(szret <= vlen);
12807 
12808 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
12809 			add_string(values, buf);
12810 
12811 		free(buf);
12812 	}
12813 
12814 	if (ret == -1)
12815 		scfdie();
12816 
12817 	scf_value_destroy(val);
12818 	scf_iter_destroy(iter);
12819 }
12820 
12821 static int
12822 lscf_setpropvalue(const char *pgname, const char *type,
12823     const char *arg, int isadd, int isnotfoundok)
12824 {
12825 	scf_type_t ty;
12826 	scf_propertygroup_t *pg;
12827 	scf_property_t *prop;
12828 	int ret, result = 0;
12829 	scf_transaction_t *tx;
12830 	scf_transaction_entry_t *e;
12831 	scf_value_t *v;
12832 	string_list_t *sp;
12833 	char *propname;
12834 	uu_list_t *values;
12835 	uu_list_walk_t *walk;
12836 	void *cookie = NULL;
12837 	char *pattern = NULL;
12838 
12839 	lscf_prep_hndl();
12840 
12841 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
12842 		uu_die(gettext("Could not create property list: %s\n"),
12843 		    uu_strerror(uu_error()));
12844 
12845 	if (!isadd)
12846 		pattern = safe_strdup(arg);
12847 
12848 	if ((e = scf_entry_create(g_hndl)) == NULL ||
12849 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12850 	    (prop = scf_property_create(g_hndl)) == NULL ||
12851 	    (tx = scf_transaction_create(g_hndl)) == NULL)
12852 		scfdie();
12853 
12854 	if (cur_snap != NULL) {
12855 		semerr(emsg_cant_modify_snapshots);
12856 		goto fail;
12857 	}
12858 
12859 	if (cur_inst == NULL && cur_svc == NULL) {
12860 		semerr(emsg_entity_not_selected);
12861 		goto fail;
12862 	}
12863 
12864 	propname = strchr(pgname, '/');
12865 	if (propname == NULL) {
12866 		semerr(gettext("Property names must contain a `/'.\n"));
12867 		goto fail;
12868 	}
12869 
12870 	*propname = '\0';
12871 	++propname;
12872 
12873 	if (type != NULL) {
12874 		ty = string_to_type(type);
12875 		if (ty == SCF_TYPE_INVALID) {
12876 			semerr(gettext("Unknown type \"%s\".\n"), type);
12877 			goto fail;
12878 		}
12879 	}
12880 
12881 	if (cur_inst != NULL)
12882 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12883 	else
12884 		ret = scf_service_get_pg(cur_svc, pgname, pg);
12885 	if (ret != 0) {
12886 		switch (scf_error()) {
12887 		case SCF_ERROR_NOT_FOUND:
12888 			if (isnotfoundok) {
12889 				result = 0;
12890 			} else {
12891 				semerr(emsg_no_such_pg, pgname);
12892 				result = -1;
12893 			}
12894 			goto out;
12895 
12896 		case SCF_ERROR_INVALID_ARGUMENT:
12897 			semerr(emsg_invalid_pg_name, pgname);
12898 			goto fail;
12899 
12900 		default:
12901 			scfdie();
12902 		}
12903 	}
12904 
12905 	do {
12906 		if (scf_pg_update(pg) == -1)
12907 			scfdie();
12908 		if (scf_transaction_start(tx, pg) != 0) {
12909 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12910 				scfdie();
12911 
12912 			semerr(emsg_permission_denied);
12913 			goto fail;
12914 		}
12915 
12916 		ret = scf_pg_get_property(pg, propname, prop);
12917 		if (ret == 0) {
12918 			scf_type_t ptype;
12919 			char *pat = pattern;
12920 
12921 			if (scf_property_type(prop, &ptype) != 0)
12922 				scfdie();
12923 
12924 			if (isadd) {
12925 				if (type != NULL && ptype != ty) {
12926 					semerr(gettext("Property \"%s\" is not "
12927 					    "of type \"%s\".\n"), propname,
12928 					    type);
12929 					goto fail;
12930 				}
12931 
12932 				pat = NULL;
12933 			} else {
12934 				size_t len = strlen(pat);
12935 				if (len > 0 && pat[len - 1] == '\"')
12936 					pat[len - 1] = '\0';
12937 				if (len > 0 && pat[0] == '\"')
12938 					pat++;
12939 			}
12940 
12941 			ty = ptype;
12942 
12943 			get_prop_values(prop, values, pat);
12944 
12945 			if (isadd)
12946 				add_string(values, arg);
12947 
12948 			if (scf_transaction_property_change(tx, e,
12949 			    propname, ty) == -1)
12950 				scfdie();
12951 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12952 			if (isadd) {
12953 				if (type == NULL) {
12954 					semerr(gettext("Type required "
12955 					    "for new properties.\n"));
12956 					goto fail;
12957 				}
12958 
12959 				add_string(values, arg);
12960 
12961 				if (scf_transaction_property_new(tx, e,
12962 				    propname, ty) == -1)
12963 					scfdie();
12964 			} else if (isnotfoundok) {
12965 				result = 0;
12966 				goto out;
12967 			} else {
12968 				semerr(gettext("No such property %s/%s.\n"),
12969 				    pgname, propname);
12970 				result = -1;
12971 				goto out;
12972 			}
12973 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12974 			semerr(emsg_invalid_prop_name, propname);
12975 			goto fail;
12976 		} else {
12977 			scfdie();
12978 		}
12979 
12980 		walk = uu_list_walk_start(values, UU_DEFAULT);
12981 		if (walk == NULL)
12982 			uu_die(gettext("Could not walk property list.\n"));
12983 
12984 		for (sp = uu_list_walk_next(walk); sp != NULL;
12985 		    sp = uu_list_walk_next(walk)) {
12986 			v = string_to_value(sp->str, ty, 0);
12987 
12988 			if (v == NULL) {
12989 				scf_entry_destroy_children(e);
12990 				goto fail;
12991 			}
12992 			ret = scf_entry_add_value(e, v);
12993 			assert(ret == 0);
12994 		}
12995 		uu_list_walk_end(walk);
12996 
12997 		result = scf_transaction_commit(tx);
12998 
12999 		scf_transaction_reset(tx);
13000 		scf_entry_destroy_children(e);
13001 	} while (result == 0);
13002 
13003 	if (result < 0) {
13004 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13005 			scfdie();
13006 
13007 		semerr(emsg_permission_denied);
13008 		goto fail;
13009 	}
13010 
13011 	result = 0;
13012 
13013 	private_refresh();
13014 
13015 out:
13016 	scf_transaction_destroy(tx);
13017 	scf_entry_destroy(e);
13018 	scf_pg_destroy(pg);
13019 	scf_property_destroy(prop);
13020 	free(pattern);
13021 
13022 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
13023 		free(sp->str);
13024 		free(sp);
13025 	}
13026 
13027 	uu_list_destroy(values);
13028 
13029 	return (result);
13030 
13031 fail:
13032 	result = -1;
13033 	goto out;
13034 }
13035 
13036 int
13037 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
13038 {
13039 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
13040 }
13041 
13042 int
13043 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
13044 {
13045 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
13046 }
13047 
13048 /*
13049  * Look for a standard start method, first in the instance (if any),
13050  * then the service.
13051  */
13052 static const char *
13053 start_method_name(int *in_instance)
13054 {
13055 	scf_propertygroup_t *pg;
13056 	char **p;
13057 	int ret;
13058 	scf_instance_t *inst = cur_inst;
13059 
13060 	if ((pg = scf_pg_create(g_hndl)) == NULL)
13061 		scfdie();
13062 
13063 again:
13064 	for (p = start_method_names; *p != NULL; p++) {
13065 		if (inst != NULL)
13066 			ret = scf_instance_get_pg(inst, *p, pg);
13067 		else
13068 			ret = scf_service_get_pg(cur_svc, *p, pg);
13069 
13070 		if (ret == 0) {
13071 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
13072 			char *buf = safe_malloc(bufsz);
13073 
13074 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
13075 				free(buf);
13076 				continue;
13077 			}
13078 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
13079 				free(buf);
13080 				continue;
13081 			}
13082 
13083 			free(buf);
13084 			*in_instance = (inst != NULL);
13085 			scf_pg_destroy(pg);
13086 			return (*p);
13087 		}
13088 
13089 		if (scf_error() == SCF_ERROR_NOT_FOUND)
13090 			continue;
13091 
13092 		scfdie();
13093 	}
13094 
13095 	if (inst != NULL) {
13096 		inst = NULL;
13097 		goto again;
13098 	}
13099 
13100 	scf_pg_destroy(pg);
13101 	return (NULL);
13102 }
13103 
13104 static int
13105 addpg(const char *name, const char *type)
13106 {
13107 	scf_propertygroup_t *pg;
13108 	int ret;
13109 
13110 	pg = scf_pg_create(g_hndl);
13111 	if (pg == NULL)
13112 		scfdie();
13113 
13114 	if (cur_inst != NULL)
13115 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
13116 	else
13117 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
13118 
13119 	if (ret != 0) {
13120 		switch (scf_error()) {
13121 		case SCF_ERROR_EXISTS:
13122 			ret = 0;
13123 			break;
13124 
13125 		case SCF_ERROR_PERMISSION_DENIED:
13126 			semerr(emsg_permission_denied);
13127 			break;
13128 
13129 		default:
13130 			scfdie();
13131 		}
13132 	}
13133 
13134 	scf_pg_destroy(pg);
13135 	return (ret);
13136 }
13137 
13138 int
13139 lscf_setenv(uu_list_t *args, int isunset)
13140 {
13141 	int ret = 0;
13142 	size_t i;
13143 	int argc;
13144 	char **argv = NULL;
13145 	string_list_t *slp;
13146 	char *pattern;
13147 	char *prop;
13148 	int do_service = 0;
13149 	int do_instance = 0;
13150 	const char *method = NULL;
13151 	const char *name = NULL;
13152 	const char *value = NULL;
13153 	scf_instance_t *saved_cur_inst = cur_inst;
13154 
13155 	lscf_prep_hndl();
13156 
13157 	argc = uu_list_numnodes(args);
13158 	if (argc < 1)
13159 		goto usage;
13160 
13161 	argv = calloc(argc + 1, sizeof (char *));
13162 	if (argv == NULL)
13163 		uu_die(gettext("Out of memory.\n"));
13164 
13165 	for (slp = uu_list_first(args), i = 0;
13166 	    slp != NULL;
13167 	    slp = uu_list_next(args, slp), ++i)
13168 		argv[i] = slp->str;
13169 
13170 	argv[i] = NULL;
13171 
13172 	opterr = 0;
13173 	optind = 0;
13174 	for (;;) {
13175 		ret = getopt(argc, argv, "sim:");
13176 		if (ret == -1)
13177 			break;
13178 
13179 		switch (ret) {
13180 		case 's':
13181 			do_service = 1;
13182 			cur_inst = NULL;
13183 			break;
13184 
13185 		case 'i':
13186 			do_instance = 1;
13187 			break;
13188 
13189 		case 'm':
13190 			method = optarg;
13191 			break;
13192 
13193 		case '?':
13194 			goto usage;
13195 
13196 		default:
13197 			bad_error("getopt", ret);
13198 		}
13199 	}
13200 
13201 	argc -= optind;
13202 	if ((do_service && do_instance) ||
13203 	    (isunset && argc != 1) ||
13204 	    (!isunset && argc != 2))
13205 		goto usage;
13206 
13207 	name = argv[optind];
13208 	if (!isunset)
13209 		value = argv[optind + 1];
13210 
13211 	if (cur_snap != NULL) {
13212 		semerr(emsg_cant_modify_snapshots);
13213 		ret = -1;
13214 		goto out;
13215 	}
13216 
13217 	if (cur_inst == NULL && cur_svc == NULL) {
13218 		semerr(emsg_entity_not_selected);
13219 		ret = -1;
13220 		goto out;
13221 	}
13222 
13223 	if (do_instance && cur_inst == NULL) {
13224 		semerr(gettext("No instance is selected.\n"));
13225 		ret = -1;
13226 		goto out;
13227 	}
13228 
13229 	if (do_service && cur_svc == NULL) {
13230 		semerr(gettext("No service is selected.\n"));
13231 		ret = -1;
13232 		goto out;
13233 	}
13234 
13235 	if (method == NULL) {
13236 		if (do_instance || do_service) {
13237 			method = "method_context";
13238 			if (!isunset) {
13239 				ret = addpg("method_context",
13240 				    SCF_GROUP_FRAMEWORK);
13241 				if (ret != 0)
13242 					goto out;
13243 			}
13244 		} else {
13245 			int in_instance;
13246 			method = start_method_name(&in_instance);
13247 			if (method == NULL) {
13248 				semerr(gettext(
13249 				    "Couldn't find start method; please "
13250 				    "specify a method with '-m'.\n"));
13251 				ret = -1;
13252 				goto out;
13253 			}
13254 			if (!in_instance)
13255 				cur_inst = NULL;
13256 		}
13257 	} else {
13258 		scf_propertygroup_t *pg;
13259 		size_t bufsz;
13260 		char *buf;
13261 		int ret;
13262 
13263 		if ((pg = scf_pg_create(g_hndl)) == NULL)
13264 			scfdie();
13265 
13266 		if (cur_inst != NULL)
13267 			ret = scf_instance_get_pg(cur_inst, method, pg);
13268 		else
13269 			ret = scf_service_get_pg(cur_svc, method, pg);
13270 
13271 		if (ret != 0) {
13272 			scf_pg_destroy(pg);
13273 			switch (scf_error()) {
13274 			case SCF_ERROR_NOT_FOUND:
13275 				semerr(gettext("Couldn't find the method "
13276 				    "\"%s\".\n"), method);
13277 				goto out;
13278 
13279 			case SCF_ERROR_INVALID_ARGUMENT:
13280 				semerr(gettext("Invalid method name \"%s\".\n"),
13281 				    method);
13282 				goto out;
13283 
13284 			default:
13285 				scfdie();
13286 			}
13287 		}
13288 
13289 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
13290 		buf = safe_malloc(bufsz);
13291 
13292 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
13293 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
13294 			semerr(gettext("Property group \"%s\" is not of type "
13295 			    "\"method\".\n"), method);
13296 			ret = -1;
13297 			free(buf);
13298 			scf_pg_destroy(pg);
13299 			goto out;
13300 		}
13301 
13302 		free(buf);
13303 		scf_pg_destroy(pg);
13304 	}
13305 
13306 	prop = uu_msprintf("%s/environment", method);
13307 	pattern = uu_msprintf("%s=*", name);
13308 
13309 	if (prop == NULL || pattern == NULL)
13310 		uu_die(gettext("Out of memory.\n"));
13311 
13312 	ret = lscf_delpropvalue(prop, pattern, !isunset);
13313 
13314 	if (ret == 0 && !isunset) {
13315 		uu_free(pattern);
13316 		uu_free(prop);
13317 		prop = uu_msprintf("%s/environment", method);
13318 		pattern = uu_msprintf("%s=%s", name, value);
13319 		if (prop == NULL || pattern == NULL)
13320 			uu_die(gettext("Out of memory.\n"));
13321 		ret = lscf_addpropvalue(prop, "astring:", pattern);
13322 	}
13323 	uu_free(pattern);
13324 	uu_free(prop);
13325 
13326 out:
13327 	cur_inst = saved_cur_inst;
13328 
13329 	free(argv);
13330 	return (ret);
13331 usage:
13332 	ret = -2;
13333 	goto out;
13334 }
13335 
13336 /*
13337  * Snapshot commands
13338  */
13339 
13340 void
13341 lscf_listsnap()
13342 {
13343 	scf_snapshot_t *snap;
13344 	scf_iter_t *iter;
13345 	char *nb;
13346 	int r;
13347 
13348 	lscf_prep_hndl();
13349 
13350 	if (cur_inst == NULL) {
13351 		semerr(gettext("Instance not selected.\n"));
13352 		return;
13353 	}
13354 
13355 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13356 	    (iter = scf_iter_create(g_hndl)) == NULL)
13357 		scfdie();
13358 
13359 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
13360 		scfdie();
13361 
13362 	nb = safe_malloc(max_scf_name_len + 1);
13363 
13364 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
13365 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
13366 			scfdie();
13367 
13368 		(void) puts(nb);
13369 	}
13370 	if (r < 0)
13371 		scfdie();
13372 
13373 	free(nb);
13374 	scf_iter_destroy(iter);
13375 	scf_snapshot_destroy(snap);
13376 }
13377 
13378 void
13379 lscf_selectsnap(const char *name)
13380 {
13381 	scf_snapshot_t *snap;
13382 	scf_snaplevel_t *level;
13383 
13384 	lscf_prep_hndl();
13385 
13386 	if (cur_inst == NULL) {
13387 		semerr(gettext("Instance not selected.\n"));
13388 		return;
13389 	}
13390 
13391 	if (cur_snap != NULL) {
13392 		if (name != NULL) {
13393 			char *cur_snap_name;
13394 			boolean_t nochange;
13395 
13396 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
13397 
13398 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
13399 			    max_scf_name_len + 1) < 0)
13400 				scfdie();
13401 
13402 			nochange = strcmp(name, cur_snap_name) == 0;
13403 
13404 			free(cur_snap_name);
13405 
13406 			if (nochange)
13407 				return;
13408 		}
13409 
13410 		unselect_cursnap();
13411 	}
13412 
13413 	if (name == NULL)
13414 		return;
13415 
13416 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13417 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
13418 		scfdie();
13419 
13420 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
13421 	    SCF_SUCCESS) {
13422 		switch (scf_error()) {
13423 		case SCF_ERROR_INVALID_ARGUMENT:
13424 			semerr(gettext("Invalid name \"%s\".\n"), name);
13425 			break;
13426 
13427 		case SCF_ERROR_NOT_FOUND:
13428 			semerr(gettext("No such snapshot \"%s\".\n"), name);
13429 			break;
13430 
13431 		default:
13432 			scfdie();
13433 		}
13434 
13435 		scf_snaplevel_destroy(level);
13436 		scf_snapshot_destroy(snap);
13437 		return;
13438 	}
13439 
13440 	/* Load the snaplevels into our list. */
13441 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
13442 	if (cur_levels == NULL)
13443 		uu_die(gettext("Could not create list: %s\n"),
13444 		    uu_strerror(uu_error()));
13445 
13446 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13447 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13448 			scfdie();
13449 
13450 		semerr(gettext("Snapshot has no snaplevels.\n"));
13451 
13452 		scf_snaplevel_destroy(level);
13453 		scf_snapshot_destroy(snap);
13454 		return;
13455 	}
13456 
13457 	cur_snap = snap;
13458 
13459 	for (;;) {
13460 		cur_elt = safe_malloc(sizeof (*cur_elt));
13461 		uu_list_node_init(cur_elt, &cur_elt->list_node,
13462 		    snaplevel_pool);
13463 		cur_elt->sl = level;
13464 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
13465 			uu_die(gettext("libuutil error: %s\n"),
13466 			    uu_strerror(uu_error()));
13467 
13468 		level = scf_snaplevel_create(g_hndl);
13469 		if (level == NULL)
13470 			scfdie();
13471 
13472 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
13473 		    level) != SCF_SUCCESS) {
13474 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13475 				scfdie();
13476 
13477 			scf_snaplevel_destroy(level);
13478 			break;
13479 		}
13480 	}
13481 
13482 	cur_elt = uu_list_last(cur_levels);
13483 	cur_level = cur_elt->sl;
13484 }
13485 
13486 /*
13487  * Copies the properties & values in src to dst.  Assumes src won't change.
13488  * Returns -1 if permission is denied, -2 if another transaction interrupts,
13489  * and 0 on success.
13490  *
13491  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
13492  * property, if it is copied and has type boolean.  (See comment in
13493  * lscf_revert()).
13494  */
13495 static int
13496 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
13497     uint8_t enabled)
13498 {
13499 	scf_transaction_t *tx;
13500 	scf_iter_t *iter, *viter;
13501 	scf_property_t *prop;
13502 	scf_value_t *v;
13503 	char *nbuf;
13504 	int r;
13505 
13506 	tx = scf_transaction_create(g_hndl);
13507 	if (tx == NULL)
13508 		scfdie();
13509 
13510 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
13511 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13512 			scfdie();
13513 
13514 		scf_transaction_destroy(tx);
13515 
13516 		return (-1);
13517 	}
13518 
13519 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13520 	    (prop = scf_property_create(g_hndl)) == NULL ||
13521 	    (viter = scf_iter_create(g_hndl)) == NULL)
13522 		scfdie();
13523 
13524 	nbuf = safe_malloc(max_scf_name_len + 1);
13525 
13526 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
13527 		scfdie();
13528 
13529 	for (;;) {
13530 		scf_transaction_entry_t *e;
13531 		scf_type_t ty;
13532 
13533 		r = scf_iter_next_property(iter, prop);
13534 		if (r == -1)
13535 			scfdie();
13536 		if (r == 0)
13537 			break;
13538 
13539 		e = scf_entry_create(g_hndl);
13540 		if (e == NULL)
13541 			scfdie();
13542 
13543 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
13544 			scfdie();
13545 
13546 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
13547 			scfdie();
13548 
13549 		if (scf_transaction_property_new(tx, e, nbuf,
13550 		    ty) != SCF_SUCCESS)
13551 			scfdie();
13552 
13553 		if ((enabled == 0 || enabled == 1) &&
13554 		    strcmp(nbuf, scf_property_enabled) == 0 &&
13555 		    ty == SCF_TYPE_BOOLEAN) {
13556 			v = scf_value_create(g_hndl);
13557 			if (v == NULL)
13558 				scfdie();
13559 
13560 			scf_value_set_boolean(v, enabled);
13561 
13562 			if (scf_entry_add_value(e, v) != 0)
13563 				scfdie();
13564 		} else {
13565 			if (scf_iter_property_values(viter, prop) != 0)
13566 				scfdie();
13567 
13568 			for (;;) {
13569 				v = scf_value_create(g_hndl);
13570 				if (v == NULL)
13571 					scfdie();
13572 
13573 				r = scf_iter_next_value(viter, v);
13574 				if (r == -1)
13575 					scfdie();
13576 				if (r == 0) {
13577 					scf_value_destroy(v);
13578 					break;
13579 				}
13580 
13581 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
13582 					scfdie();
13583 			}
13584 		}
13585 	}
13586 
13587 	free(nbuf);
13588 	scf_iter_destroy(viter);
13589 	scf_property_destroy(prop);
13590 	scf_iter_destroy(iter);
13591 
13592 	r = scf_transaction_commit(tx);
13593 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13594 		scfdie();
13595 
13596 	scf_transaction_destroy_children(tx);
13597 	scf_transaction_destroy(tx);
13598 
13599 	switch (r) {
13600 	case 1:		return (0);
13601 	case 0:		return (-2);
13602 	case -1:	return (-1);
13603 
13604 	default:
13605 		abort();
13606 	}
13607 
13608 	/* NOTREACHED */
13609 }
13610 
13611 void
13612 lscf_revert(const char *snapname)
13613 {
13614 	scf_snapshot_t *snap, *prev;
13615 	scf_snaplevel_t *level, *nlevel;
13616 	scf_iter_t *iter;
13617 	scf_propertygroup_t *pg, *npg;
13618 	scf_property_t *prop;
13619 	scf_value_t *val;
13620 	char *nbuf, *tbuf;
13621 	uint8_t enabled;
13622 
13623 	lscf_prep_hndl();
13624 
13625 	if (cur_inst == NULL) {
13626 		semerr(gettext("Instance not selected.\n"));
13627 		return;
13628 	}
13629 
13630 	if (snapname != NULL) {
13631 		snap = scf_snapshot_create(g_hndl);
13632 		if (snap == NULL)
13633 			scfdie();
13634 
13635 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
13636 		    SCF_SUCCESS) {
13637 			switch (scf_error()) {
13638 			case SCF_ERROR_INVALID_ARGUMENT:
13639 				semerr(gettext("Invalid snapshot name "
13640 				    "\"%s\".\n"), snapname);
13641 				break;
13642 
13643 			case SCF_ERROR_NOT_FOUND:
13644 				semerr(gettext("No such snapshot.\n"));
13645 				break;
13646 
13647 			default:
13648 				scfdie();
13649 			}
13650 
13651 			scf_snapshot_destroy(snap);
13652 			return;
13653 		}
13654 	} else {
13655 		if (cur_snap != NULL) {
13656 			snap = cur_snap;
13657 		} else {
13658 			semerr(gettext("No snapshot selected.\n"));
13659 			return;
13660 		}
13661 	}
13662 
13663 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
13664 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
13665 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13666 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13667 	    (npg = scf_pg_create(g_hndl)) == NULL ||
13668 	    (prop = scf_property_create(g_hndl)) == NULL ||
13669 	    (val = scf_value_create(g_hndl)) == NULL)
13670 		scfdie();
13671 
13672 	nbuf = safe_malloc(max_scf_name_len + 1);
13673 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
13674 
13675 	/* Take the "previous" snapshot before we blow away the properties. */
13676 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
13677 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
13678 			scfdie();
13679 	} else {
13680 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13681 			scfdie();
13682 
13683 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
13684 			scfdie();
13685 	}
13686 
13687 	/* Save general/enabled, since we're probably going to replace it. */
13688 	enabled = 2;
13689 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
13690 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
13691 	    scf_property_get_value(prop, val) == 0)
13692 		(void) scf_value_get_boolean(val, &enabled);
13693 
13694 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13695 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13696 			scfdie();
13697 
13698 		goto out;
13699 	}
13700 
13701 	for (;;) {
13702 		boolean_t isinst;
13703 		uint32_t flags;
13704 		int r;
13705 
13706 		/* Clear the properties from the corresponding entity. */
13707 		isinst = snaplevel_is_instance(level);
13708 
13709 		if (!isinst)
13710 			r = scf_iter_service_pgs(iter, cur_svc);
13711 		else
13712 			r = scf_iter_instance_pgs(iter, cur_inst);
13713 		if (r != SCF_SUCCESS)
13714 			scfdie();
13715 
13716 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13717 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13718 				scfdie();
13719 
13720 			/* Skip nonpersistent pgs. */
13721 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
13722 				continue;
13723 
13724 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
13725 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13726 					scfdie();
13727 
13728 				semerr(emsg_permission_denied);
13729 				goto out;
13730 			}
13731 		}
13732 		if (r == -1)
13733 			scfdie();
13734 
13735 		/* Copy the properties to the corresponding entity. */
13736 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
13737 			scfdie();
13738 
13739 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13740 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
13741 				scfdie();
13742 
13743 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
13744 			    0)
13745 				scfdie();
13746 
13747 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13748 				scfdie();
13749 
13750 			if (!isinst)
13751 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
13752 				    flags, npg);
13753 			else
13754 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
13755 				    flags, npg);
13756 			if (r != SCF_SUCCESS) {
13757 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13758 					scfdie();
13759 
13760 				semerr(emsg_permission_denied);
13761 				goto out;
13762 			}
13763 
13764 			if ((enabled == 0 || enabled == 1) &&
13765 			    strcmp(nbuf, scf_pg_general) == 0)
13766 				r = pg_copy(pg, npg, enabled);
13767 			else
13768 				r = pg_copy(pg, npg, 2);
13769 
13770 			switch (r) {
13771 			case 0:
13772 				break;
13773 
13774 			case -1:
13775 				semerr(emsg_permission_denied);
13776 				goto out;
13777 
13778 			case -2:
13779 				semerr(gettext(
13780 				    "Interrupted by another change.\n"));
13781 				goto out;
13782 
13783 			default:
13784 				abort();
13785 			}
13786 		}
13787 		if (r == -1)
13788 			scfdie();
13789 
13790 		/* Get next level. */
13791 		nlevel = scf_snaplevel_create(g_hndl);
13792 		if (nlevel == NULL)
13793 			scfdie();
13794 
13795 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
13796 		    SCF_SUCCESS) {
13797 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13798 				scfdie();
13799 
13800 			scf_snaplevel_destroy(nlevel);
13801 			break;
13802 		}
13803 
13804 		scf_snaplevel_destroy(level);
13805 		level = nlevel;
13806 	}
13807 
13808 	if (snapname == NULL) {
13809 		lscf_selectsnap(NULL);
13810 		snap = NULL;		/* cur_snap has been destroyed */
13811 	}
13812 
13813 out:
13814 	free(tbuf);
13815 	free(nbuf);
13816 	scf_value_destroy(val);
13817 	scf_property_destroy(prop);
13818 	scf_pg_destroy(npg);
13819 	scf_pg_destroy(pg);
13820 	scf_iter_destroy(iter);
13821 	scf_snaplevel_destroy(level);
13822 	scf_snapshot_destroy(prev);
13823 	if (snap != cur_snap)
13824 		scf_snapshot_destroy(snap);
13825 }
13826 
13827 void
13828 lscf_refresh(void)
13829 {
13830 	ssize_t fmrilen;
13831 	size_t bufsz;
13832 	char *fmribuf;
13833 	int r;
13834 
13835 	lscf_prep_hndl();
13836 
13837 	if (cur_inst == NULL) {
13838 		semerr(gettext("Instance not selected.\n"));
13839 		return;
13840 	}
13841 
13842 	bufsz = max_scf_fmri_len + 1;
13843 	fmribuf = safe_malloc(bufsz);
13844 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
13845 	if (fmrilen < 0) {
13846 		free(fmribuf);
13847 		if (scf_error() != SCF_ERROR_DELETED)
13848 			scfdie();
13849 		scf_instance_destroy(cur_inst);
13850 		cur_inst = NULL;
13851 		warn(emsg_deleted);
13852 		return;
13853 	}
13854 	assert(fmrilen < bufsz);
13855 
13856 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
13857 	switch (r) {
13858 	case 0:
13859 		break;
13860 
13861 	case ECONNABORTED:
13862 		warn(gettext("Could not refresh %s "
13863 		    "(repository connection broken).\n"), fmribuf);
13864 		break;
13865 
13866 	case ECANCELED:
13867 		warn(emsg_deleted);
13868 		break;
13869 
13870 	case EPERM:
13871 		warn(gettext("Could not refresh %s "
13872 		    "(permission denied).\n"), fmribuf);
13873 		break;
13874 
13875 	case ENOSPC:
13876 		warn(gettext("Could not refresh %s "
13877 		    "(repository server out of resources).\n"),
13878 		    fmribuf);
13879 		break;
13880 
13881 	case EACCES:
13882 	default:
13883 		bad_error("refresh_entity", scf_error());
13884 	}
13885 
13886 	free(fmribuf);
13887 }
13888 
13889 /*
13890  * describe [-v] [-t] [pg/prop]
13891  */
13892 int
13893 lscf_describe(uu_list_t *args, int hasargs)
13894 {
13895 	int ret = 0;
13896 	size_t i;
13897 	int argc;
13898 	char **argv = NULL;
13899 	string_list_t *slp;
13900 	int do_verbose = 0;
13901 	int do_templates = 0;
13902 	char *pattern = NULL;
13903 
13904 	lscf_prep_hndl();
13905 
13906 	if (hasargs != 0)  {
13907 		argc = uu_list_numnodes(args);
13908 		if (argc < 1)
13909 			goto usage;
13910 
13911 		argv = calloc(argc + 1, sizeof (char *));
13912 		if (argv == NULL)
13913 			uu_die(gettext("Out of memory.\n"));
13914 
13915 		for (slp = uu_list_first(args), i = 0;
13916 		    slp != NULL;
13917 		    slp = uu_list_next(args, slp), ++i)
13918 			argv[i] = slp->str;
13919 
13920 		argv[i] = NULL;
13921 
13922 		/*
13923 		 * We start optind = 0 because our list of arguments
13924 		 * starts at argv[0]
13925 		 */
13926 		optind = 0;
13927 		opterr = 0;
13928 		for (;;) {
13929 			ret = getopt(argc, argv, "vt");
13930 			if (ret == -1)
13931 				break;
13932 
13933 			switch (ret) {
13934 			case 'v':
13935 				do_verbose = 1;
13936 				break;
13937 
13938 			case 't':
13939 				do_templates = 1;
13940 				break;
13941 
13942 			case '?':
13943 				goto usage;
13944 
13945 			default:
13946 				bad_error("getopt", ret);
13947 			}
13948 		}
13949 
13950 		pattern = argv[optind];
13951 	}
13952 
13953 	if (cur_inst == NULL && cur_svc == NULL) {
13954 		semerr(emsg_entity_not_selected);
13955 		ret = -1;
13956 		goto out;
13957 	}
13958 
13959 	/*
13960 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
13961 	 * output if their last parameter is set to 2.  Less information is
13962 	 * produced if the parameter is set to 1.
13963 	 */
13964 	if (pattern == NULL) {
13965 		if (do_verbose == 1)
13966 			list_entity_tmpl(2);
13967 		else
13968 			list_entity_tmpl(1);
13969 	}
13970 
13971 	if (do_templates == 0) {
13972 		if (do_verbose == 1)
13973 			listprop(pattern, 0, 2);
13974 		else
13975 			listprop(pattern, 0, 1);
13976 	} else {
13977 		if (do_verbose == 1)
13978 			listtmpl(pattern, 2);
13979 		else
13980 			listtmpl(pattern, 1);
13981 	}
13982 
13983 	ret = 0;
13984 out:
13985 	if (argv != NULL)
13986 		free(argv);
13987 	return (ret);
13988 usage:
13989 	ret = -2;
13990 	goto out;
13991 }
13992 
13993 #ifndef NATIVE_BUILD
13994 /* ARGSUSED */
13995 CPL_MATCH_FN(complete_select)
13996 {
13997 	const char *arg0, *arg1, *arg1end;
13998 	int word_start, err = 0, r;
13999 	size_t len;
14000 	char *buf;
14001 
14002 	lscf_prep_hndl();
14003 
14004 	arg0 = line + strspn(line, " \t");
14005 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
14006 
14007 	arg1 = arg0 + sizeof ("select") - 1;
14008 	arg1 += strspn(arg1, " \t");
14009 	word_start = arg1 - line;
14010 
14011 	arg1end = arg1 + strcspn(arg1, " \t");
14012 	if (arg1end < line + word_end)
14013 		return (0);
14014 
14015 	len = line + word_end - arg1;
14016 
14017 	buf = safe_malloc(max_scf_name_len + 1);
14018 
14019 	if (cur_snap != NULL) {
14020 		return (0);
14021 	} else if (cur_inst != NULL) {
14022 		return (0);
14023 	} else if (cur_svc != NULL) {
14024 		scf_instance_t *inst;
14025 		scf_iter_t *iter;
14026 
14027 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
14028 		    (iter = scf_iter_create(g_hndl)) == NULL)
14029 			scfdie();
14030 
14031 		if (scf_iter_service_instances(iter, cur_svc) != 0)
14032 			scfdie();
14033 
14034 		for (;;) {
14035 			r = scf_iter_next_instance(iter, inst);
14036 			if (r == 0)
14037 				break;
14038 			if (r != 1)
14039 				scfdie();
14040 
14041 			if (scf_instance_get_name(inst, buf,
14042 			    max_scf_name_len + 1) < 0)
14043 				scfdie();
14044 
14045 			if (strncmp(buf, arg1, len) == 0) {
14046 				err = cpl_add_completion(cpl, line, word_start,
14047 				    word_end, buf + len, "", " ");
14048 				if (err != 0)
14049 					break;
14050 			}
14051 		}
14052 
14053 		scf_iter_destroy(iter);
14054 		scf_instance_destroy(inst);
14055 
14056 		return (err);
14057 	} else {
14058 		scf_service_t *svc;
14059 		scf_iter_t *iter;
14060 
14061 		assert(cur_scope != NULL);
14062 
14063 		if ((svc = scf_service_create(g_hndl)) == NULL ||
14064 		    (iter = scf_iter_create(g_hndl)) == NULL)
14065 			scfdie();
14066 
14067 		if (scf_iter_scope_services(iter, cur_scope) != 0)
14068 			scfdie();
14069 
14070 		for (;;) {
14071 			r = scf_iter_next_service(iter, svc);
14072 			if (r == 0)
14073 				break;
14074 			if (r != 1)
14075 				scfdie();
14076 
14077 			if (scf_service_get_name(svc, buf,
14078 			    max_scf_name_len + 1) < 0)
14079 				scfdie();
14080 
14081 			if (strncmp(buf, arg1, len) == 0) {
14082 				err = cpl_add_completion(cpl, line, word_start,
14083 				    word_end, buf + len, "", " ");
14084 				if (err != 0)
14085 					break;
14086 			}
14087 		}
14088 
14089 		scf_iter_destroy(iter);
14090 		scf_service_destroy(svc);
14091 
14092 		return (err);
14093 	}
14094 }
14095 
14096 /* ARGSUSED */
14097 CPL_MATCH_FN(complete_command)
14098 {
14099 	uint32_t scope = 0;
14100 
14101 	if (cur_snap != NULL)
14102 		scope = CS_SNAP;
14103 	else if (cur_inst != NULL)
14104 		scope = CS_INST;
14105 	else if (cur_svc != NULL)
14106 		scope = CS_SVC;
14107 	else
14108 		scope = CS_SCOPE;
14109 
14110 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
14111 }
14112 #endif	/* NATIVE_BUILD */
14113