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