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