xref: /illumos-gate/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision bfed486ad8de8b8ebc6345a8e10accae08bf2f45)
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 	cbdata.sc_flags = 0;
6082 
6083 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6084 	    UU_DEFAULT) != 0) {
6085 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6086 			bad_error("uu_list_walk", uu_error());
6087 
6088 		lcbdata->sc_err = cbdata.sc_err;
6089 		switch (cbdata.sc_err) {
6090 		case ECONNABORTED:
6091 			goto connaborted;
6092 
6093 		case ECANCELED:
6094 			warn(ts_deleted, imp_tsname);
6095 			lcbdata->sc_err = EBUSY;
6096 			return (UU_WALK_ERROR);
6097 
6098 		case EEXIST:
6099 			warn(ts_pg_added, imp_tsname);
6100 			lcbdata->sc_err = EBUSY;
6101 			return (UU_WALK_ERROR);
6102 		}
6103 
6104 		r = UU_WALK_ERROR;
6105 		goto deltemp;
6106 	}
6107 
6108 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6109 	    UU_DEFAULT) != 0) {
6110 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6111 			bad_error("uu_list_walk", uu_error());
6112 
6113 		lcbdata->sc_err = cbdata.sc_err;
6114 		switch (cbdata.sc_err) {
6115 		case ECONNABORTED:
6116 			goto connaborted;
6117 
6118 		case ECANCELED:
6119 			warn(ts_deleted, imp_tsname);
6120 			lcbdata->sc_err = EBUSY;
6121 			return (UU_WALK_ERROR);
6122 
6123 		case EEXIST:
6124 			warn(ts_pg_added, imp_tsname);
6125 			lcbdata->sc_err = EBUSY;
6126 			return (UU_WALK_ERROR);
6127 		}
6128 
6129 		r = UU_WALK_ERROR;
6130 		goto deltemp;
6131 	}
6132 
6133 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6134 		switch (scf_error()) {
6135 		case SCF_ERROR_NOT_FOUND:
6136 			break;
6137 
6138 		case SCF_ERROR_CONNECTION_BROKEN:
6139 			goto connaborted;
6140 
6141 		case SCF_ERROR_INVALID_ARGUMENT:
6142 		case SCF_ERROR_HANDLE_MISMATCH:
6143 		case SCF_ERROR_NOT_BOUND:
6144 		case SCF_ERROR_NOT_SET:
6145 		default:
6146 			bad_error("scf_scope_get_service", scf_error());
6147 		}
6148 
6149 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6150 			switch (scf_error()) {
6151 			case SCF_ERROR_CONNECTION_BROKEN:
6152 				goto connaborted;
6153 
6154 			case SCF_ERROR_NO_RESOURCES:
6155 			case SCF_ERROR_BACKEND_READONLY:
6156 			case SCF_ERROR_BACKEND_ACCESS:
6157 				r = stash_scferror(lcbdata);
6158 				goto deltemp;
6159 
6160 			case SCF_ERROR_EXISTS:
6161 				warn(gettext("Scope \"%s\" changed unexpectedly"
6162 				    " (service \"%s\" added).\n"),
6163 				    SCF_SCOPE_LOCAL, s->sc_name);
6164 				lcbdata->sc_err = EBUSY;
6165 				goto deltemp;
6166 
6167 			case SCF_ERROR_PERMISSION_DENIED:
6168 				warn(gettext("Could not create service \"%s\" "
6169 				    "(permission denied).\n"), s->sc_name);
6170 				goto deltemp;
6171 
6172 			case SCF_ERROR_INVALID_ARGUMENT:
6173 			case SCF_ERROR_HANDLE_MISMATCH:
6174 			case SCF_ERROR_NOT_BOUND:
6175 			case SCF_ERROR_NOT_SET:
6176 			default:
6177 				bad_error("scf_scope_add_service", scf_error());
6178 			}
6179 		}
6180 
6181 		s->sc_import_state = IMPORT_PROP_BEGUN;
6182 
6183 		/* import service properties */
6184 		cbdata.sc_handle = lcbdata->sc_handle;
6185 		cbdata.sc_parent = imp_svc;
6186 		cbdata.sc_service = 1;
6187 		cbdata.sc_flags = lcbdata->sc_flags;
6188 		cbdata.sc_source_fmri = s->sc_fmri;
6189 		cbdata.sc_target_fmri = s->sc_fmri;
6190 
6191 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6192 		    &cbdata, UU_DEFAULT) != 0) {
6193 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6194 				bad_error("uu_list_walk", uu_error());
6195 
6196 			lcbdata->sc_err = cbdata.sc_err;
6197 			switch (cbdata.sc_err) {
6198 			case ECONNABORTED:
6199 				goto connaborted;
6200 
6201 			case ECANCELED:
6202 				warn(s_deleted, s->sc_fmri);
6203 				lcbdata->sc_err = EBUSY;
6204 				return (UU_WALK_ERROR);
6205 
6206 			case EEXIST:
6207 				warn(gettext("%s changed unexpectedly "
6208 				    "(property group added).\n"), s->sc_fmri);
6209 				lcbdata->sc_err = EBUSY;
6210 				return (UU_WALK_ERROR);
6211 
6212 			case EINVAL:
6213 				/* caught above */
6214 				bad_error("entity_pgroup_import",
6215 				    cbdata.sc_err);
6216 			}
6217 
6218 			r = UU_WALK_ERROR;
6219 			goto deltemp;
6220 		}
6221 
6222 		cbdata.sc_trans = NULL;
6223 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
6224 		    &cbdata, UU_DEFAULT) != 0) {
6225 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6226 				bad_error("uu_list_walk", uu_error());
6227 
6228 			lcbdata->sc_err = cbdata.sc_err;
6229 			if (cbdata.sc_err == ECONNABORTED)
6230 				goto connaborted;
6231 			r = UU_WALK_ERROR;
6232 			goto deltemp;
6233 		}
6234 
6235 		s->sc_import_state = IMPORT_PROP_DONE;
6236 
6237 		/*
6238 		 * This is a new service, so we can't take previous snapshots
6239 		 * or upgrade service properties.
6240 		 */
6241 		fresh = 1;
6242 		goto instances;
6243 	}
6244 
6245 	/* Clear sc_seen for the instances. */
6246 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
6247 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
6248 		bad_error("uu_list_walk", uu_error());
6249 
6250 	/*
6251 	 * Take previous snapshots for all instances.  Even for ones not
6252 	 * mentioned in the bundle, since we might change their service
6253 	 * properties.
6254 	 */
6255 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6256 		switch (scf_error()) {
6257 		case SCF_ERROR_CONNECTION_BROKEN:
6258 			goto connaborted;
6259 
6260 		case SCF_ERROR_DELETED:
6261 			warn(s_deleted, s->sc_fmri);
6262 			lcbdata->sc_err = EBUSY;
6263 			r = UU_WALK_ERROR;
6264 			goto deltemp;
6265 
6266 		case SCF_ERROR_HANDLE_MISMATCH:
6267 		case SCF_ERROR_NOT_BOUND:
6268 		case SCF_ERROR_NOT_SET:
6269 		default:
6270 			bad_error("scf_iter_service_instances", scf_error());
6271 		}
6272 	}
6273 
6274 	for (;;) {
6275 		r = scf_iter_next_instance(imp_iter, imp_inst);
6276 		if (r == 0)
6277 			break;
6278 		if (r != 1) {
6279 			switch (scf_error()) {
6280 			case SCF_ERROR_DELETED:
6281 				warn(s_deleted, s->sc_fmri);
6282 				lcbdata->sc_err = EBUSY;
6283 				r = UU_WALK_ERROR;
6284 				goto deltemp;
6285 
6286 			case SCF_ERROR_CONNECTION_BROKEN:
6287 				goto connaborted;
6288 
6289 			case SCF_ERROR_NOT_BOUND:
6290 			case SCF_ERROR_HANDLE_MISMATCH:
6291 			case SCF_ERROR_INVALID_ARGUMENT:
6292 			case SCF_ERROR_NOT_SET:
6293 			default:
6294 				bad_error("scf_iter_next_instance",
6295 				    scf_error());
6296 			}
6297 		}
6298 
6299 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
6300 			switch (scf_error()) {
6301 			case SCF_ERROR_DELETED:
6302 				continue;
6303 
6304 			case SCF_ERROR_CONNECTION_BROKEN:
6305 				goto connaborted;
6306 
6307 			case SCF_ERROR_NOT_SET:
6308 			case SCF_ERROR_NOT_BOUND:
6309 			default:
6310 				bad_error("scf_instance_get_name", scf_error());
6311 			}
6312 		}
6313 
6314 		if (g_verbose)
6315 			warn(gettext(
6316 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
6317 			    snap_previous, s->sc_name, imp_str);
6318 
6319 		r = take_snap(imp_inst, snap_previous, imp_snap);
6320 		switch (r) {
6321 		case 0:
6322 			break;
6323 
6324 		case ECANCELED:
6325 			continue;
6326 
6327 		case ECONNABORTED:
6328 			goto connaborted;
6329 
6330 		case EPERM:
6331 			warn(gettext("Could not take \"%s\" snapshot of "
6332 			    "svc:/%s:%s (permission denied).\n"),
6333 			    snap_previous, s->sc_name, imp_str);
6334 			lcbdata->sc_err = r;
6335 			return (UU_WALK_ERROR);
6336 
6337 		case ENOSPC:
6338 		case -1:
6339 			lcbdata->sc_err = r;
6340 			r = UU_WALK_ERROR;
6341 			goto deltemp;
6342 
6343 		default:
6344 			bad_error("take_snap", r);
6345 		}
6346 
6347 		linst.sc_name = imp_str;
6348 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
6349 		    &linst, NULL, NULL);
6350 		if (inst != NULL) {
6351 			inst->sc_import_state = IMPORT_PREVIOUS;
6352 			inst->sc_seen = 1;
6353 		}
6354 	}
6355 
6356 	/*
6357 	 * Create the new instances and take previous snapshots of
6358 	 * them.  This is not necessary, but it maximizes data preservation.
6359 	 */
6360 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
6361 	    inst != NULL;
6362 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
6363 	    inst)) {
6364 		if (inst->sc_seen)
6365 			continue;
6366 
6367 		if (scf_service_add_instance(imp_svc, inst->sc_name,
6368 		    imp_inst) != 0) {
6369 			switch (scf_error()) {
6370 			case SCF_ERROR_CONNECTION_BROKEN:
6371 				goto connaborted;
6372 
6373 			case SCF_ERROR_BACKEND_READONLY:
6374 			case SCF_ERROR_BACKEND_ACCESS:
6375 			case SCF_ERROR_NO_RESOURCES:
6376 				r = stash_scferror(lcbdata);
6377 				goto deltemp;
6378 
6379 			case SCF_ERROR_EXISTS:
6380 				warn(gettext("%s changed unexpectedly "
6381 				    "(instance \"%s\" added).\n"), s->sc_fmri,
6382 				    inst->sc_name);
6383 				lcbdata->sc_err = EBUSY;
6384 				r = UU_WALK_ERROR;
6385 				goto deltemp;
6386 
6387 			case SCF_ERROR_INVALID_ARGUMENT:
6388 				warn(gettext("Service \"%s\" has instance with "
6389 				    "invalid name \"%s\".\n"), s->sc_name,
6390 				    inst->sc_name);
6391 				r = stash_scferror(lcbdata);
6392 				goto deltemp;
6393 
6394 			case SCF_ERROR_PERMISSION_DENIED:
6395 				warn(gettext("Could not create instance \"%s\" "
6396 				    "in %s (permission denied).\n"),
6397 				    inst->sc_name, s->sc_fmri);
6398 				r = stash_scferror(lcbdata);
6399 				goto deltemp;
6400 
6401 			case SCF_ERROR_HANDLE_MISMATCH:
6402 			case SCF_ERROR_NOT_BOUND:
6403 			case SCF_ERROR_NOT_SET:
6404 			default:
6405 				bad_error("scf_service_add_instance",
6406 				    scf_error());
6407 			}
6408 		}
6409 
6410 		if (g_verbose)
6411 			warn(gettext("Taking \"%s\" snapshot for "
6412 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
6413 		r = take_snap(imp_inst, snap_previous, imp_snap);
6414 		switch (r) {
6415 		case 0:
6416 			break;
6417 
6418 		case ECANCELED:
6419 			warn(i_deleted, s->sc_fmri, inst->sc_name);
6420 			lcbdata->sc_err = EBUSY;
6421 			r = UU_WALK_ERROR;
6422 			goto deltemp;
6423 
6424 		case ECONNABORTED:
6425 			goto connaborted;
6426 
6427 		case EPERM:
6428 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
6429 			lcbdata->sc_err = r;
6430 			r = UU_WALK_ERROR;
6431 			goto deltemp;
6432 
6433 		case ENOSPC:
6434 		case -1:
6435 			r = UU_WALK_ERROR;
6436 			goto deltemp;
6437 
6438 		default:
6439 			bad_error("take_snap", r);
6440 		}
6441 	}
6442 
6443 	s->sc_import_state = IMPORT_PREVIOUS;
6444 
6445 	/*
6446 	 * Upgrade service properties, if we can find a last-import snapshot.
6447 	 * Any will do because we don't support different service properties
6448 	 * in different manifests, so all snaplevels of the service in all of
6449 	 * the last-import snapshots of the instances should be the same.
6450 	 */
6451 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6452 		switch (scf_error()) {
6453 		case SCF_ERROR_CONNECTION_BROKEN:
6454 			goto connaborted;
6455 
6456 		case SCF_ERROR_DELETED:
6457 			warn(s_deleted, s->sc_fmri);
6458 			lcbdata->sc_err = EBUSY;
6459 			r = UU_WALK_ERROR;
6460 			goto deltemp;
6461 
6462 		case SCF_ERROR_HANDLE_MISMATCH:
6463 		case SCF_ERROR_NOT_BOUND:
6464 		case SCF_ERROR_NOT_SET:
6465 		default:
6466 			bad_error("scf_iter_service_instances", scf_error());
6467 		}
6468 	}
6469 
6470 	have_ge = 0;
6471 	li_only = 0;
6472 
6473 	for (;;) {
6474 		r = scf_iter_next_instance(imp_iter, imp_inst);
6475 		if (r == -1) {
6476 			switch (scf_error()) {
6477 			case SCF_ERROR_DELETED:
6478 				warn(s_deleted, s->sc_fmri);
6479 				lcbdata->sc_err = EBUSY;
6480 				r = UU_WALK_ERROR;
6481 				goto deltemp;
6482 
6483 			case SCF_ERROR_CONNECTION_BROKEN:
6484 				goto connaborted;
6485 
6486 			case SCF_ERROR_NOT_BOUND:
6487 			case SCF_ERROR_HANDLE_MISMATCH:
6488 			case SCF_ERROR_INVALID_ARGUMENT:
6489 			case SCF_ERROR_NOT_SET:
6490 			default:
6491 				bad_error("scf_iter_next_instance",
6492 				    scf_error());
6493 			}
6494 		}
6495 
6496 		if (r == 0) {
6497 			/*
6498 			 * Didn't find any last-import snapshots.  Override-
6499 			 * import the properties.  Unless one of the instances
6500 			 * has a general/enabled property, in which case we're
6501 			 * probably running a last-import-capable svccfg for
6502 			 * the first time, and we should only take the
6503 			 * last-import snapshot.
6504 			 */
6505 			if (have_ge) {
6506 				li_only = 1;
6507 				no_refresh = 1;
6508 				break;
6509 			}
6510 
6511 			s->sc_import_state = IMPORT_PROP_BEGUN;
6512 
6513 			cbdata.sc_handle = g_hndl;
6514 			cbdata.sc_parent = imp_svc;
6515 			cbdata.sc_service = 1;
6516 			cbdata.sc_flags = SCI_FORCE;
6517 			cbdata.sc_source_fmri = s->sc_fmri;
6518 			cbdata.sc_target_fmri = s->sc_fmri;
6519 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6520 			    &cbdata, UU_DEFAULT) != 0) {
6521 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6522 					bad_error("uu_list_walk", uu_error());
6523 				lcbdata->sc_err = cbdata.sc_err;
6524 				switch (cbdata.sc_err) {
6525 				case ECONNABORTED:
6526 					goto connaborted;
6527 
6528 				case ECANCELED:
6529 					warn(s_deleted, s->sc_fmri);
6530 					lcbdata->sc_err = EBUSY;
6531 					break;
6532 
6533 				case EINVAL:	/* caught above */
6534 				case EEXIST:
6535 					bad_error("entity_pgroup_import",
6536 					    cbdata.sc_err);
6537 				}
6538 
6539 				r = UU_WALK_ERROR;
6540 				goto deltemp;
6541 			}
6542 
6543 			cbdata.sc_trans = NULL;
6544 			if (uu_list_walk(s->sc_dependents,
6545 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
6546 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6547 					bad_error("uu_list_walk", uu_error());
6548 				lcbdata->sc_err = cbdata.sc_err;
6549 				if (cbdata.sc_err == ECONNABORTED)
6550 					goto connaborted;
6551 				r = UU_WALK_ERROR;
6552 				goto deltemp;
6553 			}
6554 			break;
6555 		}
6556 
6557 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6558 		    imp_snap) != 0) {
6559 			switch (scf_error()) {
6560 			case SCF_ERROR_DELETED:
6561 				continue;
6562 
6563 			case SCF_ERROR_NOT_FOUND:
6564 				break;
6565 
6566 			case SCF_ERROR_CONNECTION_BROKEN:
6567 				goto connaborted;
6568 
6569 			case SCF_ERROR_HANDLE_MISMATCH:
6570 			case SCF_ERROR_NOT_BOUND:
6571 			case SCF_ERROR_INVALID_ARGUMENT:
6572 			case SCF_ERROR_NOT_SET:
6573 			default:
6574 				bad_error("scf_instance_get_snapshot",
6575 				    scf_error());
6576 			}
6577 
6578 			if (have_ge)
6579 				continue;
6580 
6581 			/*
6582 			 * Check for a general/enabled property.  This is how
6583 			 * we tell whether to import if there turn out to be
6584 			 * no last-import snapshots.
6585 			 */
6586 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
6587 			    imp_pg) == 0) {
6588 				if (scf_pg_get_property(imp_pg,
6589 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
6590 					have_ge = 1;
6591 				} else {
6592 					switch (scf_error()) {
6593 					case SCF_ERROR_DELETED:
6594 					case SCF_ERROR_NOT_FOUND:
6595 						continue;
6596 
6597 					case SCF_ERROR_INVALID_ARGUMENT:
6598 					case SCF_ERROR_HANDLE_MISMATCH:
6599 					case SCF_ERROR_CONNECTION_BROKEN:
6600 					case SCF_ERROR_NOT_BOUND:
6601 					case SCF_ERROR_NOT_SET:
6602 					default:
6603 						bad_error("scf_pg_get_property",
6604 						    scf_error());
6605 					}
6606 				}
6607 			} else {
6608 				switch (scf_error()) {
6609 				case SCF_ERROR_DELETED:
6610 				case SCF_ERROR_NOT_FOUND:
6611 					continue;
6612 
6613 				case SCF_ERROR_CONNECTION_BROKEN:
6614 					goto connaborted;
6615 
6616 				case SCF_ERROR_NOT_BOUND:
6617 				case SCF_ERROR_NOT_SET:
6618 				case SCF_ERROR_INVALID_ARGUMENT:
6619 				case SCF_ERROR_HANDLE_MISMATCH:
6620 				default:
6621 					bad_error("scf_instance_get_pg",
6622 					    scf_error());
6623 				}
6624 			}
6625 			continue;
6626 		}
6627 
6628 		/* find service snaplevel */
6629 		r = get_snaplevel(imp_snap, 1, imp_snpl);
6630 		switch (r) {
6631 		case 0:
6632 			break;
6633 
6634 		case ECONNABORTED:
6635 			goto connaborted;
6636 
6637 		case ECANCELED:
6638 			continue;
6639 
6640 		case ENOENT:
6641 			if (scf_instance_get_name(imp_inst, imp_str,
6642 			    imp_str_sz) < 0)
6643 				(void) strcpy(imp_str, "?");
6644 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
6645 			lcbdata->sc_err = EBADF;
6646 			r = UU_WALK_ERROR;
6647 			goto deltemp;
6648 
6649 		default:
6650 			bad_error("get_snaplevel", r);
6651 		}
6652 
6653 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6654 		    imp_rsnap) != 0) {
6655 			switch (scf_error()) {
6656 			case SCF_ERROR_DELETED:
6657 				continue;
6658 
6659 			case SCF_ERROR_NOT_FOUND:
6660 				break;
6661 
6662 			case SCF_ERROR_CONNECTION_BROKEN:
6663 				goto connaborted;
6664 
6665 			case SCF_ERROR_INVALID_ARGUMENT:
6666 			case SCF_ERROR_HANDLE_MISMATCH:
6667 			case SCF_ERROR_NOT_BOUND:
6668 			case SCF_ERROR_NOT_SET:
6669 			default:
6670 				bad_error("scf_instance_get_snapshot",
6671 				    scf_error());
6672 			}
6673 			running = NULL;
6674 		} else {
6675 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
6676 			switch (r) {
6677 			case 0:
6678 				running = imp_rsnpl;
6679 				break;
6680 
6681 			case ECONNABORTED:
6682 				goto connaborted;
6683 
6684 			case ECANCELED:
6685 				continue;
6686 
6687 			case ENOENT:
6688 				if (scf_instance_get_name(imp_inst, imp_str,
6689 				    imp_str_sz) < 0)
6690 					(void) strcpy(imp_str, "?");
6691 				warn(badsnap, snap_running, s->sc_name,
6692 				    imp_str);
6693 				lcbdata->sc_err = EBADF;
6694 				r = UU_WALK_ERROR;
6695 				goto deltemp;
6696 
6697 			default:
6698 				bad_error("get_snaplevel", r);
6699 			}
6700 		}
6701 
6702 		if (g_verbose) {
6703 			if (scf_instance_get_name(imp_inst, imp_str,
6704 			    imp_str_sz) < 0)
6705 				(void) strcpy(imp_str, "?");
6706 			warn(gettext("Upgrading properties of %s according to "
6707 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
6708 		}
6709 
6710 		/* upgrade service properties */
6711 		r = upgrade_props(imp_svc, running, imp_snpl, s);
6712 		if (r == 0)
6713 			break;
6714 
6715 		switch (r) {
6716 		case ECONNABORTED:
6717 			goto connaborted;
6718 
6719 		case ECANCELED:
6720 			warn(s_deleted, s->sc_fmri);
6721 			lcbdata->sc_err = EBUSY;
6722 			break;
6723 
6724 		case ENODEV:
6725 			if (scf_instance_get_name(imp_inst, imp_str,
6726 			    imp_str_sz) < 0)
6727 				(void) strcpy(imp_str, "?");
6728 			warn(i_deleted, s->sc_fmri, imp_str);
6729 			lcbdata->sc_err = EBUSY;
6730 			break;
6731 
6732 		default:
6733 			lcbdata->sc_err = r;
6734 		}
6735 
6736 		r = UU_WALK_ERROR;
6737 		goto deltemp;
6738 	}
6739 
6740 	s->sc_import_state = IMPORT_PROP_DONE;
6741 
6742 instances:
6743 	/* import instances */
6744 	cbdata.sc_handle = lcbdata->sc_handle;
6745 	cbdata.sc_parent = imp_svc;
6746 	cbdata.sc_service = 1;
6747 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
6748 	cbdata.sc_general = NULL;
6749 
6750 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
6751 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
6752 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6753 			bad_error("uu_list_walk", uu_error());
6754 
6755 		lcbdata->sc_err = cbdata.sc_err;
6756 		if (cbdata.sc_err == ECONNABORTED)
6757 			goto connaborted;
6758 		r = UU_WALK_ERROR;
6759 		goto deltemp;
6760 	}
6761 
6762 	s->sc_import_state = IMPORT_COMPLETE;
6763 	r = UU_WALK_NEXT;
6764 
6765 deltemp:
6766 	/* delete temporary service */
6767 	if (scf_service_delete(imp_tsvc) != 0) {
6768 		switch (scf_error()) {
6769 		case SCF_ERROR_DELETED:
6770 			break;
6771 
6772 		case SCF_ERROR_CONNECTION_BROKEN:
6773 			goto connaborted;
6774 
6775 		case SCF_ERROR_EXISTS:
6776 			warn(gettext(
6777 			    "Could not delete svc:/%s (instances exist).\n"),
6778 			    imp_tsname);
6779 			break;
6780 
6781 		case SCF_ERROR_NOT_SET:
6782 		case SCF_ERROR_NOT_BOUND:
6783 		default:
6784 			bad_error("scf_service_delete", scf_error());
6785 		}
6786 	}
6787 
6788 	return (r);
6789 
6790 connaborted:
6791 	warn(gettext("Could not delete svc:/%s "
6792 	    "(repository connection broken).\n"), imp_tsname);
6793 	lcbdata->sc_err = ECONNABORTED;
6794 	return (UU_WALK_ERROR);
6795 }
6796 
6797 static const char *
6798 import_progress(int st)
6799 {
6800 	switch (st) {
6801 	case 0:
6802 		return (gettext("not reached."));
6803 
6804 	case IMPORT_PREVIOUS:
6805 		return (gettext("previous snapshot taken."));
6806 
6807 	case IMPORT_PROP_BEGUN:
6808 		return (gettext("some properties imported."));
6809 
6810 	case IMPORT_PROP_DONE:
6811 		return (gettext("properties imported."));
6812 
6813 	case IMPORT_COMPLETE:
6814 		return (gettext("imported."));
6815 
6816 	case IMPORT_REFRESHED:
6817 		return (gettext("refresh requested."));
6818 
6819 	default:
6820 #ifndef NDEBUG
6821 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
6822 		    __FILE__, __LINE__, st);
6823 #endif
6824 		abort();
6825 		/* NOTREACHED */
6826 	}
6827 }
6828 
6829 /*
6830  * Returns
6831  *   0 - success
6832  *     - fmri wasn't found (error printed)
6833  *     - entity was deleted (error printed)
6834  *     - backend denied access (error printed)
6835  *   ENOMEM - out of memory (error printed)
6836  *   ECONNABORTED - repository connection broken (error printed)
6837  *   EPERM - permission denied (error printed)
6838  *   -1 - unknown libscf error (error printed)
6839  */
6840 static int
6841 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
6842 {
6843 	scf_error_t serr;
6844 	void *ent;
6845 	int issvc;
6846 	int r;
6847 
6848 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
6849 	const char *dpt_deleted = gettext("Could not refresh %s "
6850 	    "(dependent \"%s\" of %s) (deleted).\n");
6851 
6852 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
6853 	switch (serr) {
6854 	case SCF_ERROR_NONE:
6855 		break;
6856 
6857 	case SCF_ERROR_NO_MEMORY:
6858 		if (name == NULL)
6859 			warn(gettext("Could not refresh %s (out of memory).\n"),
6860 			    fmri);
6861 		else
6862 			warn(gettext("Could not refresh %s "
6863 			    "(dependent \"%s\" of %s) (out of memory).\n"),
6864 			    fmri, name, d_fmri);
6865 		return (ENOMEM);
6866 
6867 	case SCF_ERROR_NOT_FOUND:
6868 		if (name == NULL)
6869 			warn(deleted, fmri);
6870 		else
6871 			warn(dpt_deleted, fmri, name, d_fmri);
6872 		return (0);
6873 
6874 	case SCF_ERROR_INVALID_ARGUMENT:
6875 	case SCF_ERROR_CONSTRAINT_VIOLATED:
6876 	default:
6877 		bad_error("fmri_to_entity", serr);
6878 	}
6879 
6880 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
6881 	switch (r) {
6882 	case 0:
6883 		break;
6884 
6885 	case ECONNABORTED:
6886 		if (name != NULL)
6887 			warn(gettext("Could not refresh %s "
6888 			    "(dependent \"%s\" of %s) "
6889 			    "(repository connection broken).\n"), fmri, name,
6890 			    d_fmri);
6891 		return (r);
6892 
6893 	case ECANCELED:
6894 		if (name == NULL)
6895 			warn(deleted, fmri);
6896 		else
6897 			warn(dpt_deleted, fmri, name, d_fmri);
6898 		return (0);
6899 
6900 	case EACCES:
6901 		if (!g_verbose)
6902 			return (0);
6903 		if (name == NULL)
6904 			warn(gettext("Could not refresh %s "
6905 			    "(backend access denied).\n"), fmri);
6906 		else
6907 			warn(gettext("Could not refresh %s "
6908 			    "(dependent \"%s\" of %s) "
6909 			    "(backend access denied).\n"), fmri, name, d_fmri);
6910 		return (0);
6911 
6912 	case EPERM:
6913 		if (name == NULL)
6914 			warn(gettext("Could not refresh %s "
6915 			    "(permission denied).\n"), fmri);
6916 		else
6917 			warn(gettext("Could not refresh %s "
6918 			    "(dependent \"%s\" of %s) "
6919 			    "(permission denied).\n"), fmri, name, d_fmri);
6920 		return (r);
6921 
6922 	case ENOSPC:
6923 		if (name == NULL)
6924 			warn(gettext("Could not refresh %s "
6925 			    "(repository server out of resources).\n"),
6926 			    fmri);
6927 		else
6928 			warn(gettext("Could not refresh %s "
6929 			    "(dependent \"%s\" of %s) "
6930 			    "(repository server out of resources).\n"),
6931 			    fmri, name, d_fmri);
6932 		return (r);
6933 
6934 	case -1:
6935 		scfwarn();
6936 		return (r);
6937 
6938 	default:
6939 		bad_error("refresh_entity", r);
6940 	}
6941 
6942 	if (issvc)
6943 		scf_service_destroy(ent);
6944 	else
6945 		scf_instance_destroy(ent);
6946 
6947 	return (0);
6948 }
6949 
6950 int
6951 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
6952 {
6953 	scf_callback_t cbdata;
6954 	int result = 0;
6955 	entity_t *svc, *inst;
6956 	uu_list_t *insts;
6957 	int r;
6958 	pgroup_t *old_dpt;
6959 	void *cookie;
6960 	int annotation_set = 0;
6961 
6962 	const char * const emsg_nomem = gettext("Out of memory.\n");
6963 	const char * const emsg_nores =
6964 	    gettext("svc.configd is out of resources.\n");
6965 
6966 	lscf_prep_hndl();
6967 
6968 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
6969 	    max_scf_name_len : max_scf_fmri_len) + 1;
6970 
6971 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
6972 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
6973 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
6974 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
6975 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
6976 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
6977 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
6978 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
6979 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
6980 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
6981 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
6982 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
6983 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
6984 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
6985 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
6986 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
6987 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
6988 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
6989 	    (imp_str = malloc(imp_str_sz)) == NULL ||
6990 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
6991 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
6992 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
6993 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
6994 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
6995 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
6996 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
6997 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
6998 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
6999 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7000 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7001 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7002 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7003 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7004 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7005 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7006 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7007 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7008 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7009 			warn(emsg_nores);
7010 		else
7011 			warn(emsg_nomem);
7012 		result = -1;
7013 		goto out;
7014 	}
7015 
7016 	r = load_init();
7017 	switch (r) {
7018 	case 0:
7019 		break;
7020 
7021 	case ENOMEM:
7022 		warn(emsg_nomem);
7023 		result = -1;
7024 		goto out;
7025 
7026 	default:
7027 		bad_error("load_init", r);
7028 	}
7029 
7030 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7031 		switch (scf_error()) {
7032 		case SCF_ERROR_CONNECTION_BROKEN:
7033 			warn(gettext("Repository connection broken.\n"));
7034 			repository_teardown();
7035 			result = -1;
7036 			goto out;
7037 
7038 		case SCF_ERROR_NOT_FOUND:
7039 		case SCF_ERROR_INVALID_ARGUMENT:
7040 		case SCF_ERROR_NOT_BOUND:
7041 		case SCF_ERROR_HANDLE_MISMATCH:
7042 		default:
7043 			bad_error("scf_handle_get_scope", scf_error());
7044 		}
7045 	}
7046 
7047 	/* Set up the auditing annotation. */
7048 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7049 		annotation_set = 1;
7050 	} else {
7051 		switch (scf_error()) {
7052 		case SCF_ERROR_CONNECTION_BROKEN:
7053 			warn(gettext("Repository connection broken.\n"));
7054 			repository_teardown();
7055 			result = -1;
7056 			goto out;
7057 
7058 		case SCF_ERROR_INVALID_ARGUMENT:
7059 		case SCF_ERROR_NOT_BOUND:
7060 		case SCF_ERROR_NO_RESOURCES:
7061 		case SCF_ERROR_INTERNAL:
7062 			bad_error("_scf_set_annotation", scf_error());
7063 			/* NOTREACHED */
7064 
7065 		default:
7066 			/*
7067 			 * Do not terminate import because of inability to
7068 			 * generate annotation audit event.
7069 			 */
7070 			warn(gettext("_scf_set_annotation() unexpectedly "
7071 			    "failed with return code of %d\n"), scf_error());
7072 			break;
7073 		}
7074 	}
7075 
7076 	/*
7077 	 * Clear the sc_import_state's of all services & instances so we can
7078 	 * report how far we got if we fail.
7079 	 */
7080 	for (svc = uu_list_first(bndl->sc_bundle_services);
7081 	    svc != NULL;
7082 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7083 		svc->sc_import_state = 0;
7084 
7085 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
7086 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
7087 		    UU_DEFAULT) != 0)
7088 			bad_error("uu_list_walk", uu_error());
7089 	}
7090 
7091 	cbdata.sc_handle = g_hndl;
7092 	cbdata.sc_parent = imp_scope;
7093 	cbdata.sc_flags = flags;
7094 	cbdata.sc_general = NULL;
7095 
7096 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
7097 	    &cbdata, UU_DEFAULT) == 0) {
7098 		/* Success.  Refresh everything. */
7099 
7100 		if (flags & SCI_NOREFRESH || no_refresh) {
7101 			result = 0;
7102 			goto out;
7103 		}
7104 
7105 		for (svc = uu_list_first(bndl->sc_bundle_services);
7106 		    svc != NULL;
7107 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7108 			pgroup_t *dpt;
7109 
7110 			insts = svc->sc_u.sc_service.sc_service_instances;
7111 
7112 			for (inst = uu_list_first(insts);
7113 			    inst != NULL;
7114 			    inst = uu_list_next(insts, inst)) {
7115 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
7116 				switch (r) {
7117 				case 0:
7118 					break;
7119 
7120 				case ENOMEM:
7121 				case ECONNABORTED:
7122 				case EPERM:
7123 				case -1:
7124 					goto progress;
7125 
7126 				default:
7127 					bad_error("imp_refresh_fmri", r);
7128 				}
7129 
7130 				inst->sc_import_state = IMPORT_REFRESHED;
7131 
7132 				for (dpt = uu_list_first(inst->sc_dependents);
7133 				    dpt != NULL;
7134 				    dpt = uu_list_next(inst->sc_dependents,
7135 				    dpt))
7136 					if (imp_refresh_fmri(
7137 					    dpt->sc_pgroup_fmri,
7138 					    dpt->sc_pgroup_name,
7139 					    inst->sc_fmri) != 0)
7140 						goto progress;
7141 			}
7142 
7143 			for (dpt = uu_list_first(svc->sc_dependents);
7144 			    dpt != NULL;
7145 			    dpt = uu_list_next(svc->sc_dependents, dpt))
7146 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
7147 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
7148 					goto progress;
7149 		}
7150 
7151 		for (old_dpt = uu_list_first(imp_deleted_dpts);
7152 		    old_dpt != NULL;
7153 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
7154 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
7155 			    old_dpt->sc_pgroup_name,
7156 			    old_dpt->sc_parent->sc_fmri) != 0)
7157 				goto progress;
7158 
7159 		result = 0;
7160 		goto out;
7161 	}
7162 
7163 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7164 		bad_error("uu_list_walk", uu_error());
7165 
7166 printerr:
7167 	/* If the error hasn't been printed yet, do so here. */
7168 	switch (cbdata.sc_err) {
7169 	case ECONNABORTED:
7170 		warn(gettext("Repository connection broken.\n"));
7171 		break;
7172 
7173 	case ENOMEM:
7174 		warn(emsg_nomem);
7175 		break;
7176 
7177 	case ENOSPC:
7178 		warn(emsg_nores);
7179 		break;
7180 
7181 	case EROFS:
7182 		warn(gettext("Repository is read-only.\n"));
7183 		break;
7184 
7185 	case EACCES:
7186 		warn(gettext("Repository backend denied access.\n"));
7187 		break;
7188 
7189 	case EPERM:
7190 	case EINVAL:
7191 	case EEXIST:
7192 	case EBUSY:
7193 	case EBADF:
7194 	case -1:
7195 		break;
7196 
7197 	default:
7198 		bad_error("lscf_service_import", cbdata.sc_err);
7199 	}
7200 
7201 progress:
7202 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
7203 
7204 	for (svc = uu_list_first(bndl->sc_bundle_services);
7205 	    svc != NULL;
7206 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7207 		insts = svc->sc_u.sc_service.sc_service_instances;
7208 
7209 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
7210 		    import_progress(svc->sc_import_state));
7211 
7212 		for (inst = uu_list_first(insts);
7213 		    inst != NULL;
7214 		    inst = uu_list_next(insts, inst))
7215 			warn(gettext("    Instance \"%s\": %s\n"),
7216 			    inst->sc_name,
7217 			    import_progress(inst->sc_import_state));
7218 	}
7219 
7220 	if (cbdata.sc_err == ECONNABORTED)
7221 		repository_teardown();
7222 
7223 
7224 	result = -1;
7225 
7226 out:
7227 	if (annotation_set != 0) {
7228 		/* Turn off annotation.  It is no longer needed. */
7229 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7230 	}
7231 	load_fini();
7232 
7233 	free(ud_ctarg);
7234 	free(ud_oldtarg);
7235 	free(ud_name);
7236 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7237 
7238 	scf_transaction_destroy(ud_tx);
7239 	ud_tx = NULL;
7240 	scf_iter_destroy(ud_iter);
7241 	scf_iter_destroy(ud_iter2);
7242 	ud_iter = ud_iter2 = NULL;
7243 	scf_value_destroy(ud_val);
7244 	ud_val = NULL;
7245 	scf_property_destroy(ud_prop);
7246 	scf_property_destroy(ud_dpt_prop);
7247 	ud_prop = ud_dpt_prop = NULL;
7248 	scf_pg_destroy(ud_pg);
7249 	scf_pg_destroy(ud_cur_depts_pg);
7250 	scf_pg_destroy(ud_run_dpts_pg);
7251 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7252 	scf_snaplevel_destroy(ud_snpl);
7253 	ud_snpl = NULL;
7254 	scf_instance_destroy(ud_inst);
7255 	ud_inst = NULL;
7256 
7257 	free(imp_str);
7258 	free(imp_tsname);
7259 	free(imp_fe1);
7260 	free(imp_fe2);
7261 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7262 
7263 	cookie = NULL;
7264 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7265 	    NULL) {
7266 		free((char *)old_dpt->sc_pgroup_name);
7267 		free((char *)old_dpt->sc_pgroup_fmri);
7268 		internal_pgroup_free(old_dpt);
7269 	}
7270 	uu_list_destroy(imp_deleted_dpts);
7271 
7272 	scf_transaction_destroy(imp_tx);
7273 	imp_tx = NULL;
7274 	scf_iter_destroy(imp_iter);
7275 	scf_iter_destroy(imp_rpg_iter);
7276 	scf_iter_destroy(imp_up_iter);
7277 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7278 	scf_property_destroy(imp_prop);
7279 	imp_prop = NULL;
7280 	scf_pg_destroy(imp_pg);
7281 	scf_pg_destroy(imp_pg2);
7282 	imp_pg = imp_pg2 = NULL;
7283 	scf_snaplevel_destroy(imp_snpl);
7284 	scf_snaplevel_destroy(imp_rsnpl);
7285 	imp_snpl = imp_rsnpl = NULL;
7286 	scf_snapshot_destroy(imp_snap);
7287 	scf_snapshot_destroy(imp_lisnap);
7288 	scf_snapshot_destroy(imp_tlisnap);
7289 	scf_snapshot_destroy(imp_rsnap);
7290 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7291 	scf_instance_destroy(imp_inst);
7292 	scf_instance_destroy(imp_tinst);
7293 	imp_inst = imp_tinst = NULL;
7294 	scf_service_destroy(imp_svc);
7295 	scf_service_destroy(imp_tsvc);
7296 	imp_svc = imp_tsvc = NULL;
7297 	scf_scope_destroy(imp_scope);
7298 	imp_scope = NULL;
7299 
7300 	return (result);
7301 }
7302 
7303 
7304 /*
7305  * Returns
7306  *   0 - success
7307  *   -1 - lscf_import_instance_pgs() failed.
7308  */
7309 int
7310 lscf_bundle_apply(bundle_t *bndl, const char *file)
7311 {
7312 	entity_t *svc, *inst;
7313 	scf_scope_t *rscope;
7314 	scf_service_t *rsvc;
7315 	scf_instance_t *rinst;
7316 	int annotation_set = 0;
7317 	int r;
7318 
7319 	lscf_prep_hndl();
7320 
7321 	if ((rscope = scf_scope_create(g_hndl)) == NULL ||
7322 	    (rsvc = scf_service_create(g_hndl)) == NULL ||
7323 	    (rinst = scf_instance_create(g_hndl)) == NULL ||
7324 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7325 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL)
7326 		scfdie();
7327 
7328 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0)
7329 		scfdie();
7330 
7331 	/*
7332 	 * Set the strings to be used for the security audit annotation
7333 	 * event.
7334 	 */
7335 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
7336 		annotation_set = 1;
7337 	} else {
7338 		switch (scf_error()) {
7339 		case SCF_ERROR_CONNECTION_BROKEN:
7340 			warn(gettext("Repository connection broken.\n"));
7341 			goto out;
7342 
7343 		case SCF_ERROR_INVALID_ARGUMENT:
7344 		case SCF_ERROR_NOT_BOUND:
7345 		case SCF_ERROR_NO_RESOURCES:
7346 		case SCF_ERROR_INTERNAL:
7347 			bad_error("_scf_set_annotation", scf_error());
7348 			/* NOTREACHED */
7349 
7350 		default:
7351 			/*
7352 			 * Do not abort apply operation because of
7353 			 * inability to create annotation audit event.
7354 			 */
7355 			warn(gettext("_scf_set_annotation() unexpectedly "
7356 			    "failed with return code of %d\n"), scf_error());
7357 			break;
7358 		}
7359 	}
7360 
7361 	for (svc = uu_list_first(bndl->sc_bundle_services);
7362 	    svc != NULL;
7363 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7364 		if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) {
7365 			switch (scf_error()) {
7366 			case SCF_ERROR_NOT_FOUND:
7367 				if (g_verbose)
7368 					warn(gettext("Ignoring nonexistent "
7369 					    "service %s.\n"), svc->sc_name);
7370 				continue;
7371 
7372 			default:
7373 				scfdie();
7374 			}
7375 		}
7376 
7377 		for (inst = uu_list_first(
7378 		    svc->sc_u.sc_service.sc_service_instances);
7379 		    inst != NULL;
7380 		    inst = uu_list_next(
7381 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
7382 			if (scf_service_get_instance(rsvc, inst->sc_name,
7383 			    rinst) != 0) {
7384 				switch (scf_error()) {
7385 				case SCF_ERROR_NOT_FOUND:
7386 					if (g_verbose)
7387 						warn(gettext("Ignoring "
7388 						    "nonexistant instance "
7389 						    "%s:%s.\n"),
7390 						    inst->sc_parent->sc_name,
7391 						    inst->sc_name);
7392 					continue;
7393 
7394 				default:
7395 					scfdie();
7396 				}
7397 			}
7398 
7399 			r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst,
7400 			    SCI_FORCE | SCI_KEEP);
7401 			switch (r) {
7402 			case 0:
7403 				if (g_verbose)
7404 					warn(gettext("%s updated.\n"),
7405 					    inst->sc_fmri);
7406 				break;
7407 
7408 			case ECONNABORTED:
7409 				warn(gettext("Could not update %s "
7410 				    "(repository connection broken).\n"),
7411 				    inst->sc_fmri);
7412 				goto out;
7413 
7414 			case ENOMEM:
7415 				warn(gettext("Could not update %s "
7416 				    "(out of memory).\n"), inst->sc_fmri);
7417 				goto out;
7418 
7419 			case ENOSPC:
7420 				warn(gettext("Could not update %s "
7421 				    "(repository server out of resources).\n"),
7422 				    inst->sc_fmri);
7423 				goto out;
7424 
7425 			case ECANCELED:
7426 				warn(gettext(
7427 				    "Could not update %s (deleted).\n"),
7428 				    inst->sc_fmri);
7429 				break;
7430 
7431 			case EPERM:
7432 			case EINVAL:
7433 			case EBUSY:
7434 				break;
7435 
7436 			case EROFS:
7437 				warn(gettext("Could not update %s "
7438 				    "(repository read-only).\n"),
7439 				    inst->sc_fmri);
7440 				goto out;
7441 
7442 			case EACCES:
7443 				warn(gettext("Could not update %s "
7444 				    "(backend access denied).\n"),
7445 				    inst->sc_fmri);
7446 				break;
7447 
7448 			case EEXIST:
7449 			default:
7450 				bad_error("lscf_import_instance_pgs", r);
7451 			}
7452 		}
7453 	}
7454 
7455 out:
7456 	if (annotation_set) {
7457 		/* Remove security audit annotation strings. */
7458 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7459 	}
7460 
7461 	scf_transaction_destroy(imp_tx);
7462 	imp_tx = NULL;
7463 	scf_pg_destroy(imp_pg);
7464 	imp_pg = NULL;
7465 
7466 	scf_instance_destroy(rinst);
7467 	scf_service_destroy(rsvc);
7468 	scf_scope_destroy(rscope);
7469 	return (0);
7470 }
7471 
7472 
7473 /*
7474  * Export.  These functions create and output an XML tree of a service
7475  * description from the repository.  This is largely the inverse of
7476  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
7477  *
7478  * - We must include any properties which are not represented specifically by
7479  *   a service manifest, e.g., properties created by an admin post-import.  To
7480  *   do so we'll iterate through all properties and deal with each
7481  *   apropriately.
7482  *
7483  * - Children of services and instances must must be in the order set by the
7484  *   DTD, but we iterate over the properties in undefined order.  The elements
7485  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
7486  *   number of classes of them, however, we'll keep the classes separate and
7487  *   assemble them in order.
7488  */
7489 
7490 /*
7491  * Convenience function to handle xmlSetProp errors (and type casting).
7492  */
7493 static void
7494 safe_setprop(xmlNodePtr n, const char *name, const char *val)
7495 {
7496 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
7497 		uu_die(gettext("Could not set XML property.\n"));
7498 }
7499 
7500 /*
7501  * Convenience function to set an XML attribute to the single value of an
7502  * astring property.  If the value happens to be the default, don't set the
7503  * attribute.  "dval" should be the default value supplied by the DTD, or
7504  * NULL for no default.
7505  */
7506 static int
7507 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
7508     const char *name, const char *dval)
7509 {
7510 	scf_value_t *val;
7511 	ssize_t len;
7512 	char *str;
7513 
7514 	val = scf_value_create(g_hndl);
7515 	if (val == NULL)
7516 		scfdie();
7517 
7518 	if (prop_get_val(prop, val) != 0) {
7519 		scf_value_destroy(val);
7520 		return (-1);
7521 	}
7522 
7523 	len = scf_value_get_as_string(val, NULL, 0);
7524 	if (len < 0)
7525 		scfdie();
7526 
7527 	str = safe_malloc(len + 1);
7528 
7529 	if (scf_value_get_as_string(val, str, len + 1) < 0)
7530 		scfdie();
7531 
7532 	scf_value_destroy(val);
7533 
7534 	if (dval == NULL || strcmp(str, dval) != 0)
7535 		safe_setprop(n, name, str);
7536 
7537 	free(str);
7538 
7539 	return (0);
7540 }
7541 
7542 /*
7543  * As above, but the attribute is always set.
7544  */
7545 static int
7546 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
7547 {
7548 	return (set_attr_from_prop_default(prop, n, name, NULL));
7549 }
7550 
7551 /*
7552  * Dump the given document onto f, with "'s replaced by ''s.
7553  */
7554 static int
7555 write_service_bundle(xmlDocPtr doc, FILE *f)
7556 {
7557 	xmlChar *mem;
7558 	int sz, i;
7559 
7560 	mem = NULL;
7561 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
7562 
7563 	if (mem == NULL) {
7564 		semerr(gettext("Could not dump XML tree.\n"));
7565 		return (-1);
7566 	}
7567 
7568 	/*
7569 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
7570 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
7571 	 * &apos; code?!
7572 	 */
7573 	for (i = 0; i < sz; ++i) {
7574 		char c = (char)mem[i];
7575 
7576 		if (c == '"')
7577 			(void) fputc('\'', f);
7578 		else if (c == '\'')
7579 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
7580 		else
7581 			(void) fputc(c, f);
7582 	}
7583 
7584 	return (0);
7585 }
7586 
7587 /*
7588  * Create the DOM elements in elts necessary to (generically) represent prop
7589  * (i.e., a property or propval element).  If the name of the property is
7590  * known, it should be passed as name_arg.  Otherwise, pass NULL.
7591  */
7592 static void
7593 export_property(scf_property_t *prop, const char *name_arg,
7594     struct pg_elts *elts, int flags)
7595 {
7596 	const char *type;
7597 	scf_error_t err = 0;
7598 	xmlNodePtr pnode, lnode;
7599 	char *lnname;
7600 	int ret;
7601 
7602 	/* name */
7603 	if (name_arg != NULL) {
7604 		(void) strcpy(exp_str, name_arg);
7605 	} else {
7606 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
7607 			scfdie();
7608 	}
7609 
7610 	/* type */
7611 	type = prop_to_typestr(prop);
7612 	if (type == NULL)
7613 		uu_die(gettext("Can't export property %s: unknown type.\n"),
7614 		    exp_str);
7615 
7616 	/* If we're exporting values, and there's just one, export it here. */
7617 	if (!(flags & SCE_ALL_VALUES))
7618 		goto empty;
7619 
7620 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
7621 		xmlNodePtr n;
7622 
7623 		/* Single value, so use propval */
7624 		n = xmlNewNode(NULL, (xmlChar *)"propval");
7625 		if (n == NULL)
7626 			uu_die(emsg_create_xml);
7627 
7628 		safe_setprop(n, name_attr, exp_str);
7629 		safe_setprop(n, type_attr, type);
7630 
7631 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
7632 			scfdie();
7633 		safe_setprop(n, value_attr, exp_str);
7634 
7635 		if (elts->propvals == NULL)
7636 			elts->propvals = n;
7637 		else
7638 			(void) xmlAddSibling(elts->propvals, n);
7639 
7640 		return;
7641 	}
7642 
7643 	err = scf_error();
7644 
7645 	if (err == SCF_ERROR_PERMISSION_DENIED) {
7646 		semerr(emsg_permission_denied);
7647 		return;
7648 	}
7649 
7650 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
7651 	    err != SCF_ERROR_NOT_FOUND &&
7652 	    err != SCF_ERROR_PERMISSION_DENIED)
7653 		scfdie();
7654 
7655 empty:
7656 	/* Multiple (or no) values, so use property */
7657 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
7658 	if (pnode == NULL)
7659 		uu_die(emsg_create_xml);
7660 
7661 	safe_setprop(pnode, name_attr, exp_str);
7662 	safe_setprop(pnode, type_attr, type);
7663 
7664 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
7665 		lnname = uu_msprintf("%s_list", type);
7666 		if (lnname == NULL)
7667 			uu_die(gettext("Could not create string"));
7668 
7669 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
7670 		if (lnode == NULL)
7671 			uu_die(emsg_create_xml);
7672 
7673 		uu_free(lnname);
7674 
7675 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
7676 			scfdie();
7677 
7678 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
7679 		    1) {
7680 			xmlNodePtr vn;
7681 
7682 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
7683 			    NULL);
7684 			if (vn == NULL)
7685 				uu_die(emsg_create_xml);
7686 
7687 			if (scf_value_get_as_string(exp_val, exp_str,
7688 			    exp_str_sz) < 0)
7689 				scfdie();
7690 			safe_setprop(vn, value_attr, exp_str);
7691 		}
7692 		if (ret != 0)
7693 			scfdie();
7694 	}
7695 
7696 	if (elts->properties == NULL)
7697 		elts->properties = pnode;
7698 	else
7699 		(void) xmlAddSibling(elts->properties, pnode);
7700 }
7701 
7702 /*
7703  * Add a property_group element for this property group to elts.
7704  */
7705 static void
7706 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
7707 {
7708 	xmlNodePtr n;
7709 	struct pg_elts elts;
7710 	int ret;
7711 	boolean_t read_protected;
7712 
7713 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
7714 
7715 	/* name */
7716 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
7717 		scfdie();
7718 	safe_setprop(n, name_attr, exp_str);
7719 
7720 	/* type */
7721 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
7722 		scfdie();
7723 	safe_setprop(n, type_attr, exp_str);
7724 
7725 	/* properties */
7726 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
7727 		scfdie();
7728 
7729 	(void) memset(&elts, 0, sizeof (elts));
7730 
7731 	/*
7732 	 * If this property group is not read protected, we always want to
7733 	 * output all the values.  Otherwise, we only output the values if the
7734 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
7735 	 */
7736 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
7737 		scfdie();
7738 
7739 	if (!read_protected)
7740 		flags |= SCE_ALL_VALUES;
7741 
7742 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
7743 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
7744 			scfdie();
7745 
7746 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
7747 			xmlNodePtr m;
7748 
7749 			m = xmlNewNode(NULL, (xmlChar *)"stability");
7750 			if (m == NULL)
7751 				uu_die(emsg_create_xml);
7752 
7753 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
7754 				elts.stability = m;
7755 				continue;
7756 			}
7757 
7758 			xmlFreeNode(m);
7759 		}
7760 
7761 		export_property(exp_prop, NULL, &elts, flags);
7762 	}
7763 	if (ret == -1)
7764 		scfdie();
7765 
7766 	(void) xmlAddChild(n, elts.stability);
7767 	(void) xmlAddChildList(n, elts.propvals);
7768 	(void) xmlAddChildList(n, elts.properties);
7769 
7770 	if (eelts->property_groups == NULL)
7771 		eelts->property_groups = n;
7772 	else
7773 		(void) xmlAddSibling(eelts->property_groups, n);
7774 }
7775 
7776 /*
7777  * Create an XML node representing the dependency described by the given
7778  * property group and put it in eelts.  Unless the dependency is not valid, in
7779  * which case create a generic property_group element which represents it and
7780  * put it in eelts.
7781  */
7782 static void
7783 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
7784 {
7785 	xmlNodePtr n;
7786 	int err = 0, ret;
7787 	struct pg_elts elts;
7788 
7789 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
7790 	if (n == NULL)
7791 		uu_die(emsg_create_xml);
7792 
7793 	/*
7794 	 * If the external flag is present, skip this dependency because it
7795 	 * should have been created by another manifest.
7796 	 */
7797 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
7798 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
7799 		    prop_get_val(exp_prop, exp_val) == 0) {
7800 			uint8_t b;
7801 
7802 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
7803 				scfdie();
7804 
7805 			if (b)
7806 				return;
7807 		}
7808 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
7809 		scfdie();
7810 
7811 	/* Get the required attributes. */
7812 
7813 	/* name */
7814 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
7815 		scfdie();
7816 	safe_setprop(n, name_attr, exp_str);
7817 
7818 	/* grouping */
7819 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
7820 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
7821 		err = 1;
7822 
7823 	/* restart_on */
7824 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
7825 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
7826 		err = 1;
7827 
7828 	/* type */
7829 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
7830 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
7831 		err = 1;
7832 
7833 	/*
7834 	 * entities: Not required, but if we create no children, it will be
7835 	 * created as empty on import, so fail if it's missing.
7836 	 */
7837 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
7838 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
7839 		scf_iter_t *eiter;
7840 		int ret2;
7841 
7842 		eiter = scf_iter_create(g_hndl);
7843 		if (eiter == NULL)
7844 			scfdie();
7845 
7846 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
7847 			scfdie();
7848 
7849 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
7850 			xmlNodePtr ch;
7851 
7852 			if (scf_value_get_astring(exp_val, exp_str,
7853 			    exp_str_sz) < 0)
7854 				scfdie();
7855 
7856 			/*
7857 			 * service_fmri's must be first, so we can add them
7858 			 * here.
7859 			 */
7860 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
7861 			    NULL);
7862 			if (ch == NULL)
7863 				uu_die(emsg_create_xml);
7864 
7865 			safe_setprop(ch, value_attr, exp_str);
7866 		}
7867 		if (ret2 == -1)
7868 			scfdie();
7869 
7870 		scf_iter_destroy(eiter);
7871 	} else
7872 		err = 1;
7873 
7874 	if (err) {
7875 		xmlFreeNode(n);
7876 
7877 		export_pg(pg, eelts, 0);
7878 
7879 		return;
7880 	}
7881 
7882 	/* Iterate through the properties & handle each. */
7883 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
7884 		scfdie();
7885 
7886 	(void) memset(&elts, 0, sizeof (elts));
7887 
7888 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
7889 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
7890 			scfdie();
7891 
7892 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
7893 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
7894 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
7895 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
7896 			continue;
7897 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
7898 			xmlNodePtr m;
7899 
7900 			m = xmlNewNode(NULL, (xmlChar *)"stability");
7901 			if (m == NULL)
7902 				uu_die(emsg_create_xml);
7903 
7904 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
7905 				elts.stability = m;
7906 				continue;
7907 			}
7908 
7909 			xmlFreeNode(m);
7910 		}
7911 
7912 		export_property(exp_prop, exp_str, &elts, 0);
7913 	}
7914 	if (ret == -1)
7915 		scfdie();
7916 
7917 	(void) xmlAddChild(n, elts.stability);
7918 	(void) xmlAddChildList(n, elts.propvals);
7919 	(void) xmlAddChildList(n, elts.properties);
7920 
7921 	if (eelts->dependencies == NULL)
7922 		eelts->dependencies = n;
7923 	else
7924 		(void) xmlAddSibling(eelts->dependencies, n);
7925 }
7926 
7927 static xmlNodePtr
7928 export_method_environment(scf_propertygroup_t *pg)
7929 {
7930 	xmlNodePtr env;
7931 	int ret;
7932 	int children = 0;
7933 
7934 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
7935 		return (NULL);
7936 
7937 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
7938 	if (env == NULL)
7939 		uu_die(emsg_create_xml);
7940 
7941 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
7942 		scfdie();
7943 
7944 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
7945 		scfdie();
7946 
7947 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
7948 		xmlNodePtr ev;
7949 		char *cp;
7950 
7951 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
7952 			scfdie();
7953 
7954 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
7955 			warn(gettext("Invalid environment variable \"%s\".\n"),
7956 			    exp_str);
7957 			continue;
7958 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
7959 			warn(gettext("Invalid environment variable \"%s\"; "
7960 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
7961 			continue;
7962 		}
7963 
7964 		*cp = '\0';
7965 		cp++;
7966 
7967 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
7968 		if (ev == NULL)
7969 			uu_die(emsg_create_xml);
7970 
7971 		safe_setprop(ev, name_attr, exp_str);
7972 		safe_setprop(ev, value_attr, cp);
7973 		children++;
7974 	}
7975 
7976 	if (ret != 0)
7977 		scfdie();
7978 
7979 	if (children == 0) {
7980 		xmlFreeNode(env);
7981 		return (NULL);
7982 	}
7983 
7984 	return (env);
7985 }
7986 
7987 /*
7988  * As above, but for a method property group.
7989  */
7990 static void
7991 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
7992 {
7993 	xmlNodePtr n, env;
7994 	char *str;
7995 	int err = 0, nonenv, ret;
7996 	uint8_t use_profile;
7997 	struct pg_elts elts;
7998 	xmlNodePtr ctxt;
7999 
8000 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
8001 
8002 	/* Get the required attributes. */
8003 
8004 	/* name */
8005 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8006 		scfdie();
8007 	safe_setprop(n, name_attr, exp_str);
8008 
8009 	/* type */
8010 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8011 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8012 		err = 1;
8013 
8014 	/* exec */
8015 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
8016 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
8017 		err = 1;
8018 
8019 	/* timeout */
8020 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
8021 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
8022 	    prop_get_val(exp_prop, exp_val) == 0) {
8023 		uint64_t c;
8024 
8025 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
8026 			scfdie();
8027 
8028 		str = uu_msprintf("%llu", c);
8029 		if (str == NULL)
8030 			uu_die(gettext("Could not create string"));
8031 
8032 		safe_setprop(n, "timeout_seconds", str);
8033 		free(str);
8034 	} else
8035 		err = 1;
8036 
8037 	if (err) {
8038 		xmlFreeNode(n);
8039 
8040 		export_pg(pg, eelts, 0);
8041 
8042 		return;
8043 	}
8044 
8045 	ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8046 	if (ctxt == NULL)
8047 		uu_die(emsg_create_xml);
8048 
8049 	/*
8050 	 * If we're going to have a method_context child, we need to know
8051 	 * before we iterate through the properties.  Since method_context's
8052 	 * are optional, we don't want to complain about any properties
8053 	 * missing if none of them are there.  Thus we can't use the
8054 	 * convenience functions.
8055 	 */
8056 	nonenv =
8057 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
8058 	    SCF_SUCCESS ||
8059 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
8060 	    SCF_SUCCESS ||
8061 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
8062 	    SCF_SUCCESS ||
8063 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
8064 	    SCF_SUCCESS;
8065 
8066 	if (nonenv) {
8067 		/*
8068 		 * We only want to complain about profile or credential
8069 		 * properties if we will use them.  To determine that we must
8070 		 * examine USE_PROFILE.
8071 		 */
8072 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8073 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8074 		    prop_get_val(exp_prop, exp_val) == 0) {
8075 			if (scf_value_get_boolean(exp_val, &use_profile) !=
8076 			    SCF_SUCCESS)
8077 				scfdie();
8078 		} else
8079 			/*
8080 			 * USE_PROFILE is misconfigured.  Since we should have
8081 			 * complained just now, we don't want to complain
8082 			 * about any of the other properties, so don't look
8083 			 * for them.
8084 			 */
8085 			nonenv = 0;
8086 	}
8087 
8088 	if (nonenv) {
8089 
8090 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) !=
8091 		    0 ||
8092 		    set_attr_from_prop_default(exp_prop, ctxt,
8093 		    "working_directory", ":default") != 0)
8094 			err = 1;
8095 
8096 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) != 0 ||
8097 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
8098 		    ":default") != 0)
8099 			err = 1;
8100 
8101 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) !=
8102 		    0 ||
8103 		    set_attr_from_prop_default(exp_prop, ctxt,
8104 		    "resource_pool", ":default") != 0)
8105 			err = 1;
8106 
8107 		if (use_profile) {
8108 			xmlNodePtr prof;
8109 
8110 			prof = xmlNewChild(ctxt, NULL,
8111 			    (xmlChar *)"method_profile", NULL);
8112 			if (prof == NULL)
8113 				uu_die(emsg_create_xml);
8114 
8115 			if (pg_get_prop(pg, SCF_PROPERTY_PROFILE, exp_prop) !=
8116 			    0 || set_attr_from_prop(exp_prop, prof,
8117 			    name_attr) != 0)
8118 				err = 1;
8119 		} else {
8120 			xmlNodePtr cred;
8121 
8122 			cred = xmlNewChild(ctxt, NULL,
8123 			    (xmlChar *)"method_credential", NULL);
8124 			if (cred == NULL)
8125 				uu_die(emsg_create_xml);
8126 
8127 			if (pg_get_prop(pg, SCF_PROPERTY_USER, exp_prop) != 0 ||
8128 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
8129 				err = 1;
8130 
8131 			if (pg_get_prop(pg, SCF_PROPERTY_GROUP, exp_prop) !=
8132 			    0 ||
8133 			    set_attr_from_prop_default(exp_prop, cred,
8134 			    "group", ":default") != 0)
8135 				err = 1;
8136 
8137 			if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
8138 			    exp_prop) != 0 ||
8139 			    set_attr_from_prop_default(exp_prop, cred,
8140 			    "supp_groups", ":default") != 0)
8141 				err = 1;
8142 
8143 			if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
8144 			    exp_prop) != 0 ||
8145 			    set_attr_from_prop_default(exp_prop, cred,
8146 			    "privileges", ":default") != 0)
8147 				err = 1;
8148 
8149 			if (pg_get_prop(pg, SCF_PROPERTY_LIMIT_PRIVILEGES,
8150 			    exp_prop) != 0 ||
8151 			    set_attr_from_prop_default(exp_prop, cred,
8152 			    "limit_privileges", ":default") != 0)
8153 				err = 1;
8154 		}
8155 	}
8156 
8157 	if ((env = export_method_environment(pg)) != NULL)
8158 		(void) xmlAddChild(ctxt, env);
8159 
8160 	if (env != NULL || err == 0)
8161 		(void) xmlAddChild(n, ctxt);
8162 	else
8163 		xmlFreeNode(ctxt);
8164 
8165 	nonenv = (err == 0);
8166 
8167 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8168 		scfdie();
8169 
8170 	(void) memset(&elts, 0, sizeof (elts));
8171 
8172 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8173 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8174 			scfdie();
8175 
8176 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8177 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
8178 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
8179 			continue;
8180 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8181 			xmlNodePtr m;
8182 
8183 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8184 			if (m == NULL)
8185 				uu_die(emsg_create_xml);
8186 
8187 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8188 				elts.stability = m;
8189 				continue;
8190 			}
8191 
8192 			xmlFreeNode(m);
8193 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
8194 		    0 ||
8195 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
8196 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
8197 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8198 			if (nonenv)
8199 				continue;
8200 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
8201 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
8202 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
8203 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
8204 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
8205 			if (nonenv && !use_profile)
8206 				continue;
8207 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8208 			if (nonenv && use_profile)
8209 				continue;
8210 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
8211 			if (env != NULL)
8212 				continue;
8213 		}
8214 
8215 		export_property(exp_prop, exp_str, &elts, 0);
8216 	}
8217 	if (ret == -1)
8218 		scfdie();
8219 
8220 	(void) xmlAddChild(n, elts.stability);
8221 	(void) xmlAddChildList(n, elts.propvals);
8222 	(void) xmlAddChildList(n, elts.properties);
8223 
8224 	if (eelts->exec_methods == NULL)
8225 		eelts->exec_methods = n;
8226 	else
8227 		(void) xmlAddSibling(eelts->exec_methods, n);
8228 }
8229 
8230 static void
8231 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
8232     struct entity_elts *eelts)
8233 {
8234 	xmlNodePtr pgnode;
8235 
8236 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
8237 	if (pgnode == NULL)
8238 		uu_die(emsg_create_xml);
8239 
8240 	safe_setprop(pgnode, name_attr, name);
8241 	safe_setprop(pgnode, type_attr, type);
8242 
8243 	(void) xmlAddChildList(pgnode, elts->propvals);
8244 	(void) xmlAddChildList(pgnode, elts->properties);
8245 
8246 	if (eelts->property_groups == NULL)
8247 		eelts->property_groups = pgnode;
8248 	else
8249 		(void) xmlAddSibling(eelts->property_groups, pgnode);
8250 }
8251 
8252 /*
8253  * Process the general property group for a service.  This is the one with the
8254  * goodies.
8255  */
8256 static void
8257 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
8258 {
8259 	struct pg_elts elts;
8260 	int ret;
8261 
8262 	/*
8263 	 * In case there are properties which don't correspond to child
8264 	 * entities of the service entity, we'll set up a pg_elts structure to
8265 	 * put them in.
8266 	 */
8267 	(void) memset(&elts, 0, sizeof (elts));
8268 
8269 	/* Walk the properties, looking for special ones. */
8270 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8271 		scfdie();
8272 
8273 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8274 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8275 			scfdie();
8276 
8277 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
8278 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8279 			    prop_get_val(exp_prop, exp_val) == 0) {
8280 				uint8_t b;
8281 
8282 				if (scf_value_get_boolean(exp_val, &b) !=
8283 				    SCF_SUCCESS)
8284 					scfdie();
8285 
8286 				if (b) {
8287 					selts->single_instance =
8288 					    xmlNewNode(NULL,
8289 					    (xmlChar *)"single_instance");
8290 					if (selts->single_instance == NULL)
8291 						uu_die(emsg_create_xml);
8292 				}
8293 
8294 				continue;
8295 			}
8296 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8297 			xmlNodePtr rnode, sfnode;
8298 
8299 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8300 			if (rnode == NULL)
8301 				uu_die(emsg_create_xml);
8302 
8303 			sfnode = xmlNewChild(rnode, NULL,
8304 			    (xmlChar *)"service_fmri", NULL);
8305 			if (sfnode == NULL)
8306 				uu_die(emsg_create_xml);
8307 
8308 			if (set_attr_from_prop(exp_prop, sfnode,
8309 			    value_attr) == 0) {
8310 				selts->restarter = rnode;
8311 				continue;
8312 			}
8313 
8314 			xmlFreeNode(rnode);
8315 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
8316 		    0) {
8317 			xmlNodePtr s;
8318 
8319 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8320 			if (s == NULL)
8321 				uu_die(emsg_create_xml);
8322 
8323 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8324 				selts->stability = s;
8325 				continue;
8326 			}
8327 
8328 			xmlFreeNode(s);
8329 		}
8330 
8331 		export_property(exp_prop, exp_str, &elts, 0);
8332 	}
8333 	if (ret == -1)
8334 		scfdie();
8335 
8336 	if (elts.propvals != NULL || elts.properties != NULL)
8337 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
8338 		    selts);
8339 }
8340 
8341 static void
8342 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
8343 {
8344 	xmlNodePtr n, prof, cred, env;
8345 	uint8_t use_profile;
8346 	int ret, err = 0;
8347 
8348 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
8349 
8350 	env = export_method_environment(pg);
8351 
8352 	/* Need to know whether we'll use a profile or not. */
8353 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) != 0 ||
8354 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) != 0 ||
8355 	    prop_get_val(exp_prop, exp_val) != 0) {
8356 		if (env != NULL) {
8357 			(void) xmlAddChild(n, env);
8358 			elts->method_context = n;
8359 		} else {
8360 			xmlFreeNode(n);
8361 			export_pg(pg, elts, 0);
8362 		}
8363 		return;
8364 	}
8365 
8366 	if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
8367 		scfdie();
8368 
8369 	if (use_profile)
8370 		prof = xmlNewChild(n, NULL, (xmlChar *)"method_profile", NULL);
8371 	else
8372 		cred =
8373 		    xmlNewChild(n, NULL, (xmlChar *)"method_credential", NULL);
8374 
8375 	if (env != NULL)
8376 		(void) xmlAddChild(n, env);
8377 
8378 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8379 		scfdie();
8380 
8381 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8382 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8383 			scfdie();
8384 
8385 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
8386 			if (set_attr_from_prop(exp_prop, n,
8387 			    "working_directory") != 0)
8388 				err = 1;
8389 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
8390 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
8391 				err = 1;
8392 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
8393 			if (set_attr_from_prop(exp_prop, n,
8394 			    "resource_pool") != 0)
8395 				err = 1;
8396 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8397 			/* EMPTY */
8398 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
8399 			if (use_profile ||
8400 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
8401 				err = 1;
8402 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
8403 			if (use_profile ||
8404 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
8405 				err = 1;
8406 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
8407 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8408 			    "supp_groups") != 0)
8409 				err = 1;
8410 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
8411 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8412 			    "privileges") != 0)
8413 				err = 1;
8414 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
8415 		    0) {
8416 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8417 			    "limit_privileges") != 0)
8418 				err = 1;
8419 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8420 			if (!use_profile || set_attr_from_prop(exp_prop,
8421 			    prof, name_attr) != 0)
8422 				err = 1;
8423 		} else {
8424 			/* Can't have generic properties in method_context's */
8425 			err = 1;
8426 		}
8427 	}
8428 	if (ret == -1)
8429 		scfdie();
8430 
8431 	if (err && env == NULL) {
8432 		xmlFreeNode(n);
8433 		export_pg(pg, elts, 0);
8434 		return;
8435 	}
8436 
8437 	elts->method_context = n;
8438 }
8439 
8440 /*
8441  * Given a dependency property group in the tfmri entity (target fmri), return
8442  * a dependent element which represents it.
8443  */
8444 static xmlNodePtr
8445 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
8446 {
8447 	uint8_t b;
8448 	xmlNodePtr n, sf;
8449 	int err = 0, ret;
8450 	struct pg_elts pgelts;
8451 
8452 	/*
8453 	 * If external isn't set to true then exporting the service will
8454 	 * export this as a normal dependency, so we should stop to avoid
8455 	 * duplication.
8456 	 */
8457 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
8458 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
8459 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
8460 		if (g_verbose) {
8461 			warn(gettext("Dependent \"%s\" cannot be exported "
8462 			    "properly because the \"%s\" property of the "
8463 			    "\"%s\" dependency of %s is not set to true.\n"),
8464 			    name, scf_property_external, name, tfmri);
8465 		}
8466 
8467 		return (NULL);
8468 	}
8469 
8470 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
8471 	if (n == NULL)
8472 		uu_die(emsg_create_xml);
8473 
8474 	safe_setprop(n, name_attr, name);
8475 
8476 	/* Get the required attributes */
8477 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8478 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8479 		err = 1;
8480 
8481 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8482 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8483 		err = 1;
8484 
8485 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8486 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
8487 	    prop_get_val(exp_prop, exp_val) == 0) {
8488 		/* EMPTY */
8489 	} else
8490 		err = 1;
8491 
8492 	if (err) {
8493 		xmlFreeNode(n);
8494 		return (NULL);
8495 	}
8496 
8497 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
8498 	if (sf == NULL)
8499 		uu_die(emsg_create_xml);
8500 
8501 	safe_setprop(sf, value_attr, tfmri);
8502 
8503 	/*
8504 	 * Now add elements for the other properties.
8505 	 */
8506 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8507 		scfdie();
8508 
8509 	(void) memset(&pgelts, 0, sizeof (pgelts));
8510 
8511 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8512 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8513 			scfdie();
8514 
8515 		if (strcmp(exp_str, scf_property_external) == 0 ||
8516 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8517 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8518 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8519 			continue;
8520 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
8521 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
8522 			    prop_get_val(exp_prop, exp_val) == 0) {
8523 				char type[sizeof ("service") + 1];
8524 
8525 				if (scf_value_get_astring(exp_val, type,
8526 				    sizeof (type)) < 0)
8527 					scfdie();
8528 
8529 				if (strcmp(type, "service") == 0)
8530 					continue;
8531 			}
8532 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8533 			xmlNodePtr s;
8534 
8535 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8536 			if (s == NULL)
8537 				uu_die(emsg_create_xml);
8538 
8539 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8540 				pgelts.stability = s;
8541 				continue;
8542 			}
8543 
8544 			xmlFreeNode(s);
8545 		}
8546 
8547 		export_property(exp_prop, exp_str, &pgelts, 0);
8548 	}
8549 	if (ret == -1)
8550 		scfdie();
8551 
8552 	(void) xmlAddChild(n, pgelts.stability);
8553 	(void) xmlAddChildList(n, pgelts.propvals);
8554 	(void) xmlAddChildList(n, pgelts.properties);
8555 
8556 	return (n);
8557 }
8558 
8559 static void
8560 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
8561 {
8562 	scf_propertygroup_t *opg;
8563 	scf_iter_t *iter;
8564 	char *type, *fmri;
8565 	int ret;
8566 	struct pg_elts pgelts;
8567 	xmlNodePtr n;
8568 	scf_error_t serr;
8569 
8570 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
8571 	    (iter = scf_iter_create(g_hndl)) == NULL)
8572 		scfdie();
8573 
8574 	/* Can't use exp_prop_iter due to export_dependent(). */
8575 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
8576 		scfdie();
8577 
8578 	type = safe_malloc(max_scf_pg_type_len + 1);
8579 
8580 	/* Get an extra byte so we can tell if values are too long. */
8581 	fmri = safe_malloc(max_scf_fmri_len + 2);
8582 
8583 	(void) memset(&pgelts, 0, sizeof (pgelts));
8584 
8585 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
8586 		void *entity;
8587 		int isservice;
8588 		scf_type_t ty;
8589 
8590 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
8591 			scfdie();
8592 
8593 		if ((ty != SCF_TYPE_ASTRING &&
8594 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
8595 		    prop_get_val(exp_prop, exp_val) != 0) {
8596 			export_property(exp_prop, NULL, &pgelts, 0);
8597 			continue;
8598 		}
8599 
8600 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8601 			scfdie();
8602 
8603 		if (scf_value_get_astring(exp_val, fmri,
8604 		    max_scf_fmri_len + 2) < 0)
8605 			scfdie();
8606 
8607 		/* Look for a dependency group in the target fmri. */
8608 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
8609 		switch (serr) {
8610 		case SCF_ERROR_NONE:
8611 			break;
8612 
8613 		case SCF_ERROR_NO_MEMORY:
8614 			uu_die(gettext("Out of memory.\n"));
8615 			/* NOTREACHED */
8616 
8617 		case SCF_ERROR_INVALID_ARGUMENT:
8618 			if (g_verbose) {
8619 				if (scf_property_to_fmri(exp_prop, fmri,
8620 				    max_scf_fmri_len + 2) < 0)
8621 					scfdie();
8622 
8623 				warn(gettext("The value of %s is not a valid "
8624 				    "FMRI.\n"), fmri);
8625 			}
8626 
8627 			export_property(exp_prop, exp_str, &pgelts, 0);
8628 			continue;
8629 
8630 		case SCF_ERROR_CONSTRAINT_VIOLATED:
8631 			if (g_verbose) {
8632 				if (scf_property_to_fmri(exp_prop, fmri,
8633 				    max_scf_fmri_len + 2) < 0)
8634 					scfdie();
8635 
8636 				warn(gettext("The value of %s does not specify "
8637 				    "a service or an instance.\n"), fmri);
8638 			}
8639 
8640 			export_property(exp_prop, exp_str, &pgelts, 0);
8641 			continue;
8642 
8643 		case SCF_ERROR_NOT_FOUND:
8644 			if (g_verbose) {
8645 				if (scf_property_to_fmri(exp_prop, fmri,
8646 				    max_scf_fmri_len + 2) < 0)
8647 					scfdie();
8648 
8649 				warn(gettext("The entity specified by %s does "
8650 				    "not exist.\n"), fmri);
8651 			}
8652 
8653 			export_property(exp_prop, exp_str, &pgelts, 0);
8654 			continue;
8655 
8656 		default:
8657 #ifndef NDEBUG
8658 			(void) fprintf(stderr, "%s:%d: %s() failed with "
8659 			    "unexpected error %d.\n", __FILE__, __LINE__,
8660 			    "fmri_to_entity", serr);
8661 #endif
8662 			abort();
8663 		}
8664 
8665 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
8666 			if (scf_error() != SCF_ERROR_NOT_FOUND)
8667 				scfdie();
8668 
8669 			warn(gettext("Entity %s is missing dependency property "
8670 			    "group %s.\n"), fmri, exp_str);
8671 
8672 			export_property(exp_prop, NULL, &pgelts, 0);
8673 			continue;
8674 		}
8675 
8676 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
8677 			scfdie();
8678 
8679 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
8680 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
8681 				scfdie();
8682 
8683 			warn(gettext("Property group %s is not of "
8684 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
8685 
8686 			export_property(exp_prop, NULL, &pgelts, 0);
8687 			continue;
8688 		}
8689 
8690 		n = export_dependent(opg, exp_str, fmri);
8691 		if (n == NULL)
8692 			export_property(exp_prop, exp_str, &pgelts, 0);
8693 		else {
8694 			if (eelts->dependents == NULL)
8695 				eelts->dependents = n;
8696 			else
8697 				(void) xmlAddSibling(eelts->dependents,
8698 				    n);
8699 		}
8700 	}
8701 	if (ret == -1)
8702 		scfdie();
8703 
8704 	free(fmri);
8705 	free(type);
8706 
8707 	scf_iter_destroy(iter);
8708 	scf_pg_destroy(opg);
8709 
8710 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
8711 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
8712 		    eelts);
8713 }
8714 
8715 static void
8716 make_node(xmlNodePtr *nodep, const char *name)
8717 {
8718 	if (*nodep == NULL) {
8719 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
8720 		if (*nodep == NULL)
8721 			uu_die(emsg_create_xml);
8722 	}
8723 }
8724 
8725 static xmlNodePtr
8726 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
8727 {
8728 	int ret;
8729 	xmlNodePtr parent = NULL;
8730 	xmlNodePtr loctext = NULL;
8731 
8732 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8733 		scfdie();
8734 
8735 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8736 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
8737 		    prop_get_val(exp_prop, exp_val) != 0)
8738 			continue;
8739 
8740 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
8741 			scfdie();
8742 
8743 		make_node(&parent, parname);
8744 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
8745 		    (xmlChar *)exp_str);
8746 		if (loctext == NULL)
8747 			uu_die(emsg_create_xml);
8748 
8749 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8750 			scfdie();
8751 
8752 		safe_setprop(loctext, "xml:lang", exp_str);
8753 	}
8754 
8755 	if (ret == -1)
8756 		scfdie();
8757 
8758 	return (parent);
8759 }
8760 
8761 static xmlNodePtr
8762 export_tm_manpage(scf_propertygroup_t *pg)
8763 {
8764 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
8765 	if (manpage == NULL)
8766 		uu_die(emsg_create_xml);
8767 
8768 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
8769 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
8770 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
8771 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
8772 		xmlFreeNode(manpage);
8773 		return (NULL);
8774 	}
8775 
8776 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
8777 		(void) set_attr_from_prop_default(exp_prop,
8778 		    manpage, "manpath", ":default");
8779 
8780 	return (manpage);
8781 }
8782 
8783 static xmlNodePtr
8784 export_tm_doc_link(scf_propertygroup_t *pg)
8785 {
8786 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
8787 	if (doc_link == NULL)
8788 		uu_die(emsg_create_xml);
8789 
8790 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
8791 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
8792 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
8793 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
8794 		xmlFreeNode(doc_link);
8795 		return (NULL);
8796 	}
8797 	return (doc_link);
8798 }
8799 
8800 /*
8801  * Process template information for a service or instances.
8802  */
8803 static void
8804 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
8805     struct template_elts *telts)
8806 {
8807 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
8808 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
8809 	xmlNodePtr child = NULL;
8810 
8811 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
8812 		scfdie();
8813 
8814 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
8815 		telts->common_name = export_tm_loctext(pg, "common_name");
8816 		if (telts->common_name == NULL)
8817 			export_pg(pg, elts, 0);
8818 		return;
8819 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
8820 		telts->description = export_tm_loctext(pg, "description");
8821 		if (telts->description == NULL)
8822 			export_pg(pg, elts, 0);
8823 		return;
8824 	}
8825 
8826 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
8827 		child = export_tm_manpage(pg);
8828 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
8829 		child = export_tm_doc_link(pg);
8830 	}
8831 
8832 	if (child != NULL) {
8833 		make_node(&telts->documentation, "documentation");
8834 		(void) xmlAddChild(telts->documentation, child);
8835 	} else {
8836 		export_pg(pg, elts, 0);
8837 	}
8838 }
8839 
8840 /*
8841  * Process the general property group for an instance.
8842  */
8843 static void
8844 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
8845     struct entity_elts *elts)
8846 {
8847 	uint8_t enabled;
8848 	struct pg_elts pgelts;
8849 	int ret;
8850 
8851 	/* enabled */
8852 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
8853 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8854 	    prop_get_val(exp_prop, exp_val) == 0) {
8855 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
8856 			scfdie();
8857 	} else {
8858 		enabled = 0;
8859 	}
8860 
8861 	safe_setprop(inode, enabled_attr, enabled ? true : false);
8862 
8863 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8864 		scfdie();
8865 
8866 	(void) memset(&pgelts, 0, sizeof (pgelts));
8867 
8868 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8869 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8870 			scfdie();
8871 
8872 		if (strcmp(exp_str, scf_property_enabled) == 0) {
8873 			continue;
8874 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8875 			xmlNodePtr rnode, sfnode;
8876 
8877 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8878 			if (rnode == NULL)
8879 				uu_die(emsg_create_xml);
8880 
8881 			sfnode = xmlNewChild(rnode, NULL,
8882 			    (xmlChar *)"service_fmri", NULL);
8883 			if (sfnode == NULL)
8884 				uu_die(emsg_create_xml);
8885 
8886 			if (set_attr_from_prop(exp_prop, sfnode,
8887 			    value_attr) == 0) {
8888 				elts->restarter = rnode;
8889 				continue;
8890 			}
8891 
8892 			xmlFreeNode(rnode);
8893 		}
8894 
8895 		export_property(exp_prop, exp_str, &pgelts, 0);
8896 	}
8897 	if (ret == -1)
8898 		scfdie();
8899 
8900 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
8901 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
8902 		    elts);
8903 }
8904 
8905 /*
8906  * Put an instance element for the given instance into selts.
8907  */
8908 static void
8909 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
8910 {
8911 	xmlNodePtr n;
8912 	boolean_t isdefault;
8913 	struct entity_elts elts;
8914 	struct template_elts template_elts;
8915 	int ret;
8916 
8917 	n = xmlNewNode(NULL, (xmlChar *)"instance");
8918 	if (n == NULL)
8919 		uu_die(emsg_create_xml);
8920 
8921 	/* name */
8922 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
8923 		scfdie();
8924 	safe_setprop(n, name_attr, exp_str);
8925 	isdefault = strcmp(exp_str, "default") == 0;
8926 
8927 	/* check existance of general pg (since general/enabled is required) */
8928 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
8929 		if (scf_error() != SCF_ERROR_NOT_FOUND)
8930 			scfdie();
8931 
8932 		if (g_verbose) {
8933 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
8934 				scfdie();
8935 
8936 			warn(gettext("Instance %s has no general property "
8937 			    "group; it will be marked disabled.\n"), exp_str);
8938 		}
8939 
8940 		safe_setprop(n, enabled_attr, false);
8941 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
8942 	    strcmp(exp_str, scf_group_framework) != 0) {
8943 		if (g_verbose) {
8944 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
8945 				scfdie();
8946 
8947 			warn(gettext("Property group %s is not of type "
8948 			    "framework; the instance will be marked "
8949 			    "disabled.\n"), exp_str);
8950 		}
8951 
8952 		safe_setprop(n, enabled_attr, false);
8953 	}
8954 
8955 	/* property groups */
8956 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
8957 		scfdie();
8958 
8959 	(void) memset(&elts, 0, sizeof (elts));
8960 	(void) memset(&template_elts, 0, sizeof (template_elts));
8961 
8962 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
8963 		uint32_t pgflags;
8964 
8965 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
8966 			scfdie();
8967 
8968 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
8969 			continue;
8970 
8971 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
8972 			scfdie();
8973 
8974 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
8975 			export_dependency(exp_pg, &elts);
8976 			continue;
8977 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
8978 			export_method(exp_pg, &elts);
8979 			continue;
8980 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
8981 			if (scf_pg_get_name(exp_pg, exp_str,
8982 			    max_scf_name_len + 1) < 0)
8983 				scfdie();
8984 
8985 			if (strcmp(exp_str, scf_pg_general) == 0) {
8986 				export_inst_general(exp_pg, n, &elts);
8987 				continue;
8988 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
8989 			    0) {
8990 				export_method_context(exp_pg, &elts);
8991 				continue;
8992 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
8993 				export_dependents(exp_pg, &elts);
8994 				continue;
8995 			}
8996 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
8997 			export_template(exp_pg, &elts, &template_elts);
8998 			continue;
8999 		}
9000 
9001 		/* Ordinary pg. */
9002 		export_pg(exp_pg, &elts, flags);
9003 	}
9004 	if (ret == -1)
9005 		scfdie();
9006 
9007 	if (template_elts.common_name != NULL) {
9008 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9009 		(void) xmlAddChild(elts.template, template_elts.common_name);
9010 		(void) xmlAddChild(elts.template, template_elts.description);
9011 		(void) xmlAddChild(elts.template, template_elts.documentation);
9012 	} else {
9013 		xmlFreeNode(template_elts.description);
9014 		xmlFreeNode(template_elts.documentation);
9015 	}
9016 
9017 	if (isdefault && elts.restarter == NULL &&
9018 	    elts.dependencies == NULL && elts.method_context == NULL &&
9019 	    elts.exec_methods == NULL && elts.property_groups == NULL &&
9020 	    elts.template == NULL) {
9021 		xmlChar *eval;
9022 
9023 		/* This is a default instance */
9024 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
9025 
9026 		xmlFreeNode(n);
9027 
9028 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
9029 		if (n == NULL)
9030 			uu_die(emsg_create_xml);
9031 
9032 		safe_setprop(n, enabled_attr, (char *)eval);
9033 		xmlFree(eval);
9034 
9035 		selts->create_default_instance = n;
9036 	} else {
9037 		/* Assemble the children in order. */
9038 		(void) xmlAddChild(n, elts.restarter);
9039 		(void) xmlAddChildList(n, elts.dependencies);
9040 		(void) xmlAddChildList(n, elts.dependents);
9041 		(void) xmlAddChild(n, elts.method_context);
9042 		(void) xmlAddChildList(n, elts.exec_methods);
9043 		(void) xmlAddChildList(n, elts.property_groups);
9044 		(void) xmlAddChild(n, elts.template);
9045 
9046 		if (selts->instances == NULL)
9047 			selts->instances = n;
9048 		else
9049 			(void) xmlAddSibling(selts->instances, n);
9050 	}
9051 }
9052 
9053 /*
9054  * Return a service element for the given service.
9055  */
9056 static xmlNodePtr
9057 export_service(scf_service_t *svc, int flags)
9058 {
9059 	xmlNodePtr snode;
9060 	struct entity_elts elts;
9061 	struct template_elts template_elts;
9062 	int ret;
9063 
9064 	snode = xmlNewNode(NULL, (xmlChar *)"service");
9065 	if (snode == NULL)
9066 		uu_die(emsg_create_xml);
9067 
9068 	/* Get & set name attribute */
9069 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
9070 		scfdie();
9071 	safe_setprop(snode, name_attr, exp_str);
9072 
9073 	safe_setprop(snode, type_attr, "service");
9074 	safe_setprop(snode, "version", "0");
9075 
9076 	/* Acquire child elements. */
9077 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
9078 		scfdie();
9079 
9080 	(void) memset(&elts, 0, sizeof (elts));
9081 	(void) memset(&template_elts, 0, sizeof (template_elts));
9082 
9083 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9084 		uint32_t pgflags;
9085 
9086 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9087 			scfdie();
9088 
9089 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9090 			continue;
9091 
9092 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9093 			scfdie();
9094 
9095 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9096 			export_dependency(exp_pg, &elts);
9097 			continue;
9098 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9099 			export_method(exp_pg, &elts);
9100 			continue;
9101 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9102 			if (scf_pg_get_name(exp_pg, exp_str,
9103 			    max_scf_name_len + 1) < 0)
9104 				scfdie();
9105 
9106 			if (strcmp(exp_str, scf_pg_general) == 0) {
9107 				export_svc_general(exp_pg, &elts);
9108 				continue;
9109 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9110 			    0) {
9111 				export_method_context(exp_pg, &elts);
9112 				continue;
9113 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9114 				export_dependents(exp_pg, &elts);
9115 				continue;
9116 			}
9117 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9118 			export_template(exp_pg, &elts, &template_elts);
9119 			continue;
9120 		}
9121 
9122 		export_pg(exp_pg, &elts, flags);
9123 	}
9124 	if (ret == -1)
9125 		scfdie();
9126 
9127 	if (template_elts.common_name != NULL) {
9128 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9129 		(void) xmlAddChild(elts.template, template_elts.common_name);
9130 		(void) xmlAddChild(elts.template, template_elts.description);
9131 		(void) xmlAddChild(elts.template, template_elts.documentation);
9132 	} else {
9133 		xmlFreeNode(template_elts.description);
9134 		xmlFreeNode(template_elts.documentation);
9135 	}
9136 
9137 	/* Iterate instances */
9138 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
9139 		scfdie();
9140 
9141 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
9142 		export_instance(exp_inst, &elts, flags);
9143 	if (ret == -1)
9144 		scfdie();
9145 
9146 	/* Now add all of the accumulated elements in order. */
9147 	(void) xmlAddChild(snode, elts.create_default_instance);
9148 	(void) xmlAddChild(snode, elts.single_instance);
9149 	(void) xmlAddChild(snode, elts.restarter);
9150 	(void) xmlAddChildList(snode, elts.dependencies);
9151 	(void) xmlAddChildList(snode, elts.dependents);
9152 	(void) xmlAddChild(snode, elts.method_context);
9153 	(void) xmlAddChildList(snode, elts.exec_methods);
9154 	(void) xmlAddChildList(snode, elts.property_groups);
9155 	(void) xmlAddChildList(snode, elts.instances);
9156 	(void) xmlAddChild(snode, elts.stability);
9157 	(void) xmlAddChild(snode, elts.template);
9158 
9159 	return (snode);
9160 }
9161 
9162 static int
9163 export_callback(void *data, scf_walkinfo_t *wip)
9164 {
9165 	FILE *f;
9166 	xmlDocPtr doc;
9167 	xmlNodePtr sb;
9168 	int result;
9169 	struct export_args *argsp = (struct export_args *)data;
9170 
9171 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
9172 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9173 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9174 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9175 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9176 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9177 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9178 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9179 		scfdie();
9180 
9181 	exp_str_sz = max_scf_len + 1;
9182 	exp_str = safe_malloc(exp_str_sz);
9183 
9184 	if (argsp->filename != NULL) {
9185 		errno = 0;
9186 		f = fopen(argsp->filename, "wb");
9187 		if (f == NULL) {
9188 			if (errno == 0)
9189 				uu_die(gettext("Could not open \"%s\": no free "
9190 				    "stdio streams.\n"), argsp->filename);
9191 			else
9192 				uu_die(gettext("Could not open \"%s\""),
9193 				    argsp->filename);
9194 		}
9195 	} else
9196 		f = stdout;
9197 
9198 	doc = xmlNewDoc((xmlChar *)"1.0");
9199 	if (doc == NULL)
9200 		uu_die(gettext("Could not create XML document.\n"));
9201 
9202 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9203 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9204 		uu_die(emsg_create_xml);
9205 
9206 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9207 	if (sb == NULL)
9208 		uu_die(emsg_create_xml);
9209 	safe_setprop(sb, type_attr, "manifest");
9210 	safe_setprop(sb, name_attr, "export");
9211 	(void) xmlAddSibling(doc->children, sb);
9212 
9213 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
9214 
9215 	result = write_service_bundle(doc, f);
9216 
9217 	free(exp_str);
9218 	scf_iter_destroy(exp_val_iter);
9219 	scf_iter_destroy(exp_prop_iter);
9220 	scf_iter_destroy(exp_pg_iter);
9221 	scf_iter_destroy(exp_inst_iter);
9222 	scf_value_destroy(exp_val);
9223 	scf_property_destroy(exp_prop);
9224 	scf_pg_destroy(exp_pg);
9225 	scf_instance_destroy(exp_inst);
9226 
9227 	xmlFreeDoc(doc);
9228 
9229 	if (f != stdout)
9230 		(void) fclose(f);
9231 
9232 	return (result);
9233 }
9234 
9235 /*
9236  * Get the service named by fmri, build an XML tree which represents it, and
9237  * dump it into filename (or stdout if filename is NULL).
9238  */
9239 int
9240 lscf_service_export(char *fmri, const char *filename, int flags)
9241 {
9242 	struct export_args args;
9243 	int ret, err;
9244 
9245 	lscf_prep_hndl();
9246 
9247 	bzero(&args, sizeof (args));
9248 	args.filename = filename;
9249 	args.flags = flags;
9250 
9251 	err = 0;
9252 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
9253 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
9254 	    &args, &err, semerr)) != 0) {
9255 		if (ret != -1)
9256 			semerr(gettext("Failed to walk instances: %s\n"),
9257 			    scf_strerror(ret));
9258 		return (-1);
9259 	}
9260 
9261 	/*
9262 	 * Error message has already been printed.
9263 	 */
9264 	if (err != 0)
9265 		return (-1);
9266 
9267 	return (0);
9268 }
9269 
9270 
9271 /*
9272  * Archive
9273  */
9274 
9275 static xmlNodePtr
9276 make_archive(int flags)
9277 {
9278 	xmlNodePtr sb;
9279 	scf_scope_t *scope;
9280 	scf_service_t *svc;
9281 	scf_iter_t *iter;
9282 	int r;
9283 
9284 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9285 	    (svc = scf_service_create(g_hndl)) == NULL ||
9286 	    (iter = scf_iter_create(g_hndl)) == NULL ||
9287 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
9288 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9289 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9290 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9291 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9292 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9293 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9294 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9295 		scfdie();
9296 
9297 	exp_str_sz = max_scf_len + 1;
9298 	exp_str = safe_malloc(exp_str_sz);
9299 
9300 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9301 	if (sb == NULL)
9302 		uu_die(emsg_create_xml);
9303 	safe_setprop(sb, type_attr, "archive");
9304 	safe_setprop(sb, name_attr, "none");
9305 
9306 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
9307 		scfdie();
9308 	if (scf_iter_scope_services(iter, scope) != 0)
9309 		scfdie();
9310 
9311 	for (;;) {
9312 		r = scf_iter_next_service(iter, svc);
9313 		if (r == 0)
9314 			break;
9315 		if (r != 1)
9316 			scfdie();
9317 
9318 		if (scf_service_get_name(svc, exp_str,
9319 		    max_scf_name_len + 1) < 0)
9320 			scfdie();
9321 
9322 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
9323 			continue;
9324 
9325 		xmlAddChild(sb, export_service(svc, flags));
9326 	}
9327 
9328 	free(exp_str);
9329 
9330 	scf_iter_destroy(exp_val_iter);
9331 	scf_iter_destroy(exp_prop_iter);
9332 	scf_iter_destroy(exp_pg_iter);
9333 	scf_iter_destroy(exp_inst_iter);
9334 	scf_value_destroy(exp_val);
9335 	scf_property_destroy(exp_prop);
9336 	scf_pg_destroy(exp_pg);
9337 	scf_instance_destroy(exp_inst);
9338 	scf_iter_destroy(iter);
9339 	scf_service_destroy(svc);
9340 	scf_scope_destroy(scope);
9341 
9342 	return (sb);
9343 }
9344 
9345 int
9346 lscf_archive(const char *filename, int flags)
9347 {
9348 	FILE *f;
9349 	xmlDocPtr doc;
9350 	int result;
9351 
9352 	lscf_prep_hndl();
9353 
9354 	if (filename != NULL) {
9355 		errno = 0;
9356 		f = fopen(filename, "wb");
9357 		if (f == NULL) {
9358 			if (errno == 0)
9359 				uu_die(gettext("Could not open \"%s\": no free "
9360 				    "stdio streams.\n"), filename);
9361 			else
9362 				uu_die(gettext("Could not open \"%s\""),
9363 				    filename);
9364 		}
9365 	} else
9366 		f = stdout;
9367 
9368 	doc = xmlNewDoc((xmlChar *)"1.0");
9369 	if (doc == NULL)
9370 		uu_die(gettext("Could not create XML document.\n"));
9371 
9372 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9373 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9374 		uu_die(emsg_create_xml);
9375 
9376 	(void) xmlAddSibling(doc->children, make_archive(flags));
9377 
9378 	result = write_service_bundle(doc, f);
9379 
9380 	xmlFreeDoc(doc);
9381 
9382 	if (f != stdout)
9383 		(void) fclose(f);
9384 
9385 	return (result);
9386 }
9387 
9388 
9389 /*
9390  * "Extract" a profile.
9391  */
9392 int
9393 lscf_profile_extract(const char *filename)
9394 {
9395 	FILE *f;
9396 	xmlDocPtr doc;
9397 	xmlNodePtr sb, snode, inode;
9398 	scf_scope_t *scope;
9399 	scf_service_t *svc;
9400 	scf_instance_t *inst;
9401 	scf_propertygroup_t *pg;
9402 	scf_property_t *prop;
9403 	scf_value_t *val;
9404 	scf_iter_t *siter, *iiter;
9405 	int r, s;
9406 	char *namebuf;
9407 	uint8_t b;
9408 	int result;
9409 
9410 	lscf_prep_hndl();
9411 
9412 	if (filename != NULL) {
9413 		errno = 0;
9414 		f = fopen(filename, "wb");
9415 		if (f == NULL) {
9416 			if (errno == 0)
9417 				uu_die(gettext("Could not open \"%s\": no "
9418 				    "free stdio streams.\n"), filename);
9419 			else
9420 				uu_die(gettext("Could not open \"%s\""),
9421 				    filename);
9422 		}
9423 	} else
9424 		f = stdout;
9425 
9426 	doc = xmlNewDoc((xmlChar *)"1.0");
9427 	if (doc == NULL)
9428 		uu_die(gettext("Could not create XML document.\n"));
9429 
9430 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9431 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9432 		uu_die(emsg_create_xml);
9433 
9434 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9435 	if (sb == NULL)
9436 		uu_die(emsg_create_xml);
9437 	safe_setprop(sb, type_attr, "profile");
9438 	safe_setprop(sb, name_attr, "extract");
9439 	(void) xmlAddSibling(doc->children, sb);
9440 
9441 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9442 	    (svc = scf_service_create(g_hndl)) == NULL ||
9443 	    (inst = scf_instance_create(g_hndl)) == NULL ||
9444 	    (pg = scf_pg_create(g_hndl)) == NULL ||
9445 	    (prop = scf_property_create(g_hndl)) == NULL ||
9446 	    (val = scf_value_create(g_hndl)) == NULL ||
9447 	    (siter = scf_iter_create(g_hndl)) == NULL ||
9448 	    (iiter = scf_iter_create(g_hndl)) == NULL)
9449 		scfdie();
9450 
9451 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
9452 		scfdie();
9453 
9454 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
9455 		scfdie();
9456 
9457 	namebuf = safe_malloc(max_scf_name_len + 1);
9458 
9459 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
9460 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
9461 			scfdie();
9462 
9463 		snode = xmlNewNode(NULL, (xmlChar *)"service");
9464 		if (snode == NULL)
9465 			uu_die(emsg_create_xml);
9466 
9467 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
9468 		    0)
9469 			scfdie();
9470 
9471 		safe_setprop(snode, name_attr, namebuf);
9472 
9473 		safe_setprop(snode, type_attr, "service");
9474 		safe_setprop(snode, "version", "0");
9475 
9476 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
9477 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
9478 			    SCF_SUCCESS) {
9479 				if (scf_error() != SCF_ERROR_NOT_FOUND)
9480 					scfdie();
9481 
9482 				if (g_verbose) {
9483 					ssize_t len;
9484 					char *fmri;
9485 
9486 					len =
9487 					    scf_instance_to_fmri(inst, NULL, 0);
9488 					if (len < 0)
9489 						scfdie();
9490 
9491 					fmri = safe_malloc(len + 1);
9492 
9493 					if (scf_instance_to_fmri(inst, fmri,
9494 					    len + 1) < 0)
9495 						scfdie();
9496 
9497 					warn("Instance %s has no \"%s\" "
9498 					    "property group.\n", fmri,
9499 					    scf_pg_general);
9500 
9501 					free(fmri);
9502 				}
9503 
9504 				continue;
9505 			}
9506 
9507 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
9508 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
9509 			    prop_get_val(prop, val) != 0)
9510 				continue;
9511 
9512 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
9513 			    NULL);
9514 			if (inode == NULL)
9515 				uu_die(emsg_create_xml);
9516 
9517 			if (scf_instance_get_name(inst, namebuf,
9518 			    max_scf_name_len + 1) < 0)
9519 				scfdie();
9520 
9521 			safe_setprop(inode, name_attr, namebuf);
9522 
9523 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
9524 				scfdie();
9525 
9526 			safe_setprop(inode, enabled_attr, b ? true : false);
9527 		}
9528 		if (s < 0)
9529 			scfdie();
9530 
9531 		if (snode->children != NULL)
9532 			xmlAddChild(sb, snode);
9533 		else
9534 			xmlFreeNode(snode);
9535 	}
9536 	if (r < 0)
9537 		scfdie();
9538 
9539 	free(namebuf);
9540 
9541 	result = write_service_bundle(doc, f);
9542 
9543 	xmlFreeDoc(doc);
9544 
9545 	if (f != stdout)
9546 		(void) fclose(f);
9547 
9548 	return (result);
9549 }
9550 
9551 
9552 /*
9553  * Entity manipulation commands
9554  */
9555 
9556 /*
9557  * Entity selection.  If no entity is selected, then the current scope is in
9558  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
9559  * only cur_inst is NULL, and when an instance is selected, none are NULL.
9560  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
9561  * cur_inst will be non-NULL.
9562  */
9563 
9564 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
9565 static int
9566 select_inst(const char *name)
9567 {
9568 	scf_instance_t *inst;
9569 	scf_error_t err;
9570 
9571 	assert(cur_svc != NULL);
9572 
9573 	inst = scf_instance_create(g_hndl);
9574 	if (inst == NULL)
9575 		scfdie();
9576 
9577 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
9578 		cur_inst = inst;
9579 		return (0);
9580 	}
9581 
9582 	err = scf_error();
9583 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9584 		scfdie();
9585 
9586 	scf_instance_destroy(inst);
9587 	return (1);
9588 }
9589 
9590 /* Returns as above. */
9591 static int
9592 select_svc(const char *name)
9593 {
9594 	scf_service_t *svc;
9595 	scf_error_t err;
9596 
9597 	assert(cur_scope != NULL);
9598 
9599 	svc = scf_service_create(g_hndl);
9600 	if (svc == NULL)
9601 		scfdie();
9602 
9603 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
9604 		cur_svc = svc;
9605 		return (0);
9606 	}
9607 
9608 	err = scf_error();
9609 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9610 		scfdie();
9611 
9612 	scf_service_destroy(svc);
9613 	return (1);
9614 }
9615 
9616 /* ARGSUSED */
9617 static int
9618 select_callback(void *unused, scf_walkinfo_t *wip)
9619 {
9620 	scf_instance_t *inst;
9621 	scf_service_t *svc;
9622 	scf_scope_t *scope;
9623 
9624 	if (wip->inst != NULL) {
9625 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9626 		    (svc = scf_service_create(g_hndl)) == NULL ||
9627 		    (inst = scf_instance_create(g_hndl)) == NULL)
9628 			scfdie();
9629 
9630 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9631 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9632 			scfdie();
9633 	} else {
9634 		assert(wip->svc != NULL);
9635 
9636 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9637 		    (svc = scf_service_create(g_hndl)) == NULL)
9638 			scfdie();
9639 
9640 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9641 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9642 			scfdie();
9643 
9644 		inst = NULL;
9645 	}
9646 
9647 	/* Clear out the current selection */
9648 	assert(cur_scope != NULL);
9649 	scf_scope_destroy(cur_scope);
9650 	scf_service_destroy(cur_svc);
9651 	scf_instance_destroy(cur_inst);
9652 
9653 	cur_scope = scope;
9654 	cur_svc = svc;
9655 	cur_inst = inst;
9656 
9657 	return (0);
9658 }
9659 
9660 static int
9661 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
9662 {
9663 	char **fmri = fmri_p;
9664 
9665 	*fmri = strdup(wip->fmri);
9666 	if (*fmri == NULL)
9667 		uu_die(gettext("Out of memory.\n"));
9668 
9669 	return (0);
9670 }
9671 
9672 /*
9673  * validate [fmri]
9674  * Perform the validation of an FMRI instance.
9675  */
9676 void
9677 lscf_validate_fmri(const char *fmri)
9678 {
9679 	int ret = 0;
9680 	size_t inst_sz;
9681 	char *inst_fmri = NULL;
9682 	scf_tmpl_errors_t *errs = NULL;
9683 	char *snapbuf = NULL;
9684 
9685 	lscf_prep_hndl();
9686 
9687 	if (fmri == NULL) {
9688 		inst_sz = max_scf_fmri_len + 1;
9689 		inst_fmri = safe_malloc(inst_sz);
9690 
9691 		if (cur_snap != NULL) {
9692 			snapbuf = safe_malloc(max_scf_name_len + 1);
9693 			if (scf_snapshot_get_name(cur_snap, snapbuf,
9694 			    max_scf_name_len + 1) < 0)
9695 				scfdie();
9696 		}
9697 		if (cur_inst == NULL) {
9698 			semerr(gettext("No instance selected\n"));
9699 			goto cleanup;
9700 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
9701 		    inst_sz) >= inst_sz) {
9702 			/* sanity check. Should never get here */
9703 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
9704 			    __FILE__, __LINE__);
9705 		}
9706 	} else {
9707 		scf_error_t scf_err;
9708 		int err = 0;
9709 
9710 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
9711 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
9712 			uu_warn("Failed to walk instances: %s\n",
9713 			    scf_strerror(scf_err));
9714 			goto cleanup;
9715 		}
9716 		if (err != 0)
9717 			/* error message displayed by scf_walk_fmri */
9718 			goto cleanup;
9719 	}
9720 
9721 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
9722 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
9723 	if (ret == -1) {
9724 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
9725 			warn(gettext("Template data for %s is invalid. "
9726 			    "Consider reverting to a previous snapshot or "
9727 			    "restoring original configuration.\n"), inst_fmri);
9728 		} else {
9729 			uu_warn("%s: %s\n",
9730 			    gettext("Error validating the instance"),
9731 			    scf_strerror(scf_error()));
9732 		}
9733 	} else if (ret == 1 && errs != NULL) {
9734 		scf_tmpl_error_t *err = NULL;
9735 		char *msg;
9736 		size_t len = 256;	/* initial error buffer size */
9737 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
9738 		    SCF_TMPL_STRERROR_HUMAN : 0;
9739 
9740 		msg = safe_malloc(len);
9741 
9742 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
9743 			int ret;
9744 
9745 			if ((ret = scf_tmpl_strerror(err, msg, len,
9746 			    flag)) >= len) {
9747 				len = ret + 1;
9748 				msg = realloc(msg, len);
9749 				if (msg == NULL)
9750 					uu_die(gettext(
9751 					    "Out of memory.\n"));
9752 				(void) scf_tmpl_strerror(err, msg, len,
9753 				    flag);
9754 			}
9755 			(void) fprintf(stderr, "%s\n", msg);
9756 		}
9757 		if (msg != NULL)
9758 			free(msg);
9759 	}
9760 	if (errs != NULL)
9761 		scf_tmpl_errors_destroy(errs);
9762 cleanup:
9763 	free(inst_fmri);
9764 	free(snapbuf);
9765 }
9766 
9767 static void
9768 lscf_validate_file(const char *filename)
9769 {
9770 	tmpl_errors_t *errs;
9771 
9772 	bundle_t *b = internal_bundle_new();
9773 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
9774 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
9775 			tmpl_errors_print(stderr, errs, "");
9776 			semerr(gettext("Validation failed.\n"));
9777 		}
9778 		tmpl_errors_destroy(errs);
9779 	}
9780 	(void) internal_bundle_free(b);
9781 }
9782 
9783 /*
9784  * validate [fmri|file]
9785  */
9786 void
9787 lscf_validate(const char *arg)
9788 {
9789 	const char *str;
9790 
9791 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
9792 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
9793 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
9794 		lscf_validate_file(str);
9795 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
9796 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
9797 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
9798 		lscf_validate_fmri(str);
9799 	} else if (access(arg, R_OK | F_OK) == 0) {
9800 		lscf_validate_file(arg);
9801 	} else {
9802 		lscf_validate_fmri(arg);
9803 	}
9804 }
9805 
9806 void
9807 lscf_select(const char *fmri)
9808 {
9809 	int ret, err;
9810 
9811 	lscf_prep_hndl();
9812 
9813 	if (cur_snap != NULL) {
9814 		struct snaplevel *elt;
9815 		char *buf;
9816 
9817 		/* Error unless name is that of the next level. */
9818 		elt = uu_list_next(cur_levels, cur_elt);
9819 		if (elt == NULL) {
9820 			semerr(gettext("No children.\n"));
9821 			return;
9822 		}
9823 
9824 		buf = safe_malloc(max_scf_name_len + 1);
9825 
9826 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
9827 		    max_scf_name_len + 1) < 0)
9828 			scfdie();
9829 
9830 		if (strcmp(buf, fmri) != 0) {
9831 			semerr(gettext("No such child.\n"));
9832 			free(buf);
9833 			return;
9834 		}
9835 
9836 		free(buf);
9837 
9838 		cur_elt = elt;
9839 		cur_level = elt->sl;
9840 		return;
9841 	}
9842 
9843 	/*
9844 	 * Special case for 'svc:', which takes the user to the scope level.
9845 	 */
9846 	if (strcmp(fmri, "svc:") == 0) {
9847 		scf_instance_destroy(cur_inst);
9848 		scf_service_destroy(cur_svc);
9849 		cur_inst = NULL;
9850 		cur_svc = NULL;
9851 		return;
9852 	}
9853 
9854 	/*
9855 	 * Special case for ':properties'.  This appears as part of 'list' but
9856 	 * can't be selected.  Give a more helpful error message in this case.
9857 	 */
9858 	if (strcmp(fmri, ":properties") == 0) {
9859 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
9860 		    "to list properties.\n"));
9861 		return;
9862 	}
9863 
9864 	/*
9865 	 * First try the argument as relative to the current selection.
9866 	 */
9867 	if (cur_inst != NULL) {
9868 		/* EMPTY */;
9869 	} else if (cur_svc != NULL) {
9870 		if (select_inst(fmri) != 1)
9871 			return;
9872 	} else {
9873 		if (select_svc(fmri) != 1)
9874 			return;
9875 	}
9876 
9877 	err = 0;
9878 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
9879 	    select_callback, NULL, &err, semerr)) != 0) {
9880 		semerr(gettext("Failed to walk instances: %s\n"),
9881 		    scf_strerror(ret));
9882 	}
9883 }
9884 
9885 void
9886 lscf_unselect(void)
9887 {
9888 	lscf_prep_hndl();
9889 
9890 	if (cur_snap != NULL) {
9891 		struct snaplevel *elt;
9892 
9893 		elt = uu_list_prev(cur_levels, cur_elt);
9894 		if (elt == NULL) {
9895 			semerr(gettext("No parent levels.\n"));
9896 		} else {
9897 			cur_elt = elt;
9898 			cur_level = elt->sl;
9899 		}
9900 	} else if (cur_inst != NULL) {
9901 		scf_instance_destroy(cur_inst);
9902 		cur_inst = NULL;
9903 	} else if (cur_svc != NULL) {
9904 		scf_service_destroy(cur_svc);
9905 		cur_svc = NULL;
9906 	} else {
9907 		semerr(gettext("Cannot unselect at scope level.\n"));
9908 	}
9909 }
9910 
9911 /*
9912  * Return the FMRI of the current selection, for the prompt.
9913  */
9914 void
9915 lscf_get_selection_str(char *buf, size_t bufsz)
9916 {
9917 	char *cp;
9918 	ssize_t fmrilen, szret;
9919 	boolean_t deleted = B_FALSE;
9920 
9921 	if (g_hndl == NULL) {
9922 		(void) strlcpy(buf, "svc:", bufsz);
9923 		return;
9924 	}
9925 
9926 	if (cur_level != NULL) {
9927 		assert(cur_snap != NULL);
9928 
9929 		/* [ snapshot ] FMRI [: instance ] */
9930 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
9931 		    + 2 + max_scf_name_len + 1 + 1);
9932 
9933 		buf[0] = '[';
9934 
9935 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
9936 		    max_scf_name_len + 1);
9937 		if (szret < 0) {
9938 			if (scf_error() != SCF_ERROR_DELETED)
9939 				scfdie();
9940 
9941 			goto snap_deleted;
9942 		}
9943 
9944 		(void) strcat(buf, "]svc:/");
9945 
9946 		cp = strchr(buf, '\0');
9947 
9948 		szret = scf_snaplevel_get_service_name(cur_level, cp,
9949 		    max_scf_name_len + 1);
9950 		if (szret < 0) {
9951 			if (scf_error() != SCF_ERROR_DELETED)
9952 				scfdie();
9953 
9954 			goto snap_deleted;
9955 		}
9956 
9957 		cp = strchr(cp, '\0');
9958 
9959 		if (snaplevel_is_instance(cur_level)) {
9960 			*cp++ = ':';
9961 
9962 			if (scf_snaplevel_get_instance_name(cur_level, cp,
9963 			    max_scf_name_len + 1) < 0) {
9964 				if (scf_error() != SCF_ERROR_DELETED)
9965 					scfdie();
9966 
9967 				goto snap_deleted;
9968 			}
9969 		} else {
9970 			*cp++ = '[';
9971 			*cp++ = ':';
9972 
9973 			if (scf_instance_get_name(cur_inst, cp,
9974 			    max_scf_name_len + 1) < 0) {
9975 				if (scf_error() != SCF_ERROR_DELETED)
9976 					scfdie();
9977 
9978 				goto snap_deleted;
9979 			}
9980 
9981 			(void) strcat(buf, "]");
9982 		}
9983 
9984 		return;
9985 
9986 snap_deleted:
9987 		deleted = B_TRUE;
9988 		free(buf);
9989 		unselect_cursnap();
9990 	}
9991 
9992 	assert(cur_snap == NULL);
9993 
9994 	if (cur_inst != NULL) {
9995 		assert(cur_svc != NULL);
9996 		assert(cur_scope != NULL);
9997 
9998 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
9999 		if (fmrilen >= 0) {
10000 			assert(fmrilen < bufsz);
10001 			if (deleted)
10002 				warn(emsg_deleted);
10003 			return;
10004 		}
10005 
10006 		if (scf_error() != SCF_ERROR_DELETED)
10007 			scfdie();
10008 
10009 		deleted = B_TRUE;
10010 
10011 		scf_instance_destroy(cur_inst);
10012 		cur_inst = NULL;
10013 	}
10014 
10015 	if (cur_svc != NULL) {
10016 		assert(cur_scope != NULL);
10017 
10018 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
10019 		if (szret >= 0) {
10020 			assert(szret < bufsz);
10021 			if (deleted)
10022 				warn(emsg_deleted);
10023 			return;
10024 		}
10025 
10026 		if (scf_error() != SCF_ERROR_DELETED)
10027 			scfdie();
10028 
10029 		deleted = B_TRUE;
10030 		scf_service_destroy(cur_svc);
10031 		cur_svc = NULL;
10032 	}
10033 
10034 	assert(cur_scope != NULL);
10035 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
10036 
10037 	if (fmrilen < 0)
10038 		scfdie();
10039 
10040 	assert(fmrilen < bufsz);
10041 	if (deleted)
10042 		warn(emsg_deleted);
10043 }
10044 
10045 /*
10046  * Entity listing.  Entities and colon namespaces (e.g., :properties and
10047  * :statistics) are listed for the current selection.
10048  */
10049 void
10050 lscf_list(const char *pattern)
10051 {
10052 	scf_iter_t *iter;
10053 	char *buf;
10054 	int ret;
10055 
10056 	lscf_prep_hndl();
10057 
10058 	if (cur_level != NULL) {
10059 		struct snaplevel *elt;
10060 
10061 		(void) fputs(COLON_NAMESPACES, stdout);
10062 
10063 		elt = uu_list_next(cur_levels, cur_elt);
10064 		if (elt == NULL)
10065 			return;
10066 
10067 		/*
10068 		 * For now, we know that the next level is an instance.  But
10069 		 * if we ever have multiple scopes, this could be complicated.
10070 		 */
10071 		buf = safe_malloc(max_scf_name_len + 1);
10072 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10073 		    max_scf_name_len + 1) >= 0) {
10074 			(void) puts(buf);
10075 		} else {
10076 			if (scf_error() != SCF_ERROR_DELETED)
10077 				scfdie();
10078 		}
10079 
10080 		free(buf);
10081 
10082 		return;
10083 	}
10084 
10085 	if (cur_inst != NULL) {
10086 		(void) fputs(COLON_NAMESPACES, stdout);
10087 		return;
10088 	}
10089 
10090 	iter = scf_iter_create(g_hndl);
10091 	if (iter == NULL)
10092 		scfdie();
10093 
10094 	buf = safe_malloc(max_scf_name_len + 1);
10095 
10096 	if (cur_svc != NULL) {
10097 		/* List the instances in this service. */
10098 		scf_instance_t *inst;
10099 
10100 		inst = scf_instance_create(g_hndl);
10101 		if (inst == NULL)
10102 			scfdie();
10103 
10104 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
10105 			safe_printf(COLON_NAMESPACES);
10106 
10107 			for (;;) {
10108 				ret = scf_iter_next_instance(iter, inst);
10109 				if (ret == 0)
10110 					break;
10111 				if (ret != 1) {
10112 					if (scf_error() != SCF_ERROR_DELETED)
10113 						scfdie();
10114 
10115 					break;
10116 				}
10117 
10118 				if (scf_instance_get_name(inst, buf,
10119 				    max_scf_name_len + 1) >= 0) {
10120 					if (pattern == NULL ||
10121 					    fnmatch(pattern, buf, 0) == 0)
10122 						(void) puts(buf);
10123 				} else {
10124 					if (scf_error() != SCF_ERROR_DELETED)
10125 						scfdie();
10126 				}
10127 			}
10128 		} else {
10129 			if (scf_error() != SCF_ERROR_DELETED)
10130 				scfdie();
10131 		}
10132 
10133 		scf_instance_destroy(inst);
10134 	} else {
10135 		/* List the services in this scope. */
10136 		scf_service_t *svc;
10137 
10138 		assert(cur_scope != NULL);
10139 
10140 		svc = scf_service_create(g_hndl);
10141 		if (svc == NULL)
10142 			scfdie();
10143 
10144 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
10145 			scfdie();
10146 
10147 		for (;;) {
10148 			ret = scf_iter_next_service(iter, svc);
10149 			if (ret == 0)
10150 				break;
10151 			if (ret != 1)
10152 				scfdie();
10153 
10154 			if (scf_service_get_name(svc, buf,
10155 			    max_scf_name_len + 1) >= 0) {
10156 				if (pattern == NULL ||
10157 				    fnmatch(pattern, buf, 0) == 0)
10158 					safe_printf("%s\n", buf);
10159 			} else {
10160 				if (scf_error() != SCF_ERROR_DELETED)
10161 					scfdie();
10162 			}
10163 		}
10164 
10165 		scf_service_destroy(svc);
10166 	}
10167 
10168 	free(buf);
10169 	scf_iter_destroy(iter);
10170 }
10171 
10172 /*
10173  * Entity addition.  Creates an empty entity in the current selection.
10174  */
10175 void
10176 lscf_add(const char *name)
10177 {
10178 	lscf_prep_hndl();
10179 
10180 	if (cur_snap != NULL) {
10181 		semerr(emsg_cant_modify_snapshots);
10182 	} else if (cur_inst != NULL) {
10183 		semerr(gettext("Cannot add entities to an instance.\n"));
10184 	} else if (cur_svc != NULL) {
10185 
10186 		if (scf_service_add_instance(cur_svc, name, NULL) !=
10187 		    SCF_SUCCESS) {
10188 			switch (scf_error()) {
10189 			case SCF_ERROR_INVALID_ARGUMENT:
10190 				semerr(gettext("Invalid name.\n"));
10191 				break;
10192 
10193 			case SCF_ERROR_EXISTS:
10194 				semerr(gettext("Instance already exists.\n"));
10195 				break;
10196 
10197 			case SCF_ERROR_PERMISSION_DENIED:
10198 				semerr(emsg_permission_denied);
10199 				break;
10200 
10201 			default:
10202 				scfdie();
10203 			}
10204 		}
10205 	} else {
10206 		assert(cur_scope != NULL);
10207 
10208 		if (scf_scope_add_service(cur_scope, name, NULL) !=
10209 		    SCF_SUCCESS) {
10210 			switch (scf_error()) {
10211 			case SCF_ERROR_INVALID_ARGUMENT:
10212 				semerr(gettext("Invalid name.\n"));
10213 				break;
10214 
10215 			case SCF_ERROR_EXISTS:
10216 				semerr(gettext("Service already exists.\n"));
10217 				break;
10218 
10219 			case SCF_ERROR_PERMISSION_DENIED:
10220 				semerr(emsg_permission_denied);
10221 				break;
10222 
10223 			case SCF_ERROR_BACKEND_READONLY:
10224 				semerr(emsg_read_only);
10225 				break;
10226 
10227 			default:
10228 				scfdie();
10229 			}
10230 		}
10231 	}
10232 }
10233 
10234 /* return 1 if the entity has no persistent pgs, else return 0 */
10235 static int
10236 entity_has_no_pgs(void *ent, int isservice)
10237 {
10238 	scf_iter_t *iter = NULL;
10239 	scf_propertygroup_t *pg = NULL;
10240 	uint32_t flags;
10241 	int err;
10242 	int ret = 1;
10243 
10244 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10245 	    (pg = scf_pg_create(g_hndl)) == NULL)
10246 		scfdie();
10247 
10248 	if (isservice) {
10249 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
10250 			scfdie();
10251 	} else {
10252 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
10253 			scfdie();
10254 	}
10255 
10256 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10257 		if (scf_pg_get_flags(pg, &flags) != 0)
10258 			scfdie();
10259 
10260 		/* skip nonpersistent pgs */
10261 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
10262 			continue;
10263 
10264 		ret = 0;
10265 		break;
10266 	}
10267 
10268 	if (err == -1)
10269 		scfdie();
10270 
10271 	scf_pg_destroy(pg);
10272 	scf_iter_destroy(iter);
10273 
10274 	return (ret);
10275 }
10276 
10277 /* return 1 if the service has no instances, else return 0 */
10278 static int
10279 svc_has_no_insts(scf_service_t *svc)
10280 {
10281 	scf_instance_t *inst;
10282 	scf_iter_t *iter;
10283 	int r;
10284 	int ret = 1;
10285 
10286 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10287 	    (iter = scf_iter_create(g_hndl)) == NULL)
10288 		scfdie();
10289 
10290 	if (scf_iter_service_instances(iter, svc) != 0)
10291 		scfdie();
10292 
10293 	r = scf_iter_next_instance(iter, inst);
10294 	if (r == 1) {
10295 		ret = 0;
10296 	} else if (r == 0) {
10297 		ret = 1;
10298 	} else if (r == -1) {
10299 		scfdie();
10300 	} else {
10301 		bad_error("scf_iter_next_instance", r);
10302 	}
10303 
10304 	scf_iter_destroy(iter);
10305 	scf_instance_destroy(inst);
10306 
10307 	return (ret);
10308 }
10309 
10310 /*
10311  * Entity deletion.
10312  */
10313 
10314 /*
10315  * Delete the property group <fmri>/:properties/<name>.  Returns
10316  * SCF_ERROR_NONE on success (or if the entity is not found),
10317  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
10318  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
10319  * denied.
10320  */
10321 static scf_error_t
10322 delete_dependency_pg(const char *fmri, const char *name)
10323 {
10324 	void *entity = NULL;
10325 	int isservice;
10326 	scf_propertygroup_t *pg = NULL;
10327 	scf_error_t result;
10328 	char *pgty;
10329 	scf_service_t *svc = NULL;
10330 	scf_instance_t *inst = NULL;
10331 	scf_iter_t *iter = NULL;
10332 	char *name_buf = NULL;
10333 
10334 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10335 	switch (result) {
10336 	case SCF_ERROR_NONE:
10337 		break;
10338 
10339 	case SCF_ERROR_NO_MEMORY:
10340 		uu_die(gettext("Out of memory.\n"));
10341 		/* NOTREACHED */
10342 
10343 	case SCF_ERROR_INVALID_ARGUMENT:
10344 	case SCF_ERROR_CONSTRAINT_VIOLATED:
10345 		return (SCF_ERROR_INVALID_ARGUMENT);
10346 
10347 	case SCF_ERROR_NOT_FOUND:
10348 		result = SCF_ERROR_NONE;
10349 		goto out;
10350 
10351 	default:
10352 		bad_error("fmri_to_entity", result);
10353 	}
10354 
10355 	pg = scf_pg_create(g_hndl);
10356 	if (pg == NULL)
10357 		scfdie();
10358 
10359 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
10360 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10361 			scfdie();
10362 
10363 		result = SCF_ERROR_NONE;
10364 		goto out;
10365 	}
10366 
10367 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10368 
10369 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10370 		scfdie();
10371 
10372 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
10373 		result = SCF_ERROR_TYPE_MISMATCH;
10374 		free(pgty);
10375 		goto out;
10376 	}
10377 
10378 	free(pgty);
10379 
10380 	if (scf_pg_delete(pg) != 0) {
10381 		result = scf_error();
10382 		if (result != SCF_ERROR_PERMISSION_DENIED)
10383 			scfdie();
10384 		goto out;
10385 	}
10386 
10387 	/*
10388 	 * We have to handle the case where we've just deleted the last
10389 	 * property group of a "dummy" entity (instance or service).
10390 	 * A "dummy" entity is an entity only present to hold an
10391 	 * external dependency.
10392 	 * So, in the case we deleted the last property group then we
10393 	 * can also delete the entity. If the entity is an instance then
10394 	 * we must verify if this was the last instance for the service
10395 	 * and if it is, we can also delete the service if it doesn't
10396 	 * have any property group either.
10397 	 */
10398 
10399 	result = SCF_ERROR_NONE;
10400 
10401 	if (isservice) {
10402 		svc = (scf_service_t *)entity;
10403 
10404 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
10405 		    (iter = scf_iter_create(g_hndl)) == NULL)
10406 			scfdie();
10407 
10408 		name_buf = safe_malloc(max_scf_name_len + 1);
10409 	} else {
10410 		inst = (scf_instance_t *)entity;
10411 	}
10412 
10413 	/*
10414 	 * If the entity is an instance and we've just deleted its last
10415 	 * property group then we should delete it.
10416 	 */
10417 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
10418 		/* find the service before deleting the inst. - needed later */
10419 		if ((svc = scf_service_create(g_hndl)) == NULL)
10420 			scfdie();
10421 
10422 		if (scf_instance_get_parent(inst, svc) != 0)
10423 			scfdie();
10424 
10425 		/* delete the instance */
10426 		if (scf_instance_delete(inst) != 0) {
10427 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10428 				scfdie();
10429 
10430 			result = SCF_ERROR_PERMISSION_DENIED;
10431 			goto out;
10432 		}
10433 		/* no need to refresh the instance */
10434 		inst = NULL;
10435 	}
10436 
10437 	/*
10438 	 * If the service has no more instances and pgs or we just deleted the
10439 	 * last instance and the service doesn't have anymore propery groups
10440 	 * then the service should be deleted.
10441 	 */
10442 	if (svc != NULL &&
10443 	    svc_has_no_insts(svc) &&
10444 	    entity_has_no_pgs((void *)svc, 1)) {
10445 		if (scf_service_delete(svc) == 0) {
10446 			if (isservice) {
10447 				/* no need to refresh the service */
10448 				svc = NULL;
10449 			}
10450 
10451 			goto out;
10452 		}
10453 
10454 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10455 			scfdie();
10456 
10457 		result = SCF_ERROR_PERMISSION_DENIED;
10458 	}
10459 
10460 	/* if the entity has not been deleted, refresh it */
10461 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
10462 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
10463 		    name_buf);
10464 	}
10465 
10466 out:
10467 	if (isservice && (inst != NULL && iter != NULL)) {
10468 		free(name_buf);
10469 		scf_iter_destroy(iter);
10470 		scf_instance_destroy(inst);
10471 	}
10472 
10473 	if (!isservice && svc != NULL) {
10474 		scf_service_destroy(svc);
10475 	}
10476 
10477 	scf_pg_destroy(pg);
10478 	if (entity != NULL)
10479 		entity_destroy(entity, isservice);
10480 
10481 	return (result);
10482 }
10483 
10484 static int
10485 delete_dependents(scf_propertygroup_t *pg)
10486 {
10487 	char *pgty, *name, *fmri;
10488 	scf_property_t *prop;
10489 	scf_value_t *val;
10490 	scf_iter_t *iter;
10491 	int r;
10492 	scf_error_t err;
10493 
10494 	/* Verify that the pg has the correct type. */
10495 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10496 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10497 		scfdie();
10498 
10499 	if (strcmp(pgty, scf_group_framework) != 0) {
10500 		if (g_verbose) {
10501 			fmri = safe_malloc(max_scf_fmri_len + 1);
10502 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
10503 				scfdie();
10504 
10505 			warn(gettext("Property group %s is not of expected "
10506 			    "type %s.\n"), fmri, scf_group_framework);
10507 
10508 			free(fmri);
10509 		}
10510 
10511 		free(pgty);
10512 		return (-1);
10513 	}
10514 
10515 	free(pgty);
10516 
10517 	/* map delete_dependency_pg onto the properties. */
10518 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10519 	    (val = scf_value_create(g_hndl)) == NULL ||
10520 	    (iter = scf_iter_create(g_hndl)) == NULL)
10521 		scfdie();
10522 
10523 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10524 		scfdie();
10525 
10526 	name = safe_malloc(max_scf_name_len + 1);
10527 	fmri = safe_malloc(max_scf_fmri_len + 2);
10528 
10529 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
10530 		scf_type_t ty;
10531 
10532 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
10533 			scfdie();
10534 
10535 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
10536 			scfdie();
10537 
10538 		if ((ty != SCF_TYPE_ASTRING &&
10539 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
10540 		    prop_get_val(prop, val) != 0)
10541 			continue;
10542 
10543 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
10544 			scfdie();
10545 
10546 		err = delete_dependency_pg(fmri, name);
10547 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
10548 			if (scf_property_to_fmri(prop, fmri,
10549 			    max_scf_fmri_len + 2) < 0)
10550 				scfdie();
10551 
10552 			warn(gettext("Value of %s is not a valid FMRI.\n"),
10553 			    fmri);
10554 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
10555 			warn(gettext("Property group \"%s\" of entity \"%s\" "
10556 			    "does not have dependency type.\n"), name, fmri);
10557 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
10558 			warn(gettext("Could not delete property group \"%s\" "
10559 			    "of entity \"%s\" (permission denied).\n"), name,
10560 			    fmri);
10561 		}
10562 	}
10563 	if (r == -1)
10564 		scfdie();
10565 
10566 	scf_value_destroy(val);
10567 	scf_property_destroy(prop);
10568 
10569 	return (0);
10570 }
10571 
10572 /*
10573  * Returns 1 if the instance may be running, and 0 otherwise.
10574  */
10575 static int
10576 inst_is_running(scf_instance_t *inst)
10577 {
10578 	scf_propertygroup_t *pg;
10579 	scf_property_t *prop;
10580 	scf_value_t *val;
10581 	char buf[MAX_SCF_STATE_STRING_SZ];
10582 	int ret = 0;
10583 	ssize_t szret;
10584 
10585 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10586 	    (prop = scf_property_create(g_hndl)) == NULL ||
10587 	    (val = scf_value_create(g_hndl)) == NULL)
10588 		scfdie();
10589 
10590 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
10591 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10592 			scfdie();
10593 		goto out;
10594 	}
10595 
10596 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
10597 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
10598 	    prop_get_val(prop, val) != 0)
10599 		goto out;
10600 
10601 	szret = scf_value_get_astring(val, buf, sizeof (buf));
10602 	assert(szret >= 0);
10603 
10604 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
10605 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
10606 
10607 out:
10608 	scf_value_destroy(val);
10609 	scf_property_destroy(prop);
10610 	scf_pg_destroy(pg);
10611 	return (ret);
10612 }
10613 
10614 static uint8_t
10615 pg_is_external_dependency(scf_propertygroup_t *pg)
10616 {
10617 	char *type;
10618 	scf_value_t *val;
10619 	scf_property_t *prop;
10620 	uint8_t b = B_FALSE;
10621 
10622 	type = safe_malloc(max_scf_pg_type_len + 1);
10623 
10624 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
10625 		scfdie();
10626 
10627 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10628 	    (val = scf_value_create(g_hndl)) == NULL)
10629 		scfdie();
10630 
10631 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
10632 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
10633 			if (scf_property_get_value(prop, val) != 0)
10634 				scfdie();
10635 			if (scf_value_get_boolean(val, &b) != 0)
10636 				scfdie();
10637 		}
10638 	}
10639 
10640 	free(type);
10641 	(void) scf_value_destroy(val);
10642 	(void) scf_property_destroy(prop);
10643 
10644 	return (b);
10645 }
10646 
10647 #define	DELETE_FAILURE			-1
10648 #define	DELETE_SUCCESS_NOEXTDEPS	0
10649 #define	DELETE_SUCCESS_EXTDEPS		1
10650 
10651 /*
10652  * lscf_instance_delete() deletes an instance.  Before calling
10653  * scf_instance_delete(), though, we make sure the instance isn't
10654  * running and delete dependencies in other entities which the instance
10655  * declared as "dependents".  If there are dependencies which were
10656  * created for other entities, then instead of deleting the instance we
10657  * make it "empty" by deleting all other property groups and all
10658  * snapshots.
10659  *
10660  * lscf_instance_delete() verifies that there is no external dependency pgs
10661  * before suppressing the instance. If there is, then we must not remove them
10662  * now in case the instance is re-created otherwise the dependencies would be
10663  * lost. The external dependency pgs will be removed if the dependencies are
10664  * removed.
10665  *
10666  * Returns:
10667  *  DELETE_FAILURE		on failure
10668  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
10669  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
10670  */
10671 static int
10672 lscf_instance_delete(scf_instance_t *inst, int force)
10673 {
10674 	scf_propertygroup_t *pg;
10675 	scf_snapshot_t *snap;
10676 	scf_iter_t *iter;
10677 	int err;
10678 	int external = 0;
10679 
10680 	/* If we're not forcing and the instance is running, refuse. */
10681 	if (!force && inst_is_running(inst)) {
10682 		char *fmri;
10683 
10684 		fmri = safe_malloc(max_scf_fmri_len + 1);
10685 
10686 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
10687 			scfdie();
10688 
10689 		semerr(gettext("Instance %s may be running.  "
10690 		    "Use delete -f if it is not.\n"), fmri);
10691 
10692 		free(fmri);
10693 		return (DELETE_FAILURE);
10694 	}
10695 
10696 	pg = scf_pg_create(g_hndl);
10697 	if (pg == NULL)
10698 		scfdie();
10699 
10700 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
10701 		(void) delete_dependents(pg);
10702 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
10703 		scfdie();
10704 
10705 	scf_pg_destroy(pg);
10706 
10707 	/*
10708 	 * If the instance has some external dependencies then we must
10709 	 * keep them in case the instance is reimported otherwise the
10710 	 * dependencies would be lost on reimport.
10711 	 */
10712 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10713 	    (pg = scf_pg_create(g_hndl)) == NULL)
10714 		scfdie();
10715 
10716 	if (scf_iter_instance_pgs(iter, inst) < 0)
10717 		scfdie();
10718 
10719 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10720 		if (pg_is_external_dependency(pg)) {
10721 			external = 1;
10722 			continue;
10723 		}
10724 
10725 		if (scf_pg_delete(pg) != 0) {
10726 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10727 				scfdie();
10728 			else {
10729 				semerr(emsg_permission_denied);
10730 
10731 				(void) scf_iter_destroy(iter);
10732 				(void) scf_pg_destroy(pg);
10733 				return (DELETE_FAILURE);
10734 			}
10735 		}
10736 	}
10737 
10738 	if (err == -1)
10739 		scfdie();
10740 
10741 	(void) scf_iter_destroy(iter);
10742 	(void) scf_pg_destroy(pg);
10743 
10744 	if (external) {
10745 		/*
10746 		 * All the pgs have been deleted for the instance except
10747 		 * the ones holding the external dependencies.
10748 		 * For the job to be complete, we must also delete the
10749 		 * snapshots associated with the instance.
10750 		 */
10751 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
10752 		    NULL)
10753 			scfdie();
10754 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
10755 			scfdie();
10756 
10757 		if (scf_iter_instance_snapshots(iter, inst) == -1)
10758 			scfdie();
10759 
10760 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
10761 			if (_scf_snapshot_delete(snap) != 0) {
10762 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10763 					scfdie();
10764 
10765 				semerr(emsg_permission_denied);
10766 
10767 				(void) scf_iter_destroy(iter);
10768 				(void) scf_snapshot_destroy(snap);
10769 				return (DELETE_FAILURE);
10770 			}
10771 		}
10772 
10773 		if (err == -1)
10774 			scfdie();
10775 
10776 		(void) scf_iter_destroy(iter);
10777 		(void) scf_snapshot_destroy(snap);
10778 		return (DELETE_SUCCESS_EXTDEPS);
10779 	}
10780 
10781 	if (scf_instance_delete(inst) != 0) {
10782 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10783 			scfdie();
10784 
10785 		semerr(emsg_permission_denied);
10786 
10787 		return (DELETE_FAILURE);
10788 	}
10789 
10790 	return (DELETE_SUCCESS_NOEXTDEPS);
10791 }
10792 
10793 /*
10794  * lscf_service_delete() deletes a service.  Before calling
10795  * scf_service_delete(), though, we call lscf_instance_delete() for
10796  * each of the instances and delete dependencies in other entities
10797  * which were created as "dependents" of this service.  If there are
10798  * dependencies which were created for other entities, then we delete
10799  * all other property groups in the service and leave it as "empty".
10800  *
10801  * lscf_service_delete() verifies that there is no external dependency
10802  * pgs at the instance & service level before suppressing the service.
10803  * If there is, then we must not remove them now in case the service
10804  * is re-imported otherwise the dependencies would be lost. The external
10805  * dependency pgs will be removed if the dependencies are removed.
10806  *
10807  * Returns:
10808  *   DELETE_FAILURE		on failure
10809  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
10810  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
10811  */
10812 static int
10813 lscf_service_delete(scf_service_t *svc, int force)
10814 {
10815 	int r;
10816 	scf_instance_t *inst;
10817 	scf_propertygroup_t *pg;
10818 	scf_iter_t *iter;
10819 	int ret;
10820 	int external = 0;
10821 
10822 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10823 	    (pg = scf_pg_create(g_hndl)) == NULL ||
10824 	    (iter = scf_iter_create(g_hndl)) == NULL)
10825 		scfdie();
10826 
10827 	if (scf_iter_service_instances(iter, svc) != 0)
10828 		scfdie();
10829 
10830 	for (r = scf_iter_next_instance(iter, inst);
10831 	    r == 1;
10832 	    r = scf_iter_next_instance(iter, inst)) {
10833 
10834 		ret = lscf_instance_delete(inst, force);
10835 		if (ret == DELETE_FAILURE) {
10836 			scf_iter_destroy(iter);
10837 			scf_pg_destroy(pg);
10838 			scf_instance_destroy(inst);
10839 			return (DELETE_FAILURE);
10840 		}
10841 
10842 		/*
10843 		 * Record the fact that there is some external dependencies
10844 		 * at the instance level.
10845 		 */
10846 		if (ret == DELETE_SUCCESS_EXTDEPS)
10847 			external |= 1;
10848 	}
10849 
10850 	if (r != 0)
10851 		scfdie();
10852 
10853 	/* Delete dependency property groups in dependent services. */
10854 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
10855 		(void) delete_dependents(pg);
10856 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
10857 		scfdie();
10858 
10859 	scf_iter_destroy(iter);
10860 	scf_pg_destroy(pg);
10861 	scf_instance_destroy(inst);
10862 
10863 	/*
10864 	 * If the service has some external dependencies then we don't
10865 	 * want to remove them in case the service is re-imported.
10866 	 */
10867 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10868 	    (iter = scf_iter_create(g_hndl)) == NULL)
10869 		scfdie();
10870 
10871 	if (scf_iter_service_pgs(iter, svc) < 0)
10872 		scfdie();
10873 
10874 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
10875 		if (pg_is_external_dependency(pg)) {
10876 			external |= 2;
10877 			continue;
10878 		}
10879 
10880 		if (scf_pg_delete(pg) != 0) {
10881 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10882 				scfdie();
10883 			else {
10884 				semerr(emsg_permission_denied);
10885 
10886 				(void) scf_iter_destroy(iter);
10887 				(void) scf_pg_destroy(pg);
10888 				return (DELETE_FAILURE);
10889 			}
10890 		}
10891 	}
10892 
10893 	if (r == -1)
10894 		scfdie();
10895 
10896 	(void) scf_iter_destroy(iter);
10897 	(void) scf_pg_destroy(pg);
10898 
10899 	if (external != 0)
10900 		return (DELETE_SUCCESS_EXTDEPS);
10901 
10902 	if (scf_service_delete(svc) == 0)
10903 		return (DELETE_SUCCESS_NOEXTDEPS);
10904 
10905 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10906 		scfdie();
10907 
10908 	semerr(emsg_permission_denied);
10909 	return (DELETE_FAILURE);
10910 }
10911 
10912 static int
10913 delete_callback(void *data, scf_walkinfo_t *wip)
10914 {
10915 	int force = (int)data;
10916 
10917 	if (wip->inst != NULL)
10918 		(void) lscf_instance_delete(wip->inst, force);
10919 	else
10920 		(void) lscf_service_delete(wip->svc, force);
10921 
10922 	return (0);
10923 }
10924 
10925 void
10926 lscf_delete(const char *fmri, int force)
10927 {
10928 	scf_service_t *svc;
10929 	scf_instance_t *inst;
10930 	int ret;
10931 
10932 	lscf_prep_hndl();
10933 
10934 	if (cur_snap != NULL) {
10935 		if (!snaplevel_is_instance(cur_level)) {
10936 			char *buf;
10937 
10938 			buf = safe_malloc(max_scf_name_len + 1);
10939 			if (scf_instance_get_name(cur_inst, buf,
10940 			    max_scf_name_len + 1) >= 0) {
10941 				if (strcmp(buf, fmri) == 0) {
10942 					semerr(emsg_cant_modify_snapshots);
10943 					free(buf);
10944 					return;
10945 				}
10946 			} else if (scf_error() != SCF_ERROR_DELETED) {
10947 				scfdie();
10948 			}
10949 			free(buf);
10950 		}
10951 	} else if (cur_inst != NULL) {
10952 		/* EMPTY */;
10953 	} else if (cur_svc != NULL) {
10954 		inst = scf_instance_create(g_hndl);
10955 		if (inst == NULL)
10956 			scfdie();
10957 
10958 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
10959 		    SCF_SUCCESS) {
10960 			(void) lscf_instance_delete(inst, force);
10961 			scf_instance_destroy(inst);
10962 			return;
10963 		}
10964 
10965 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
10966 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
10967 			scfdie();
10968 
10969 		scf_instance_destroy(inst);
10970 	} else {
10971 		assert(cur_scope != NULL);
10972 
10973 		svc = scf_service_create(g_hndl);
10974 		if (svc == NULL)
10975 			scfdie();
10976 
10977 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
10978 		    SCF_SUCCESS) {
10979 			(void) lscf_service_delete(svc, force);
10980 			scf_service_destroy(svc);
10981 			return;
10982 		}
10983 
10984 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
10985 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
10986 			scfdie();
10987 
10988 		scf_service_destroy(svc);
10989 	}
10990 
10991 	/*
10992 	 * Match FMRI to entity.
10993 	 */
10994 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
10995 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
10996 		semerr(gettext("Failed to walk instances: %s\n"),
10997 		    scf_strerror(ret));
10998 	}
10999 }
11000 
11001 
11002 
11003 /*
11004  * :properties commands.  These all end with "pg" or "prop" and generally
11005  * operate on the currently selected entity.
11006  */
11007 
11008 /*
11009  * Property listing.  List the property groups, properties, their types and
11010  * their values for the currently selected entity.
11011  */
11012 static void
11013 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
11014 {
11015 	char *buf;
11016 	uint32_t flags;
11017 
11018 	buf = safe_malloc(max_scf_pg_type_len + 1);
11019 
11020 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
11021 		scfdie();
11022 
11023 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
11024 		scfdie();
11025 
11026 	safe_printf("%-*s  %s", namewidth, name, buf);
11027 
11028 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
11029 		safe_printf("\tNONPERSISTENT");
11030 
11031 	safe_printf("\n");
11032 
11033 	free(buf);
11034 }
11035 
11036 static boolean_t
11037 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
11038 {
11039 	if (scf_property_get_value(prop, val) == 0) {
11040 		return (B_FALSE);
11041 	} else {
11042 		switch (scf_error()) {
11043 		case SCF_ERROR_NOT_FOUND:
11044 			return (B_FALSE);
11045 		case SCF_ERROR_PERMISSION_DENIED:
11046 		case SCF_ERROR_CONSTRAINT_VIOLATED:
11047 			return (B_TRUE);
11048 		default:
11049 			scfdie();
11050 			/*NOTREACHED*/
11051 		}
11052 	}
11053 }
11054 
11055 static void
11056 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
11057 {
11058 	scf_iter_t *iter;
11059 	scf_value_t *val;
11060 	const char *type;
11061 	int multiple_strings = 0;
11062 	int ret;
11063 
11064 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11065 	    (val = scf_value_create(g_hndl)) == NULL)
11066 		scfdie();
11067 
11068 	type = prop_to_typestr(prop);
11069 	assert(type != NULL);
11070 
11071 	safe_printf("%-*s  %-7s ", len, name, type);
11072 
11073 	if (prop_has_multiple_values(prop, val) &&
11074 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
11075 	    scf_value_type(val) == SCF_TYPE_USTRING))
11076 		multiple_strings = 1;
11077 
11078 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11079 		scfdie();
11080 
11081 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11082 		char *buf;
11083 		ssize_t vlen, szret;
11084 
11085 		vlen = scf_value_get_as_string(val, NULL, 0);
11086 		if (vlen < 0)
11087 			scfdie();
11088 
11089 		buf = safe_malloc(vlen + 1);
11090 
11091 		szret = scf_value_get_as_string(val, buf, vlen + 1);
11092 		if (szret < 0)
11093 			scfdie();
11094 		assert(szret <= vlen);
11095 
11096 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11097 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
11098 			safe_printf(" \"");
11099 			(void) quote_and_print(buf, stdout, 0);
11100 			(void) putchar('"');
11101 			if (ferror(stdout)) {
11102 				(void) putchar('\n');
11103 				uu_die(gettext("Error writing to stdout.\n"));
11104 			}
11105 		} else {
11106 			safe_printf(" %s", buf);
11107 		}
11108 
11109 		free(buf);
11110 	}
11111 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11112 		scfdie();
11113 
11114 	if (putchar('\n') != '\n')
11115 		uu_die(gettext("Could not output newline"));
11116 }
11117 
11118 /*
11119  * Outputs template property group info for the describe subcommand.
11120  * If 'templates' == 2, verbose output is printed in the format expected
11121  * for describe -v, which includes all templates fields.  If pg is
11122  * not NULL, we're describing the template data, not an existing property
11123  * group, and formatting should be appropriate for describe -t.
11124  */
11125 static void
11126 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
11127 {
11128 	char *buf;
11129 	uint8_t required;
11130 	scf_property_t *stability_prop;
11131 	scf_value_t *stability_val;
11132 
11133 	if (templates == 0)
11134 		return;
11135 
11136 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
11137 	    (stability_val = scf_value_create(g_hndl)) == NULL)
11138 		scfdie();
11139 
11140 	if (templates == 2 && pg != NULL) {
11141 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
11142 		    stability_prop) == 0) {
11143 			if (prop_check_type(stability_prop,
11144 			    SCF_TYPE_ASTRING) == 0 &&
11145 			    prop_get_val(stability_prop, stability_val) == 0) {
11146 				char *stability;
11147 
11148 				stability = safe_malloc(max_scf_value_len + 1);
11149 
11150 				if (scf_value_get_astring(stability_val,
11151 				    stability, max_scf_value_len + 1) == -1 &&
11152 				    scf_error() != SCF_ERROR_NOT_FOUND)
11153 					scfdie();
11154 
11155 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11156 				    gettext("stability"), stability);
11157 
11158 				free(stability);
11159 			}
11160 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
11161 			scfdie();
11162 	}
11163 
11164 	scf_property_destroy(stability_prop);
11165 	scf_value_destroy(stability_val);
11166 
11167 	if (pgt == NULL)
11168 		return;
11169 
11170 	if (pg == NULL || templates == 2) {
11171 		/* print type info only if scf_tmpl_pg_name succeeds */
11172 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
11173 			if (pg != NULL)
11174 				safe_printf("%s", TMPL_INDENT);
11175 			safe_printf("%s: ", gettext("name"));
11176 			safe_printf("%s\n", buf);
11177 			free(buf);
11178 		}
11179 
11180 		/* print type info only if scf_tmpl_pg_type succeeds */
11181 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
11182 			if (pg != NULL)
11183 				safe_printf("%s", TMPL_INDENT);
11184 			safe_printf("%s: ", gettext("type"));
11185 			safe_printf("%s\n", buf);
11186 			free(buf);
11187 		}
11188 	}
11189 
11190 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
11191 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11192 		    required ? "true" : "false");
11193 
11194 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
11195 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
11196 		    buf);
11197 		free(buf);
11198 	}
11199 
11200 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
11201 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11202 		    buf);
11203 		free(buf);
11204 	}
11205 
11206 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
11207 		if (templates == 2)
11208 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11209 			    gettext("description"), buf);
11210 		else
11211 			safe_printf("%s%s\n", TMPL_INDENT, buf);
11212 		free(buf);
11213 	}
11214 
11215 }
11216 
11217 /*
11218  * With as_value set to true, indent as appropriate for the value level.
11219  * If false, indent to appropriate level for inclusion in constraint
11220  * or choice printout.
11221  */
11222 static void
11223 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
11224     int as_value)
11225 {
11226 	char *buf;
11227 
11228 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
11229 		if (as_value == 0)
11230 			safe_printf("%s", TMPL_CHOICE_INDENT);
11231 		else
11232 			safe_printf("%s", TMPL_INDENT);
11233 		safe_printf("%s: %s\n", gettext("value common name"), buf);
11234 		free(buf);
11235 	}
11236 
11237 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
11238 		if (as_value == 0)
11239 			safe_printf("%s", TMPL_CHOICE_INDENT);
11240 		else
11241 			safe_printf("%s", TMPL_INDENT);
11242 		safe_printf("%s: %s\n", gettext("value description"), buf);
11243 		free(buf);
11244 	}
11245 }
11246 
11247 static void
11248 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
11249 {
11250 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
11251 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11252 	safe_printf("%s\n", val_buf);
11253 
11254 	print_template_value_details(prt, val_buf, 1);
11255 }
11256 
11257 static void
11258 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
11259 {
11260 	int i, printed = 0;
11261 	scf_values_t values;
11262 	scf_count_ranges_t c_ranges;
11263 	scf_int_ranges_t i_ranges;
11264 
11265 	printed = 0;
11266 	i = 0;
11267 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
11268 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11269 		    gettext("value constraints"));
11270 		printed++;
11271 		for (i = 0; i < values.value_count; ++i) {
11272 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11273 			    gettext("value name"), values.values_as_strings[i]);
11274 			if (verbose == 1)
11275 				print_template_value_details(prt,
11276 				    values.values_as_strings[i], 0);
11277 		}
11278 
11279 		scf_values_destroy(&values);
11280 	}
11281 
11282 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
11283 		if (printed++ == 0)
11284 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11285 			    gettext("value constraints"));
11286 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11287 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11288 			    gettext("range"), c_ranges.scr_min[i],
11289 			    c_ranges.scr_max[i]);
11290 		}
11291 		scf_count_ranges_destroy(&c_ranges);
11292 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11293 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
11294 		if (printed++ == 0)
11295 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11296 			    gettext("value constraints"));
11297 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11298 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11299 			    gettext("range"), i_ranges.sir_min[i],
11300 			    i_ranges.sir_max[i]);
11301 		}
11302 		scf_int_ranges_destroy(&i_ranges);
11303 	}
11304 }
11305 
11306 static void
11307 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
11308 {
11309 	int i = 0, printed = 0;
11310 	scf_values_t values;
11311 	scf_count_ranges_t c_ranges;
11312 	scf_int_ranges_t i_ranges;
11313 
11314 	printed = 0;
11315 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
11316 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11317 		    gettext("value constraints"));
11318 		printed++;
11319 		for (i = 0; i < values.value_count; i++) {
11320 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11321 			    gettext("value name"), values.values_as_strings[i]);
11322 			if (verbose == 1)
11323 				print_template_value_details(prt,
11324 				    values.values_as_strings[i], 0);
11325 		}
11326 
11327 		scf_values_destroy(&values);
11328 	}
11329 
11330 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
11331 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11332 			if (printed++ == 0)
11333 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11334 				    gettext("value choices"));
11335 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11336 			    gettext("range"), c_ranges.scr_min[i],
11337 			    c_ranges.scr_max[i]);
11338 		}
11339 		scf_count_ranges_destroy(&c_ranges);
11340 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11341 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
11342 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11343 			if (printed++ == 0)
11344 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11345 				    gettext("value choices"));
11346 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11347 			    gettext("range"), i_ranges.sir_min[i],
11348 			    i_ranges.sir_max[i]);
11349 		}
11350 		scf_int_ranges_destroy(&i_ranges);
11351 	}
11352 }
11353 
11354 static void
11355 list_values_by_template(scf_prop_tmpl_t *prt)
11356 {
11357 	print_template_constraints(prt, 1);
11358 	print_template_choices(prt, 1);
11359 }
11360 
11361 static void
11362 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
11363 {
11364 	char *val_buf;
11365 	scf_iter_t *iter;
11366 	scf_value_t *val;
11367 	int ret;
11368 
11369 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11370 	    (val = scf_value_create(g_hndl)) == NULL)
11371 		scfdie();
11372 
11373 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11374 		scfdie();
11375 
11376 	val_buf = safe_malloc(max_scf_value_len + 1);
11377 
11378 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11379 		if (scf_value_get_as_string(val, val_buf,
11380 		    max_scf_value_len + 1) < 0)
11381 			scfdie();
11382 
11383 		print_template_value(prt, val_buf);
11384 	}
11385 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11386 		scfdie();
11387 	free(val_buf);
11388 
11389 	print_template_constraints(prt, 0);
11390 	print_template_choices(prt, 0);
11391 
11392 }
11393 
11394 /*
11395  * Outputs property info for the describe subcommand
11396  * Verbose output if templates == 2, -v option of svccfg describe
11397  * Displays template data if prop is not NULL, -t option of svccfg describe
11398  */
11399 static void
11400 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
11401 {
11402 	char *buf;
11403 	uint8_t u_buf;
11404 	int i;
11405 	uint64_t min, max;
11406 	scf_values_t values;
11407 
11408 	if (prt == NULL || templates == 0)
11409 		return;
11410 
11411 	if (prop == NULL) {
11412 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
11413 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
11414 			safe_printf("%s\n", buf);
11415 			free(buf);
11416 		} else
11417 			safe_printf("(%s)\n", gettext("any"));
11418 	}
11419 
11420 	if (prop == NULL || templates == 2) {
11421 		if (prop != NULL)
11422 			safe_printf("%s", TMPL_INDENT);
11423 		else
11424 			safe_printf("%s", TMPL_VALUE_INDENT);
11425 		safe_printf("%s: ", gettext("type"));
11426 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
11427 			safe_printf("%s\n", buf);
11428 			free(buf);
11429 		} else
11430 			safe_printf("(%s)\n", gettext("any"));
11431 	}
11432 
11433 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
11434 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11435 		    u_buf ? "true" : "false");
11436 
11437 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
11438 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11439 		    buf);
11440 		free(buf);
11441 	}
11442 
11443 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
11444 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
11445 		    buf);
11446 		free(buf);
11447 	}
11448 
11449 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
11450 		safe_printf("%s%s\n", TMPL_INDENT, buf);
11451 		free(buf);
11452 	}
11453 
11454 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
11455 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
11456 		    scf_tmpl_visibility_to_string(u_buf));
11457 
11458 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
11459 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11460 		    gettext("minimum number of values"), min);
11461 		if (max == ULLONG_MAX) {
11462 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11463 			    gettext("maximum number of values"),
11464 			    gettext("unlimited"));
11465 		} else {
11466 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11467 			    gettext("maximum number of values"), max);
11468 		}
11469 	}
11470 
11471 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
11472 		for (i = 0; i < values.value_count; i++) {
11473 			if (i == 0) {
11474 				safe_printf("%s%s:", TMPL_INDENT,
11475 				    gettext("internal separators"));
11476 			}
11477 			safe_printf(" \"%s\"", values.values_as_strings[i]);
11478 		}
11479 		safe_printf("\n");
11480 	}
11481 
11482 	if (templates != 2)
11483 		return;
11484 
11485 	if (prop != NULL)
11486 		list_values_tmpl(prt, prop);
11487 	else
11488 		list_values_by_template(prt);
11489 }
11490 
11491 static char *
11492 read_astring(scf_propertygroup_t *pg, const char *prop_name)
11493 {
11494 	char *rv;
11495 
11496 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
11497 	if (rv == NULL) {
11498 		switch (scf_error()) {
11499 		case SCF_ERROR_NOT_FOUND:
11500 			break;
11501 		default:
11502 			scfdie();
11503 		}
11504 	}
11505 	return (rv);
11506 }
11507 
11508 static void
11509 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
11510 {
11511 	size_t doc_len;
11512 	size_t man_len;
11513 	char *pg_name;
11514 	char *text = NULL;
11515 	int rv;
11516 
11517 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
11518 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
11519 	pg_name = safe_malloc(max_scf_name_len + 1);
11520 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
11521 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
11522 			scfdie();
11523 		}
11524 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
11525 			/* Display doc_link and and uri */
11526 			safe_printf("%s%s:\n", TMPL_INDENT,
11527 			    gettext("doc_link"));
11528 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
11529 			if (text != NULL) {
11530 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11531 				    TMPL_INDENT, gettext("name"), text);
11532 				uu_free(text);
11533 			}
11534 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
11535 			if (text != NULL) {
11536 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
11537 				    gettext("uri"), text);
11538 				uu_free(text);
11539 			}
11540 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
11541 		    man_len) == 0) {
11542 			/* Display manpage title, section and path */
11543 			safe_printf("%s%s:\n", TMPL_INDENT,
11544 			    gettext("manpage"));
11545 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
11546 			if (text != NULL) {
11547 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11548 				    TMPL_INDENT, gettext("title"), text);
11549 				uu_free(text);
11550 			}
11551 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
11552 			if (text != NULL) {
11553 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11554 				    TMPL_INDENT, gettext("section"), text);
11555 				uu_free(text);
11556 			}
11557 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
11558 			if (text != NULL) {
11559 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11560 				    TMPL_INDENT, gettext("manpath"), text);
11561 				uu_free(text);
11562 			}
11563 		}
11564 	}
11565 	if (rv == -1)
11566 		scfdie();
11567 
11568 done:
11569 	free(pg_name);
11570 }
11571 
11572 static void
11573 list_entity_tmpl(int templates)
11574 {
11575 	char *common_name = NULL;
11576 	char *description = NULL;
11577 	char *locale = NULL;
11578 	scf_iter_t *iter;
11579 	scf_propertygroup_t *pg;
11580 	scf_property_t *prop;
11581 	int r;
11582 	scf_value_t *val;
11583 
11584 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11585 	    (prop = scf_property_create(g_hndl)) == NULL ||
11586 	    (val = scf_value_create(g_hndl)) == NULL ||
11587 	    (iter = scf_iter_create(g_hndl)) == NULL)
11588 		scfdie();
11589 
11590 	locale = setlocale(LC_MESSAGES, NULL);
11591 
11592 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
11593 		common_name = safe_malloc(max_scf_value_len + 1);
11594 
11595 		/* Try both the current locale and the "C" locale. */
11596 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
11597 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
11598 		    scf_pg_get_property(pg, "C", prop) == 0)) {
11599 			if (prop_get_val(prop, val) == 0 &&
11600 			    scf_value_get_ustring(val, common_name,
11601 			    max_scf_value_len + 1) != -1) {
11602 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11603 				    gettext("common name"), common_name);
11604 			}
11605 		}
11606 	}
11607 
11608 	/*
11609 	 * Do description, manpages, and doc links if templates == 2.
11610 	 */
11611 	if (templates == 2) {
11612 		/* Get the description. */
11613 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
11614 			description = safe_malloc(max_scf_value_len + 1);
11615 
11616 			/* Try both the current locale and the "C" locale. */
11617 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
11618 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
11619 			    scf_pg_get_property(pg, "C", prop) == 0)) {
11620 				if (prop_get_val(prop, val) == 0 &&
11621 				    scf_value_get_ustring(val, description,
11622 				    max_scf_value_len + 1) != -1) {
11623 					safe_printf("%s%s: %s\n", TMPL_INDENT,
11624 					    gettext("description"),
11625 					    description);
11626 				}
11627 			}
11628 		}
11629 
11630 		/* Process doc_link & manpage elements. */
11631 		if (cur_level != NULL) {
11632 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
11633 			    SCF_GROUP_TEMPLATE);
11634 		} else if (cur_inst != NULL) {
11635 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
11636 			    SCF_GROUP_TEMPLATE);
11637 		} else {
11638 			r = scf_iter_service_pgs_typed(iter, cur_svc,
11639 			    SCF_GROUP_TEMPLATE);
11640 		}
11641 		if (r == 0) {
11642 			display_documentation(iter, pg);
11643 		}
11644 	}
11645 
11646 	free(common_name);
11647 	free(description);
11648 	scf_pg_destroy(pg);
11649 	scf_property_destroy(prop);
11650 	scf_value_destroy(val);
11651 	scf_iter_destroy(iter);
11652 }
11653 
11654 static void
11655 listtmpl(const char *pattern, int templates)
11656 {
11657 	scf_pg_tmpl_t *pgt;
11658 	scf_prop_tmpl_t *prt;
11659 	char *snapbuf = NULL;
11660 	char *fmribuf;
11661 	char *pg_name = NULL, *prop_name = NULL;
11662 	ssize_t prop_name_size;
11663 	char *qual_prop_name;
11664 	char *search_name;
11665 	int listed = 0;
11666 
11667 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
11668 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
11669 		scfdie();
11670 
11671 	fmribuf = safe_malloc(max_scf_name_len + 1);
11672 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
11673 
11674 	if (cur_snap != NULL) {
11675 		snapbuf = safe_malloc(max_scf_name_len + 1);
11676 		if (scf_snapshot_get_name(cur_snap, snapbuf,
11677 		    max_scf_name_len + 1) < 0)
11678 			scfdie();
11679 	}
11680 
11681 	if (cur_inst != NULL) {
11682 		if (scf_instance_to_fmri(cur_inst, fmribuf,
11683 		    max_scf_name_len + 1) < 0)
11684 			scfdie();
11685 	} else if (cur_svc != NULL) {
11686 		if (scf_service_to_fmri(cur_svc, fmribuf,
11687 		    max_scf_name_len + 1) < 0)
11688 			scfdie();
11689 	} else
11690 		abort();
11691 
11692 	/* If pattern is specified, we want to list only those items. */
11693 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
11694 		listed = 0;
11695 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
11696 		    fnmatch(pattern, pg_name, 0) == 0)) {
11697 			list_pg_tmpl(pgt, NULL, templates);
11698 			listed++;
11699 		}
11700 
11701 		scf_tmpl_prop_reset(prt);
11702 
11703 		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
11704 			search_name = NULL;
11705 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
11706 			if ((prop_name_size > 0) && (pg_name != NULL)) {
11707 				if (snprintf(qual_prop_name,
11708 				    max_scf_name_len + 1, "%s/%s",
11709 				    pg_name, prop_name) >=
11710 				    max_scf_name_len + 1) {
11711 					prop_name_size = -1;
11712 				} else {
11713 					search_name = qual_prop_name;
11714 				}
11715 			}
11716 			if (listed > 0 || pattern == NULL ||
11717 			    (prop_name_size > 0 &&
11718 			    fnmatch(pattern, search_name,
11719 			    FNM_PATHNAME) == 0))
11720 				list_prop_tmpl(prt, NULL, templates);
11721 			if (prop_name != NULL) {
11722 				free(prop_name);
11723 				prop_name = NULL;
11724 			}
11725 		}
11726 		if (pg_name != NULL) {
11727 			free(pg_name);
11728 			pg_name = NULL;
11729 		}
11730 	}
11731 
11732 	scf_tmpl_prop_destroy(prt);
11733 	scf_tmpl_pg_destroy(pgt);
11734 	free(snapbuf);
11735 	free(fmribuf);
11736 	free(qual_prop_name);
11737 }
11738 
11739 static void
11740 listprop(const char *pattern, int only_pgs, int templates)
11741 {
11742 	scf_propertygroup_t *pg;
11743 	scf_property_t *prop;
11744 	scf_iter_t *iter, *piter;
11745 	char *pgnbuf, *prnbuf, *ppnbuf;
11746 	scf_pg_tmpl_t *pgt, *pgtp;
11747 	scf_prop_tmpl_t *prt;
11748 
11749 	void **objects;
11750 	char **names;
11751 	void **tmpls;
11752 	int allocd, i;
11753 
11754 	int ret;
11755 	ssize_t pgnlen, prnlen, szret;
11756 	size_t max_len = 0;
11757 
11758 	if (cur_svc == NULL && cur_inst == NULL) {
11759 		semerr(emsg_entity_not_selected);
11760 		return;
11761 	}
11762 
11763 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11764 	    (prop = scf_property_create(g_hndl)) == NULL ||
11765 	    (iter = scf_iter_create(g_hndl)) == NULL ||
11766 	    (piter = scf_iter_create(g_hndl)) == NULL ||
11767 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
11768 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
11769 		scfdie();
11770 
11771 	prnbuf = safe_malloc(max_scf_name_len + 1);
11772 
11773 	if (cur_level != NULL)
11774 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
11775 	else if (cur_inst != NULL)
11776 		ret = scf_iter_instance_pgs(iter, cur_inst);
11777 	else
11778 		ret = scf_iter_service_pgs(iter, cur_svc);
11779 	if (ret != 0) {
11780 		return;
11781 	}
11782 
11783 	/*
11784 	 * We want to only list items which match pattern, and we want the
11785 	 * second column to line up, so during the first pass we'll save
11786 	 * matching items, their names, and their templates in objects,
11787 	 * names, and tmpls, computing the maximum name length as we go,
11788 	 * and then we'll print them out.
11789 	 *
11790 	 * Note: We always keep an extra slot available so the array can be
11791 	 * NULL-terminated.
11792 	 */
11793 	i = 0;
11794 	allocd = 1;
11795 	objects = safe_malloc(sizeof (*objects));
11796 	names = safe_malloc(sizeof (*names));
11797 	tmpls = safe_malloc(sizeof (*tmpls));
11798 
11799 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
11800 		int new_pg = 0;
11801 		int print_props = 0;
11802 		pgtp = NULL;
11803 
11804 		pgnlen = scf_pg_get_name(pg, NULL, 0);
11805 		if (pgnlen < 0)
11806 			scfdie();
11807 
11808 		pgnbuf = safe_malloc(pgnlen + 1);
11809 
11810 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
11811 		if (szret < 0)
11812 			scfdie();
11813 		assert(szret <= pgnlen);
11814 
11815 		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
11816 			if (scf_error() != SCF_ERROR_NOT_FOUND)
11817 				scfdie();
11818 			pgtp = NULL;
11819 		} else {
11820 			pgtp = pgt;
11821 		}
11822 
11823 		if (pattern == NULL ||
11824 		    fnmatch(pattern, pgnbuf, 0) == 0) {
11825 			if (i+1 >= allocd) {
11826 				allocd *= 2;
11827 				objects = realloc(objects,
11828 				    sizeof (*objects) * allocd);
11829 				names =
11830 				    realloc(names, sizeof (*names) * allocd);
11831 				tmpls = realloc(tmpls,
11832 				    sizeof (*tmpls) * allocd);
11833 				if (objects == NULL || names == NULL ||
11834 				    tmpls == NULL)
11835 					uu_die(gettext("Out of memory"));
11836 			}
11837 			objects[i] = pg;
11838 			names[i] = pgnbuf;
11839 
11840 			if (pgtp == NULL)
11841 				tmpls[i] = NULL;
11842 			else
11843 				tmpls[i] = pgt;
11844 
11845 			++i;
11846 
11847 			if (pgnlen > max_len)
11848 				max_len = pgnlen;
11849 
11850 			new_pg = 1;
11851 			print_props = 1;
11852 		}
11853 
11854 		if (only_pgs) {
11855 			if (new_pg) {
11856 				pg = scf_pg_create(g_hndl);
11857 				if (pg == NULL)
11858 					scfdie();
11859 				pgt = scf_tmpl_pg_create(g_hndl);
11860 				if (pgt == NULL)
11861 					scfdie();
11862 			} else
11863 				free(pgnbuf);
11864 
11865 			continue;
11866 		}
11867 
11868 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
11869 			scfdie();
11870 
11871 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
11872 			prnlen = scf_property_get_name(prop, prnbuf,
11873 			    max_scf_name_len + 1);
11874 			if (prnlen < 0)
11875 				scfdie();
11876 
11877 			/* Will prepend the property group name and a slash. */
11878 			prnlen += pgnlen + 1;
11879 
11880 			ppnbuf = safe_malloc(prnlen + 1);
11881 
11882 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
11883 			    prnbuf) < 0)
11884 				uu_die("snprintf");
11885 
11886 			if (pattern == NULL || print_props == 1 ||
11887 			    fnmatch(pattern, ppnbuf, 0) == 0) {
11888 				if (i+1 >= allocd) {
11889 					allocd *= 2;
11890 					objects = realloc(objects,
11891 					    sizeof (*objects) * allocd);
11892 					names = realloc(names,
11893 					    sizeof (*names) * allocd);
11894 					tmpls = realloc(tmpls,
11895 					    sizeof (*tmpls) * allocd);
11896 					if (objects == NULL || names == NULL ||
11897 					    tmpls == NULL)
11898 						uu_die(gettext(
11899 						    "Out of memory"));
11900 				}
11901 
11902 				objects[i] = prop;
11903 				names[i] = ppnbuf;
11904 
11905 				if (pgtp != NULL) {
11906 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
11907 					    prt, NULL) < 0) {
11908 						if (scf_error() !=
11909 						    SCF_ERROR_NOT_FOUND)
11910 							scfdie();
11911 						tmpls[i] = NULL;
11912 					} else {
11913 						tmpls[i] = prt;
11914 					}
11915 				} else {
11916 					tmpls[i] = NULL;
11917 				}
11918 
11919 				++i;
11920 
11921 				if (prnlen > max_len)
11922 					max_len = prnlen;
11923 
11924 				prop = scf_property_create(g_hndl);
11925 				prt = scf_tmpl_prop_create(g_hndl);
11926 			} else {
11927 				free(ppnbuf);
11928 			}
11929 		}
11930 
11931 		if (new_pg) {
11932 			pg = scf_pg_create(g_hndl);
11933 			if (pg == NULL)
11934 				scfdie();
11935 			pgt = scf_tmpl_pg_create(g_hndl);
11936 			if (pgt == NULL)
11937 				scfdie();
11938 		} else
11939 			free(pgnbuf);
11940 	}
11941 	if (ret != 0)
11942 		scfdie();
11943 
11944 	objects[i] = NULL;
11945 
11946 	scf_pg_destroy(pg);
11947 	scf_tmpl_pg_destroy(pgt);
11948 	scf_property_destroy(prop);
11949 	scf_tmpl_prop_destroy(prt);
11950 
11951 	for (i = 0; objects[i] != NULL; ++i) {
11952 		if (strchr(names[i], '/') == NULL) {
11953 			/* property group */
11954 			pg = (scf_propertygroup_t *)objects[i];
11955 			pgt = (scf_pg_tmpl_t *)tmpls[i];
11956 			list_pg_info(pg, names[i], max_len);
11957 			list_pg_tmpl(pgt, pg, templates);
11958 			free(names[i]);
11959 			scf_pg_destroy(pg);
11960 			if (pgt != NULL)
11961 				scf_tmpl_pg_destroy(pgt);
11962 		} else {
11963 			/* property */
11964 			prop = (scf_property_t *)objects[i];
11965 			prt = (scf_prop_tmpl_t *)tmpls[i];
11966 			list_prop_info(prop, names[i], max_len);
11967 			list_prop_tmpl(prt, prop, templates);
11968 			free(names[i]);
11969 			scf_property_destroy(prop);
11970 			if (prt != NULL)
11971 				scf_tmpl_prop_destroy(prt);
11972 		}
11973 	}
11974 
11975 	free(names);
11976 	free(objects);
11977 	free(tmpls);
11978 }
11979 
11980 void
11981 lscf_listpg(const char *pattern)
11982 {
11983 	lscf_prep_hndl();
11984 
11985 	listprop(pattern, 1, 0);
11986 }
11987 
11988 /*
11989  * Property group and property creation, setting, and deletion.  setprop (and
11990  * its alias, addprop) can either create a property group of a given type, or
11991  * it can create or set a property to a given type and list of values.
11992  */
11993 void
11994 lscf_addpg(const char *name, const char *type, const char *flags)
11995 {
11996 	scf_propertygroup_t *pg;
11997 	int ret;
11998 	uint32_t flgs = 0;
11999 	const char *cp;
12000 
12001 
12002 	lscf_prep_hndl();
12003 
12004 	if (cur_snap != NULL) {
12005 		semerr(emsg_cant_modify_snapshots);
12006 		return;
12007 	}
12008 
12009 	if (cur_inst == NULL && cur_svc == NULL) {
12010 		semerr(emsg_entity_not_selected);
12011 		return;
12012 	}
12013 
12014 	if (flags != NULL) {
12015 		for (cp = flags; *cp != '\0'; ++cp) {
12016 			switch (*cp) {
12017 			case 'P':
12018 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
12019 				break;
12020 
12021 			case 'p':
12022 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
12023 				break;
12024 
12025 			default:
12026 				semerr(gettext("Invalid property group flag "
12027 				    "%c."), *cp);
12028 				return;
12029 			}
12030 		}
12031 	}
12032 
12033 	pg = scf_pg_create(g_hndl);
12034 	if (pg == NULL)
12035 		scfdie();
12036 
12037 	if (cur_inst != NULL)
12038 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
12039 	else
12040 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
12041 
12042 	if (ret != SCF_SUCCESS) {
12043 		switch (scf_error()) {
12044 		case SCF_ERROR_INVALID_ARGUMENT:
12045 			semerr(gettext("Name, type, or flags are invalid.\n"));
12046 			break;
12047 
12048 		case SCF_ERROR_EXISTS:
12049 			semerr(gettext("Property group already exists.\n"));
12050 			break;
12051 
12052 		case SCF_ERROR_PERMISSION_DENIED:
12053 			semerr(emsg_permission_denied);
12054 			break;
12055 
12056 		case SCF_ERROR_BACKEND_ACCESS:
12057 			semerr(gettext("Backend refused access.\n"));
12058 			break;
12059 
12060 		default:
12061 			scfdie();
12062 		}
12063 	}
12064 
12065 	scf_pg_destroy(pg);
12066 
12067 	private_refresh();
12068 }
12069 
12070 void
12071 lscf_delpg(char *name)
12072 {
12073 	lscf_prep_hndl();
12074 
12075 	if (cur_snap != NULL) {
12076 		semerr(emsg_cant_modify_snapshots);
12077 		return;
12078 	}
12079 
12080 	if (cur_inst == NULL && cur_svc == NULL) {
12081 		semerr(emsg_entity_not_selected);
12082 		return;
12083 	}
12084 
12085 	if (strchr(name, '/') != NULL) {
12086 		semerr(emsg_invalid_pg_name, name);
12087 		return;
12088 	}
12089 
12090 	lscf_delprop(name);
12091 }
12092 
12093 /*
12094  * scf_delhash() is used to remove the property group related to the
12095  * hash entry for a specific manifest in the repository. pgname will be
12096  * constructed from the location of the manifest file. If deathrow isn't 0,
12097  * manifest file doesn't need to exist (manifest string will be used as
12098  * an absolute path).
12099  */
12100 void
12101 lscf_delhash(char *manifest, int deathrow)
12102 {
12103 	char *pgname;
12104 
12105 	if (cur_snap != NULL ||
12106 	    cur_inst != NULL || cur_svc != NULL) {
12107 		warn(gettext("error, an entity is selected\n"));
12108 		return;
12109 	}
12110 
12111 	/* select smf/manifest */
12112 	lscf_select("smf/manifest");
12113 	/*
12114 	 * Translate the manifest file name to property name. In the deathrow
12115 	 * case, the manifest file does not need to exist.
12116 	 */
12117 	pgname = mhash_filename_to_propname(manifest,
12118 	    deathrow ? B_TRUE : B_FALSE);
12119 	if (pgname == NULL) {
12120 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
12121 		return;
12122 	}
12123 	/* delete the hash property name */
12124 	lscf_delpg(pgname);
12125 }
12126 
12127 void
12128 lscf_listprop(const char *pattern)
12129 {
12130 	lscf_prep_hndl();
12131 
12132 	listprop(pattern, 0, 0);
12133 }
12134 
12135 int
12136 lscf_setprop(const char *pgname, const char *type, const char *value,
12137     const uu_list_t *values)
12138 {
12139 	scf_type_t ty, current_ty;
12140 	scf_service_t *svc;
12141 	scf_propertygroup_t *pg, *parent_pg;
12142 	scf_property_t *prop, *parent_prop;
12143 	scf_pg_tmpl_t *pgt;
12144 	scf_prop_tmpl_t *prt;
12145 	int ret, result = 0;
12146 	scf_transaction_t *tx;
12147 	scf_transaction_entry_t *e;
12148 	scf_value_t *v;
12149 	uu_list_walk_t *walk;
12150 	string_list_t *sp;
12151 	char *propname;
12152 	int req_quotes = 0;
12153 
12154 	lscf_prep_hndl();
12155 
12156 	if ((e = scf_entry_create(g_hndl)) == NULL ||
12157 	    (svc = scf_service_create(g_hndl)) == NULL ||
12158 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
12159 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12160 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
12161 	    (prop = scf_property_create(g_hndl)) == NULL ||
12162 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12163 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12164 	    (tx = scf_transaction_create(g_hndl)) == NULL)
12165 		scfdie();
12166 
12167 	if (cur_snap != NULL) {
12168 		semerr(emsg_cant_modify_snapshots);
12169 		goto fail;
12170 	}
12171 
12172 	if (cur_inst == NULL && cur_svc == NULL) {
12173 		semerr(emsg_entity_not_selected);
12174 		goto fail;
12175 	}
12176 
12177 	propname = strchr(pgname, '/');
12178 	if (propname == NULL) {
12179 		semerr(gettext("Property names must contain a `/'.\n"));
12180 		goto fail;
12181 	}
12182 
12183 	*propname = '\0';
12184 	++propname;
12185 
12186 	if (type != NULL) {
12187 		ty = string_to_type(type);
12188 		if (ty == SCF_TYPE_INVALID) {
12189 			semerr(gettext("Unknown type \"%s\".\n"), type);
12190 			goto fail;
12191 		}
12192 	}
12193 
12194 	if (cur_inst != NULL)
12195 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12196 	else
12197 		ret = scf_service_get_pg(cur_svc, pgname, pg);
12198 	if (ret != SCF_SUCCESS) {
12199 		switch (scf_error()) {
12200 		case SCF_ERROR_NOT_FOUND:
12201 			semerr(emsg_no_such_pg, pgname);
12202 			goto fail;
12203 
12204 		case SCF_ERROR_INVALID_ARGUMENT:
12205 			semerr(emsg_invalid_pg_name, pgname);
12206 			goto fail;
12207 
12208 		default:
12209 			scfdie();
12210 			break;
12211 		}
12212 	}
12213 
12214 	do {
12215 		if (scf_pg_update(pg) == -1)
12216 			scfdie();
12217 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12218 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12219 				scfdie();
12220 
12221 			semerr(emsg_permission_denied);
12222 			goto fail;
12223 		}
12224 
12225 		ret = scf_pg_get_property(pg, propname, prop);
12226 		if (ret == SCF_SUCCESS) {
12227 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
12228 				scfdie();
12229 
12230 			if (type == NULL)
12231 				ty = current_ty;
12232 			if (scf_transaction_property_change_type(tx, e,
12233 			    propname, ty) == -1)
12234 				scfdie();
12235 
12236 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12237 			/* Infer the type, if possible. */
12238 			if (type == NULL) {
12239 				/*
12240 				 * First check if we're an instance and the
12241 				 * property is set on the service.
12242 				 */
12243 				if (cur_inst != NULL &&
12244 				    scf_instance_get_parent(cur_inst,
12245 				    svc) == 0 &&
12246 				    scf_service_get_pg(cur_svc, pgname,
12247 				    parent_pg) == 0 &&
12248 				    scf_pg_get_property(parent_pg, propname,
12249 				    parent_prop) == 0 &&
12250 				    scf_property_type(parent_prop,
12251 				    &current_ty) == 0) {
12252 					ty = current_ty;
12253 
12254 				/* Then check for a type set in a template. */
12255 				} else if (scf_tmpl_get_by_pg(pg, pgt,
12256 				    NULL) == 0 &&
12257 				    scf_tmpl_get_by_prop(pgt, propname, prt,
12258 				    NULL) == 0 &&
12259 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
12260 					ty = current_ty;
12261 
12262 				/* If type can't be inferred, fail. */
12263 				} else {
12264 					semerr(gettext("Type required for new "
12265 					    "properties.\n"));
12266 					goto fail;
12267 				}
12268 			}
12269 			if (scf_transaction_property_new(tx, e, propname,
12270 			    ty) == -1)
12271 				scfdie();
12272 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12273 			semerr(emsg_invalid_prop_name, propname);
12274 			goto fail;
12275 		} else {
12276 			scfdie();
12277 		}
12278 
12279 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
12280 			req_quotes = 1;
12281 
12282 		if (value != NULL) {
12283 			v = string_to_value(value, ty, 0);
12284 
12285 			if (v == NULL)
12286 				goto fail;
12287 
12288 			ret = scf_entry_add_value(e, v);
12289 			assert(ret == SCF_SUCCESS);
12290 		} else {
12291 			assert(values != NULL);
12292 
12293 			walk = uu_list_walk_start((uu_list_t *)values,
12294 			    UU_DEFAULT);
12295 			if (walk == NULL)
12296 				uu_die(gettext("Could not walk list"));
12297 
12298 			for (sp = uu_list_walk_next(walk); sp != NULL;
12299 			    sp = uu_list_walk_next(walk)) {
12300 				v = string_to_value(sp->str, ty, req_quotes);
12301 
12302 				if (v == NULL) {
12303 					scf_entry_destroy_children(e);
12304 					goto fail;
12305 				}
12306 
12307 				ret = scf_entry_add_value(e, v);
12308 				assert(ret == SCF_SUCCESS);
12309 			}
12310 			uu_list_walk_end(walk);
12311 		}
12312 		result = scf_transaction_commit(tx);
12313 
12314 		scf_transaction_reset(tx);
12315 		scf_entry_destroy_children(e);
12316 	} while (result == 0);
12317 
12318 	if (result < 0) {
12319 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12320 			scfdie();
12321 
12322 		semerr(emsg_permission_denied);
12323 		goto fail;
12324 	}
12325 
12326 	ret = 0;
12327 
12328 	private_refresh();
12329 
12330 	goto cleanup;
12331 
12332 fail:
12333 	ret = -1;
12334 
12335 cleanup:
12336 	scf_transaction_destroy(tx);
12337 	scf_entry_destroy(e);
12338 	scf_service_destroy(svc);
12339 	scf_pg_destroy(parent_pg);
12340 	scf_pg_destroy(pg);
12341 	scf_property_destroy(parent_prop);
12342 	scf_property_destroy(prop);
12343 	scf_tmpl_pg_destroy(pgt);
12344 	scf_tmpl_prop_destroy(prt);
12345 
12346 	return (ret);
12347 }
12348 
12349 void
12350 lscf_delprop(char *pgn)
12351 {
12352 	char *slash, *pn;
12353 	scf_propertygroup_t *pg;
12354 	scf_transaction_t *tx;
12355 	scf_transaction_entry_t *e;
12356 	int ret;
12357 
12358 
12359 	lscf_prep_hndl();
12360 
12361 	if (cur_snap != NULL) {
12362 		semerr(emsg_cant_modify_snapshots);
12363 		return;
12364 	}
12365 
12366 	if (cur_inst == NULL && cur_svc == NULL) {
12367 		semerr(emsg_entity_not_selected);
12368 		return;
12369 	}
12370 
12371 	pg = scf_pg_create(g_hndl);
12372 	if (pg == NULL)
12373 		scfdie();
12374 
12375 	slash = strchr(pgn, '/');
12376 	if (slash == NULL) {
12377 		pn = NULL;
12378 	} else {
12379 		*slash = '\0';
12380 		pn = slash + 1;
12381 	}
12382 
12383 	if (cur_inst != NULL)
12384 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
12385 	else
12386 		ret = scf_service_get_pg(cur_svc, pgn, pg);
12387 	if (ret != SCF_SUCCESS) {
12388 		switch (scf_error()) {
12389 		case SCF_ERROR_NOT_FOUND:
12390 			semerr(emsg_no_such_pg, pgn);
12391 			break;
12392 
12393 		case SCF_ERROR_INVALID_ARGUMENT:
12394 			semerr(emsg_invalid_pg_name, pgn);
12395 			break;
12396 
12397 		default:
12398 			scfdie();
12399 		}
12400 
12401 		scf_pg_destroy(pg);
12402 
12403 		return;
12404 	}
12405 
12406 	if (pn == NULL) {
12407 		/* Try to delete the property group. */
12408 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
12409 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12410 				scfdie();
12411 
12412 			semerr(emsg_permission_denied);
12413 		} else {
12414 			private_refresh();
12415 		}
12416 
12417 		scf_pg_destroy(pg);
12418 		return;
12419 	}
12420 
12421 	e = scf_entry_create(g_hndl);
12422 	tx = scf_transaction_create(g_hndl);
12423 
12424 	do {
12425 		if (scf_pg_update(pg) == -1)
12426 			scfdie();
12427 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12428 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12429 				scfdie();
12430 
12431 			semerr(emsg_permission_denied);
12432 			break;
12433 		}
12434 
12435 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
12436 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
12437 				semerr(gettext("No such property %s/%s.\n"),
12438 				    pgn, pn);
12439 				break;
12440 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12441 				semerr(emsg_invalid_prop_name, pn);
12442 				break;
12443 			} else {
12444 				scfdie();
12445 			}
12446 		}
12447 
12448 		ret = scf_transaction_commit(tx);
12449 
12450 		if (ret == 0)
12451 			scf_transaction_reset(tx);
12452 	} while (ret == 0);
12453 
12454 	if (ret < 0) {
12455 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12456 			scfdie();
12457 
12458 		semerr(emsg_permission_denied);
12459 	} else {
12460 		private_refresh();
12461 	}
12462 
12463 	scf_transaction_destroy(tx);
12464 	scf_entry_destroy(e);
12465 	scf_pg_destroy(pg);
12466 }
12467 
12468 /*
12469  * Property editing.
12470  */
12471 
12472 static int
12473 write_edit_script(FILE *strm)
12474 {
12475 	char *fmribuf;
12476 	ssize_t fmrilen;
12477 
12478 	scf_propertygroup_t *pg;
12479 	scf_property_t *prop;
12480 	scf_value_t *val;
12481 	scf_type_t ty;
12482 	int ret, result = 0;
12483 	scf_iter_t *iter, *piter, *viter;
12484 	char *buf, *tybuf, *pname;
12485 	const char *emsg_write_error;
12486 
12487 
12488 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
12489 
12490 
12491 	/* select fmri */
12492 	if (cur_inst != NULL) {
12493 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
12494 		if (fmrilen < 0)
12495 			scfdie();
12496 		fmribuf = safe_malloc(fmrilen + 1);
12497 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
12498 			scfdie();
12499 	} else {
12500 		assert(cur_svc != NULL);
12501 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
12502 		if (fmrilen < 0)
12503 			scfdie();
12504 		fmribuf = safe_malloc(fmrilen + 1);
12505 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
12506 			scfdie();
12507 	}
12508 
12509 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
12510 		warn(emsg_write_error, strerror(errno));
12511 		free(fmribuf);
12512 		return (-1);
12513 	}
12514 
12515 	free(fmribuf);
12516 
12517 
12518 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12519 	    (prop = scf_property_create(g_hndl)) == NULL ||
12520 	    (val = scf_value_create(g_hndl)) == NULL ||
12521 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12522 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12523 	    (viter = scf_iter_create(g_hndl)) == NULL)
12524 		scfdie();
12525 
12526 	buf = safe_malloc(max_scf_name_len + 1);
12527 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
12528 	pname = safe_malloc(max_scf_name_len + 1);
12529 
12530 	if (cur_inst != NULL)
12531 		ret = scf_iter_instance_pgs(iter, cur_inst);
12532 	else
12533 		ret = scf_iter_service_pgs(iter, cur_svc);
12534 	if (ret != SCF_SUCCESS)
12535 		scfdie();
12536 
12537 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12538 		int ret2;
12539 
12540 		/*
12541 		 * # delprop pg
12542 		 * # addpg pg type
12543 		 */
12544 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
12545 			scfdie();
12546 
12547 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
12548 			scfdie();
12549 
12550 		if (fprintf(strm, "# Property group \"%s\"\n"
12551 		    "# delprop %s\n"
12552 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
12553 			warn(emsg_write_error, strerror(errno));
12554 			result = -1;
12555 			goto out;
12556 		}
12557 
12558 		/* # setprop pg/prop = (values) */
12559 
12560 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12561 			scfdie();
12562 
12563 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
12564 			int first = 1;
12565 			int ret3;
12566 			int multiple;
12567 			int is_str;
12568 			scf_type_t bty;
12569 
12570 			if (scf_property_get_name(prop, pname,
12571 			    max_scf_name_len + 1) < 0)
12572 				scfdie();
12573 
12574 			if (scf_property_type(prop, &ty) != 0)
12575 				scfdie();
12576 
12577 			multiple = prop_has_multiple_values(prop, val);
12578 
12579 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
12580 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
12581 			    < 0) {
12582 				warn(emsg_write_error, strerror(errno));
12583 				result = -1;
12584 				goto out;
12585 			}
12586 
12587 			(void) scf_type_base_type(ty, &bty);
12588 			is_str = (bty == SCF_TYPE_ASTRING);
12589 
12590 			if (scf_iter_property_values(viter, prop) !=
12591 			    SCF_SUCCESS)
12592 				scfdie();
12593 
12594 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
12595 				char *buf;
12596 				ssize_t buflen;
12597 
12598 				buflen = scf_value_get_as_string(val, NULL, 0);
12599 				if (buflen < 0)
12600 					scfdie();
12601 
12602 				buf = safe_malloc(buflen + 1);
12603 
12604 				if (scf_value_get_as_string(val, buf,
12605 				    buflen + 1) < 0)
12606 					scfdie();
12607 
12608 				if (first)
12609 					first = 0;
12610 				else {
12611 					if (putc(' ', strm) != ' ') {
12612 						warn(emsg_write_error,
12613 						    strerror(errno));
12614 						result = -1;
12615 						goto out;
12616 					}
12617 				}
12618 
12619 				if ((is_str && multiple) ||
12620 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
12621 					(void) putc('"', strm);
12622 					(void) quote_and_print(buf, strm, 1);
12623 					(void) putc('"', strm);
12624 
12625 					if (ferror(strm)) {
12626 						warn(emsg_write_error,
12627 						    strerror(errno));
12628 						result = -1;
12629 						goto out;
12630 					}
12631 				} else {
12632 					if (fprintf(strm, "%s", buf) < 0) {
12633 						warn(emsg_write_error,
12634 						    strerror(errno));
12635 						result = -1;
12636 						goto out;
12637 					}
12638 				}
12639 
12640 				free(buf);
12641 			}
12642 			if (ret3 < 0 &&
12643 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
12644 				scfdie();
12645 
12646 			/* Write closing paren if mult-value property */
12647 			if ((multiple && putc(')', strm) == EOF) ||
12648 
12649 			    /* Write final newline */
12650 			    fputc('\n', strm) == EOF) {
12651 				warn(emsg_write_error, strerror(errno));
12652 				result = -1;
12653 				goto out;
12654 			}
12655 		}
12656 		if (ret2 < 0)
12657 			scfdie();
12658 
12659 		if (fputc('\n', strm) == EOF) {
12660 			warn(emsg_write_error, strerror(errno));
12661 			result = -1;
12662 			goto out;
12663 		}
12664 	}
12665 	if (ret < 0)
12666 		scfdie();
12667 
12668 out:
12669 	free(pname);
12670 	free(tybuf);
12671 	free(buf);
12672 	scf_iter_destroy(viter);
12673 	scf_iter_destroy(piter);
12674 	scf_iter_destroy(iter);
12675 	scf_value_destroy(val);
12676 	scf_property_destroy(prop);
12677 	scf_pg_destroy(pg);
12678 
12679 	if (result == 0) {
12680 		if (fflush(strm) != 0) {
12681 			warn(emsg_write_error, strerror(errno));
12682 			return (-1);
12683 		}
12684 	}
12685 
12686 	return (result);
12687 }
12688 
12689 int
12690 lscf_editprop()
12691 {
12692 	char *buf, *editor;
12693 	size_t bufsz;
12694 	int tmpfd;
12695 	char tempname[] = TEMP_FILE_PATTERN;
12696 
12697 	lscf_prep_hndl();
12698 
12699 	if (cur_snap != NULL) {
12700 		semerr(emsg_cant_modify_snapshots);
12701 		return (-1);
12702 	}
12703 
12704 	if (cur_svc == NULL && cur_inst == NULL) {
12705 		semerr(emsg_entity_not_selected);
12706 		return (-1);
12707 	}
12708 
12709 	tmpfd = mkstemp(tempname);
12710 	if (tmpfd == -1) {
12711 		semerr(gettext("Could not create temporary file.\n"));
12712 		return (-1);
12713 	}
12714 
12715 	(void) strcpy(tempfilename, tempname);
12716 
12717 	tempfile = fdopen(tmpfd, "r+");
12718 	if (tempfile == NULL) {
12719 		warn(gettext("Could not create temporary file.\n"));
12720 		if (close(tmpfd) == -1)
12721 			warn(gettext("Could not close temporary file: %s.\n"),
12722 			    strerror(errno));
12723 
12724 		remove_tempfile();
12725 
12726 		return (-1);
12727 	}
12728 
12729 	if (write_edit_script(tempfile) == -1) {
12730 		remove_tempfile();
12731 		return (-1);
12732 	}
12733 
12734 	editor = getenv("EDITOR");
12735 	if (editor == NULL)
12736 		editor = "vi";
12737 
12738 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
12739 	buf = safe_malloc(bufsz);
12740 
12741 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
12742 		uu_die(gettext("Error creating editor command"));
12743 
12744 	if (system(buf) == -1) {
12745 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
12746 		    strerror(errno));
12747 		free(buf);
12748 		remove_tempfile();
12749 		return (-1);
12750 	}
12751 
12752 	free(buf);
12753 
12754 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
12755 
12756 	remove_tempfile();
12757 
12758 	return (0);
12759 }
12760 
12761 static void
12762 add_string(uu_list_t *strlist, const char *str)
12763 {
12764 	string_list_t *elem;
12765 	elem = safe_malloc(sizeof (*elem));
12766 	uu_list_node_init(elem, &elem->node, string_pool);
12767 	elem->str = safe_strdup(str);
12768 	if (uu_list_append(strlist, elem) != 0)
12769 		uu_die(gettext("libuutil error: %s\n"),
12770 		    uu_strerror(uu_error()));
12771 }
12772 
12773 /*
12774  * Get all property values that don't match the given glob pattern,
12775  * if a pattern is specified.
12776  */
12777 static void
12778 get_prop_values(scf_property_t *prop, uu_list_t *values,
12779     const char *pattern)
12780 {
12781 	scf_iter_t *iter;
12782 	scf_value_t *val;
12783 	int ret;
12784 
12785 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12786 	    (val = scf_value_create(g_hndl)) == NULL)
12787 		scfdie();
12788 
12789 	if (scf_iter_property_values(iter, prop) != 0)
12790 		scfdie();
12791 
12792 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12793 		char *buf;
12794 		ssize_t vlen, szret;
12795 
12796 		vlen = scf_value_get_as_string(val, NULL, 0);
12797 		if (vlen < 0)
12798 			scfdie();
12799 
12800 		buf = safe_malloc(vlen + 1);
12801 
12802 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12803 		if (szret < 0)
12804 			scfdie();
12805 		assert(szret <= vlen);
12806 
12807 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
12808 			add_string(values, buf);
12809 
12810 		free(buf);
12811 	}
12812 
12813 	if (ret == -1)
12814 		scfdie();
12815 
12816 	scf_value_destroy(val);
12817 	scf_iter_destroy(iter);
12818 }
12819 
12820 static int
12821 lscf_setpropvalue(const char *pgname, const char *type,
12822     const char *arg, int isadd, int isnotfoundok)
12823 {
12824 	scf_type_t ty;
12825 	scf_propertygroup_t *pg;
12826 	scf_property_t *prop;
12827 	int ret, result = 0;
12828 	scf_transaction_t *tx;
12829 	scf_transaction_entry_t *e;
12830 	scf_value_t *v;
12831 	string_list_t *sp;
12832 	char *propname;
12833 	uu_list_t *values;
12834 	uu_list_walk_t *walk;
12835 	void *cookie = NULL;
12836 	char *pattern = NULL;
12837 
12838 	lscf_prep_hndl();
12839 
12840 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
12841 		uu_die(gettext("Could not create property list: %s\n"),
12842 		    uu_strerror(uu_error()));
12843 
12844 	if (!isadd)
12845 		pattern = safe_strdup(arg);
12846 
12847 	if ((e = scf_entry_create(g_hndl)) == NULL ||
12848 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12849 	    (prop = scf_property_create(g_hndl)) == NULL ||
12850 	    (tx = scf_transaction_create(g_hndl)) == NULL)
12851 		scfdie();
12852 
12853 	if (cur_snap != NULL) {
12854 		semerr(emsg_cant_modify_snapshots);
12855 		goto fail;
12856 	}
12857 
12858 	if (cur_inst == NULL && cur_svc == NULL) {
12859 		semerr(emsg_entity_not_selected);
12860 		goto fail;
12861 	}
12862 
12863 	propname = strchr(pgname, '/');
12864 	if (propname == NULL) {
12865 		semerr(gettext("Property names must contain a `/'.\n"));
12866 		goto fail;
12867 	}
12868 
12869 	*propname = '\0';
12870 	++propname;
12871 
12872 	if (type != NULL) {
12873 		ty = string_to_type(type);
12874 		if (ty == SCF_TYPE_INVALID) {
12875 			semerr(gettext("Unknown type \"%s\".\n"), type);
12876 			goto fail;
12877 		}
12878 	}
12879 
12880 	if (cur_inst != NULL)
12881 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12882 	else
12883 		ret = scf_service_get_pg(cur_svc, pgname, pg);
12884 	if (ret != 0) {
12885 		switch (scf_error()) {
12886 		case SCF_ERROR_NOT_FOUND:
12887 			if (isnotfoundok) {
12888 				result = 0;
12889 			} else {
12890 				semerr(emsg_no_such_pg, pgname);
12891 				result = -1;
12892 			}
12893 			goto out;
12894 
12895 		case SCF_ERROR_INVALID_ARGUMENT:
12896 			semerr(emsg_invalid_pg_name, pgname);
12897 			goto fail;
12898 
12899 		default:
12900 			scfdie();
12901 		}
12902 	}
12903 
12904 	do {
12905 		if (scf_pg_update(pg) == -1)
12906 			scfdie();
12907 		if (scf_transaction_start(tx, pg) != 0) {
12908 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12909 				scfdie();
12910 
12911 			semerr(emsg_permission_denied);
12912 			goto fail;
12913 		}
12914 
12915 		ret = scf_pg_get_property(pg, propname, prop);
12916 		if (ret == 0) {
12917 			scf_type_t ptype;
12918 			char *pat = pattern;
12919 
12920 			if (scf_property_type(prop, &ptype) != 0)
12921 				scfdie();
12922 
12923 			if (isadd) {
12924 				if (type != NULL && ptype != ty) {
12925 					semerr(gettext("Property \"%s\" is not "
12926 					    "of type \"%s\".\n"), propname,
12927 					    type);
12928 					goto fail;
12929 				}
12930 
12931 				pat = NULL;
12932 			} else {
12933 				size_t len = strlen(pat);
12934 				if (len > 0 && pat[len - 1] == '\"')
12935 					pat[len - 1] = '\0';
12936 				if (len > 0 && pat[0] == '\"')
12937 					pat++;
12938 			}
12939 
12940 			ty = ptype;
12941 
12942 			get_prop_values(prop, values, pat);
12943 
12944 			if (isadd)
12945 				add_string(values, arg);
12946 
12947 			if (scf_transaction_property_change(tx, e,
12948 			    propname, ty) == -1)
12949 				scfdie();
12950 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12951 			if (isadd) {
12952 				if (type == NULL) {
12953 					semerr(gettext("Type required "
12954 					    "for new properties.\n"));
12955 					goto fail;
12956 				}
12957 
12958 				add_string(values, arg);
12959 
12960 				if (scf_transaction_property_new(tx, e,
12961 				    propname, ty) == -1)
12962 					scfdie();
12963 			} else if (isnotfoundok) {
12964 				result = 0;
12965 				goto out;
12966 			} else {
12967 				semerr(gettext("No such property %s/%s.\n"),
12968 				    pgname, propname);
12969 				result = -1;
12970 				goto out;
12971 			}
12972 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12973 			semerr(emsg_invalid_prop_name, propname);
12974 			goto fail;
12975 		} else {
12976 			scfdie();
12977 		}
12978 
12979 		walk = uu_list_walk_start(values, UU_DEFAULT);
12980 		if (walk == NULL)
12981 			uu_die(gettext("Could not walk property list.\n"));
12982 
12983 		for (sp = uu_list_walk_next(walk); sp != NULL;
12984 		    sp = uu_list_walk_next(walk)) {
12985 			v = string_to_value(sp->str, ty, 0);
12986 
12987 			if (v == NULL) {
12988 				scf_entry_destroy_children(e);
12989 				goto fail;
12990 			}
12991 			ret = scf_entry_add_value(e, v);
12992 			assert(ret == 0);
12993 		}
12994 		uu_list_walk_end(walk);
12995 
12996 		result = scf_transaction_commit(tx);
12997 
12998 		scf_transaction_reset(tx);
12999 		scf_entry_destroy_children(e);
13000 	} while (result == 0);
13001 
13002 	if (result < 0) {
13003 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13004 			scfdie();
13005 
13006 		semerr(emsg_permission_denied);
13007 		goto fail;
13008 	}
13009 
13010 	result = 0;
13011 
13012 	private_refresh();
13013 
13014 out:
13015 	scf_transaction_destroy(tx);
13016 	scf_entry_destroy(e);
13017 	scf_pg_destroy(pg);
13018 	scf_property_destroy(prop);
13019 	free(pattern);
13020 
13021 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
13022 		free(sp->str);
13023 		free(sp);
13024 	}
13025 
13026 	uu_list_destroy(values);
13027 
13028 	return (result);
13029 
13030 fail:
13031 	result = -1;
13032 	goto out;
13033 }
13034 
13035 int
13036 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
13037 {
13038 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
13039 }
13040 
13041 int
13042 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
13043 {
13044 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
13045 }
13046 
13047 /*
13048  * Look for a standard start method, first in the instance (if any),
13049  * then the service.
13050  */
13051 static const char *
13052 start_method_name(int *in_instance)
13053 {
13054 	scf_propertygroup_t *pg;
13055 	char **p;
13056 	int ret;
13057 	scf_instance_t *inst = cur_inst;
13058 
13059 	if ((pg = scf_pg_create(g_hndl)) == NULL)
13060 		scfdie();
13061 
13062 again:
13063 	for (p = start_method_names; *p != NULL; p++) {
13064 		if (inst != NULL)
13065 			ret = scf_instance_get_pg(inst, *p, pg);
13066 		else
13067 			ret = scf_service_get_pg(cur_svc, *p, pg);
13068 
13069 		if (ret == 0) {
13070 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
13071 			char *buf = safe_malloc(bufsz);
13072 
13073 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
13074 				free(buf);
13075 				continue;
13076 			}
13077 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
13078 				free(buf);
13079 				continue;
13080 			}
13081 
13082 			free(buf);
13083 			*in_instance = (inst != NULL);
13084 			scf_pg_destroy(pg);
13085 			return (*p);
13086 		}
13087 
13088 		if (scf_error() == SCF_ERROR_NOT_FOUND)
13089 			continue;
13090 
13091 		scfdie();
13092 	}
13093 
13094 	if (inst != NULL) {
13095 		inst = NULL;
13096 		goto again;
13097 	}
13098 
13099 	scf_pg_destroy(pg);
13100 	return (NULL);
13101 }
13102 
13103 static int
13104 addpg(const char *name, const char *type)
13105 {
13106 	scf_propertygroup_t *pg;
13107 	int ret;
13108 
13109 	pg = scf_pg_create(g_hndl);
13110 	if (pg == NULL)
13111 		scfdie();
13112 
13113 	if (cur_inst != NULL)
13114 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
13115 	else
13116 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
13117 
13118 	if (ret != 0) {
13119 		switch (scf_error()) {
13120 		case SCF_ERROR_EXISTS:
13121 			ret = 0;
13122 			break;
13123 
13124 		case SCF_ERROR_PERMISSION_DENIED:
13125 			semerr(emsg_permission_denied);
13126 			break;
13127 
13128 		default:
13129 			scfdie();
13130 		}
13131 	}
13132 
13133 	scf_pg_destroy(pg);
13134 	return (ret);
13135 }
13136 
13137 int
13138 lscf_setenv(uu_list_t *args, int isunset)
13139 {
13140 	int ret = 0;
13141 	size_t i;
13142 	int argc;
13143 	char **argv = NULL;
13144 	string_list_t *slp;
13145 	char *pattern;
13146 	char *prop;
13147 	int do_service = 0;
13148 	int do_instance = 0;
13149 	const char *method = NULL;
13150 	const char *name = NULL;
13151 	const char *value = NULL;
13152 	scf_instance_t *saved_cur_inst = cur_inst;
13153 
13154 	lscf_prep_hndl();
13155 
13156 	argc = uu_list_numnodes(args);
13157 	if (argc < 1)
13158 		goto usage;
13159 
13160 	argv = calloc(argc + 1, sizeof (char *));
13161 	if (argv == NULL)
13162 		uu_die(gettext("Out of memory.\n"));
13163 
13164 	for (slp = uu_list_first(args), i = 0;
13165 	    slp != NULL;
13166 	    slp = uu_list_next(args, slp), ++i)
13167 		argv[i] = slp->str;
13168 
13169 	argv[i] = NULL;
13170 
13171 	opterr = 0;
13172 	optind = 0;
13173 	for (;;) {
13174 		ret = getopt(argc, argv, "sim:");
13175 		if (ret == -1)
13176 			break;
13177 
13178 		switch (ret) {
13179 		case 's':
13180 			do_service = 1;
13181 			cur_inst = NULL;
13182 			break;
13183 
13184 		case 'i':
13185 			do_instance = 1;
13186 			break;
13187 
13188 		case 'm':
13189 			method = optarg;
13190 			break;
13191 
13192 		case '?':
13193 			goto usage;
13194 
13195 		default:
13196 			bad_error("getopt", ret);
13197 		}
13198 	}
13199 
13200 	argc -= optind;
13201 	if ((do_service && do_instance) ||
13202 	    (isunset && argc != 1) ||
13203 	    (!isunset && argc != 2))
13204 		goto usage;
13205 
13206 	name = argv[optind];
13207 	if (!isunset)
13208 		value = argv[optind + 1];
13209 
13210 	if (cur_snap != NULL) {
13211 		semerr(emsg_cant_modify_snapshots);
13212 		ret = -1;
13213 		goto out;
13214 	}
13215 
13216 	if (cur_inst == NULL && cur_svc == NULL) {
13217 		semerr(emsg_entity_not_selected);
13218 		ret = -1;
13219 		goto out;
13220 	}
13221 
13222 	if (do_instance && cur_inst == NULL) {
13223 		semerr(gettext("No instance is selected.\n"));
13224 		ret = -1;
13225 		goto out;
13226 	}
13227 
13228 	if (do_service && cur_svc == NULL) {
13229 		semerr(gettext("No service is selected.\n"));
13230 		ret = -1;
13231 		goto out;
13232 	}
13233 
13234 	if (method == NULL) {
13235 		if (do_instance || do_service) {
13236 			method = "method_context";
13237 			if (!isunset) {
13238 				ret = addpg("method_context",
13239 				    SCF_GROUP_FRAMEWORK);
13240 				if (ret != 0)
13241 					goto out;
13242 			}
13243 		} else {
13244 			int in_instance;
13245 			method = start_method_name(&in_instance);
13246 			if (method == NULL) {
13247 				semerr(gettext(
13248 				    "Couldn't find start method; please "
13249 				    "specify a method with '-m'.\n"));
13250 				ret = -1;
13251 				goto out;
13252 			}
13253 			if (!in_instance)
13254 				cur_inst = NULL;
13255 		}
13256 	} else {
13257 		scf_propertygroup_t *pg;
13258 		size_t bufsz;
13259 		char *buf;
13260 		int ret;
13261 
13262 		if ((pg = scf_pg_create(g_hndl)) == NULL)
13263 			scfdie();
13264 
13265 		if (cur_inst != NULL)
13266 			ret = scf_instance_get_pg(cur_inst, method, pg);
13267 		else
13268 			ret = scf_service_get_pg(cur_svc, method, pg);
13269 
13270 		if (ret != 0) {
13271 			scf_pg_destroy(pg);
13272 			switch (scf_error()) {
13273 			case SCF_ERROR_NOT_FOUND:
13274 				semerr(gettext("Couldn't find the method "
13275 				    "\"%s\".\n"), method);
13276 				goto out;
13277 
13278 			case SCF_ERROR_INVALID_ARGUMENT:
13279 				semerr(gettext("Invalid method name \"%s\".\n"),
13280 				    method);
13281 				goto out;
13282 
13283 			default:
13284 				scfdie();
13285 			}
13286 		}
13287 
13288 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
13289 		buf = safe_malloc(bufsz);
13290 
13291 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
13292 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
13293 			semerr(gettext("Property group \"%s\" is not of type "
13294 			    "\"method\".\n"), method);
13295 			ret = -1;
13296 			free(buf);
13297 			scf_pg_destroy(pg);
13298 			goto out;
13299 		}
13300 
13301 		free(buf);
13302 		scf_pg_destroy(pg);
13303 	}
13304 
13305 	prop = uu_msprintf("%s/environment", method);
13306 	pattern = uu_msprintf("%s=*", name);
13307 
13308 	if (prop == NULL || pattern == NULL)
13309 		uu_die(gettext("Out of memory.\n"));
13310 
13311 	ret = lscf_delpropvalue(prop, pattern, !isunset);
13312 
13313 	if (ret == 0 && !isunset) {
13314 		uu_free(pattern);
13315 		uu_free(prop);
13316 		prop = uu_msprintf("%s/environment", method);
13317 		pattern = uu_msprintf("%s=%s", name, value);
13318 		if (prop == NULL || pattern == NULL)
13319 			uu_die(gettext("Out of memory.\n"));
13320 		ret = lscf_addpropvalue(prop, "astring:", pattern);
13321 	}
13322 	uu_free(pattern);
13323 	uu_free(prop);
13324 
13325 out:
13326 	cur_inst = saved_cur_inst;
13327 
13328 	free(argv);
13329 	return (ret);
13330 usage:
13331 	ret = -2;
13332 	goto out;
13333 }
13334 
13335 /*
13336  * Snapshot commands
13337  */
13338 
13339 void
13340 lscf_listsnap()
13341 {
13342 	scf_snapshot_t *snap;
13343 	scf_iter_t *iter;
13344 	char *nb;
13345 	int r;
13346 
13347 	lscf_prep_hndl();
13348 
13349 	if (cur_inst == NULL) {
13350 		semerr(gettext("Instance not selected.\n"));
13351 		return;
13352 	}
13353 
13354 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13355 	    (iter = scf_iter_create(g_hndl)) == NULL)
13356 		scfdie();
13357 
13358 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
13359 		scfdie();
13360 
13361 	nb = safe_malloc(max_scf_name_len + 1);
13362 
13363 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
13364 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
13365 			scfdie();
13366 
13367 		(void) puts(nb);
13368 	}
13369 	if (r < 0)
13370 		scfdie();
13371 
13372 	free(nb);
13373 	scf_iter_destroy(iter);
13374 	scf_snapshot_destroy(snap);
13375 }
13376 
13377 void
13378 lscf_selectsnap(const char *name)
13379 {
13380 	scf_snapshot_t *snap;
13381 	scf_snaplevel_t *level;
13382 
13383 	lscf_prep_hndl();
13384 
13385 	if (cur_inst == NULL) {
13386 		semerr(gettext("Instance not selected.\n"));
13387 		return;
13388 	}
13389 
13390 	if (cur_snap != NULL) {
13391 		if (name != NULL) {
13392 			char *cur_snap_name;
13393 			boolean_t nochange;
13394 
13395 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
13396 
13397 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
13398 			    max_scf_name_len + 1) < 0)
13399 				scfdie();
13400 
13401 			nochange = strcmp(name, cur_snap_name) == 0;
13402 
13403 			free(cur_snap_name);
13404 
13405 			if (nochange)
13406 				return;
13407 		}
13408 
13409 		unselect_cursnap();
13410 	}
13411 
13412 	if (name == NULL)
13413 		return;
13414 
13415 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13416 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
13417 		scfdie();
13418 
13419 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
13420 	    SCF_SUCCESS) {
13421 		switch (scf_error()) {
13422 		case SCF_ERROR_INVALID_ARGUMENT:
13423 			semerr(gettext("Invalid name \"%s\".\n"), name);
13424 			break;
13425 
13426 		case SCF_ERROR_NOT_FOUND:
13427 			semerr(gettext("No such snapshot \"%s\".\n"), name);
13428 			break;
13429 
13430 		default:
13431 			scfdie();
13432 		}
13433 
13434 		scf_snaplevel_destroy(level);
13435 		scf_snapshot_destroy(snap);
13436 		return;
13437 	}
13438 
13439 	/* Load the snaplevels into our list. */
13440 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
13441 	if (cur_levels == NULL)
13442 		uu_die(gettext("Could not create list: %s\n"),
13443 		    uu_strerror(uu_error()));
13444 
13445 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13446 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13447 			scfdie();
13448 
13449 		semerr(gettext("Snapshot has no snaplevels.\n"));
13450 
13451 		scf_snaplevel_destroy(level);
13452 		scf_snapshot_destroy(snap);
13453 		return;
13454 	}
13455 
13456 	cur_snap = snap;
13457 
13458 	for (;;) {
13459 		cur_elt = safe_malloc(sizeof (*cur_elt));
13460 		uu_list_node_init(cur_elt, &cur_elt->list_node,
13461 		    snaplevel_pool);
13462 		cur_elt->sl = level;
13463 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
13464 			uu_die(gettext("libuutil error: %s\n"),
13465 			    uu_strerror(uu_error()));
13466 
13467 		level = scf_snaplevel_create(g_hndl);
13468 		if (level == NULL)
13469 			scfdie();
13470 
13471 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
13472 		    level) != SCF_SUCCESS) {
13473 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13474 				scfdie();
13475 
13476 			scf_snaplevel_destroy(level);
13477 			break;
13478 		}
13479 	}
13480 
13481 	cur_elt = uu_list_last(cur_levels);
13482 	cur_level = cur_elt->sl;
13483 }
13484 
13485 /*
13486  * Copies the properties & values in src to dst.  Assumes src won't change.
13487  * Returns -1 if permission is denied, -2 if another transaction interrupts,
13488  * and 0 on success.
13489  *
13490  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
13491  * property, if it is copied and has type boolean.  (See comment in
13492  * lscf_revert()).
13493  */
13494 static int
13495 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
13496     uint8_t enabled)
13497 {
13498 	scf_transaction_t *tx;
13499 	scf_iter_t *iter, *viter;
13500 	scf_property_t *prop;
13501 	scf_value_t *v;
13502 	char *nbuf;
13503 	int r;
13504 
13505 	tx = scf_transaction_create(g_hndl);
13506 	if (tx == NULL)
13507 		scfdie();
13508 
13509 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
13510 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13511 			scfdie();
13512 
13513 		scf_transaction_destroy(tx);
13514 
13515 		return (-1);
13516 	}
13517 
13518 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13519 	    (prop = scf_property_create(g_hndl)) == NULL ||
13520 	    (viter = scf_iter_create(g_hndl)) == NULL)
13521 		scfdie();
13522 
13523 	nbuf = safe_malloc(max_scf_name_len + 1);
13524 
13525 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
13526 		scfdie();
13527 
13528 	for (;;) {
13529 		scf_transaction_entry_t *e;
13530 		scf_type_t ty;
13531 
13532 		r = scf_iter_next_property(iter, prop);
13533 		if (r == -1)
13534 			scfdie();
13535 		if (r == 0)
13536 			break;
13537 
13538 		e = scf_entry_create(g_hndl);
13539 		if (e == NULL)
13540 			scfdie();
13541 
13542 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
13543 			scfdie();
13544 
13545 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
13546 			scfdie();
13547 
13548 		if (scf_transaction_property_new(tx, e, nbuf,
13549 		    ty) != SCF_SUCCESS)
13550 			scfdie();
13551 
13552 		if ((enabled == 0 || enabled == 1) &&
13553 		    strcmp(nbuf, scf_property_enabled) == 0 &&
13554 		    ty == SCF_TYPE_BOOLEAN) {
13555 			v = scf_value_create(g_hndl);
13556 			if (v == NULL)
13557 				scfdie();
13558 
13559 			scf_value_set_boolean(v, enabled);
13560 
13561 			if (scf_entry_add_value(e, v) != 0)
13562 				scfdie();
13563 		} else {
13564 			if (scf_iter_property_values(viter, prop) != 0)
13565 				scfdie();
13566 
13567 			for (;;) {
13568 				v = scf_value_create(g_hndl);
13569 				if (v == NULL)
13570 					scfdie();
13571 
13572 				r = scf_iter_next_value(viter, v);
13573 				if (r == -1)
13574 					scfdie();
13575 				if (r == 0) {
13576 					scf_value_destroy(v);
13577 					break;
13578 				}
13579 
13580 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
13581 					scfdie();
13582 			}
13583 		}
13584 	}
13585 
13586 	free(nbuf);
13587 	scf_iter_destroy(viter);
13588 	scf_property_destroy(prop);
13589 	scf_iter_destroy(iter);
13590 
13591 	r = scf_transaction_commit(tx);
13592 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13593 		scfdie();
13594 
13595 	scf_transaction_destroy_children(tx);
13596 	scf_transaction_destroy(tx);
13597 
13598 	switch (r) {
13599 	case 1:		return (0);
13600 	case 0:		return (-2);
13601 	case -1:	return (-1);
13602 
13603 	default:
13604 		abort();
13605 	}
13606 
13607 	/* NOTREACHED */
13608 }
13609 
13610 void
13611 lscf_revert(const char *snapname)
13612 {
13613 	scf_snapshot_t *snap, *prev;
13614 	scf_snaplevel_t *level, *nlevel;
13615 	scf_iter_t *iter;
13616 	scf_propertygroup_t *pg, *npg;
13617 	scf_property_t *prop;
13618 	scf_value_t *val;
13619 	char *nbuf, *tbuf;
13620 	uint8_t enabled;
13621 
13622 	lscf_prep_hndl();
13623 
13624 	if (cur_inst == NULL) {
13625 		semerr(gettext("Instance not selected.\n"));
13626 		return;
13627 	}
13628 
13629 	if (snapname != NULL) {
13630 		snap = scf_snapshot_create(g_hndl);
13631 		if (snap == NULL)
13632 			scfdie();
13633 
13634 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
13635 		    SCF_SUCCESS) {
13636 			switch (scf_error()) {
13637 			case SCF_ERROR_INVALID_ARGUMENT:
13638 				semerr(gettext("Invalid snapshot name "
13639 				    "\"%s\".\n"), snapname);
13640 				break;
13641 
13642 			case SCF_ERROR_NOT_FOUND:
13643 				semerr(gettext("No such snapshot.\n"));
13644 				break;
13645 
13646 			default:
13647 				scfdie();
13648 			}
13649 
13650 			scf_snapshot_destroy(snap);
13651 			return;
13652 		}
13653 	} else {
13654 		if (cur_snap != NULL) {
13655 			snap = cur_snap;
13656 		} else {
13657 			semerr(gettext("No snapshot selected.\n"));
13658 			return;
13659 		}
13660 	}
13661 
13662 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
13663 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
13664 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13665 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13666 	    (npg = scf_pg_create(g_hndl)) == NULL ||
13667 	    (prop = scf_property_create(g_hndl)) == NULL ||
13668 	    (val = scf_value_create(g_hndl)) == NULL)
13669 		scfdie();
13670 
13671 	nbuf = safe_malloc(max_scf_name_len + 1);
13672 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
13673 
13674 	/* Take the "previous" snapshot before we blow away the properties. */
13675 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
13676 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
13677 			scfdie();
13678 	} else {
13679 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13680 			scfdie();
13681 
13682 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
13683 			scfdie();
13684 	}
13685 
13686 	/* Save general/enabled, since we're probably going to replace it. */
13687 	enabled = 2;
13688 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
13689 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
13690 	    scf_property_get_value(prop, val) == 0)
13691 		(void) scf_value_get_boolean(val, &enabled);
13692 
13693 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13694 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13695 			scfdie();
13696 
13697 		goto out;
13698 	}
13699 
13700 	for (;;) {
13701 		boolean_t isinst;
13702 		uint32_t flags;
13703 		int r;
13704 
13705 		/* Clear the properties from the corresponding entity. */
13706 		isinst = snaplevel_is_instance(level);
13707 
13708 		if (!isinst)
13709 			r = scf_iter_service_pgs(iter, cur_svc);
13710 		else
13711 			r = scf_iter_instance_pgs(iter, cur_inst);
13712 		if (r != SCF_SUCCESS)
13713 			scfdie();
13714 
13715 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13716 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13717 				scfdie();
13718 
13719 			/* Skip nonpersistent pgs. */
13720 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
13721 				continue;
13722 
13723 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
13724 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13725 					scfdie();
13726 
13727 				semerr(emsg_permission_denied);
13728 				goto out;
13729 			}
13730 		}
13731 		if (r == -1)
13732 			scfdie();
13733 
13734 		/* Copy the properties to the corresponding entity. */
13735 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
13736 			scfdie();
13737 
13738 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13739 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
13740 				scfdie();
13741 
13742 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
13743 			    0)
13744 				scfdie();
13745 
13746 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13747 				scfdie();
13748 
13749 			if (!isinst)
13750 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
13751 				    flags, npg);
13752 			else
13753 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
13754 				    flags, npg);
13755 			if (r != SCF_SUCCESS) {
13756 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13757 					scfdie();
13758 
13759 				semerr(emsg_permission_denied);
13760 				goto out;
13761 			}
13762 
13763 			if ((enabled == 0 || enabled == 1) &&
13764 			    strcmp(nbuf, scf_pg_general) == 0)
13765 				r = pg_copy(pg, npg, enabled);
13766 			else
13767 				r = pg_copy(pg, npg, 2);
13768 
13769 			switch (r) {
13770 			case 0:
13771 				break;
13772 
13773 			case -1:
13774 				semerr(emsg_permission_denied);
13775 				goto out;
13776 
13777 			case -2:
13778 				semerr(gettext(
13779 				    "Interrupted by another change.\n"));
13780 				goto out;
13781 
13782 			default:
13783 				abort();
13784 			}
13785 		}
13786 		if (r == -1)
13787 			scfdie();
13788 
13789 		/* Get next level. */
13790 		nlevel = scf_snaplevel_create(g_hndl);
13791 		if (nlevel == NULL)
13792 			scfdie();
13793 
13794 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
13795 		    SCF_SUCCESS) {
13796 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13797 				scfdie();
13798 
13799 			scf_snaplevel_destroy(nlevel);
13800 			break;
13801 		}
13802 
13803 		scf_snaplevel_destroy(level);
13804 		level = nlevel;
13805 	}
13806 
13807 	if (snapname == NULL) {
13808 		lscf_selectsnap(NULL);
13809 		snap = NULL;		/* cur_snap has been destroyed */
13810 	}
13811 
13812 out:
13813 	free(tbuf);
13814 	free(nbuf);
13815 	scf_value_destroy(val);
13816 	scf_property_destroy(prop);
13817 	scf_pg_destroy(npg);
13818 	scf_pg_destroy(pg);
13819 	scf_iter_destroy(iter);
13820 	scf_snaplevel_destroy(level);
13821 	scf_snapshot_destroy(prev);
13822 	if (snap != cur_snap)
13823 		scf_snapshot_destroy(snap);
13824 }
13825 
13826 void
13827 lscf_refresh(void)
13828 {
13829 	ssize_t fmrilen;
13830 	size_t bufsz;
13831 	char *fmribuf;
13832 	int r;
13833 
13834 	lscf_prep_hndl();
13835 
13836 	if (cur_inst == NULL) {
13837 		semerr(gettext("Instance not selected.\n"));
13838 		return;
13839 	}
13840 
13841 	bufsz = max_scf_fmri_len + 1;
13842 	fmribuf = safe_malloc(bufsz);
13843 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
13844 	if (fmrilen < 0) {
13845 		free(fmribuf);
13846 		if (scf_error() != SCF_ERROR_DELETED)
13847 			scfdie();
13848 		scf_instance_destroy(cur_inst);
13849 		cur_inst = NULL;
13850 		warn(emsg_deleted);
13851 		return;
13852 	}
13853 	assert(fmrilen < bufsz);
13854 
13855 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
13856 	switch (r) {
13857 	case 0:
13858 		break;
13859 
13860 	case ECONNABORTED:
13861 		warn(gettext("Could not refresh %s "
13862 		    "(repository connection broken).\n"), fmribuf);
13863 		break;
13864 
13865 	case ECANCELED:
13866 		warn(emsg_deleted);
13867 		break;
13868 
13869 	case EPERM:
13870 		warn(gettext("Could not refresh %s "
13871 		    "(permission denied).\n"), fmribuf);
13872 		break;
13873 
13874 	case ENOSPC:
13875 		warn(gettext("Could not refresh %s "
13876 		    "(repository server out of resources).\n"),
13877 		    fmribuf);
13878 		break;
13879 
13880 	case EACCES:
13881 	default:
13882 		bad_error("refresh_entity", scf_error());
13883 	}
13884 
13885 	free(fmribuf);
13886 }
13887 
13888 /*
13889  * describe [-v] [-t] [pg/prop]
13890  */
13891 int
13892 lscf_describe(uu_list_t *args, int hasargs)
13893 {
13894 	int ret = 0;
13895 	size_t i;
13896 	int argc;
13897 	char **argv = NULL;
13898 	string_list_t *slp;
13899 	int do_verbose = 0;
13900 	int do_templates = 0;
13901 	char *pattern = NULL;
13902 
13903 	lscf_prep_hndl();
13904 
13905 	if (hasargs != 0)  {
13906 		argc = uu_list_numnodes(args);
13907 		if (argc < 1)
13908 			goto usage;
13909 
13910 		argv = calloc(argc + 1, sizeof (char *));
13911 		if (argv == NULL)
13912 			uu_die(gettext("Out of memory.\n"));
13913 
13914 		for (slp = uu_list_first(args), i = 0;
13915 		    slp != NULL;
13916 		    slp = uu_list_next(args, slp), ++i)
13917 			argv[i] = slp->str;
13918 
13919 		argv[i] = NULL;
13920 
13921 		/*
13922 		 * We start optind = 0 because our list of arguments
13923 		 * starts at argv[0]
13924 		 */
13925 		optind = 0;
13926 		opterr = 0;
13927 		for (;;) {
13928 			ret = getopt(argc, argv, "vt");
13929 			if (ret == -1)
13930 				break;
13931 
13932 			switch (ret) {
13933 			case 'v':
13934 				do_verbose = 1;
13935 				break;
13936 
13937 			case 't':
13938 				do_templates = 1;
13939 				break;
13940 
13941 			case '?':
13942 				goto usage;
13943 
13944 			default:
13945 				bad_error("getopt", ret);
13946 			}
13947 		}
13948 
13949 		pattern = argv[optind];
13950 	}
13951 
13952 	if (cur_inst == NULL && cur_svc == NULL) {
13953 		semerr(emsg_entity_not_selected);
13954 		ret = -1;
13955 		goto out;
13956 	}
13957 
13958 	/*
13959 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
13960 	 * output if their last parameter is set to 2.  Less information is
13961 	 * produced if the parameter is set to 1.
13962 	 */
13963 	if (pattern == NULL) {
13964 		if (do_verbose == 1)
13965 			list_entity_tmpl(2);
13966 		else
13967 			list_entity_tmpl(1);
13968 	}
13969 
13970 	if (do_templates == 0) {
13971 		if (do_verbose == 1)
13972 			listprop(pattern, 0, 2);
13973 		else
13974 			listprop(pattern, 0, 1);
13975 	} else {
13976 		if (do_verbose == 1)
13977 			listtmpl(pattern, 2);
13978 		else
13979 			listtmpl(pattern, 1);
13980 	}
13981 
13982 	ret = 0;
13983 out:
13984 	if (argv != NULL)
13985 		free(argv);
13986 	return (ret);
13987 usage:
13988 	ret = -2;
13989 	goto out;
13990 }
13991 
13992 #ifndef NATIVE_BUILD
13993 /* ARGSUSED */
13994 CPL_MATCH_FN(complete_select)
13995 {
13996 	const char *arg0, *arg1, *arg1end;
13997 	int word_start, err = 0, r;
13998 	size_t len;
13999 	char *buf;
14000 
14001 	lscf_prep_hndl();
14002 
14003 	arg0 = line + strspn(line, " \t");
14004 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
14005 
14006 	arg1 = arg0 + sizeof ("select") - 1;
14007 	arg1 += strspn(arg1, " \t");
14008 	word_start = arg1 - line;
14009 
14010 	arg1end = arg1 + strcspn(arg1, " \t");
14011 	if (arg1end < line + word_end)
14012 		return (0);
14013 
14014 	len = line + word_end - arg1;
14015 
14016 	buf = safe_malloc(max_scf_name_len + 1);
14017 
14018 	if (cur_snap != NULL) {
14019 		return (0);
14020 	} else if (cur_inst != NULL) {
14021 		return (0);
14022 	} else if (cur_svc != NULL) {
14023 		scf_instance_t *inst;
14024 		scf_iter_t *iter;
14025 
14026 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
14027 		    (iter = scf_iter_create(g_hndl)) == NULL)
14028 			scfdie();
14029 
14030 		if (scf_iter_service_instances(iter, cur_svc) != 0)
14031 			scfdie();
14032 
14033 		for (;;) {
14034 			r = scf_iter_next_instance(iter, inst);
14035 			if (r == 0)
14036 				break;
14037 			if (r != 1)
14038 				scfdie();
14039 
14040 			if (scf_instance_get_name(inst, buf,
14041 			    max_scf_name_len + 1) < 0)
14042 				scfdie();
14043 
14044 			if (strncmp(buf, arg1, len) == 0) {
14045 				err = cpl_add_completion(cpl, line, word_start,
14046 				    word_end, buf + len, "", " ");
14047 				if (err != 0)
14048 					break;
14049 			}
14050 		}
14051 
14052 		scf_iter_destroy(iter);
14053 		scf_instance_destroy(inst);
14054 
14055 		return (err);
14056 	} else {
14057 		scf_service_t *svc;
14058 		scf_iter_t *iter;
14059 
14060 		assert(cur_scope != NULL);
14061 
14062 		if ((svc = scf_service_create(g_hndl)) == NULL ||
14063 		    (iter = scf_iter_create(g_hndl)) == NULL)
14064 			scfdie();
14065 
14066 		if (scf_iter_scope_services(iter, cur_scope) != 0)
14067 			scfdie();
14068 
14069 		for (;;) {
14070 			r = scf_iter_next_service(iter, svc);
14071 			if (r == 0)
14072 				break;
14073 			if (r != 1)
14074 				scfdie();
14075 
14076 			if (scf_service_get_name(svc, buf,
14077 			    max_scf_name_len + 1) < 0)
14078 				scfdie();
14079 
14080 			if (strncmp(buf, arg1, len) == 0) {
14081 				err = cpl_add_completion(cpl, line, word_start,
14082 				    word_end, buf + len, "", " ");
14083 				if (err != 0)
14084 					break;
14085 			}
14086 		}
14087 
14088 		scf_iter_destroy(iter);
14089 		scf_service_destroy(svc);
14090 
14091 		return (err);
14092 	}
14093 }
14094 
14095 /* ARGSUSED */
14096 CPL_MATCH_FN(complete_command)
14097 {
14098 	uint32_t scope = 0;
14099 
14100 	if (cur_snap != NULL)
14101 		scope = CS_SNAP;
14102 	else if (cur_inst != NULL)
14103 		scope = CS_INST;
14104 	else if (cur_svc != NULL)
14105 		scope = CS_SVC;
14106 	else
14107 		scope = CS_SCOPE;
14108 
14109 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
14110 }
14111 #endif	/* NATIVE_BUILD */
14112