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