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