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