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