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