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