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