xref: /titanic_50/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision a23420cf95f05ac67f2c299116a3225581e519d1)
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 2010 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 #include <poll.h>
49 
50 #include <libxml/tree.h>
51 
52 #include <sys/param.h>
53 
54 #include <sys/stat.h>
55 #include <sys/mman.h>
56 
57 #include "svccfg.h"
58 #include "manifest_hash.h"
59 #include "manifest_find.h"
60 
61 /* The colon namespaces in each entity (each followed by a newline). */
62 #define	COLON_NAMESPACES	":properties\n"
63 
64 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
65 
66 /* These are characters which the lexer requires to be in double-quotes. */
67 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
68 
69 #define	HASH_SIZE		16
70 #define	HASH_PG_TYPE		"framework"
71 #define	HASH_PG_FLAGS		0
72 #define	HASH_PROP		"md5sum"
73 
74 /*
75  * Indentation used in the output of the describe subcommand.
76  */
77 #define	TMPL_VALUE_INDENT	"  "
78 #define	TMPL_INDENT		"    "
79 #define	TMPL_INDENT_2X		"        "
80 #define	TMPL_CHOICE_INDENT	"      "
81 
82 /*
83  * Directory locations for manifests
84  */
85 #define	VARSVC_DIR		"/var/svc/manifest"
86 #define	LIBSVC_DIR		"/lib/svc/manifest"
87 #define	VARSVC_PR		"var_svc_manifest"
88 #define	LIBSVC_PR		"lib_svc_manifest"
89 #define	MFSTFILEPR		"manifestfile"
90 
91 #define	SUPPORTPROP		"support"
92 
93 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
94 
95 #define	MFSTFILE_MAX		16
96 
97 /*
98  * These are the classes of elements which may appear as children of service
99  * or instance elements in XML manifests.
100  */
101 struct entity_elts {
102 	xmlNodePtr	create_default_instance;
103 	xmlNodePtr	single_instance;
104 	xmlNodePtr	restarter;
105 	xmlNodePtr	dependencies;
106 	xmlNodePtr	dependents;
107 	xmlNodePtr	method_context;
108 	xmlNodePtr	exec_methods;
109 	xmlNodePtr	property_groups;
110 	xmlNodePtr	instances;
111 	xmlNodePtr	stability;
112 	xmlNodePtr	template;
113 };
114 
115 /*
116  * Likewise for property_group elements.
117  */
118 struct pg_elts {
119 	xmlNodePtr	stability;
120 	xmlNodePtr	propvals;
121 	xmlNodePtr	properties;
122 };
123 
124 /*
125  * Likewise for template elements.
126  */
127 struct template_elts {
128 	xmlNodePtr	common_name;
129 	xmlNodePtr	description;
130 	xmlNodePtr	documentation;
131 };
132 
133 /*
134  * This structure is for snaplevel lists.  They are convenient because libscf
135  * only allows traversing snaplevels in one direction.
136  */
137 struct snaplevel {
138 	uu_list_node_t	list_node;
139 	scf_snaplevel_t	*sl;
140 };
141 
142 /*
143  * This is used for communication between lscf_service_export and
144  * export_callback.
145  */
146 struct export_args {
147 	const char	*filename;
148 	int 		flags;
149 };
150 
151 /*
152  * The service_manifest structure is used by the upgrade process
153  * to create a list of service to manifest linkages from the manifests
154  * in a set of given directories.
155  */
156 typedef struct service_manifest {
157 	const char 	*servicename;
158 	uu_list_t	*mfstlist;
159 	size_t	mfstlist_sz;
160 
161 	uu_avl_node_t	svcmfst_node;
162 } service_manifest_t;
163 
164 /*
165  * Structure to track the manifest file property group
166  * and the manifest file associated with that property
167  * group.  Also, a flag to keep the access once it has
168  * been checked.
169  */
170 struct mpg_mfile {
171 	char	*mpg;
172 	char	*mfile;
173 	int	access;
174 };
175 
176 const char * const scf_pg_general = SCF_PG_GENERAL;
177 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
178 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
179 const char * const scf_property_external = "external";
180 
181 const char * const snap_initial = "initial";
182 const char * const snap_lastimport = "last-import";
183 const char * const snap_previous = "previous";
184 const char * const snap_running = "running";
185 
186 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
187 
188 ssize_t max_scf_fmri_len;
189 ssize_t max_scf_name_len;
190 ssize_t max_scf_pg_type_len;
191 ssize_t max_scf_value_len;
192 static size_t max_scf_len;
193 
194 static scf_scope_t *cur_scope;
195 static scf_service_t *cur_svc = NULL;
196 static scf_instance_t *cur_inst = NULL;
197 static scf_snapshot_t *cur_snap = NULL;
198 static scf_snaplevel_t *cur_level = NULL;
199 
200 static uu_list_pool_t *snaplevel_pool;
201 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
202 static uu_list_t *cur_levels;
203 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
204 
205 static FILE *tempfile = NULL;
206 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
207 
208 static const char *emsg_entity_not_selected;
209 static const char *emsg_permission_denied;
210 static const char *emsg_create_xml;
211 static const char *emsg_cant_modify_snapshots;
212 static const char *emsg_read_only;
213 static const char *emsg_deleted;
214 static const char *emsg_invalid_pg_name;
215 static const char *emsg_invalid_prop_name;
216 static const char *emsg_no_such_pg;
217 static const char *emsg_fmri_invalid_pg_name;
218 static const char *emsg_fmri_invalid_pg_name_type;
219 static const char *emsg_pg_added;
220 static const char *emsg_pg_changed;
221 static const char *emsg_pg_deleted;
222 static const char *emsg_pg_mod_perm;
223 static const char *emsg_pg_add_perm;
224 static const char *emsg_pg_del_perm;
225 static const char *emsg_snap_perm;
226 static const char *emsg_dpt_dangling;
227 static const char *emsg_dpt_no_dep;
228 
229 static int li_only = 0;
230 static int no_refresh = 0;
231 
232 /* import globals, to minimize allocations */
233 static scf_scope_t *imp_scope = NULL;
234 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
235 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
236 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
237 static scf_snapshot_t *imp_rsnap = NULL;
238 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
239 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
240 static scf_property_t *imp_prop = NULL;
241 static scf_iter_t *imp_iter = NULL;
242 static scf_iter_t *imp_rpg_iter = NULL;
243 static scf_iter_t *imp_up_iter = NULL;
244 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
245 static char *imp_str = NULL;
246 static size_t imp_str_sz;
247 static char *imp_tsname = NULL;
248 static char *imp_fe1 = NULL;		/* for fmri_equal() */
249 static char *imp_fe2 = NULL;
250 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
251 
252 /* upgrade_dependents() globals */
253 static scf_instance_t *ud_inst = NULL;
254 static scf_snaplevel_t *ud_snpl = NULL;
255 static scf_propertygroup_t *ud_pg = NULL;
256 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
257 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
258 static int ud_run_dpts_pg_set = 0;
259 static scf_property_t *ud_prop = NULL;
260 static scf_property_t *ud_dpt_prop = NULL;
261 static scf_value_t *ud_val = NULL;
262 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
263 static scf_transaction_t *ud_tx = NULL;
264 static char *ud_ctarg = NULL;
265 static char *ud_oldtarg = NULL;
266 static char *ud_name = NULL;
267 
268 /* export globals */
269 static scf_instance_t *exp_inst;
270 static scf_propertygroup_t *exp_pg;
271 static scf_property_t *exp_prop;
272 static scf_value_t *exp_val;
273 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
274 static char *exp_str;
275 static size_t exp_str_sz;
276 
277 /* cleanup globals */
278 static uu_avl_pool_t *service_manifest_pool = NULL;
279 static uu_avl_t *service_manifest_tree = NULL;
280 
281 static void scfdie_lineno(int lineno) __NORETURN;
282 
283 static char *start_method_names[] = {
284 	"start",
285 	"inetd_start",
286 	NULL
287 };
288 
289 static void
290 safe_printf(const char *fmt, ...)
291 {
292 	va_list va;
293 
294 	va_start(va, fmt);
295 	if (vprintf(fmt, va) < 0)
296 		uu_die(gettext("Error writing to stdout"));
297 	va_end(va);
298 }
299 
300 /*
301  * For unexpected libscf errors.
302  */
303 #ifdef NDEBUG
304 
305 static void scfdie(void) __NORETURN;
306 
307 static void
308 scfdie(void)
309 {
310 	scf_error_t err = scf_error();
311 
312 	if (err == SCF_ERROR_CONNECTION_BROKEN)
313 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
314 
315 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
316 	    scf_strerror(err));
317 }
318 
319 #else
320 
321 #define	scfdie()	scfdie_lineno(__LINE__)
322 
323 static void
324 scfdie_lineno(int lineno)
325 {
326 	scf_error_t err = scf_error();
327 
328 	if (err == SCF_ERROR_CONNECTION_BROKEN)
329 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
330 
331 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
332 	    ": %s.\n"), lineno, scf_strerror(err));
333 }
334 
335 #endif
336 
337 static void
338 scfwarn(void)
339 {
340 	warn(gettext("Unexpected libscf error: %s.\n"),
341 	    scf_strerror(scf_error()));
342 }
343 
344 /*
345  * Clear a field of a structure.
346  */
347 static int
348 clear_int(void *a, void *b)
349 {
350 	/* LINTED */
351 	*(int *)((char *)a + (size_t)b) = 0;
352 
353 	return (UU_WALK_NEXT);
354 }
355 
356 static int
357 scferror2errno(scf_error_t err)
358 {
359 	switch (err) {
360 	case SCF_ERROR_BACKEND_ACCESS:
361 		return (EACCES);
362 
363 	case SCF_ERROR_BACKEND_READONLY:
364 		return (EROFS);
365 
366 	case SCF_ERROR_CONNECTION_BROKEN:
367 		return (ECONNABORTED);
368 
369 	case SCF_ERROR_CONSTRAINT_VIOLATED:
370 	case SCF_ERROR_INVALID_ARGUMENT:
371 		return (EINVAL);
372 
373 	case SCF_ERROR_DELETED:
374 		return (ECANCELED);
375 
376 	case SCF_ERROR_EXISTS:
377 		return (EEXIST);
378 
379 	case SCF_ERROR_NO_MEMORY:
380 		return (ENOMEM);
381 
382 	case SCF_ERROR_NO_RESOURCES:
383 		return (ENOSPC);
384 
385 	case SCF_ERROR_NOT_FOUND:
386 		return (ENOENT);
387 
388 	case SCF_ERROR_PERMISSION_DENIED:
389 		return (EPERM);
390 
391 	default:
392 #ifndef NDEBUG
393 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
394 		    __FILE__, __LINE__, err);
395 #else
396 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
397 #endif
398 		abort();
399 		/* NOTREACHED */
400 	}
401 }
402 
403 static int
404 entity_get_pg(void *ent, int issvc, const char *name,
405     scf_propertygroup_t *pg)
406 {
407 	if (issvc)
408 		return (scf_service_get_pg(ent, name, pg));
409 	else
410 		return (scf_instance_get_pg(ent, name, pg));
411 }
412 
413 static void
414 entity_destroy(void *ent, int issvc)
415 {
416 	if (issvc)
417 		scf_service_destroy(ent);
418 	else
419 		scf_instance_destroy(ent);
420 }
421 
422 static int
423 get_pg(const char *pg_name, scf_propertygroup_t *pg)
424 {
425 	int ret;
426 
427 	if (cur_level != NULL)
428 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
429 	else if (cur_inst != NULL)
430 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
431 	else
432 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
433 
434 	return (ret);
435 }
436 
437 /*
438  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
439  * snaplevel.  Otherwise find the instance snaplevel.
440  *
441  * Returns
442  *   0 - success
443  *   ECONNABORTED - repository connection broken
444  *   ECANCELED - instance containing snap was deleted
445  *   ENOENT - snap has no snaplevels
446  *	    - requested snaplevel not found
447  */
448 static int
449 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
450 {
451 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
452 		switch (scf_error()) {
453 		case SCF_ERROR_CONNECTION_BROKEN:
454 		case SCF_ERROR_DELETED:
455 		case SCF_ERROR_NOT_FOUND:
456 			return (scferror2errno(scf_error()));
457 
458 		case SCF_ERROR_HANDLE_MISMATCH:
459 		case SCF_ERROR_NOT_BOUND:
460 		case SCF_ERROR_NOT_SET:
461 		default:
462 			bad_error("scf_snapshot_get_base_snaplevel",
463 			    scf_error());
464 		}
465 	}
466 
467 	for (;;) {
468 		ssize_t ssz;
469 
470 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
471 		if (ssz >= 0) {
472 			if (!get_svc)
473 				return (0);
474 		} else {
475 			switch (scf_error()) {
476 			case SCF_ERROR_CONSTRAINT_VIOLATED:
477 				if (get_svc)
478 					return (0);
479 				break;
480 
481 			case SCF_ERROR_DELETED:
482 			case SCF_ERROR_CONNECTION_BROKEN:
483 				return (scferror2errno(scf_error()));
484 
485 			case SCF_ERROR_NOT_SET:
486 			case SCF_ERROR_NOT_BOUND:
487 			default:
488 				bad_error("scf_snaplevel_get_instance_name",
489 				    scf_error());
490 			}
491 		}
492 
493 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
494 			switch (scf_error()) {
495 			case SCF_ERROR_NOT_FOUND:
496 			case SCF_ERROR_CONNECTION_BROKEN:
497 			case SCF_ERROR_DELETED:
498 				return (scferror2errno(scf_error()));
499 
500 			case SCF_ERROR_HANDLE_MISMATCH:
501 			case SCF_ERROR_NOT_BOUND:
502 			case SCF_ERROR_NOT_SET:
503 			case SCF_ERROR_INVALID_ARGUMENT:
504 			default:
505 				bad_error("scf_snaplevel_get_next_snaplevel",
506 				    scf_error());
507 			}
508 		}
509 	}
510 }
511 
512 /*
513  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
514  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
515  * the property group named name in it.  If it doesn't have a running
516  * snapshot, set pg to the instance's current property group named name.
517  *
518  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
519  * its instances.  If one has a running snapshot with a service snaplevel, set
520  * pg to the property group named name in it.  If no such snaplevel could be
521  * found, set pg to the service's current property group named name.
522  *
523  * iter, inst, snap, and snpl are required scratch objects.
524  *
525  * Returns
526  *   0 - success
527  *   ECONNABORTED - repository connection broken
528  *   ECANCELED - ent was deleted
529  *   ENOENT - no such property group
530  *   EINVAL - name is an invalid property group name
531  *   EBADF - found running snapshot is missing a snaplevel
532  */
533 static int
534 entity_get_running_pg(void *ent, int issvc, const char *name,
535     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
536     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
537 {
538 	int r;
539 
540 	if (issvc) {
541 		/* Search for an instance with a running snapshot. */
542 		if (scf_iter_service_instances(iter, ent) != 0) {
543 			switch (scf_error()) {
544 			case SCF_ERROR_DELETED:
545 			case SCF_ERROR_CONNECTION_BROKEN:
546 				return (scferror2errno(scf_error()));
547 
548 			case SCF_ERROR_NOT_SET:
549 			case SCF_ERROR_NOT_BOUND:
550 			case SCF_ERROR_HANDLE_MISMATCH:
551 			default:
552 				bad_error("scf_iter_service_instances",
553 				    scf_error());
554 			}
555 		}
556 
557 		for (;;) {
558 			r = scf_iter_next_instance(iter, inst);
559 			if (r == 0) {
560 				if (scf_service_get_pg(ent, name, pg) == 0)
561 					return (0);
562 
563 				switch (scf_error()) {
564 				case SCF_ERROR_DELETED:
565 				case SCF_ERROR_NOT_FOUND:
566 				case SCF_ERROR_INVALID_ARGUMENT:
567 				case SCF_ERROR_CONNECTION_BROKEN:
568 					return (scferror2errno(scf_error()));
569 
570 				case SCF_ERROR_NOT_BOUND:
571 				case SCF_ERROR_HANDLE_MISMATCH:
572 				case SCF_ERROR_NOT_SET:
573 				default:
574 					bad_error("scf_service_get_pg",
575 					    scf_error());
576 				}
577 			}
578 			if (r != 1) {
579 				switch (scf_error()) {
580 				case SCF_ERROR_DELETED:
581 				case SCF_ERROR_CONNECTION_BROKEN:
582 					return (scferror2errno(scf_error()));
583 
584 				case SCF_ERROR_INVALID_ARGUMENT:
585 				case SCF_ERROR_NOT_SET:
586 				case SCF_ERROR_NOT_BOUND:
587 				case SCF_ERROR_HANDLE_MISMATCH:
588 				default:
589 					bad_error("scf_iter_next_instance",
590 					    scf_error());
591 				}
592 			}
593 
594 			if (scf_instance_get_snapshot(inst, snap_running,
595 			    snap) == 0)
596 				break;
597 
598 			switch (scf_error()) {
599 			case SCF_ERROR_NOT_FOUND:
600 			case SCF_ERROR_DELETED:
601 				continue;
602 
603 			case SCF_ERROR_CONNECTION_BROKEN:
604 				return (ECONNABORTED);
605 
606 			case SCF_ERROR_HANDLE_MISMATCH:
607 			case SCF_ERROR_INVALID_ARGUMENT:
608 			case SCF_ERROR_NOT_SET:
609 			case SCF_ERROR_NOT_BOUND:
610 			default:
611 				bad_error("scf_instance_get_snapshot",
612 				    scf_error());
613 			}
614 		}
615 	} else {
616 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
617 			switch (scf_error()) {
618 			case SCF_ERROR_NOT_FOUND:
619 				break;
620 
621 			case SCF_ERROR_DELETED:
622 			case SCF_ERROR_CONNECTION_BROKEN:
623 				return (scferror2errno(scf_error()));
624 
625 			case SCF_ERROR_NOT_BOUND:
626 			case SCF_ERROR_HANDLE_MISMATCH:
627 			case SCF_ERROR_INVALID_ARGUMENT:
628 			case SCF_ERROR_NOT_SET:
629 			default:
630 				bad_error("scf_instance_get_snapshot",
631 				    scf_error());
632 			}
633 
634 			if (scf_instance_get_pg(ent, name, pg) == 0)
635 				return (0);
636 
637 			switch (scf_error()) {
638 			case SCF_ERROR_DELETED:
639 			case SCF_ERROR_NOT_FOUND:
640 			case SCF_ERROR_INVALID_ARGUMENT:
641 			case SCF_ERROR_CONNECTION_BROKEN:
642 				return (scferror2errno(scf_error()));
643 
644 			case SCF_ERROR_NOT_BOUND:
645 			case SCF_ERROR_HANDLE_MISMATCH:
646 			case SCF_ERROR_NOT_SET:
647 			default:
648 				bad_error("scf_instance_get_pg", scf_error());
649 			}
650 		}
651 	}
652 
653 	r = get_snaplevel(snap, issvc, snpl);
654 	switch (r) {
655 	case 0:
656 		break;
657 
658 	case ECONNABORTED:
659 	case ECANCELED:
660 		return (r);
661 
662 	case ENOENT:
663 		return (EBADF);
664 
665 	default:
666 		bad_error("get_snaplevel", r);
667 	}
668 
669 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
670 		return (0);
671 
672 	switch (scf_error()) {
673 	case SCF_ERROR_DELETED:
674 	case SCF_ERROR_INVALID_ARGUMENT:
675 	case SCF_ERROR_CONNECTION_BROKEN:
676 	case SCF_ERROR_NOT_FOUND:
677 		return (scferror2errno(scf_error()));
678 
679 	case SCF_ERROR_NOT_BOUND:
680 	case SCF_ERROR_HANDLE_MISMATCH:
681 	case SCF_ERROR_NOT_SET:
682 	default:
683 		bad_error("scf_snaplevel_get_pg", scf_error());
684 		/* NOTREACHED */
685 	}
686 }
687 
688 /*
689  * To be registered with atexit().
690  */
691 static void
692 remove_tempfile(void)
693 {
694 	int ret;
695 
696 	if (tempfile != NULL) {
697 		if (fclose(tempfile) == EOF)
698 			(void) warn(gettext("Could not close temporary file"));
699 		tempfile = NULL;
700 	}
701 
702 	if (tempfilename[0] != '\0') {
703 		do {
704 			ret = remove(tempfilename);
705 		} while (ret == -1 && errno == EINTR);
706 		if (ret == -1)
707 			warn(gettext("Could not remove temporary file"));
708 		tempfilename[0] = '\0';
709 	}
710 }
711 
712 /*
713  * Launch private svc.configd(1M) for manipulating alternate repositories.
714  */
715 static void
716 start_private_repository(engine_state_t *est)
717 {
718 	int fd, stat;
719 	struct door_info info;
720 	pid_t pid;
721 
722 	/*
723 	 * 1.  Create a temporary file for the door.
724 	 */
725 	if (est->sc_repo_doorname != NULL)
726 		free((void *)est->sc_repo_doorname);
727 
728 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
729 	if (est->sc_repo_doorname == NULL)
730 		uu_die(gettext("Could not acquire temporary filename"));
731 
732 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
733 	if (fd < 0)
734 		uu_die(gettext("Could not create temporary file for "
735 		    "repository server"));
736 
737 	(void) close(fd);
738 
739 	/*
740 	 * 2.  Launch a configd with that door, using the specified
741 	 * repository.
742 	 */
743 	if ((est->sc_repo_pid = fork()) == 0) {
744 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
745 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
746 		    NULL);
747 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
748 	} else if (est->sc_repo_pid == -1)
749 		uu_die(gettext("Attempt to fork failed"));
750 
751 	do {
752 		pid = waitpid(est->sc_repo_pid, &stat, 0);
753 	} while (pid == -1 && errno == EINTR);
754 
755 	if (pid == -1)
756 		uu_die(gettext("Could not waitpid() for repository server"));
757 
758 	if (!WIFEXITED(stat)) {
759 		uu_die(gettext("Repository server failed (status %d).\n"),
760 		    stat);
761 	} else if (WEXITSTATUS(stat) != 0) {
762 		uu_die(gettext("Repository server failed (exit %d).\n"),
763 		    WEXITSTATUS(stat));
764 	}
765 
766 	/*
767 	 * See if it was successful by checking if the door is a door.
768 	 */
769 
770 	fd = open(est->sc_repo_doorname, O_RDWR);
771 	if (fd < 0)
772 		uu_die(gettext("Could not open door \"%s\""),
773 		    est->sc_repo_doorname);
774 
775 	if (door_info(fd, &info) < 0)
776 		uu_die(gettext("Unexpected door_info() error"));
777 
778 	if (close(fd) == -1)
779 		warn(gettext("Could not close repository door"),
780 		    strerror(errno));
781 
782 	est->sc_repo_pid = info.di_target;
783 }
784 
785 void
786 lscf_cleanup(void)
787 {
788 	/*
789 	 * In the case where we've launched a private svc.configd(1M)
790 	 * instance, we must terminate our child and remove the temporary
791 	 * rendezvous point.
792 	 */
793 	if (est->sc_repo_pid > 0) {
794 		(void) kill(est->sc_repo_pid, SIGTERM);
795 		(void) waitpid(est->sc_repo_pid, NULL, 0);
796 		(void) unlink(est->sc_repo_doorname);
797 
798 		est->sc_repo_pid = 0;
799 	}
800 }
801 
802 void
803 unselect_cursnap(void)
804 {
805 	void *cookie;
806 
807 	cur_level = NULL;
808 
809 	cookie = NULL;
810 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
811 		scf_snaplevel_destroy(cur_elt->sl);
812 		free(cur_elt);
813 	}
814 
815 	scf_snapshot_destroy(cur_snap);
816 	cur_snap = NULL;
817 }
818 
819 void
820 lscf_prep_hndl(void)
821 {
822 	if (g_hndl != NULL)
823 		return;
824 
825 	g_hndl = scf_handle_create(SCF_VERSION);
826 	if (g_hndl == NULL)
827 		scfdie();
828 
829 	if (est->sc_repo_filename != NULL)
830 		start_private_repository(est);
831 
832 	if (est->sc_repo_doorname != NULL) {
833 		scf_value_t *repo_value;
834 		int ret;
835 
836 		repo_value = scf_value_create(g_hndl);
837 		if (repo_value == NULL)
838 			scfdie();
839 
840 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
841 		assert(ret == SCF_SUCCESS);
842 
843 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
844 		    SCF_SUCCESS)
845 			scfdie();
846 
847 		scf_value_destroy(repo_value);
848 	}
849 
850 	if (scf_handle_bind(g_hndl) != 0)
851 		uu_die(gettext("Could not connect to repository server: %s.\n"),
852 		    scf_strerror(scf_error()));
853 
854 	cur_scope = scf_scope_create(g_hndl);
855 	if (cur_scope == NULL)
856 		scfdie();
857 
858 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
859 		scfdie();
860 }
861 
862 static void
863 repository_teardown(void)
864 {
865 	if (g_hndl != NULL) {
866 		if (cur_snap != NULL)
867 			unselect_cursnap();
868 		scf_instance_destroy(cur_inst);
869 		scf_service_destroy(cur_svc);
870 		scf_scope_destroy(cur_scope);
871 		scf_handle_destroy(g_hndl);
872 		cur_inst = NULL;
873 		cur_svc = NULL;
874 		cur_scope = NULL;
875 		g_hndl = NULL;
876 		lscf_cleanup();
877 	}
878 }
879 
880 void
881 lscf_set_repository(const char *repfile, int force)
882 {
883 	repository_teardown();
884 
885 	if (est->sc_repo_filename != NULL) {
886 		free((void *)est->sc_repo_filename);
887 		est->sc_repo_filename = NULL;
888 	}
889 
890 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
891 		/*
892 		 * Repository file does not exist
893 		 * or has no read permission.
894 		 */
895 		warn(gettext("Cannot access \"%s\": %s\n"),
896 		    repfile, strerror(errno));
897 	} else {
898 		est->sc_repo_filename = safe_strdup(repfile);
899 	}
900 
901 	lscf_prep_hndl();
902 }
903 
904 void
905 lscf_init()
906 {
907 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
908 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
909 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
910 	    0 ||
911 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
912 		scfdie();
913 
914 	max_scf_len = max_scf_fmri_len;
915 	if (max_scf_name_len > max_scf_len)
916 		max_scf_len = max_scf_name_len;
917 	if (max_scf_pg_type_len > max_scf_len)
918 		max_scf_len = max_scf_pg_type_len;
919 	if (max_scf_value_len > max_scf_len)
920 		max_scf_len = max_scf_value_len;
921 
922 	if (atexit(remove_tempfile) != 0)
923 		uu_die(gettext("Could not register atexit() function"));
924 
925 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
926 	emsg_permission_denied = gettext("Permission denied.\n");
927 	emsg_create_xml = gettext("Could not create XML node.\n");
928 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
929 	emsg_read_only = gettext("Backend read-only.\n");
930 	emsg_deleted = gettext("Current selection has been deleted.\n");
931 	emsg_invalid_pg_name =
932 	    gettext("Invalid property group name \"%s\".\n");
933 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
934 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
935 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
936 	    "with invalid name \"%s\".\n");
937 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
938 	    "group with invalid name \"%s\" or type \"%s\".\n");
939 	emsg_pg_added = gettext("%s changed unexpectedly "
940 	    "(property group \"%s\" added).\n");
941 	emsg_pg_changed = gettext("%s changed unexpectedly "
942 	    "(property group \"%s\" changed).\n");
943 	emsg_pg_deleted = gettext("%s changed unexpectedly "
944 	    "(property group \"%s\" or an ancestor was deleted).\n");
945 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
946 	    "in %s (permission denied).\n");
947 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
948 	    "in %s (permission denied).\n");
949 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
950 	    "in %s (permission denied).\n");
951 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
952 	    "(permission denied).\n");
953 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
954 	    "new dependent \"%s\" because it already exists).  Warning: The "
955 	    "current dependent's target (%s) does not exist.\n");
956 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
957 	    "dependent \"%s\" because it already exists).  Warning: The "
958 	    "current dependent's target (%s) does not have a dependency named "
959 	    "\"%s\" as expected.\n");
960 
961 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
962 	    offsetof(string_list_t, node), NULL, 0);
963 	snaplevel_pool = uu_list_pool_create("snaplevels",
964 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
965 	    NULL, 0);
966 }
967 
968 
969 static const char *
970 prop_to_typestr(const scf_property_t *prop)
971 {
972 	scf_type_t ty;
973 
974 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
975 		scfdie();
976 
977 	return (scf_type_to_string(ty));
978 }
979 
980 static scf_type_t
981 string_to_type(const char *type)
982 {
983 	size_t len = strlen(type);
984 	char *buf;
985 
986 	if (len == 0 || type[len - 1] != ':')
987 		return (SCF_TYPE_INVALID);
988 
989 	buf = (char *)alloca(len + 1);
990 	(void) strlcpy(buf, type, len + 1);
991 	buf[len - 1] = 0;
992 
993 	return (scf_string_to_type(buf));
994 }
995 
996 static scf_value_t *
997 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
998 {
999 	scf_value_t *v;
1000 	char *dup, *nstr;
1001 	size_t len;
1002 
1003 	v = scf_value_create(g_hndl);
1004 	if (v == NULL)
1005 		scfdie();
1006 
1007 	len = strlen(str);
1008 	if (require_quotes &&
1009 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1010 		semerr(gettext("Multiple string values or string values "
1011 		    "with spaces must be quoted with '\"'.\n"));
1012 		scf_value_destroy(v);
1013 		return (NULL);
1014 	}
1015 
1016 	nstr = dup = safe_strdup(str);
1017 	if (dup[0] == '\"') {
1018 		/*
1019 		 * Strip out the first and the last quote.
1020 		 */
1021 		dup[len - 1] = '\0';
1022 		nstr = dup + 1;
1023 	}
1024 
1025 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1026 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1027 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1028 		    scf_type_to_string(ty), nstr);
1029 		scf_value_destroy(v);
1030 		v = NULL;
1031 	}
1032 	free(dup);
1033 	return (v);
1034 }
1035 
1036 /*
1037  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1038  * Optionally append a comment prefix ('#') to newlines ('\n').
1039  */
1040 static int
1041 quote_and_print(const char *str, FILE *strm, int commentnl)
1042 {
1043 	const char *cp;
1044 
1045 	for (cp = str; *cp != '\0'; ++cp) {
1046 		if (*cp == '"' || *cp == '\\')
1047 			(void) putc('\\', strm);
1048 
1049 		(void) putc(*cp, strm);
1050 
1051 		if (commentnl && *cp == '\n') {
1052 			(void) putc('#', strm);
1053 		}
1054 	}
1055 
1056 	return (ferror(strm));
1057 }
1058 
1059 /*
1060  * These wrappers around lowlevel functions provide consistent error checking
1061  * and warnings.
1062  */
1063 static int
1064 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1065 {
1066 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1067 		return (0);
1068 
1069 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1070 		scfdie();
1071 
1072 	if (g_verbose) {
1073 		ssize_t len;
1074 		char *fmri;
1075 
1076 		len = scf_pg_to_fmri(pg, NULL, 0);
1077 		if (len < 0)
1078 			scfdie();
1079 
1080 		fmri = safe_malloc(len + 1);
1081 
1082 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1083 			scfdie();
1084 
1085 		warn(gettext("Expected property %s of property group %s is "
1086 		    "missing.\n"), propname, fmri);
1087 
1088 		free(fmri);
1089 	}
1090 
1091 	return (-1);
1092 }
1093 
1094 static int
1095 prop_check_type(scf_property_t *prop, scf_type_t ty)
1096 {
1097 	scf_type_t pty;
1098 
1099 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1100 		scfdie();
1101 
1102 	if (ty == pty)
1103 		return (0);
1104 
1105 	if (g_verbose) {
1106 		ssize_t len;
1107 		char *fmri;
1108 		const char *tystr;
1109 
1110 		len = scf_property_to_fmri(prop, NULL, 0);
1111 		if (len < 0)
1112 			scfdie();
1113 
1114 		fmri = safe_malloc(len + 1);
1115 
1116 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1117 			scfdie();
1118 
1119 		tystr = scf_type_to_string(ty);
1120 		if (tystr == NULL)
1121 			tystr = "?";
1122 
1123 		warn(gettext("Property %s is not of expected type %s.\n"),
1124 		    fmri, tystr);
1125 
1126 		free(fmri);
1127 	}
1128 
1129 	return (-1);
1130 }
1131 
1132 static int
1133 prop_get_val(scf_property_t *prop, scf_value_t *val)
1134 {
1135 	scf_error_t err;
1136 
1137 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1138 		return (0);
1139 
1140 	err = scf_error();
1141 
1142 	if (err != SCF_ERROR_NOT_FOUND &&
1143 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1144 	    err != SCF_ERROR_PERMISSION_DENIED)
1145 		scfdie();
1146 
1147 	if (g_verbose) {
1148 		ssize_t len;
1149 		char *fmri, *emsg;
1150 
1151 		len = scf_property_to_fmri(prop, NULL, 0);
1152 		if (len < 0)
1153 			scfdie();
1154 
1155 		fmri = safe_malloc(len + 1);
1156 
1157 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1158 			scfdie();
1159 
1160 		if (err == SCF_ERROR_NOT_FOUND)
1161 			emsg = gettext("Property %s has no values; expected "
1162 			    "one.\n");
1163 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1164 			emsg = gettext("Property %s has multiple values; "
1165 			    "expected one.\n");
1166 		else
1167 			emsg = gettext("No permission to read property %s.\n");
1168 
1169 		warn(emsg, fmri);
1170 
1171 		free(fmri);
1172 	}
1173 
1174 	return (-1);
1175 }
1176 
1177 
1178 static boolean_t
1179 snaplevel_is_instance(const scf_snaplevel_t *level)
1180 {
1181 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1182 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1183 			scfdie();
1184 		return (0);
1185 	} else {
1186 		return (1);
1187 	}
1188 }
1189 
1190 /*
1191  * Decode FMRI into a service or instance, and put the result in *ep.  If
1192  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1193  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1194  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1195  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1196  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1197  * whether *ep is a service.
1198  */
1199 static scf_error_t
1200 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1201 {
1202 	char *fmri_copy;
1203 	const char *sstr, *istr, *pgstr;
1204 	scf_service_t *svc;
1205 	scf_instance_t *inst;
1206 
1207 	fmri_copy = strdup(fmri);
1208 	if (fmri_copy == NULL)
1209 		return (SCF_ERROR_NO_MEMORY);
1210 
1211 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1212 	    SCF_SUCCESS) {
1213 		free(fmri_copy);
1214 		return (SCF_ERROR_INVALID_ARGUMENT);
1215 	}
1216 
1217 	free(fmri_copy);
1218 
1219 	if (sstr == NULL || pgstr != NULL)
1220 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1221 
1222 	if (istr == NULL) {
1223 		svc = scf_service_create(h);
1224 		if (svc == NULL)
1225 			return (SCF_ERROR_NO_MEMORY);
1226 
1227 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1228 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1229 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1230 				scfdie();
1231 
1232 			return (SCF_ERROR_NOT_FOUND);
1233 		}
1234 
1235 		*ep = svc;
1236 		*isservice = 1;
1237 	} else {
1238 		inst = scf_instance_create(h);
1239 		if (inst == NULL)
1240 			return (SCF_ERROR_NO_MEMORY);
1241 
1242 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1243 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1244 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1245 				scfdie();
1246 
1247 			return (SCF_ERROR_NOT_FOUND);
1248 		}
1249 
1250 		*ep = inst;
1251 		*isservice = 0;
1252 	}
1253 
1254 	return (SCF_ERROR_NONE);
1255 }
1256 
1257 /*
1258  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1259  * *ep, and set or clear *isservicep if it is a service or an instance.
1260  * Returns
1261  *   SCF_ERROR_NONE - success
1262  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1263  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1264  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1265  *   SCF_ERROR_NOT_FOUND - no such scope
1266  *   SCF_ERROR_PERMISSION_DENIED
1267  *   SCF_ERROR_BACKEND_READONLY
1268  *   SCF_ERROR_BACKEND_ACCESS
1269  */
1270 static scf_error_t
1271 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1272 {
1273 	char *fmri_copy;
1274 	const char *scstr, *sstr, *istr, *pgstr;
1275 	scf_scope_t *scope = NULL;
1276 	scf_service_t *svc = NULL;
1277 	scf_instance_t *inst = NULL;
1278 	scf_error_t scfe;
1279 
1280 	fmri_copy = safe_strdup(fmri);
1281 
1282 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1283 	    0) {
1284 		free(fmri_copy);
1285 		return (SCF_ERROR_INVALID_ARGUMENT);
1286 	}
1287 
1288 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1289 		free(fmri_copy);
1290 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1291 	}
1292 
1293 	*ep = NULL;
1294 
1295 	if ((scope = scf_scope_create(h)) == NULL ||
1296 	    (svc = scf_service_create(h)) == NULL ||
1297 	    (inst = scf_instance_create(h)) == NULL) {
1298 		scfe = SCF_ERROR_NO_MEMORY;
1299 		goto out;
1300 	}
1301 
1302 get_scope:
1303 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1304 		switch (scf_error()) {
1305 		case SCF_ERROR_CONNECTION_BROKEN:
1306 			scfdie();
1307 			/* NOTREACHED */
1308 
1309 		case SCF_ERROR_NOT_FOUND:
1310 			scfe = SCF_ERROR_NOT_FOUND;
1311 			goto out;
1312 
1313 		case SCF_ERROR_HANDLE_MISMATCH:
1314 		case SCF_ERROR_NOT_BOUND:
1315 		case SCF_ERROR_INVALID_ARGUMENT:
1316 		default:
1317 			bad_error("scf_handle_get_scope", scf_error());
1318 		}
1319 	}
1320 
1321 get_svc:
1322 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1323 		switch (scf_error()) {
1324 		case SCF_ERROR_CONNECTION_BROKEN:
1325 			scfdie();
1326 			/* NOTREACHED */
1327 
1328 		case SCF_ERROR_DELETED:
1329 			goto get_scope;
1330 
1331 		case SCF_ERROR_NOT_FOUND:
1332 			break;
1333 
1334 		case SCF_ERROR_HANDLE_MISMATCH:
1335 		case SCF_ERROR_INVALID_ARGUMENT:
1336 		case SCF_ERROR_NOT_BOUND:
1337 		case SCF_ERROR_NOT_SET:
1338 		default:
1339 			bad_error("scf_scope_get_service", scf_error());
1340 		}
1341 
1342 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1343 			switch (scf_error()) {
1344 			case SCF_ERROR_CONNECTION_BROKEN:
1345 				scfdie();
1346 				/* NOTREACHED */
1347 
1348 			case SCF_ERROR_DELETED:
1349 				goto get_scope;
1350 
1351 			case SCF_ERROR_PERMISSION_DENIED:
1352 			case SCF_ERROR_BACKEND_READONLY:
1353 			case SCF_ERROR_BACKEND_ACCESS:
1354 				scfe = scf_error();
1355 				goto out;
1356 
1357 			case SCF_ERROR_HANDLE_MISMATCH:
1358 			case SCF_ERROR_INVALID_ARGUMENT:
1359 			case SCF_ERROR_NOT_BOUND:
1360 			case SCF_ERROR_NOT_SET:
1361 			default:
1362 				bad_error("scf_scope_get_service", scf_error());
1363 			}
1364 		}
1365 	}
1366 
1367 	if (istr == NULL) {
1368 		scfe = SCF_ERROR_NONE;
1369 		*ep = svc;
1370 		*isservicep = 1;
1371 		goto out;
1372 	}
1373 
1374 get_inst:
1375 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1376 		switch (scf_error()) {
1377 		case SCF_ERROR_CONNECTION_BROKEN:
1378 			scfdie();
1379 			/* NOTREACHED */
1380 
1381 		case SCF_ERROR_DELETED:
1382 			goto get_svc;
1383 
1384 		case SCF_ERROR_NOT_FOUND:
1385 			break;
1386 
1387 		case SCF_ERROR_HANDLE_MISMATCH:
1388 		case SCF_ERROR_INVALID_ARGUMENT:
1389 		case SCF_ERROR_NOT_BOUND:
1390 		case SCF_ERROR_NOT_SET:
1391 		default:
1392 			bad_error("scf_service_get_instance", scf_error());
1393 		}
1394 
1395 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1396 			switch (scf_error()) {
1397 			case SCF_ERROR_CONNECTION_BROKEN:
1398 				scfdie();
1399 				/* NOTREACHED */
1400 
1401 			case SCF_ERROR_DELETED:
1402 				goto get_svc;
1403 
1404 			case SCF_ERROR_PERMISSION_DENIED:
1405 			case SCF_ERROR_BACKEND_READONLY:
1406 			case SCF_ERROR_BACKEND_ACCESS:
1407 				scfe = scf_error();
1408 				goto out;
1409 
1410 			case SCF_ERROR_HANDLE_MISMATCH:
1411 			case SCF_ERROR_INVALID_ARGUMENT:
1412 			case SCF_ERROR_NOT_BOUND:
1413 			case SCF_ERROR_NOT_SET:
1414 			default:
1415 				bad_error("scf_service_add_instance",
1416 				    scf_error());
1417 			}
1418 		}
1419 	}
1420 
1421 	scfe = SCF_ERROR_NONE;
1422 	*ep = inst;
1423 	*isservicep = 0;
1424 
1425 out:
1426 	if (*ep != inst)
1427 		scf_instance_destroy(inst);
1428 	if (*ep != svc)
1429 		scf_service_destroy(svc);
1430 	scf_scope_destroy(scope);
1431 	free(fmri_copy);
1432 	return (scfe);
1433 }
1434 
1435 /*
1436  * Create or update a snapshot of inst.  snap is a required scratch object.
1437  *
1438  * Returns
1439  *   0 - success
1440  *   ECONNABORTED - repository connection broken
1441  *   EPERM - permission denied
1442  *   ENOSPC - configd is out of resources
1443  *   ECANCELED - inst was deleted
1444  *   -1 - unknown libscf error (message printed)
1445  */
1446 static int
1447 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1448 {
1449 again:
1450 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1451 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1452 			switch (scf_error()) {
1453 			case SCF_ERROR_CONNECTION_BROKEN:
1454 			case SCF_ERROR_PERMISSION_DENIED:
1455 			case SCF_ERROR_NO_RESOURCES:
1456 				return (scferror2errno(scf_error()));
1457 
1458 			case SCF_ERROR_NOT_SET:
1459 			case SCF_ERROR_INVALID_ARGUMENT:
1460 			default:
1461 				bad_error("_scf_snapshot_take_attach",
1462 				    scf_error());
1463 			}
1464 		}
1465 	} else {
1466 		switch (scf_error()) {
1467 		case SCF_ERROR_NOT_FOUND:
1468 			break;
1469 
1470 		case SCF_ERROR_DELETED:
1471 		case SCF_ERROR_CONNECTION_BROKEN:
1472 			return (scferror2errno(scf_error()));
1473 
1474 		case SCF_ERROR_HANDLE_MISMATCH:
1475 		case SCF_ERROR_NOT_BOUND:
1476 		case SCF_ERROR_INVALID_ARGUMENT:
1477 		case SCF_ERROR_NOT_SET:
1478 		default:
1479 			bad_error("scf_instance_get_snapshot", scf_error());
1480 		}
1481 
1482 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1483 			switch (scf_error()) {
1484 			case SCF_ERROR_EXISTS:
1485 				goto again;
1486 
1487 			case SCF_ERROR_CONNECTION_BROKEN:
1488 			case SCF_ERROR_NO_RESOURCES:
1489 			case SCF_ERROR_PERMISSION_DENIED:
1490 				return (scferror2errno(scf_error()));
1491 
1492 			default:
1493 				scfwarn();
1494 				return (-1);
1495 
1496 			case SCF_ERROR_NOT_SET:
1497 			case SCF_ERROR_INTERNAL:
1498 			case SCF_ERROR_INVALID_ARGUMENT:
1499 			case SCF_ERROR_HANDLE_MISMATCH:
1500 				bad_error("_scf_snapshot_take_new",
1501 				    scf_error());
1502 			}
1503 		}
1504 	}
1505 
1506 	return (0);
1507 }
1508 
1509 static int
1510 refresh_running_snapshot(void *entity)
1511 {
1512 	scf_snapshot_t *snap;
1513 	int r;
1514 
1515 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1516 		scfdie();
1517 	r = take_snap(entity, snap_running, snap);
1518 	scf_snapshot_destroy(snap);
1519 
1520 	return (r);
1521 }
1522 
1523 /*
1524  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1525  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1526  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1527  * for scratch space.  Returns
1528  *   0 - success
1529  *   ECONNABORTED - repository connection broken
1530  *   ECANCELED - entity was deleted
1531  *   EACCES - backend denied access
1532  *   EPERM - permission denied
1533  *   ENOSPC - repository server out of resources
1534  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1535  */
1536 static int
1537 refresh_entity(int isservice, void *entity, const char *fmri,
1538     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1539 {
1540 	scf_error_t scfe;
1541 	int r;
1542 
1543 	if (!isservice) {
1544 		/*
1545 		 * Let restarter handles refreshing and making new running
1546 		 * snapshot only if operating on a live repository and not
1547 		 * running in early import.
1548 		 */
1549 		if (est->sc_repo_filename == NULL &&
1550 		    est->sc_repo_doorname == NULL &&
1551 		    est->sc_in_emi == 0) {
1552 			if (_smf_refresh_instance_i(entity) == 0) {
1553 				if (g_verbose)
1554 					warn(gettext("Refreshed %s.\n"), fmri);
1555 				return (0);
1556 			}
1557 
1558 			switch (scf_error()) {
1559 			case SCF_ERROR_BACKEND_ACCESS:
1560 				return (EACCES);
1561 
1562 			case SCF_ERROR_PERMISSION_DENIED:
1563 				return (EPERM);
1564 
1565 			default:
1566 				return (-1);
1567 			}
1568 		} else {
1569 			r = refresh_running_snapshot(entity);
1570 			switch (r) {
1571 			case 0:
1572 				break;
1573 
1574 			case ECONNABORTED:
1575 			case ECANCELED:
1576 			case EPERM:
1577 			case ENOSPC:
1578 				break;
1579 
1580 			default:
1581 				bad_error("refresh_running_snapshot",
1582 				    scf_error());
1583 			}
1584 
1585 			return (r);
1586 		}
1587 	}
1588 
1589 	if (scf_iter_service_instances(iter, entity) != 0) {
1590 		switch (scf_error()) {
1591 		case SCF_ERROR_CONNECTION_BROKEN:
1592 			return (ECONNABORTED);
1593 
1594 		case SCF_ERROR_DELETED:
1595 			return (ECANCELED);
1596 
1597 		case SCF_ERROR_HANDLE_MISMATCH:
1598 		case SCF_ERROR_NOT_BOUND:
1599 		case SCF_ERROR_NOT_SET:
1600 		default:
1601 			bad_error("scf_iter_service_instances", scf_error());
1602 		}
1603 	}
1604 
1605 	for (;;) {
1606 		r = scf_iter_next_instance(iter, inst);
1607 		if (r == 0)
1608 			break;
1609 		if (r != 1) {
1610 			switch (scf_error()) {
1611 			case SCF_ERROR_CONNECTION_BROKEN:
1612 				return (ECONNABORTED);
1613 
1614 			case SCF_ERROR_DELETED:
1615 				return (ECANCELED);
1616 
1617 			case SCF_ERROR_HANDLE_MISMATCH:
1618 			case SCF_ERROR_NOT_BOUND:
1619 			case SCF_ERROR_NOT_SET:
1620 			case SCF_ERROR_INVALID_ARGUMENT:
1621 			default:
1622 				bad_error("scf_iter_next_instance",
1623 				    scf_error());
1624 			}
1625 		}
1626 
1627 		/*
1628 		 * Similarly, just take a new running snapshot if operating on
1629 		 * a non-live repository or running during early import.
1630 		 */
1631 		if (est->sc_repo_filename != NULL ||
1632 		    est->sc_repo_doorname != NULL ||
1633 		    est->sc_in_emi == 1) {
1634 			r = refresh_running_snapshot(inst);
1635 			switch (r) {
1636 			case 0:
1637 				continue;
1638 
1639 			case ECONNABORTED:
1640 			case ECANCELED:
1641 			case EPERM:
1642 			case ENOSPC:
1643 				break;
1644 			default:
1645 				bad_error("refresh_running_snapshot",
1646 				    scf_error());
1647 			}
1648 
1649 			return (r);
1650 
1651 		}
1652 
1653 		if (_smf_refresh_instance_i(inst) == 0) {
1654 			if (g_verbose) {
1655 				if (scf_instance_get_name(inst, name_buf,
1656 				    max_scf_name_len + 1) < 0)
1657 					(void) strcpy(name_buf, "?");
1658 
1659 				warn(gettext("Refreshed %s:%s.\n"),
1660 				    fmri, name_buf);
1661 			}
1662 		} else {
1663 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1664 			    g_verbose) {
1665 				scfe = scf_error();
1666 
1667 				if (scf_instance_to_fmri(inst, name_buf,
1668 				    max_scf_name_len + 1) < 0)
1669 					(void) strcpy(name_buf, "?");
1670 
1671 				warn(gettext(
1672 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1673 				    name_buf, scf_strerror(scfe));
1674 			}
1675 		}
1676 	}
1677 
1678 	return (0);
1679 }
1680 
1681 static void
1682 private_refresh(void)
1683 {
1684 	scf_instance_t *pinst = NULL;
1685 	scf_iter_t *piter = NULL;
1686 	ssize_t fmrilen;
1687 	size_t bufsz;
1688 	char *fmribuf;
1689 	void *ent;
1690 	int issvc;
1691 	int r;
1692 
1693 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1694 		return;
1695 
1696 	assert(cur_svc != NULL);
1697 
1698 	bufsz = max_scf_fmri_len + 1;
1699 	fmribuf = safe_malloc(bufsz);
1700 	if (cur_inst) {
1701 		issvc = 0;
1702 		ent = cur_inst;
1703 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1704 	} else {
1705 		issvc = 1;
1706 		ent = cur_svc;
1707 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1708 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1709 			scfdie();
1710 
1711 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1712 			scfdie();
1713 	}
1714 	if (fmrilen < 0) {
1715 		free(fmribuf);
1716 		if (scf_error() != SCF_ERROR_DELETED)
1717 			scfdie();
1718 
1719 		warn(emsg_deleted);
1720 		return;
1721 	}
1722 	assert(fmrilen < bufsz);
1723 
1724 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1725 	switch (r) {
1726 	case 0:
1727 		break;
1728 
1729 	case ECONNABORTED:
1730 		warn(gettext("Could not refresh %s "
1731 		    "(repository connection broken).\n"), fmribuf);
1732 		break;
1733 
1734 	case ECANCELED:
1735 		warn(emsg_deleted);
1736 		break;
1737 
1738 	case EPERM:
1739 		warn(gettext("Could not refresh %s "
1740 		    "(permission denied).\n"), fmribuf);
1741 		break;
1742 
1743 	case ENOSPC:
1744 		warn(gettext("Could not refresh %s "
1745 		    "(repository server out of resources).\n"),
1746 		    fmribuf);
1747 		break;
1748 
1749 	case EACCES:
1750 	default:
1751 		bad_error("refresh_entity", scf_error());
1752 	}
1753 
1754 	if (issvc) {
1755 		scf_instance_destroy(pinst);
1756 		scf_iter_destroy(piter);
1757 	}
1758 
1759 	free(fmribuf);
1760 }
1761 
1762 
1763 static int
1764 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1765 {
1766 	cbp->sc_err = scferror2errno(err);
1767 	return (UU_WALK_ERROR);
1768 }
1769 
1770 static int
1771 stash_scferror(scf_callback_t *cbp)
1772 {
1773 	return (stash_scferror_err(cbp, scf_error()));
1774 }
1775 
1776 /*
1777  * Import.  These functions import a bundle into the repository.
1778  */
1779 
1780 /*
1781  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
1782  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
1783  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1784  * lcbdata->sc_err to
1785  *   ENOMEM - out of memory
1786  *   ECONNABORTED - repository connection broken
1787  *   ECANCELED - sc_trans's property group was deleted
1788  *   EINVAL - p's name is invalid (error printed)
1789  *	    - p has an invalid value (error printed)
1790  */
1791 static int
1792 lscf_property_import(void *v, void *pvt)
1793 {
1794 	property_t *p = v;
1795 	scf_callback_t *lcbdata = pvt;
1796 	value_t *vp;
1797 	scf_transaction_t *trans = lcbdata->sc_trans;
1798 	scf_transaction_entry_t *entr;
1799 	scf_value_t *val;
1800 	scf_type_t tp;
1801 
1802 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
1803 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
1804 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
1805 		lcbdata->sc_enable = p;
1806 		return (UU_WALK_NEXT);
1807 	}
1808 
1809 	entr = scf_entry_create(lcbdata->sc_handle);
1810 	if (entr == NULL) {
1811 		switch (scf_error()) {
1812 		case SCF_ERROR_NO_MEMORY:
1813 			return (stash_scferror(lcbdata));
1814 
1815 		case SCF_ERROR_INVALID_ARGUMENT:
1816 		default:
1817 			bad_error("scf_entry_create", scf_error());
1818 		}
1819 	}
1820 
1821 	tp = p->sc_value_type;
1822 
1823 	if (scf_transaction_property_new(trans, entr,
1824 	    p->sc_property_name, tp) != 0) {
1825 		switch (scf_error()) {
1826 		case SCF_ERROR_INVALID_ARGUMENT:
1827 			semerr(emsg_invalid_prop_name, p->sc_property_name);
1828 			scf_entry_destroy(entr);
1829 			return (stash_scferror(lcbdata));
1830 
1831 		case SCF_ERROR_EXISTS:
1832 			break;
1833 
1834 		case SCF_ERROR_DELETED:
1835 		case SCF_ERROR_CONNECTION_BROKEN:
1836 			scf_entry_destroy(entr);
1837 			return (stash_scferror(lcbdata));
1838 
1839 		case SCF_ERROR_NOT_BOUND:
1840 		case SCF_ERROR_HANDLE_MISMATCH:
1841 		case SCF_ERROR_NOT_SET:
1842 		default:
1843 			bad_error("scf_transaction_property_new", scf_error());
1844 		}
1845 
1846 		if (scf_transaction_property_change_type(trans, entr,
1847 		    p->sc_property_name, tp) != 0) {
1848 			switch (scf_error()) {
1849 			case SCF_ERROR_DELETED:
1850 			case SCF_ERROR_CONNECTION_BROKEN:
1851 				scf_entry_destroy(entr);
1852 				return (stash_scferror(lcbdata));
1853 
1854 			case SCF_ERROR_INVALID_ARGUMENT:
1855 				semerr(emsg_invalid_prop_name,
1856 				    p->sc_property_name);
1857 				scf_entry_destroy(entr);
1858 				return (stash_scferror(lcbdata));
1859 
1860 			case SCF_ERROR_NOT_FOUND:
1861 			case SCF_ERROR_NOT_SET:
1862 			case SCF_ERROR_HANDLE_MISMATCH:
1863 			case SCF_ERROR_NOT_BOUND:
1864 			default:
1865 				bad_error(
1866 				    "scf_transaction_property_change_type",
1867 				    scf_error());
1868 			}
1869 		}
1870 	}
1871 
1872 	for (vp = uu_list_first(p->sc_property_values);
1873 	    vp != NULL;
1874 	    vp = uu_list_next(p->sc_property_values, vp)) {
1875 		val = scf_value_create(g_hndl);
1876 		if (val == NULL) {
1877 			switch (scf_error()) {
1878 			case SCF_ERROR_NO_MEMORY:
1879 				return (stash_scferror(lcbdata));
1880 
1881 			case SCF_ERROR_INVALID_ARGUMENT:
1882 			default:
1883 				bad_error("scf_value_create", scf_error());
1884 			}
1885 		}
1886 
1887 		switch (tp) {
1888 		case SCF_TYPE_BOOLEAN:
1889 			scf_value_set_boolean(val, vp->sc_u.sc_count);
1890 			break;
1891 		case SCF_TYPE_COUNT:
1892 			scf_value_set_count(val, vp->sc_u.sc_count);
1893 			break;
1894 		case SCF_TYPE_INTEGER:
1895 			scf_value_set_integer(val, vp->sc_u.sc_integer);
1896 			break;
1897 		default:
1898 			assert(vp->sc_u.sc_string != NULL);
1899 			if (scf_value_set_from_string(val, tp,
1900 			    vp->sc_u.sc_string) != 0) {
1901 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
1902 					bad_error("scf_value_set_from_string",
1903 					    scf_error());
1904 
1905 				warn(gettext("Value \"%s\" is not a valid "
1906 				    "%s.\n"), vp->sc_u.sc_string,
1907 				    scf_type_to_string(tp));
1908 				scf_value_destroy(val);
1909 				return (stash_scferror(lcbdata));
1910 			}
1911 			break;
1912 		}
1913 
1914 		if (scf_entry_add_value(entr, val) != 0)
1915 			bad_error("scf_entry_add_value", scf_error());
1916 	}
1917 
1918 	return (UU_WALK_NEXT);
1919 }
1920 
1921 /*
1922  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
1923  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
1924  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
1925  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1926  * lcbdata->sc_err to
1927  *   ECONNABORTED - repository connection broken
1928  *   ENOMEM - out of memory
1929  *   ENOSPC - svc.configd is out of resources
1930  *   ECANCELED - sc_parent was deleted
1931  *   EPERM - could not create property group (permission denied) (error printed)
1932  *	   - could not modify property group (permission denied) (error printed)
1933  *	   - could not delete property group (permission denied) (error	printed)
1934  *   EROFS - could not create property group (repository is read-only)
1935  *	   - could not delete property group (repository is read-only)
1936  *   EACCES - could not create property group (backend access denied)
1937  *	    - could not delete property group (backend access denied)
1938  *   EEXIST - could not create property group (already exists)
1939  *   EINVAL - invalid property group name (error printed)
1940  *	    - invalid property name (error printed)
1941  *	    - invalid value (error printed)
1942  *   EBUSY - new property group deleted (error printed)
1943  *	   - new property group changed (error printed)
1944  *	   - property group added (error printed)
1945  *	   - property group deleted (error printed)
1946  */
1947 static int
1948 entity_pgroup_import(void *v, void *pvt)
1949 {
1950 	pgroup_t *p = v;
1951 	scf_callback_t cbdata;
1952 	scf_callback_t *lcbdata = pvt;
1953 	void *ent = lcbdata->sc_parent;
1954 	int issvc = lcbdata->sc_service;
1955 	int r;
1956 
1957 	const char * const pg_changed = gettext("%s changed unexpectedly "
1958 	    "(new property group \"%s\" changed).\n");
1959 
1960 	/* Never import deleted property groups. */
1961 	if (p->sc_pgroup_delete)
1962 		return (UU_WALK_NEXT);
1963 
1964 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
1965 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
1966 		lcbdata->sc_general = p;
1967 		return (UU_WALK_NEXT);
1968 	}
1969 
1970 add_pg:
1971 	if (issvc)
1972 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
1973 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1974 	else
1975 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
1976 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1977 	if (r != 0) {
1978 		switch (scf_error()) {
1979 		case SCF_ERROR_DELETED:
1980 		case SCF_ERROR_CONNECTION_BROKEN:
1981 		case SCF_ERROR_BACKEND_READONLY:
1982 		case SCF_ERROR_BACKEND_ACCESS:
1983 		case SCF_ERROR_NO_RESOURCES:
1984 			return (stash_scferror(lcbdata));
1985 
1986 		case SCF_ERROR_EXISTS:
1987 			if (lcbdata->sc_flags & SCI_FORCE)
1988 				break;
1989 			return (stash_scferror(lcbdata));
1990 
1991 		case SCF_ERROR_INVALID_ARGUMENT:
1992 			warn(emsg_fmri_invalid_pg_name_type,
1993 			    lcbdata->sc_source_fmri,
1994 			    p->sc_pgroup_name, p->sc_pgroup_type);
1995 			return (stash_scferror(lcbdata));
1996 
1997 		case SCF_ERROR_PERMISSION_DENIED:
1998 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
1999 			    lcbdata->sc_target_fmri);
2000 			return (stash_scferror(lcbdata));
2001 
2002 		case SCF_ERROR_NOT_BOUND:
2003 		case SCF_ERROR_HANDLE_MISMATCH:
2004 		case SCF_ERROR_NOT_SET:
2005 		default:
2006 			bad_error("scf_service_add_pg", scf_error());
2007 		}
2008 
2009 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2010 			switch (scf_error()) {
2011 			case SCF_ERROR_CONNECTION_BROKEN:
2012 			case SCF_ERROR_DELETED:
2013 				return (stash_scferror(lcbdata));
2014 
2015 			case SCF_ERROR_INVALID_ARGUMENT:
2016 				warn(emsg_fmri_invalid_pg_name,
2017 				    lcbdata->sc_source_fmri,
2018 				    p->sc_pgroup_name);
2019 				return (stash_scferror(lcbdata));
2020 
2021 			case SCF_ERROR_NOT_FOUND:
2022 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2023 				    p->sc_pgroup_name);
2024 				lcbdata->sc_err = EBUSY;
2025 				return (UU_WALK_ERROR);
2026 
2027 			case SCF_ERROR_NOT_BOUND:
2028 			case SCF_ERROR_HANDLE_MISMATCH:
2029 			case SCF_ERROR_NOT_SET:
2030 			default:
2031 				bad_error("entity_get_pg", scf_error());
2032 			}
2033 		}
2034 
2035 		if (lcbdata->sc_flags & SCI_KEEP)
2036 			goto props;
2037 
2038 		if (scf_pg_delete(imp_pg) != 0) {
2039 			switch (scf_error()) {
2040 			case SCF_ERROR_DELETED:
2041 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2042 				    p->sc_pgroup_name);
2043 				lcbdata->sc_err = EBUSY;
2044 				return (UU_WALK_ERROR);
2045 
2046 			case SCF_ERROR_PERMISSION_DENIED:
2047 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2048 				    lcbdata->sc_target_fmri);
2049 				return (stash_scferror(lcbdata));
2050 
2051 			case SCF_ERROR_BACKEND_READONLY:
2052 			case SCF_ERROR_BACKEND_ACCESS:
2053 			case SCF_ERROR_CONNECTION_BROKEN:
2054 				return (stash_scferror(lcbdata));
2055 
2056 			case SCF_ERROR_NOT_SET:
2057 			default:
2058 				bad_error("scf_pg_delete", scf_error());
2059 			}
2060 		}
2061 
2062 		goto add_pg;
2063 	}
2064 
2065 props:
2066 
2067 	/*
2068 	 * Add properties to property group, if any.
2069 	 */
2070 	cbdata.sc_handle = lcbdata->sc_handle;
2071 	cbdata.sc_parent = imp_pg;
2072 	cbdata.sc_flags = lcbdata->sc_flags;
2073 	cbdata.sc_trans = imp_tx;
2074 	cbdata.sc_enable = NULL;
2075 
2076 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2077 		switch (scf_error()) {
2078 		case SCF_ERROR_BACKEND_ACCESS:
2079 		case SCF_ERROR_BACKEND_READONLY:
2080 		case SCF_ERROR_CONNECTION_BROKEN:
2081 			return (stash_scferror(lcbdata));
2082 
2083 		case SCF_ERROR_DELETED:
2084 			warn(pg_changed, lcbdata->sc_target_fmri,
2085 			    p->sc_pgroup_name);
2086 			lcbdata->sc_err = EBUSY;
2087 			return (UU_WALK_ERROR);
2088 
2089 		case SCF_ERROR_PERMISSION_DENIED:
2090 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2091 			    lcbdata->sc_target_fmri);
2092 			return (stash_scferror(lcbdata));
2093 
2094 		case SCF_ERROR_NOT_BOUND:
2095 		case SCF_ERROR_NOT_SET:
2096 		case SCF_ERROR_IN_USE:
2097 		case SCF_ERROR_HANDLE_MISMATCH:
2098 		default:
2099 			bad_error("scf_transaction_start", scf_error());
2100 		}
2101 	}
2102 
2103 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2104 	    UU_DEFAULT) != 0) {
2105 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2106 			bad_error("uu_list_walk", uu_error());
2107 		scf_transaction_reset(imp_tx);
2108 
2109 		lcbdata->sc_err = cbdata.sc_err;
2110 		if (cbdata.sc_err == ECANCELED) {
2111 			warn(pg_changed, lcbdata->sc_target_fmri,
2112 			    p->sc_pgroup_name);
2113 			lcbdata->sc_err = EBUSY;
2114 		}
2115 		return (UU_WALK_ERROR);
2116 	}
2117 
2118 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2119 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2120 
2121 		/*
2122 		 * take the snapshot running snapshot then
2123 		 * import the stored general/enable property
2124 		 */
2125 		r = take_snap(ent, snap_running, imp_rsnap);
2126 		switch (r) {
2127 		case 0:
2128 			break;
2129 
2130 		case ECONNABORTED:
2131 			warn(gettext("Could not take %s snapshot on import "
2132 			    "(repository connection broken).\n"),
2133 			    snap_running);
2134 			lcbdata->sc_err = r;
2135 			return (UU_WALK_ERROR);
2136 		case ECANCELED:
2137 			warn(emsg_deleted);
2138 			lcbdata->sc_err = r;
2139 			return (UU_WALK_ERROR);
2140 
2141 		case EPERM:
2142 			warn(gettext("Could not take %s snapshot "
2143 			    "(permission denied).\n"), snap_running);
2144 			lcbdata->sc_err = r;
2145 			return (UU_WALK_ERROR);
2146 
2147 		case ENOSPC:
2148 			warn(gettext("Could not take %s snapshot"
2149 			    "(repository server out of resources).\n"),
2150 			    snap_running);
2151 			lcbdata->sc_err = r;
2152 			return (UU_WALK_ERROR);
2153 
2154 		default:
2155 			bad_error("take_snap", r);
2156 		}
2157 
2158 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2159 		if (r != UU_WALK_NEXT) {
2160 			if (r != UU_WALK_ERROR)
2161 				bad_error("lscf_property_import", r);
2162 			return (EINVAL);
2163 		}
2164 	}
2165 
2166 	r = scf_transaction_commit(imp_tx);
2167 	switch (r) {
2168 	case 1:
2169 		r = UU_WALK_NEXT;
2170 		break;
2171 
2172 	case 0:
2173 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2174 		lcbdata->sc_err = EBUSY;
2175 		r = UU_WALK_ERROR;
2176 		break;
2177 
2178 	case -1:
2179 		switch (scf_error()) {
2180 		case SCF_ERROR_BACKEND_READONLY:
2181 		case SCF_ERROR_BACKEND_ACCESS:
2182 		case SCF_ERROR_CONNECTION_BROKEN:
2183 		case SCF_ERROR_NO_RESOURCES:
2184 			r = stash_scferror(lcbdata);
2185 			break;
2186 
2187 		case SCF_ERROR_DELETED:
2188 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2189 			    p->sc_pgroup_name);
2190 			lcbdata->sc_err = EBUSY;
2191 			r = UU_WALK_ERROR;
2192 			break;
2193 
2194 		case SCF_ERROR_PERMISSION_DENIED:
2195 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2196 			    lcbdata->sc_target_fmri);
2197 			r = stash_scferror(lcbdata);
2198 			break;
2199 
2200 		case SCF_ERROR_NOT_SET:
2201 		case SCF_ERROR_INVALID_ARGUMENT:
2202 		case SCF_ERROR_NOT_BOUND:
2203 		default:
2204 			bad_error("scf_transaction_commit", scf_error());
2205 		}
2206 		break;
2207 
2208 	default:
2209 		bad_error("scf_transaction_commit", r);
2210 	}
2211 
2212 	scf_transaction_destroy_children(imp_tx);
2213 
2214 	return (r);
2215 }
2216 
2217 /*
2218  * Returns
2219  *   0 - success
2220  *   ECONNABORTED - repository connection broken
2221  *   ENOMEM - out of memory
2222  *   ENOSPC - svc.configd is out of resources
2223  *   ECANCELED - inst was deleted
2224  *   EPERM - could not create property group (permission denied) (error printed)
2225  *	   - could not modify property group (permission denied) (error printed)
2226  *   EROFS - could not create property group (repository is read-only)
2227  *   EACCES - could not create property group (backend access denied)
2228  *   EEXIST - could not create property group (already exists)
2229  *   EINVAL - invalid property group name (error printed)
2230  *	    - invalid property name (error printed)
2231  *	    - invalid value (error printed)
2232  *   EBUSY - new property group changed (error printed)
2233  */
2234 static int
2235 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2236     const entity_t *isvc, int flags)
2237 {
2238 	scf_callback_t cbdata;
2239 
2240 	cbdata.sc_handle = scf_service_handle(svc);
2241 	cbdata.sc_parent = svc;
2242 	cbdata.sc_service = 1;
2243 	cbdata.sc_general = 0;
2244 	cbdata.sc_enable = 0;
2245 	cbdata.sc_flags = flags;
2246 	cbdata.sc_source_fmri = isvc->sc_fmri;
2247 	cbdata.sc_target_fmri = target_fmri;
2248 
2249 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2250 	    UU_DEFAULT) != 0) {
2251 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2252 			bad_error("uu_list_walk", uu_error());
2253 
2254 		return (cbdata.sc_err);
2255 	}
2256 
2257 	return (0);
2258 }
2259 
2260 /*
2261  * Returns
2262  *   0 - success
2263  *   ECONNABORTED - repository connection broken
2264  *   ENOMEM - out of memory
2265  *   ENOSPC - svc.configd is out of resources
2266  *   ECANCELED - inst was deleted
2267  *   EPERM - could not create property group (permission denied) (error printed)
2268  *	   - could not modify property group (permission denied) (error printed)
2269  *   EROFS - could not create property group (repository is read-only)
2270  *   EACCES - could not create property group (backend access denied)
2271  *   EEXIST - could not create property group (already exists)
2272  *   EINVAL - invalid property group name (error printed)
2273  *	    - invalid property name (error printed)
2274  *	    - invalid value (error printed)
2275  *   EBUSY - new property group changed (error printed)
2276  */
2277 static int
2278 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2279     const entity_t *iinst, int flags)
2280 {
2281 	scf_callback_t cbdata;
2282 
2283 	cbdata.sc_handle = scf_instance_handle(inst);
2284 	cbdata.sc_parent = inst;
2285 	cbdata.sc_service = 0;
2286 	cbdata.sc_general = NULL;
2287 	cbdata.sc_enable = NULL;
2288 	cbdata.sc_flags = flags;
2289 	cbdata.sc_source_fmri = iinst->sc_fmri;
2290 	cbdata.sc_target_fmri = target_fmri;
2291 
2292 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2293 	    UU_DEFAULT) != 0) {
2294 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2295 			bad_error("uu_list_walk", uu_error());
2296 
2297 		return (cbdata.sc_err);
2298 	}
2299 
2300 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2301 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2302 		/*
2303 		 * If importing with the SCI_NOENABLED flag then
2304 		 * skip the delay, but if not then add the delay
2305 		 * of the enable property.
2306 		 */
2307 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2308 			cbdata.sc_flags |= SCI_DELAYENABLE;
2309 		}
2310 
2311 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2312 		    != UU_WALK_NEXT)
2313 			return (cbdata.sc_err);
2314 	}
2315 
2316 	return (0);
2317 }
2318 
2319 /*
2320  * Report the reasons why we can't upgrade pg2 to pg1.
2321  */
2322 static void
2323 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2324     int new)
2325 {
2326 	property_t *p1, *p2;
2327 
2328 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2329 
2330 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2331 		return;
2332 
2333 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2334 	    p1 != NULL;
2335 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2336 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2337 		if (p2 != NULL) {
2338 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2339 			    new);
2340 			continue;
2341 		}
2342 
2343 		if (new)
2344 			warn(gettext("Conflict upgrading %s (new property "
2345 			    "group \"%s\" is missing property \"%s\").\n"),
2346 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2347 		else
2348 			warn(gettext("Conflict upgrading %s (property "
2349 			    "\"%s/%s\" is missing).\n"), fmri,
2350 			    pg1->sc_pgroup_name, p1->sc_property_name);
2351 	}
2352 
2353 	/*
2354 	 * Since pg1 should be from the manifest, any properties in pg2 which
2355 	 * aren't in pg1 shouldn't be reported as conflicts.
2356 	 */
2357 }
2358 
2359 /*
2360  * Add transaction entries to tx which will upgrade cur's pg according to old
2361  * & new.
2362  *
2363  * Returns
2364  *   0 - success
2365  *   EINVAL - new has a property with an invalid name or value (message emitted)
2366  *   ENOMEM - out of memory
2367  */
2368 static int
2369 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2370     pgroup_t *cur, int speak, const char *fmri)
2371 {
2372 	property_t *p, *new_p, *cur_p;
2373 	scf_transaction_entry_t *e;
2374 	int r;
2375 	int is_general;
2376 	int is_protected;
2377 
2378 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2379 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2380 		bad_error("uu_list_walk", uu_error());
2381 
2382 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2383 
2384 	for (p = uu_list_first(old->sc_pgroup_props);
2385 	    p != NULL;
2386 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2387 		/* p is a property in the old property group. */
2388 
2389 		/* Protect live properties. */
2390 		is_protected = 0;
2391 		if (is_general) {
2392 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2393 			    0 ||
2394 			    strcmp(p->sc_property_name,
2395 			    SCF_PROPERTY_RESTARTER) == 0)
2396 				is_protected = 1;
2397 		}
2398 
2399 		/* Look for the same property in the new properties. */
2400 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2401 		if (new_p != NULL) {
2402 			new_p->sc_seen = 1;
2403 
2404 			/*
2405 			 * If the new property is the same as the old, don't do
2406 			 * anything (leave any user customizations).
2407 			 */
2408 			if (prop_equal(p, new_p, NULL, NULL, 0))
2409 				continue;
2410 
2411 			if (new_p->sc_property_override)
2412 				goto upgrade;
2413 		}
2414 
2415 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2416 		if (cur_p == NULL) {
2417 			/*
2418 			 * p has been deleted from the repository.  If we were
2419 			 * going to delete it anyway, do nothing.  Otherwise
2420 			 * report a conflict.
2421 			 */
2422 			if (new_p == NULL)
2423 				continue;
2424 
2425 			if (is_protected)
2426 				continue;
2427 
2428 			warn(gettext("Conflict upgrading %s "
2429 			    "(property \"%s/%s\" is missing).\n"), fmri,
2430 			    old->sc_pgroup_name, p->sc_property_name);
2431 			continue;
2432 		}
2433 
2434 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2435 			/*
2436 			 * Conflict.  Don't warn if the property is already the
2437 			 * way we want it, though.
2438 			 */
2439 			if (is_protected)
2440 				continue;
2441 
2442 			if (new_p == NULL)
2443 				(void) prop_equal(p, cur_p, fmri,
2444 				    old->sc_pgroup_name, 0);
2445 			else
2446 				(void) prop_equal(cur_p, new_p, fmri,
2447 				    old->sc_pgroup_name, 0);
2448 			continue;
2449 		}
2450 
2451 		if (is_protected) {
2452 			if (speak)
2453 				warn(gettext("%s: Refusing to upgrade "
2454 				    "\"%s/%s\" (live property).\n"), fmri,
2455 				    old->sc_pgroup_name, p->sc_property_name);
2456 			continue;
2457 		}
2458 
2459 upgrade:
2460 		/* p hasn't been customized in the repository.  Upgrade it. */
2461 		if (new_p == NULL) {
2462 			/* p was deleted.  Delete from cur if unchanged. */
2463 			if (speak)
2464 				warn(gettext(
2465 				    "%s: Deleting property \"%s/%s\".\n"),
2466 				    fmri, old->sc_pgroup_name,
2467 				    p->sc_property_name);
2468 
2469 			e = scf_entry_create(g_hndl);
2470 			if (e == NULL)
2471 				return (ENOMEM);
2472 
2473 			if (scf_transaction_property_delete(tx, e,
2474 			    p->sc_property_name) != 0) {
2475 				switch (scf_error()) {
2476 				case SCF_ERROR_DELETED:
2477 					scf_entry_destroy(e);
2478 					return (ECANCELED);
2479 
2480 				case SCF_ERROR_CONNECTION_BROKEN:
2481 					scf_entry_destroy(e);
2482 					return (ECONNABORTED);
2483 
2484 				case SCF_ERROR_NOT_FOUND:
2485 					/*
2486 					 * This can happen if cur is from the
2487 					 * running snapshot (and it differs
2488 					 * from the live properties).
2489 					 */
2490 					scf_entry_destroy(e);
2491 					break;
2492 
2493 				case SCF_ERROR_HANDLE_MISMATCH:
2494 				case SCF_ERROR_NOT_BOUND:
2495 				case SCF_ERROR_NOT_SET:
2496 				case SCF_ERROR_INVALID_ARGUMENT:
2497 				default:
2498 					bad_error(
2499 					    "scf_transaction_property_delete",
2500 					    scf_error());
2501 				}
2502 			}
2503 		} else {
2504 			scf_callback_t ctx;
2505 
2506 			if (speak)
2507 				warn(gettext(
2508 				    "%s: Upgrading property \"%s/%s\".\n"),
2509 				    fmri, old->sc_pgroup_name,
2510 				    p->sc_property_name);
2511 
2512 			ctx.sc_handle = g_hndl;
2513 			ctx.sc_trans = tx;
2514 			ctx.sc_flags = 0;
2515 
2516 			r = lscf_property_import(new_p, &ctx);
2517 			if (r != UU_WALK_NEXT) {
2518 				if (r != UU_WALK_ERROR)
2519 					bad_error("lscf_property_import", r);
2520 				return (EINVAL);
2521 			}
2522 		}
2523 	}
2524 
2525 	/* Go over the properties which were added. */
2526 	for (new_p = uu_list_first(new->sc_pgroup_props);
2527 	    new_p != NULL;
2528 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
2529 		if (new_p->sc_seen)
2530 			continue;
2531 
2532 		/* This is a new property. */
2533 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
2534 		if (cur_p == NULL) {
2535 			scf_callback_t ctx;
2536 
2537 			ctx.sc_handle = g_hndl;
2538 			ctx.sc_trans = tx;
2539 			ctx.sc_flags = 0;
2540 
2541 			r = lscf_property_import(new_p, &ctx);
2542 			if (r != UU_WALK_NEXT) {
2543 				if (r != UU_WALK_ERROR)
2544 					bad_error("lscf_property_import", r);
2545 				return (EINVAL);
2546 			}
2547 			continue;
2548 		}
2549 
2550 		/*
2551 		 * Report a conflict if the new property differs from the
2552 		 * current one.  Unless it's general/enabled, since that's
2553 		 * never in the last-import snapshot.
2554 		 */
2555 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2556 		    0 &&
2557 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
2558 			continue;
2559 
2560 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
2561 	}
2562 
2563 	return (0);
2564 }
2565 
2566 /*
2567  * Upgrade pg according to old & new.
2568  *
2569  * Returns
2570  *   0 - success
2571  *   ECONNABORTED - repository connection broken
2572  *   ENOMEM - out of memory
2573  *   ENOSPC - svc.configd is out of resources
2574  *   ECANCELED - pg was deleted
2575  *   EPERM - couldn't modify pg (permission denied)
2576  *   EROFS - couldn't modify pg (backend read-only)
2577  *   EACCES - couldn't modify pg (backend access denied)
2578  *   EINVAL - new has a property with invalid name or value (error printed)
2579  *   EBUSY - pg changed unexpectedly
2580  */
2581 static int
2582 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
2583     pgroup_t *new, int speak, const char *fmri)
2584 {
2585 	int r;
2586 
2587 	if (scf_transaction_start(imp_tx, pg) != 0) {
2588 		switch (scf_error()) {
2589 		case SCF_ERROR_CONNECTION_BROKEN:
2590 		case SCF_ERROR_DELETED:
2591 		case SCF_ERROR_PERMISSION_DENIED:
2592 		case SCF_ERROR_BACKEND_READONLY:
2593 		case SCF_ERROR_BACKEND_ACCESS:
2594 			return (scferror2errno(scf_error()));
2595 
2596 		case SCF_ERROR_HANDLE_MISMATCH:
2597 		case SCF_ERROR_IN_USE:
2598 		case SCF_ERROR_NOT_BOUND:
2599 		case SCF_ERROR_NOT_SET:
2600 		default:
2601 			bad_error("scf_transaction_start", scf_error());
2602 		}
2603 	}
2604 
2605 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
2606 	switch (r) {
2607 	case 0:
2608 		break;
2609 
2610 	case EINVAL:
2611 	case ENOMEM:
2612 		scf_transaction_destroy_children(imp_tx);
2613 		return (r);
2614 
2615 	default:
2616 		bad_error("add_upgrade_entries", r);
2617 	}
2618 
2619 	r = scf_transaction_commit(imp_tx);
2620 
2621 	scf_transaction_destroy_children(imp_tx);
2622 
2623 	switch (r) {
2624 	case 1:
2625 		break;
2626 
2627 	case 0:
2628 		return (EBUSY);
2629 
2630 	case -1:
2631 		switch (scf_error()) {
2632 		case SCF_ERROR_CONNECTION_BROKEN:
2633 		case SCF_ERROR_NO_RESOURCES:
2634 		case SCF_ERROR_PERMISSION_DENIED:
2635 		case SCF_ERROR_BACKEND_READONLY:
2636 		case SCF_ERROR_BACKEND_ACCESS:
2637 		case SCF_ERROR_DELETED:
2638 			return (scferror2errno(scf_error()));
2639 
2640 		case SCF_ERROR_NOT_BOUND:
2641 		case SCF_ERROR_INVALID_ARGUMENT:
2642 		case SCF_ERROR_NOT_SET:
2643 		default:
2644 			bad_error("scf_transaction_commit", scf_error());
2645 		}
2646 
2647 	default:
2648 		bad_error("scf_transaction_commit", r);
2649 	}
2650 
2651 	return (0);
2652 }
2653 
2654 /*
2655  * Compares two entity FMRIs.  Returns
2656  *
2657  *   1 - equal
2658  *   0 - not equal
2659  *   -1 - f1 is invalid or not an entity
2660  *   -2 - f2 is invalid or not an entity
2661  */
2662 static int
2663 fmri_equal(const char *f1, const char *f2)
2664 {
2665 	int r;
2666 	const char *s1, *i1, *pg1;
2667 	const char *s2, *i2, *pg2;
2668 
2669 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2670 		return (-1);
2671 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
2672 		return (-1);
2673 
2674 	if (s1 == NULL || pg1 != NULL)
2675 		return (-1);
2676 
2677 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2678 		return (-2);
2679 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
2680 		return (-2);
2681 
2682 	if (s2 == NULL || pg2 != NULL)
2683 		return (-2);
2684 
2685 	r = strcmp(s1, s2);
2686 	if (r != 0)
2687 		return (0);
2688 
2689 	if (i1 == NULL && i2 == NULL)
2690 		return (1);
2691 
2692 	if (i1 == NULL || i2 == NULL)
2693 		return (0);
2694 
2695 	return (strcmp(i1, i2) == 0);
2696 }
2697 
2698 /*
2699  * Import a dependent by creating a dependency property group in the dependent
2700  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
2701  * dependents pg, and add an entry to create a new property for this
2702  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
2703  *
2704  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
2705  * lcbdata->sc_err to
2706  *   ECONNABORTED - repository connection broken
2707  *   ENOMEM - out of memory
2708  *   ENOSPC - configd is out of resources
2709  *   EINVAL - target is invalid (error printed)
2710  *	    - target is not an entity (error printed)
2711  *	    - dependent has invalid name (error printed)
2712  *	    - invalid property name (error printed)
2713  *	    - invalid value (error printed)
2714  *	    - scope of target does not exist (error printed)
2715  *   EPERM - couldn't create target (permission denied) (error printed)
2716  *	   - couldn't create dependency pg (permission denied) (error printed)
2717  *	   - couldn't modify dependency pg (permission denied) (error printed)
2718  *   EROFS - couldn't create target (repository read-only)
2719  *	   - couldn't create dependency pg (repository read-only)
2720  *   EACCES - couldn't create target (backend access denied)
2721  *	    - couldn't create dependency pg (backend access denied)
2722  *   ECANCELED - sc_trans's pg was deleted
2723  *   EALREADY - property for dependent already exists in sc_trans's pg
2724  *   EEXIST - dependency pg already exists in target (error printed)
2725  *   EBUSY - target deleted (error printed)
2726  *         - property group changed during import (error printed)
2727  */
2728 static int
2729 lscf_dependent_import(void *a1, void *pvt)
2730 {
2731 	pgroup_t *pgrp = a1;
2732 	scf_callback_t *lcbdata = pvt;
2733 
2734 	int isservice;
2735 	int ret;
2736 	scf_transaction_entry_t *e;
2737 	scf_value_t *val;
2738 	scf_callback_t dependent_cbdata;
2739 	scf_error_t scfe;
2740 
2741 	/*
2742 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
2743 	 * it's invalid, we fail before modifying the repository.
2744 	 */
2745 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2746 	    &dependent_cbdata.sc_parent, &isservice);
2747 	switch (scfe) {
2748 	case SCF_ERROR_NONE:
2749 		break;
2750 
2751 	case SCF_ERROR_NO_MEMORY:
2752 		return (stash_scferror_err(lcbdata, scfe));
2753 
2754 	case SCF_ERROR_INVALID_ARGUMENT:
2755 		semerr(gettext("The FMRI for the \"%s\" dependent is "
2756 		    "invalid.\n"), pgrp->sc_pgroup_name);
2757 		return (stash_scferror_err(lcbdata, scfe));
2758 
2759 	case SCF_ERROR_CONSTRAINT_VIOLATED:
2760 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
2761 		    "specifies neither a service nor an instance.\n"),
2762 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2763 		return (stash_scferror_err(lcbdata, scfe));
2764 
2765 	case SCF_ERROR_NOT_FOUND:
2766 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2767 		    &dependent_cbdata.sc_parent, &isservice);
2768 		switch (scfe) {
2769 		case SCF_ERROR_NONE:
2770 			break;
2771 
2772 		case SCF_ERROR_NO_MEMORY:
2773 		case SCF_ERROR_BACKEND_READONLY:
2774 		case SCF_ERROR_BACKEND_ACCESS:
2775 			return (stash_scferror_err(lcbdata, scfe));
2776 
2777 		case SCF_ERROR_NOT_FOUND:
2778 			semerr(gettext("The scope in FMRI \"%s\" for the "
2779 			    "\"%s\" dependent does not exist.\n"),
2780 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2781 			lcbdata->sc_err = EINVAL;
2782 			return (UU_WALK_ERROR);
2783 
2784 		case SCF_ERROR_PERMISSION_DENIED:
2785 			warn(gettext(
2786 			    "Could not create %s (permission denied).\n"),
2787 			    pgrp->sc_pgroup_fmri);
2788 			return (stash_scferror_err(lcbdata, scfe));
2789 
2790 		case SCF_ERROR_INVALID_ARGUMENT:
2791 		case SCF_ERROR_CONSTRAINT_VIOLATED:
2792 		default:
2793 			bad_error("create_entity", scfe);
2794 		}
2795 		break;
2796 
2797 	default:
2798 		bad_error("fmri_to_entity", scfe);
2799 	}
2800 
2801 	if (lcbdata->sc_trans != NULL) {
2802 		e = scf_entry_create(lcbdata->sc_handle);
2803 		if (e == NULL) {
2804 			if (scf_error() != SCF_ERROR_NO_MEMORY)
2805 				bad_error("scf_entry_create", scf_error());
2806 
2807 			entity_destroy(dependent_cbdata.sc_parent, isservice);
2808 			return (stash_scferror(lcbdata));
2809 		}
2810 
2811 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
2812 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
2813 			switch (scf_error()) {
2814 			case SCF_ERROR_INVALID_ARGUMENT:
2815 				warn(gettext("Dependent of %s has invalid name "
2816 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
2817 				    pgrp->sc_pgroup_name);
2818 				/* FALLTHROUGH */
2819 
2820 			case SCF_ERROR_DELETED:
2821 			case SCF_ERROR_CONNECTION_BROKEN:
2822 				scf_entry_destroy(e);
2823 				entity_destroy(dependent_cbdata.sc_parent,
2824 				    isservice);
2825 				return (stash_scferror(lcbdata));
2826 
2827 			case SCF_ERROR_EXISTS:
2828 				scf_entry_destroy(e);
2829 				entity_destroy(dependent_cbdata.sc_parent,
2830 				    isservice);
2831 				lcbdata->sc_err = EALREADY;
2832 				return (UU_WALK_ERROR);
2833 
2834 			case SCF_ERROR_NOT_BOUND:
2835 			case SCF_ERROR_HANDLE_MISMATCH:
2836 			case SCF_ERROR_NOT_SET:
2837 			default:
2838 				bad_error("scf_transaction_property_new",
2839 				    scf_error());
2840 			}
2841 		}
2842 
2843 		val = scf_value_create(lcbdata->sc_handle);
2844 		if (val == NULL) {
2845 			if (scf_error() != SCF_ERROR_NO_MEMORY)
2846 				bad_error("scf_value_create", scf_error());
2847 
2848 			entity_destroy(dependent_cbdata.sc_parent, isservice);
2849 			return (stash_scferror(lcbdata));
2850 		}
2851 
2852 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
2853 		    pgrp->sc_pgroup_fmri) != 0)
2854 			/* invalid should have been caught above */
2855 			bad_error("scf_value_set_from_string", scf_error());
2856 
2857 		if (scf_entry_add_value(e, val) != 0)
2858 			bad_error("scf_entry_add_value", scf_error());
2859 	}
2860 
2861 	/* Add the property group to the target entity. */
2862 
2863 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
2864 	dependent_cbdata.sc_flags = 0;
2865 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
2866 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
2867 
2868 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
2869 
2870 	entity_destroy(dependent_cbdata.sc_parent, isservice);
2871 
2872 	if (ret == UU_WALK_NEXT)
2873 		return (ret);
2874 
2875 	if (ret != UU_WALK_ERROR)
2876 		bad_error("entity_pgroup_import", ret);
2877 
2878 	switch (dependent_cbdata.sc_err) {
2879 	case ECANCELED:
2880 		warn(gettext("%s deleted unexpectedly.\n"),
2881 		    pgrp->sc_pgroup_fmri);
2882 		lcbdata->sc_err = EBUSY;
2883 		break;
2884 
2885 	case EEXIST:
2886 		warn(gettext("Could not create \"%s\" dependency in %s "
2887 		    "(already exists).\n"), pgrp->sc_pgroup_name,
2888 		    pgrp->sc_pgroup_fmri);
2889 		/* FALLTHROUGH */
2890 
2891 	default:
2892 		lcbdata->sc_err = dependent_cbdata.sc_err;
2893 	}
2894 
2895 	return (UU_WALK_ERROR);
2896 }
2897 
2898 static int upgrade_dependent(const scf_property_t *, const entity_t *,
2899     const scf_snaplevel_t *, scf_transaction_t *);
2900 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
2901     const pgroup_t *);
2902 
2903 /*
2904  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
2905  * the current dependent targets from running (the snaplevel of a running
2906  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
2907  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
2908  * dependent targets and dependency properties from li_dpts_pg (the
2909  * "dependents" property group in snpl) and snpl (the snaplevel which
2910  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
2911  * snpl doesn't have a "dependents" property group, and any dependents in ient
2912  * are new.
2913  *
2914  * Returns
2915  *   0 - success
2916  *   ECONNABORTED - repository connection broken
2917  *   ENOMEM - out of memory
2918  *   ENOSPC - configd is out of resources
2919  *   ECANCELED - ent was deleted
2920  *   ENODEV - the entity containing li_dpts_pg was deleted
2921  *   EPERM - could not modify dependents pg (permission denied) (error printed)
2922  *	   - couldn't upgrade dependent (permission denied) (error printed)
2923  *	   - couldn't create dependent (permission denied) (error printed)
2924  *   EROFS - could not modify dependents pg (repository read-only)
2925  *	   - couldn't upgrade dependent (repository read-only)
2926  *	   - couldn't create dependent (repository read-only)
2927  *   EACCES - could not modify dependents pg (backend access denied)
2928  *	    - could not upgrade dependent (backend access denied)
2929  *	    - could not create dependent (backend access denied)
2930  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
2931  *	   - dependent target deleted (error printed)
2932  *	   - dependent pg changed (error printed)
2933  *   EINVAL - new dependent is invalid (error printed)
2934  *   EBADF - snpl is corrupt (error printed)
2935  *	   - snpl has corrupt pg (error printed)
2936  *	   - dependency pg in target is corrupt (error printed)
2937  *	   - target has corrupt snapshot (error printed)
2938  *   EEXIST - dependency pg already existed in target service (error printed)
2939  */
2940 static int
2941 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
2942     const scf_snaplevel_t *snpl, const entity_t *ient,
2943     const scf_snaplevel_t *running, void *ent)
2944 {
2945 	pgroup_t *new_dpt_pgroup;
2946 	scf_callback_t cbdata;
2947 	int r, unseen, tx_started = 0;
2948 	int have_cur_depts;
2949 
2950 	const char * const dependents = "dependents";
2951 
2952 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
2953 
2954 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
2955 		/* Nothing to do. */
2956 		return (0);
2957 
2958 	/* Fetch the current version of the "dependents" property group. */
2959 	have_cur_depts = 1;
2960 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
2961 		switch (scf_error()) {
2962 		case SCF_ERROR_NOT_FOUND:
2963 			break;
2964 
2965 		case SCF_ERROR_DELETED:
2966 		case SCF_ERROR_CONNECTION_BROKEN:
2967 			return (scferror2errno(scf_error()));
2968 
2969 		case SCF_ERROR_NOT_SET:
2970 		case SCF_ERROR_INVALID_ARGUMENT:
2971 		case SCF_ERROR_HANDLE_MISMATCH:
2972 		case SCF_ERROR_NOT_BOUND:
2973 		default:
2974 			bad_error("entity_get_pg", scf_error());
2975 		}
2976 
2977 		have_cur_depts = 0;
2978 	}
2979 
2980 	/* Fetch the running version of the "dependents" property group. */
2981 	ud_run_dpts_pg_set = 0;
2982 	if (running != NULL)
2983 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
2984 	else
2985 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
2986 	if (r == 0) {
2987 		ud_run_dpts_pg_set = 1;
2988 	} else {
2989 		switch (scf_error()) {
2990 		case SCF_ERROR_NOT_FOUND:
2991 			break;
2992 
2993 		case SCF_ERROR_DELETED:
2994 		case SCF_ERROR_CONNECTION_BROKEN:
2995 			return (scferror2errno(scf_error()));
2996 
2997 		case SCF_ERROR_NOT_SET:
2998 		case SCF_ERROR_INVALID_ARGUMENT:
2999 		case SCF_ERROR_HANDLE_MISMATCH:
3000 		case SCF_ERROR_NOT_BOUND:
3001 		default:
3002 			bad_error(running ? "scf_snaplevel_get_pg" :
3003 			    "entity_get_pg", scf_error());
3004 		}
3005 	}
3006 
3007 	/*
3008 	 * Clear the seen fields of the dependents, so we can tell which ones
3009 	 * are new.
3010 	 */
3011 	if (uu_list_walk(ient->sc_dependents, clear_int,
3012 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3013 		bad_error("uu_list_walk", uu_error());
3014 
3015 	if (li_dpts_pg != NULL) {
3016 		/*
3017 		 * Each property in li_dpts_pg represents a dependent tag in
3018 		 * the old manifest.  For each, call upgrade_dependent(),
3019 		 * which will change ud_cur_depts_pg or dependencies in other
3020 		 * services as appropriate.  Note (a) that changes to
3021 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3022 		 * made en masse, and (b) it's ok if the entity doesn't have
3023 		 * a current version of the "dependents" property group,
3024 		 * because we'll just consider all dependents as customized
3025 		 * (by being deleted).
3026 		 */
3027 
3028 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3029 			switch (scf_error()) {
3030 			case SCF_ERROR_DELETED:
3031 				return (ENODEV);
3032 
3033 			case SCF_ERROR_CONNECTION_BROKEN:
3034 				return (ECONNABORTED);
3035 
3036 			case SCF_ERROR_HANDLE_MISMATCH:
3037 			case SCF_ERROR_NOT_BOUND:
3038 			case SCF_ERROR_NOT_SET:
3039 			default:
3040 				bad_error("scf_iter_pg_properties",
3041 				    scf_error());
3042 			}
3043 		}
3044 
3045 		if (have_cur_depts &&
3046 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3047 			switch (scf_error()) {
3048 			case SCF_ERROR_BACKEND_ACCESS:
3049 			case SCF_ERROR_BACKEND_READONLY:
3050 			case SCF_ERROR_CONNECTION_BROKEN:
3051 				return (scferror2errno(scf_error()));
3052 
3053 			case SCF_ERROR_DELETED:
3054 				warn(emsg_pg_deleted, ient->sc_fmri,
3055 				    dependents);
3056 				return (EBUSY);
3057 
3058 			case SCF_ERROR_PERMISSION_DENIED:
3059 				warn(emsg_pg_mod_perm, dependents,
3060 				    ient->sc_fmri);
3061 				return (scferror2errno(scf_error()));
3062 
3063 			case SCF_ERROR_HANDLE_MISMATCH:
3064 			case SCF_ERROR_IN_USE:
3065 			case SCF_ERROR_NOT_BOUND:
3066 			case SCF_ERROR_NOT_SET:
3067 			default:
3068 				bad_error("scf_transaction_start", scf_error());
3069 			}
3070 		}
3071 		tx_started = have_cur_depts;
3072 
3073 		for (;;) {
3074 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3075 			if (r == 0)
3076 				break;
3077 			if (r == 1) {
3078 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3079 				    tx_started ? ud_tx : NULL);
3080 				switch (r) {
3081 				case 0:
3082 					continue;
3083 
3084 				case ECONNABORTED:
3085 				case ENOMEM:
3086 				case ENOSPC:
3087 				case EBADF:
3088 				case EBUSY:
3089 				case EINVAL:
3090 				case EPERM:
3091 				case EROFS:
3092 				case EACCES:
3093 				case EEXIST:
3094 					break;
3095 
3096 				case ECANCELED:
3097 					r = ENODEV;
3098 					break;
3099 
3100 				default:
3101 					bad_error("upgrade_dependent", r);
3102 				}
3103 
3104 				if (tx_started)
3105 					scf_transaction_destroy_children(ud_tx);
3106 				return (r);
3107 			}
3108 			if (r != -1)
3109 				bad_error("scf_iter_next_property", r);
3110 
3111 			switch (scf_error()) {
3112 			case SCF_ERROR_DELETED:
3113 				r = ENODEV;
3114 				break;
3115 
3116 			case SCF_ERROR_CONNECTION_BROKEN:
3117 				r = ECONNABORTED;
3118 				break;
3119 
3120 			case SCF_ERROR_NOT_SET:
3121 			case SCF_ERROR_INVALID_ARGUMENT:
3122 			case SCF_ERROR_NOT_BOUND:
3123 			case SCF_ERROR_HANDLE_MISMATCH:
3124 			default:
3125 				bad_error("scf_iter_next_property",
3126 				    scf_error());
3127 			}
3128 
3129 			if (tx_started)
3130 				scf_transaction_destroy_children(ud_tx);
3131 			return (r);
3132 		}
3133 	}
3134 
3135 	/* import unseen dependents */
3136 	unseen = 0;
3137 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3138 	    new_dpt_pgroup != NULL;
3139 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3140 	    new_dpt_pgroup)) {
3141 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3142 			unseen = 1;
3143 			break;
3144 		}
3145 	}
3146 
3147 	/* If there are none, exit early. */
3148 	if (unseen == 0)
3149 		goto commit;
3150 
3151 	/* Set up for lscf_dependent_import() */
3152 	cbdata.sc_handle = g_hndl;
3153 	cbdata.sc_parent = ent;
3154 	cbdata.sc_service = issvc;
3155 	cbdata.sc_flags = 0;
3156 
3157 	if (!have_cur_depts) {
3158 		/*
3159 		 * We have new dependents to import, so we need a "dependents"
3160 		 * property group.
3161 		 */
3162 		if (issvc)
3163 			r = scf_service_add_pg(ent, dependents,
3164 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3165 		else
3166 			r = scf_instance_add_pg(ent, dependents,
3167 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3168 		if (r != 0) {
3169 			switch (scf_error()) {
3170 			case SCF_ERROR_DELETED:
3171 			case SCF_ERROR_CONNECTION_BROKEN:
3172 			case SCF_ERROR_BACKEND_READONLY:
3173 			case SCF_ERROR_BACKEND_ACCESS:
3174 			case SCF_ERROR_NO_RESOURCES:
3175 				return (scferror2errno(scf_error()));
3176 
3177 			case SCF_ERROR_EXISTS:
3178 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3179 				return (EBUSY);
3180 
3181 			case SCF_ERROR_PERMISSION_DENIED:
3182 				warn(emsg_pg_add_perm, dependents,
3183 				    ient->sc_fmri);
3184 				return (scferror2errno(scf_error()));
3185 
3186 			case SCF_ERROR_NOT_BOUND:
3187 			case SCF_ERROR_HANDLE_MISMATCH:
3188 			case SCF_ERROR_INVALID_ARGUMENT:
3189 			case SCF_ERROR_NOT_SET:
3190 			default:
3191 				bad_error("scf_service_add_pg", scf_error());
3192 			}
3193 		}
3194 	}
3195 
3196 	cbdata.sc_trans = ud_tx;
3197 
3198 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3199 		switch (scf_error()) {
3200 		case SCF_ERROR_CONNECTION_BROKEN:
3201 		case SCF_ERROR_BACKEND_ACCESS:
3202 		case SCF_ERROR_BACKEND_READONLY:
3203 			return (scferror2errno(scf_error()));
3204 
3205 		case SCF_ERROR_DELETED:
3206 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3207 			return (EBUSY);
3208 
3209 		case SCF_ERROR_PERMISSION_DENIED:
3210 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3211 			return (scferror2errno(scf_error()));
3212 
3213 		case SCF_ERROR_HANDLE_MISMATCH:
3214 		case SCF_ERROR_IN_USE:
3215 		case SCF_ERROR_NOT_BOUND:
3216 		case SCF_ERROR_NOT_SET:
3217 		default:
3218 			bad_error("scf_transaction_start", scf_error());
3219 		}
3220 	}
3221 	tx_started = 1;
3222 
3223 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3224 	    new_dpt_pgroup != NULL;
3225 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3226 	    new_dpt_pgroup)) {
3227 		if (new_dpt_pgroup->sc_pgroup_seen)
3228 			continue;
3229 
3230 		if (ud_run_dpts_pg_set) {
3231 			/*
3232 			 * If the dependent is already there, then we have
3233 			 * a conflict.
3234 			 */
3235 			if (scf_pg_get_property(ud_run_dpts_pg,
3236 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3237 				r = handle_dependent_conflict(ient, ud_prop,
3238 				    new_dpt_pgroup);
3239 				switch (r) {
3240 				case 0:
3241 					continue;
3242 
3243 				case ECONNABORTED:
3244 				case ENOMEM:
3245 				case EBUSY:
3246 				case EBADF:
3247 				case EINVAL:
3248 					scf_transaction_destroy_children(ud_tx);
3249 					return (r);
3250 
3251 				default:
3252 					bad_error("handle_dependent_conflict",
3253 					    r);
3254 				}
3255 			} else {
3256 				switch (scf_error()) {
3257 				case SCF_ERROR_NOT_FOUND:
3258 					break;
3259 
3260 				case SCF_ERROR_INVALID_ARGUMENT:
3261 					warn(emsg_fmri_invalid_pg_name,
3262 					    ient->sc_fmri,
3263 					    new_dpt_pgroup->sc_pgroup_name);
3264 					scf_transaction_destroy_children(ud_tx);
3265 					return (EINVAL);
3266 
3267 				case SCF_ERROR_DELETED:
3268 					warn(emsg_pg_deleted, ient->sc_fmri,
3269 					    new_dpt_pgroup->sc_pgroup_name);
3270 					scf_transaction_destroy_children(ud_tx);
3271 					return (EBUSY);
3272 
3273 				case SCF_ERROR_CONNECTION_BROKEN:
3274 					scf_transaction_destroy_children(ud_tx);
3275 					return (ECONNABORTED);
3276 
3277 				case SCF_ERROR_NOT_BOUND:
3278 				case SCF_ERROR_HANDLE_MISMATCH:
3279 				case SCF_ERROR_NOT_SET:
3280 				default:
3281 					bad_error("scf_pg_get_property",
3282 					    scf_error());
3283 				}
3284 			}
3285 		}
3286 
3287 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3288 		if (r != UU_WALK_NEXT) {
3289 			if (r != UU_WALK_ERROR)
3290 				bad_error("lscf_dependent_import", r);
3291 
3292 			if (cbdata.sc_err == EALREADY) {
3293 				/* Collisions were handled preemptively. */
3294 				bad_error("lscf_dependent_import",
3295 				    cbdata.sc_err);
3296 			}
3297 
3298 			scf_transaction_destroy_children(ud_tx);
3299 			return (cbdata.sc_err);
3300 		}
3301 	}
3302 
3303 commit:
3304 	if (!tx_started)
3305 		return (0);
3306 
3307 	r = scf_transaction_commit(ud_tx);
3308 
3309 	scf_transaction_destroy_children(ud_tx);
3310 
3311 	switch (r) {
3312 	case 1:
3313 		return (0);
3314 
3315 	case 0:
3316 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3317 		return (EBUSY);
3318 
3319 	case -1:
3320 		break;
3321 
3322 	default:
3323 		bad_error("scf_transaction_commit", r);
3324 	}
3325 
3326 	switch (scf_error()) {
3327 	case SCF_ERROR_CONNECTION_BROKEN:
3328 	case SCF_ERROR_BACKEND_READONLY:
3329 	case SCF_ERROR_BACKEND_ACCESS:
3330 	case SCF_ERROR_NO_RESOURCES:
3331 		return (scferror2errno(scf_error()));
3332 
3333 	case SCF_ERROR_DELETED:
3334 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3335 		return (EBUSY);
3336 
3337 	case SCF_ERROR_PERMISSION_DENIED:
3338 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3339 		return (scferror2errno(scf_error()));
3340 
3341 	case SCF_ERROR_NOT_BOUND:
3342 	case SCF_ERROR_INVALID_ARGUMENT:
3343 	case SCF_ERROR_NOT_SET:
3344 	default:
3345 		bad_error("scf_transaction_destroy", scf_error());
3346 		/* NOTREACHED */
3347 	}
3348 }
3349 
3350 /*
3351  * Used to add the manifests to the list of currently supported manifests.
3352  * We can modify the existing manifest list removing entries if the files
3353  * don't exist.
3354  *
3355  * Get the old list and the new file name
3356  * If the new file name is in the list return
3357  * If not then add the file to the list.
3358  * As we process the list check to see if the files in the old list exist
3359  * 	if not then remove the file from the list.
3360  * Commit the list of manifest file names.
3361  *
3362  */
3363 static int
3364 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3365     const scf_snaplevel_t *running, void *ent)
3366 {
3367 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3368 	scf_property_t *ud_prop = NULL;
3369 	scf_iter_t *ud_prop_iter;
3370 	scf_value_t *fname_value;
3371 	scf_callback_t cbdata;
3372 	pgroup_t *mfst_pgroup;
3373 	property_t *mfst_prop;
3374 	property_t *old_prop;
3375 	char *pname = malloc(MAXPATHLEN);
3376 	char *fval = NULL;
3377 	char *old_pname;
3378 	char *old_fval;
3379 	int no_upgrade_pg;
3380 	int mfst_seen;
3381 	int r;
3382 
3383 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3384 
3385 	/*
3386 	 * This should always be the service base on the code
3387 	 * path, and the fact that the manifests pg is a service
3388 	 * level property group only.
3389 	 */
3390 	ud_mfsts_pg = scf_pg_create(g_hndl);
3391 	ud_prop = scf_property_create(g_hndl);
3392 	ud_prop_iter = scf_iter_create(g_hndl);
3393 	fname_value = scf_value_create(g_hndl);
3394 
3395 	/* Fetch the "manifests" property group */
3396 	no_upgrade_pg = 0;
3397 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3398 	    ud_mfsts_pg);
3399 	if (r != 0) {
3400 		switch (scf_error()) {
3401 		case SCF_ERROR_NOT_FOUND:
3402 			no_upgrade_pg = 1;
3403 			break;
3404 
3405 		case SCF_ERROR_DELETED:
3406 		case SCF_ERROR_CONNECTION_BROKEN:
3407 			return (scferror2errno(scf_error()));
3408 
3409 		case SCF_ERROR_NOT_SET:
3410 		case SCF_ERROR_INVALID_ARGUMENT:
3411 		case SCF_ERROR_HANDLE_MISMATCH:
3412 		case SCF_ERROR_NOT_BOUND:
3413 		default:
3414 			bad_error(running ? "scf_snaplevel_get_pg" :
3415 			    "entity_get_pg", scf_error());
3416 		}
3417 	}
3418 
3419 	if (no_upgrade_pg) {
3420 		cbdata.sc_handle = g_hndl;
3421 		cbdata.sc_parent = ent;
3422 		cbdata.sc_service = issvc;
3423 		cbdata.sc_flags = SCI_FORCE;
3424 		cbdata.sc_source_fmri = ient->sc_fmri;
3425 		cbdata.sc_target_fmri = ient->sc_fmri;
3426 
3427 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3428 			return (cbdata.sc_err);
3429 
3430 		return (0);
3431 	}
3432 
3433 	/* Fetch the new manifests property group */
3434 	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3435 	    mfst_pgroup != NULL;
3436 	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3437 		if (strcmp(mfst_pgroup->sc_pgroup_name,
3438 		    SCF_PG_MANIFESTFILES) == 0)
3439 			break;
3440 	}
3441 
3442 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3443 	    SCF_SUCCESS)
3444 		return (-1);
3445 
3446 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3447 		mfst_seen = 0;
3448 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3449 			continue;
3450 
3451 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3452 		    mfst_prop != NULL;
3453 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3454 		    mfst_prop)) {
3455 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3456 				mfst_seen = 1;
3457 			}
3458 		}
3459 
3460 		/*
3461 		 * If the manifest is not seen then add it to the new mfst
3462 		 * property list to get proccessed into the repo.
3463 		 */
3464 		if (mfst_seen == 0) {
3465 			if (fval == NULL)
3466 				fval = malloc(MAXPATHLEN);
3467 
3468 			/*
3469 			 * If we cannot get the value then there is no
3470 			 * reason to attempt to attach the value to
3471 			 * the property group
3472 			 */
3473 			if (fval != NULL &&
3474 			    prop_get_val(ud_prop, fname_value) == 0 &&
3475 			    scf_value_get_astring(fname_value, fval,
3476 			    MAXPATHLEN) != -1)  {
3477 				/*
3478 				 * If the filesystem/minimal service is
3479 				 * online check to see if the manifest is
3480 				 * there.  If not then there is no need to
3481 				 * add it.
3482 				 *
3483 				 * If filesystem/minimal service is not
3484 				 * online, we go ahead and record the
3485 				 * manifest file name.  We don't check for
3486 				 * its existence because it may be on a
3487 				 * file system that is not yet mounted.
3488 				 */
3489 				if ((est->sc_fs_minimal) &&
3490 				    (access(fval, F_OK) == -1)) {
3491 					continue;
3492 				}
3493 
3494 				old_pname = safe_strdup(pname);
3495 				old_fval = safe_strdup(fval);
3496 				old_prop = internal_property_create(old_pname,
3497 				    SCF_TYPE_ASTRING, 1, old_fval);
3498 
3499 				/*
3500 				 * Already checked to see if the property exists
3501 				 * in the group, and it does not.
3502 				 */
3503 				(void) internal_attach_property(mfst_pgroup,
3504 				    old_prop);
3505 			}
3506 		}
3507 	}
3508 	free(fval);
3509 
3510 	cbdata.sc_handle = g_hndl;
3511 	cbdata.sc_parent = ent;
3512 	cbdata.sc_service = issvc;
3513 	cbdata.sc_flags = SCI_FORCE;
3514 	cbdata.sc_source_fmri = ient->sc_fmri;
3515 	cbdata.sc_target_fmri = ient->sc_fmri;
3516 
3517 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
3518 		return (cbdata.sc_err);
3519 
3520 	return (r);
3521 }
3522 
3523 /*
3524  * prop is taken to be a property in the "dependents" property group of snpl,
3525  * which is taken to be the snaplevel of a last-import snapshot corresponding
3526  * to ient.  If prop is a valid dependents property, upgrade the dependent it
3527  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
3528  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
3529  * of the entity ient represents (possibly in the running snapshot).  If it
3530  * needs to be changed, an entry will be added to tx, if not NULL.
3531  *
3532  * Returns
3533  *   0 - success
3534  *   ECONNABORTED - repository connection broken
3535  *   ENOMEM - out of memory
3536  *   ENOSPC - configd was out of resources
3537  *   ECANCELED - snpl's entity was deleted
3538  *   EINVAL - dependent target is invalid (error printed)
3539  *	    - dependent is invalid (error printed)
3540  *   EBADF - snpl is corrupt (error printed)
3541  *	   - snpl has corrupt pg (error printed)
3542  *	   - dependency pg in target is corrupt (error printed)
3543  *	   - running snapshot in dependent is missing snaplevel (error printed)
3544  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
3545  *	   - couldn't create dependent (permission denied) (error printed)
3546  *	   - couldn't modify dependent pg (permission denied) (error printed)
3547  *   EROFS - couldn't delete dependency pg (repository read-only)
3548  *	   - couldn't create dependent (repository read-only)
3549  *   EACCES - couldn't delete dependency pg (backend access denied)
3550  *	    - couldn't create dependent (backend access denied)
3551  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
3552  *	   - tx's pg was deleted (error printed)
3553  *	   - dependent pg was changed or deleted (error printed)
3554  *   EEXIST - dependency pg already exists in new target (error printed)
3555  */
3556 static int
3557 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
3558     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
3559 {
3560 	pgroup_t pgrp;
3561 	scf_type_t ty;
3562 	pgroup_t *new_dpt_pgroup;
3563 	pgroup_t *old_dpt_pgroup = NULL;
3564 	pgroup_t *current_pg;
3565 	scf_callback_t cbdata;
3566 	int tissvc;
3567 	void *target_ent;
3568 	scf_error_t serr;
3569 	int r;
3570 	scf_transaction_entry_t *ent;
3571 
3572 	const char * const cf_inval = gettext("Conflict upgrading %s "
3573 	    "(dependent \"%s\" has invalid dependents property).\n");
3574 	const char * const cf_missing = gettext("Conflict upgrading %s "
3575 	    "(dependent \"%s\" is missing).\n");
3576 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
3577 	    "(dependent \"%s\" has new dependency property group).\n");
3578 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
3579 	    "(dependent \"%s\" has new target).\n");
3580 	const char * const li_corrupt =
3581 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
3582 	const char * const upgrading =
3583 	    gettext("%s: Upgrading dependent \"%s\".\n");
3584 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
3585 	    "corrupt (missing snaplevel).\n");
3586 
3587 	if (scf_property_type(prop, &ty) != 0) {
3588 		switch (scf_error()) {
3589 		case SCF_ERROR_DELETED:
3590 		case SCF_ERROR_CONNECTION_BROKEN:
3591 			return (scferror2errno(scf_error()));
3592 
3593 		case SCF_ERROR_NOT_BOUND:
3594 		case SCF_ERROR_NOT_SET:
3595 		default:
3596 			bad_error("scf_property_type", scf_error());
3597 		}
3598 	}
3599 
3600 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3601 		warn(li_corrupt, ient->sc_fmri);
3602 		return (EBADF);
3603 	}
3604 
3605 	/*
3606 	 * prop represents a dependent in the old manifest.  It is named after
3607 	 * the dependent.
3608 	 */
3609 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
3610 		switch (scf_error()) {
3611 		case SCF_ERROR_DELETED:
3612 		case SCF_ERROR_CONNECTION_BROKEN:
3613 			return (scferror2errno(scf_error()));
3614 
3615 		case SCF_ERROR_NOT_BOUND:
3616 		case SCF_ERROR_NOT_SET:
3617 		default:
3618 			bad_error("scf_property_get_name", scf_error());
3619 		}
3620 	}
3621 
3622 	/* See if it's in the new manifest. */
3623 	pgrp.sc_pgroup_name = ud_name;
3624 	new_dpt_pgroup =
3625 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
3626 
3627 	/* If it's not, delete it... if it hasn't been customized. */
3628 	if (new_dpt_pgroup == NULL) {
3629 		pgroup_t *dpt;
3630 
3631 		if (!ud_run_dpts_pg_set)
3632 			return (0);
3633 
3634 		if (scf_property_get_value(prop, ud_val) != 0) {
3635 			switch (scf_error()) {
3636 			case SCF_ERROR_NOT_FOUND:
3637 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3638 				warn(li_corrupt, ient->sc_fmri);
3639 				return (EBADF);
3640 
3641 			case SCF_ERROR_DELETED:
3642 			case SCF_ERROR_CONNECTION_BROKEN:
3643 				return (scferror2errno(scf_error()));
3644 
3645 			case SCF_ERROR_HANDLE_MISMATCH:
3646 			case SCF_ERROR_NOT_BOUND:
3647 			case SCF_ERROR_NOT_SET:
3648 			case SCF_ERROR_PERMISSION_DENIED:
3649 			default:
3650 				bad_error("scf_property_get_value",
3651 				    scf_error());
3652 			}
3653 		}
3654 
3655 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
3656 		    max_scf_value_len + 1) < 0)
3657 			bad_error("scf_value_get_as_string", scf_error());
3658 
3659 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
3660 		    0) {
3661 			switch (scf_error()) {
3662 			case SCF_ERROR_NOT_FOUND:
3663 				return (0);
3664 
3665 			case SCF_ERROR_CONNECTION_BROKEN:
3666 				return (scferror2errno(scf_error()));
3667 
3668 			case SCF_ERROR_DELETED:
3669 				warn(emsg_pg_deleted, ient->sc_fmri,
3670 				    "dependents");
3671 				return (EBUSY);
3672 
3673 			case SCF_ERROR_INVALID_ARGUMENT:
3674 			case SCF_ERROR_NOT_BOUND:
3675 			case SCF_ERROR_HANDLE_MISMATCH:
3676 			case SCF_ERROR_NOT_SET:
3677 			default:
3678 				bad_error("scf_pg_get_property", scf_error());
3679 			}
3680 		}
3681 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
3682 			switch (scf_error()) {
3683 			case SCF_ERROR_NOT_FOUND:
3684 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3685 				warn(cf_inval, ient->sc_fmri, ud_name);
3686 				return (0);
3687 
3688 			case SCF_ERROR_DELETED:
3689 			case SCF_ERROR_CONNECTION_BROKEN:
3690 				return (scferror2errno(scf_error()));
3691 
3692 			case SCF_ERROR_HANDLE_MISMATCH:
3693 			case SCF_ERROR_NOT_BOUND:
3694 			case SCF_ERROR_NOT_SET:
3695 			case SCF_ERROR_PERMISSION_DENIED:
3696 			default:
3697 				bad_error("scf_property_get_value",
3698 				    scf_error());
3699 			}
3700 		}
3701 
3702 		ty = scf_value_type(ud_val);
3703 		assert(ty != SCF_TYPE_INVALID);
3704 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3705 			warn(cf_inval, ient->sc_fmri, ud_name);
3706 			return (0);
3707 		}
3708 
3709 		if (scf_value_get_as_string(ud_val, ud_ctarg,
3710 		    max_scf_value_len + 1) < 0)
3711 			bad_error("scf_value_get_as_string", scf_error());
3712 
3713 		r = fmri_equal(ud_ctarg, ud_oldtarg);
3714 		switch (r) {
3715 		case 1:
3716 			break;
3717 
3718 		case 0:
3719 		case -1:	/* warn? */
3720 			warn(cf_newtarg, ient->sc_fmri, ud_name);
3721 			return (0);
3722 
3723 		case -2:
3724 			warn(li_corrupt, ient->sc_fmri);
3725 			return (EBADF);
3726 
3727 		default:
3728 			bad_error("fmri_equal", r);
3729 		}
3730 
3731 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3732 			switch (scf_error()) {
3733 			case SCF_ERROR_NOT_FOUND:
3734 				warn(li_corrupt, ient->sc_fmri);
3735 				return (EBADF);
3736 
3737 			case SCF_ERROR_DELETED:
3738 			case SCF_ERROR_CONNECTION_BROKEN:
3739 				return (scferror2errno(scf_error()));
3740 
3741 			case SCF_ERROR_NOT_BOUND:
3742 			case SCF_ERROR_HANDLE_MISMATCH:
3743 			case SCF_ERROR_INVALID_ARGUMENT:
3744 			case SCF_ERROR_NOT_SET:
3745 			default:
3746 				bad_error("scf_snaplevel_get_pg", scf_error());
3747 			}
3748 		}
3749 
3750 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3751 		    snap_lastimport);
3752 		switch (r) {
3753 		case 0:
3754 			break;
3755 
3756 		case ECANCELED:
3757 		case ECONNABORTED:
3758 		case ENOMEM:
3759 		case EBADF:
3760 			return (r);
3761 
3762 		case EACCES:
3763 		default:
3764 			bad_error("load_pg", r);
3765 		}
3766 
3767 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3768 		switch (serr) {
3769 		case SCF_ERROR_NONE:
3770 			break;
3771 
3772 		case SCF_ERROR_NO_MEMORY:
3773 			internal_pgroup_free(old_dpt_pgroup);
3774 			return (ENOMEM);
3775 
3776 		case SCF_ERROR_NOT_FOUND:
3777 			internal_pgroup_free(old_dpt_pgroup);
3778 			goto delprop;
3779 
3780 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
3781 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
3782 		default:
3783 			bad_error("fmri_to_entity", serr);
3784 		}
3785 
3786 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
3787 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
3788 		switch (r) {
3789 		case 0:
3790 			break;
3791 
3792 		case ECONNABORTED:
3793 			internal_pgroup_free(old_dpt_pgroup);
3794 			return (r);
3795 
3796 		case ECANCELED:
3797 		case ENOENT:
3798 			internal_pgroup_free(old_dpt_pgroup);
3799 			goto delprop;
3800 
3801 		case EBADF:
3802 			warn(r_no_lvl, ud_ctarg);
3803 			internal_pgroup_free(old_dpt_pgroup);
3804 			return (r);
3805 
3806 		case EINVAL:
3807 		default:
3808 			bad_error("entity_get_running_pg", r);
3809 		}
3810 
3811 		/* load it */
3812 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
3813 		switch (r) {
3814 		case 0:
3815 			break;
3816 
3817 		case ECANCELED:
3818 			internal_pgroup_free(old_dpt_pgroup);
3819 			goto delprop;
3820 
3821 		case ECONNABORTED:
3822 		case ENOMEM:
3823 		case EBADF:
3824 			internal_pgroup_free(old_dpt_pgroup);
3825 			return (r);
3826 
3827 		case EACCES:
3828 		default:
3829 			bad_error("load_pg", r);
3830 		}
3831 
3832 		/* compare property groups */
3833 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
3834 			warn(cf_newdpg, ient->sc_fmri, ud_name);
3835 			internal_pgroup_free(old_dpt_pgroup);
3836 			internal_pgroup_free(current_pg);
3837 			return (0);
3838 		}
3839 
3840 		internal_pgroup_free(old_dpt_pgroup);
3841 		internal_pgroup_free(current_pg);
3842 
3843 		if (g_verbose)
3844 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
3845 			    ient->sc_fmri, ud_name);
3846 
3847 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
3848 			switch (scf_error()) {
3849 			case SCF_ERROR_NOT_FOUND:
3850 			case SCF_ERROR_DELETED:
3851 				internal_pgroup_free(old_dpt_pgroup);
3852 				goto delprop;
3853 
3854 			case SCF_ERROR_CONNECTION_BROKEN:
3855 				internal_pgroup_free(old_dpt_pgroup);
3856 				return (ECONNABORTED);
3857 
3858 			case SCF_ERROR_NOT_SET:
3859 			case SCF_ERROR_INVALID_ARGUMENT:
3860 			case SCF_ERROR_HANDLE_MISMATCH:
3861 			case SCF_ERROR_NOT_BOUND:
3862 			default:
3863 				bad_error("entity_get_pg", scf_error());
3864 			}
3865 		}
3866 
3867 		if (scf_pg_delete(ud_pg) != 0) {
3868 			switch (scf_error()) {
3869 			case SCF_ERROR_DELETED:
3870 				break;
3871 
3872 			case SCF_ERROR_CONNECTION_BROKEN:
3873 			case SCF_ERROR_BACKEND_READONLY:
3874 			case SCF_ERROR_BACKEND_ACCESS:
3875 				return (scferror2errno(scf_error()));
3876 
3877 			case SCF_ERROR_PERMISSION_DENIED:
3878 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
3879 				return (scferror2errno(scf_error()));
3880 
3881 			case SCF_ERROR_NOT_SET:
3882 			default:
3883 				bad_error("scf_pg_delete", scf_error());
3884 			}
3885 		}
3886 
3887 		/*
3888 		 * This service was changed, so it must be refreshed.  But
3889 		 * since it's not mentioned in the new manifest, we have to
3890 		 * record its FMRI here for use later.  We record the name
3891 		 * & the entity (via sc_parent) in case we need to print error
3892 		 * messages during the refresh.
3893 		 */
3894 		dpt = internal_pgroup_new();
3895 		if (dpt == NULL)
3896 			return (ENOMEM);
3897 		dpt->sc_pgroup_name = strdup(ud_name);
3898 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
3899 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
3900 			return (ENOMEM);
3901 		dpt->sc_parent = (entity_t *)ient;
3902 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
3903 			uu_die(gettext("libuutil error: %s\n"),
3904 			    uu_strerror(uu_error()));
3905 
3906 delprop:
3907 		if (tx == NULL)
3908 			return (0);
3909 
3910 		ent = scf_entry_create(g_hndl);
3911 		if (ent == NULL)
3912 			return (ENOMEM);
3913 
3914 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
3915 			scf_entry_destroy(ent);
3916 			switch (scf_error()) {
3917 			case SCF_ERROR_DELETED:
3918 				warn(emsg_pg_deleted, ient->sc_fmri,
3919 				    "dependents");
3920 				return (EBUSY);
3921 
3922 			case SCF_ERROR_CONNECTION_BROKEN:
3923 				return (scferror2errno(scf_error()));
3924 
3925 			case SCF_ERROR_NOT_FOUND:
3926 				break;
3927 
3928 			case SCF_ERROR_HANDLE_MISMATCH:
3929 			case SCF_ERROR_NOT_BOUND:
3930 			case SCF_ERROR_INVALID_ARGUMENT:
3931 			case SCF_ERROR_NOT_SET:
3932 			default:
3933 				bad_error("scf_transaction_property_delete",
3934 				    scf_error());
3935 			}
3936 		}
3937 
3938 		return (0);
3939 	}
3940 
3941 	new_dpt_pgroup->sc_pgroup_seen = 1;
3942 
3943 	/*
3944 	 * Decide whether the dependent has changed in the manifest.
3945 	 */
3946 	/* Compare the target. */
3947 	if (scf_property_get_value(prop, ud_val) != 0) {
3948 		switch (scf_error()) {
3949 		case SCF_ERROR_NOT_FOUND:
3950 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3951 			warn(li_corrupt, ient->sc_fmri);
3952 			return (EBADF);
3953 
3954 		case SCF_ERROR_DELETED:
3955 		case SCF_ERROR_CONNECTION_BROKEN:
3956 			return (scferror2errno(scf_error()));
3957 
3958 		case SCF_ERROR_HANDLE_MISMATCH:
3959 		case SCF_ERROR_NOT_BOUND:
3960 		case SCF_ERROR_NOT_SET:
3961 		case SCF_ERROR_PERMISSION_DENIED:
3962 		default:
3963 			bad_error("scf_property_get_value", scf_error());
3964 		}
3965 	}
3966 
3967 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
3968 	    0)
3969 		bad_error("scf_value_get_as_string", scf_error());
3970 
3971 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
3972 	switch (r) {
3973 	case 0:
3974 		break;
3975 
3976 	case 1:
3977 		/* Compare the dependency pgs. */
3978 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3979 			switch (scf_error()) {
3980 			case SCF_ERROR_NOT_FOUND:
3981 				warn(li_corrupt, ient->sc_fmri);
3982 				return (EBADF);
3983 
3984 			case SCF_ERROR_DELETED:
3985 			case SCF_ERROR_CONNECTION_BROKEN:
3986 				return (scferror2errno(scf_error()));
3987 
3988 			case SCF_ERROR_NOT_BOUND:
3989 			case SCF_ERROR_HANDLE_MISMATCH:
3990 			case SCF_ERROR_INVALID_ARGUMENT:
3991 			case SCF_ERROR_NOT_SET:
3992 			default:
3993 				bad_error("scf_snaplevel_get_pg", scf_error());
3994 			}
3995 		}
3996 
3997 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3998 		    snap_lastimport);
3999 		switch (r) {
4000 		case 0:
4001 			break;
4002 
4003 		case ECANCELED:
4004 		case ECONNABORTED:
4005 		case ENOMEM:
4006 		case EBADF:
4007 			return (r);
4008 
4009 		case EACCES:
4010 		default:
4011 			bad_error("load_pg", r);
4012 		}
4013 
4014 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4015 			/* no change, leave customizations */
4016 			internal_pgroup_free(old_dpt_pgroup);
4017 			return (0);
4018 		}
4019 		break;
4020 
4021 	case -1:
4022 		warn(li_corrupt, ient->sc_fmri);
4023 		return (EBADF);
4024 
4025 	case -2:
4026 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4027 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4028 		return (EINVAL);
4029 
4030 	default:
4031 		bad_error("fmri_equal", r);
4032 	}
4033 
4034 	/*
4035 	 * The dependent has changed in the manifest.  Upgrade the current
4036 	 * properties if they haven't been customized.
4037 	 */
4038 
4039 	/*
4040 	 * If new_dpt_pgroup->sc_override, then act as though the property
4041 	 * group hasn't been customized.
4042 	 */
4043 	if (new_dpt_pgroup->sc_pgroup_override)
4044 		goto nocust;
4045 
4046 	if (!ud_run_dpts_pg_set) {
4047 		warn(cf_missing, ient->sc_fmri, ud_name);
4048 		r = 0;
4049 		goto out;
4050 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4051 		switch (scf_error()) {
4052 		case SCF_ERROR_NOT_FOUND:
4053 			warn(cf_missing, ient->sc_fmri, ud_name);
4054 			r = 0;
4055 			goto out;
4056 
4057 		case SCF_ERROR_CONNECTION_BROKEN:
4058 			r = scferror2errno(scf_error());
4059 			goto out;
4060 
4061 		case SCF_ERROR_DELETED:
4062 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4063 			r = EBUSY;
4064 			goto out;
4065 
4066 		case SCF_ERROR_INVALID_ARGUMENT:
4067 		case SCF_ERROR_NOT_BOUND:
4068 		case SCF_ERROR_HANDLE_MISMATCH:
4069 		case SCF_ERROR_NOT_SET:
4070 		default:
4071 			bad_error("scf_pg_get_property", scf_error());
4072 		}
4073 	}
4074 
4075 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4076 		switch (scf_error()) {
4077 		case SCF_ERROR_NOT_FOUND:
4078 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4079 			warn(cf_inval, ient->sc_fmri, ud_name);
4080 			r = 0;
4081 			goto out;
4082 
4083 		case SCF_ERROR_DELETED:
4084 		case SCF_ERROR_CONNECTION_BROKEN:
4085 			r = scferror2errno(scf_error());
4086 			goto out;
4087 
4088 		case SCF_ERROR_HANDLE_MISMATCH:
4089 		case SCF_ERROR_NOT_BOUND:
4090 		case SCF_ERROR_NOT_SET:
4091 		case SCF_ERROR_PERMISSION_DENIED:
4092 		default:
4093 			bad_error("scf_property_get_value", scf_error());
4094 		}
4095 	}
4096 
4097 	ty = scf_value_type(ud_val);
4098 	assert(ty != SCF_TYPE_INVALID);
4099 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4100 		warn(cf_inval, ient->sc_fmri, ud_name);
4101 		r = 0;
4102 		goto out;
4103 	}
4104 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4105 	    0)
4106 		bad_error("scf_value_get_as_string", scf_error());
4107 
4108 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4109 	if (r == -1) {
4110 		warn(cf_inval, ient->sc_fmri, ud_name);
4111 		r = 0;
4112 		goto out;
4113 	} else if (r == -2) {
4114 		warn(li_corrupt, ient->sc_fmri);
4115 		r = EBADF;
4116 		goto out;
4117 	} else if (r == 0) {
4118 		/*
4119 		 * Target has been changed.  Only abort now if it's been
4120 		 * changed to something other than what's in the manifest.
4121 		 */
4122 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4123 		if (r == -1) {
4124 			warn(cf_inval, ient->sc_fmri, ud_name);
4125 			r = 0;
4126 			goto out;
4127 		} else if (r == 0) {
4128 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4129 			r = 0;
4130 			goto out;
4131 		} else if (r != 1) {
4132 			/* invalid sc_pgroup_fmri caught above */
4133 			bad_error("fmri_equal", r);
4134 		}
4135 
4136 		/*
4137 		 * Fetch the current dependency pg.  If it's what the manifest
4138 		 * says, then no problem.
4139 		 */
4140 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4141 		switch (serr) {
4142 		case SCF_ERROR_NONE:
4143 			break;
4144 
4145 		case SCF_ERROR_NOT_FOUND:
4146 			warn(cf_missing, ient->sc_fmri, ud_name);
4147 			r = 0;
4148 			goto out;
4149 
4150 		case SCF_ERROR_NO_MEMORY:
4151 			r = ENOMEM;
4152 			goto out;
4153 
4154 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4155 		case SCF_ERROR_INVALID_ARGUMENT:
4156 		default:
4157 			bad_error("fmri_to_entity", serr);
4158 		}
4159 
4160 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4161 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4162 		switch (r) {
4163 		case 0:
4164 			break;
4165 
4166 		case ECONNABORTED:
4167 			goto out;
4168 
4169 		case ECANCELED:
4170 		case ENOENT:
4171 			warn(cf_missing, ient->sc_fmri, ud_name);
4172 			r = 0;
4173 			goto out;
4174 
4175 		case EBADF:
4176 			warn(r_no_lvl, ud_ctarg);
4177 			goto out;
4178 
4179 		case EINVAL:
4180 		default:
4181 			bad_error("entity_get_running_pg", r);
4182 		}
4183 
4184 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4185 		switch (r) {
4186 		case 0:
4187 			break;
4188 
4189 		case ECANCELED:
4190 			warn(cf_missing, ient->sc_fmri, ud_name);
4191 			r = 0;
4192 			goto out;
4193 
4194 		case ECONNABORTED:
4195 		case ENOMEM:
4196 		case EBADF:
4197 			goto out;
4198 
4199 		case EACCES:
4200 		default:
4201 			bad_error("load_pg", r);
4202 		}
4203 
4204 		if (!pg_equal(current_pg, new_dpt_pgroup))
4205 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4206 		internal_pgroup_free(current_pg);
4207 		r = 0;
4208 		goto out;
4209 	} else if (r != 1) {
4210 		bad_error("fmri_equal", r);
4211 	}
4212 
4213 nocust:
4214 	/*
4215 	 * Target has not been customized.  Check the dependency property
4216 	 * group.
4217 	 */
4218 
4219 	if (old_dpt_pgroup == NULL) {
4220 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4221 		    ud_pg) != 0) {
4222 			switch (scf_error()) {
4223 			case SCF_ERROR_NOT_FOUND:
4224 				warn(li_corrupt, ient->sc_fmri);
4225 				return (EBADF);
4226 
4227 			case SCF_ERROR_DELETED:
4228 			case SCF_ERROR_CONNECTION_BROKEN:
4229 				return (scferror2errno(scf_error()));
4230 
4231 			case SCF_ERROR_NOT_BOUND:
4232 			case SCF_ERROR_HANDLE_MISMATCH:
4233 			case SCF_ERROR_INVALID_ARGUMENT:
4234 			case SCF_ERROR_NOT_SET:
4235 			default:
4236 				bad_error("scf_snaplevel_get_pg", scf_error());
4237 			}
4238 		}
4239 
4240 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4241 		    snap_lastimport);
4242 		switch (r) {
4243 		case 0:
4244 			break;
4245 
4246 		case ECANCELED:
4247 		case ECONNABORTED:
4248 		case ENOMEM:
4249 		case EBADF:
4250 			return (r);
4251 
4252 		case EACCES:
4253 		default:
4254 			bad_error("load_pg", r);
4255 		}
4256 	}
4257 
4258 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4259 	switch (serr) {
4260 	case SCF_ERROR_NONE:
4261 		break;
4262 
4263 	case SCF_ERROR_NOT_FOUND:
4264 		warn(cf_missing, ient->sc_fmri, ud_name);
4265 		r = 0;
4266 		goto out;
4267 
4268 	case SCF_ERROR_NO_MEMORY:
4269 		r = ENOMEM;
4270 		goto out;
4271 
4272 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4273 	case SCF_ERROR_INVALID_ARGUMENT:
4274 	default:
4275 		bad_error("fmri_to_entity", serr);
4276 	}
4277 
4278 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4279 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4280 	switch (r) {
4281 	case 0:
4282 		break;
4283 
4284 	case ECONNABORTED:
4285 		goto out;
4286 
4287 	case ECANCELED:
4288 	case ENOENT:
4289 		warn(cf_missing, ient->sc_fmri, ud_name);
4290 		r = 0;
4291 		goto out;
4292 
4293 	case EBADF:
4294 		warn(r_no_lvl, ud_ctarg);
4295 		goto out;
4296 
4297 	case EINVAL:
4298 	default:
4299 		bad_error("entity_get_running_pg", r);
4300 	}
4301 
4302 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4303 	switch (r) {
4304 	case 0:
4305 		break;
4306 
4307 	case ECANCELED:
4308 		warn(cf_missing, ient->sc_fmri, ud_name);
4309 		goto out;
4310 
4311 	case ECONNABORTED:
4312 	case ENOMEM:
4313 	case EBADF:
4314 		goto out;
4315 
4316 	case EACCES:
4317 	default:
4318 		bad_error("load_pg", r);
4319 	}
4320 
4321 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4322 		if (!pg_equal(current_pg, new_dpt_pgroup))
4323 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4324 		internal_pgroup_free(current_pg);
4325 		r = 0;
4326 		goto out;
4327 	}
4328 
4329 	/* Uncustomized.  Upgrade. */
4330 
4331 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4332 	switch (r) {
4333 	case 1:
4334 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4335 			/* Already upgraded. */
4336 			internal_pgroup_free(current_pg);
4337 			r = 0;
4338 			goto out;
4339 		}
4340 
4341 		internal_pgroup_free(current_pg);
4342 
4343 		/* upgrade current_pg */
4344 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4345 			switch (scf_error()) {
4346 			case SCF_ERROR_CONNECTION_BROKEN:
4347 				r = scferror2errno(scf_error());
4348 				goto out;
4349 
4350 			case SCF_ERROR_DELETED:
4351 				warn(cf_missing, ient->sc_fmri, ud_name);
4352 				r = 0;
4353 				goto out;
4354 
4355 			case SCF_ERROR_NOT_FOUND:
4356 				break;
4357 
4358 			case SCF_ERROR_INVALID_ARGUMENT:
4359 			case SCF_ERROR_NOT_BOUND:
4360 			case SCF_ERROR_NOT_SET:
4361 			case SCF_ERROR_HANDLE_MISMATCH:
4362 			default:
4363 				bad_error("entity_get_pg", scf_error());
4364 			}
4365 
4366 			if (tissvc)
4367 				r = scf_service_add_pg(target_ent, ud_name,
4368 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4369 			else
4370 				r = scf_instance_add_pg(target_ent, ud_name,
4371 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4372 			if (r != 0) {
4373 				switch (scf_error()) {
4374 				case SCF_ERROR_CONNECTION_BROKEN:
4375 				case SCF_ERROR_NO_RESOURCES:
4376 				case SCF_ERROR_BACKEND_READONLY:
4377 				case SCF_ERROR_BACKEND_ACCESS:
4378 					r = scferror2errno(scf_error());
4379 					goto out;
4380 
4381 				case SCF_ERROR_DELETED:
4382 					warn(cf_missing, ient->sc_fmri,
4383 					    ud_name);
4384 					r = 0;
4385 					goto out;
4386 
4387 				case SCF_ERROR_PERMISSION_DENIED:
4388 					warn(emsg_pg_deleted, ud_ctarg,
4389 					    ud_name);
4390 					r = EPERM;
4391 					goto out;
4392 
4393 				case SCF_ERROR_EXISTS:
4394 					warn(emsg_pg_added, ud_ctarg, ud_name);
4395 					r = EBUSY;
4396 					goto out;
4397 
4398 				case SCF_ERROR_NOT_BOUND:
4399 				case SCF_ERROR_HANDLE_MISMATCH:
4400 				case SCF_ERROR_INVALID_ARGUMENT:
4401 				case SCF_ERROR_NOT_SET:
4402 				default:
4403 					bad_error("entity_add_pg", scf_error());
4404 				}
4405 			}
4406 		}
4407 
4408 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4409 		switch (r) {
4410 		case 0:
4411 			break;
4412 
4413 		case ECANCELED:
4414 			warn(cf_missing, ient->sc_fmri, ud_name);
4415 			goto out;
4416 
4417 		case ECONNABORTED:
4418 		case ENOMEM:
4419 		case EBADF:
4420 			goto out;
4421 
4422 		case EACCES:
4423 		default:
4424 			bad_error("load_pg", r);
4425 		}
4426 
4427 		if (g_verbose)
4428 			warn(upgrading, ient->sc_fmri, ud_name);
4429 
4430 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4431 		    new_dpt_pgroup, 0, ient->sc_fmri);
4432 		switch (r) {
4433 		case 0:
4434 			break;
4435 
4436 		case ECANCELED:
4437 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4438 			r = EBUSY;
4439 			goto out;
4440 
4441 		case EPERM:
4442 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4443 			goto out;
4444 
4445 		case EBUSY:
4446 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4447 			goto out;
4448 
4449 		case ECONNABORTED:
4450 		case ENOMEM:
4451 		case ENOSPC:
4452 		case EROFS:
4453 		case EACCES:
4454 		case EINVAL:
4455 			goto out;
4456 
4457 		default:
4458 			bad_error("upgrade_pg", r);
4459 		}
4460 		break;
4461 
4462 	case 0: {
4463 		scf_transaction_entry_t *ent;
4464 		scf_value_t *val;
4465 
4466 		internal_pgroup_free(current_pg);
4467 
4468 		/* delete old pg */
4469 		if (g_verbose)
4470 			warn(upgrading, ient->sc_fmri, ud_name);
4471 
4472 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4473 			switch (scf_error()) {
4474 			case SCF_ERROR_CONNECTION_BROKEN:
4475 				r = scferror2errno(scf_error());
4476 				goto out;
4477 
4478 			case SCF_ERROR_DELETED:
4479 				warn(cf_missing, ient->sc_fmri, ud_name);
4480 				r = 0;
4481 				goto out;
4482 
4483 			case SCF_ERROR_NOT_FOUND:
4484 				break;
4485 
4486 			case SCF_ERROR_INVALID_ARGUMENT:
4487 			case SCF_ERROR_NOT_BOUND:
4488 			case SCF_ERROR_NOT_SET:
4489 			case SCF_ERROR_HANDLE_MISMATCH:
4490 			default:
4491 				bad_error("entity_get_pg", scf_error());
4492 			}
4493 		} else if (scf_pg_delete(ud_pg) != 0) {
4494 			switch (scf_error()) {
4495 			case SCF_ERROR_DELETED:
4496 				break;
4497 
4498 			case SCF_ERROR_CONNECTION_BROKEN:
4499 			case SCF_ERROR_BACKEND_READONLY:
4500 			case SCF_ERROR_BACKEND_ACCESS:
4501 				r = scferror2errno(scf_error());
4502 				goto out;
4503 
4504 			case SCF_ERROR_PERMISSION_DENIED:
4505 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4506 				r = scferror2errno(scf_error());
4507 				goto out;
4508 
4509 			case SCF_ERROR_NOT_SET:
4510 			default:
4511 				bad_error("scf_pg_delete", scf_error());
4512 			}
4513 		}
4514 
4515 		/* import new one */
4516 		cbdata.sc_handle = g_hndl;
4517 		cbdata.sc_trans = NULL;		/* handled below */
4518 
4519 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
4520 		if (r != UU_WALK_NEXT) {
4521 			if (r != UU_WALK_ERROR)
4522 				bad_error("lscf_dependent_import", r);
4523 
4524 			r = cbdata.sc_err;
4525 			goto out;
4526 		}
4527 
4528 		if (tx == NULL)
4529 			break;
4530 
4531 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
4532 		    (val = scf_value_create(g_hndl)) == NULL) {
4533 			if (scf_error() == SCF_ERROR_NO_MEMORY)
4534 				return (ENOMEM);
4535 
4536 			bad_error("scf_entry_create", scf_error());
4537 		}
4538 
4539 		if (scf_transaction_property_change_type(tx, ent, ud_name,
4540 		    SCF_TYPE_FMRI) != 0) {
4541 			switch (scf_error()) {
4542 			case SCF_ERROR_CONNECTION_BROKEN:
4543 				r = scferror2errno(scf_error());
4544 				goto out;
4545 
4546 			case SCF_ERROR_DELETED:
4547 				warn(emsg_pg_deleted, ient->sc_fmri,
4548 				    "dependents");
4549 				r = EBUSY;
4550 				goto out;
4551 
4552 			case SCF_ERROR_NOT_FOUND:
4553 				break;
4554 
4555 			case SCF_ERROR_NOT_BOUND:
4556 			case SCF_ERROR_HANDLE_MISMATCH:
4557 			case SCF_ERROR_INVALID_ARGUMENT:
4558 			case SCF_ERROR_NOT_SET:
4559 			default:
4560 				bad_error("scf_transaction_property_"
4561 				    "change_type", scf_error());
4562 			}
4563 
4564 			if (scf_transaction_property_new(tx, ent, ud_name,
4565 			    SCF_TYPE_FMRI) != 0) {
4566 				switch (scf_error()) {
4567 				case SCF_ERROR_CONNECTION_BROKEN:
4568 					r = scferror2errno(scf_error());
4569 					goto out;
4570 
4571 				case SCF_ERROR_DELETED:
4572 					warn(emsg_pg_deleted, ient->sc_fmri,
4573 					    "dependents");
4574 					r = EBUSY;
4575 					goto out;
4576 
4577 				case SCF_ERROR_EXISTS:
4578 					warn(emsg_pg_changed, ient->sc_fmri,
4579 					    "dependents");
4580 					r = EBUSY;
4581 					goto out;
4582 
4583 				case SCF_ERROR_INVALID_ARGUMENT:
4584 				case SCF_ERROR_HANDLE_MISMATCH:
4585 				case SCF_ERROR_NOT_BOUND:
4586 				case SCF_ERROR_NOT_SET:
4587 				default:
4588 					bad_error("scf_transaction_property_"
4589 					    "new", scf_error());
4590 				}
4591 			}
4592 		}
4593 
4594 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
4595 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
4596 			/* invalid sc_pgroup_fmri caught above */
4597 			bad_error("scf_value_set_from_string",
4598 			    scf_error());
4599 
4600 		if (scf_entry_add_value(ent, val) != 0)
4601 			bad_error("scf_entry_add_value", scf_error());
4602 		break;
4603 	}
4604 
4605 	case -2:
4606 		warn(li_corrupt, ient->sc_fmri);
4607 		internal_pgroup_free(current_pg);
4608 		r = EBADF;
4609 		goto out;
4610 
4611 	case -1:
4612 	default:
4613 		/* invalid sc_pgroup_fmri caught above */
4614 		bad_error("fmri_equal", r);
4615 	}
4616 
4617 	r = 0;
4618 
4619 out:
4620 	if (old_dpt_pgroup != NULL)
4621 		internal_pgroup_free(old_dpt_pgroup);
4622 
4623 	return (r);
4624 }
4625 
4626 /*
4627  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
4628  * would import it, except it seems to exist in the service anyway.  Compare
4629  * the existent dependent with the one we would import, and report any
4630  * differences (if there are none, be silent).  prop is the property which
4631  * represents the existent dependent (in the dependents property group) in the
4632  * entity corresponding to ient.
4633  *
4634  * Returns
4635  *   0 - success (Sort of.  At least, we can continue importing.)
4636  *   ECONNABORTED - repository connection broken
4637  *   EBUSY - ancestor of prop was deleted (error printed)
4638  *   ENOMEM - out of memory
4639  *   EBADF - corrupt property group (error printed)
4640  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
4641  */
4642 static int
4643 handle_dependent_conflict(const entity_t * const ient,
4644     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
4645 {
4646 	int r;
4647 	scf_type_t ty;
4648 	scf_error_t scfe;
4649 	void *tptr;
4650 	int tissvc;
4651 	pgroup_t *pgroup;
4652 
4653 	if (scf_property_get_value(prop, ud_val) != 0) {
4654 		switch (scf_error()) {
4655 		case SCF_ERROR_CONNECTION_BROKEN:
4656 			return (scferror2errno(scf_error()));
4657 
4658 		case SCF_ERROR_DELETED:
4659 			warn(emsg_pg_deleted, ient->sc_fmri,
4660 			    new_dpt_pgroup->sc_pgroup_name);
4661 			return (EBUSY);
4662 
4663 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4664 		case SCF_ERROR_NOT_FOUND:
4665 			warn(gettext("Conflict upgrading %s (not importing "
4666 			    "dependent \"%s\" because it already exists.)  "
4667 			    "Warning: The \"%s/%2$s\" property has more or "
4668 			    "fewer than one value)).\n"), ient->sc_fmri,
4669 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
4670 			return (0);
4671 
4672 		case SCF_ERROR_HANDLE_MISMATCH:
4673 		case SCF_ERROR_NOT_BOUND:
4674 		case SCF_ERROR_NOT_SET:
4675 		case SCF_ERROR_PERMISSION_DENIED:
4676 		default:
4677 			bad_error("scf_property_get_value",
4678 			    scf_error());
4679 		}
4680 	}
4681 
4682 	ty = scf_value_type(ud_val);
4683 	assert(ty != SCF_TYPE_INVALID);
4684 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4685 		warn(gettext("Conflict upgrading %s (not importing dependent "
4686 		    "\"%s\" because it already exists).  Warning: The "
4687 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
4688 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
4689 		    scf_type_to_string(ty), "dependents");
4690 		return (0);
4691 	}
4692 
4693 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4694 	    0)
4695 		bad_error("scf_value_get_as_string", scf_error());
4696 
4697 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4698 	switch (r) {
4699 	case 0:
4700 		warn(gettext("Conflict upgrading %s (not importing dependent "
4701 		    "\"%s\" (target \"%s\") because it already exists with "
4702 		    "target \"%s\").\n"), ient->sc_fmri,
4703 		    new_dpt_pgroup->sc_pgroup_name,
4704 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
4705 		return (0);
4706 
4707 	case 1:
4708 		break;
4709 
4710 	case -1:
4711 		warn(gettext("Conflict upgrading %s (not importing dependent "
4712 		    "\"%s\" because it already exists).  Warning: The current "
4713 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
4714 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4715 		return (0);
4716 
4717 	case -2:
4718 		warn(gettext("Dependent \"%s\" of %s has invalid target "
4719 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
4720 		    new_dpt_pgroup->sc_pgroup_fmri);
4721 		return (EINVAL);
4722 
4723 	default:
4724 		bad_error("fmri_equal", r);
4725 	}
4726 
4727 	/* compare dependency pgs in target */
4728 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
4729 	switch (scfe) {
4730 	case SCF_ERROR_NONE:
4731 		break;
4732 
4733 	case SCF_ERROR_NO_MEMORY:
4734 		return (ENOMEM);
4735 
4736 	case SCF_ERROR_NOT_FOUND:
4737 		warn(emsg_dpt_dangling, ient->sc_fmri,
4738 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4739 		return (0);
4740 
4741 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4742 	case SCF_ERROR_INVALID_ARGUMENT:
4743 	default:
4744 		bad_error("fmri_to_entity", scfe);
4745 	}
4746 
4747 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
4748 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
4749 	switch (r) {
4750 	case 0:
4751 		break;
4752 
4753 	case ECONNABORTED:
4754 		return (r);
4755 
4756 	case ECANCELED:
4757 		warn(emsg_dpt_dangling, ient->sc_fmri,
4758 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4759 		return (0);
4760 
4761 	case EBADF:
4762 		if (tissvc)
4763 			warn(gettext("%s has an instance with a \"%s\" "
4764 			    "snapshot which is missing a snaplevel.\n"),
4765 			    ud_ctarg, "running");
4766 		else
4767 			warn(gettext("%s has a \"%s\" snapshot which is "
4768 			    "missing a snaplevel.\n"), ud_ctarg, "running");
4769 		/* FALLTHROUGH */
4770 
4771 	case ENOENT:
4772 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4773 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4774 		    new_dpt_pgroup->sc_pgroup_name);
4775 		return (0);
4776 
4777 	case EINVAL:
4778 	default:
4779 		bad_error("entity_get_running_pg", r);
4780 	}
4781 
4782 	pgroup = internal_pgroup_new();
4783 	if (pgroup == NULL)
4784 		return (ENOMEM);
4785 
4786 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
4787 	switch (r) {
4788 	case 0:
4789 		break;
4790 
4791 	case ECONNABORTED:
4792 	case EBADF:
4793 	case ENOMEM:
4794 		internal_pgroup_free(pgroup);
4795 		return (r);
4796 
4797 	case ECANCELED:
4798 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4799 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4800 		    new_dpt_pgroup->sc_pgroup_name);
4801 		internal_pgroup_free(pgroup);
4802 		return (0);
4803 
4804 	case EACCES:
4805 	default:
4806 		bad_error("load_pg", r);
4807 	}
4808 
4809 	/* report differences */
4810 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
4811 	internal_pgroup_free(pgroup);
4812 	return (0);
4813 }
4814 
4815 /*
4816  * lipg is a property group in the last-import snapshot of ent, which is an
4817  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
4818  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
4819  * in ents's property groups, compare and upgrade ent appropriately.
4820  *
4821  * Returns
4822  *   0 - success
4823  *   ECONNABORTED - repository connection broken
4824  *   ENOMEM - out of memory
4825  *   ENOSPC - configd is out of resources
4826  *   EINVAL - ient has invalid dependent (error printed)
4827  *	    - ient has invalid pgroup_t (error printed)
4828  *   ECANCELED - ent has been deleted
4829  *   ENODEV - entity containing lipg has been deleted
4830  *	    - entity containing running has been deleted
4831  *   EPERM - could not delete pg (permission denied) (error printed)
4832  *	   - couldn't upgrade dependents (permission denied) (error printed)
4833  *	   - couldn't import pg (permission denied) (error printed)
4834  *	   - couldn't upgrade pg (permission denied) (error printed)
4835  *   EROFS - could not delete pg (repository read-only)
4836  *	   - couldn't upgrade dependents (repository read-only)
4837  *	   - couldn't import pg (repository read-only)
4838  *	   - couldn't upgrade pg (repository read-only)
4839  *   EACCES - could not delete pg (backend access denied)
4840  *	    - couldn't upgrade dependents (backend access denied)
4841  *	    - couldn't import pg (backend access denied)
4842  *	    - couldn't upgrade pg (backend access denied)
4843  *	    - couldn't read property (backend access denied)
4844  *   EBUSY - property group was added (error printed)
4845  *	   - property group was deleted (error printed)
4846  *	   - property group changed (error printed)
4847  *	   - "dependents" pg was added, changed, or deleted (error printed)
4848  *	   - dependent target deleted (error printed)
4849  *	   - dependent pg changed (error printed)
4850  *   EBADF - imp_snpl is corrupt (error printed)
4851  *	   - ent has bad pg (error printed)
4852  *   EEXIST - dependent collision in target service (error printed)
4853  */
4854 static int
4855 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
4856     const scf_snaplevel_t *running)
4857 {
4858 	int r;
4859 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
4860 	scf_callback_t cbdata;
4861 
4862 	const char * const cf_pg_missing =
4863 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
4864 	const char * const deleting =
4865 	    gettext("%s: Deleting property group \"%s\".\n");
4866 
4867 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
4868 
4869 	/* Skip dependent property groups. */
4870 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
4871 		switch (scf_error()) {
4872 		case SCF_ERROR_DELETED:
4873 			return (ENODEV);
4874 
4875 		case SCF_ERROR_CONNECTION_BROKEN:
4876 			return (ECONNABORTED);
4877 
4878 		case SCF_ERROR_NOT_SET:
4879 		case SCF_ERROR_NOT_BOUND:
4880 		default:
4881 			bad_error("scf_pg_get_type", scf_error());
4882 		}
4883 	}
4884 
4885 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
4886 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
4887 			return (0);
4888 
4889 		switch (scf_error()) {
4890 		case SCF_ERROR_NOT_FOUND:
4891 			break;
4892 
4893 		case SCF_ERROR_CONNECTION_BROKEN:
4894 			return (ECONNABORTED);
4895 
4896 		case SCF_ERROR_DELETED:
4897 			return (ENODEV);
4898 
4899 		case SCF_ERROR_INVALID_ARGUMENT:
4900 		case SCF_ERROR_NOT_BOUND:
4901 		case SCF_ERROR_HANDLE_MISMATCH:
4902 		case SCF_ERROR_NOT_SET:
4903 		default:
4904 			bad_error("scf_pg_get_property", scf_error());
4905 		}
4906 	}
4907 
4908 	/* lookup pg in new properties */
4909 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
4910 		switch (scf_error()) {
4911 		case SCF_ERROR_DELETED:
4912 			return (ENODEV);
4913 
4914 		case SCF_ERROR_CONNECTION_BROKEN:
4915 			return (ECONNABORTED);
4916 
4917 		case SCF_ERROR_NOT_SET:
4918 		case SCF_ERROR_NOT_BOUND:
4919 		default:
4920 			bad_error("scf_pg_get_name", scf_error());
4921 		}
4922 	}
4923 
4924 	pgrp.sc_pgroup_name = imp_str;
4925 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
4926 
4927 	if (mpg != NULL)
4928 		mpg->sc_pgroup_seen = 1;
4929 
4930 	/* Special handling for dependents */
4931 	if (strcmp(imp_str, "dependents") == 0)
4932 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
4933 
4934 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
4935 		return (upgrade_manifestfiles(NULL, ient, running, ent));
4936 
4937 	if (mpg == NULL || mpg->sc_pgroup_delete) {
4938 		/* property group was deleted from manifest */
4939 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4940 			switch (scf_error()) {
4941 			case SCF_ERROR_NOT_FOUND:
4942 				return (0);
4943 
4944 			case SCF_ERROR_DELETED:
4945 			case SCF_ERROR_CONNECTION_BROKEN:
4946 				return (scferror2errno(scf_error()));
4947 
4948 			case SCF_ERROR_INVALID_ARGUMENT:
4949 			case SCF_ERROR_HANDLE_MISMATCH:
4950 			case SCF_ERROR_NOT_BOUND:
4951 			case SCF_ERROR_NOT_SET:
4952 			default:
4953 				bad_error("entity_get_pg", scf_error());
4954 			}
4955 		}
4956 
4957 		if (mpg != NULL && mpg->sc_pgroup_delete) {
4958 			if (g_verbose)
4959 				warn(deleting, ient->sc_fmri, imp_str);
4960 			if (scf_pg_delete(imp_pg2) == 0)
4961 				return (0);
4962 
4963 			switch (scf_error()) {
4964 			case SCF_ERROR_DELETED:
4965 				return (0);
4966 
4967 			case SCF_ERROR_CONNECTION_BROKEN:
4968 			case SCF_ERROR_BACKEND_READONLY:
4969 			case SCF_ERROR_BACKEND_ACCESS:
4970 				return (scferror2errno(scf_error()));
4971 
4972 			case SCF_ERROR_PERMISSION_DENIED:
4973 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
4974 				return (scferror2errno(scf_error()));
4975 
4976 			case SCF_ERROR_NOT_SET:
4977 			default:
4978 				bad_error("scf_pg_delete", scf_error());
4979 			}
4980 		}
4981 
4982 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4983 		switch (r) {
4984 		case 0:
4985 			break;
4986 
4987 		case ECANCELED:
4988 			return (ENODEV);
4989 
4990 		case ECONNABORTED:
4991 		case ENOMEM:
4992 		case EBADF:
4993 		case EACCES:
4994 			return (r);
4995 
4996 		default:
4997 			bad_error("load_pg", r);
4998 		}
4999 
5000 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5001 		switch (r) {
5002 		case 0:
5003 			break;
5004 
5005 		case ECANCELED:
5006 		case ECONNABORTED:
5007 		case ENOMEM:
5008 		case EBADF:
5009 		case EACCES:
5010 			internal_pgroup_free(lipg_i);
5011 			return (r);
5012 
5013 		default:
5014 			bad_error("load_pg", r);
5015 		}
5016 
5017 		if (pg_equal(lipg_i, curpg_i)) {
5018 			if (g_verbose)
5019 				warn(deleting, ient->sc_fmri, imp_str);
5020 			if (scf_pg_delete(imp_pg2) != 0) {
5021 				switch (scf_error()) {
5022 				case SCF_ERROR_DELETED:
5023 					break;
5024 
5025 				case SCF_ERROR_CONNECTION_BROKEN:
5026 					internal_pgroup_free(lipg_i);
5027 					internal_pgroup_free(curpg_i);
5028 					return (ECONNABORTED);
5029 
5030 				case SCF_ERROR_NOT_SET:
5031 				case SCF_ERROR_NOT_BOUND:
5032 				default:
5033 					bad_error("scf_pg_delete", scf_error());
5034 				}
5035 			}
5036 		} else {
5037 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5038 		}
5039 
5040 		internal_pgroup_free(lipg_i);
5041 		internal_pgroup_free(curpg_i);
5042 
5043 		return (0);
5044 	}
5045 
5046 	/*
5047 	 * Only dependent pgs can have override set, and we skipped those
5048 	 * above.
5049 	 */
5050 	assert(!mpg->sc_pgroup_override);
5051 
5052 	/* compare */
5053 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5054 	switch (r) {
5055 	case 0:
5056 		break;
5057 
5058 	case ECANCELED:
5059 		return (ENODEV);
5060 
5061 	case ECONNABORTED:
5062 	case EBADF:
5063 	case ENOMEM:
5064 	case EACCES:
5065 		return (r);
5066 
5067 	default:
5068 		bad_error("load_pg", r);
5069 	}
5070 
5071 	if (pg_equal(mpg, lipg_i)) {
5072 		/* The manifest pg has not changed.  Move on. */
5073 		r = 0;
5074 		goto out;
5075 	}
5076 
5077 	/* upgrade current properties according to lipg & mpg */
5078 	if (running != NULL)
5079 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5080 	else
5081 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5082 	if (r != 0) {
5083 		switch (scf_error()) {
5084 		case SCF_ERROR_CONNECTION_BROKEN:
5085 			r = scferror2errno(scf_error());
5086 			goto out;
5087 
5088 		case SCF_ERROR_DELETED:
5089 			if (running != NULL)
5090 				r = ENODEV;
5091 			else
5092 				r = ECANCELED;
5093 			goto out;
5094 
5095 		case SCF_ERROR_NOT_FOUND:
5096 			break;
5097 
5098 		case SCF_ERROR_INVALID_ARGUMENT:
5099 		case SCF_ERROR_HANDLE_MISMATCH:
5100 		case SCF_ERROR_NOT_BOUND:
5101 		case SCF_ERROR_NOT_SET:
5102 		default:
5103 			bad_error("entity_get_pg", scf_error());
5104 		}
5105 
5106 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5107 
5108 		r = 0;
5109 		goto out;
5110 	}
5111 
5112 	r = load_pg_attrs(imp_pg2, &curpg_i);
5113 	switch (r) {
5114 	case 0:
5115 		break;
5116 
5117 	case ECANCELED:
5118 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5119 		r = 0;
5120 		goto out;
5121 
5122 	case ECONNABORTED:
5123 	case ENOMEM:
5124 		goto out;
5125 
5126 	default:
5127 		bad_error("load_pg_attrs", r);
5128 	}
5129 
5130 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5131 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5132 		internal_pgroup_free(curpg_i);
5133 		r = 0;
5134 		goto out;
5135 	}
5136 
5137 	internal_pgroup_free(curpg_i);
5138 
5139 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5140 	switch (r) {
5141 	case 0:
5142 		break;
5143 
5144 	case ECANCELED:
5145 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5146 		r = 0;
5147 		goto out;
5148 
5149 	case ECONNABORTED:
5150 	case EBADF:
5151 	case ENOMEM:
5152 	case EACCES:
5153 		goto out;
5154 
5155 	default:
5156 		bad_error("load_pg", r);
5157 	}
5158 
5159 	if (pg_equal(lipg_i, curpg_i) &&
5160 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5161 		int do_delete = 1;
5162 
5163 		if (g_verbose)
5164 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5165 			    ient->sc_fmri, mpg->sc_pgroup_name);
5166 
5167 		internal_pgroup_free(curpg_i);
5168 
5169 		if (running != NULL &&
5170 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5171 			switch (scf_error()) {
5172 			case SCF_ERROR_DELETED:
5173 				r = ECANCELED;
5174 				goto out;
5175 
5176 			case SCF_ERROR_NOT_FOUND:
5177 				do_delete = 0;
5178 				break;
5179 
5180 			case SCF_ERROR_CONNECTION_BROKEN:
5181 				r = scferror2errno(scf_error());
5182 				goto out;
5183 
5184 			case SCF_ERROR_HANDLE_MISMATCH:
5185 			case SCF_ERROR_INVALID_ARGUMENT:
5186 			case SCF_ERROR_NOT_SET:
5187 			case SCF_ERROR_NOT_BOUND:
5188 			default:
5189 				bad_error("entity_get_pg", scf_error());
5190 			}
5191 		}
5192 
5193 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5194 			switch (scf_error()) {
5195 			case SCF_ERROR_DELETED:
5196 				break;
5197 
5198 			case SCF_ERROR_CONNECTION_BROKEN:
5199 			case SCF_ERROR_BACKEND_READONLY:
5200 			case SCF_ERROR_BACKEND_ACCESS:
5201 				r = scferror2errno(scf_error());
5202 				goto out;
5203 
5204 			case SCF_ERROR_PERMISSION_DENIED:
5205 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5206 				    ient->sc_fmri);
5207 				r = scferror2errno(scf_error());
5208 				goto out;
5209 
5210 			case SCF_ERROR_NOT_SET:
5211 			case SCF_ERROR_NOT_BOUND:
5212 			default:
5213 				bad_error("scf_pg_delete", scf_error());
5214 			}
5215 		}
5216 
5217 		cbdata.sc_handle = g_hndl;
5218 		cbdata.sc_parent = ent;
5219 		cbdata.sc_service = issvc;
5220 		cbdata.sc_flags = 0;
5221 		cbdata.sc_source_fmri = ient->sc_fmri;
5222 		cbdata.sc_target_fmri = ient->sc_fmri;
5223 
5224 		r = entity_pgroup_import(mpg, &cbdata);
5225 		switch (r) {
5226 		case UU_WALK_NEXT:
5227 			r = 0;
5228 			goto out;
5229 
5230 		case UU_WALK_ERROR:
5231 			if (cbdata.sc_err == EEXIST) {
5232 				warn(emsg_pg_added, ient->sc_fmri,
5233 				    mpg->sc_pgroup_name);
5234 				r = EBUSY;
5235 			} else {
5236 				r = cbdata.sc_err;
5237 			}
5238 			goto out;
5239 
5240 		default:
5241 			bad_error("entity_pgroup_import", r);
5242 		}
5243 	}
5244 
5245 	if (running != NULL &&
5246 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5247 		switch (scf_error()) {
5248 		case SCF_ERROR_CONNECTION_BROKEN:
5249 		case SCF_ERROR_DELETED:
5250 			r = scferror2errno(scf_error());
5251 			goto out;
5252 
5253 		case SCF_ERROR_NOT_FOUND:
5254 			break;
5255 
5256 		case SCF_ERROR_HANDLE_MISMATCH:
5257 		case SCF_ERROR_INVALID_ARGUMENT:
5258 		case SCF_ERROR_NOT_SET:
5259 		case SCF_ERROR_NOT_BOUND:
5260 		default:
5261 			bad_error("entity_get_pg", scf_error());
5262 		}
5263 
5264 		cbdata.sc_handle = g_hndl;
5265 		cbdata.sc_parent = ent;
5266 		cbdata.sc_service = issvc;
5267 		cbdata.sc_flags = SCI_FORCE;
5268 		cbdata.sc_source_fmri = ient->sc_fmri;
5269 		cbdata.sc_target_fmri = ient->sc_fmri;
5270 
5271 		r = entity_pgroup_import(mpg, &cbdata);
5272 		switch (r) {
5273 		case UU_WALK_NEXT:
5274 			r = 0;
5275 			goto out;
5276 
5277 		case UU_WALK_ERROR:
5278 			if (cbdata.sc_err == EEXIST) {
5279 				warn(emsg_pg_added, ient->sc_fmri,
5280 				    mpg->sc_pgroup_name);
5281 				r = EBUSY;
5282 			} else {
5283 				r = cbdata.sc_err;
5284 			}
5285 			goto out;
5286 
5287 		default:
5288 			bad_error("entity_pgroup_import", r);
5289 		}
5290 	}
5291 
5292 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5293 	internal_pgroup_free(curpg_i);
5294 	switch (r) {
5295 	case 0:
5296 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5297 		break;
5298 
5299 	case ECANCELED:
5300 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5301 		r = EBUSY;
5302 		break;
5303 
5304 	case EPERM:
5305 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5306 		break;
5307 
5308 	case EBUSY:
5309 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5310 		break;
5311 
5312 	case ECONNABORTED:
5313 	case ENOMEM:
5314 	case ENOSPC:
5315 	case EROFS:
5316 	case EACCES:
5317 	case EINVAL:
5318 		break;
5319 
5320 	default:
5321 		bad_error("upgrade_pg", r);
5322 	}
5323 
5324 out:
5325 	internal_pgroup_free(lipg_i);
5326 	return (r);
5327 }
5328 
5329 /*
5330  * Upgrade the properties of ent according to snpl & ient.
5331  *
5332  * Returns
5333  *   0 - success
5334  *   ECONNABORTED - repository connection broken
5335  *   ENOMEM - out of memory
5336  *   ENOSPC - configd is out of resources
5337  *   ECANCELED - ent was deleted
5338  *   ENODEV - entity containing snpl was deleted
5339  *	    - entity containing running was deleted
5340  *   EBADF - imp_snpl is corrupt (error printed)
5341  *	   - ent has corrupt pg (error printed)
5342  *	   - dependent has corrupt pg (error printed)
5343  *	   - dependent target has a corrupt snapshot (error printed)
5344  *   EBUSY - pg was added, changed, or deleted (error printed)
5345  *	   - dependent target was deleted (error printed)
5346  *	   - dependent pg changed (error printed)
5347  *   EINVAL - invalid property group name (error printed)
5348  *	    - invalid property name (error printed)
5349  *	    - invalid value (error printed)
5350  *	    - ient has invalid pgroup or dependent (error printed)
5351  *   EPERM - could not create property group (permission denied) (error printed)
5352  *	   - could not modify property group (permission denied) (error printed)
5353  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5354  *   EROFS - could not create property group (repository read-only)
5355  *	   - couldn't delete, upgrade, or import pg or dependent
5356  *   EACCES - could not create property group (backend access denied)
5357  *	    - couldn't delete, upgrade, or import pg or dependent
5358  *   EEXIST - dependent collision in target service (error printed)
5359  */
5360 static int
5361 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5362     entity_t *ient)
5363 {
5364 	pgroup_t *pg, *rpg;
5365 	int r;
5366 	uu_list_t *pgs = ient->sc_pgroups;
5367 
5368 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5369 
5370 	/* clear sc_sceen for pgs */
5371 	if (uu_list_walk(pgs, clear_int,
5372 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5373 		bad_error("uu_list_walk", uu_error());
5374 
5375 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5376 		switch (scf_error()) {
5377 		case SCF_ERROR_DELETED:
5378 			return (ENODEV);
5379 
5380 		case SCF_ERROR_CONNECTION_BROKEN:
5381 			return (ECONNABORTED);
5382 
5383 		case SCF_ERROR_NOT_SET:
5384 		case SCF_ERROR_NOT_BOUND:
5385 		case SCF_ERROR_HANDLE_MISMATCH:
5386 		default:
5387 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5388 		}
5389 	}
5390 
5391 	for (;;) {
5392 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5393 		if (r == 0)
5394 			break;
5395 		if (r == 1) {
5396 			r = process_old_pg(imp_pg, ient, ent, running);
5397 			switch (r) {
5398 			case 0:
5399 				break;
5400 
5401 			case ECONNABORTED:
5402 			case ENOMEM:
5403 			case ENOSPC:
5404 			case ECANCELED:
5405 			case ENODEV:
5406 			case EPERM:
5407 			case EROFS:
5408 			case EACCES:
5409 			case EBADF:
5410 			case EBUSY:
5411 			case EINVAL:
5412 			case EEXIST:
5413 				return (r);
5414 
5415 			default:
5416 				bad_error("process_old_pg", r);
5417 			}
5418 			continue;
5419 		}
5420 		if (r != -1)
5421 			bad_error("scf_iter_next_pg", r);
5422 
5423 		switch (scf_error()) {
5424 		case SCF_ERROR_DELETED:
5425 			return (ENODEV);
5426 
5427 		case SCF_ERROR_CONNECTION_BROKEN:
5428 			return (ECONNABORTED);
5429 
5430 		case SCF_ERROR_HANDLE_MISMATCH:
5431 		case SCF_ERROR_NOT_BOUND:
5432 		case SCF_ERROR_NOT_SET:
5433 		case SCF_ERROR_INVALID_ARGUMENT:
5434 		default:
5435 			bad_error("scf_iter_next_pg", scf_error());
5436 		}
5437 	}
5438 
5439 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5440 		if (pg->sc_pgroup_seen)
5441 			continue;
5442 
5443 		/* pg is new */
5444 
5445 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5446 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5447 			    ent);
5448 			switch (r) {
5449 			case 0:
5450 				break;
5451 
5452 			case ECONNABORTED:
5453 			case ENOMEM:
5454 			case ENOSPC:
5455 			case ECANCELED:
5456 			case ENODEV:
5457 			case EBADF:
5458 			case EBUSY:
5459 			case EINVAL:
5460 			case EPERM:
5461 			case EROFS:
5462 			case EACCES:
5463 			case EEXIST:
5464 				return (r);
5465 
5466 			default:
5467 				bad_error("upgrade_dependents", r);
5468 			}
5469 			continue;
5470 		}
5471 
5472 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
5473 			r = upgrade_manifestfiles(pg, ient, running, ent);
5474 			switch (r) {
5475 			case 0:
5476 				break;
5477 
5478 			case ECONNABORTED:
5479 			case ENOMEM:
5480 			case ENOSPC:
5481 			case ECANCELED:
5482 			case ENODEV:
5483 			case EBADF:
5484 			case EBUSY:
5485 			case EINVAL:
5486 			case EPERM:
5487 			case EROFS:
5488 			case EACCES:
5489 			case EEXIST:
5490 				return (r);
5491 
5492 			default:
5493 				bad_error("upgrade_manifestfiles", r);
5494 			}
5495 			continue;
5496 		}
5497 
5498 		if (running != NULL) {
5499 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
5500 			    imp_pg);
5501 		} else {
5502 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
5503 			    imp_pg);
5504 		}
5505 		if (r != 0) {
5506 			scf_callback_t cbdata;
5507 
5508 			switch (scf_error()) {
5509 			case SCF_ERROR_NOT_FOUND:
5510 				break;
5511 
5512 			case SCF_ERROR_CONNECTION_BROKEN:
5513 				return (scferror2errno(scf_error()));
5514 
5515 			case SCF_ERROR_DELETED:
5516 				if (running != NULL)
5517 					return (ENODEV);
5518 				else
5519 					return (scferror2errno(scf_error()));
5520 
5521 			case SCF_ERROR_INVALID_ARGUMENT:
5522 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
5523 				    pg->sc_pgroup_name);
5524 				return (EINVAL);
5525 
5526 			case SCF_ERROR_NOT_SET:
5527 			case SCF_ERROR_HANDLE_MISMATCH:
5528 			case SCF_ERROR_NOT_BOUND:
5529 			default:
5530 				bad_error("entity_get_pg", scf_error());
5531 			}
5532 
5533 			/* User doesn't have pg, so import it. */
5534 
5535 			cbdata.sc_handle = g_hndl;
5536 			cbdata.sc_parent = ent;
5537 			cbdata.sc_service = issvc;
5538 			cbdata.sc_flags = SCI_FORCE;
5539 			cbdata.sc_source_fmri = ient->sc_fmri;
5540 			cbdata.sc_target_fmri = ient->sc_fmri;
5541 
5542 			r = entity_pgroup_import(pg, &cbdata);
5543 			switch (r) {
5544 			case UU_WALK_NEXT:
5545 				ient->sc_import_state = IMPORT_PROP_BEGUN;
5546 				continue;
5547 
5548 			case UU_WALK_ERROR:
5549 				if (cbdata.sc_err == EEXIST) {
5550 					warn(emsg_pg_added, ient->sc_fmri,
5551 					    pg->sc_pgroup_name);
5552 					return (EBUSY);
5553 				}
5554 				return (cbdata.sc_err);
5555 
5556 			default:
5557 				bad_error("entity_pgroup_import", r);
5558 			}
5559 		}
5560 
5561 		/* report differences between pg & current */
5562 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
5563 		switch (r) {
5564 		case 0:
5565 			break;
5566 
5567 		case ECANCELED:
5568 			warn(emsg_pg_deleted, ient->sc_fmri,
5569 			    pg->sc_pgroup_name);
5570 			return (EBUSY);
5571 
5572 		case ECONNABORTED:
5573 		case EBADF:
5574 		case ENOMEM:
5575 		case EACCES:
5576 			return (r);
5577 
5578 		default:
5579 			bad_error("load_pg", r);
5580 		}
5581 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
5582 		internal_pgroup_free(rpg);
5583 		rpg = NULL;
5584 	}
5585 
5586 	return (0);
5587 }
5588 
5589 /*
5590  * Import an instance.  If it doesn't exist, create it.  If it has
5591  * a last-import snapshot, upgrade its properties.  Finish by updating its
5592  * last-import snapshot.  If it doesn't have a last-import snapshot then it
5593  * could have been created for a dependent tag in another manifest.  Import the
5594  * new properties.  If there's a conflict, don't override, like now?
5595  *
5596  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
5597  * lcbdata->sc_err to
5598  *   ECONNABORTED - repository connection broken
5599  *   ENOMEM - out of memory
5600  *   ENOSPC - svc.configd is out of resources
5601  *   EEXIST - dependency collision in dependent service (error printed)
5602  *   EPERM - couldn't create temporary instance (permission denied)
5603  *	   - couldn't import into temporary instance (permission denied)
5604  *	   - couldn't take snapshot (permission denied)
5605  *	   - couldn't upgrade properties (permission denied)
5606  *	   - couldn't import properties (permission denied)
5607  *	   - couldn't import dependents (permission denied)
5608  *   EROFS - couldn't create temporary instance (repository read-only)
5609  *	   - couldn't import into temporary instance (repository read-only)
5610  *	   - couldn't upgrade properties (repository read-only)
5611  *	   - couldn't import properties (repository read-only)
5612  *	   - couldn't import dependents (repository read-only)
5613  *   EACCES - couldn't create temporary instance (backend access denied)
5614  *	    - couldn't import into temporary instance (backend access denied)
5615  *	    - couldn't upgrade properties (backend access denied)
5616  *	    - couldn't import properties (backend access denied)
5617  *	    - couldn't import dependents (backend access denied)
5618  *   EINVAL - invalid instance name (error printed)
5619  *	    - invalid pgroup_t's (error printed)
5620  *	    - invalid dependents (error printed)
5621  *   EBUSY - temporary service deleted (error printed)
5622  *	   - temporary instance deleted (error printed)
5623  *	   - temporary instance changed (error printed)
5624  *	   - temporary instance already exists (error printed)
5625  *	   - instance deleted (error printed)
5626  *   EBADF - instance has corrupt last-import snapshot (error printed)
5627  *	   - instance is corrupt (error printed)
5628  *	   - dependent has corrupt pg (error printed)
5629  *	   - dependent target has a corrupt snapshot (error printed)
5630  *   -1 - unknown libscf error (error printed)
5631  */
5632 static int
5633 lscf_instance_import(void *v, void *pvt)
5634 {
5635 	entity_t *inst = v;
5636 	scf_callback_t ctx;
5637 	scf_callback_t *lcbdata = pvt;
5638 	scf_service_t *rsvc = lcbdata->sc_parent;
5639 	int r;
5640 	scf_snaplevel_t *running;
5641 	int flags = lcbdata->sc_flags;
5642 
5643 	const char * const emsg_tdel =
5644 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
5645 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
5646 	    "changed unexpectedly.\n");
5647 	const char * const emsg_del = gettext("%s changed unexpectedly "
5648 	    "(instance \"%s\" was deleted.)\n");
5649 	const char * const emsg_badsnap = gettext(
5650 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
5651 
5652 	/*
5653 	 * prepare last-import snapshot:
5654 	 * create temporary instance (service was precreated)
5655 	 * populate with properties from bundle
5656 	 * take snapshot
5657 	 */
5658 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
5659 		switch (scf_error()) {
5660 		case SCF_ERROR_CONNECTION_BROKEN:
5661 		case SCF_ERROR_NO_RESOURCES:
5662 		case SCF_ERROR_BACKEND_READONLY:
5663 		case SCF_ERROR_BACKEND_ACCESS:
5664 			return (stash_scferror(lcbdata));
5665 
5666 		case SCF_ERROR_EXISTS:
5667 			warn(gettext("Temporary service svc:/%s "
5668 			    "changed unexpectedly (instance \"%s\" added).\n"),
5669 			    imp_tsname, inst->sc_name);
5670 			lcbdata->sc_err = EBUSY;
5671 			return (UU_WALK_ERROR);
5672 
5673 		case SCF_ERROR_DELETED:
5674 			warn(gettext("Temporary service svc:/%s "
5675 			    "was deleted unexpectedly.\n"), imp_tsname);
5676 			lcbdata->sc_err = EBUSY;
5677 			return (UU_WALK_ERROR);
5678 
5679 		case SCF_ERROR_INVALID_ARGUMENT:
5680 			warn(gettext("Invalid instance name \"%s\".\n"),
5681 			    inst->sc_name);
5682 			return (stash_scferror(lcbdata));
5683 
5684 		case SCF_ERROR_PERMISSION_DENIED:
5685 			warn(gettext("Could not create temporary instance "
5686 			    "\"%s\" in svc:/%s (permission denied).\n"),
5687 			    inst->sc_name, imp_tsname);
5688 			return (stash_scferror(lcbdata));
5689 
5690 		case SCF_ERROR_HANDLE_MISMATCH:
5691 		case SCF_ERROR_NOT_BOUND:
5692 		case SCF_ERROR_NOT_SET:
5693 		default:
5694 			bad_error("scf_service_add_instance", scf_error());
5695 		}
5696 	}
5697 
5698 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5699 	    inst->sc_name);
5700 	if (r < 0)
5701 		bad_error("snprintf", errno);
5702 
5703 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
5704 	    lcbdata->sc_flags | SCI_NOENABLED);
5705 	switch (r) {
5706 	case 0:
5707 		break;
5708 
5709 	case ECANCELED:
5710 		warn(emsg_tdel, imp_tsname, inst->sc_name);
5711 		lcbdata->sc_err = EBUSY;
5712 		r = UU_WALK_ERROR;
5713 		goto deltemp;
5714 
5715 	case EEXIST:
5716 		warn(emsg_tchg, imp_tsname, inst->sc_name);
5717 		lcbdata->sc_err = EBUSY;
5718 		r = UU_WALK_ERROR;
5719 		goto deltemp;
5720 
5721 	case ECONNABORTED:
5722 		goto connaborted;
5723 
5724 	case ENOMEM:
5725 	case ENOSPC:
5726 	case EPERM:
5727 	case EROFS:
5728 	case EACCES:
5729 	case EINVAL:
5730 	case EBUSY:
5731 		lcbdata->sc_err = r;
5732 		r = UU_WALK_ERROR;
5733 		goto deltemp;
5734 
5735 	default:
5736 		bad_error("lscf_import_instance_pgs", r);
5737 	}
5738 
5739 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5740 	    inst->sc_name);
5741 	if (r < 0)
5742 		bad_error("snprintf", errno);
5743 
5744 	ctx.sc_handle = lcbdata->sc_handle;
5745 	ctx.sc_parent = imp_tinst;
5746 	ctx.sc_service = 0;
5747 	ctx.sc_source_fmri = inst->sc_fmri;
5748 	ctx.sc_target_fmri = imp_str;
5749 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
5750 	    UU_DEFAULT) != 0) {
5751 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5752 			bad_error("uu_list_walk", uu_error());
5753 
5754 		switch (ctx.sc_err) {
5755 		case ECONNABORTED:
5756 			goto connaborted;
5757 
5758 		case ECANCELED:
5759 			warn(emsg_tdel, imp_tsname, inst->sc_name);
5760 			lcbdata->sc_err = EBUSY;
5761 			break;
5762 
5763 		case EEXIST:
5764 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5765 			lcbdata->sc_err = EBUSY;
5766 			break;
5767 
5768 		default:
5769 			lcbdata->sc_err = ctx.sc_err;
5770 		}
5771 		r = UU_WALK_ERROR;
5772 		goto deltemp;
5773 	}
5774 
5775 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
5776 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
5777 		switch (scf_error()) {
5778 		case SCF_ERROR_CONNECTION_BROKEN:
5779 			goto connaborted;
5780 
5781 		case SCF_ERROR_NO_RESOURCES:
5782 			r = stash_scferror(lcbdata);
5783 			goto deltemp;
5784 
5785 		case SCF_ERROR_EXISTS:
5786 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5787 			lcbdata->sc_err = EBUSY;
5788 			r = UU_WALK_ERROR;
5789 			goto deltemp;
5790 
5791 		case SCF_ERROR_PERMISSION_DENIED:
5792 			warn(gettext("Could not take \"%s\" snapshot of %s "
5793 			    "(permission denied).\n"), snap_lastimport,
5794 			    imp_str);
5795 			r = stash_scferror(lcbdata);
5796 			goto deltemp;
5797 
5798 		default:
5799 			scfwarn();
5800 			lcbdata->sc_err = -1;
5801 			r = UU_WALK_ERROR;
5802 			goto deltemp;
5803 
5804 		case SCF_ERROR_HANDLE_MISMATCH:
5805 		case SCF_ERROR_INVALID_ARGUMENT:
5806 		case SCF_ERROR_NOT_SET:
5807 			bad_error("_scf_snapshot_take_new_named", scf_error());
5808 		}
5809 	}
5810 
5811 	if (lcbdata->sc_flags & SCI_FRESH)
5812 		goto fresh;
5813 
5814 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
5815 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
5816 		    imp_lisnap) != 0) {
5817 			switch (scf_error()) {
5818 			case SCF_ERROR_DELETED:
5819 				warn(emsg_del, inst->sc_parent->sc_fmri,
5820 				    inst->sc_name);
5821 				lcbdata->sc_err = EBUSY;
5822 				r = UU_WALK_ERROR;
5823 				goto deltemp;
5824 
5825 			case SCF_ERROR_NOT_FOUND:
5826 				flags |= SCI_FORCE;
5827 				goto nosnap;
5828 
5829 			case SCF_ERROR_CONNECTION_BROKEN:
5830 				goto connaborted;
5831 
5832 			case SCF_ERROR_INVALID_ARGUMENT:
5833 			case SCF_ERROR_HANDLE_MISMATCH:
5834 			case SCF_ERROR_NOT_BOUND:
5835 			case SCF_ERROR_NOT_SET:
5836 			default:
5837 				bad_error("scf_instance_get_snapshot",
5838 				    scf_error());
5839 			}
5840 		}
5841 
5842 		/* upgrade */
5843 
5844 		/*
5845 		 * compare new properties with last-import properties
5846 		 * upgrade current properties
5847 		 */
5848 		/* clear sc_sceen for pgs */
5849 		if (uu_list_walk(inst->sc_pgroups, clear_int,
5850 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
5851 		    0)
5852 			bad_error("uu_list_walk", uu_error());
5853 
5854 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
5855 		switch (r) {
5856 		case 0:
5857 			break;
5858 
5859 		case ECONNABORTED:
5860 			goto connaborted;
5861 
5862 		case ECANCELED:
5863 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5864 			lcbdata->sc_err = EBUSY;
5865 			r = UU_WALK_ERROR;
5866 			goto deltemp;
5867 
5868 		case ENOENT:
5869 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
5870 			lcbdata->sc_err = EBADF;
5871 			r = UU_WALK_ERROR;
5872 			goto deltemp;
5873 
5874 		default:
5875 			bad_error("get_snaplevel", r);
5876 		}
5877 
5878 		if (scf_instance_get_snapshot(imp_inst, snap_running,
5879 		    imp_rsnap) != 0) {
5880 			switch (scf_error()) {
5881 			case SCF_ERROR_DELETED:
5882 				warn(emsg_del, inst->sc_parent->sc_fmri,
5883 				    inst->sc_name);
5884 				lcbdata->sc_err = EBUSY;
5885 				r = UU_WALK_ERROR;
5886 				goto deltemp;
5887 
5888 			case SCF_ERROR_NOT_FOUND:
5889 				break;
5890 
5891 			case SCF_ERROR_CONNECTION_BROKEN:
5892 				goto connaborted;
5893 
5894 			case SCF_ERROR_INVALID_ARGUMENT:
5895 			case SCF_ERROR_HANDLE_MISMATCH:
5896 			case SCF_ERROR_NOT_BOUND:
5897 			case SCF_ERROR_NOT_SET:
5898 			default:
5899 				bad_error("scf_instance_get_snapshot",
5900 				    scf_error());
5901 			}
5902 
5903 			running = NULL;
5904 		} else {
5905 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
5906 			switch (r) {
5907 			case 0:
5908 				running = imp_rsnpl;
5909 				break;
5910 
5911 			case ECONNABORTED:
5912 				goto connaborted;
5913 
5914 			case ECANCELED:
5915 				warn(emsg_del, inst->sc_parent->sc_fmri,
5916 				    inst->sc_name);
5917 				lcbdata->sc_err = EBUSY;
5918 				r = UU_WALK_ERROR;
5919 				goto deltemp;
5920 
5921 			case ENOENT:
5922 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
5923 				lcbdata->sc_err = EBADF;
5924 				r = UU_WALK_ERROR;
5925 				goto deltemp;
5926 
5927 			default:
5928 				bad_error("get_snaplevel", r);
5929 			}
5930 		}
5931 
5932 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
5933 		switch (r) {
5934 		case 0:
5935 			break;
5936 
5937 		case ECANCELED:
5938 		case ENODEV:
5939 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5940 			lcbdata->sc_err = EBUSY;
5941 			r = UU_WALK_ERROR;
5942 			goto deltemp;
5943 
5944 		case ECONNABORTED:
5945 			goto connaborted;
5946 
5947 		case ENOMEM:
5948 		case ENOSPC:
5949 		case EBADF:
5950 		case EBUSY:
5951 		case EINVAL:
5952 		case EPERM:
5953 		case EROFS:
5954 		case EACCES:
5955 		case EEXIST:
5956 			lcbdata->sc_err = r;
5957 			r = UU_WALK_ERROR;
5958 			goto deltemp;
5959 
5960 		default:
5961 			bad_error("upgrade_props", r);
5962 		}
5963 
5964 		inst->sc_import_state = IMPORT_PROP_DONE;
5965 	} else {
5966 		switch (scf_error()) {
5967 		case SCF_ERROR_CONNECTION_BROKEN:
5968 			goto connaborted;
5969 
5970 		case SCF_ERROR_NOT_FOUND:
5971 			break;
5972 
5973 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
5974 		case SCF_ERROR_HANDLE_MISMATCH:
5975 		case SCF_ERROR_NOT_BOUND:
5976 		case SCF_ERROR_NOT_SET:
5977 		default:
5978 			bad_error("scf_service_get_instance", scf_error());
5979 		}
5980 
5981 fresh:
5982 		/* create instance */
5983 		if (scf_service_add_instance(rsvc, inst->sc_name,
5984 		    imp_inst) != 0) {
5985 			switch (scf_error()) {
5986 			case SCF_ERROR_CONNECTION_BROKEN:
5987 				goto connaborted;
5988 
5989 			case SCF_ERROR_NO_RESOURCES:
5990 			case SCF_ERROR_BACKEND_READONLY:
5991 			case SCF_ERROR_BACKEND_ACCESS:
5992 				r = stash_scferror(lcbdata);
5993 				goto deltemp;
5994 
5995 			case SCF_ERROR_EXISTS:
5996 				warn(gettext("%s changed unexpectedly "
5997 				    "(instance \"%s\" added).\n"),
5998 				    inst->sc_parent->sc_fmri, inst->sc_name);
5999 				lcbdata->sc_err = EBUSY;
6000 				r = UU_WALK_ERROR;
6001 				goto deltemp;
6002 
6003 			case SCF_ERROR_PERMISSION_DENIED:
6004 				warn(gettext("Could not create \"%s\" instance "
6005 				    "in %s (permission denied).\n"),
6006 				    inst->sc_name, inst->sc_parent->sc_fmri);
6007 				r = stash_scferror(lcbdata);
6008 				goto deltemp;
6009 
6010 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6011 			case SCF_ERROR_HANDLE_MISMATCH:
6012 			case SCF_ERROR_NOT_BOUND:
6013 			case SCF_ERROR_NOT_SET:
6014 			default:
6015 				bad_error("scf_service_add_instance",
6016 				    scf_error());
6017 			}
6018 		}
6019 
6020 nosnap:
6021 		/*
6022 		 * Create a last-import snapshot to serve as an attachment
6023 		 * point for the real one from the temporary instance.  Since
6024 		 * the contents is irrelevant, take it now, while the instance
6025 		 * is empty, to minimize svc.configd's work.
6026 		 */
6027 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6028 		    imp_lisnap) != 0) {
6029 			switch (scf_error()) {
6030 			case SCF_ERROR_CONNECTION_BROKEN:
6031 				goto connaborted;
6032 
6033 			case SCF_ERROR_NO_RESOURCES:
6034 				r = stash_scferror(lcbdata);
6035 				goto deltemp;
6036 
6037 			case SCF_ERROR_EXISTS:
6038 				warn(gettext("%s changed unexpectedly "
6039 				    "(snapshot \"%s\" added).\n"),
6040 				    inst->sc_fmri, snap_lastimport);
6041 				lcbdata->sc_err = EBUSY;
6042 				r = UU_WALK_ERROR;
6043 				goto deltemp;
6044 
6045 			case SCF_ERROR_PERMISSION_DENIED:
6046 				warn(gettext("Could not take \"%s\" snapshot "
6047 				    "of %s (permission denied).\n"),
6048 				    snap_lastimport, inst->sc_fmri);
6049 				r = stash_scferror(lcbdata);
6050 				goto deltemp;
6051 
6052 			default:
6053 				scfwarn();
6054 				lcbdata->sc_err = -1;
6055 				r = UU_WALK_ERROR;
6056 				goto deltemp;
6057 
6058 			case SCF_ERROR_NOT_SET:
6059 			case SCF_ERROR_INTERNAL:
6060 			case SCF_ERROR_INVALID_ARGUMENT:
6061 			case SCF_ERROR_HANDLE_MISMATCH:
6062 				bad_error("_scf_snapshot_take_new",
6063 				    scf_error());
6064 			}
6065 		}
6066 
6067 		if (li_only)
6068 			goto lionly;
6069 
6070 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6071 
6072 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6073 		    flags);
6074 		switch (r) {
6075 		case 0:
6076 			break;
6077 
6078 		case ECONNABORTED:
6079 			goto connaborted;
6080 
6081 		case ECANCELED:
6082 			warn(gettext("%s changed unexpectedly "
6083 			    "(instance \"%s\" deleted).\n"),
6084 			    inst->sc_parent->sc_fmri, inst->sc_name);
6085 			lcbdata->sc_err = EBUSY;
6086 			r = UU_WALK_ERROR;
6087 			goto deltemp;
6088 
6089 		case EEXIST:
6090 			warn(gettext("%s changed unexpectedly "
6091 			    "(property group added).\n"), inst->sc_fmri);
6092 			lcbdata->sc_err = EBUSY;
6093 			r = UU_WALK_ERROR;
6094 			goto deltemp;
6095 
6096 		default:
6097 			lcbdata->sc_err = r;
6098 			r = UU_WALK_ERROR;
6099 			goto deltemp;
6100 
6101 		case EINVAL:	/* caught above */
6102 			bad_error("lscf_import_instance_pgs", r);
6103 		}
6104 
6105 		ctx.sc_parent = imp_inst;
6106 		ctx.sc_service = 0;
6107 		ctx.sc_trans = NULL;
6108 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6109 		    &ctx, UU_DEFAULT) != 0) {
6110 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6111 				bad_error("uu_list_walk", uu_error());
6112 
6113 			if (ctx.sc_err == ECONNABORTED)
6114 				goto connaborted;
6115 			lcbdata->sc_err = ctx.sc_err;
6116 			r = UU_WALK_ERROR;
6117 			goto deltemp;
6118 		}
6119 
6120 		inst->sc_import_state = IMPORT_PROP_DONE;
6121 
6122 		if (g_verbose)
6123 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6124 			    snap_initial, inst->sc_fmri);
6125 		r = take_snap(imp_inst, snap_initial, imp_snap);
6126 		switch (r) {
6127 		case 0:
6128 			break;
6129 
6130 		case ECONNABORTED:
6131 			goto connaborted;
6132 
6133 		case ENOSPC:
6134 		case -1:
6135 			lcbdata->sc_err = r;
6136 			r = UU_WALK_ERROR;
6137 			goto deltemp;
6138 
6139 		case ECANCELED:
6140 			warn(gettext("%s changed unexpectedly "
6141 			    "(instance %s deleted).\n"),
6142 			    inst->sc_parent->sc_fmri, inst->sc_name);
6143 			lcbdata->sc_err = r;
6144 			r = UU_WALK_ERROR;
6145 			goto deltemp;
6146 
6147 		case EPERM:
6148 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6149 			lcbdata->sc_err = r;
6150 			r = UU_WALK_ERROR;
6151 			goto deltemp;
6152 
6153 		default:
6154 			bad_error("take_snap", r);
6155 		}
6156 	}
6157 
6158 lionly:
6159 	if (lcbdata->sc_flags & SCI_NOSNAP)
6160 		goto deltemp;
6161 
6162 	/* transfer snapshot from temporary instance */
6163 	if (g_verbose)
6164 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6165 		    snap_lastimport, inst->sc_fmri);
6166 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6167 		switch (scf_error()) {
6168 		case SCF_ERROR_CONNECTION_BROKEN:
6169 			goto connaborted;
6170 
6171 		case SCF_ERROR_NO_RESOURCES:
6172 			r = stash_scferror(lcbdata);
6173 			goto deltemp;
6174 
6175 		case SCF_ERROR_PERMISSION_DENIED:
6176 			warn(gettext("Could not take \"%s\" snapshot for %s "
6177 			    "(permission denied).\n"), snap_lastimport,
6178 			    inst->sc_fmri);
6179 			r = stash_scferror(lcbdata);
6180 			goto deltemp;
6181 
6182 		case SCF_ERROR_NOT_SET:
6183 		case SCF_ERROR_HANDLE_MISMATCH:
6184 		default:
6185 			bad_error("_scf_snapshot_attach", scf_error());
6186 		}
6187 	}
6188 
6189 	inst->sc_import_state = IMPORT_COMPLETE;
6190 
6191 	r = UU_WALK_NEXT;
6192 
6193 deltemp:
6194 	/* delete temporary instance */
6195 	if (scf_instance_delete(imp_tinst) != 0) {
6196 		switch (scf_error()) {
6197 		case SCF_ERROR_DELETED:
6198 			break;
6199 
6200 		case SCF_ERROR_CONNECTION_BROKEN:
6201 			goto connaborted;
6202 
6203 		case SCF_ERROR_NOT_SET:
6204 		case SCF_ERROR_NOT_BOUND:
6205 		default:
6206 			bad_error("scf_instance_delete", scf_error());
6207 		}
6208 	}
6209 
6210 	return (r);
6211 
6212 connaborted:
6213 	warn(gettext("Could not delete svc:/%s:%s "
6214 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6215 	lcbdata->sc_err = ECONNABORTED;
6216 	return (UU_WALK_ERROR);
6217 }
6218 
6219 /*
6220  * If the service is missing, create it, import its properties, and import the
6221  * instances.  Since the service is brand new, it should be empty, and if we
6222  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6223  *
6224  * If the service exists, we want to upgrade its properties and import the
6225  * instances.  Upgrade requires a last-import snapshot, though, which are
6226  * children of instances, so first we'll have to go through the instances
6227  * looking for a last-import snapshot.  If we don't find one then we'll just
6228  * override-import the service properties (but don't delete existing
6229  * properties: another service might have declared us as a dependent).  Before
6230  * we change anything, though, we want to take the previous snapshots.  We
6231  * also give lscf_instance_import() a leg up on taking last-import snapshots
6232  * by importing the manifest's service properties into a temporary service.
6233  *
6234  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6235  * sets lcbdata->sc_err to
6236  *   ECONNABORTED - repository connection broken
6237  *   ENOMEM - out of memory
6238  *   ENOSPC - svc.configd is out of resources
6239  *   EPERM - couldn't create temporary service (error printed)
6240  *	   - couldn't import into temp service (error printed)
6241  *	   - couldn't create service (error printed)
6242  *	   - couldn't import dependent (error printed)
6243  *	   - couldn't take snapshot (error printed)
6244  *	   - couldn't create instance (error printed)
6245  *	   - couldn't create, modify, or delete pg (error printed)
6246  *	   - couldn't create, modify, or delete dependent (error printed)
6247  *	   - couldn't import instance (error printed)
6248  *   EROFS - couldn't create temporary service (repository read-only)
6249  *	   - couldn't import into temporary service (repository read-only)
6250  *	   - couldn't create service (repository read-only)
6251  *	   - couldn't import dependent (repository read-only)
6252  *	   - couldn't create instance (repository read-only)
6253  *	   - couldn't create, modify, or delete pg or dependent
6254  *	   - couldn't import instance (repository read-only)
6255  *   EACCES - couldn't create temporary service (backend access denied)
6256  *	    - couldn't import into temporary service (backend access denied)
6257  *	    - couldn't create service (backend access denied)
6258  *	    - couldn't import dependent (backend access denied)
6259  *	    - couldn't create instance (backend access denied)
6260  *	    - couldn't create, modify, or delete pg or dependent
6261  *	    - couldn't import instance (backend access denied)
6262  *   EINVAL - service name is invalid (error printed)
6263  *	    - service name is too long (error printed)
6264  *	    - s has invalid pgroup (error printed)
6265  *	    - s has invalid dependent (error printed)
6266  *	    - instance name is invalid (error printed)
6267  *	    - instance entity_t is invalid (error printed)
6268  *   EEXIST - couldn't create temporary service (already exists) (error printed)
6269  *	    - couldn't import dependent (dependency pg already exists) (printed)
6270  *	    - dependency collision in dependent service (error printed)
6271  *   EBUSY - temporary service deleted (error printed)
6272  *	   - property group added to temporary service (error printed)
6273  *	   - new property group changed or was deleted (error printed)
6274  *	   - service was added unexpectedly (error printed)
6275  *	   - service was deleted unexpectedly (error printed)
6276  *	   - property group added to new service (error printed)
6277  *	   - instance added unexpectedly (error printed)
6278  *	   - instance deleted unexpectedly (error printed)
6279  *	   - dependent service deleted unexpectedly (error printed)
6280  *	   - pg was added, changed, or deleted (error printed)
6281  *	   - dependent pg changed (error printed)
6282  *	   - temporary instance added, changed, or deleted (error printed)
6283  *   EBADF - a last-import snapshot is corrupt (error printed)
6284  *	   - the service is corrupt (error printed)
6285  *	   - a dependent is corrupt (error printed)
6286  *	   - an instance is corrupt (error printed)
6287  *	   - an instance has a corrupt last-import snapshot (error printed)
6288  *	   - dependent target has a corrupt snapshot (error printed)
6289  *   -1 - unknown libscf error (error printed)
6290  */
6291 static int
6292 lscf_service_import(void *v, void *pvt)
6293 {
6294 	entity_t *s = v;
6295 	scf_callback_t cbdata;
6296 	scf_callback_t *lcbdata = pvt;
6297 	scf_scope_t *scope = lcbdata->sc_parent;
6298 	entity_t *inst, linst;
6299 	int r;
6300 	int fresh = 0;
6301 	scf_snaplevel_t *running;
6302 	int have_ge = 0;
6303 
6304 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
6305 	    "was deleted unexpectedly.\n");
6306 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6307 	    "changed unexpectedly (property group added).\n");
6308 	const char * const s_deleted =
6309 	    gettext("%s was deleted unexpectedly.\n");
6310 	const char * const i_deleted =
6311 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6312 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6313 	    "is corrupt (missing service snaplevel).\n");
6314 
6315 	li_only = 0;
6316 	/* Validate the service name */
6317 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6318 		switch (scf_error()) {
6319 		case SCF_ERROR_CONNECTION_BROKEN:
6320 			return (stash_scferror(lcbdata));
6321 
6322 		case SCF_ERROR_INVALID_ARGUMENT:
6323 			warn(gettext("\"%s\" is an invalid service name.  "
6324 			    "Cannot import.\n"), s->sc_name);
6325 			return (stash_scferror(lcbdata));
6326 
6327 		case SCF_ERROR_NOT_FOUND:
6328 			break;
6329 
6330 		case SCF_ERROR_HANDLE_MISMATCH:
6331 		case SCF_ERROR_NOT_BOUND:
6332 		case SCF_ERROR_NOT_SET:
6333 		default:
6334 			bad_error("scf_scope_get_service", scf_error());
6335 		}
6336 	}
6337 
6338 	/* create temporary service */
6339 	/*
6340 	 * the size of the buffer was reduced to max_scf_name_len to prevent
6341 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6342 	 * should be restored to its original value (max_scf_name_len +1)
6343 	 */
6344 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6345 	if (r < 0)
6346 		bad_error("snprintf", errno);
6347 	if (r > max_scf_name_len) {
6348 		warn(gettext(
6349 		    "Service name \"%s\" is too long.  Cannot import.\n"),
6350 		    s->sc_name);
6351 		lcbdata->sc_err = EINVAL;
6352 		return (UU_WALK_ERROR);
6353 	}
6354 
6355 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6356 		switch (scf_error()) {
6357 		case SCF_ERROR_CONNECTION_BROKEN:
6358 		case SCF_ERROR_NO_RESOURCES:
6359 		case SCF_ERROR_BACKEND_READONLY:
6360 		case SCF_ERROR_BACKEND_ACCESS:
6361 			return (stash_scferror(lcbdata));
6362 
6363 		case SCF_ERROR_EXISTS:
6364 			warn(gettext(
6365 			    "Temporary service \"%s\" must be deleted before "
6366 			    "this manifest can be imported.\n"), imp_tsname);
6367 			return (stash_scferror(lcbdata));
6368 
6369 		case SCF_ERROR_PERMISSION_DENIED:
6370 			warn(gettext("Could not create temporary service "
6371 			    "\"%s\" (permission denied).\n"), imp_tsname);
6372 			return (stash_scferror(lcbdata));
6373 
6374 		case SCF_ERROR_INVALID_ARGUMENT:
6375 		case SCF_ERROR_HANDLE_MISMATCH:
6376 		case SCF_ERROR_NOT_BOUND:
6377 		case SCF_ERROR_NOT_SET:
6378 		default:
6379 			bad_error("scf_scope_add_service", scf_error());
6380 		}
6381 	}
6382 
6383 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6384 	if (r < 0)
6385 		bad_error("snprintf", errno);
6386 
6387 	cbdata.sc_handle = lcbdata->sc_handle;
6388 	cbdata.sc_parent = imp_tsvc;
6389 	cbdata.sc_service = 1;
6390 	cbdata.sc_source_fmri = s->sc_fmri;
6391 	cbdata.sc_target_fmri = imp_str;
6392 	cbdata.sc_flags = 0;
6393 
6394 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6395 	    UU_DEFAULT) != 0) {
6396 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6397 			bad_error("uu_list_walk", uu_error());
6398 
6399 		lcbdata->sc_err = cbdata.sc_err;
6400 		switch (cbdata.sc_err) {
6401 		case ECONNABORTED:
6402 			goto connaborted;
6403 
6404 		case ECANCELED:
6405 			warn(ts_deleted, imp_tsname);
6406 			lcbdata->sc_err = EBUSY;
6407 			return (UU_WALK_ERROR);
6408 
6409 		case EEXIST:
6410 			warn(ts_pg_added, imp_tsname);
6411 			lcbdata->sc_err = EBUSY;
6412 			return (UU_WALK_ERROR);
6413 		}
6414 
6415 		r = UU_WALK_ERROR;
6416 		goto deltemp;
6417 	}
6418 
6419 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6420 	    UU_DEFAULT) != 0) {
6421 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6422 			bad_error("uu_list_walk", uu_error());
6423 
6424 		lcbdata->sc_err = cbdata.sc_err;
6425 		switch (cbdata.sc_err) {
6426 		case ECONNABORTED:
6427 			goto connaborted;
6428 
6429 		case ECANCELED:
6430 			warn(ts_deleted, imp_tsname);
6431 			lcbdata->sc_err = EBUSY;
6432 			return (UU_WALK_ERROR);
6433 
6434 		case EEXIST:
6435 			warn(ts_pg_added, imp_tsname);
6436 			lcbdata->sc_err = EBUSY;
6437 			return (UU_WALK_ERROR);
6438 		}
6439 
6440 		r = UU_WALK_ERROR;
6441 		goto deltemp;
6442 	}
6443 
6444 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6445 		switch (scf_error()) {
6446 		case SCF_ERROR_NOT_FOUND:
6447 			break;
6448 
6449 		case SCF_ERROR_CONNECTION_BROKEN:
6450 			goto connaborted;
6451 
6452 		case SCF_ERROR_INVALID_ARGUMENT:
6453 		case SCF_ERROR_HANDLE_MISMATCH:
6454 		case SCF_ERROR_NOT_BOUND:
6455 		case SCF_ERROR_NOT_SET:
6456 		default:
6457 			bad_error("scf_scope_get_service", scf_error());
6458 		}
6459 
6460 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6461 			switch (scf_error()) {
6462 			case SCF_ERROR_CONNECTION_BROKEN:
6463 				goto connaborted;
6464 
6465 			case SCF_ERROR_NO_RESOURCES:
6466 			case SCF_ERROR_BACKEND_READONLY:
6467 			case SCF_ERROR_BACKEND_ACCESS:
6468 				r = stash_scferror(lcbdata);
6469 				goto deltemp;
6470 
6471 			case SCF_ERROR_EXISTS:
6472 				warn(gettext("Scope \"%s\" changed unexpectedly"
6473 				    " (service \"%s\" added).\n"),
6474 				    SCF_SCOPE_LOCAL, s->sc_name);
6475 				lcbdata->sc_err = EBUSY;
6476 				goto deltemp;
6477 
6478 			case SCF_ERROR_PERMISSION_DENIED:
6479 				warn(gettext("Could not create service \"%s\" "
6480 				    "(permission denied).\n"), s->sc_name);
6481 				goto deltemp;
6482 
6483 			case SCF_ERROR_INVALID_ARGUMENT:
6484 			case SCF_ERROR_HANDLE_MISMATCH:
6485 			case SCF_ERROR_NOT_BOUND:
6486 			case SCF_ERROR_NOT_SET:
6487 			default:
6488 				bad_error("scf_scope_add_service", scf_error());
6489 			}
6490 		}
6491 
6492 		s->sc_import_state = IMPORT_PROP_BEGUN;
6493 
6494 		/* import service properties */
6495 		cbdata.sc_handle = lcbdata->sc_handle;
6496 		cbdata.sc_parent = imp_svc;
6497 		cbdata.sc_service = 1;
6498 		cbdata.sc_flags = lcbdata->sc_flags;
6499 		cbdata.sc_source_fmri = s->sc_fmri;
6500 		cbdata.sc_target_fmri = s->sc_fmri;
6501 
6502 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6503 		    &cbdata, UU_DEFAULT) != 0) {
6504 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6505 				bad_error("uu_list_walk", uu_error());
6506 
6507 			lcbdata->sc_err = cbdata.sc_err;
6508 			switch (cbdata.sc_err) {
6509 			case ECONNABORTED:
6510 				goto connaborted;
6511 
6512 			case ECANCELED:
6513 				warn(s_deleted, s->sc_fmri);
6514 				lcbdata->sc_err = EBUSY;
6515 				return (UU_WALK_ERROR);
6516 
6517 			case EEXIST:
6518 				warn(gettext("%s changed unexpectedly "
6519 				    "(property group added).\n"), s->sc_fmri);
6520 				lcbdata->sc_err = EBUSY;
6521 				return (UU_WALK_ERROR);
6522 
6523 			case EINVAL:
6524 				/* caught above */
6525 				bad_error("entity_pgroup_import",
6526 				    cbdata.sc_err);
6527 			}
6528 
6529 			r = UU_WALK_ERROR;
6530 			goto deltemp;
6531 		}
6532 
6533 		cbdata.sc_trans = NULL;
6534 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
6535 		    &cbdata, UU_DEFAULT) != 0) {
6536 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6537 				bad_error("uu_list_walk", uu_error());
6538 
6539 			lcbdata->sc_err = cbdata.sc_err;
6540 			if (cbdata.sc_err == ECONNABORTED)
6541 				goto connaborted;
6542 			r = UU_WALK_ERROR;
6543 			goto deltemp;
6544 		}
6545 
6546 		s->sc_import_state = IMPORT_PROP_DONE;
6547 
6548 		/*
6549 		 * This is a new service, so we can't take previous snapshots
6550 		 * or upgrade service properties.
6551 		 */
6552 		fresh = 1;
6553 		goto instances;
6554 	}
6555 
6556 	/* Clear sc_seen for the instances. */
6557 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
6558 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
6559 		bad_error("uu_list_walk", uu_error());
6560 
6561 	/*
6562 	 * Take previous snapshots for all instances.  Even for ones not
6563 	 * mentioned in the bundle, since we might change their service
6564 	 * properties.
6565 	 */
6566 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6567 		switch (scf_error()) {
6568 		case SCF_ERROR_CONNECTION_BROKEN:
6569 			goto connaborted;
6570 
6571 		case SCF_ERROR_DELETED:
6572 			warn(s_deleted, s->sc_fmri);
6573 			lcbdata->sc_err = EBUSY;
6574 			r = UU_WALK_ERROR;
6575 			goto deltemp;
6576 
6577 		case SCF_ERROR_HANDLE_MISMATCH:
6578 		case SCF_ERROR_NOT_BOUND:
6579 		case SCF_ERROR_NOT_SET:
6580 		default:
6581 			bad_error("scf_iter_service_instances", scf_error());
6582 		}
6583 	}
6584 
6585 	for (;;) {
6586 		r = scf_iter_next_instance(imp_iter, imp_inst);
6587 		if (r == 0)
6588 			break;
6589 		if (r != 1) {
6590 			switch (scf_error()) {
6591 			case SCF_ERROR_DELETED:
6592 				warn(s_deleted, s->sc_fmri);
6593 				lcbdata->sc_err = EBUSY;
6594 				r = UU_WALK_ERROR;
6595 				goto deltemp;
6596 
6597 			case SCF_ERROR_CONNECTION_BROKEN:
6598 				goto connaborted;
6599 
6600 			case SCF_ERROR_NOT_BOUND:
6601 			case SCF_ERROR_HANDLE_MISMATCH:
6602 			case SCF_ERROR_INVALID_ARGUMENT:
6603 			case SCF_ERROR_NOT_SET:
6604 			default:
6605 				bad_error("scf_iter_next_instance",
6606 				    scf_error());
6607 			}
6608 		}
6609 
6610 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
6611 			switch (scf_error()) {
6612 			case SCF_ERROR_DELETED:
6613 				continue;
6614 
6615 			case SCF_ERROR_CONNECTION_BROKEN:
6616 				goto connaborted;
6617 
6618 			case SCF_ERROR_NOT_SET:
6619 			case SCF_ERROR_NOT_BOUND:
6620 			default:
6621 				bad_error("scf_instance_get_name", scf_error());
6622 			}
6623 		}
6624 
6625 		if (g_verbose)
6626 			warn(gettext(
6627 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
6628 			    snap_previous, s->sc_name, imp_str);
6629 
6630 		r = take_snap(imp_inst, snap_previous, imp_snap);
6631 		switch (r) {
6632 		case 0:
6633 			break;
6634 
6635 		case ECANCELED:
6636 			continue;
6637 
6638 		case ECONNABORTED:
6639 			goto connaborted;
6640 
6641 		case EPERM:
6642 			warn(gettext("Could not take \"%s\" snapshot of "
6643 			    "svc:/%s:%s (permission denied).\n"),
6644 			    snap_previous, s->sc_name, imp_str);
6645 			lcbdata->sc_err = r;
6646 			return (UU_WALK_ERROR);
6647 
6648 		case ENOSPC:
6649 		case -1:
6650 			lcbdata->sc_err = r;
6651 			r = UU_WALK_ERROR;
6652 			goto deltemp;
6653 
6654 		default:
6655 			bad_error("take_snap", r);
6656 		}
6657 
6658 		linst.sc_name = imp_str;
6659 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
6660 		    &linst, NULL, NULL);
6661 		if (inst != NULL) {
6662 			inst->sc_import_state = IMPORT_PREVIOUS;
6663 			inst->sc_seen = 1;
6664 		}
6665 	}
6666 
6667 	/*
6668 	 * Create the new instances and take previous snapshots of
6669 	 * them.  This is not necessary, but it maximizes data preservation.
6670 	 */
6671 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
6672 	    inst != NULL;
6673 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
6674 	    inst)) {
6675 		if (inst->sc_seen)
6676 			continue;
6677 
6678 		if (scf_service_add_instance(imp_svc, inst->sc_name,
6679 		    imp_inst) != 0) {
6680 			switch (scf_error()) {
6681 			case SCF_ERROR_CONNECTION_BROKEN:
6682 				goto connaborted;
6683 
6684 			case SCF_ERROR_BACKEND_READONLY:
6685 			case SCF_ERROR_BACKEND_ACCESS:
6686 			case SCF_ERROR_NO_RESOURCES:
6687 				r = stash_scferror(lcbdata);
6688 				goto deltemp;
6689 
6690 			case SCF_ERROR_EXISTS:
6691 				warn(gettext("%s changed unexpectedly "
6692 				    "(instance \"%s\" added).\n"), s->sc_fmri,
6693 				    inst->sc_name);
6694 				lcbdata->sc_err = EBUSY;
6695 				r = UU_WALK_ERROR;
6696 				goto deltemp;
6697 
6698 			case SCF_ERROR_INVALID_ARGUMENT:
6699 				warn(gettext("Service \"%s\" has instance with "
6700 				    "invalid name \"%s\".\n"), s->sc_name,
6701 				    inst->sc_name);
6702 				r = stash_scferror(lcbdata);
6703 				goto deltemp;
6704 
6705 			case SCF_ERROR_PERMISSION_DENIED:
6706 				warn(gettext("Could not create instance \"%s\" "
6707 				    "in %s (permission denied).\n"),
6708 				    inst->sc_name, s->sc_fmri);
6709 				r = stash_scferror(lcbdata);
6710 				goto deltemp;
6711 
6712 			case SCF_ERROR_HANDLE_MISMATCH:
6713 			case SCF_ERROR_NOT_BOUND:
6714 			case SCF_ERROR_NOT_SET:
6715 			default:
6716 				bad_error("scf_service_add_instance",
6717 				    scf_error());
6718 			}
6719 		}
6720 
6721 		if (g_verbose)
6722 			warn(gettext("Taking \"%s\" snapshot for "
6723 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
6724 		r = take_snap(imp_inst, snap_previous, imp_snap);
6725 		switch (r) {
6726 		case 0:
6727 			break;
6728 
6729 		case ECANCELED:
6730 			warn(i_deleted, s->sc_fmri, inst->sc_name);
6731 			lcbdata->sc_err = EBUSY;
6732 			r = UU_WALK_ERROR;
6733 			goto deltemp;
6734 
6735 		case ECONNABORTED:
6736 			goto connaborted;
6737 
6738 		case EPERM:
6739 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
6740 			lcbdata->sc_err = r;
6741 			r = UU_WALK_ERROR;
6742 			goto deltemp;
6743 
6744 		case ENOSPC:
6745 		case -1:
6746 			r = UU_WALK_ERROR;
6747 			goto deltemp;
6748 
6749 		default:
6750 			bad_error("take_snap", r);
6751 		}
6752 	}
6753 
6754 	s->sc_import_state = IMPORT_PREVIOUS;
6755 
6756 	/*
6757 	 * Upgrade service properties, if we can find a last-import snapshot.
6758 	 * Any will do because we don't support different service properties
6759 	 * in different manifests, so all snaplevels of the service in all of
6760 	 * the last-import snapshots of the instances should be the same.
6761 	 */
6762 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6763 		switch (scf_error()) {
6764 		case SCF_ERROR_CONNECTION_BROKEN:
6765 			goto connaborted;
6766 
6767 		case SCF_ERROR_DELETED:
6768 			warn(s_deleted, s->sc_fmri);
6769 			lcbdata->sc_err = EBUSY;
6770 			r = UU_WALK_ERROR;
6771 			goto deltemp;
6772 
6773 		case SCF_ERROR_HANDLE_MISMATCH:
6774 		case SCF_ERROR_NOT_BOUND:
6775 		case SCF_ERROR_NOT_SET:
6776 		default:
6777 			bad_error("scf_iter_service_instances", scf_error());
6778 		}
6779 	}
6780 
6781 	for (;;) {
6782 		r = scf_iter_next_instance(imp_iter, imp_inst);
6783 		if (r == -1) {
6784 			switch (scf_error()) {
6785 			case SCF_ERROR_DELETED:
6786 				warn(s_deleted, s->sc_fmri);
6787 				lcbdata->sc_err = EBUSY;
6788 				r = UU_WALK_ERROR;
6789 				goto deltemp;
6790 
6791 			case SCF_ERROR_CONNECTION_BROKEN:
6792 				goto connaborted;
6793 
6794 			case SCF_ERROR_NOT_BOUND:
6795 			case SCF_ERROR_HANDLE_MISMATCH:
6796 			case SCF_ERROR_INVALID_ARGUMENT:
6797 			case SCF_ERROR_NOT_SET:
6798 			default:
6799 				bad_error("scf_iter_next_instance",
6800 				    scf_error());
6801 			}
6802 		}
6803 
6804 		if (r == 0) {
6805 			/*
6806 			 * Didn't find any last-import snapshots.  Override-
6807 			 * import the properties.  Unless one of the instances
6808 			 * has a general/enabled property, in which case we're
6809 			 * probably running a last-import-capable svccfg for
6810 			 * the first time, and we should only take the
6811 			 * last-import snapshot.
6812 			 */
6813 			if (have_ge) {
6814 				li_only = 1;
6815 				no_refresh = 1;
6816 				break;
6817 			}
6818 
6819 			s->sc_import_state = IMPORT_PROP_BEGUN;
6820 
6821 			cbdata.sc_handle = g_hndl;
6822 			cbdata.sc_parent = imp_svc;
6823 			cbdata.sc_service = 1;
6824 			cbdata.sc_flags = SCI_FORCE;
6825 			cbdata.sc_source_fmri = s->sc_fmri;
6826 			cbdata.sc_target_fmri = s->sc_fmri;
6827 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6828 			    &cbdata, UU_DEFAULT) != 0) {
6829 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6830 					bad_error("uu_list_walk", uu_error());
6831 				lcbdata->sc_err = cbdata.sc_err;
6832 				switch (cbdata.sc_err) {
6833 				case ECONNABORTED:
6834 					goto connaborted;
6835 
6836 				case ECANCELED:
6837 					warn(s_deleted, s->sc_fmri);
6838 					lcbdata->sc_err = EBUSY;
6839 					break;
6840 
6841 				case EINVAL:	/* caught above */
6842 				case EEXIST:
6843 					bad_error("entity_pgroup_import",
6844 					    cbdata.sc_err);
6845 				}
6846 
6847 				r = UU_WALK_ERROR;
6848 				goto deltemp;
6849 			}
6850 
6851 			cbdata.sc_trans = NULL;
6852 			if (uu_list_walk(s->sc_dependents,
6853 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
6854 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6855 					bad_error("uu_list_walk", uu_error());
6856 				lcbdata->sc_err = cbdata.sc_err;
6857 				if (cbdata.sc_err == ECONNABORTED)
6858 					goto connaborted;
6859 				r = UU_WALK_ERROR;
6860 				goto deltemp;
6861 			}
6862 			break;
6863 		}
6864 
6865 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6866 		    imp_snap) != 0) {
6867 			switch (scf_error()) {
6868 			case SCF_ERROR_DELETED:
6869 				continue;
6870 
6871 			case SCF_ERROR_NOT_FOUND:
6872 				break;
6873 
6874 			case SCF_ERROR_CONNECTION_BROKEN:
6875 				goto connaborted;
6876 
6877 			case SCF_ERROR_HANDLE_MISMATCH:
6878 			case SCF_ERROR_NOT_BOUND:
6879 			case SCF_ERROR_INVALID_ARGUMENT:
6880 			case SCF_ERROR_NOT_SET:
6881 			default:
6882 				bad_error("scf_instance_get_snapshot",
6883 				    scf_error());
6884 			}
6885 
6886 			if (have_ge)
6887 				continue;
6888 
6889 			/*
6890 			 * Check for a general/enabled property.  This is how
6891 			 * we tell whether to import if there turn out to be
6892 			 * no last-import snapshots.
6893 			 */
6894 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
6895 			    imp_pg) == 0) {
6896 				if (scf_pg_get_property(imp_pg,
6897 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
6898 					have_ge = 1;
6899 				} else {
6900 					switch (scf_error()) {
6901 					case SCF_ERROR_DELETED:
6902 					case SCF_ERROR_NOT_FOUND:
6903 						continue;
6904 
6905 					case SCF_ERROR_INVALID_ARGUMENT:
6906 					case SCF_ERROR_HANDLE_MISMATCH:
6907 					case SCF_ERROR_CONNECTION_BROKEN:
6908 					case SCF_ERROR_NOT_BOUND:
6909 					case SCF_ERROR_NOT_SET:
6910 					default:
6911 						bad_error("scf_pg_get_property",
6912 						    scf_error());
6913 					}
6914 				}
6915 			} else {
6916 				switch (scf_error()) {
6917 				case SCF_ERROR_DELETED:
6918 				case SCF_ERROR_NOT_FOUND:
6919 					continue;
6920 
6921 				case SCF_ERROR_CONNECTION_BROKEN:
6922 					goto connaborted;
6923 
6924 				case SCF_ERROR_NOT_BOUND:
6925 				case SCF_ERROR_NOT_SET:
6926 				case SCF_ERROR_INVALID_ARGUMENT:
6927 				case SCF_ERROR_HANDLE_MISMATCH:
6928 				default:
6929 					bad_error("scf_instance_get_pg",
6930 					    scf_error());
6931 				}
6932 			}
6933 			continue;
6934 		}
6935 
6936 		/* find service snaplevel */
6937 		r = get_snaplevel(imp_snap, 1, imp_snpl);
6938 		switch (r) {
6939 		case 0:
6940 			break;
6941 
6942 		case ECONNABORTED:
6943 			goto connaborted;
6944 
6945 		case ECANCELED:
6946 			continue;
6947 
6948 		case ENOENT:
6949 			if (scf_instance_get_name(imp_inst, imp_str,
6950 			    imp_str_sz) < 0)
6951 				(void) strcpy(imp_str, "?");
6952 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
6953 			lcbdata->sc_err = EBADF;
6954 			r = UU_WALK_ERROR;
6955 			goto deltemp;
6956 
6957 		default:
6958 			bad_error("get_snaplevel", r);
6959 		}
6960 
6961 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6962 		    imp_rsnap) != 0) {
6963 			switch (scf_error()) {
6964 			case SCF_ERROR_DELETED:
6965 				continue;
6966 
6967 			case SCF_ERROR_NOT_FOUND:
6968 				break;
6969 
6970 			case SCF_ERROR_CONNECTION_BROKEN:
6971 				goto connaborted;
6972 
6973 			case SCF_ERROR_INVALID_ARGUMENT:
6974 			case SCF_ERROR_HANDLE_MISMATCH:
6975 			case SCF_ERROR_NOT_BOUND:
6976 			case SCF_ERROR_NOT_SET:
6977 			default:
6978 				bad_error("scf_instance_get_snapshot",
6979 				    scf_error());
6980 			}
6981 			running = NULL;
6982 		} else {
6983 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
6984 			switch (r) {
6985 			case 0:
6986 				running = imp_rsnpl;
6987 				break;
6988 
6989 			case ECONNABORTED:
6990 				goto connaborted;
6991 
6992 			case ECANCELED:
6993 				continue;
6994 
6995 			case ENOENT:
6996 				if (scf_instance_get_name(imp_inst, imp_str,
6997 				    imp_str_sz) < 0)
6998 					(void) strcpy(imp_str, "?");
6999 				warn(badsnap, snap_running, s->sc_name,
7000 				    imp_str);
7001 				lcbdata->sc_err = EBADF;
7002 				r = UU_WALK_ERROR;
7003 				goto deltemp;
7004 
7005 			default:
7006 				bad_error("get_snaplevel", r);
7007 			}
7008 		}
7009 
7010 		if (g_verbose) {
7011 			if (scf_instance_get_name(imp_inst, imp_str,
7012 			    imp_str_sz) < 0)
7013 				(void) strcpy(imp_str, "?");
7014 			warn(gettext("Upgrading properties of %s according to "
7015 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7016 		}
7017 
7018 		/* upgrade service properties */
7019 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7020 		if (r == 0)
7021 			break;
7022 
7023 		switch (r) {
7024 		case ECONNABORTED:
7025 			goto connaborted;
7026 
7027 		case ECANCELED:
7028 			warn(s_deleted, s->sc_fmri);
7029 			lcbdata->sc_err = EBUSY;
7030 			break;
7031 
7032 		case ENODEV:
7033 			if (scf_instance_get_name(imp_inst, imp_str,
7034 			    imp_str_sz) < 0)
7035 				(void) strcpy(imp_str, "?");
7036 			warn(i_deleted, s->sc_fmri, imp_str);
7037 			lcbdata->sc_err = EBUSY;
7038 			break;
7039 
7040 		default:
7041 			lcbdata->sc_err = r;
7042 		}
7043 
7044 		r = UU_WALK_ERROR;
7045 		goto deltemp;
7046 	}
7047 
7048 	s->sc_import_state = IMPORT_PROP_DONE;
7049 
7050 instances:
7051 	/* import instances */
7052 	cbdata.sc_handle = lcbdata->sc_handle;
7053 	cbdata.sc_parent = imp_svc;
7054 	cbdata.sc_service = 1;
7055 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7056 	cbdata.sc_general = NULL;
7057 
7058 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7059 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7060 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7061 			bad_error("uu_list_walk", uu_error());
7062 
7063 		lcbdata->sc_err = cbdata.sc_err;
7064 		if (cbdata.sc_err == ECONNABORTED)
7065 			goto connaborted;
7066 		r = UU_WALK_ERROR;
7067 		goto deltemp;
7068 	}
7069 
7070 	s->sc_import_state = IMPORT_COMPLETE;
7071 	r = UU_WALK_NEXT;
7072 
7073 deltemp:
7074 	/* delete temporary service */
7075 	if (scf_service_delete(imp_tsvc) != 0) {
7076 		switch (scf_error()) {
7077 		case SCF_ERROR_DELETED:
7078 			break;
7079 
7080 		case SCF_ERROR_CONNECTION_BROKEN:
7081 			goto connaborted;
7082 
7083 		case SCF_ERROR_EXISTS:
7084 			warn(gettext(
7085 			    "Could not delete svc:/%s (instances exist).\n"),
7086 			    imp_tsname);
7087 			break;
7088 
7089 		case SCF_ERROR_NOT_SET:
7090 		case SCF_ERROR_NOT_BOUND:
7091 		default:
7092 			bad_error("scf_service_delete", scf_error());
7093 		}
7094 	}
7095 
7096 	return (r);
7097 
7098 connaborted:
7099 	warn(gettext("Could not delete svc:/%s "
7100 	    "(repository connection broken).\n"), imp_tsname);
7101 	lcbdata->sc_err = ECONNABORTED;
7102 	return (UU_WALK_ERROR);
7103 }
7104 
7105 static const char *
7106 import_progress(int st)
7107 {
7108 	switch (st) {
7109 	case 0:
7110 		return (gettext("not reached."));
7111 
7112 	case IMPORT_PREVIOUS:
7113 		return (gettext("previous snapshot taken."));
7114 
7115 	case IMPORT_PROP_BEGUN:
7116 		return (gettext("some properties imported."));
7117 
7118 	case IMPORT_PROP_DONE:
7119 		return (gettext("properties imported."));
7120 
7121 	case IMPORT_COMPLETE:
7122 		return (gettext("imported."));
7123 
7124 	case IMPORT_REFRESHED:
7125 		return (gettext("refresh requested."));
7126 
7127 	default:
7128 #ifndef NDEBUG
7129 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7130 		    __FILE__, __LINE__, st);
7131 #endif
7132 		abort();
7133 		/* NOTREACHED */
7134 	}
7135 }
7136 
7137 /*
7138  * Returns
7139  *   0 - success
7140  *     - fmri wasn't found (error printed)
7141  *     - entity was deleted (error printed)
7142  *     - backend denied access (error printed)
7143  *   ENOMEM - out of memory (error printed)
7144  *   ECONNABORTED - repository connection broken (error printed)
7145  *   EPERM - permission denied (error printed)
7146  *   -1 - unknown libscf error (error printed)
7147  */
7148 static int
7149 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7150 {
7151 	scf_error_t serr;
7152 	void *ent;
7153 	int issvc;
7154 	int r;
7155 
7156 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7157 	const char *dpt_deleted = gettext("Could not refresh %s "
7158 	    "(dependent \"%s\" of %s) (deleted).\n");
7159 
7160 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7161 	switch (serr) {
7162 	case SCF_ERROR_NONE:
7163 		break;
7164 
7165 	case SCF_ERROR_NO_MEMORY:
7166 		if (name == NULL)
7167 			warn(gettext("Could not refresh %s (out of memory).\n"),
7168 			    fmri);
7169 		else
7170 			warn(gettext("Could not refresh %s "
7171 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7172 			    fmri, name, d_fmri);
7173 		return (ENOMEM);
7174 
7175 	case SCF_ERROR_NOT_FOUND:
7176 		if (name == NULL)
7177 			warn(deleted, fmri);
7178 		else
7179 			warn(dpt_deleted, fmri, name, d_fmri);
7180 		return (0);
7181 
7182 	case SCF_ERROR_INVALID_ARGUMENT:
7183 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7184 	default:
7185 		bad_error("fmri_to_entity", serr);
7186 	}
7187 
7188 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7189 	switch (r) {
7190 	case 0:
7191 		break;
7192 
7193 	case ECONNABORTED:
7194 		if (name != NULL)
7195 			warn(gettext("Could not refresh %s "
7196 			    "(dependent \"%s\" of %s) "
7197 			    "(repository connection broken).\n"), fmri, name,
7198 			    d_fmri);
7199 		return (r);
7200 
7201 	case ECANCELED:
7202 		if (name == NULL)
7203 			warn(deleted, fmri);
7204 		else
7205 			warn(dpt_deleted, fmri, name, d_fmri);
7206 		return (0);
7207 
7208 	case EACCES:
7209 		if (!g_verbose)
7210 			return (0);
7211 		if (name == NULL)
7212 			warn(gettext("Could not refresh %s "
7213 			    "(backend access denied).\n"), fmri);
7214 		else
7215 			warn(gettext("Could not refresh %s "
7216 			    "(dependent \"%s\" of %s) "
7217 			    "(backend access denied).\n"), fmri, name, d_fmri);
7218 		return (0);
7219 
7220 	case EPERM:
7221 		if (name == NULL)
7222 			warn(gettext("Could not refresh %s "
7223 			    "(permission denied).\n"), fmri);
7224 		else
7225 			warn(gettext("Could not refresh %s "
7226 			    "(dependent \"%s\" of %s) "
7227 			    "(permission denied).\n"), fmri, name, d_fmri);
7228 		return (r);
7229 
7230 	case ENOSPC:
7231 		if (name == NULL)
7232 			warn(gettext("Could not refresh %s "
7233 			    "(repository server out of resources).\n"),
7234 			    fmri);
7235 		else
7236 			warn(gettext("Could not refresh %s "
7237 			    "(dependent \"%s\" of %s) "
7238 			    "(repository server out of resources).\n"),
7239 			    fmri, name, d_fmri);
7240 		return (r);
7241 
7242 	case -1:
7243 		scfwarn();
7244 		return (r);
7245 
7246 	default:
7247 		bad_error("refresh_entity", r);
7248 	}
7249 
7250 	if (issvc)
7251 		scf_service_destroy(ent);
7252 	else
7253 		scf_instance_destroy(ent);
7254 
7255 	return (0);
7256 }
7257 
7258 int
7259 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7260 {
7261 	scf_callback_t cbdata;
7262 	int result = 0;
7263 	entity_t *svc, *inst;
7264 	uu_list_t *insts;
7265 	int r;
7266 	pgroup_t *old_dpt;
7267 	void *cookie;
7268 	int annotation_set = 0;
7269 
7270 	const char * const emsg_nomem = gettext("Out of memory.\n");
7271 	const char * const emsg_nores =
7272 	    gettext("svc.configd is out of resources.\n");
7273 
7274 	lscf_prep_hndl();
7275 
7276 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7277 	    max_scf_name_len : max_scf_fmri_len) + 1;
7278 
7279 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7280 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
7281 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7282 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7283 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7284 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7285 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7286 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7287 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7288 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7289 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7290 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7291 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7292 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7293 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7294 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7295 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7296 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7297 	    (imp_str = malloc(imp_str_sz)) == NULL ||
7298 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7299 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7300 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7301 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7302 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7303 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7304 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7305 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7306 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7307 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7308 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7309 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7310 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7311 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7312 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7313 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7314 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7315 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7316 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7317 			warn(emsg_nores);
7318 		else
7319 			warn(emsg_nomem);
7320 		result = -1;
7321 		goto out;
7322 	}
7323 
7324 	r = load_init();
7325 	switch (r) {
7326 	case 0:
7327 		break;
7328 
7329 	case ENOMEM:
7330 		warn(emsg_nomem);
7331 		result = -1;
7332 		goto out;
7333 
7334 	default:
7335 		bad_error("load_init", r);
7336 	}
7337 
7338 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7339 		switch (scf_error()) {
7340 		case SCF_ERROR_CONNECTION_BROKEN:
7341 			warn(gettext("Repository connection broken.\n"));
7342 			repository_teardown();
7343 			result = -1;
7344 			goto out;
7345 
7346 		case SCF_ERROR_NOT_FOUND:
7347 		case SCF_ERROR_INVALID_ARGUMENT:
7348 		case SCF_ERROR_NOT_BOUND:
7349 		case SCF_ERROR_HANDLE_MISMATCH:
7350 		default:
7351 			bad_error("scf_handle_get_scope", scf_error());
7352 		}
7353 	}
7354 
7355 	/* Set up the auditing annotation. */
7356 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7357 		annotation_set = 1;
7358 	} else {
7359 		switch (scf_error()) {
7360 		case SCF_ERROR_CONNECTION_BROKEN:
7361 			warn(gettext("Repository connection broken.\n"));
7362 			repository_teardown();
7363 			result = -1;
7364 			goto out;
7365 
7366 		case SCF_ERROR_INVALID_ARGUMENT:
7367 		case SCF_ERROR_NOT_BOUND:
7368 		case SCF_ERROR_NO_RESOURCES:
7369 		case SCF_ERROR_INTERNAL:
7370 			bad_error("_scf_set_annotation", scf_error());
7371 			/* NOTREACHED */
7372 
7373 		default:
7374 			/*
7375 			 * Do not terminate import because of inability to
7376 			 * generate annotation audit event.
7377 			 */
7378 			warn(gettext("_scf_set_annotation() unexpectedly "
7379 			    "failed with return code of %d\n"), scf_error());
7380 			break;
7381 		}
7382 	}
7383 
7384 	/*
7385 	 * Clear the sc_import_state's of all services & instances so we can
7386 	 * report how far we got if we fail.
7387 	 */
7388 	for (svc = uu_list_first(bndl->sc_bundle_services);
7389 	    svc != NULL;
7390 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7391 		svc->sc_import_state = 0;
7392 
7393 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
7394 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
7395 		    UU_DEFAULT) != 0)
7396 			bad_error("uu_list_walk", uu_error());
7397 	}
7398 
7399 	cbdata.sc_handle = g_hndl;
7400 	cbdata.sc_parent = imp_scope;
7401 	cbdata.sc_flags = flags;
7402 	cbdata.sc_general = NULL;
7403 
7404 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
7405 	    &cbdata, UU_DEFAULT) == 0) {
7406 		/* Success.  Refresh everything. */
7407 
7408 		if (flags & SCI_NOREFRESH || no_refresh) {
7409 			no_refresh = 0;
7410 			result = 0;
7411 			goto out;
7412 		}
7413 
7414 		for (svc = uu_list_first(bndl->sc_bundle_services);
7415 		    svc != NULL;
7416 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7417 			pgroup_t *dpt;
7418 
7419 			insts = svc->sc_u.sc_service.sc_service_instances;
7420 
7421 			for (inst = uu_list_first(insts);
7422 			    inst != NULL;
7423 			    inst = uu_list_next(insts, inst)) {
7424 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
7425 				switch (r) {
7426 				case 0:
7427 					break;
7428 
7429 				case ENOMEM:
7430 				case ECONNABORTED:
7431 				case EPERM:
7432 				case -1:
7433 					goto progress;
7434 
7435 				default:
7436 					bad_error("imp_refresh_fmri", r);
7437 				}
7438 
7439 				inst->sc_import_state = IMPORT_REFRESHED;
7440 
7441 				for (dpt = uu_list_first(inst->sc_dependents);
7442 				    dpt != NULL;
7443 				    dpt = uu_list_next(inst->sc_dependents,
7444 				    dpt))
7445 					if (imp_refresh_fmri(
7446 					    dpt->sc_pgroup_fmri,
7447 					    dpt->sc_pgroup_name,
7448 					    inst->sc_fmri) != 0)
7449 						goto progress;
7450 			}
7451 
7452 			for (dpt = uu_list_first(svc->sc_dependents);
7453 			    dpt != NULL;
7454 			    dpt = uu_list_next(svc->sc_dependents, dpt))
7455 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
7456 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
7457 					goto progress;
7458 		}
7459 
7460 		for (old_dpt = uu_list_first(imp_deleted_dpts);
7461 		    old_dpt != NULL;
7462 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
7463 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
7464 			    old_dpt->sc_pgroup_name,
7465 			    old_dpt->sc_parent->sc_fmri) != 0)
7466 				goto progress;
7467 
7468 		result = 0;
7469 		goto out;
7470 	}
7471 
7472 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7473 		bad_error("uu_list_walk", uu_error());
7474 
7475 printerr:
7476 	/* If the error hasn't been printed yet, do so here. */
7477 	switch (cbdata.sc_err) {
7478 	case ECONNABORTED:
7479 		warn(gettext("Repository connection broken.\n"));
7480 		break;
7481 
7482 	case ENOMEM:
7483 		warn(emsg_nomem);
7484 		break;
7485 
7486 	case ENOSPC:
7487 		warn(emsg_nores);
7488 		break;
7489 
7490 	case EROFS:
7491 		warn(gettext("Repository is read-only.\n"));
7492 		break;
7493 
7494 	case EACCES:
7495 		warn(gettext("Repository backend denied access.\n"));
7496 		break;
7497 
7498 	case EPERM:
7499 	case EINVAL:
7500 	case EEXIST:
7501 	case EBUSY:
7502 	case EBADF:
7503 	case -1:
7504 		break;
7505 
7506 	default:
7507 		bad_error("lscf_service_import", cbdata.sc_err);
7508 	}
7509 
7510 progress:
7511 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
7512 
7513 	for (svc = uu_list_first(bndl->sc_bundle_services);
7514 	    svc != NULL;
7515 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7516 		insts = svc->sc_u.sc_service.sc_service_instances;
7517 
7518 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
7519 		    import_progress(svc->sc_import_state));
7520 
7521 		for (inst = uu_list_first(insts);
7522 		    inst != NULL;
7523 		    inst = uu_list_next(insts, inst))
7524 			warn(gettext("    Instance \"%s\": %s\n"),
7525 			    inst->sc_name,
7526 			    import_progress(inst->sc_import_state));
7527 	}
7528 
7529 	if (cbdata.sc_err == ECONNABORTED)
7530 		repository_teardown();
7531 
7532 
7533 	result = -1;
7534 
7535 out:
7536 	if (annotation_set != 0) {
7537 		/* Turn off annotation.  It is no longer needed. */
7538 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7539 	}
7540 	load_fini();
7541 
7542 	free(ud_ctarg);
7543 	free(ud_oldtarg);
7544 	free(ud_name);
7545 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7546 
7547 	scf_transaction_destroy(ud_tx);
7548 	ud_tx = NULL;
7549 	scf_iter_destroy(ud_iter);
7550 	scf_iter_destroy(ud_iter2);
7551 	ud_iter = ud_iter2 = NULL;
7552 	scf_value_destroy(ud_val);
7553 	ud_val = NULL;
7554 	scf_property_destroy(ud_prop);
7555 	scf_property_destroy(ud_dpt_prop);
7556 	ud_prop = ud_dpt_prop = NULL;
7557 	scf_pg_destroy(ud_pg);
7558 	scf_pg_destroy(ud_cur_depts_pg);
7559 	scf_pg_destroy(ud_run_dpts_pg);
7560 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7561 	scf_snaplevel_destroy(ud_snpl);
7562 	ud_snpl = NULL;
7563 	scf_instance_destroy(ud_inst);
7564 	ud_inst = NULL;
7565 
7566 	free(imp_str);
7567 	free(imp_tsname);
7568 	free(imp_fe1);
7569 	free(imp_fe2);
7570 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7571 
7572 	cookie = NULL;
7573 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7574 	    NULL) {
7575 		free((char *)old_dpt->sc_pgroup_name);
7576 		free((char *)old_dpt->sc_pgroup_fmri);
7577 		internal_pgroup_free(old_dpt);
7578 	}
7579 	uu_list_destroy(imp_deleted_dpts);
7580 
7581 	scf_transaction_destroy(imp_tx);
7582 	imp_tx = NULL;
7583 	scf_iter_destroy(imp_iter);
7584 	scf_iter_destroy(imp_rpg_iter);
7585 	scf_iter_destroy(imp_up_iter);
7586 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7587 	scf_property_destroy(imp_prop);
7588 	imp_prop = NULL;
7589 	scf_pg_destroy(imp_pg);
7590 	scf_pg_destroy(imp_pg2);
7591 	imp_pg = imp_pg2 = NULL;
7592 	scf_snaplevel_destroy(imp_snpl);
7593 	scf_snaplevel_destroy(imp_rsnpl);
7594 	imp_snpl = imp_rsnpl = NULL;
7595 	scf_snapshot_destroy(imp_snap);
7596 	scf_snapshot_destroy(imp_lisnap);
7597 	scf_snapshot_destroy(imp_tlisnap);
7598 	scf_snapshot_destroy(imp_rsnap);
7599 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7600 	scf_instance_destroy(imp_inst);
7601 	scf_instance_destroy(imp_tinst);
7602 	imp_inst = imp_tinst = NULL;
7603 	scf_service_destroy(imp_svc);
7604 	scf_service_destroy(imp_tsvc);
7605 	imp_svc = imp_tsvc = NULL;
7606 	scf_scope_destroy(imp_scope);
7607 	imp_scope = NULL;
7608 
7609 	return (result);
7610 }
7611 
7612 /*
7613  * _lscf_import_err() summarize the error handling returned by
7614  * lscf_import_{instance | service}_pgs
7615  * Return values are:
7616  * IMPORT_NEXT
7617  * IMPORT_OUT
7618  * IMPORT_BAD
7619  */
7620 
7621 #define	IMPORT_BAD	-1
7622 #define	IMPORT_NEXT	0
7623 #define	IMPORT_OUT	1
7624 
7625 static int
7626 _lscf_import_err(int err, const char *fmri)
7627 {
7628 	switch (err) {
7629 	case 0:
7630 		if (g_verbose)
7631 			warn(gettext("%s updated.\n"), fmri);
7632 		return (IMPORT_NEXT);
7633 
7634 	case ECONNABORTED:
7635 		warn(gettext("Could not update %s "
7636 		    "(repository connection broken).\n"), fmri);
7637 		return (IMPORT_OUT);
7638 
7639 	case ENOMEM:
7640 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
7641 		return (IMPORT_OUT);
7642 
7643 	case ENOSPC:
7644 		warn(gettext("Could not update %s "
7645 		    "(repository server out of resources).\n"), fmri);
7646 		return (IMPORT_OUT);
7647 
7648 	case ECANCELED:
7649 		warn(gettext(
7650 		    "Could not update %s (deleted).\n"), fmri);
7651 		return (IMPORT_NEXT);
7652 
7653 	case EPERM:
7654 	case EINVAL:
7655 	case EBUSY:
7656 		return (IMPORT_NEXT);
7657 
7658 	case EROFS:
7659 		warn(gettext("Could not update %s (repository read-only).\n"),
7660 		    fmri);
7661 		return (IMPORT_OUT);
7662 
7663 	case EACCES:
7664 		warn(gettext("Could not update %s "
7665 		    "(backend access denied).\n"), fmri);
7666 		return (IMPORT_NEXT);
7667 
7668 	case EEXIST:
7669 	default:
7670 		return (IMPORT_BAD);
7671 	}
7672 
7673 	/*NOTREACHED*/
7674 }
7675 
7676 /*
7677  * Returns
7678  *   0 - success
7679  *   -1 - lscf_import_instance_pgs() failed.
7680  */
7681 int
7682 lscf_bundle_apply(bundle_t *bndl, const char *file)
7683 {
7684 	entity_t *svc, *inst;
7685 	scf_scope_t *rscope;
7686 	scf_service_t *rsvc;
7687 	scf_instance_t *rinst;
7688 	scf_snapshot_t *rsnap;
7689 	scf_iter_t *iter;
7690 	int annotation_set = 0;
7691 	int r;
7692 
7693 	lscf_prep_hndl();
7694 
7695 	if ((rscope = scf_scope_create(g_hndl)) == NULL ||
7696 	    (rsvc = scf_service_create(g_hndl)) == NULL ||
7697 	    (rinst = scf_instance_create(g_hndl)) == NULL ||
7698 	    (rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7699 	    (iter = scf_iter_create(g_hndl)) == NULL ||
7700 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7701 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7702 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL)
7703 		scfdie();
7704 
7705 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0)
7706 		scfdie();
7707 
7708 	/*
7709 	 * Set the strings to be used for the security audit annotation
7710 	 * event.
7711 	 */
7712 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
7713 		annotation_set = 1;
7714 	} else {
7715 		switch (scf_error()) {
7716 		case SCF_ERROR_CONNECTION_BROKEN:
7717 			warn(gettext("Repository connection broken.\n"));
7718 			goto out;
7719 
7720 		case SCF_ERROR_INVALID_ARGUMENT:
7721 		case SCF_ERROR_NOT_BOUND:
7722 		case SCF_ERROR_NO_RESOURCES:
7723 		case SCF_ERROR_INTERNAL:
7724 			bad_error("_scf_set_annotation", scf_error());
7725 			/* NOTREACHED */
7726 
7727 		default:
7728 			/*
7729 			 * Do not abort apply operation because of
7730 			 * inability to create annotation audit event.
7731 			 */
7732 			warn(gettext("_scf_set_annotation() unexpectedly "
7733 			    "failed with return code of %d\n"), scf_error());
7734 			break;
7735 		}
7736 	}
7737 
7738 	for (svc = uu_list_first(bndl->sc_bundle_services);
7739 	    svc != NULL;
7740 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7741 		int refresh = 0;
7742 
7743 		if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) {
7744 			switch (scf_error()) {
7745 			case SCF_ERROR_NOT_FOUND:
7746 				if (g_verbose)
7747 					warn(gettext("Ignoring nonexistent "
7748 					    "service %s.\n"), svc->sc_name);
7749 				continue;
7750 
7751 			default:
7752 				scfdie();
7753 			}
7754 		}
7755 
7756 		/*
7757 		 * if we have pgs in the profile, we need to refresh ALL
7758 		 * instances of the service
7759 		 */
7760 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
7761 			refresh = 1;
7762 			r = lscf_import_service_pgs(rsvc, svc->sc_fmri, svc,
7763 			    SCI_FORCE | SCI_KEEP);
7764 			switch (_lscf_import_err(r, svc->sc_fmri)) {
7765 			case IMPORT_NEXT:
7766 				break;
7767 
7768 			case IMPORT_OUT:
7769 				goto out;
7770 
7771 			case IMPORT_BAD:
7772 			default:
7773 				bad_error("lscf_import_service_pgs", r);
7774 			}
7775 		}
7776 
7777 		for (inst = uu_list_first(
7778 		    svc->sc_u.sc_service.sc_service_instances);
7779 		    inst != NULL;
7780 		    inst = uu_list_next(
7781 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
7782 			if (scf_service_get_instance(rsvc, inst->sc_name,
7783 			    rinst) != 0) {
7784 				switch (scf_error()) {
7785 				case SCF_ERROR_NOT_FOUND:
7786 					if (g_verbose)
7787 						warn(gettext("Ignoring "
7788 						    "nonexistant instance "
7789 						    "%s:%s.\n"),
7790 						    inst->sc_parent->sc_name,
7791 						    inst->sc_name);
7792 					continue;
7793 
7794 				default:
7795 					scfdie();
7796 				}
7797 			}
7798 
7799 			/*
7800 			 * If the instance does not have a general/enabled
7801 			 * property and no last-import snapshot then the
7802 			 * instance is not a fully installed instance and
7803 			 * should not have a profile applied to it.
7804 			 *
7805 			 * This could happen if a service/instance declares
7806 			 * a dependent on behalf of another service/instance.
7807 			 */
7808 			if (scf_instance_get_snapshot(rinst, snap_lastimport,
7809 			    rsnap) != 0) {
7810 				if (scf_instance_get_pg(rinst, SCF_PG_GENERAL,
7811 				    imp_pg) != 0 || scf_pg_get_property(imp_pg,
7812 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
7813 					if (g_verbose)
7814 						warn(gettext("Ignoreing "
7815 						    "partial instance "
7816 						    "%s:%s.\n"),
7817 						    inst->sc_parent->sc_name,
7818 						    inst->sc_name);
7819 					continue;
7820 				}
7821 			}
7822 
7823 			r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst,
7824 			    SCI_FORCE | SCI_KEEP);
7825 			switch (_lscf_import_err(r, inst->sc_fmri)) {
7826 			case IMPORT_NEXT:
7827 				break;
7828 
7829 			case IMPORT_OUT:
7830 				goto out;
7831 
7832 			case IMPORT_BAD:
7833 			default:
7834 				bad_error("lscf_import_instance_pgs", r);
7835 			}
7836 
7837 			/* refresh only if there is no pgs in the service */
7838 			if (refresh == 0)
7839 				(void) refresh_entity(0, rinst, inst->sc_fmri,
7840 				    NULL, NULL, NULL);
7841 		}
7842 
7843 		if (refresh == 1) {
7844 			char *name_buf = safe_malloc(max_scf_name_len + 1);
7845 
7846 			(void) refresh_entity(1, rsvc, svc->sc_name, rinst,
7847 			    iter, name_buf);
7848 			free(name_buf);
7849 		}
7850 	}
7851 
7852 out:
7853 	if (annotation_set) {
7854 		/* Remove security audit annotation strings. */
7855 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7856 	}
7857 
7858 	scf_transaction_destroy(imp_tx);
7859 	imp_tx = NULL;
7860 	scf_pg_destroy(imp_pg);
7861 	imp_pg = NULL;
7862 	scf_property_destroy(imp_prop);
7863 	imp_prop = NULL;
7864 
7865 	scf_snapshot_destroy(rsnap);
7866 	scf_iter_destroy(iter);
7867 	scf_instance_destroy(rinst);
7868 	scf_service_destroy(rsvc);
7869 	scf_scope_destroy(rscope);
7870 	return (0);
7871 }
7872 
7873 
7874 /*
7875  * Export.  These functions create and output an XML tree of a service
7876  * description from the repository.  This is largely the inverse of
7877  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
7878  *
7879  * - We must include any properties which are not represented specifically by
7880  *   a service manifest, e.g., properties created by an admin post-import.  To
7881  *   do so we'll iterate through all properties and deal with each
7882  *   apropriately.
7883  *
7884  * - Children of services and instances must must be in the order set by the
7885  *   DTD, but we iterate over the properties in undefined order.  The elements
7886  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
7887  *   number of classes of them, however, we'll keep the classes separate and
7888  *   assemble them in order.
7889  */
7890 
7891 /*
7892  * Convenience function to handle xmlSetProp errors (and type casting).
7893  */
7894 static void
7895 safe_setprop(xmlNodePtr n, const char *name, const char *val)
7896 {
7897 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
7898 		uu_die(gettext("Could not set XML property.\n"));
7899 }
7900 
7901 /*
7902  * Convenience function to set an XML attribute to the single value of an
7903  * astring property.  If the value happens to be the default, don't set the
7904  * attribute.  "dval" should be the default value supplied by the DTD, or
7905  * NULL for no default.
7906  */
7907 static int
7908 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
7909     const char *name, const char *dval)
7910 {
7911 	scf_value_t *val;
7912 	ssize_t len;
7913 	char *str;
7914 
7915 	val = scf_value_create(g_hndl);
7916 	if (val == NULL)
7917 		scfdie();
7918 
7919 	if (prop_get_val(prop, val) != 0) {
7920 		scf_value_destroy(val);
7921 		return (-1);
7922 	}
7923 
7924 	len = scf_value_get_as_string(val, NULL, 0);
7925 	if (len < 0)
7926 		scfdie();
7927 
7928 	str = safe_malloc(len + 1);
7929 
7930 	if (scf_value_get_as_string(val, str, len + 1) < 0)
7931 		scfdie();
7932 
7933 	scf_value_destroy(val);
7934 
7935 	if (dval == NULL || strcmp(str, dval) != 0)
7936 		safe_setprop(n, name, str);
7937 
7938 	free(str);
7939 
7940 	return (0);
7941 }
7942 
7943 /*
7944  * As above, but the attribute is always set.
7945  */
7946 static int
7947 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
7948 {
7949 	return (set_attr_from_prop_default(prop, n, name, NULL));
7950 }
7951 
7952 /*
7953  * Dump the given document onto f, with "'s replaced by ''s.
7954  */
7955 static int
7956 write_service_bundle(xmlDocPtr doc, FILE *f)
7957 {
7958 	xmlChar *mem;
7959 	int sz, i;
7960 
7961 	mem = NULL;
7962 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
7963 
7964 	if (mem == NULL) {
7965 		semerr(gettext("Could not dump XML tree.\n"));
7966 		return (-1);
7967 	}
7968 
7969 	/*
7970 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
7971 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
7972 	 * &apos; code?!
7973 	 */
7974 	for (i = 0; i < sz; ++i) {
7975 		char c = (char)mem[i];
7976 
7977 		if (c == '"')
7978 			(void) fputc('\'', f);
7979 		else if (c == '\'')
7980 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
7981 		else
7982 			(void) fputc(c, f);
7983 	}
7984 
7985 	return (0);
7986 }
7987 
7988 /*
7989  * Create the DOM elements in elts necessary to (generically) represent prop
7990  * (i.e., a property or propval element).  If the name of the property is
7991  * known, it should be passed as name_arg.  Otherwise, pass NULL.
7992  */
7993 static void
7994 export_property(scf_property_t *prop, const char *name_arg,
7995     struct pg_elts *elts, int flags)
7996 {
7997 	const char *type;
7998 	scf_error_t err = 0;
7999 	xmlNodePtr pnode, lnode;
8000 	char *lnname;
8001 	int ret;
8002 
8003 	/* name */
8004 	if (name_arg != NULL) {
8005 		(void) strcpy(exp_str, name_arg);
8006 	} else {
8007 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8008 			scfdie();
8009 	}
8010 
8011 	/* type */
8012 	type = prop_to_typestr(prop);
8013 	if (type == NULL)
8014 		uu_die(gettext("Can't export property %s: unknown type.\n"),
8015 		    exp_str);
8016 
8017 	/* If we're exporting values, and there's just one, export it here. */
8018 	if (!(flags & SCE_ALL_VALUES))
8019 		goto empty;
8020 
8021 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8022 		xmlNodePtr n;
8023 
8024 		/* Single value, so use propval */
8025 		n = xmlNewNode(NULL, (xmlChar *)"propval");
8026 		if (n == NULL)
8027 			uu_die(emsg_create_xml);
8028 
8029 		safe_setprop(n, name_attr, exp_str);
8030 		safe_setprop(n, type_attr, type);
8031 
8032 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8033 			scfdie();
8034 		safe_setprop(n, value_attr, exp_str);
8035 
8036 		if (elts->propvals == NULL)
8037 			elts->propvals = n;
8038 		else
8039 			(void) xmlAddSibling(elts->propvals, n);
8040 
8041 		return;
8042 	}
8043 
8044 	err = scf_error();
8045 
8046 	if (err == SCF_ERROR_PERMISSION_DENIED) {
8047 		semerr(emsg_permission_denied);
8048 		return;
8049 	}
8050 
8051 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8052 	    err != SCF_ERROR_NOT_FOUND &&
8053 	    err != SCF_ERROR_PERMISSION_DENIED)
8054 		scfdie();
8055 
8056 empty:
8057 	/* Multiple (or no) values, so use property */
8058 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
8059 	if (pnode == NULL)
8060 		uu_die(emsg_create_xml);
8061 
8062 	safe_setprop(pnode, name_attr, exp_str);
8063 	safe_setprop(pnode, type_attr, type);
8064 
8065 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8066 		lnname = uu_msprintf("%s_list", type);
8067 		if (lnname == NULL)
8068 			uu_die(gettext("Could not create string"));
8069 
8070 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8071 		if (lnode == NULL)
8072 			uu_die(emsg_create_xml);
8073 
8074 		uu_free(lnname);
8075 
8076 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8077 			scfdie();
8078 
8079 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8080 		    1) {
8081 			xmlNodePtr vn;
8082 
8083 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8084 			    NULL);
8085 			if (vn == NULL)
8086 				uu_die(emsg_create_xml);
8087 
8088 			if (scf_value_get_as_string(exp_val, exp_str,
8089 			    exp_str_sz) < 0)
8090 				scfdie();
8091 			safe_setprop(vn, value_attr, exp_str);
8092 		}
8093 		if (ret != 0)
8094 			scfdie();
8095 	}
8096 
8097 	if (elts->properties == NULL)
8098 		elts->properties = pnode;
8099 	else
8100 		(void) xmlAddSibling(elts->properties, pnode);
8101 }
8102 
8103 /*
8104  * Add a property_group element for this property group to elts.
8105  */
8106 static void
8107 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8108 {
8109 	xmlNodePtr n;
8110 	struct pg_elts elts;
8111 	int ret;
8112 	boolean_t read_protected;
8113 
8114 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
8115 
8116 	/* name */
8117 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8118 		scfdie();
8119 	safe_setprop(n, name_attr, exp_str);
8120 
8121 	/* type */
8122 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8123 		scfdie();
8124 	safe_setprop(n, type_attr, exp_str);
8125 
8126 	/* properties */
8127 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8128 		scfdie();
8129 
8130 	(void) memset(&elts, 0, sizeof (elts));
8131 
8132 	/*
8133 	 * If this property group is not read protected, we always want to
8134 	 * output all the values.  Otherwise, we only output the values if the
8135 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8136 	 */
8137 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8138 		scfdie();
8139 
8140 	if (!read_protected)
8141 		flags |= SCE_ALL_VALUES;
8142 
8143 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8144 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8145 			scfdie();
8146 
8147 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8148 			xmlNodePtr m;
8149 
8150 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8151 			if (m == NULL)
8152 				uu_die(emsg_create_xml);
8153 
8154 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8155 				elts.stability = m;
8156 				continue;
8157 			}
8158 
8159 			xmlFreeNode(m);
8160 		}
8161 
8162 		export_property(exp_prop, NULL, &elts, flags);
8163 	}
8164 	if (ret == -1)
8165 		scfdie();
8166 
8167 	(void) xmlAddChild(n, elts.stability);
8168 	(void) xmlAddChildList(n, elts.propvals);
8169 	(void) xmlAddChildList(n, elts.properties);
8170 
8171 	if (eelts->property_groups == NULL)
8172 		eelts->property_groups = n;
8173 	else
8174 		(void) xmlAddSibling(eelts->property_groups, n);
8175 }
8176 
8177 /*
8178  * Create an XML node representing the dependency described by the given
8179  * property group and put it in eelts.  Unless the dependency is not valid, in
8180  * which case create a generic property_group element which represents it and
8181  * put it in eelts.
8182  */
8183 static void
8184 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8185 {
8186 	xmlNodePtr n;
8187 	int err = 0, ret;
8188 	struct pg_elts elts;
8189 
8190 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
8191 	if (n == NULL)
8192 		uu_die(emsg_create_xml);
8193 
8194 	/*
8195 	 * If the external flag is present, skip this dependency because it
8196 	 * should have been created by another manifest.
8197 	 */
8198 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
8199 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8200 		    prop_get_val(exp_prop, exp_val) == 0) {
8201 			uint8_t b;
8202 
8203 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
8204 				scfdie();
8205 
8206 			if (b)
8207 				return;
8208 		}
8209 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
8210 		scfdie();
8211 
8212 	/* Get the required attributes. */
8213 
8214 	/* name */
8215 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8216 		scfdie();
8217 	safe_setprop(n, name_attr, exp_str);
8218 
8219 	/* grouping */
8220 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8221 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8222 		err = 1;
8223 
8224 	/* restart_on */
8225 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8226 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8227 		err = 1;
8228 
8229 	/* type */
8230 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8231 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8232 		err = 1;
8233 
8234 	/*
8235 	 * entities: Not required, but if we create no children, it will be
8236 	 * created as empty on import, so fail if it's missing.
8237 	 */
8238 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8239 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
8240 		scf_iter_t *eiter;
8241 		int ret2;
8242 
8243 		eiter = scf_iter_create(g_hndl);
8244 		if (eiter == NULL)
8245 			scfdie();
8246 
8247 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
8248 			scfdie();
8249 
8250 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
8251 			xmlNodePtr ch;
8252 
8253 			if (scf_value_get_astring(exp_val, exp_str,
8254 			    exp_str_sz) < 0)
8255 				scfdie();
8256 
8257 			/*
8258 			 * service_fmri's must be first, so we can add them
8259 			 * here.
8260 			 */
8261 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
8262 			    NULL);
8263 			if (ch == NULL)
8264 				uu_die(emsg_create_xml);
8265 
8266 			safe_setprop(ch, value_attr, exp_str);
8267 		}
8268 		if (ret2 == -1)
8269 			scfdie();
8270 
8271 		scf_iter_destroy(eiter);
8272 	} else
8273 		err = 1;
8274 
8275 	if (err) {
8276 		xmlFreeNode(n);
8277 
8278 		export_pg(pg, eelts, 0);
8279 
8280 		return;
8281 	}
8282 
8283 	/* Iterate through the properties & handle each. */
8284 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8285 		scfdie();
8286 
8287 	(void) memset(&elts, 0, sizeof (elts));
8288 
8289 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8290 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8291 			scfdie();
8292 
8293 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8294 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8295 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8296 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8297 			continue;
8298 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8299 			xmlNodePtr m;
8300 
8301 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8302 			if (m == NULL)
8303 				uu_die(emsg_create_xml);
8304 
8305 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8306 				elts.stability = m;
8307 				continue;
8308 			}
8309 
8310 			xmlFreeNode(m);
8311 		}
8312 
8313 		export_property(exp_prop, exp_str, &elts, 0);
8314 	}
8315 	if (ret == -1)
8316 		scfdie();
8317 
8318 	(void) xmlAddChild(n, elts.stability);
8319 	(void) xmlAddChildList(n, elts.propvals);
8320 	(void) xmlAddChildList(n, elts.properties);
8321 
8322 	if (eelts->dependencies == NULL)
8323 		eelts->dependencies = n;
8324 	else
8325 		(void) xmlAddSibling(eelts->dependencies, n);
8326 }
8327 
8328 static xmlNodePtr
8329 export_method_environment(scf_propertygroup_t *pg)
8330 {
8331 	xmlNodePtr env;
8332 	int ret;
8333 	int children = 0;
8334 
8335 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
8336 		return (NULL);
8337 
8338 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
8339 	if (env == NULL)
8340 		uu_die(emsg_create_xml);
8341 
8342 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
8343 		scfdie();
8344 
8345 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
8346 		scfdie();
8347 
8348 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
8349 		xmlNodePtr ev;
8350 		char *cp;
8351 
8352 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8353 			scfdie();
8354 
8355 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
8356 			warn(gettext("Invalid environment variable \"%s\".\n"),
8357 			    exp_str);
8358 			continue;
8359 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
8360 			warn(gettext("Invalid environment variable \"%s\"; "
8361 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
8362 			continue;
8363 		}
8364 
8365 		*cp = '\0';
8366 		cp++;
8367 
8368 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
8369 		if (ev == NULL)
8370 			uu_die(emsg_create_xml);
8371 
8372 		safe_setprop(ev, name_attr, exp_str);
8373 		safe_setprop(ev, value_attr, cp);
8374 		children++;
8375 	}
8376 
8377 	if (ret != 0)
8378 		scfdie();
8379 
8380 	if (children == 0) {
8381 		xmlFreeNode(env);
8382 		return (NULL);
8383 	}
8384 
8385 	return (env);
8386 }
8387 
8388 /*
8389  * As above, but for a method property group.
8390  */
8391 static void
8392 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
8393 {
8394 	xmlNodePtr n, env;
8395 	char *str;
8396 	int err = 0, nonenv, ret;
8397 	uint8_t use_profile;
8398 	struct pg_elts elts;
8399 	xmlNodePtr ctxt = NULL;
8400 
8401 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
8402 
8403 	/* Get the required attributes. */
8404 
8405 	/* name */
8406 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8407 		scfdie();
8408 	safe_setprop(n, name_attr, exp_str);
8409 
8410 	/* type */
8411 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8412 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8413 		err = 1;
8414 
8415 	/* exec */
8416 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
8417 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
8418 		err = 1;
8419 
8420 	/* timeout */
8421 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
8422 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
8423 	    prop_get_val(exp_prop, exp_val) == 0) {
8424 		uint64_t c;
8425 
8426 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
8427 			scfdie();
8428 
8429 		str = uu_msprintf("%llu", c);
8430 		if (str == NULL)
8431 			uu_die(gettext("Could not create string"));
8432 
8433 		safe_setprop(n, "timeout_seconds", str);
8434 		free(str);
8435 	} else
8436 		err = 1;
8437 
8438 	if (err) {
8439 		xmlFreeNode(n);
8440 
8441 		export_pg(pg, eelts, 0);
8442 
8443 		return;
8444 	}
8445 
8446 
8447 	/*
8448 	 * If we're going to have a method_context child, we need to know
8449 	 * before we iterate through the properties.  Since method_context's
8450 	 * are optional, we don't want to complain about any properties
8451 	 * missing if none of them are there.  Thus we can't use the
8452 	 * convenience functions.
8453 	 */
8454 	nonenv =
8455 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
8456 	    SCF_SUCCESS ||
8457 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
8458 	    SCF_SUCCESS ||
8459 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
8460 	    SCF_SUCCESS ||
8461 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
8462 	    SCF_SUCCESS;
8463 
8464 	if (nonenv) {
8465 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8466 		if (ctxt == NULL)
8467 			uu_die(emsg_create_xml);
8468 
8469 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
8470 		    0 &&
8471 		    set_attr_from_prop_default(exp_prop, ctxt,
8472 		    "working_directory", ":default") != 0)
8473 			err = 1;
8474 
8475 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
8476 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
8477 		    ":default") != 0)
8478 			err = 1;
8479 
8480 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
8481 		    0 &&
8482 		    set_attr_from_prop_default(exp_prop, ctxt,
8483 		    "resource_pool", ":default") != 0)
8484 			err = 1;
8485 		/*
8486 		 * We only want to complain about profile or credential
8487 		 * properties if we will use them.  To determine that we must
8488 		 * examine USE_PROFILE.
8489 		 */
8490 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8491 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8492 		    prop_get_val(exp_prop, exp_val) == 0) {
8493 			if (scf_value_get_boolean(exp_val, &use_profile) !=
8494 			    SCF_SUCCESS) {
8495 				scfdie();
8496 			}
8497 
8498 			if (use_profile) {
8499 				xmlNodePtr prof;
8500 
8501 				prof = xmlNewChild(ctxt, NULL,
8502 				    (xmlChar *)"method_profile", NULL);
8503 				if (prof == NULL)
8504 					uu_die(emsg_create_xml);
8505 
8506 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
8507 				    exp_prop) != 0 ||
8508 				    set_attr_from_prop(exp_prop, prof,
8509 				    name_attr) != 0)
8510 					err = 1;
8511 			} else {
8512 				xmlNodePtr cred;
8513 
8514 				cred = xmlNewChild(ctxt, NULL,
8515 				    (xmlChar *)"method_credential", NULL);
8516 				if (cred == NULL)
8517 					uu_die(emsg_create_xml);
8518 
8519 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
8520 				    exp_prop) != 0 ||
8521 				    set_attr_from_prop(exp_prop, cred,
8522 				    "user") != 0) {
8523 					err = 1;
8524 				}
8525 
8526 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
8527 				    exp_prop) == 0 &&
8528 				    set_attr_from_prop_default(exp_prop, cred,
8529 				    "group", ":default") != 0)
8530 					err = 1;
8531 
8532 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
8533 				    exp_prop) == 0 &&
8534 				    set_attr_from_prop_default(exp_prop, cred,
8535 				    "supp_groups", ":default") != 0)
8536 					err = 1;
8537 
8538 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
8539 				    exp_prop) == 0 &&
8540 				    set_attr_from_prop_default(exp_prop, cred,
8541 				    "privileges", ":default") != 0)
8542 					err = 1;
8543 
8544 				if (pg_get_prop(pg,
8545 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
8546 				    exp_prop) == 0 &&
8547 				    set_attr_from_prop_default(exp_prop, cred,
8548 				    "limit_privileges", ":default") != 0)
8549 					err = 1;
8550 			}
8551 		}
8552 	}
8553 
8554 	if ((env = export_method_environment(pg)) != NULL) {
8555 		if (ctxt == NULL) {
8556 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8557 			if (ctxt == NULL)
8558 				uu_die(emsg_create_xml);
8559 		}
8560 		(void) xmlAddChild(ctxt, env);
8561 	}
8562 
8563 	if (env != NULL || (nonenv && err == 0))
8564 		(void) xmlAddChild(n, ctxt);
8565 	else
8566 		xmlFreeNode(ctxt);
8567 
8568 	nonenv = (err == 0);
8569 
8570 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8571 		scfdie();
8572 
8573 	(void) memset(&elts, 0, sizeof (elts));
8574 
8575 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8576 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8577 			scfdie();
8578 
8579 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8580 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
8581 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
8582 			continue;
8583 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8584 			xmlNodePtr m;
8585 
8586 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8587 			if (m == NULL)
8588 				uu_die(emsg_create_xml);
8589 
8590 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8591 				elts.stability = m;
8592 				continue;
8593 			}
8594 
8595 			xmlFreeNode(m);
8596 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
8597 		    0 ||
8598 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
8599 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
8600 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8601 			if (nonenv)
8602 				continue;
8603 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
8604 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
8605 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
8606 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
8607 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
8608 			if (nonenv && !use_profile)
8609 				continue;
8610 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8611 			if (nonenv && use_profile)
8612 				continue;
8613 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
8614 			if (env != NULL)
8615 				continue;
8616 		}
8617 
8618 		export_property(exp_prop, exp_str, &elts, 0);
8619 	}
8620 	if (ret == -1)
8621 		scfdie();
8622 
8623 	(void) xmlAddChild(n, elts.stability);
8624 	(void) xmlAddChildList(n, elts.propvals);
8625 	(void) xmlAddChildList(n, elts.properties);
8626 
8627 	if (eelts->exec_methods == NULL)
8628 		eelts->exec_methods = n;
8629 	else
8630 		(void) xmlAddSibling(eelts->exec_methods, n);
8631 }
8632 
8633 static void
8634 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
8635     struct entity_elts *eelts)
8636 {
8637 	xmlNodePtr pgnode;
8638 
8639 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
8640 	if (pgnode == NULL)
8641 		uu_die(emsg_create_xml);
8642 
8643 	safe_setprop(pgnode, name_attr, name);
8644 	safe_setprop(pgnode, type_attr, type);
8645 
8646 	(void) xmlAddChildList(pgnode, elts->propvals);
8647 	(void) xmlAddChildList(pgnode, elts->properties);
8648 
8649 	if (eelts->property_groups == NULL)
8650 		eelts->property_groups = pgnode;
8651 	else
8652 		(void) xmlAddSibling(eelts->property_groups, pgnode);
8653 }
8654 
8655 /*
8656  * Process the general property group for a service.  This is the one with the
8657  * goodies.
8658  */
8659 static void
8660 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
8661 {
8662 	struct pg_elts elts;
8663 	int ret;
8664 
8665 	/*
8666 	 * In case there are properties which don't correspond to child
8667 	 * entities of the service entity, we'll set up a pg_elts structure to
8668 	 * put them in.
8669 	 */
8670 	(void) memset(&elts, 0, sizeof (elts));
8671 
8672 	/* Walk the properties, looking for special ones. */
8673 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8674 		scfdie();
8675 
8676 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8677 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8678 			scfdie();
8679 
8680 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
8681 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8682 			    prop_get_val(exp_prop, exp_val) == 0) {
8683 				uint8_t b;
8684 
8685 				if (scf_value_get_boolean(exp_val, &b) !=
8686 				    SCF_SUCCESS)
8687 					scfdie();
8688 
8689 				if (b) {
8690 					selts->single_instance =
8691 					    xmlNewNode(NULL,
8692 					    (xmlChar *)"single_instance");
8693 					if (selts->single_instance == NULL)
8694 						uu_die(emsg_create_xml);
8695 				}
8696 
8697 				continue;
8698 			}
8699 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8700 			xmlNodePtr rnode, sfnode;
8701 
8702 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8703 			if (rnode == NULL)
8704 				uu_die(emsg_create_xml);
8705 
8706 			sfnode = xmlNewChild(rnode, NULL,
8707 			    (xmlChar *)"service_fmri", NULL);
8708 			if (sfnode == NULL)
8709 				uu_die(emsg_create_xml);
8710 
8711 			if (set_attr_from_prop(exp_prop, sfnode,
8712 			    value_attr) == 0) {
8713 				selts->restarter = rnode;
8714 				continue;
8715 			}
8716 
8717 			xmlFreeNode(rnode);
8718 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
8719 		    0) {
8720 			xmlNodePtr s;
8721 
8722 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8723 			if (s == NULL)
8724 				uu_die(emsg_create_xml);
8725 
8726 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8727 				selts->stability = s;
8728 				continue;
8729 			}
8730 
8731 			xmlFreeNode(s);
8732 		}
8733 
8734 		export_property(exp_prop, exp_str, &elts, 0);
8735 	}
8736 	if (ret == -1)
8737 		scfdie();
8738 
8739 	if (elts.propvals != NULL || elts.properties != NULL)
8740 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
8741 		    selts);
8742 }
8743 
8744 static void
8745 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
8746 {
8747 	xmlNodePtr n, prof, cred, env;
8748 	uint8_t use_profile;
8749 	int ret, err = 0;
8750 
8751 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
8752 
8753 	env = export_method_environment(pg);
8754 
8755 	/* Need to know whether we'll use a profile or not. */
8756 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8757 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8758 	    prop_get_val(exp_prop, exp_val) == 0) {
8759 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
8760 			scfdie();
8761 
8762 		if (use_profile)
8763 			prof =
8764 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
8765 			    NULL);
8766 		else
8767 			cred =
8768 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
8769 			    NULL);
8770 	}
8771 
8772 	if (env != NULL)
8773 		(void) xmlAddChild(n, env);
8774 
8775 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8776 		scfdie();
8777 
8778 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8779 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8780 			scfdie();
8781 
8782 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
8783 			if (set_attr_from_prop(exp_prop, n,
8784 			    "working_directory") != 0)
8785 				err = 1;
8786 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
8787 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
8788 				err = 1;
8789 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
8790 			if (set_attr_from_prop(exp_prop, n,
8791 			    "resource_pool") != 0)
8792 				err = 1;
8793 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8794 			/* EMPTY */
8795 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
8796 			if (use_profile ||
8797 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
8798 				err = 1;
8799 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
8800 			if (use_profile ||
8801 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
8802 				err = 1;
8803 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
8804 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8805 			    "supp_groups") != 0)
8806 				err = 1;
8807 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
8808 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8809 			    "privileges") != 0)
8810 				err = 1;
8811 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
8812 		    0) {
8813 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8814 			    "limit_privileges") != 0)
8815 				err = 1;
8816 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8817 			if (!use_profile || set_attr_from_prop(exp_prop,
8818 			    prof, name_attr) != 0)
8819 				err = 1;
8820 		} else {
8821 			/* Can't have generic properties in method_context's */
8822 			err = 1;
8823 		}
8824 	}
8825 	if (ret == -1)
8826 		scfdie();
8827 
8828 	if (err && env == NULL) {
8829 		xmlFreeNode(n);
8830 		export_pg(pg, elts, 0);
8831 		return;
8832 	}
8833 
8834 	elts->method_context = n;
8835 }
8836 
8837 /*
8838  * Given a dependency property group in the tfmri entity (target fmri), return
8839  * a dependent element which represents it.
8840  */
8841 static xmlNodePtr
8842 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
8843 {
8844 	uint8_t b;
8845 	xmlNodePtr n, sf;
8846 	int err = 0, ret;
8847 	struct pg_elts pgelts;
8848 
8849 	/*
8850 	 * If external isn't set to true then exporting the service will
8851 	 * export this as a normal dependency, so we should stop to avoid
8852 	 * duplication.
8853 	 */
8854 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
8855 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
8856 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
8857 		if (g_verbose) {
8858 			warn(gettext("Dependent \"%s\" cannot be exported "
8859 			    "properly because the \"%s\" property of the "
8860 			    "\"%s\" dependency of %s is not set to true.\n"),
8861 			    name, scf_property_external, name, tfmri);
8862 		}
8863 
8864 		return (NULL);
8865 	}
8866 
8867 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
8868 	if (n == NULL)
8869 		uu_die(emsg_create_xml);
8870 
8871 	safe_setprop(n, name_attr, name);
8872 
8873 	/* Get the required attributes */
8874 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8875 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8876 		err = 1;
8877 
8878 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8879 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8880 		err = 1;
8881 
8882 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8883 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
8884 	    prop_get_val(exp_prop, exp_val) == 0) {
8885 		/* EMPTY */
8886 	} else
8887 		err = 1;
8888 
8889 	if (err) {
8890 		xmlFreeNode(n);
8891 		return (NULL);
8892 	}
8893 
8894 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
8895 	if (sf == NULL)
8896 		uu_die(emsg_create_xml);
8897 
8898 	safe_setprop(sf, value_attr, tfmri);
8899 
8900 	/*
8901 	 * Now add elements for the other properties.
8902 	 */
8903 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8904 		scfdie();
8905 
8906 	(void) memset(&pgelts, 0, sizeof (pgelts));
8907 
8908 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8909 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8910 			scfdie();
8911 
8912 		if (strcmp(exp_str, scf_property_external) == 0 ||
8913 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8914 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8915 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8916 			continue;
8917 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
8918 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
8919 			    prop_get_val(exp_prop, exp_val) == 0) {
8920 				char type[sizeof ("service") + 1];
8921 
8922 				if (scf_value_get_astring(exp_val, type,
8923 				    sizeof (type)) < 0)
8924 					scfdie();
8925 
8926 				if (strcmp(type, "service") == 0)
8927 					continue;
8928 			}
8929 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8930 			xmlNodePtr s;
8931 
8932 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8933 			if (s == NULL)
8934 				uu_die(emsg_create_xml);
8935 
8936 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8937 				pgelts.stability = s;
8938 				continue;
8939 			}
8940 
8941 			xmlFreeNode(s);
8942 		}
8943 
8944 		export_property(exp_prop, exp_str, &pgelts, 0);
8945 	}
8946 	if (ret == -1)
8947 		scfdie();
8948 
8949 	(void) xmlAddChild(n, pgelts.stability);
8950 	(void) xmlAddChildList(n, pgelts.propvals);
8951 	(void) xmlAddChildList(n, pgelts.properties);
8952 
8953 	return (n);
8954 }
8955 
8956 static void
8957 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
8958 {
8959 	scf_propertygroup_t *opg;
8960 	scf_iter_t *iter;
8961 	char *type, *fmri;
8962 	int ret;
8963 	struct pg_elts pgelts;
8964 	xmlNodePtr n;
8965 	scf_error_t serr;
8966 
8967 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
8968 	    (iter = scf_iter_create(g_hndl)) == NULL)
8969 		scfdie();
8970 
8971 	/* Can't use exp_prop_iter due to export_dependent(). */
8972 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
8973 		scfdie();
8974 
8975 	type = safe_malloc(max_scf_pg_type_len + 1);
8976 
8977 	/* Get an extra byte so we can tell if values are too long. */
8978 	fmri = safe_malloc(max_scf_fmri_len + 2);
8979 
8980 	(void) memset(&pgelts, 0, sizeof (pgelts));
8981 
8982 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
8983 		void *entity;
8984 		int isservice;
8985 		scf_type_t ty;
8986 
8987 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
8988 			scfdie();
8989 
8990 		if ((ty != SCF_TYPE_ASTRING &&
8991 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
8992 		    prop_get_val(exp_prop, exp_val) != 0) {
8993 			export_property(exp_prop, NULL, &pgelts, 0);
8994 			continue;
8995 		}
8996 
8997 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8998 			scfdie();
8999 
9000 		if (scf_value_get_astring(exp_val, fmri,
9001 		    max_scf_fmri_len + 2) < 0)
9002 			scfdie();
9003 
9004 		/* Look for a dependency group in the target fmri. */
9005 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9006 		switch (serr) {
9007 		case SCF_ERROR_NONE:
9008 			break;
9009 
9010 		case SCF_ERROR_NO_MEMORY:
9011 			uu_die(gettext("Out of memory.\n"));
9012 			/* NOTREACHED */
9013 
9014 		case SCF_ERROR_INVALID_ARGUMENT:
9015 			if (g_verbose) {
9016 				if (scf_property_to_fmri(exp_prop, fmri,
9017 				    max_scf_fmri_len + 2) < 0)
9018 					scfdie();
9019 
9020 				warn(gettext("The value of %s is not a valid "
9021 				    "FMRI.\n"), fmri);
9022 			}
9023 
9024 			export_property(exp_prop, exp_str, &pgelts, 0);
9025 			continue;
9026 
9027 		case SCF_ERROR_CONSTRAINT_VIOLATED:
9028 			if (g_verbose) {
9029 				if (scf_property_to_fmri(exp_prop, fmri,
9030 				    max_scf_fmri_len + 2) < 0)
9031 					scfdie();
9032 
9033 				warn(gettext("The value of %s does not specify "
9034 				    "a service or an instance.\n"), fmri);
9035 			}
9036 
9037 			export_property(exp_prop, exp_str, &pgelts, 0);
9038 			continue;
9039 
9040 		case SCF_ERROR_NOT_FOUND:
9041 			if (g_verbose) {
9042 				if (scf_property_to_fmri(exp_prop, fmri,
9043 				    max_scf_fmri_len + 2) < 0)
9044 					scfdie();
9045 
9046 				warn(gettext("The entity specified by %s does "
9047 				    "not exist.\n"), fmri);
9048 			}
9049 
9050 			export_property(exp_prop, exp_str, &pgelts, 0);
9051 			continue;
9052 
9053 		default:
9054 #ifndef NDEBUG
9055 			(void) fprintf(stderr, "%s:%d: %s() failed with "
9056 			    "unexpected error %d.\n", __FILE__, __LINE__,
9057 			    "fmri_to_entity", serr);
9058 #endif
9059 			abort();
9060 		}
9061 
9062 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9063 			if (scf_error() != SCF_ERROR_NOT_FOUND)
9064 				scfdie();
9065 
9066 			warn(gettext("Entity %s is missing dependency property "
9067 			    "group %s.\n"), fmri, exp_str);
9068 
9069 			export_property(exp_prop, NULL, &pgelts, 0);
9070 			continue;
9071 		}
9072 
9073 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9074 			scfdie();
9075 
9076 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9077 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9078 				scfdie();
9079 
9080 			warn(gettext("Property group %s is not of "
9081 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9082 
9083 			export_property(exp_prop, NULL, &pgelts, 0);
9084 			continue;
9085 		}
9086 
9087 		n = export_dependent(opg, exp_str, fmri);
9088 		if (n == NULL)
9089 			export_property(exp_prop, exp_str, &pgelts, 0);
9090 		else {
9091 			if (eelts->dependents == NULL)
9092 				eelts->dependents = n;
9093 			else
9094 				(void) xmlAddSibling(eelts->dependents,
9095 				    n);
9096 		}
9097 	}
9098 	if (ret == -1)
9099 		scfdie();
9100 
9101 	free(fmri);
9102 	free(type);
9103 
9104 	scf_iter_destroy(iter);
9105 	scf_pg_destroy(opg);
9106 
9107 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9108 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9109 		    eelts);
9110 }
9111 
9112 static void
9113 make_node(xmlNodePtr *nodep, const char *name)
9114 {
9115 	if (*nodep == NULL) {
9116 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
9117 		if (*nodep == NULL)
9118 			uu_die(emsg_create_xml);
9119 	}
9120 }
9121 
9122 static xmlNodePtr
9123 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9124 {
9125 	int ret;
9126 	xmlNodePtr parent = NULL;
9127 	xmlNodePtr loctext = NULL;
9128 
9129 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9130 		scfdie();
9131 
9132 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9133 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9134 		    prop_get_val(exp_prop, exp_val) != 0)
9135 			continue;
9136 
9137 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9138 			scfdie();
9139 
9140 		make_node(&parent, parname);
9141 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9142 		    (xmlChar *)exp_str);
9143 		if (loctext == NULL)
9144 			uu_die(emsg_create_xml);
9145 
9146 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9147 			scfdie();
9148 
9149 		safe_setprop(loctext, "xml:lang", exp_str);
9150 	}
9151 
9152 	if (ret == -1)
9153 		scfdie();
9154 
9155 	return (parent);
9156 }
9157 
9158 static xmlNodePtr
9159 export_tm_manpage(scf_propertygroup_t *pg)
9160 {
9161 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9162 	if (manpage == NULL)
9163 		uu_die(emsg_create_xml);
9164 
9165 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9166 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9167 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9168 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9169 		xmlFreeNode(manpage);
9170 		return (NULL);
9171 	}
9172 
9173 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9174 		(void) set_attr_from_prop_default(exp_prop,
9175 		    manpage, "manpath", ":default");
9176 
9177 	return (manpage);
9178 }
9179 
9180 static xmlNodePtr
9181 export_tm_doc_link(scf_propertygroup_t *pg)
9182 {
9183 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9184 	if (doc_link == NULL)
9185 		uu_die(emsg_create_xml);
9186 
9187 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9188 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9189 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9190 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9191 		xmlFreeNode(doc_link);
9192 		return (NULL);
9193 	}
9194 	return (doc_link);
9195 }
9196 
9197 /*
9198  * Process template information for a service or instances.
9199  */
9200 static void
9201 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
9202     struct template_elts *telts)
9203 {
9204 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
9205 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
9206 	xmlNodePtr child = NULL;
9207 
9208 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
9209 		scfdie();
9210 
9211 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
9212 		telts->common_name = export_tm_loctext(pg, "common_name");
9213 		if (telts->common_name == NULL)
9214 			export_pg(pg, elts, 0);
9215 		return;
9216 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
9217 		telts->description = export_tm_loctext(pg, "description");
9218 		if (telts->description == NULL)
9219 			export_pg(pg, elts, 0);
9220 		return;
9221 	}
9222 
9223 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
9224 		child = export_tm_manpage(pg);
9225 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
9226 		child = export_tm_doc_link(pg);
9227 	}
9228 
9229 	if (child != NULL) {
9230 		make_node(&telts->documentation, "documentation");
9231 		(void) xmlAddChild(telts->documentation, child);
9232 	} else {
9233 		export_pg(pg, elts, 0);
9234 	}
9235 }
9236 
9237 /*
9238  * Process the general property group for an instance.
9239  */
9240 static void
9241 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
9242     struct entity_elts *elts)
9243 {
9244 	uint8_t enabled;
9245 	struct pg_elts pgelts;
9246 	int ret;
9247 
9248 	/* enabled */
9249 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
9250 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9251 	    prop_get_val(exp_prop, exp_val) == 0) {
9252 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
9253 			scfdie();
9254 	} else {
9255 		enabled = 0;
9256 	}
9257 
9258 	safe_setprop(inode, enabled_attr, enabled ? true : false);
9259 
9260 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9261 		scfdie();
9262 
9263 	(void) memset(&pgelts, 0, sizeof (pgelts));
9264 
9265 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9266 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9267 			scfdie();
9268 
9269 		if (strcmp(exp_str, scf_property_enabled) == 0) {
9270 			continue;
9271 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9272 			xmlNodePtr rnode, sfnode;
9273 
9274 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9275 			if (rnode == NULL)
9276 				uu_die(emsg_create_xml);
9277 
9278 			sfnode = xmlNewChild(rnode, NULL,
9279 			    (xmlChar *)"service_fmri", NULL);
9280 			if (sfnode == NULL)
9281 				uu_die(emsg_create_xml);
9282 
9283 			if (set_attr_from_prop(exp_prop, sfnode,
9284 			    value_attr) == 0) {
9285 				elts->restarter = rnode;
9286 				continue;
9287 			}
9288 
9289 			xmlFreeNode(rnode);
9290 		}
9291 
9292 		export_property(exp_prop, exp_str, &pgelts, 0);
9293 	}
9294 	if (ret == -1)
9295 		scfdie();
9296 
9297 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9298 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
9299 		    elts);
9300 }
9301 
9302 /*
9303  * Put an instance element for the given instance into selts.
9304  */
9305 static void
9306 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
9307 {
9308 	xmlNodePtr n;
9309 	boolean_t isdefault;
9310 	struct entity_elts elts;
9311 	struct template_elts template_elts;
9312 	int ret;
9313 
9314 	n = xmlNewNode(NULL, (xmlChar *)"instance");
9315 	if (n == NULL)
9316 		uu_die(emsg_create_xml);
9317 
9318 	/* name */
9319 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
9320 		scfdie();
9321 	safe_setprop(n, name_attr, exp_str);
9322 	isdefault = strcmp(exp_str, "default") == 0;
9323 
9324 	/* check existance of general pg (since general/enabled is required) */
9325 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
9326 		if (scf_error() != SCF_ERROR_NOT_FOUND)
9327 			scfdie();
9328 
9329 		if (g_verbose) {
9330 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
9331 				scfdie();
9332 
9333 			warn(gettext("Instance %s has no general property "
9334 			    "group; it will be marked disabled.\n"), exp_str);
9335 		}
9336 
9337 		safe_setprop(n, enabled_attr, false);
9338 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
9339 	    strcmp(exp_str, scf_group_framework) != 0) {
9340 		if (g_verbose) {
9341 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
9342 				scfdie();
9343 
9344 			warn(gettext("Property group %s is not of type "
9345 			    "framework; the instance will be marked "
9346 			    "disabled.\n"), exp_str);
9347 		}
9348 
9349 		safe_setprop(n, enabled_attr, false);
9350 	}
9351 
9352 	/* property groups */
9353 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
9354 		scfdie();
9355 
9356 	(void) memset(&elts, 0, sizeof (elts));
9357 	(void) memset(&template_elts, 0, sizeof (template_elts));
9358 
9359 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9360 		uint32_t pgflags;
9361 
9362 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9363 			scfdie();
9364 
9365 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9366 			continue;
9367 
9368 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9369 			scfdie();
9370 
9371 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9372 			export_dependency(exp_pg, &elts);
9373 			continue;
9374 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9375 			export_method(exp_pg, &elts);
9376 			continue;
9377 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9378 			if (scf_pg_get_name(exp_pg, exp_str,
9379 			    max_scf_name_len + 1) < 0)
9380 				scfdie();
9381 
9382 			if (strcmp(exp_str, scf_pg_general) == 0) {
9383 				export_inst_general(exp_pg, n, &elts);
9384 				continue;
9385 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9386 			    0) {
9387 				export_method_context(exp_pg, &elts);
9388 				continue;
9389 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9390 				export_dependents(exp_pg, &elts);
9391 				continue;
9392 			}
9393 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9394 			export_template(exp_pg, &elts, &template_elts);
9395 			continue;
9396 		}
9397 
9398 		/* Ordinary pg. */
9399 		export_pg(exp_pg, &elts, flags);
9400 	}
9401 	if (ret == -1)
9402 		scfdie();
9403 
9404 	if (template_elts.common_name != NULL) {
9405 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9406 		(void) xmlAddChild(elts.template, template_elts.common_name);
9407 		(void) xmlAddChild(elts.template, template_elts.description);
9408 		(void) xmlAddChild(elts.template, template_elts.documentation);
9409 	} else {
9410 		xmlFreeNode(template_elts.description);
9411 		xmlFreeNode(template_elts.documentation);
9412 	}
9413 
9414 	if (isdefault && elts.restarter == NULL &&
9415 	    elts.dependencies == NULL && elts.method_context == NULL &&
9416 	    elts.exec_methods == NULL && elts.property_groups == NULL &&
9417 	    elts.template == NULL) {
9418 		xmlChar *eval;
9419 
9420 		/* This is a default instance */
9421 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
9422 
9423 		xmlFreeNode(n);
9424 
9425 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
9426 		if (n == NULL)
9427 			uu_die(emsg_create_xml);
9428 
9429 		safe_setprop(n, enabled_attr, (char *)eval);
9430 		xmlFree(eval);
9431 
9432 		selts->create_default_instance = n;
9433 	} else {
9434 		/* Assemble the children in order. */
9435 		(void) xmlAddChild(n, elts.restarter);
9436 		(void) xmlAddChildList(n, elts.dependencies);
9437 		(void) xmlAddChildList(n, elts.dependents);
9438 		(void) xmlAddChild(n, elts.method_context);
9439 		(void) xmlAddChildList(n, elts.exec_methods);
9440 		(void) xmlAddChildList(n, elts.property_groups);
9441 		(void) xmlAddChild(n, elts.template);
9442 
9443 		if (selts->instances == NULL)
9444 			selts->instances = n;
9445 		else
9446 			(void) xmlAddSibling(selts->instances, n);
9447 	}
9448 }
9449 
9450 /*
9451  * Return a service element for the given service.
9452  */
9453 static xmlNodePtr
9454 export_service(scf_service_t *svc, int flags)
9455 {
9456 	xmlNodePtr snode;
9457 	struct entity_elts elts;
9458 	struct template_elts template_elts;
9459 	int ret;
9460 
9461 	snode = xmlNewNode(NULL, (xmlChar *)"service");
9462 	if (snode == NULL)
9463 		uu_die(emsg_create_xml);
9464 
9465 	/* Get & set name attribute */
9466 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
9467 		scfdie();
9468 	safe_setprop(snode, name_attr, exp_str);
9469 
9470 	safe_setprop(snode, type_attr, "service");
9471 	safe_setprop(snode, "version", "0");
9472 
9473 	/* Acquire child elements. */
9474 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
9475 		scfdie();
9476 
9477 	(void) memset(&elts, 0, sizeof (elts));
9478 	(void) memset(&template_elts, 0, sizeof (template_elts));
9479 
9480 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9481 		uint32_t pgflags;
9482 
9483 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9484 			scfdie();
9485 
9486 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9487 			continue;
9488 
9489 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9490 			scfdie();
9491 
9492 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9493 			export_dependency(exp_pg, &elts);
9494 			continue;
9495 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9496 			export_method(exp_pg, &elts);
9497 			continue;
9498 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9499 			if (scf_pg_get_name(exp_pg, exp_str,
9500 			    max_scf_name_len + 1) < 0)
9501 				scfdie();
9502 
9503 			if (strcmp(exp_str, scf_pg_general) == 0) {
9504 				export_svc_general(exp_pg, &elts);
9505 				continue;
9506 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9507 			    0) {
9508 				export_method_context(exp_pg, &elts);
9509 				continue;
9510 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9511 				export_dependents(exp_pg, &elts);
9512 				continue;
9513 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
9514 				continue;
9515 			}
9516 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9517 			export_template(exp_pg, &elts, &template_elts);
9518 			continue;
9519 		}
9520 
9521 		export_pg(exp_pg, &elts, flags);
9522 	}
9523 	if (ret == -1)
9524 		scfdie();
9525 
9526 	if (template_elts.common_name != NULL) {
9527 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9528 		(void) xmlAddChild(elts.template, template_elts.common_name);
9529 		(void) xmlAddChild(elts.template, template_elts.description);
9530 		(void) xmlAddChild(elts.template, template_elts.documentation);
9531 	} else {
9532 		xmlFreeNode(template_elts.description);
9533 		xmlFreeNode(template_elts.documentation);
9534 	}
9535 
9536 	/* Iterate instances */
9537 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
9538 		scfdie();
9539 
9540 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
9541 		export_instance(exp_inst, &elts, flags);
9542 	if (ret == -1)
9543 		scfdie();
9544 
9545 	/* Now add all of the accumulated elements in order. */
9546 	(void) xmlAddChild(snode, elts.create_default_instance);
9547 	(void) xmlAddChild(snode, elts.single_instance);
9548 	(void) xmlAddChild(snode, elts.restarter);
9549 	(void) xmlAddChildList(snode, elts.dependencies);
9550 	(void) xmlAddChildList(snode, elts.dependents);
9551 	(void) xmlAddChild(snode, elts.method_context);
9552 	(void) xmlAddChildList(snode, elts.exec_methods);
9553 	(void) xmlAddChildList(snode, elts.property_groups);
9554 	(void) xmlAddChildList(snode, elts.instances);
9555 	(void) xmlAddChild(snode, elts.stability);
9556 	(void) xmlAddChild(snode, elts.template);
9557 
9558 	return (snode);
9559 }
9560 
9561 static int
9562 export_callback(void *data, scf_walkinfo_t *wip)
9563 {
9564 	FILE *f;
9565 	xmlDocPtr doc;
9566 	xmlNodePtr sb;
9567 	int result;
9568 	struct export_args *argsp = (struct export_args *)data;
9569 
9570 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
9571 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9572 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9573 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9574 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9575 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9576 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9577 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9578 		scfdie();
9579 
9580 	exp_str_sz = max_scf_len + 1;
9581 	exp_str = safe_malloc(exp_str_sz);
9582 
9583 	if (argsp->filename != NULL) {
9584 		errno = 0;
9585 		f = fopen(argsp->filename, "wb");
9586 		if (f == NULL) {
9587 			if (errno == 0)
9588 				uu_die(gettext("Could not open \"%s\": no free "
9589 				    "stdio streams.\n"), argsp->filename);
9590 			else
9591 				uu_die(gettext("Could not open \"%s\""),
9592 				    argsp->filename);
9593 		}
9594 	} else
9595 		f = stdout;
9596 
9597 	doc = xmlNewDoc((xmlChar *)"1.0");
9598 	if (doc == NULL)
9599 		uu_die(gettext("Could not create XML document.\n"));
9600 
9601 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9602 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9603 		uu_die(emsg_create_xml);
9604 
9605 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9606 	if (sb == NULL)
9607 		uu_die(emsg_create_xml);
9608 	safe_setprop(sb, type_attr, "manifest");
9609 	safe_setprop(sb, name_attr, "export");
9610 	(void) xmlAddSibling(doc->children, sb);
9611 
9612 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
9613 
9614 	result = write_service_bundle(doc, f);
9615 
9616 	free(exp_str);
9617 	scf_iter_destroy(exp_val_iter);
9618 	scf_iter_destroy(exp_prop_iter);
9619 	scf_iter_destroy(exp_pg_iter);
9620 	scf_iter_destroy(exp_inst_iter);
9621 	scf_value_destroy(exp_val);
9622 	scf_property_destroy(exp_prop);
9623 	scf_pg_destroy(exp_pg);
9624 	scf_instance_destroy(exp_inst);
9625 
9626 	xmlFreeDoc(doc);
9627 
9628 	if (f != stdout)
9629 		(void) fclose(f);
9630 
9631 	return (result);
9632 }
9633 
9634 /*
9635  * Get the service named by fmri, build an XML tree which represents it, and
9636  * dump it into filename (or stdout if filename is NULL).
9637  */
9638 int
9639 lscf_service_export(char *fmri, const char *filename, int flags)
9640 {
9641 	struct export_args args;
9642 	int ret, err;
9643 
9644 	lscf_prep_hndl();
9645 
9646 	bzero(&args, sizeof (args));
9647 	args.filename = filename;
9648 	args.flags = flags;
9649 
9650 	err = 0;
9651 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
9652 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
9653 	    &args, &err, semerr)) != 0) {
9654 		if (ret != -1)
9655 			semerr(gettext("Failed to walk instances: %s\n"),
9656 			    scf_strerror(ret));
9657 		return (-1);
9658 	}
9659 
9660 	/*
9661 	 * Error message has already been printed.
9662 	 */
9663 	if (err != 0)
9664 		return (-1);
9665 
9666 	return (0);
9667 }
9668 
9669 
9670 /*
9671  * Archive
9672  */
9673 
9674 static xmlNodePtr
9675 make_archive(int flags)
9676 {
9677 	xmlNodePtr sb;
9678 	scf_scope_t *scope;
9679 	scf_service_t *svc;
9680 	scf_iter_t *iter;
9681 	int r;
9682 
9683 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9684 	    (svc = scf_service_create(g_hndl)) == NULL ||
9685 	    (iter = scf_iter_create(g_hndl)) == NULL ||
9686 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
9687 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9688 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9689 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9690 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9691 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9692 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9693 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9694 		scfdie();
9695 
9696 	exp_str_sz = max_scf_len + 1;
9697 	exp_str = safe_malloc(exp_str_sz);
9698 
9699 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9700 	if (sb == NULL)
9701 		uu_die(emsg_create_xml);
9702 	safe_setprop(sb, type_attr, "archive");
9703 	safe_setprop(sb, name_attr, "none");
9704 
9705 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
9706 		scfdie();
9707 	if (scf_iter_scope_services(iter, scope) != 0)
9708 		scfdie();
9709 
9710 	for (;;) {
9711 		r = scf_iter_next_service(iter, svc);
9712 		if (r == 0)
9713 			break;
9714 		if (r != 1)
9715 			scfdie();
9716 
9717 		if (scf_service_get_name(svc, exp_str,
9718 		    max_scf_name_len + 1) < 0)
9719 			scfdie();
9720 
9721 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
9722 			continue;
9723 
9724 		(void) xmlAddChild(sb, export_service(svc, flags));
9725 	}
9726 
9727 	free(exp_str);
9728 
9729 	scf_iter_destroy(exp_val_iter);
9730 	scf_iter_destroy(exp_prop_iter);
9731 	scf_iter_destroy(exp_pg_iter);
9732 	scf_iter_destroy(exp_inst_iter);
9733 	scf_value_destroy(exp_val);
9734 	scf_property_destroy(exp_prop);
9735 	scf_pg_destroy(exp_pg);
9736 	scf_instance_destroy(exp_inst);
9737 	scf_iter_destroy(iter);
9738 	scf_service_destroy(svc);
9739 	scf_scope_destroy(scope);
9740 
9741 	return (sb);
9742 }
9743 
9744 int
9745 lscf_archive(const char *filename, int flags)
9746 {
9747 	FILE *f;
9748 	xmlDocPtr doc;
9749 	int result;
9750 
9751 	lscf_prep_hndl();
9752 
9753 	if (filename != NULL) {
9754 		errno = 0;
9755 		f = fopen(filename, "wb");
9756 		if (f == NULL) {
9757 			if (errno == 0)
9758 				uu_die(gettext("Could not open \"%s\": no free "
9759 				    "stdio streams.\n"), filename);
9760 			else
9761 				uu_die(gettext("Could not open \"%s\""),
9762 				    filename);
9763 		}
9764 	} else
9765 		f = stdout;
9766 
9767 	doc = xmlNewDoc((xmlChar *)"1.0");
9768 	if (doc == NULL)
9769 		uu_die(gettext("Could not create XML document.\n"));
9770 
9771 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9772 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9773 		uu_die(emsg_create_xml);
9774 
9775 	(void) xmlAddSibling(doc->children, make_archive(flags));
9776 
9777 	result = write_service_bundle(doc, f);
9778 
9779 	xmlFreeDoc(doc);
9780 
9781 	if (f != stdout)
9782 		(void) fclose(f);
9783 
9784 	return (result);
9785 }
9786 
9787 
9788 /*
9789  * "Extract" a profile.
9790  */
9791 int
9792 lscf_profile_extract(const char *filename)
9793 {
9794 	FILE *f;
9795 	xmlDocPtr doc;
9796 	xmlNodePtr sb, snode, inode;
9797 	scf_scope_t *scope;
9798 	scf_service_t *svc;
9799 	scf_instance_t *inst;
9800 	scf_propertygroup_t *pg;
9801 	scf_property_t *prop;
9802 	scf_value_t *val;
9803 	scf_iter_t *siter, *iiter;
9804 	int r, s;
9805 	char *namebuf;
9806 	uint8_t b;
9807 	int result;
9808 
9809 	lscf_prep_hndl();
9810 
9811 	if (filename != NULL) {
9812 		errno = 0;
9813 		f = fopen(filename, "wb");
9814 		if (f == NULL) {
9815 			if (errno == 0)
9816 				uu_die(gettext("Could not open \"%s\": no "
9817 				    "free stdio streams.\n"), filename);
9818 			else
9819 				uu_die(gettext("Could not open \"%s\""),
9820 				    filename);
9821 		}
9822 	} else
9823 		f = stdout;
9824 
9825 	doc = xmlNewDoc((xmlChar *)"1.0");
9826 	if (doc == NULL)
9827 		uu_die(gettext("Could not create XML document.\n"));
9828 
9829 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9830 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9831 		uu_die(emsg_create_xml);
9832 
9833 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9834 	if (sb == NULL)
9835 		uu_die(emsg_create_xml);
9836 	safe_setprop(sb, type_attr, "profile");
9837 	safe_setprop(sb, name_attr, "extract");
9838 	(void) xmlAddSibling(doc->children, sb);
9839 
9840 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9841 	    (svc = scf_service_create(g_hndl)) == NULL ||
9842 	    (inst = scf_instance_create(g_hndl)) == NULL ||
9843 	    (pg = scf_pg_create(g_hndl)) == NULL ||
9844 	    (prop = scf_property_create(g_hndl)) == NULL ||
9845 	    (val = scf_value_create(g_hndl)) == NULL ||
9846 	    (siter = scf_iter_create(g_hndl)) == NULL ||
9847 	    (iiter = scf_iter_create(g_hndl)) == NULL)
9848 		scfdie();
9849 
9850 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
9851 		scfdie();
9852 
9853 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
9854 		scfdie();
9855 
9856 	namebuf = safe_malloc(max_scf_name_len + 1);
9857 
9858 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
9859 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
9860 			scfdie();
9861 
9862 		snode = xmlNewNode(NULL, (xmlChar *)"service");
9863 		if (snode == NULL)
9864 			uu_die(emsg_create_xml);
9865 
9866 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
9867 		    0)
9868 			scfdie();
9869 
9870 		safe_setprop(snode, name_attr, namebuf);
9871 
9872 		safe_setprop(snode, type_attr, "service");
9873 		safe_setprop(snode, "version", "0");
9874 
9875 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
9876 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
9877 			    SCF_SUCCESS) {
9878 				if (scf_error() != SCF_ERROR_NOT_FOUND)
9879 					scfdie();
9880 
9881 				if (g_verbose) {
9882 					ssize_t len;
9883 					char *fmri;
9884 
9885 					len =
9886 					    scf_instance_to_fmri(inst, NULL, 0);
9887 					if (len < 0)
9888 						scfdie();
9889 
9890 					fmri = safe_malloc(len + 1);
9891 
9892 					if (scf_instance_to_fmri(inst, fmri,
9893 					    len + 1) < 0)
9894 						scfdie();
9895 
9896 					warn("Instance %s has no \"%s\" "
9897 					    "property group.\n", fmri,
9898 					    scf_pg_general);
9899 
9900 					free(fmri);
9901 				}
9902 
9903 				continue;
9904 			}
9905 
9906 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
9907 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
9908 			    prop_get_val(prop, val) != 0)
9909 				continue;
9910 
9911 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
9912 			    NULL);
9913 			if (inode == NULL)
9914 				uu_die(emsg_create_xml);
9915 
9916 			if (scf_instance_get_name(inst, namebuf,
9917 			    max_scf_name_len + 1) < 0)
9918 				scfdie();
9919 
9920 			safe_setprop(inode, name_attr, namebuf);
9921 
9922 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
9923 				scfdie();
9924 
9925 			safe_setprop(inode, enabled_attr, b ? true : false);
9926 		}
9927 		if (s < 0)
9928 			scfdie();
9929 
9930 		if (snode->children != NULL)
9931 			(void) xmlAddChild(sb, snode);
9932 		else
9933 			xmlFreeNode(snode);
9934 	}
9935 	if (r < 0)
9936 		scfdie();
9937 
9938 	free(namebuf);
9939 
9940 	result = write_service_bundle(doc, f);
9941 
9942 	xmlFreeDoc(doc);
9943 
9944 	if (f != stdout)
9945 		(void) fclose(f);
9946 
9947 	return (result);
9948 }
9949 
9950 
9951 /*
9952  * Entity manipulation commands
9953  */
9954 
9955 /*
9956  * Entity selection.  If no entity is selected, then the current scope is in
9957  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
9958  * only cur_inst is NULL, and when an instance is selected, none are NULL.
9959  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
9960  * cur_inst will be non-NULL.
9961  */
9962 
9963 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
9964 static int
9965 select_inst(const char *name)
9966 {
9967 	scf_instance_t *inst;
9968 	scf_error_t err;
9969 
9970 	assert(cur_svc != NULL);
9971 
9972 	inst = scf_instance_create(g_hndl);
9973 	if (inst == NULL)
9974 		scfdie();
9975 
9976 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
9977 		cur_inst = inst;
9978 		return (0);
9979 	}
9980 
9981 	err = scf_error();
9982 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9983 		scfdie();
9984 
9985 	scf_instance_destroy(inst);
9986 	return (1);
9987 }
9988 
9989 /* Returns as above. */
9990 static int
9991 select_svc(const char *name)
9992 {
9993 	scf_service_t *svc;
9994 	scf_error_t err;
9995 
9996 	assert(cur_scope != NULL);
9997 
9998 	svc = scf_service_create(g_hndl);
9999 	if (svc == NULL)
10000 		scfdie();
10001 
10002 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10003 		cur_svc = svc;
10004 		return (0);
10005 	}
10006 
10007 	err = scf_error();
10008 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10009 		scfdie();
10010 
10011 	scf_service_destroy(svc);
10012 	return (1);
10013 }
10014 
10015 /* ARGSUSED */
10016 static int
10017 select_callback(void *unused, scf_walkinfo_t *wip)
10018 {
10019 	scf_instance_t *inst;
10020 	scf_service_t *svc;
10021 	scf_scope_t *scope;
10022 
10023 	if (wip->inst != NULL) {
10024 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10025 		    (svc = scf_service_create(g_hndl)) == NULL ||
10026 		    (inst = scf_instance_create(g_hndl)) == NULL)
10027 			scfdie();
10028 
10029 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10030 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10031 			scfdie();
10032 	} else {
10033 		assert(wip->svc != NULL);
10034 
10035 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
10036 		    (svc = scf_service_create(g_hndl)) == NULL)
10037 			scfdie();
10038 
10039 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
10040 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
10041 			scfdie();
10042 
10043 		inst = NULL;
10044 	}
10045 
10046 	/* Clear out the current selection */
10047 	assert(cur_scope != NULL);
10048 	scf_scope_destroy(cur_scope);
10049 	scf_service_destroy(cur_svc);
10050 	scf_instance_destroy(cur_inst);
10051 
10052 	cur_scope = scope;
10053 	cur_svc = svc;
10054 	cur_inst = inst;
10055 
10056 	return (0);
10057 }
10058 
10059 static int
10060 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
10061 {
10062 	char **fmri = fmri_p;
10063 
10064 	*fmri = strdup(wip->fmri);
10065 	if (*fmri == NULL)
10066 		uu_die(gettext("Out of memory.\n"));
10067 
10068 	return (0);
10069 }
10070 
10071 /*
10072  * validate [fmri]
10073  * Perform the validation of an FMRI instance.
10074  */
10075 void
10076 lscf_validate_fmri(const char *fmri)
10077 {
10078 	int ret = 0;
10079 	size_t inst_sz;
10080 	char *inst_fmri = NULL;
10081 	scf_tmpl_errors_t *errs = NULL;
10082 	char *snapbuf = NULL;
10083 
10084 	lscf_prep_hndl();
10085 
10086 	if (fmri == NULL) {
10087 		inst_sz = max_scf_fmri_len + 1;
10088 		inst_fmri = safe_malloc(inst_sz);
10089 
10090 		if (cur_snap != NULL) {
10091 			snapbuf = safe_malloc(max_scf_name_len + 1);
10092 			if (scf_snapshot_get_name(cur_snap, snapbuf,
10093 			    max_scf_name_len + 1) < 0)
10094 				scfdie();
10095 		}
10096 		if (cur_inst == NULL) {
10097 			semerr(gettext("No instance selected\n"));
10098 			goto cleanup;
10099 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
10100 		    inst_sz) >= inst_sz) {
10101 			/* sanity check. Should never get here */
10102 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
10103 			    __FILE__, __LINE__);
10104 		}
10105 	} else {
10106 		scf_error_t scf_err;
10107 		int err = 0;
10108 
10109 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
10110 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
10111 			uu_warn("Failed to walk instances: %s\n",
10112 			    scf_strerror(scf_err));
10113 			goto cleanup;
10114 		}
10115 		if (err != 0) {
10116 			/* error message displayed by scf_walk_fmri */
10117 			goto cleanup;
10118 		}
10119 	}
10120 
10121 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
10122 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
10123 	if (ret == -1) {
10124 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
10125 			warn(gettext("Template data for %s is invalid. "
10126 			    "Consider reverting to a previous snapshot or "
10127 			    "restoring original configuration.\n"), inst_fmri);
10128 		} else {
10129 			uu_warn("%s: %s\n",
10130 			    gettext("Error validating the instance"),
10131 			    scf_strerror(scf_error()));
10132 		}
10133 	} else if (ret == 1 && errs != NULL) {
10134 		scf_tmpl_error_t *err = NULL;
10135 		char *msg;
10136 		size_t len = 256;	/* initial error buffer size */
10137 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
10138 		    SCF_TMPL_STRERROR_HUMAN : 0;
10139 
10140 		msg = safe_malloc(len);
10141 
10142 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
10143 			int ret;
10144 
10145 			if ((ret = scf_tmpl_strerror(err, msg, len,
10146 			    flag)) >= len) {
10147 				len = ret + 1;
10148 				msg = realloc(msg, len);
10149 				if (msg == NULL)
10150 					uu_die(gettext(
10151 					    "Out of memory.\n"));
10152 				(void) scf_tmpl_strerror(err, msg, len,
10153 				    flag);
10154 			}
10155 			(void) fprintf(stderr, "%s\n", msg);
10156 		}
10157 		if (msg != NULL)
10158 			free(msg);
10159 	}
10160 	if (errs != NULL)
10161 		scf_tmpl_errors_destroy(errs);
10162 
10163 cleanup:
10164 	free(inst_fmri);
10165 	free(snapbuf);
10166 }
10167 
10168 static void
10169 lscf_validate_file(const char *filename)
10170 {
10171 	tmpl_errors_t *errs;
10172 
10173 	bundle_t *b = internal_bundle_new();
10174 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
10175 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
10176 			tmpl_errors_print(stderr, errs, "");
10177 			semerr(gettext("Validation failed.\n"));
10178 		}
10179 		tmpl_errors_destroy(errs);
10180 	}
10181 	(void) internal_bundle_free(b);
10182 }
10183 
10184 /*
10185  * validate [fmri|file]
10186  */
10187 void
10188 lscf_validate(const char *arg)
10189 {
10190 	const char *str;
10191 
10192 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
10193 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
10194 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
10195 		lscf_validate_file(str);
10196 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
10197 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
10198 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
10199 		lscf_validate_fmri(str);
10200 	} else if (access(arg, R_OK | F_OK) == 0) {
10201 		lscf_validate_file(arg);
10202 	} else {
10203 		lscf_validate_fmri(arg);
10204 	}
10205 }
10206 
10207 void
10208 lscf_select(const char *fmri)
10209 {
10210 	int ret, err;
10211 
10212 	lscf_prep_hndl();
10213 
10214 	if (cur_snap != NULL) {
10215 		struct snaplevel *elt;
10216 		char *buf;
10217 
10218 		/* Error unless name is that of the next level. */
10219 		elt = uu_list_next(cur_levels, cur_elt);
10220 		if (elt == NULL) {
10221 			semerr(gettext("No children.\n"));
10222 			return;
10223 		}
10224 
10225 		buf = safe_malloc(max_scf_name_len + 1);
10226 
10227 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10228 		    max_scf_name_len + 1) < 0)
10229 			scfdie();
10230 
10231 		if (strcmp(buf, fmri) != 0) {
10232 			semerr(gettext("No such child.\n"));
10233 			free(buf);
10234 			return;
10235 		}
10236 
10237 		free(buf);
10238 
10239 		cur_elt = elt;
10240 		cur_level = elt->sl;
10241 		return;
10242 	}
10243 
10244 	/*
10245 	 * Special case for 'svc:', which takes the user to the scope level.
10246 	 */
10247 	if (strcmp(fmri, "svc:") == 0) {
10248 		scf_instance_destroy(cur_inst);
10249 		scf_service_destroy(cur_svc);
10250 		cur_inst = NULL;
10251 		cur_svc = NULL;
10252 		return;
10253 	}
10254 
10255 	/*
10256 	 * Special case for ':properties'.  This appears as part of 'list' but
10257 	 * can't be selected.  Give a more helpful error message in this case.
10258 	 */
10259 	if (strcmp(fmri, ":properties") == 0) {
10260 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
10261 		    "to list properties.\n"));
10262 		return;
10263 	}
10264 
10265 	/*
10266 	 * First try the argument as relative to the current selection.
10267 	 */
10268 	if (cur_inst != NULL) {
10269 		/* EMPTY */;
10270 	} else if (cur_svc != NULL) {
10271 		if (select_inst(fmri) != 1)
10272 			return;
10273 	} else {
10274 		if (select_svc(fmri) != 1)
10275 			return;
10276 	}
10277 
10278 	err = 0;
10279 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
10280 	    select_callback, NULL, &err, semerr)) != 0) {
10281 		semerr(gettext("Failed to walk instances: %s\n"),
10282 		    scf_strerror(ret));
10283 	}
10284 }
10285 
10286 void
10287 lscf_unselect(void)
10288 {
10289 	lscf_prep_hndl();
10290 
10291 	if (cur_snap != NULL) {
10292 		struct snaplevel *elt;
10293 
10294 		elt = uu_list_prev(cur_levels, cur_elt);
10295 		if (elt == NULL) {
10296 			semerr(gettext("No parent levels.\n"));
10297 		} else {
10298 			cur_elt = elt;
10299 			cur_level = elt->sl;
10300 		}
10301 	} else if (cur_inst != NULL) {
10302 		scf_instance_destroy(cur_inst);
10303 		cur_inst = NULL;
10304 	} else if (cur_svc != NULL) {
10305 		scf_service_destroy(cur_svc);
10306 		cur_svc = NULL;
10307 	} else {
10308 		semerr(gettext("Cannot unselect at scope level.\n"));
10309 	}
10310 }
10311 
10312 /*
10313  * Return the FMRI of the current selection, for the prompt.
10314  */
10315 void
10316 lscf_get_selection_str(char *buf, size_t bufsz)
10317 {
10318 	char *cp;
10319 	ssize_t fmrilen, szret;
10320 	boolean_t deleted = B_FALSE;
10321 
10322 	if (g_hndl == NULL) {
10323 		(void) strlcpy(buf, "svc:", bufsz);
10324 		return;
10325 	}
10326 
10327 	if (cur_level != NULL) {
10328 		assert(cur_snap != NULL);
10329 
10330 		/* [ snapshot ] FMRI [: instance ] */
10331 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
10332 		    + 2 + max_scf_name_len + 1 + 1);
10333 
10334 		buf[0] = '[';
10335 
10336 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
10337 		    max_scf_name_len + 1);
10338 		if (szret < 0) {
10339 			if (scf_error() != SCF_ERROR_DELETED)
10340 				scfdie();
10341 
10342 			goto snap_deleted;
10343 		}
10344 
10345 		(void) strcat(buf, "]svc:/");
10346 
10347 		cp = strchr(buf, '\0');
10348 
10349 		szret = scf_snaplevel_get_service_name(cur_level, cp,
10350 		    max_scf_name_len + 1);
10351 		if (szret < 0) {
10352 			if (scf_error() != SCF_ERROR_DELETED)
10353 				scfdie();
10354 
10355 			goto snap_deleted;
10356 		}
10357 
10358 		cp = strchr(cp, '\0');
10359 
10360 		if (snaplevel_is_instance(cur_level)) {
10361 			*cp++ = ':';
10362 
10363 			if (scf_snaplevel_get_instance_name(cur_level, cp,
10364 			    max_scf_name_len + 1) < 0) {
10365 				if (scf_error() != SCF_ERROR_DELETED)
10366 					scfdie();
10367 
10368 				goto snap_deleted;
10369 			}
10370 		} else {
10371 			*cp++ = '[';
10372 			*cp++ = ':';
10373 
10374 			if (scf_instance_get_name(cur_inst, cp,
10375 			    max_scf_name_len + 1) < 0) {
10376 				if (scf_error() != SCF_ERROR_DELETED)
10377 					scfdie();
10378 
10379 				goto snap_deleted;
10380 			}
10381 
10382 			(void) strcat(buf, "]");
10383 		}
10384 
10385 		return;
10386 
10387 snap_deleted:
10388 		deleted = B_TRUE;
10389 		free(buf);
10390 		unselect_cursnap();
10391 	}
10392 
10393 	assert(cur_snap == NULL);
10394 
10395 	if (cur_inst != NULL) {
10396 		assert(cur_svc != NULL);
10397 		assert(cur_scope != NULL);
10398 
10399 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
10400 		if (fmrilen >= 0) {
10401 			assert(fmrilen < bufsz);
10402 			if (deleted)
10403 				warn(emsg_deleted);
10404 			return;
10405 		}
10406 
10407 		if (scf_error() != SCF_ERROR_DELETED)
10408 			scfdie();
10409 
10410 		deleted = B_TRUE;
10411 
10412 		scf_instance_destroy(cur_inst);
10413 		cur_inst = NULL;
10414 	}
10415 
10416 	if (cur_svc != NULL) {
10417 		assert(cur_scope != NULL);
10418 
10419 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
10420 		if (szret >= 0) {
10421 			assert(szret < bufsz);
10422 			if (deleted)
10423 				warn(emsg_deleted);
10424 			return;
10425 		}
10426 
10427 		if (scf_error() != SCF_ERROR_DELETED)
10428 			scfdie();
10429 
10430 		deleted = B_TRUE;
10431 		scf_service_destroy(cur_svc);
10432 		cur_svc = NULL;
10433 	}
10434 
10435 	assert(cur_scope != NULL);
10436 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
10437 
10438 	if (fmrilen < 0)
10439 		scfdie();
10440 
10441 	assert(fmrilen < bufsz);
10442 	if (deleted)
10443 		warn(emsg_deleted);
10444 }
10445 
10446 /*
10447  * Entity listing.  Entities and colon namespaces (e.g., :properties and
10448  * :statistics) are listed for the current selection.
10449  */
10450 void
10451 lscf_list(const char *pattern)
10452 {
10453 	scf_iter_t *iter;
10454 	char *buf;
10455 	int ret;
10456 
10457 	lscf_prep_hndl();
10458 
10459 	if (cur_level != NULL) {
10460 		struct snaplevel *elt;
10461 
10462 		(void) fputs(COLON_NAMESPACES, stdout);
10463 
10464 		elt = uu_list_next(cur_levels, cur_elt);
10465 		if (elt == NULL)
10466 			return;
10467 
10468 		/*
10469 		 * For now, we know that the next level is an instance.  But
10470 		 * if we ever have multiple scopes, this could be complicated.
10471 		 */
10472 		buf = safe_malloc(max_scf_name_len + 1);
10473 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10474 		    max_scf_name_len + 1) >= 0) {
10475 			(void) puts(buf);
10476 		} else {
10477 			if (scf_error() != SCF_ERROR_DELETED)
10478 				scfdie();
10479 		}
10480 
10481 		free(buf);
10482 
10483 		return;
10484 	}
10485 
10486 	if (cur_inst != NULL) {
10487 		(void) fputs(COLON_NAMESPACES, stdout);
10488 		return;
10489 	}
10490 
10491 	iter = scf_iter_create(g_hndl);
10492 	if (iter == NULL)
10493 		scfdie();
10494 
10495 	buf = safe_malloc(max_scf_name_len + 1);
10496 
10497 	if (cur_svc != NULL) {
10498 		/* List the instances in this service. */
10499 		scf_instance_t *inst;
10500 
10501 		inst = scf_instance_create(g_hndl);
10502 		if (inst == NULL)
10503 			scfdie();
10504 
10505 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
10506 			safe_printf(COLON_NAMESPACES);
10507 
10508 			for (;;) {
10509 				ret = scf_iter_next_instance(iter, inst);
10510 				if (ret == 0)
10511 					break;
10512 				if (ret != 1) {
10513 					if (scf_error() != SCF_ERROR_DELETED)
10514 						scfdie();
10515 
10516 					break;
10517 				}
10518 
10519 				if (scf_instance_get_name(inst, buf,
10520 				    max_scf_name_len + 1) >= 0) {
10521 					if (pattern == NULL ||
10522 					    fnmatch(pattern, buf, 0) == 0)
10523 						(void) puts(buf);
10524 				} else {
10525 					if (scf_error() != SCF_ERROR_DELETED)
10526 						scfdie();
10527 				}
10528 			}
10529 		} else {
10530 			if (scf_error() != SCF_ERROR_DELETED)
10531 				scfdie();
10532 		}
10533 
10534 		scf_instance_destroy(inst);
10535 	} else {
10536 		/* List the services in this scope. */
10537 		scf_service_t *svc;
10538 
10539 		assert(cur_scope != NULL);
10540 
10541 		svc = scf_service_create(g_hndl);
10542 		if (svc == NULL)
10543 			scfdie();
10544 
10545 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
10546 			scfdie();
10547 
10548 		for (;;) {
10549 			ret = scf_iter_next_service(iter, svc);
10550 			if (ret == 0)
10551 				break;
10552 			if (ret != 1)
10553 				scfdie();
10554 
10555 			if (scf_service_get_name(svc, buf,
10556 			    max_scf_name_len + 1) >= 0) {
10557 				if (pattern == NULL ||
10558 				    fnmatch(pattern, buf, 0) == 0)
10559 					safe_printf("%s\n", buf);
10560 			} else {
10561 				if (scf_error() != SCF_ERROR_DELETED)
10562 					scfdie();
10563 			}
10564 		}
10565 
10566 		scf_service_destroy(svc);
10567 	}
10568 
10569 	free(buf);
10570 	scf_iter_destroy(iter);
10571 }
10572 
10573 /*
10574  * Entity addition.  Creates an empty entity in the current selection.
10575  */
10576 void
10577 lscf_add(const char *name)
10578 {
10579 	lscf_prep_hndl();
10580 
10581 	if (cur_snap != NULL) {
10582 		semerr(emsg_cant_modify_snapshots);
10583 	} else if (cur_inst != NULL) {
10584 		semerr(gettext("Cannot add entities to an instance.\n"));
10585 	} else if (cur_svc != NULL) {
10586 
10587 		if (scf_service_add_instance(cur_svc, name, NULL) !=
10588 		    SCF_SUCCESS) {
10589 			switch (scf_error()) {
10590 			case SCF_ERROR_INVALID_ARGUMENT:
10591 				semerr(gettext("Invalid name.\n"));
10592 				break;
10593 
10594 			case SCF_ERROR_EXISTS:
10595 				semerr(gettext("Instance already exists.\n"));
10596 				break;
10597 
10598 			case SCF_ERROR_PERMISSION_DENIED:
10599 				semerr(emsg_permission_denied);
10600 				break;
10601 
10602 			default:
10603 				scfdie();
10604 			}
10605 		}
10606 	} else {
10607 		assert(cur_scope != NULL);
10608 
10609 		if (scf_scope_add_service(cur_scope, name, NULL) !=
10610 		    SCF_SUCCESS) {
10611 			switch (scf_error()) {
10612 			case SCF_ERROR_INVALID_ARGUMENT:
10613 				semerr(gettext("Invalid name.\n"));
10614 				break;
10615 
10616 			case SCF_ERROR_EXISTS:
10617 				semerr(gettext("Service already exists.\n"));
10618 				break;
10619 
10620 			case SCF_ERROR_PERMISSION_DENIED:
10621 				semerr(emsg_permission_denied);
10622 				break;
10623 
10624 			case SCF_ERROR_BACKEND_READONLY:
10625 				semerr(emsg_read_only);
10626 				break;
10627 
10628 			default:
10629 				scfdie();
10630 			}
10631 		}
10632 	}
10633 }
10634 
10635 /* return 1 if the entity has no persistent pgs, else return 0 */
10636 static int
10637 entity_has_no_pgs(void *ent, int isservice)
10638 {
10639 	scf_iter_t *iter = NULL;
10640 	scf_propertygroup_t *pg = NULL;
10641 	uint32_t flags;
10642 	int err;
10643 	int ret = 1;
10644 
10645 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10646 	    (pg = scf_pg_create(g_hndl)) == NULL)
10647 		scfdie();
10648 
10649 	if (isservice) {
10650 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
10651 			scfdie();
10652 	} else {
10653 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
10654 			scfdie();
10655 	}
10656 
10657 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10658 		if (scf_pg_get_flags(pg, &flags) != 0)
10659 			scfdie();
10660 
10661 		/* skip nonpersistent pgs */
10662 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
10663 			continue;
10664 
10665 		ret = 0;
10666 		break;
10667 	}
10668 
10669 	if (err == -1)
10670 		scfdie();
10671 
10672 	scf_pg_destroy(pg);
10673 	scf_iter_destroy(iter);
10674 
10675 	return (ret);
10676 }
10677 
10678 /* return 1 if the service has no instances, else return 0 */
10679 static int
10680 svc_has_no_insts(scf_service_t *svc)
10681 {
10682 	scf_instance_t *inst;
10683 	scf_iter_t *iter;
10684 	int r;
10685 	int ret = 1;
10686 
10687 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10688 	    (iter = scf_iter_create(g_hndl)) == NULL)
10689 		scfdie();
10690 
10691 	if (scf_iter_service_instances(iter, svc) != 0)
10692 		scfdie();
10693 
10694 	r = scf_iter_next_instance(iter, inst);
10695 	if (r == 1) {
10696 		ret = 0;
10697 	} else if (r == 0) {
10698 		ret = 1;
10699 	} else if (r == -1) {
10700 		scfdie();
10701 	} else {
10702 		bad_error("scf_iter_next_instance", r);
10703 	}
10704 
10705 	scf_iter_destroy(iter);
10706 	scf_instance_destroy(inst);
10707 
10708 	return (ret);
10709 }
10710 
10711 /*
10712  * Entity deletion.
10713  */
10714 
10715 /*
10716  * Delete the property group <fmri>/:properties/<name>.  Returns
10717  * SCF_ERROR_NONE on success (or if the entity is not found),
10718  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
10719  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
10720  * denied.
10721  */
10722 static scf_error_t
10723 delete_dependency_pg(const char *fmri, const char *name)
10724 {
10725 	void *entity = NULL;
10726 	int isservice;
10727 	scf_propertygroup_t *pg = NULL;
10728 	scf_error_t result;
10729 	char *pgty;
10730 	scf_service_t *svc = NULL;
10731 	scf_instance_t *inst = NULL;
10732 	scf_iter_t *iter = NULL;
10733 	char *name_buf = NULL;
10734 
10735 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10736 	switch (result) {
10737 	case SCF_ERROR_NONE:
10738 		break;
10739 
10740 	case SCF_ERROR_NO_MEMORY:
10741 		uu_die(gettext("Out of memory.\n"));
10742 		/* NOTREACHED */
10743 
10744 	case SCF_ERROR_INVALID_ARGUMENT:
10745 	case SCF_ERROR_CONSTRAINT_VIOLATED:
10746 		return (SCF_ERROR_INVALID_ARGUMENT);
10747 
10748 	case SCF_ERROR_NOT_FOUND:
10749 		result = SCF_ERROR_NONE;
10750 		goto out;
10751 
10752 	default:
10753 		bad_error("fmri_to_entity", result);
10754 	}
10755 
10756 	pg = scf_pg_create(g_hndl);
10757 	if (pg == NULL)
10758 		scfdie();
10759 
10760 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
10761 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10762 			scfdie();
10763 
10764 		result = SCF_ERROR_NONE;
10765 		goto out;
10766 	}
10767 
10768 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10769 
10770 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10771 		scfdie();
10772 
10773 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
10774 		result = SCF_ERROR_TYPE_MISMATCH;
10775 		free(pgty);
10776 		goto out;
10777 	}
10778 
10779 	free(pgty);
10780 
10781 	if (scf_pg_delete(pg) != 0) {
10782 		result = scf_error();
10783 		if (result != SCF_ERROR_PERMISSION_DENIED)
10784 			scfdie();
10785 		goto out;
10786 	}
10787 
10788 	/*
10789 	 * We have to handle the case where we've just deleted the last
10790 	 * property group of a "dummy" entity (instance or service).
10791 	 * A "dummy" entity is an entity only present to hold an
10792 	 * external dependency.
10793 	 * So, in the case we deleted the last property group then we
10794 	 * can also delete the entity. If the entity is an instance then
10795 	 * we must verify if this was the last instance for the service
10796 	 * and if it is, we can also delete the service if it doesn't
10797 	 * have any property group either.
10798 	 */
10799 
10800 	result = SCF_ERROR_NONE;
10801 
10802 	if (isservice) {
10803 		svc = (scf_service_t *)entity;
10804 
10805 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
10806 		    (iter = scf_iter_create(g_hndl)) == NULL)
10807 			scfdie();
10808 
10809 		name_buf = safe_malloc(max_scf_name_len + 1);
10810 	} else {
10811 		inst = (scf_instance_t *)entity;
10812 	}
10813 
10814 	/*
10815 	 * If the entity is an instance and we've just deleted its last
10816 	 * property group then we should delete it.
10817 	 */
10818 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
10819 		/* find the service before deleting the inst. - needed later */
10820 		if ((svc = scf_service_create(g_hndl)) == NULL)
10821 			scfdie();
10822 
10823 		if (scf_instance_get_parent(inst, svc) != 0)
10824 			scfdie();
10825 
10826 		/* delete the instance */
10827 		if (scf_instance_delete(inst) != 0) {
10828 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10829 				scfdie();
10830 
10831 			result = SCF_ERROR_PERMISSION_DENIED;
10832 			goto out;
10833 		}
10834 		/* no need to refresh the instance */
10835 		inst = NULL;
10836 	}
10837 
10838 	/*
10839 	 * If the service has no more instances and pgs or we just deleted the
10840 	 * last instance and the service doesn't have anymore propery groups
10841 	 * then the service should be deleted.
10842 	 */
10843 	if (svc != NULL &&
10844 	    svc_has_no_insts(svc) &&
10845 	    entity_has_no_pgs((void *)svc, 1)) {
10846 		if (scf_service_delete(svc) == 0) {
10847 			if (isservice) {
10848 				/* no need to refresh the service */
10849 				svc = NULL;
10850 			}
10851 
10852 			goto out;
10853 		}
10854 
10855 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10856 			scfdie();
10857 
10858 		result = SCF_ERROR_PERMISSION_DENIED;
10859 	}
10860 
10861 	/* if the entity has not been deleted, refresh it */
10862 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
10863 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
10864 		    name_buf);
10865 	}
10866 
10867 out:
10868 	if (isservice && (inst != NULL && iter != NULL)) {
10869 		free(name_buf);
10870 		scf_iter_destroy(iter);
10871 		scf_instance_destroy(inst);
10872 	}
10873 
10874 	if (!isservice && svc != NULL) {
10875 		scf_service_destroy(svc);
10876 	}
10877 
10878 	scf_pg_destroy(pg);
10879 	if (entity != NULL)
10880 		entity_destroy(entity, isservice);
10881 
10882 	return (result);
10883 }
10884 
10885 static int
10886 delete_dependents(scf_propertygroup_t *pg)
10887 {
10888 	char *pgty, *name, *fmri;
10889 	scf_property_t *prop;
10890 	scf_value_t *val;
10891 	scf_iter_t *iter;
10892 	int r;
10893 	scf_error_t err;
10894 
10895 	/* Verify that the pg has the correct type. */
10896 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10897 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10898 		scfdie();
10899 
10900 	if (strcmp(pgty, scf_group_framework) != 0) {
10901 		if (g_verbose) {
10902 			fmri = safe_malloc(max_scf_fmri_len + 1);
10903 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
10904 				scfdie();
10905 
10906 			warn(gettext("Property group %s is not of expected "
10907 			    "type %s.\n"), fmri, scf_group_framework);
10908 
10909 			free(fmri);
10910 		}
10911 
10912 		free(pgty);
10913 		return (-1);
10914 	}
10915 
10916 	free(pgty);
10917 
10918 	/* map delete_dependency_pg onto the properties. */
10919 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10920 	    (val = scf_value_create(g_hndl)) == NULL ||
10921 	    (iter = scf_iter_create(g_hndl)) == NULL)
10922 		scfdie();
10923 
10924 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10925 		scfdie();
10926 
10927 	name = safe_malloc(max_scf_name_len + 1);
10928 	fmri = safe_malloc(max_scf_fmri_len + 2);
10929 
10930 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
10931 		scf_type_t ty;
10932 
10933 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
10934 			scfdie();
10935 
10936 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
10937 			scfdie();
10938 
10939 		if ((ty != SCF_TYPE_ASTRING &&
10940 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
10941 		    prop_get_val(prop, val) != 0)
10942 			continue;
10943 
10944 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
10945 			scfdie();
10946 
10947 		err = delete_dependency_pg(fmri, name);
10948 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
10949 			if (scf_property_to_fmri(prop, fmri,
10950 			    max_scf_fmri_len + 2) < 0)
10951 				scfdie();
10952 
10953 			warn(gettext("Value of %s is not a valid FMRI.\n"),
10954 			    fmri);
10955 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
10956 			warn(gettext("Property group \"%s\" of entity \"%s\" "
10957 			    "does not have dependency type.\n"), name, fmri);
10958 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
10959 			warn(gettext("Could not delete property group \"%s\" "
10960 			    "of entity \"%s\" (permission denied).\n"), name,
10961 			    fmri);
10962 		}
10963 	}
10964 	if (r == -1)
10965 		scfdie();
10966 
10967 	scf_value_destroy(val);
10968 	scf_property_destroy(prop);
10969 
10970 	return (0);
10971 }
10972 
10973 /*
10974  * Returns 1 if the instance may be running, and 0 otherwise.
10975  */
10976 static int
10977 inst_is_running(scf_instance_t *inst)
10978 {
10979 	scf_propertygroup_t *pg;
10980 	scf_property_t *prop;
10981 	scf_value_t *val;
10982 	char buf[MAX_SCF_STATE_STRING_SZ];
10983 	int ret = 0;
10984 	ssize_t szret;
10985 
10986 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10987 	    (prop = scf_property_create(g_hndl)) == NULL ||
10988 	    (val = scf_value_create(g_hndl)) == NULL)
10989 		scfdie();
10990 
10991 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
10992 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10993 			scfdie();
10994 		goto out;
10995 	}
10996 
10997 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
10998 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
10999 	    prop_get_val(prop, val) != 0)
11000 		goto out;
11001 
11002 	szret = scf_value_get_astring(val, buf, sizeof (buf));
11003 	assert(szret >= 0);
11004 
11005 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11006 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11007 
11008 out:
11009 	scf_value_destroy(val);
11010 	scf_property_destroy(prop);
11011 	scf_pg_destroy(pg);
11012 	return (ret);
11013 }
11014 
11015 static uint8_t
11016 pg_is_external_dependency(scf_propertygroup_t *pg)
11017 {
11018 	char *type;
11019 	scf_value_t *val;
11020 	scf_property_t *prop;
11021 	uint8_t b = B_FALSE;
11022 
11023 	type = safe_malloc(max_scf_pg_type_len + 1);
11024 
11025 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
11026 		scfdie();
11027 
11028 	if ((prop = scf_property_create(g_hndl)) == NULL ||
11029 	    (val = scf_value_create(g_hndl)) == NULL)
11030 		scfdie();
11031 
11032 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
11033 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
11034 			if (scf_property_get_value(prop, val) != 0)
11035 				scfdie();
11036 			if (scf_value_get_boolean(val, &b) != 0)
11037 				scfdie();
11038 		}
11039 	}
11040 
11041 	free(type);
11042 	(void) scf_value_destroy(val);
11043 	(void) scf_property_destroy(prop);
11044 
11045 	return (b);
11046 }
11047 
11048 #define	DELETE_FAILURE			-1
11049 #define	DELETE_SUCCESS_NOEXTDEPS	0
11050 #define	DELETE_SUCCESS_EXTDEPS		1
11051 
11052 /*
11053  * lscf_instance_delete() deletes an instance.  Before calling
11054  * scf_instance_delete(), though, we make sure the instance isn't
11055  * running and delete dependencies in other entities which the instance
11056  * declared as "dependents".  If there are dependencies which were
11057  * created for other entities, then instead of deleting the instance we
11058  * make it "empty" by deleting all other property groups and all
11059  * snapshots.
11060  *
11061  * lscf_instance_delete() verifies that there is no external dependency pgs
11062  * before suppressing the instance. If there is, then we must not remove them
11063  * now in case the instance is re-created otherwise the dependencies would be
11064  * lost. The external dependency pgs will be removed if the dependencies are
11065  * removed.
11066  *
11067  * Returns:
11068  *  DELETE_FAILURE		on failure
11069  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11070  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11071  */
11072 static int
11073 lscf_instance_delete(scf_instance_t *inst, int force)
11074 {
11075 	scf_propertygroup_t *pg;
11076 	scf_snapshot_t *snap;
11077 	scf_iter_t *iter;
11078 	int err;
11079 	int external = 0;
11080 
11081 	/* If we're not forcing and the instance is running, refuse. */
11082 	if (!force && inst_is_running(inst)) {
11083 		char *fmri;
11084 
11085 		fmri = safe_malloc(max_scf_fmri_len + 1);
11086 
11087 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
11088 			scfdie();
11089 
11090 		semerr(gettext("Instance %s may be running.  "
11091 		    "Use delete -f if it is not.\n"), fmri);
11092 
11093 		free(fmri);
11094 		return (DELETE_FAILURE);
11095 	}
11096 
11097 	pg = scf_pg_create(g_hndl);
11098 	if (pg == NULL)
11099 		scfdie();
11100 
11101 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
11102 		(void) delete_dependents(pg);
11103 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11104 		scfdie();
11105 
11106 	scf_pg_destroy(pg);
11107 
11108 	/*
11109 	 * If the instance has some external dependencies then we must
11110 	 * keep them in case the instance is reimported otherwise the
11111 	 * dependencies would be lost on reimport.
11112 	 */
11113 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11114 	    (pg = scf_pg_create(g_hndl)) == NULL)
11115 		scfdie();
11116 
11117 	if (scf_iter_instance_pgs(iter, inst) < 0)
11118 		scfdie();
11119 
11120 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11121 		if (pg_is_external_dependency(pg)) {
11122 			external = 1;
11123 			continue;
11124 		}
11125 
11126 		if (scf_pg_delete(pg) != 0) {
11127 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11128 				scfdie();
11129 			else {
11130 				semerr(emsg_permission_denied);
11131 
11132 				(void) scf_iter_destroy(iter);
11133 				(void) scf_pg_destroy(pg);
11134 				return (DELETE_FAILURE);
11135 			}
11136 		}
11137 	}
11138 
11139 	if (err == -1)
11140 		scfdie();
11141 
11142 	(void) scf_iter_destroy(iter);
11143 	(void) scf_pg_destroy(pg);
11144 
11145 	if (external) {
11146 		/*
11147 		 * All the pgs have been deleted for the instance except
11148 		 * the ones holding the external dependencies.
11149 		 * For the job to be complete, we must also delete the
11150 		 * snapshots associated with the instance.
11151 		 */
11152 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
11153 		    NULL)
11154 			scfdie();
11155 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
11156 			scfdie();
11157 
11158 		if (scf_iter_instance_snapshots(iter, inst) == -1)
11159 			scfdie();
11160 
11161 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
11162 			if (_scf_snapshot_delete(snap) != 0) {
11163 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11164 					scfdie();
11165 
11166 				semerr(emsg_permission_denied);
11167 
11168 				(void) scf_iter_destroy(iter);
11169 				(void) scf_snapshot_destroy(snap);
11170 				return (DELETE_FAILURE);
11171 			}
11172 		}
11173 
11174 		if (err == -1)
11175 			scfdie();
11176 
11177 		(void) scf_iter_destroy(iter);
11178 		(void) scf_snapshot_destroy(snap);
11179 		return (DELETE_SUCCESS_EXTDEPS);
11180 	}
11181 
11182 	if (scf_instance_delete(inst) != 0) {
11183 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11184 			scfdie();
11185 
11186 		semerr(emsg_permission_denied);
11187 
11188 		return (DELETE_FAILURE);
11189 	}
11190 
11191 	return (DELETE_SUCCESS_NOEXTDEPS);
11192 }
11193 
11194 /*
11195  * lscf_service_delete() deletes a service.  Before calling
11196  * scf_service_delete(), though, we call lscf_instance_delete() for
11197  * each of the instances and delete dependencies in other entities
11198  * which were created as "dependents" of this service.  If there are
11199  * dependencies which were created for other entities, then we delete
11200  * all other property groups in the service and leave it as "empty".
11201  *
11202  * lscf_service_delete() verifies that there is no external dependency
11203  * pgs at the instance & service level before suppressing the service.
11204  * If there is, then we must not remove them now in case the service
11205  * is re-imported otherwise the dependencies would be lost. The external
11206  * dependency pgs will be removed if the dependencies are removed.
11207  *
11208  * Returns:
11209  *   DELETE_FAILURE		on failure
11210  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
11211  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
11212  */
11213 static int
11214 lscf_service_delete(scf_service_t *svc, int force)
11215 {
11216 	int r;
11217 	scf_instance_t *inst;
11218 	scf_propertygroup_t *pg;
11219 	scf_iter_t *iter;
11220 	int ret;
11221 	int external = 0;
11222 
11223 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11224 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11225 	    (iter = scf_iter_create(g_hndl)) == NULL)
11226 		scfdie();
11227 
11228 	if (scf_iter_service_instances(iter, svc) != 0)
11229 		scfdie();
11230 
11231 	for (r = scf_iter_next_instance(iter, inst);
11232 	    r == 1;
11233 	    r = scf_iter_next_instance(iter, inst)) {
11234 
11235 		ret = lscf_instance_delete(inst, force);
11236 		if (ret == DELETE_FAILURE) {
11237 			scf_iter_destroy(iter);
11238 			scf_pg_destroy(pg);
11239 			scf_instance_destroy(inst);
11240 			return (DELETE_FAILURE);
11241 		}
11242 
11243 		/*
11244 		 * Record the fact that there is some external dependencies
11245 		 * at the instance level.
11246 		 */
11247 		if (ret == DELETE_SUCCESS_EXTDEPS)
11248 			external |= 1;
11249 	}
11250 
11251 	if (r != 0)
11252 		scfdie();
11253 
11254 	/* Delete dependency property groups in dependent services. */
11255 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
11256 		(void) delete_dependents(pg);
11257 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
11258 		scfdie();
11259 
11260 	scf_iter_destroy(iter);
11261 	scf_pg_destroy(pg);
11262 	scf_instance_destroy(inst);
11263 
11264 	/*
11265 	 * If the service has some external dependencies then we don't
11266 	 * want to remove them in case the service is re-imported.
11267 	 */
11268 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11269 	    (iter = scf_iter_create(g_hndl)) == NULL)
11270 		scfdie();
11271 
11272 	if (scf_iter_service_pgs(iter, svc) < 0)
11273 		scfdie();
11274 
11275 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
11276 		if (pg_is_external_dependency(pg)) {
11277 			external |= 2;
11278 			continue;
11279 		}
11280 
11281 		if (scf_pg_delete(pg) != 0) {
11282 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11283 				scfdie();
11284 			else {
11285 				semerr(emsg_permission_denied);
11286 
11287 				(void) scf_iter_destroy(iter);
11288 				(void) scf_pg_destroy(pg);
11289 				return (DELETE_FAILURE);
11290 			}
11291 		}
11292 	}
11293 
11294 	if (r == -1)
11295 		scfdie();
11296 
11297 	(void) scf_iter_destroy(iter);
11298 	(void) scf_pg_destroy(pg);
11299 
11300 	if (external != 0)
11301 		return (DELETE_SUCCESS_EXTDEPS);
11302 
11303 	if (scf_service_delete(svc) == 0)
11304 		return (DELETE_SUCCESS_NOEXTDEPS);
11305 
11306 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11307 		scfdie();
11308 
11309 	semerr(emsg_permission_denied);
11310 	return (DELETE_FAILURE);
11311 }
11312 
11313 static int
11314 delete_callback(void *data, scf_walkinfo_t *wip)
11315 {
11316 	int force = (int)data;
11317 
11318 	if (wip->inst != NULL)
11319 		(void) lscf_instance_delete(wip->inst, force);
11320 	else
11321 		(void) lscf_service_delete(wip->svc, force);
11322 
11323 	return (0);
11324 }
11325 
11326 void
11327 lscf_delete(const char *fmri, int force)
11328 {
11329 	scf_service_t *svc;
11330 	scf_instance_t *inst;
11331 	int ret;
11332 
11333 	lscf_prep_hndl();
11334 
11335 	if (cur_snap != NULL) {
11336 		if (!snaplevel_is_instance(cur_level)) {
11337 			char *buf;
11338 
11339 			buf = safe_malloc(max_scf_name_len + 1);
11340 			if (scf_instance_get_name(cur_inst, buf,
11341 			    max_scf_name_len + 1) >= 0) {
11342 				if (strcmp(buf, fmri) == 0) {
11343 					semerr(emsg_cant_modify_snapshots);
11344 					free(buf);
11345 					return;
11346 				}
11347 			} else if (scf_error() != SCF_ERROR_DELETED) {
11348 				scfdie();
11349 			}
11350 			free(buf);
11351 		}
11352 	} else if (cur_inst != NULL) {
11353 		/* EMPTY */;
11354 	} else if (cur_svc != NULL) {
11355 		inst = scf_instance_create(g_hndl);
11356 		if (inst == NULL)
11357 			scfdie();
11358 
11359 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
11360 		    SCF_SUCCESS) {
11361 			(void) lscf_instance_delete(inst, force);
11362 			scf_instance_destroy(inst);
11363 			return;
11364 		}
11365 
11366 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11367 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11368 			scfdie();
11369 
11370 		scf_instance_destroy(inst);
11371 	} else {
11372 		assert(cur_scope != NULL);
11373 
11374 		svc = scf_service_create(g_hndl);
11375 		if (svc == NULL)
11376 			scfdie();
11377 
11378 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
11379 		    SCF_SUCCESS) {
11380 			(void) lscf_service_delete(svc, force);
11381 			scf_service_destroy(svc);
11382 			return;
11383 		}
11384 
11385 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
11386 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
11387 			scfdie();
11388 
11389 		scf_service_destroy(svc);
11390 	}
11391 
11392 	/*
11393 	 * Match FMRI to entity.
11394 	 */
11395 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11396 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
11397 		semerr(gettext("Failed to walk instances: %s\n"),
11398 		    scf_strerror(ret));
11399 	}
11400 }
11401 
11402 
11403 
11404 /*
11405  * :properties commands.  These all end with "pg" or "prop" and generally
11406  * operate on the currently selected entity.
11407  */
11408 
11409 /*
11410  * Property listing.  List the property groups, properties, their types and
11411  * their values for the currently selected entity.
11412  */
11413 static void
11414 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
11415 {
11416 	char *buf;
11417 	uint32_t flags;
11418 
11419 	buf = safe_malloc(max_scf_pg_type_len + 1);
11420 
11421 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
11422 		scfdie();
11423 
11424 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
11425 		scfdie();
11426 
11427 	safe_printf("%-*s  %s", namewidth, name, buf);
11428 
11429 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
11430 		safe_printf("\tNONPERSISTENT");
11431 
11432 	safe_printf("\n");
11433 
11434 	free(buf);
11435 }
11436 
11437 static boolean_t
11438 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
11439 {
11440 	if (scf_property_get_value(prop, val) == 0) {
11441 		return (B_FALSE);
11442 	} else {
11443 		switch (scf_error()) {
11444 		case SCF_ERROR_NOT_FOUND:
11445 			return (B_FALSE);
11446 		case SCF_ERROR_PERMISSION_DENIED:
11447 		case SCF_ERROR_CONSTRAINT_VIOLATED:
11448 			return (B_TRUE);
11449 		default:
11450 			scfdie();
11451 			/*NOTREACHED*/
11452 		}
11453 	}
11454 }
11455 
11456 static void
11457 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
11458 {
11459 	scf_iter_t *iter;
11460 	scf_value_t *val;
11461 	const char *type;
11462 	int multiple_strings = 0;
11463 	int ret;
11464 
11465 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11466 	    (val = scf_value_create(g_hndl)) == NULL)
11467 		scfdie();
11468 
11469 	type = prop_to_typestr(prop);
11470 	assert(type != NULL);
11471 
11472 	safe_printf("%-*s  %-7s ", len, name, type);
11473 
11474 	if (prop_has_multiple_values(prop, val) &&
11475 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
11476 	    scf_value_type(val) == SCF_TYPE_USTRING))
11477 		multiple_strings = 1;
11478 
11479 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11480 		scfdie();
11481 
11482 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11483 		char *buf;
11484 		ssize_t vlen, szret;
11485 
11486 		vlen = scf_value_get_as_string(val, NULL, 0);
11487 		if (vlen < 0)
11488 			scfdie();
11489 
11490 		buf = safe_malloc(vlen + 1);
11491 
11492 		szret = scf_value_get_as_string(val, buf, vlen + 1);
11493 		if (szret < 0)
11494 			scfdie();
11495 		assert(szret <= vlen);
11496 
11497 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11498 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
11499 			safe_printf(" \"");
11500 			(void) quote_and_print(buf, stdout, 0);
11501 			(void) putchar('"');
11502 			if (ferror(stdout)) {
11503 				(void) putchar('\n');
11504 				uu_die(gettext("Error writing to stdout.\n"));
11505 			}
11506 		} else {
11507 			safe_printf(" %s", buf);
11508 		}
11509 
11510 		free(buf);
11511 	}
11512 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11513 		scfdie();
11514 
11515 	if (putchar('\n') != '\n')
11516 		uu_die(gettext("Could not output newline"));
11517 }
11518 
11519 /*
11520  * Outputs template property group info for the describe subcommand.
11521  * If 'templates' == 2, verbose output is printed in the format expected
11522  * for describe -v, which includes all templates fields.  If pg is
11523  * not NULL, we're describing the template data, not an existing property
11524  * group, and formatting should be appropriate for describe -t.
11525  */
11526 static void
11527 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
11528 {
11529 	char *buf;
11530 	uint8_t required;
11531 	scf_property_t *stability_prop;
11532 	scf_value_t *stability_val;
11533 
11534 	if (templates == 0)
11535 		return;
11536 
11537 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
11538 	    (stability_val = scf_value_create(g_hndl)) == NULL)
11539 		scfdie();
11540 
11541 	if (templates == 2 && pg != NULL) {
11542 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
11543 		    stability_prop) == 0) {
11544 			if (prop_check_type(stability_prop,
11545 			    SCF_TYPE_ASTRING) == 0 &&
11546 			    prop_get_val(stability_prop, stability_val) == 0) {
11547 				char *stability;
11548 
11549 				stability = safe_malloc(max_scf_value_len + 1);
11550 
11551 				if (scf_value_get_astring(stability_val,
11552 				    stability, max_scf_value_len + 1) == -1 &&
11553 				    scf_error() != SCF_ERROR_NOT_FOUND)
11554 					scfdie();
11555 
11556 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11557 				    gettext("stability"), stability);
11558 
11559 				free(stability);
11560 			}
11561 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
11562 			scfdie();
11563 	}
11564 
11565 	scf_property_destroy(stability_prop);
11566 	scf_value_destroy(stability_val);
11567 
11568 	if (pgt == NULL)
11569 		return;
11570 
11571 	if (pg == NULL || templates == 2) {
11572 		/* print type info only if scf_tmpl_pg_name succeeds */
11573 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
11574 			if (pg != NULL)
11575 				safe_printf("%s", TMPL_INDENT);
11576 			safe_printf("%s: ", gettext("name"));
11577 			safe_printf("%s\n", buf);
11578 			free(buf);
11579 		}
11580 
11581 		/* print type info only if scf_tmpl_pg_type succeeds */
11582 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
11583 			if (pg != NULL)
11584 				safe_printf("%s", TMPL_INDENT);
11585 			safe_printf("%s: ", gettext("type"));
11586 			safe_printf("%s\n", buf);
11587 			free(buf);
11588 		}
11589 	}
11590 
11591 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
11592 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11593 		    required ? "true" : "false");
11594 
11595 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
11596 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
11597 		    buf);
11598 		free(buf);
11599 	}
11600 
11601 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
11602 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11603 		    buf);
11604 		free(buf);
11605 	}
11606 
11607 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
11608 		if (templates == 2)
11609 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11610 			    gettext("description"), buf);
11611 		else
11612 			safe_printf("%s%s\n", TMPL_INDENT, buf);
11613 		free(buf);
11614 	}
11615 
11616 }
11617 
11618 /*
11619  * With as_value set to true, indent as appropriate for the value level.
11620  * If false, indent to appropriate level for inclusion in constraint
11621  * or choice printout.
11622  */
11623 static void
11624 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
11625     int as_value)
11626 {
11627 	char *buf;
11628 
11629 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
11630 		if (as_value == 0)
11631 			safe_printf("%s", TMPL_CHOICE_INDENT);
11632 		else
11633 			safe_printf("%s", TMPL_INDENT);
11634 		safe_printf("%s: %s\n", gettext("value common name"), buf);
11635 		free(buf);
11636 	}
11637 
11638 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
11639 		if (as_value == 0)
11640 			safe_printf("%s", TMPL_CHOICE_INDENT);
11641 		else
11642 			safe_printf("%s", TMPL_INDENT);
11643 		safe_printf("%s: %s\n", gettext("value description"), buf);
11644 		free(buf);
11645 	}
11646 }
11647 
11648 static void
11649 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
11650 {
11651 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
11652 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11653 	safe_printf("%s\n", val_buf);
11654 
11655 	print_template_value_details(prt, val_buf, 1);
11656 }
11657 
11658 static void
11659 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
11660 {
11661 	int i, printed = 0;
11662 	scf_values_t values;
11663 	scf_count_ranges_t c_ranges;
11664 	scf_int_ranges_t i_ranges;
11665 
11666 	printed = 0;
11667 	i = 0;
11668 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
11669 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11670 		    gettext("value constraints"));
11671 		printed++;
11672 		for (i = 0; i < values.value_count; ++i) {
11673 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11674 			    gettext("value name"), values.values_as_strings[i]);
11675 			if (verbose == 1)
11676 				print_template_value_details(prt,
11677 				    values.values_as_strings[i], 0);
11678 		}
11679 
11680 		scf_values_destroy(&values);
11681 	}
11682 
11683 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
11684 		if (printed++ == 0)
11685 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11686 			    gettext("value constraints"));
11687 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11688 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11689 			    gettext("range"), c_ranges.scr_min[i],
11690 			    c_ranges.scr_max[i]);
11691 		}
11692 		scf_count_ranges_destroy(&c_ranges);
11693 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11694 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
11695 		if (printed++ == 0)
11696 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11697 			    gettext("value constraints"));
11698 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11699 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11700 			    gettext("range"), i_ranges.sir_min[i],
11701 			    i_ranges.sir_max[i]);
11702 		}
11703 		scf_int_ranges_destroy(&i_ranges);
11704 	}
11705 }
11706 
11707 static void
11708 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
11709 {
11710 	int i = 0, printed = 0;
11711 	scf_values_t values;
11712 	scf_count_ranges_t c_ranges;
11713 	scf_int_ranges_t i_ranges;
11714 
11715 	printed = 0;
11716 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
11717 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11718 		    gettext("value constraints"));
11719 		printed++;
11720 		for (i = 0; i < values.value_count; i++) {
11721 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11722 			    gettext("value name"), values.values_as_strings[i]);
11723 			if (verbose == 1)
11724 				print_template_value_details(prt,
11725 				    values.values_as_strings[i], 0);
11726 		}
11727 
11728 		scf_values_destroy(&values);
11729 	}
11730 
11731 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
11732 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11733 			if (printed++ == 0)
11734 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11735 				    gettext("value choices"));
11736 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11737 			    gettext("range"), c_ranges.scr_min[i],
11738 			    c_ranges.scr_max[i]);
11739 		}
11740 		scf_count_ranges_destroy(&c_ranges);
11741 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11742 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
11743 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11744 			if (printed++ == 0)
11745 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11746 				    gettext("value choices"));
11747 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11748 			    gettext("range"), i_ranges.sir_min[i],
11749 			    i_ranges.sir_max[i]);
11750 		}
11751 		scf_int_ranges_destroy(&i_ranges);
11752 	}
11753 }
11754 
11755 static void
11756 list_values_by_template(scf_prop_tmpl_t *prt)
11757 {
11758 	print_template_constraints(prt, 1);
11759 	print_template_choices(prt, 1);
11760 }
11761 
11762 static void
11763 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
11764 {
11765 	char *val_buf;
11766 	scf_iter_t *iter;
11767 	scf_value_t *val;
11768 	int ret;
11769 
11770 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11771 	    (val = scf_value_create(g_hndl)) == NULL)
11772 		scfdie();
11773 
11774 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11775 		scfdie();
11776 
11777 	val_buf = safe_malloc(max_scf_value_len + 1);
11778 
11779 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11780 		if (scf_value_get_as_string(val, val_buf,
11781 		    max_scf_value_len + 1) < 0)
11782 			scfdie();
11783 
11784 		print_template_value(prt, val_buf);
11785 	}
11786 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11787 		scfdie();
11788 	free(val_buf);
11789 
11790 	print_template_constraints(prt, 0);
11791 	print_template_choices(prt, 0);
11792 
11793 }
11794 
11795 /*
11796  * Outputs property info for the describe subcommand
11797  * Verbose output if templates == 2, -v option of svccfg describe
11798  * Displays template data if prop is not NULL, -t option of svccfg describe
11799  */
11800 static void
11801 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
11802 {
11803 	char *buf;
11804 	uint8_t u_buf;
11805 	int i;
11806 	uint64_t min, max;
11807 	scf_values_t values;
11808 
11809 	if (prt == NULL || templates == 0)
11810 		return;
11811 
11812 	if (prop == NULL) {
11813 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
11814 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
11815 			safe_printf("%s\n", buf);
11816 			free(buf);
11817 		} else
11818 			safe_printf("(%s)\n", gettext("any"));
11819 	}
11820 
11821 	if (prop == NULL || templates == 2) {
11822 		if (prop != NULL)
11823 			safe_printf("%s", TMPL_INDENT);
11824 		else
11825 			safe_printf("%s", TMPL_VALUE_INDENT);
11826 		safe_printf("%s: ", gettext("type"));
11827 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
11828 			safe_printf("%s\n", buf);
11829 			free(buf);
11830 		} else
11831 			safe_printf("(%s)\n", gettext("any"));
11832 	}
11833 
11834 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
11835 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11836 		    u_buf ? "true" : "false");
11837 
11838 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
11839 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11840 		    buf);
11841 		free(buf);
11842 	}
11843 
11844 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
11845 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
11846 		    buf);
11847 		free(buf);
11848 	}
11849 
11850 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
11851 		safe_printf("%s%s\n", TMPL_INDENT, buf);
11852 		free(buf);
11853 	}
11854 
11855 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
11856 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
11857 		    scf_tmpl_visibility_to_string(u_buf));
11858 
11859 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
11860 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11861 		    gettext("minimum number of values"), min);
11862 		if (max == ULLONG_MAX) {
11863 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11864 			    gettext("maximum number of values"),
11865 			    gettext("unlimited"));
11866 		} else {
11867 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11868 			    gettext("maximum number of values"), max);
11869 		}
11870 	}
11871 
11872 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
11873 		for (i = 0; i < values.value_count; i++) {
11874 			if (i == 0) {
11875 				safe_printf("%s%s:", TMPL_INDENT,
11876 				    gettext("internal separators"));
11877 			}
11878 			safe_printf(" \"%s\"", values.values_as_strings[i]);
11879 		}
11880 		safe_printf("\n");
11881 	}
11882 
11883 	if (templates != 2)
11884 		return;
11885 
11886 	if (prop != NULL)
11887 		list_values_tmpl(prt, prop);
11888 	else
11889 		list_values_by_template(prt);
11890 }
11891 
11892 static char *
11893 read_astring(scf_propertygroup_t *pg, const char *prop_name)
11894 {
11895 	char *rv;
11896 
11897 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
11898 	if (rv == NULL) {
11899 		switch (scf_error()) {
11900 		case SCF_ERROR_NOT_FOUND:
11901 			break;
11902 		default:
11903 			scfdie();
11904 		}
11905 	}
11906 	return (rv);
11907 }
11908 
11909 static void
11910 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
11911 {
11912 	size_t doc_len;
11913 	size_t man_len;
11914 	char *pg_name;
11915 	char *text = NULL;
11916 	int rv;
11917 
11918 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
11919 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
11920 	pg_name = safe_malloc(max_scf_name_len + 1);
11921 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
11922 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
11923 			scfdie();
11924 		}
11925 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
11926 			/* Display doc_link and and uri */
11927 			safe_printf("%s%s:\n", TMPL_INDENT,
11928 			    gettext("doc_link"));
11929 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
11930 			if (text != NULL) {
11931 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11932 				    TMPL_INDENT, gettext("name"), text);
11933 				uu_free(text);
11934 			}
11935 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
11936 			if (text != NULL) {
11937 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
11938 				    gettext("uri"), text);
11939 				uu_free(text);
11940 			}
11941 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
11942 		    man_len) == 0) {
11943 			/* Display manpage title, section and path */
11944 			safe_printf("%s%s:\n", TMPL_INDENT,
11945 			    gettext("manpage"));
11946 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
11947 			if (text != NULL) {
11948 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11949 				    TMPL_INDENT, gettext("title"), text);
11950 				uu_free(text);
11951 			}
11952 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
11953 			if (text != NULL) {
11954 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11955 				    TMPL_INDENT, gettext("section"), text);
11956 				uu_free(text);
11957 			}
11958 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
11959 			if (text != NULL) {
11960 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11961 				    TMPL_INDENT, gettext("manpath"), text);
11962 				uu_free(text);
11963 			}
11964 		}
11965 	}
11966 	if (rv == -1)
11967 		scfdie();
11968 
11969 done:
11970 	free(pg_name);
11971 }
11972 
11973 static void
11974 list_entity_tmpl(int templates)
11975 {
11976 	char *common_name = NULL;
11977 	char *description = NULL;
11978 	char *locale = NULL;
11979 	scf_iter_t *iter;
11980 	scf_propertygroup_t *pg;
11981 	scf_property_t *prop;
11982 	int r;
11983 	scf_value_t *val;
11984 
11985 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11986 	    (prop = scf_property_create(g_hndl)) == NULL ||
11987 	    (val = scf_value_create(g_hndl)) == NULL ||
11988 	    (iter = scf_iter_create(g_hndl)) == NULL)
11989 		scfdie();
11990 
11991 	locale = setlocale(LC_MESSAGES, NULL);
11992 
11993 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
11994 		common_name = safe_malloc(max_scf_value_len + 1);
11995 
11996 		/* Try both the current locale and the "C" locale. */
11997 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
11998 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
11999 		    scf_pg_get_property(pg, "C", prop) == 0)) {
12000 			if (prop_get_val(prop, val) == 0 &&
12001 			    scf_value_get_ustring(val, common_name,
12002 			    max_scf_value_len + 1) != -1) {
12003 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12004 				    gettext("common name"), common_name);
12005 			}
12006 		}
12007 	}
12008 
12009 	/*
12010 	 * Do description, manpages, and doc links if templates == 2.
12011 	 */
12012 	if (templates == 2) {
12013 		/* Get the description. */
12014 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12015 			description = safe_malloc(max_scf_value_len + 1);
12016 
12017 			/* Try both the current locale and the "C" locale. */
12018 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
12019 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
12020 			    scf_pg_get_property(pg, "C", prop) == 0)) {
12021 				if (prop_get_val(prop, val) == 0 &&
12022 				    scf_value_get_ustring(val, description,
12023 				    max_scf_value_len + 1) != -1) {
12024 					safe_printf("%s%s: %s\n", TMPL_INDENT,
12025 					    gettext("description"),
12026 					    description);
12027 				}
12028 			}
12029 		}
12030 
12031 		/* Process doc_link & manpage elements. */
12032 		if (cur_level != NULL) {
12033 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
12034 			    SCF_GROUP_TEMPLATE);
12035 		} else if (cur_inst != NULL) {
12036 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
12037 			    SCF_GROUP_TEMPLATE);
12038 		} else {
12039 			r = scf_iter_service_pgs_typed(iter, cur_svc,
12040 			    SCF_GROUP_TEMPLATE);
12041 		}
12042 		if (r == 0) {
12043 			display_documentation(iter, pg);
12044 		}
12045 	}
12046 
12047 	free(common_name);
12048 	free(description);
12049 	scf_pg_destroy(pg);
12050 	scf_property_destroy(prop);
12051 	scf_value_destroy(val);
12052 	scf_iter_destroy(iter);
12053 }
12054 
12055 static void
12056 listtmpl(const char *pattern, int templates)
12057 {
12058 	scf_pg_tmpl_t *pgt;
12059 	scf_prop_tmpl_t *prt;
12060 	char *snapbuf = NULL;
12061 	char *fmribuf;
12062 	char *pg_name = NULL, *prop_name = NULL;
12063 	ssize_t prop_name_size;
12064 	char *qual_prop_name;
12065 	char *search_name;
12066 	int listed = 0;
12067 
12068 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12069 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
12070 		scfdie();
12071 
12072 	fmribuf = safe_malloc(max_scf_name_len + 1);
12073 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
12074 
12075 	if (cur_snap != NULL) {
12076 		snapbuf = safe_malloc(max_scf_name_len + 1);
12077 		if (scf_snapshot_get_name(cur_snap, snapbuf,
12078 		    max_scf_name_len + 1) < 0)
12079 			scfdie();
12080 	}
12081 
12082 	if (cur_inst != NULL) {
12083 		if (scf_instance_to_fmri(cur_inst, fmribuf,
12084 		    max_scf_name_len + 1) < 0)
12085 			scfdie();
12086 	} else if (cur_svc != NULL) {
12087 		if (scf_service_to_fmri(cur_svc, fmribuf,
12088 		    max_scf_name_len + 1) < 0)
12089 			scfdie();
12090 	} else
12091 		abort();
12092 
12093 	/* If pattern is specified, we want to list only those items. */
12094 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
12095 		listed = 0;
12096 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
12097 		    fnmatch(pattern, pg_name, 0) == 0)) {
12098 			list_pg_tmpl(pgt, NULL, templates);
12099 			listed++;
12100 		}
12101 
12102 		scf_tmpl_prop_reset(prt);
12103 
12104 		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
12105 			search_name = NULL;
12106 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
12107 			if ((prop_name_size > 0) && (pg_name != NULL)) {
12108 				if (snprintf(qual_prop_name,
12109 				    max_scf_name_len + 1, "%s/%s",
12110 				    pg_name, prop_name) >=
12111 				    max_scf_name_len + 1) {
12112 					prop_name_size = -1;
12113 				} else {
12114 					search_name = qual_prop_name;
12115 				}
12116 			}
12117 			if (listed > 0 || pattern == NULL ||
12118 			    (prop_name_size > 0 &&
12119 			    fnmatch(pattern, search_name,
12120 			    FNM_PATHNAME) == 0))
12121 				list_prop_tmpl(prt, NULL, templates);
12122 			if (prop_name != NULL) {
12123 				free(prop_name);
12124 				prop_name = NULL;
12125 			}
12126 		}
12127 		if (pg_name != NULL) {
12128 			free(pg_name);
12129 			pg_name = NULL;
12130 		}
12131 	}
12132 
12133 	scf_tmpl_prop_destroy(prt);
12134 	scf_tmpl_pg_destroy(pgt);
12135 	free(snapbuf);
12136 	free(fmribuf);
12137 	free(qual_prop_name);
12138 }
12139 
12140 static void
12141 listprop(const char *pattern, int only_pgs, int templates)
12142 {
12143 	scf_propertygroup_t *pg;
12144 	scf_property_t *prop;
12145 	scf_iter_t *iter, *piter;
12146 	char *pgnbuf, *prnbuf, *ppnbuf;
12147 	scf_pg_tmpl_t *pgt, *pgtp;
12148 	scf_prop_tmpl_t *prt;
12149 
12150 	void **objects;
12151 	char **names;
12152 	void **tmpls;
12153 	int allocd, i;
12154 
12155 	int ret;
12156 	ssize_t pgnlen, prnlen, szret;
12157 	size_t max_len = 0;
12158 
12159 	if (cur_svc == NULL && cur_inst == NULL) {
12160 		semerr(emsg_entity_not_selected);
12161 		return;
12162 	}
12163 
12164 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12165 	    (prop = scf_property_create(g_hndl)) == NULL ||
12166 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12167 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12168 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12169 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
12170 		scfdie();
12171 
12172 	prnbuf = safe_malloc(max_scf_name_len + 1);
12173 
12174 	if (cur_level != NULL)
12175 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
12176 	else if (cur_inst != NULL)
12177 		ret = scf_iter_instance_pgs(iter, cur_inst);
12178 	else
12179 		ret = scf_iter_service_pgs(iter, cur_svc);
12180 	if (ret != 0) {
12181 		return;
12182 	}
12183 
12184 	/*
12185 	 * We want to only list items which match pattern, and we want the
12186 	 * second column to line up, so during the first pass we'll save
12187 	 * matching items, their names, and their templates in objects,
12188 	 * names, and tmpls, computing the maximum name length as we go,
12189 	 * and then we'll print them out.
12190 	 *
12191 	 * Note: We always keep an extra slot available so the array can be
12192 	 * NULL-terminated.
12193 	 */
12194 	i = 0;
12195 	allocd = 1;
12196 	objects = safe_malloc(sizeof (*objects));
12197 	names = safe_malloc(sizeof (*names));
12198 	tmpls = safe_malloc(sizeof (*tmpls));
12199 
12200 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12201 		int new_pg = 0;
12202 		int print_props = 0;
12203 		pgtp = NULL;
12204 
12205 		pgnlen = scf_pg_get_name(pg, NULL, 0);
12206 		if (pgnlen < 0)
12207 			scfdie();
12208 
12209 		pgnbuf = safe_malloc(pgnlen + 1);
12210 
12211 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
12212 		if (szret < 0)
12213 			scfdie();
12214 		assert(szret <= pgnlen);
12215 
12216 		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
12217 			if (scf_error() != SCF_ERROR_NOT_FOUND)
12218 				scfdie();
12219 			pgtp = NULL;
12220 		} else {
12221 			pgtp = pgt;
12222 		}
12223 
12224 		if (pattern == NULL ||
12225 		    fnmatch(pattern, pgnbuf, 0) == 0) {
12226 			if (i+1 >= allocd) {
12227 				allocd *= 2;
12228 				objects = realloc(objects,
12229 				    sizeof (*objects) * allocd);
12230 				names =
12231 				    realloc(names, sizeof (*names) * allocd);
12232 				tmpls = realloc(tmpls,
12233 				    sizeof (*tmpls) * allocd);
12234 				if (objects == NULL || names == NULL ||
12235 				    tmpls == NULL)
12236 					uu_die(gettext("Out of memory"));
12237 			}
12238 			objects[i] = pg;
12239 			names[i] = pgnbuf;
12240 
12241 			if (pgtp == NULL)
12242 				tmpls[i] = NULL;
12243 			else
12244 				tmpls[i] = pgt;
12245 
12246 			++i;
12247 
12248 			if (pgnlen > max_len)
12249 				max_len = pgnlen;
12250 
12251 			new_pg = 1;
12252 			print_props = 1;
12253 		}
12254 
12255 		if (only_pgs) {
12256 			if (new_pg) {
12257 				pg = scf_pg_create(g_hndl);
12258 				if (pg == NULL)
12259 					scfdie();
12260 				pgt = scf_tmpl_pg_create(g_hndl);
12261 				if (pgt == NULL)
12262 					scfdie();
12263 			} else
12264 				free(pgnbuf);
12265 
12266 			continue;
12267 		}
12268 
12269 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12270 			scfdie();
12271 
12272 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
12273 			prnlen = scf_property_get_name(prop, prnbuf,
12274 			    max_scf_name_len + 1);
12275 			if (prnlen < 0)
12276 				scfdie();
12277 
12278 			/* Will prepend the property group name and a slash. */
12279 			prnlen += pgnlen + 1;
12280 
12281 			ppnbuf = safe_malloc(prnlen + 1);
12282 
12283 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
12284 			    prnbuf) < 0)
12285 				uu_die("snprintf");
12286 
12287 			if (pattern == NULL || print_props == 1 ||
12288 			    fnmatch(pattern, ppnbuf, 0) == 0) {
12289 				if (i+1 >= allocd) {
12290 					allocd *= 2;
12291 					objects = realloc(objects,
12292 					    sizeof (*objects) * allocd);
12293 					names = realloc(names,
12294 					    sizeof (*names) * allocd);
12295 					tmpls = realloc(tmpls,
12296 					    sizeof (*tmpls) * allocd);
12297 					if (objects == NULL || names == NULL ||
12298 					    tmpls == NULL)
12299 						uu_die(gettext(
12300 						    "Out of memory"));
12301 				}
12302 
12303 				objects[i] = prop;
12304 				names[i] = ppnbuf;
12305 
12306 				if (pgtp != NULL) {
12307 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
12308 					    prt, NULL) < 0) {
12309 						if (scf_error() !=
12310 						    SCF_ERROR_NOT_FOUND)
12311 							scfdie();
12312 						tmpls[i] = NULL;
12313 					} else {
12314 						tmpls[i] = prt;
12315 					}
12316 				} else {
12317 					tmpls[i] = NULL;
12318 				}
12319 
12320 				++i;
12321 
12322 				if (prnlen > max_len)
12323 					max_len = prnlen;
12324 
12325 				prop = scf_property_create(g_hndl);
12326 				prt = scf_tmpl_prop_create(g_hndl);
12327 			} else {
12328 				free(ppnbuf);
12329 			}
12330 		}
12331 
12332 		if (new_pg) {
12333 			pg = scf_pg_create(g_hndl);
12334 			if (pg == NULL)
12335 				scfdie();
12336 			pgt = scf_tmpl_pg_create(g_hndl);
12337 			if (pgt == NULL)
12338 				scfdie();
12339 		} else
12340 			free(pgnbuf);
12341 	}
12342 	if (ret != 0)
12343 		scfdie();
12344 
12345 	objects[i] = NULL;
12346 
12347 	scf_pg_destroy(pg);
12348 	scf_tmpl_pg_destroy(pgt);
12349 	scf_property_destroy(prop);
12350 	scf_tmpl_prop_destroy(prt);
12351 
12352 	for (i = 0; objects[i] != NULL; ++i) {
12353 		if (strchr(names[i], '/') == NULL) {
12354 			/* property group */
12355 			pg = (scf_propertygroup_t *)objects[i];
12356 			pgt = (scf_pg_tmpl_t *)tmpls[i];
12357 			list_pg_info(pg, names[i], max_len);
12358 			list_pg_tmpl(pgt, pg, templates);
12359 			free(names[i]);
12360 			scf_pg_destroy(pg);
12361 			if (pgt != NULL)
12362 				scf_tmpl_pg_destroy(pgt);
12363 		} else {
12364 			/* property */
12365 			prop = (scf_property_t *)objects[i];
12366 			prt = (scf_prop_tmpl_t *)tmpls[i];
12367 			list_prop_info(prop, names[i], max_len);
12368 			list_prop_tmpl(prt, prop, templates);
12369 			free(names[i]);
12370 			scf_property_destroy(prop);
12371 			if (prt != NULL)
12372 				scf_tmpl_prop_destroy(prt);
12373 		}
12374 	}
12375 
12376 	free(names);
12377 	free(objects);
12378 	free(tmpls);
12379 }
12380 
12381 void
12382 lscf_listpg(const char *pattern)
12383 {
12384 	lscf_prep_hndl();
12385 
12386 	listprop(pattern, 1, 0);
12387 }
12388 
12389 /*
12390  * Property group and property creation, setting, and deletion.  setprop (and
12391  * its alias, addprop) can either create a property group of a given type, or
12392  * it can create or set a property to a given type and list of values.
12393  */
12394 void
12395 lscf_addpg(const char *name, const char *type, const char *flags)
12396 {
12397 	scf_propertygroup_t *pg;
12398 	int ret;
12399 	uint32_t flgs = 0;
12400 	const char *cp;
12401 
12402 
12403 	lscf_prep_hndl();
12404 
12405 	if (cur_snap != NULL) {
12406 		semerr(emsg_cant_modify_snapshots);
12407 		return;
12408 	}
12409 
12410 	if (cur_inst == NULL && cur_svc == NULL) {
12411 		semerr(emsg_entity_not_selected);
12412 		return;
12413 	}
12414 
12415 	if (flags != NULL) {
12416 		for (cp = flags; *cp != '\0'; ++cp) {
12417 			switch (*cp) {
12418 			case 'P':
12419 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
12420 				break;
12421 
12422 			case 'p':
12423 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
12424 				break;
12425 
12426 			default:
12427 				semerr(gettext("Invalid property group flag "
12428 				    "%c."), *cp);
12429 				return;
12430 			}
12431 		}
12432 	}
12433 
12434 	pg = scf_pg_create(g_hndl);
12435 	if (pg == NULL)
12436 		scfdie();
12437 
12438 	if (cur_inst != NULL)
12439 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
12440 	else
12441 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
12442 
12443 	if (ret != SCF_SUCCESS) {
12444 		switch (scf_error()) {
12445 		case SCF_ERROR_INVALID_ARGUMENT:
12446 			semerr(gettext("Name, type, or flags are invalid.\n"));
12447 			break;
12448 
12449 		case SCF_ERROR_EXISTS:
12450 			semerr(gettext("Property group already exists.\n"));
12451 			break;
12452 
12453 		case SCF_ERROR_PERMISSION_DENIED:
12454 			semerr(emsg_permission_denied);
12455 			break;
12456 
12457 		case SCF_ERROR_BACKEND_ACCESS:
12458 			semerr(gettext("Backend refused access.\n"));
12459 			break;
12460 
12461 		default:
12462 			scfdie();
12463 		}
12464 	}
12465 
12466 	scf_pg_destroy(pg);
12467 
12468 	private_refresh();
12469 }
12470 
12471 void
12472 lscf_delpg(char *name)
12473 {
12474 	lscf_prep_hndl();
12475 
12476 	if (cur_snap != NULL) {
12477 		semerr(emsg_cant_modify_snapshots);
12478 		return;
12479 	}
12480 
12481 	if (cur_inst == NULL && cur_svc == NULL) {
12482 		semerr(emsg_entity_not_selected);
12483 		return;
12484 	}
12485 
12486 	if (strchr(name, '/') != NULL) {
12487 		semerr(emsg_invalid_pg_name, name);
12488 		return;
12489 	}
12490 
12491 	lscf_delprop(name);
12492 }
12493 
12494 /*
12495  * scf_delhash() is used to remove the property group related to the
12496  * hash entry for a specific manifest in the repository. pgname will be
12497  * constructed from the location of the manifest file. If deathrow isn't 0,
12498  * manifest file doesn't need to exist (manifest string will be used as
12499  * an absolute path).
12500  */
12501 void
12502 lscf_delhash(char *manifest, int deathrow)
12503 {
12504 	char *pgname;
12505 
12506 	if (cur_snap != NULL ||
12507 	    cur_inst != NULL || cur_svc != NULL) {
12508 		warn(gettext("error, an entity is selected\n"));
12509 		return;
12510 	}
12511 
12512 	/* select smf/manifest */
12513 	lscf_select(HASH_SVC);
12514 	/*
12515 	 * Translate the manifest file name to property name. In the deathrow
12516 	 * case, the manifest file does not need to exist.
12517 	 */
12518 	pgname = mhash_filename_to_propname(manifest,
12519 	    deathrow ? B_TRUE : B_FALSE);
12520 	if (pgname == NULL) {
12521 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
12522 		return;
12523 	}
12524 	/* delete the hash property name */
12525 	lscf_delpg(pgname);
12526 }
12527 
12528 void
12529 lscf_listprop(const char *pattern)
12530 {
12531 	lscf_prep_hndl();
12532 
12533 	listprop(pattern, 0, 0);
12534 }
12535 
12536 int
12537 lscf_setprop(const char *pgname, const char *type, const char *value,
12538     const uu_list_t *values)
12539 {
12540 	scf_type_t ty, current_ty;
12541 	scf_service_t *svc;
12542 	scf_propertygroup_t *pg, *parent_pg;
12543 	scf_property_t *prop, *parent_prop;
12544 	scf_pg_tmpl_t *pgt;
12545 	scf_prop_tmpl_t *prt;
12546 	int ret, result = 0;
12547 	scf_transaction_t *tx;
12548 	scf_transaction_entry_t *e;
12549 	scf_value_t *v;
12550 	uu_list_walk_t *walk;
12551 	string_list_t *sp;
12552 	char *propname;
12553 	int req_quotes = 0;
12554 
12555 	lscf_prep_hndl();
12556 
12557 	if ((e = scf_entry_create(g_hndl)) == NULL ||
12558 	    (svc = scf_service_create(g_hndl)) == NULL ||
12559 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
12560 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12561 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
12562 	    (prop = scf_property_create(g_hndl)) == NULL ||
12563 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12564 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12565 	    (tx = scf_transaction_create(g_hndl)) == NULL)
12566 		scfdie();
12567 
12568 	if (cur_snap != NULL) {
12569 		semerr(emsg_cant_modify_snapshots);
12570 		goto fail;
12571 	}
12572 
12573 	if (cur_inst == NULL && cur_svc == NULL) {
12574 		semerr(emsg_entity_not_selected);
12575 		goto fail;
12576 	}
12577 
12578 	propname = strchr(pgname, '/');
12579 	if (propname == NULL) {
12580 		semerr(gettext("Property names must contain a `/'.\n"));
12581 		goto fail;
12582 	}
12583 
12584 	*propname = '\0';
12585 	++propname;
12586 
12587 	if (type != NULL) {
12588 		ty = string_to_type(type);
12589 		if (ty == SCF_TYPE_INVALID) {
12590 			semerr(gettext("Unknown type \"%s\".\n"), type);
12591 			goto fail;
12592 		}
12593 	}
12594 
12595 	if (cur_inst != NULL)
12596 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12597 	else
12598 		ret = scf_service_get_pg(cur_svc, pgname, pg);
12599 	if (ret != SCF_SUCCESS) {
12600 		switch (scf_error()) {
12601 		case SCF_ERROR_NOT_FOUND:
12602 			semerr(emsg_no_such_pg, pgname);
12603 			goto fail;
12604 
12605 		case SCF_ERROR_INVALID_ARGUMENT:
12606 			semerr(emsg_invalid_pg_name, pgname);
12607 			goto fail;
12608 
12609 		default:
12610 			scfdie();
12611 			break;
12612 		}
12613 	}
12614 
12615 	do {
12616 		if (scf_pg_update(pg) == -1)
12617 			scfdie();
12618 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12619 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12620 				scfdie();
12621 
12622 			semerr(emsg_permission_denied);
12623 			goto fail;
12624 		}
12625 
12626 		ret = scf_pg_get_property(pg, propname, prop);
12627 		if (ret == SCF_SUCCESS) {
12628 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
12629 				scfdie();
12630 
12631 			if (type == NULL)
12632 				ty = current_ty;
12633 			if (scf_transaction_property_change_type(tx, e,
12634 			    propname, ty) == -1)
12635 				scfdie();
12636 
12637 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12638 			/* Infer the type, if possible. */
12639 			if (type == NULL) {
12640 				/*
12641 				 * First check if we're an instance and the
12642 				 * property is set on the service.
12643 				 */
12644 				if (cur_inst != NULL &&
12645 				    scf_instance_get_parent(cur_inst,
12646 				    svc) == 0 &&
12647 				    scf_service_get_pg(cur_svc, pgname,
12648 				    parent_pg) == 0 &&
12649 				    scf_pg_get_property(parent_pg, propname,
12650 				    parent_prop) == 0 &&
12651 				    scf_property_type(parent_prop,
12652 				    &current_ty) == 0) {
12653 					ty = current_ty;
12654 
12655 				/* Then check for a type set in a template. */
12656 				} else if (scf_tmpl_get_by_pg(pg, pgt,
12657 				    NULL) == 0 &&
12658 				    scf_tmpl_get_by_prop(pgt, propname, prt,
12659 				    NULL) == 0 &&
12660 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
12661 					ty = current_ty;
12662 
12663 				/* If type can't be inferred, fail. */
12664 				} else {
12665 					semerr(gettext("Type required for new "
12666 					    "properties.\n"));
12667 					goto fail;
12668 				}
12669 			}
12670 			if (scf_transaction_property_new(tx, e, propname,
12671 			    ty) == -1)
12672 				scfdie();
12673 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12674 			semerr(emsg_invalid_prop_name, propname);
12675 			goto fail;
12676 		} else {
12677 			scfdie();
12678 		}
12679 
12680 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
12681 			req_quotes = 1;
12682 
12683 		if (value != NULL) {
12684 			v = string_to_value(value, ty, 0);
12685 
12686 			if (v == NULL)
12687 				goto fail;
12688 
12689 			ret = scf_entry_add_value(e, v);
12690 			assert(ret == SCF_SUCCESS);
12691 		} else {
12692 			assert(values != NULL);
12693 
12694 			walk = uu_list_walk_start((uu_list_t *)values,
12695 			    UU_DEFAULT);
12696 			if (walk == NULL)
12697 				uu_die(gettext("Could not walk list"));
12698 
12699 			for (sp = uu_list_walk_next(walk); sp != NULL;
12700 			    sp = uu_list_walk_next(walk)) {
12701 				v = string_to_value(sp->str, ty, req_quotes);
12702 
12703 				if (v == NULL) {
12704 					scf_entry_destroy_children(e);
12705 					goto fail;
12706 				}
12707 
12708 				ret = scf_entry_add_value(e, v);
12709 				assert(ret == SCF_SUCCESS);
12710 			}
12711 			uu_list_walk_end(walk);
12712 		}
12713 		result = scf_transaction_commit(tx);
12714 
12715 		scf_transaction_reset(tx);
12716 		scf_entry_destroy_children(e);
12717 	} while (result == 0);
12718 
12719 	if (result < 0) {
12720 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12721 			scfdie();
12722 
12723 		semerr(emsg_permission_denied);
12724 		goto fail;
12725 	}
12726 
12727 	ret = 0;
12728 
12729 	private_refresh();
12730 
12731 	goto cleanup;
12732 
12733 fail:
12734 	ret = -1;
12735 
12736 cleanup:
12737 	scf_transaction_destroy(tx);
12738 	scf_entry_destroy(e);
12739 	scf_service_destroy(svc);
12740 	scf_pg_destroy(parent_pg);
12741 	scf_pg_destroy(pg);
12742 	scf_property_destroy(parent_prop);
12743 	scf_property_destroy(prop);
12744 	scf_tmpl_pg_destroy(pgt);
12745 	scf_tmpl_prop_destroy(prt);
12746 
12747 	return (ret);
12748 }
12749 
12750 void
12751 lscf_delprop(char *pgn)
12752 {
12753 	char *slash, *pn;
12754 	scf_propertygroup_t *pg;
12755 	scf_transaction_t *tx;
12756 	scf_transaction_entry_t *e;
12757 	int ret;
12758 
12759 
12760 	lscf_prep_hndl();
12761 
12762 	if (cur_snap != NULL) {
12763 		semerr(emsg_cant_modify_snapshots);
12764 		return;
12765 	}
12766 
12767 	if (cur_inst == NULL && cur_svc == NULL) {
12768 		semerr(emsg_entity_not_selected);
12769 		return;
12770 	}
12771 
12772 	pg = scf_pg_create(g_hndl);
12773 	if (pg == NULL)
12774 		scfdie();
12775 
12776 	slash = strchr(pgn, '/');
12777 	if (slash == NULL) {
12778 		pn = NULL;
12779 	} else {
12780 		*slash = '\0';
12781 		pn = slash + 1;
12782 	}
12783 
12784 	if (cur_inst != NULL)
12785 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
12786 	else
12787 		ret = scf_service_get_pg(cur_svc, pgn, pg);
12788 	if (ret != SCF_SUCCESS) {
12789 		switch (scf_error()) {
12790 		case SCF_ERROR_NOT_FOUND:
12791 			semerr(emsg_no_such_pg, pgn);
12792 			break;
12793 
12794 		case SCF_ERROR_INVALID_ARGUMENT:
12795 			semerr(emsg_invalid_pg_name, pgn);
12796 			break;
12797 
12798 		default:
12799 			scfdie();
12800 		}
12801 
12802 		scf_pg_destroy(pg);
12803 
12804 		return;
12805 	}
12806 
12807 	if (pn == NULL) {
12808 		/* Try to delete the property group. */
12809 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
12810 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12811 				scfdie();
12812 
12813 			semerr(emsg_permission_denied);
12814 		} else {
12815 			private_refresh();
12816 		}
12817 
12818 		scf_pg_destroy(pg);
12819 		return;
12820 	}
12821 
12822 	e = scf_entry_create(g_hndl);
12823 	tx = scf_transaction_create(g_hndl);
12824 
12825 	do {
12826 		if (scf_pg_update(pg) == -1)
12827 			scfdie();
12828 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12829 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12830 				scfdie();
12831 
12832 			semerr(emsg_permission_denied);
12833 			break;
12834 		}
12835 
12836 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
12837 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
12838 				semerr(gettext("No such property %s/%s.\n"),
12839 				    pgn, pn);
12840 				break;
12841 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12842 				semerr(emsg_invalid_prop_name, pn);
12843 				break;
12844 			} else {
12845 				scfdie();
12846 			}
12847 		}
12848 
12849 		ret = scf_transaction_commit(tx);
12850 
12851 		if (ret == 0)
12852 			scf_transaction_reset(tx);
12853 	} while (ret == 0);
12854 
12855 	if (ret < 0) {
12856 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12857 			scfdie();
12858 
12859 		semerr(emsg_permission_denied);
12860 	} else {
12861 		private_refresh();
12862 	}
12863 
12864 	scf_transaction_destroy(tx);
12865 	scf_entry_destroy(e);
12866 	scf_pg_destroy(pg);
12867 }
12868 
12869 /*
12870  * Property editing.
12871  */
12872 
12873 static int
12874 write_edit_script(FILE *strm)
12875 {
12876 	char *fmribuf;
12877 	ssize_t fmrilen;
12878 
12879 	scf_propertygroup_t *pg;
12880 	scf_property_t *prop;
12881 	scf_value_t *val;
12882 	scf_type_t ty;
12883 	int ret, result = 0;
12884 	scf_iter_t *iter, *piter, *viter;
12885 	char *buf, *tybuf, *pname;
12886 	const char *emsg_write_error;
12887 
12888 
12889 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
12890 
12891 
12892 	/* select fmri */
12893 	if (cur_inst != NULL) {
12894 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
12895 		if (fmrilen < 0)
12896 			scfdie();
12897 		fmribuf = safe_malloc(fmrilen + 1);
12898 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
12899 			scfdie();
12900 	} else {
12901 		assert(cur_svc != NULL);
12902 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
12903 		if (fmrilen < 0)
12904 			scfdie();
12905 		fmribuf = safe_malloc(fmrilen + 1);
12906 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
12907 			scfdie();
12908 	}
12909 
12910 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
12911 		warn(emsg_write_error, strerror(errno));
12912 		free(fmribuf);
12913 		return (-1);
12914 	}
12915 
12916 	free(fmribuf);
12917 
12918 
12919 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12920 	    (prop = scf_property_create(g_hndl)) == NULL ||
12921 	    (val = scf_value_create(g_hndl)) == NULL ||
12922 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12923 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12924 	    (viter = scf_iter_create(g_hndl)) == NULL)
12925 		scfdie();
12926 
12927 	buf = safe_malloc(max_scf_name_len + 1);
12928 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
12929 	pname = safe_malloc(max_scf_name_len + 1);
12930 
12931 	if (cur_inst != NULL)
12932 		ret = scf_iter_instance_pgs(iter, cur_inst);
12933 	else
12934 		ret = scf_iter_service_pgs(iter, cur_svc);
12935 	if (ret != SCF_SUCCESS)
12936 		scfdie();
12937 
12938 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12939 		int ret2;
12940 
12941 		/*
12942 		 * # delprop pg
12943 		 * # addpg pg type
12944 		 */
12945 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
12946 			scfdie();
12947 
12948 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
12949 			scfdie();
12950 
12951 		if (fprintf(strm, "# Property group \"%s\"\n"
12952 		    "# delprop %s\n"
12953 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
12954 			warn(emsg_write_error, strerror(errno));
12955 			result = -1;
12956 			goto out;
12957 		}
12958 
12959 		/* # setprop pg/prop = (values) */
12960 
12961 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12962 			scfdie();
12963 
12964 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
12965 			int first = 1;
12966 			int ret3;
12967 			int multiple;
12968 			int is_str;
12969 			scf_type_t bty;
12970 
12971 			if (scf_property_get_name(prop, pname,
12972 			    max_scf_name_len + 1) < 0)
12973 				scfdie();
12974 
12975 			if (scf_property_type(prop, &ty) != 0)
12976 				scfdie();
12977 
12978 			multiple = prop_has_multiple_values(prop, val);
12979 
12980 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
12981 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
12982 			    < 0) {
12983 				warn(emsg_write_error, strerror(errno));
12984 				result = -1;
12985 				goto out;
12986 			}
12987 
12988 			(void) scf_type_base_type(ty, &bty);
12989 			is_str = (bty == SCF_TYPE_ASTRING);
12990 
12991 			if (scf_iter_property_values(viter, prop) !=
12992 			    SCF_SUCCESS)
12993 				scfdie();
12994 
12995 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
12996 				char *buf;
12997 				ssize_t buflen;
12998 
12999 				buflen = scf_value_get_as_string(val, NULL, 0);
13000 				if (buflen < 0)
13001 					scfdie();
13002 
13003 				buf = safe_malloc(buflen + 1);
13004 
13005 				if (scf_value_get_as_string(val, buf,
13006 				    buflen + 1) < 0)
13007 					scfdie();
13008 
13009 				if (first)
13010 					first = 0;
13011 				else {
13012 					if (putc(' ', strm) != ' ') {
13013 						warn(emsg_write_error,
13014 						    strerror(errno));
13015 						result = -1;
13016 						goto out;
13017 					}
13018 				}
13019 
13020 				if ((is_str && multiple) ||
13021 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
13022 					(void) putc('"', strm);
13023 					(void) quote_and_print(buf, strm, 1);
13024 					(void) putc('"', strm);
13025 
13026 					if (ferror(strm)) {
13027 						warn(emsg_write_error,
13028 						    strerror(errno));
13029 						result = -1;
13030 						goto out;
13031 					}
13032 				} else {
13033 					if (fprintf(strm, "%s", buf) < 0) {
13034 						warn(emsg_write_error,
13035 						    strerror(errno));
13036 						result = -1;
13037 						goto out;
13038 					}
13039 				}
13040 
13041 				free(buf);
13042 			}
13043 			if (ret3 < 0 &&
13044 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
13045 				scfdie();
13046 
13047 			/* Write closing paren if mult-value property */
13048 			if ((multiple && putc(')', strm) == EOF) ||
13049 
13050 			    /* Write final newline */
13051 			    fputc('\n', strm) == EOF) {
13052 				warn(emsg_write_error, strerror(errno));
13053 				result = -1;
13054 				goto out;
13055 			}
13056 		}
13057 		if (ret2 < 0)
13058 			scfdie();
13059 
13060 		if (fputc('\n', strm) == EOF) {
13061 			warn(emsg_write_error, strerror(errno));
13062 			result = -1;
13063 			goto out;
13064 		}
13065 	}
13066 	if (ret < 0)
13067 		scfdie();
13068 
13069 out:
13070 	free(pname);
13071 	free(tybuf);
13072 	free(buf);
13073 	scf_iter_destroy(viter);
13074 	scf_iter_destroy(piter);
13075 	scf_iter_destroy(iter);
13076 	scf_value_destroy(val);
13077 	scf_property_destroy(prop);
13078 	scf_pg_destroy(pg);
13079 
13080 	if (result == 0) {
13081 		if (fflush(strm) != 0) {
13082 			warn(emsg_write_error, strerror(errno));
13083 			return (-1);
13084 		}
13085 	}
13086 
13087 	return (result);
13088 }
13089 
13090 int
13091 lscf_editprop()
13092 {
13093 	char *buf, *editor;
13094 	size_t bufsz;
13095 	int tmpfd;
13096 	char tempname[] = TEMP_FILE_PATTERN;
13097 
13098 	lscf_prep_hndl();
13099 
13100 	if (cur_snap != NULL) {
13101 		semerr(emsg_cant_modify_snapshots);
13102 		return (-1);
13103 	}
13104 
13105 	if (cur_svc == NULL && cur_inst == NULL) {
13106 		semerr(emsg_entity_not_selected);
13107 		return (-1);
13108 	}
13109 
13110 	tmpfd = mkstemp(tempname);
13111 	if (tmpfd == -1) {
13112 		semerr(gettext("Could not create temporary file.\n"));
13113 		return (-1);
13114 	}
13115 
13116 	(void) strcpy(tempfilename, tempname);
13117 
13118 	tempfile = fdopen(tmpfd, "r+");
13119 	if (tempfile == NULL) {
13120 		warn(gettext("Could not create temporary file.\n"));
13121 		if (close(tmpfd) == -1)
13122 			warn(gettext("Could not close temporary file: %s.\n"),
13123 			    strerror(errno));
13124 
13125 		remove_tempfile();
13126 
13127 		return (-1);
13128 	}
13129 
13130 	if (write_edit_script(tempfile) == -1) {
13131 		remove_tempfile();
13132 		return (-1);
13133 	}
13134 
13135 	editor = getenv("EDITOR");
13136 	if (editor == NULL)
13137 		editor = "vi";
13138 
13139 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
13140 	buf = safe_malloc(bufsz);
13141 
13142 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
13143 		uu_die(gettext("Error creating editor command"));
13144 
13145 	if (system(buf) == -1) {
13146 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
13147 		    strerror(errno));
13148 		free(buf);
13149 		remove_tempfile();
13150 		return (-1);
13151 	}
13152 
13153 	free(buf);
13154 
13155 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
13156 
13157 	remove_tempfile();
13158 
13159 	return (0);
13160 }
13161 
13162 static void
13163 add_string(uu_list_t *strlist, const char *str)
13164 {
13165 	string_list_t *elem;
13166 	elem = safe_malloc(sizeof (*elem));
13167 	uu_list_node_init(elem, &elem->node, string_pool);
13168 	elem->str = safe_strdup(str);
13169 	if (uu_list_append(strlist, elem) != 0)
13170 		uu_die(gettext("libuutil error: %s\n"),
13171 		    uu_strerror(uu_error()));
13172 }
13173 
13174 static int
13175 remove_string(uu_list_t *strlist, const char *str)
13176 {
13177 	uu_list_walk_t	*elems;
13178 	string_list_t	*sp;
13179 
13180 	/*
13181 	 * Find the element that needs to be removed.
13182 	 */
13183 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
13184 	while ((sp = uu_list_walk_next(elems)) != NULL) {
13185 		if (strcmp(sp->str, str) == 0)
13186 			break;
13187 	}
13188 	uu_list_walk_end(elems);
13189 
13190 	/*
13191 	 * Returning 1 here as the value was not found, this
13192 	 * might not be an error.  Leave it to the caller to
13193 	 * decide.
13194 	 */
13195 	if (sp == NULL) {
13196 		return (1);
13197 	}
13198 
13199 	uu_list_remove(strlist, sp);
13200 
13201 	free(sp->str);
13202 	free(sp);
13203 
13204 	return (0);
13205 }
13206 
13207 /*
13208  * Get all property values that don't match the given glob pattern,
13209  * if a pattern is specified.
13210  */
13211 static void
13212 get_prop_values(scf_property_t *prop, uu_list_t *values,
13213     const char *pattern)
13214 {
13215 	scf_iter_t *iter;
13216 	scf_value_t *val;
13217 	int ret;
13218 
13219 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13220 	    (val = scf_value_create(g_hndl)) == NULL)
13221 		scfdie();
13222 
13223 	if (scf_iter_property_values(iter, prop) != 0)
13224 		scfdie();
13225 
13226 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13227 		char *buf;
13228 		ssize_t vlen, szret;
13229 
13230 		vlen = scf_value_get_as_string(val, NULL, 0);
13231 		if (vlen < 0)
13232 			scfdie();
13233 
13234 		buf = safe_malloc(vlen + 1);
13235 
13236 		szret = scf_value_get_as_string(val, buf, vlen + 1);
13237 		if (szret < 0)
13238 			scfdie();
13239 		assert(szret <= vlen);
13240 
13241 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
13242 			add_string(values, buf);
13243 
13244 		free(buf);
13245 	}
13246 
13247 	if (ret == -1)
13248 		scfdie();
13249 
13250 	scf_value_destroy(val);
13251 	scf_iter_destroy(iter);
13252 }
13253 
13254 static int
13255 lscf_setpropvalue(const char *pgname, const char *type,
13256     const char *arg, int isadd, int isnotfoundok)
13257 {
13258 	scf_type_t ty;
13259 	scf_propertygroup_t *pg;
13260 	scf_property_t *prop;
13261 	int ret, result = 0;
13262 	scf_transaction_t *tx;
13263 	scf_transaction_entry_t *e;
13264 	scf_value_t *v;
13265 	string_list_t *sp;
13266 	char *propname;
13267 	uu_list_t *values;
13268 	uu_list_walk_t *walk;
13269 	void *cookie = NULL;
13270 	char *pattern = NULL;
13271 
13272 	lscf_prep_hndl();
13273 
13274 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
13275 		uu_die(gettext("Could not create property list: %s\n"),
13276 		    uu_strerror(uu_error()));
13277 
13278 	if (!isadd)
13279 		pattern = safe_strdup(arg);
13280 
13281 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13282 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13283 	    (prop = scf_property_create(g_hndl)) == NULL ||
13284 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13285 		scfdie();
13286 
13287 	if (cur_snap != NULL) {
13288 		semerr(emsg_cant_modify_snapshots);
13289 		goto fail;
13290 	}
13291 
13292 	if (cur_inst == NULL && cur_svc == NULL) {
13293 		semerr(emsg_entity_not_selected);
13294 		goto fail;
13295 	}
13296 
13297 	propname = strchr(pgname, '/');
13298 	if (propname == NULL) {
13299 		semerr(gettext("Property names must contain a `/'.\n"));
13300 		goto fail;
13301 	}
13302 
13303 	*propname = '\0';
13304 	++propname;
13305 
13306 	if (type != NULL) {
13307 		ty = string_to_type(type);
13308 		if (ty == SCF_TYPE_INVALID) {
13309 			semerr(gettext("Unknown type \"%s\".\n"), type);
13310 			goto fail;
13311 		}
13312 	}
13313 
13314 	if (cur_inst != NULL)
13315 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13316 	else
13317 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13318 	if (ret != 0) {
13319 		switch (scf_error()) {
13320 		case SCF_ERROR_NOT_FOUND:
13321 			if (isnotfoundok) {
13322 				result = 0;
13323 			} else {
13324 				semerr(emsg_no_such_pg, pgname);
13325 				result = -1;
13326 			}
13327 			goto out;
13328 
13329 		case SCF_ERROR_INVALID_ARGUMENT:
13330 			semerr(emsg_invalid_pg_name, pgname);
13331 			goto fail;
13332 
13333 		default:
13334 			scfdie();
13335 		}
13336 	}
13337 
13338 	do {
13339 		if (scf_pg_update(pg) == -1)
13340 			scfdie();
13341 		if (scf_transaction_start(tx, pg) != 0) {
13342 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13343 				scfdie();
13344 
13345 			semerr(emsg_permission_denied);
13346 			goto fail;
13347 		}
13348 
13349 		ret = scf_pg_get_property(pg, propname, prop);
13350 		if (ret == 0) {
13351 			scf_type_t ptype;
13352 			char *pat = pattern;
13353 
13354 			if (scf_property_type(prop, &ptype) != 0)
13355 				scfdie();
13356 
13357 			if (isadd) {
13358 				if (type != NULL && ptype != ty) {
13359 					semerr(gettext("Property \"%s\" is not "
13360 					    "of type \"%s\".\n"), propname,
13361 					    type);
13362 					goto fail;
13363 				}
13364 
13365 				pat = NULL;
13366 			} else {
13367 				size_t len = strlen(pat);
13368 				if (len > 0 && pat[len - 1] == '\"')
13369 					pat[len - 1] = '\0';
13370 				if (len > 0 && pat[0] == '\"')
13371 					pat++;
13372 			}
13373 
13374 			ty = ptype;
13375 
13376 			get_prop_values(prop, values, pat);
13377 
13378 			if (isadd)
13379 				add_string(values, arg);
13380 
13381 			if (scf_transaction_property_change(tx, e,
13382 			    propname, ty) == -1)
13383 				scfdie();
13384 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13385 			if (isadd) {
13386 				if (type == NULL) {
13387 					semerr(gettext("Type required "
13388 					    "for new properties.\n"));
13389 					goto fail;
13390 				}
13391 
13392 				add_string(values, arg);
13393 
13394 				if (scf_transaction_property_new(tx, e,
13395 				    propname, ty) == -1)
13396 					scfdie();
13397 			} else if (isnotfoundok) {
13398 				result = 0;
13399 				goto out;
13400 			} else {
13401 				semerr(gettext("No such property %s/%s.\n"),
13402 				    pgname, propname);
13403 				result = -1;
13404 				goto out;
13405 			}
13406 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13407 			semerr(emsg_invalid_prop_name, propname);
13408 			goto fail;
13409 		} else {
13410 			scfdie();
13411 		}
13412 
13413 		walk = uu_list_walk_start(values, UU_DEFAULT);
13414 		if (walk == NULL)
13415 			uu_die(gettext("Could not walk property list.\n"));
13416 
13417 		for (sp = uu_list_walk_next(walk); sp != NULL;
13418 		    sp = uu_list_walk_next(walk)) {
13419 			v = string_to_value(sp->str, ty, 0);
13420 
13421 			if (v == NULL) {
13422 				scf_entry_destroy_children(e);
13423 				goto fail;
13424 			}
13425 			ret = scf_entry_add_value(e, v);
13426 			assert(ret == 0);
13427 		}
13428 		uu_list_walk_end(walk);
13429 
13430 		result = scf_transaction_commit(tx);
13431 
13432 		scf_transaction_reset(tx);
13433 		scf_entry_destroy_children(e);
13434 	} while (result == 0);
13435 
13436 	if (result < 0) {
13437 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13438 			scfdie();
13439 
13440 		semerr(emsg_permission_denied);
13441 		goto fail;
13442 	}
13443 
13444 	result = 0;
13445 
13446 	private_refresh();
13447 
13448 out:
13449 	scf_transaction_destroy(tx);
13450 	scf_entry_destroy(e);
13451 	scf_pg_destroy(pg);
13452 	scf_property_destroy(prop);
13453 	free(pattern);
13454 
13455 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
13456 		free(sp->str);
13457 		free(sp);
13458 	}
13459 
13460 	uu_list_destroy(values);
13461 
13462 	return (result);
13463 
13464 fail:
13465 	result = -1;
13466 	goto out;
13467 }
13468 
13469 int
13470 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
13471 {
13472 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
13473 }
13474 
13475 int
13476 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
13477 {
13478 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
13479 }
13480 
13481 /*
13482  * Look for a standard start method, first in the instance (if any),
13483  * then the service.
13484  */
13485 static const char *
13486 start_method_name(int *in_instance)
13487 {
13488 	scf_propertygroup_t *pg;
13489 	char **p;
13490 	int ret;
13491 	scf_instance_t *inst = cur_inst;
13492 
13493 	if ((pg = scf_pg_create(g_hndl)) == NULL)
13494 		scfdie();
13495 
13496 again:
13497 	for (p = start_method_names; *p != NULL; p++) {
13498 		if (inst != NULL)
13499 			ret = scf_instance_get_pg(inst, *p, pg);
13500 		else
13501 			ret = scf_service_get_pg(cur_svc, *p, pg);
13502 
13503 		if (ret == 0) {
13504 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
13505 			char *buf = safe_malloc(bufsz);
13506 
13507 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
13508 				free(buf);
13509 				continue;
13510 			}
13511 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
13512 				free(buf);
13513 				continue;
13514 			}
13515 
13516 			free(buf);
13517 			*in_instance = (inst != NULL);
13518 			scf_pg_destroy(pg);
13519 			return (*p);
13520 		}
13521 
13522 		if (scf_error() == SCF_ERROR_NOT_FOUND)
13523 			continue;
13524 
13525 		scfdie();
13526 	}
13527 
13528 	if (inst != NULL) {
13529 		inst = NULL;
13530 		goto again;
13531 	}
13532 
13533 	scf_pg_destroy(pg);
13534 	return (NULL);
13535 }
13536 
13537 static int
13538 addpg(const char *name, const char *type)
13539 {
13540 	scf_propertygroup_t *pg;
13541 	int ret;
13542 
13543 	pg = scf_pg_create(g_hndl);
13544 	if (pg == NULL)
13545 		scfdie();
13546 
13547 	if (cur_inst != NULL)
13548 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
13549 	else
13550 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
13551 
13552 	if (ret != 0) {
13553 		switch (scf_error()) {
13554 		case SCF_ERROR_EXISTS:
13555 			ret = 0;
13556 			break;
13557 
13558 		case SCF_ERROR_PERMISSION_DENIED:
13559 			semerr(emsg_permission_denied);
13560 			break;
13561 
13562 		default:
13563 			scfdie();
13564 		}
13565 	}
13566 
13567 	scf_pg_destroy(pg);
13568 	return (ret);
13569 }
13570 
13571 int
13572 lscf_setenv(uu_list_t *args, int isunset)
13573 {
13574 	int ret = 0;
13575 	size_t i;
13576 	int argc;
13577 	char **argv = NULL;
13578 	string_list_t *slp;
13579 	char *pattern;
13580 	char *prop;
13581 	int do_service = 0;
13582 	int do_instance = 0;
13583 	const char *method = NULL;
13584 	const char *name = NULL;
13585 	const char *value = NULL;
13586 	scf_instance_t *saved_cur_inst = cur_inst;
13587 
13588 	lscf_prep_hndl();
13589 
13590 	argc = uu_list_numnodes(args);
13591 	if (argc < 1)
13592 		goto usage;
13593 
13594 	argv = calloc(argc + 1, sizeof (char *));
13595 	if (argv == NULL)
13596 		uu_die(gettext("Out of memory.\n"));
13597 
13598 	for (slp = uu_list_first(args), i = 0;
13599 	    slp != NULL;
13600 	    slp = uu_list_next(args, slp), ++i)
13601 		argv[i] = slp->str;
13602 
13603 	argv[i] = NULL;
13604 
13605 	opterr = 0;
13606 	optind = 0;
13607 	for (;;) {
13608 		ret = getopt(argc, argv, "sim:");
13609 		if (ret == -1)
13610 			break;
13611 
13612 		switch (ret) {
13613 		case 's':
13614 			do_service = 1;
13615 			cur_inst = NULL;
13616 			break;
13617 
13618 		case 'i':
13619 			do_instance = 1;
13620 			break;
13621 
13622 		case 'm':
13623 			method = optarg;
13624 			break;
13625 
13626 		case '?':
13627 			goto usage;
13628 
13629 		default:
13630 			bad_error("getopt", ret);
13631 		}
13632 	}
13633 
13634 	argc -= optind;
13635 	if ((do_service && do_instance) ||
13636 	    (isunset && argc != 1) ||
13637 	    (!isunset && argc != 2))
13638 		goto usage;
13639 
13640 	name = argv[optind];
13641 	if (!isunset)
13642 		value = argv[optind + 1];
13643 
13644 	if (cur_snap != NULL) {
13645 		semerr(emsg_cant_modify_snapshots);
13646 		ret = -1;
13647 		goto out;
13648 	}
13649 
13650 	if (cur_inst == NULL && cur_svc == NULL) {
13651 		semerr(emsg_entity_not_selected);
13652 		ret = -1;
13653 		goto out;
13654 	}
13655 
13656 	if (do_instance && cur_inst == NULL) {
13657 		semerr(gettext("No instance is selected.\n"));
13658 		ret = -1;
13659 		goto out;
13660 	}
13661 
13662 	if (do_service && cur_svc == NULL) {
13663 		semerr(gettext("No service is selected.\n"));
13664 		ret = -1;
13665 		goto out;
13666 	}
13667 
13668 	if (method == NULL) {
13669 		if (do_instance || do_service) {
13670 			method = "method_context";
13671 			if (!isunset) {
13672 				ret = addpg("method_context",
13673 				    SCF_GROUP_FRAMEWORK);
13674 				if (ret != 0)
13675 					goto out;
13676 			}
13677 		} else {
13678 			int in_instance;
13679 			method = start_method_name(&in_instance);
13680 			if (method == NULL) {
13681 				semerr(gettext(
13682 				    "Couldn't find start method; please "
13683 				    "specify a method with '-m'.\n"));
13684 				ret = -1;
13685 				goto out;
13686 			}
13687 			if (!in_instance)
13688 				cur_inst = NULL;
13689 		}
13690 	} else {
13691 		scf_propertygroup_t *pg;
13692 		size_t bufsz;
13693 		char *buf;
13694 		int ret;
13695 
13696 		if ((pg = scf_pg_create(g_hndl)) == NULL)
13697 			scfdie();
13698 
13699 		if (cur_inst != NULL)
13700 			ret = scf_instance_get_pg(cur_inst, method, pg);
13701 		else
13702 			ret = scf_service_get_pg(cur_svc, method, pg);
13703 
13704 		if (ret != 0) {
13705 			scf_pg_destroy(pg);
13706 			switch (scf_error()) {
13707 			case SCF_ERROR_NOT_FOUND:
13708 				semerr(gettext("Couldn't find the method "
13709 				    "\"%s\".\n"), method);
13710 				goto out;
13711 
13712 			case SCF_ERROR_INVALID_ARGUMENT:
13713 				semerr(gettext("Invalid method name \"%s\".\n"),
13714 				    method);
13715 				goto out;
13716 
13717 			default:
13718 				scfdie();
13719 			}
13720 		}
13721 
13722 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
13723 		buf = safe_malloc(bufsz);
13724 
13725 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
13726 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
13727 			semerr(gettext("Property group \"%s\" is not of type "
13728 			    "\"method\".\n"), method);
13729 			ret = -1;
13730 			free(buf);
13731 			scf_pg_destroy(pg);
13732 			goto out;
13733 		}
13734 
13735 		free(buf);
13736 		scf_pg_destroy(pg);
13737 	}
13738 
13739 	prop = uu_msprintf("%s/environment", method);
13740 	pattern = uu_msprintf("%s=*", name);
13741 
13742 	if (prop == NULL || pattern == NULL)
13743 		uu_die(gettext("Out of memory.\n"));
13744 
13745 	ret = lscf_delpropvalue(prop, pattern, !isunset);
13746 
13747 	if (ret == 0 && !isunset) {
13748 		uu_free(pattern);
13749 		uu_free(prop);
13750 		prop = uu_msprintf("%s/environment", method);
13751 		pattern = uu_msprintf("%s=%s", name, value);
13752 		if (prop == NULL || pattern == NULL)
13753 			uu_die(gettext("Out of memory.\n"));
13754 		ret = lscf_addpropvalue(prop, "astring:", pattern);
13755 	}
13756 	uu_free(pattern);
13757 	uu_free(prop);
13758 
13759 out:
13760 	cur_inst = saved_cur_inst;
13761 
13762 	free(argv);
13763 	return (ret);
13764 usage:
13765 	ret = -2;
13766 	goto out;
13767 }
13768 
13769 /*
13770  * Snapshot commands
13771  */
13772 
13773 void
13774 lscf_listsnap()
13775 {
13776 	scf_snapshot_t *snap;
13777 	scf_iter_t *iter;
13778 	char *nb;
13779 	int r;
13780 
13781 	lscf_prep_hndl();
13782 
13783 	if (cur_inst == NULL) {
13784 		semerr(gettext("Instance not selected.\n"));
13785 		return;
13786 	}
13787 
13788 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13789 	    (iter = scf_iter_create(g_hndl)) == NULL)
13790 		scfdie();
13791 
13792 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
13793 		scfdie();
13794 
13795 	nb = safe_malloc(max_scf_name_len + 1);
13796 
13797 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
13798 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
13799 			scfdie();
13800 
13801 		(void) puts(nb);
13802 	}
13803 	if (r < 0)
13804 		scfdie();
13805 
13806 	free(nb);
13807 	scf_iter_destroy(iter);
13808 	scf_snapshot_destroy(snap);
13809 }
13810 
13811 void
13812 lscf_selectsnap(const char *name)
13813 {
13814 	scf_snapshot_t *snap;
13815 	scf_snaplevel_t *level;
13816 
13817 	lscf_prep_hndl();
13818 
13819 	if (cur_inst == NULL) {
13820 		semerr(gettext("Instance not selected.\n"));
13821 		return;
13822 	}
13823 
13824 	if (cur_snap != NULL) {
13825 		if (name != NULL) {
13826 			char *cur_snap_name;
13827 			boolean_t nochange;
13828 
13829 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
13830 
13831 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
13832 			    max_scf_name_len + 1) < 0)
13833 				scfdie();
13834 
13835 			nochange = strcmp(name, cur_snap_name) == 0;
13836 
13837 			free(cur_snap_name);
13838 
13839 			if (nochange)
13840 				return;
13841 		}
13842 
13843 		unselect_cursnap();
13844 	}
13845 
13846 	if (name == NULL)
13847 		return;
13848 
13849 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13850 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
13851 		scfdie();
13852 
13853 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
13854 	    SCF_SUCCESS) {
13855 		switch (scf_error()) {
13856 		case SCF_ERROR_INVALID_ARGUMENT:
13857 			semerr(gettext("Invalid name \"%s\".\n"), name);
13858 			break;
13859 
13860 		case SCF_ERROR_NOT_FOUND:
13861 			semerr(gettext("No such snapshot \"%s\".\n"), name);
13862 			break;
13863 
13864 		default:
13865 			scfdie();
13866 		}
13867 
13868 		scf_snaplevel_destroy(level);
13869 		scf_snapshot_destroy(snap);
13870 		return;
13871 	}
13872 
13873 	/* Load the snaplevels into our list. */
13874 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
13875 	if (cur_levels == NULL)
13876 		uu_die(gettext("Could not create list: %s\n"),
13877 		    uu_strerror(uu_error()));
13878 
13879 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13880 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13881 			scfdie();
13882 
13883 		semerr(gettext("Snapshot has no snaplevels.\n"));
13884 
13885 		scf_snaplevel_destroy(level);
13886 		scf_snapshot_destroy(snap);
13887 		return;
13888 	}
13889 
13890 	cur_snap = snap;
13891 
13892 	for (;;) {
13893 		cur_elt = safe_malloc(sizeof (*cur_elt));
13894 		uu_list_node_init(cur_elt, &cur_elt->list_node,
13895 		    snaplevel_pool);
13896 		cur_elt->sl = level;
13897 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
13898 			uu_die(gettext("libuutil error: %s\n"),
13899 			    uu_strerror(uu_error()));
13900 
13901 		level = scf_snaplevel_create(g_hndl);
13902 		if (level == NULL)
13903 			scfdie();
13904 
13905 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
13906 		    level) != SCF_SUCCESS) {
13907 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13908 				scfdie();
13909 
13910 			scf_snaplevel_destroy(level);
13911 			break;
13912 		}
13913 	}
13914 
13915 	cur_elt = uu_list_last(cur_levels);
13916 	cur_level = cur_elt->sl;
13917 }
13918 
13919 /*
13920  * Copies the properties & values in src to dst.  Assumes src won't change.
13921  * Returns -1 if permission is denied, -2 if another transaction interrupts,
13922  * and 0 on success.
13923  *
13924  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
13925  * property, if it is copied and has type boolean.  (See comment in
13926  * lscf_revert()).
13927  */
13928 static int
13929 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
13930     uint8_t enabled)
13931 {
13932 	scf_transaction_t *tx;
13933 	scf_iter_t *iter, *viter;
13934 	scf_property_t *prop;
13935 	scf_value_t *v;
13936 	char *nbuf;
13937 	int r;
13938 
13939 	tx = scf_transaction_create(g_hndl);
13940 	if (tx == NULL)
13941 		scfdie();
13942 
13943 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
13944 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13945 			scfdie();
13946 
13947 		scf_transaction_destroy(tx);
13948 
13949 		return (-1);
13950 	}
13951 
13952 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13953 	    (prop = scf_property_create(g_hndl)) == NULL ||
13954 	    (viter = scf_iter_create(g_hndl)) == NULL)
13955 		scfdie();
13956 
13957 	nbuf = safe_malloc(max_scf_name_len + 1);
13958 
13959 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
13960 		scfdie();
13961 
13962 	for (;;) {
13963 		scf_transaction_entry_t *e;
13964 		scf_type_t ty;
13965 
13966 		r = scf_iter_next_property(iter, prop);
13967 		if (r == -1)
13968 			scfdie();
13969 		if (r == 0)
13970 			break;
13971 
13972 		e = scf_entry_create(g_hndl);
13973 		if (e == NULL)
13974 			scfdie();
13975 
13976 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
13977 			scfdie();
13978 
13979 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
13980 			scfdie();
13981 
13982 		if (scf_transaction_property_new(tx, e, nbuf,
13983 		    ty) != SCF_SUCCESS)
13984 			scfdie();
13985 
13986 		if ((enabled == 0 || enabled == 1) &&
13987 		    strcmp(nbuf, scf_property_enabled) == 0 &&
13988 		    ty == SCF_TYPE_BOOLEAN) {
13989 			v = scf_value_create(g_hndl);
13990 			if (v == NULL)
13991 				scfdie();
13992 
13993 			scf_value_set_boolean(v, enabled);
13994 
13995 			if (scf_entry_add_value(e, v) != 0)
13996 				scfdie();
13997 		} else {
13998 			if (scf_iter_property_values(viter, prop) != 0)
13999 				scfdie();
14000 
14001 			for (;;) {
14002 				v = scf_value_create(g_hndl);
14003 				if (v == NULL)
14004 					scfdie();
14005 
14006 				r = scf_iter_next_value(viter, v);
14007 				if (r == -1)
14008 					scfdie();
14009 				if (r == 0) {
14010 					scf_value_destroy(v);
14011 					break;
14012 				}
14013 
14014 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14015 					scfdie();
14016 			}
14017 		}
14018 	}
14019 
14020 	free(nbuf);
14021 	scf_iter_destroy(viter);
14022 	scf_property_destroy(prop);
14023 	scf_iter_destroy(iter);
14024 
14025 	r = scf_transaction_commit(tx);
14026 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
14027 		scfdie();
14028 
14029 	scf_transaction_destroy_children(tx);
14030 	scf_transaction_destroy(tx);
14031 
14032 	switch (r) {
14033 	case 1:		return (0);
14034 	case 0:		return (-2);
14035 	case -1:	return (-1);
14036 
14037 	default:
14038 		abort();
14039 	}
14040 
14041 	/* NOTREACHED */
14042 }
14043 
14044 void
14045 lscf_revert(const char *snapname)
14046 {
14047 	scf_snapshot_t *snap, *prev;
14048 	scf_snaplevel_t *level, *nlevel;
14049 	scf_iter_t *iter;
14050 	scf_propertygroup_t *pg, *npg;
14051 	scf_property_t *prop;
14052 	scf_value_t *val;
14053 	char *nbuf, *tbuf;
14054 	uint8_t enabled;
14055 
14056 	lscf_prep_hndl();
14057 
14058 	if (cur_inst == NULL) {
14059 		semerr(gettext("Instance not selected.\n"));
14060 		return;
14061 	}
14062 
14063 	if (snapname != NULL) {
14064 		snap = scf_snapshot_create(g_hndl);
14065 		if (snap == NULL)
14066 			scfdie();
14067 
14068 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
14069 		    SCF_SUCCESS) {
14070 			switch (scf_error()) {
14071 			case SCF_ERROR_INVALID_ARGUMENT:
14072 				semerr(gettext("Invalid snapshot name "
14073 				    "\"%s\".\n"), snapname);
14074 				break;
14075 
14076 			case SCF_ERROR_NOT_FOUND:
14077 				semerr(gettext("No such snapshot.\n"));
14078 				break;
14079 
14080 			default:
14081 				scfdie();
14082 			}
14083 
14084 			scf_snapshot_destroy(snap);
14085 			return;
14086 		}
14087 	} else {
14088 		if (cur_snap != NULL) {
14089 			snap = cur_snap;
14090 		} else {
14091 			semerr(gettext("No snapshot selected.\n"));
14092 			return;
14093 		}
14094 	}
14095 
14096 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
14097 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
14098 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14099 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14100 	    (npg = scf_pg_create(g_hndl)) == NULL ||
14101 	    (prop = scf_property_create(g_hndl)) == NULL ||
14102 	    (val = scf_value_create(g_hndl)) == NULL)
14103 		scfdie();
14104 
14105 	nbuf = safe_malloc(max_scf_name_len + 1);
14106 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
14107 
14108 	/* Take the "previous" snapshot before we blow away the properties. */
14109 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
14110 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
14111 			scfdie();
14112 	} else {
14113 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14114 			scfdie();
14115 
14116 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
14117 			scfdie();
14118 	}
14119 
14120 	/* Save general/enabled, since we're probably going to replace it. */
14121 	enabled = 2;
14122 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
14123 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
14124 	    scf_property_get_value(prop, val) == 0)
14125 		(void) scf_value_get_boolean(val, &enabled);
14126 
14127 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14128 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14129 			scfdie();
14130 
14131 		goto out;
14132 	}
14133 
14134 	for (;;) {
14135 		boolean_t isinst;
14136 		uint32_t flags;
14137 		int r;
14138 
14139 		/* Clear the properties from the corresponding entity. */
14140 		isinst = snaplevel_is_instance(level);
14141 
14142 		if (!isinst)
14143 			r = scf_iter_service_pgs(iter, cur_svc);
14144 		else
14145 			r = scf_iter_instance_pgs(iter, cur_inst);
14146 		if (r != SCF_SUCCESS)
14147 			scfdie();
14148 
14149 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14150 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14151 				scfdie();
14152 
14153 			/* Skip nonpersistent pgs. */
14154 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
14155 				continue;
14156 
14157 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
14158 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14159 					scfdie();
14160 
14161 				semerr(emsg_permission_denied);
14162 				goto out;
14163 			}
14164 		}
14165 		if (r == -1)
14166 			scfdie();
14167 
14168 		/* Copy the properties to the corresponding entity. */
14169 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
14170 			scfdie();
14171 
14172 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
14173 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
14174 				scfdie();
14175 
14176 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
14177 			    0)
14178 				scfdie();
14179 
14180 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
14181 				scfdie();
14182 
14183 			if (!isinst)
14184 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
14185 				    flags, npg);
14186 			else
14187 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
14188 				    flags, npg);
14189 			if (r != SCF_SUCCESS) {
14190 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14191 					scfdie();
14192 
14193 				semerr(emsg_permission_denied);
14194 				goto out;
14195 			}
14196 
14197 			if ((enabled == 0 || enabled == 1) &&
14198 			    strcmp(nbuf, scf_pg_general) == 0)
14199 				r = pg_copy(pg, npg, enabled);
14200 			else
14201 				r = pg_copy(pg, npg, 2);
14202 
14203 			switch (r) {
14204 			case 0:
14205 				break;
14206 
14207 			case -1:
14208 				semerr(emsg_permission_denied);
14209 				goto out;
14210 
14211 			case -2:
14212 				semerr(gettext(
14213 				    "Interrupted by another change.\n"));
14214 				goto out;
14215 
14216 			default:
14217 				abort();
14218 			}
14219 		}
14220 		if (r == -1)
14221 			scfdie();
14222 
14223 		/* Get next level. */
14224 		nlevel = scf_snaplevel_create(g_hndl);
14225 		if (nlevel == NULL)
14226 			scfdie();
14227 
14228 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
14229 		    SCF_SUCCESS) {
14230 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14231 				scfdie();
14232 
14233 			scf_snaplevel_destroy(nlevel);
14234 			break;
14235 		}
14236 
14237 		scf_snaplevel_destroy(level);
14238 		level = nlevel;
14239 	}
14240 
14241 	if (snapname == NULL) {
14242 		lscf_selectsnap(NULL);
14243 		snap = NULL;		/* cur_snap has been destroyed */
14244 	}
14245 
14246 out:
14247 	free(tbuf);
14248 	free(nbuf);
14249 	scf_value_destroy(val);
14250 	scf_property_destroy(prop);
14251 	scf_pg_destroy(npg);
14252 	scf_pg_destroy(pg);
14253 	scf_iter_destroy(iter);
14254 	scf_snaplevel_destroy(level);
14255 	scf_snapshot_destroy(prev);
14256 	if (snap != cur_snap)
14257 		scf_snapshot_destroy(snap);
14258 }
14259 
14260 void
14261 lscf_refresh(void)
14262 {
14263 	ssize_t fmrilen;
14264 	size_t bufsz;
14265 	char *fmribuf;
14266 	int r;
14267 
14268 	lscf_prep_hndl();
14269 
14270 	if (cur_inst == NULL) {
14271 		semerr(gettext("Instance not selected.\n"));
14272 		return;
14273 	}
14274 
14275 	bufsz = max_scf_fmri_len + 1;
14276 	fmribuf = safe_malloc(bufsz);
14277 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
14278 	if (fmrilen < 0) {
14279 		free(fmribuf);
14280 		if (scf_error() != SCF_ERROR_DELETED)
14281 			scfdie();
14282 		scf_instance_destroy(cur_inst);
14283 		cur_inst = NULL;
14284 		warn(emsg_deleted);
14285 		return;
14286 	}
14287 	assert(fmrilen < bufsz);
14288 
14289 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
14290 	switch (r) {
14291 	case 0:
14292 		break;
14293 
14294 	case ECONNABORTED:
14295 		warn(gettext("Could not refresh %s "
14296 		    "(repository connection broken).\n"), fmribuf);
14297 		break;
14298 
14299 	case ECANCELED:
14300 		warn(emsg_deleted);
14301 		break;
14302 
14303 	case EPERM:
14304 		warn(gettext("Could not refresh %s "
14305 		    "(permission denied).\n"), fmribuf);
14306 		break;
14307 
14308 	case ENOSPC:
14309 		warn(gettext("Could not refresh %s "
14310 		    "(repository server out of resources).\n"),
14311 		    fmribuf);
14312 		break;
14313 
14314 	case EACCES:
14315 	default:
14316 		bad_error("refresh_entity", scf_error());
14317 	}
14318 
14319 	free(fmribuf);
14320 }
14321 
14322 /*
14323  * describe [-v] [-t] [pg/prop]
14324  */
14325 int
14326 lscf_describe(uu_list_t *args, int hasargs)
14327 {
14328 	int ret = 0;
14329 	size_t i;
14330 	int argc;
14331 	char **argv = NULL;
14332 	string_list_t *slp;
14333 	int do_verbose = 0;
14334 	int do_templates = 0;
14335 	char *pattern = NULL;
14336 
14337 	lscf_prep_hndl();
14338 
14339 	if (hasargs != 0)  {
14340 		argc = uu_list_numnodes(args);
14341 		if (argc < 1)
14342 			goto usage;
14343 
14344 		argv = calloc(argc + 1, sizeof (char *));
14345 		if (argv == NULL)
14346 			uu_die(gettext("Out of memory.\n"));
14347 
14348 		for (slp = uu_list_first(args), i = 0;
14349 		    slp != NULL;
14350 		    slp = uu_list_next(args, slp), ++i)
14351 			argv[i] = slp->str;
14352 
14353 		argv[i] = NULL;
14354 
14355 		/*
14356 		 * We start optind = 0 because our list of arguments
14357 		 * starts at argv[0]
14358 		 */
14359 		optind = 0;
14360 		opterr = 0;
14361 		for (;;) {
14362 			ret = getopt(argc, argv, "vt");
14363 			if (ret == -1)
14364 				break;
14365 
14366 			switch (ret) {
14367 			case 'v':
14368 				do_verbose = 1;
14369 				break;
14370 
14371 			case 't':
14372 				do_templates = 1;
14373 				break;
14374 
14375 			case '?':
14376 				goto usage;
14377 
14378 			default:
14379 				bad_error("getopt", ret);
14380 			}
14381 		}
14382 
14383 		pattern = argv[optind];
14384 	}
14385 
14386 	if (cur_inst == NULL && cur_svc == NULL) {
14387 		semerr(emsg_entity_not_selected);
14388 		ret = -1;
14389 		goto out;
14390 	}
14391 
14392 	/*
14393 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
14394 	 * output if their last parameter is set to 2.  Less information is
14395 	 * produced if the parameter is set to 1.
14396 	 */
14397 	if (pattern == NULL) {
14398 		if (do_verbose == 1)
14399 			list_entity_tmpl(2);
14400 		else
14401 			list_entity_tmpl(1);
14402 	}
14403 
14404 	if (do_templates == 0) {
14405 		if (do_verbose == 1)
14406 			listprop(pattern, 0, 2);
14407 		else
14408 			listprop(pattern, 0, 1);
14409 	} else {
14410 		if (do_verbose == 1)
14411 			listtmpl(pattern, 2);
14412 		else
14413 			listtmpl(pattern, 1);
14414 	}
14415 
14416 	ret = 0;
14417 out:
14418 	if (argv != NULL)
14419 		free(argv);
14420 	return (ret);
14421 usage:
14422 	ret = -2;
14423 	goto out;
14424 }
14425 
14426 /*
14427  * Creates a list of instance name strings associated with a service. If
14428  * wohandcrafted flag is set, get only instances that have a last-import
14429  * snapshot, instances that were imported via svccfg.
14430  */
14431 static uu_list_t *
14432 create_instance_list(scf_service_t *svc, int wohandcrafted)
14433 {
14434 	scf_snapshot_t  *snap = NULL;
14435 	scf_instance_t  *inst;
14436 	scf_iter_t	*inst_iter;
14437 	uu_list_t	*instances;
14438 	char		*instname;
14439 	int		r;
14440 
14441 	inst_iter = scf_iter_create(g_hndl);
14442 	inst = scf_instance_create(g_hndl);
14443 	if (inst_iter == NULL || inst == NULL) {
14444 		uu_warn(gettext("Could not create instance or iterator\n"));
14445 		scfdie();
14446 	}
14447 
14448 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
14449 		return (instances);
14450 
14451 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
14452 		switch (scf_error()) {
14453 		case SCF_ERROR_CONNECTION_BROKEN:
14454 		case SCF_ERROR_DELETED:
14455 			uu_list_destroy(instances);
14456 			instances = NULL;
14457 			goto out;
14458 
14459 		case SCF_ERROR_HANDLE_MISMATCH:
14460 		case SCF_ERROR_NOT_BOUND:
14461 		case SCF_ERROR_NOT_SET:
14462 		default:
14463 			bad_error("scf_iter_service_instances", scf_error());
14464 		}
14465 	}
14466 
14467 	instname = safe_malloc(max_scf_name_len + 1);
14468 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
14469 		if (r == -1) {
14470 			(void) uu_warn(gettext("Unable to iterate through "
14471 			    "instances to create instance list : %s\n"),
14472 			    scf_strerror(scf_error()));
14473 
14474 			uu_list_destroy(instances);
14475 			instances = NULL;
14476 			goto out;
14477 		}
14478 
14479 		/*
14480 		 * If the instance does not have a last-import snapshot
14481 		 * then do not add it to the list as it is a hand-crafted
14482 		 * instance that should not be managed.
14483 		 */
14484 		if (wohandcrafted) {
14485 			if (snap == NULL &&
14486 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
14487 				uu_warn(gettext("Unable to create snapshot "
14488 				    "entity\n"));
14489 				scfdie();
14490 			}
14491 
14492 			if (scf_instance_get_snapshot(inst,
14493 			    snap_lastimport, snap) != 0) {
14494 				switch (scf_error()) {
14495 				case SCF_ERROR_NOT_FOUND :
14496 				case SCF_ERROR_DELETED:
14497 					continue;
14498 
14499 				case SCF_ERROR_CONNECTION_BROKEN:
14500 					uu_list_destroy(instances);
14501 					instances = NULL;
14502 					goto out;
14503 
14504 				case SCF_ERROR_HANDLE_MISMATCH:
14505 				case SCF_ERROR_NOT_BOUND:
14506 				case SCF_ERROR_NOT_SET:
14507 				default:
14508 					bad_error("scf_iter_service_instances",
14509 					    scf_error());
14510 				}
14511 			}
14512 		}
14513 
14514 		if (scf_instance_get_name(inst, instname,
14515 		    max_scf_name_len + 1) < 0) {
14516 			switch (scf_error()) {
14517 			case SCF_ERROR_NOT_FOUND :
14518 				continue;
14519 
14520 			case SCF_ERROR_CONNECTION_BROKEN:
14521 			case SCF_ERROR_DELETED:
14522 				uu_list_destroy(instances);
14523 				instances = NULL;
14524 				goto out;
14525 
14526 			case SCF_ERROR_HANDLE_MISMATCH:
14527 			case SCF_ERROR_NOT_BOUND:
14528 			case SCF_ERROR_NOT_SET:
14529 			default:
14530 				bad_error("scf_iter_service_instances",
14531 				    scf_error());
14532 			}
14533 		}
14534 
14535 		add_string(instances, instname);
14536 	}
14537 
14538 out:
14539 	if (snap)
14540 		scf_snapshot_destroy(snap);
14541 
14542 	scf_instance_destroy(inst);
14543 	scf_iter_destroy(inst_iter);
14544 	free(instname);
14545 	return (instances);
14546 }
14547 
14548 /*
14549  * disable an instance but wait for the instance to
14550  * move out of the running state.
14551  *
14552  * Returns 0 : if the instance did not disable
14553  * Returns non-zero : if the instance disabled.
14554  *
14555  */
14556 static int
14557 disable_instance(scf_instance_t *instance)
14558 {
14559 	char	*fmribuf;
14560 	int	enabled = 10000;
14561 
14562 	if (inst_is_running(instance)) {
14563 		fmribuf = safe_malloc(max_scf_name_len + 1);
14564 		if (scf_instance_to_fmri(instance, fmribuf,
14565 		    max_scf_name_len + 1) < 0) {
14566 			free(fmribuf);
14567 			return (0);
14568 		}
14569 
14570 		/*
14571 		 * If the instance cannot be disabled then return
14572 		 * failure to disable and let the caller decide
14573 		 * if that is of importance.
14574 		 */
14575 		if (smf_disable_instance(fmribuf, 0) != 0) {
14576 			free(fmribuf);
14577 			return (0);
14578 		}
14579 
14580 		while (enabled) {
14581 			if (!inst_is_running(instance))
14582 				break;
14583 
14584 			(void) poll(NULL, 0, 5);
14585 			enabled = enabled - 5;
14586 		}
14587 
14588 		free(fmribuf);
14589 	}
14590 
14591 	return (enabled);
14592 }
14593 
14594 /*
14595  * Function to compare two service_manifest structures.
14596  */
14597 /* ARGSUSED2 */
14598 static int
14599 service_manifest_compare(const void *left, const void *right, void *unused)
14600 {
14601 	service_manifest_t *l = (service_manifest_t *)left;
14602 	service_manifest_t *r = (service_manifest_t *)right;
14603 	int rc;
14604 
14605 	rc = strcmp(l->servicename, r->servicename);
14606 
14607 	return (rc);
14608 }
14609 
14610 /*
14611  * Look for the provided service in the service to manifest
14612  * tree.  If the service exists, and a manifest was provided
14613  * then add the manifest to that service.  If the service
14614  * does not exist, then add the service and manifest to the
14615  * list.
14616  *
14617  * If the manifest is NULL, return the element if found.  If
14618  * the service is not found return NULL.
14619  */
14620 service_manifest_t *
14621 find_add_svc_mfst(const char *svnbuf, const char *mfst)
14622 {
14623 	service_manifest_t	elem;
14624 	service_manifest_t	*fnelem;
14625 	uu_avl_index_t		marker;
14626 
14627 	elem.servicename = svnbuf;
14628 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
14629 
14630 	if (mfst) {
14631 		if (fnelem) {
14632 			add_string(fnelem->mfstlist, strdup(mfst));
14633 		} else {
14634 			fnelem = safe_malloc(sizeof (*fnelem));
14635 			fnelem->servicename = safe_strdup(svnbuf);
14636 			if ((fnelem->mfstlist =
14637 			    uu_list_create(string_pool, NULL, 0)) == NULL)
14638 				uu_die(gettext("Could not create property "
14639 				    "list: %s\n"), uu_strerror(uu_error()));
14640 
14641 			add_string(fnelem->mfstlist, safe_strdup(mfst));
14642 
14643 			uu_avl_insert(service_manifest_tree, fnelem, marker);
14644 		}
14645 	}
14646 
14647 	return (fnelem);
14648 }
14649 
14650 /*
14651  * Create the service to manifest avl tree.
14652  *
14653  * Walk each of the manifests currently installed in the supported
14654  * directories, /lib/svc/manifests and /var/svc/manifests.  For
14655  * each of the manifests, inventory the services and add them to
14656  * the tree.
14657  *
14658  * Code that calls this function should make sure fileystem/minimal is online,
14659  * /var is available, since this function walks the /var/svc/manifest directory.
14660  */
14661 static void
14662 create_manifest_tree(void)
14663 {
14664 	manifest_info_t **entry;
14665 	manifest_info_t **manifests;
14666 	uu_list_walk_t	*svcs;
14667 	bundle_t	*b;
14668 	entity_t	*mfsvc;
14669 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
14670 	int		c, status;
14671 
14672 	if (service_manifest_pool)
14673 		return;
14674 
14675 	/*
14676 	 * Create the list pool for the service manifest list
14677 	 */
14678 	service_manifest_pool = uu_avl_pool_create("service_manifest",
14679 	    sizeof (service_manifest_t),
14680 	    offsetof(service_manifest_t, svcmfst_node),
14681 	    service_manifest_compare, UU_DEFAULT);
14682 	if (service_manifest_pool == NULL)
14683 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
14684 		    uu_strerror(uu_error()));
14685 
14686 	/*
14687 	 * Create the list
14688 	 */
14689 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
14690 	    UU_DEFAULT);
14691 	if (service_manifest_tree == NULL)
14692 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
14693 		    uu_strerror(uu_error()));
14694 
14695 	/*
14696 	 * Walk the manifests adding the service(s) from each manifest.
14697 	 *
14698 	 * If a service already exists add the manifest to the manifest
14699 	 * list for that service.  This covers the case of a service that
14700 	 * is supported by multiple manifest files.
14701 	 */
14702 	for (c = 0; dirs[c]; c++) {
14703 		status = find_manifests(dirs[c], &manifests, CHECKEXT);
14704 		if (status < 0) {
14705 			uu_warn(gettext("file tree walk of %s encountered "
14706 			    "error %s\n"), dirs[c], strerror(errno));
14707 
14708 			uu_avl_destroy(service_manifest_tree);
14709 			service_manifest_tree = NULL;
14710 			return;
14711 		}
14712 
14713 		/*
14714 		 * If a manifest that was in the list is not found
14715 		 * then skip and go to the next manifest file.
14716 		 */
14717 		if (manifests != NULL) {
14718 			for (entry = manifests; *entry != NULL; entry++) {
14719 				b = internal_bundle_new();
14720 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
14721 				    SVCCFG_OP_IMPORT) != 0) {
14722 					internal_bundle_free(b);
14723 					continue;
14724 				}
14725 
14726 				svcs = uu_list_walk_start(b->sc_bundle_services,
14727 				    0);
14728 				if (svcs == NULL) {
14729 					internal_bundle_free(b);
14730 					continue;
14731 				}
14732 
14733 				while ((mfsvc = uu_list_walk_next(svcs)) !=
14734 				    NULL) {
14735 					/* Add manifest to service */
14736 					(void) find_add_svc_mfst(mfsvc->sc_name,
14737 					    (*entry)->mi_path);
14738 				}
14739 
14740 				uu_list_walk_end(svcs);
14741 				internal_bundle_free(b);
14742 			}
14743 
14744 			free_manifest_array(manifests);
14745 		}
14746 	}
14747 }
14748 
14749 /*
14750  * Check the manifest history file to see
14751  * if the service was ever installed from
14752  * one of the supported directories.
14753  *
14754  * Return Values :
14755  * 	-1 - if there's error reading manifest history file
14756  *	 1 - if the service is not found
14757  *	 0 - if the service is found
14758  */
14759 static int
14760 check_mfst_history(const char *svcname)
14761 {
14762 	struct stat	st;
14763 	caddr_t		mfsthist_start;
14764 	char		*svnbuf;
14765 	int		fd;
14766 	int		r = 1;
14767 
14768 	fd = open(MFSTHISTFILE, O_RDONLY);
14769 	if (fd == -1) {
14770 		uu_warn(gettext("Unable to open the history file\n"));
14771 		return (-1);
14772 	}
14773 
14774 	if (fstat(fd, &st) == -1) {
14775 		uu_warn(gettext("Unable to stat the history file\n"));
14776 		return (-1);
14777 	}
14778 
14779 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
14780 	    MAP_PRIVATE, fd, 0);
14781 
14782 	(void) close(fd);
14783 	if (mfsthist_start == MAP_FAILED ||
14784 	    *(mfsthist_start + st.st_size) != '\0') {
14785 		(void) munmap(mfsthist_start, st.st_size);
14786 		return (-1);
14787 	}
14788 
14789 	/*
14790 	 * The manifest history file is a space delimited list
14791 	 * of service and instance to manifest linkage.  Adding
14792 	 * a space to the end of the service name so to get only
14793 	 * the service that is being searched for.
14794 	 */
14795 	svnbuf = uu_msprintf("%s ", svcname);
14796 	if (svnbuf == NULL)
14797 		uu_die(gettext("Out of memory"));
14798 
14799 	if (strstr(mfsthist_start, svnbuf) != NULL)
14800 		r = 0;
14801 
14802 	(void) munmap(mfsthist_start, st.st_size);
14803 	uu_free(svnbuf);
14804 	return (r);
14805 }
14806 
14807 /*
14808  * Take down each of the instances in the service
14809  * and remove them, then delete the service.
14810  */
14811 static void
14812 teardown_service(scf_service_t *svc, const char *svnbuf)
14813 {
14814 	scf_instance_t	*instance;
14815 	scf_iter_t	*iter;
14816 	int		r;
14817 
14818 	safe_printf(gettext("Delete service %s as there are no "
14819 	    "supporting manifests\n"), svnbuf);
14820 
14821 	instance = scf_instance_create(g_hndl);
14822 	iter = scf_iter_create(g_hndl);
14823 	if (iter == NULL || instance == NULL) {
14824 		uu_warn(gettext("Unable to create supporting entities to "
14825 		    "teardown the service\n"));
14826 		uu_warn(gettext("scf error is : %s\n"),
14827 		    scf_strerror(scf_error()));
14828 		scfdie();
14829 	}
14830 
14831 	if (scf_iter_service_instances(iter, svc) != 0) {
14832 		switch (scf_error()) {
14833 		case SCF_ERROR_CONNECTION_BROKEN:
14834 		case SCF_ERROR_DELETED:
14835 			goto out;
14836 
14837 		case SCF_ERROR_HANDLE_MISMATCH:
14838 		case SCF_ERROR_NOT_BOUND:
14839 		case SCF_ERROR_NOT_SET:
14840 		default:
14841 			bad_error("scf_iter_service_instances",
14842 			    scf_error());
14843 		}
14844 	}
14845 
14846 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
14847 		if (r == -1) {
14848 			uu_warn(gettext("Error - %s\n"),
14849 			    scf_strerror(scf_error()));
14850 			goto out;
14851 		}
14852 
14853 		(void) disable_instance(instance);
14854 	}
14855 
14856 	/*
14857 	 * Delete the service... forcing the deletion in case
14858 	 * any of the instances did not disable.
14859 	 */
14860 	(void) lscf_service_delete(svc, 1);
14861 out:
14862 	scf_instance_destroy(instance);
14863 	scf_iter_destroy(iter);
14864 }
14865 
14866 /*
14867  * Get the list of instances supported by the manifest
14868  * file.
14869  *
14870  * Return 0 if there are no instances.
14871  *
14872  * Return -1 if there are errors attempting to collect instances.
14873  *
14874  * Return the count of instances found if there are no errors.
14875  *
14876  */
14877 static int
14878 check_instance_support(char *mfstfile, const char *svcname,
14879     uu_list_t *instances)
14880 {
14881 	uu_list_walk_t	*svcs, *insts;
14882 	uu_list_t	*ilist;
14883 	bundle_t	*b;
14884 	entity_t	*mfsvc, *mfinst;
14885 	const char	*svcn;
14886 	int		rminstcnt = 0;
14887 
14888 
14889 	b = internal_bundle_new();
14890 
14891 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
14892 		/*
14893 		 * Unable to process the manifest file for
14894 		 * instance support, so just return as
14895 		 * don't want to remove instances that could
14896 		 * not be accounted for that might exist here.
14897 		 */
14898 		internal_bundle_free(b);
14899 		return (0);
14900 	}
14901 
14902 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
14903 	if (svcs == NULL) {
14904 		internal_bundle_free(b);
14905 		return (0);
14906 	}
14907 
14908 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
14909 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
14910 
14911 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
14912 		if (strcmp(mfsvc->sc_name, svcn) == 0)
14913 			break;
14914 	}
14915 	uu_list_walk_end(svcs);
14916 
14917 	if (mfsvc == NULL) {
14918 		internal_bundle_free(b);
14919 		return (-1);
14920 	}
14921 
14922 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
14923 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
14924 		internal_bundle_free(b);
14925 		return (0);
14926 	}
14927 
14928 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
14929 		/*
14930 		 * Remove the instance from the instances list.
14931 		 * The unaccounted for instances will be removed
14932 		 * from the service once all manifests are
14933 		 * processed.
14934 		 */
14935 		(void) remove_string(instances,
14936 		    mfinst->sc_name);
14937 		rminstcnt++;
14938 	}
14939 
14940 	uu_list_walk_end(insts);
14941 	internal_bundle_free(b);
14942 
14943 	return (rminstcnt);
14944 }
14945 
14946 /*
14947  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
14948  * 'false' to indicate there's no manifest file(s) found for the service.
14949  */
14950 static void
14951 svc_add_no_support(scf_service_t *svc)
14952 {
14953 	char	*pname;
14954 
14955 	/* Add no support */
14956 	cur_svc = svc;
14957 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
14958 		return;
14959 
14960 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
14961 	if (pname == NULL)
14962 		uu_die(gettext("Out of memory.\n"));
14963 
14964 	(void) lscf_addpropvalue(pname, "boolean:", "0");
14965 
14966 	uu_free(pname);
14967 	cur_svc = NULL;
14968 }
14969 
14970 /*
14971  * This function handles all upgrade scenarios for a service that doesn't have
14972  * SCF_PG_MANIFESTFILES pg. The function creates and populates
14973  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
14974  * manifest(s) mapping. Manifests under supported directories are inventoried
14975  * and a property is added for each file that delivers configuration to the
14976  * service.  A service that has no corresponding manifest files (deleted) are
14977  * removed from repository.
14978  *
14979  * Unsupported services:
14980  *
14981  * A service is considered unsupported if there is no corresponding manifest
14982  * in the supported directories for that service and the service isn't in the
14983  * history file list.  The history file, MFSTHISTFILE, contains a list of all
14984  * services and instances that were delivered by Solaris before the introduction
14985  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
14986  * the path to the manifest file that defined the service or instance.
14987  *
14988  * Another type of unsupported services is 'handcrafted' services,
14989  * programmatically created services or services created by dependent entries
14990  * in other manifests. A handcrafted service is identified by its lack of any
14991  * instance containing last-import snapshot which is created during svccfg
14992  * import.
14993  *
14994  * This function sets a flag for unsupported services by setting services'
14995  * SCF_PG_MANIFESTFILES/support property to false.
14996  */
14997 static void
14998 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
14999 {
15000 	service_manifest_t	*elem;
15001 	uu_list_walk_t		*mfwalk;
15002 	string_list_t		*mfile;
15003 	uu_list_t		*instances;
15004 	const char		*sname;
15005 	char			*pname;
15006 	int			r;
15007 
15008 	/*
15009 	 * Since there's no guarantee manifests under /var are available during
15010 	 * early import, don't perform any upgrade during early import.
15011 	 */
15012 	if (IGNORE_VAR)
15013 		return;
15014 
15015 	if (service_manifest_tree == NULL) {
15016 		create_manifest_tree();
15017 	}
15018 
15019 	/*
15020 	 * Find service's supporting manifest(s) after
15021 	 * stripping off the svc:/ prefix that is part
15022 	 * of the fmri that is not used in the service
15023 	 * manifest bundle list.
15024 	 */
15025 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
15026 	    strlen(SCF_FMRI_SERVICE_PREFIX);
15027 	elem = find_add_svc_mfst(sname, NULL);
15028 	if (elem == NULL) {
15029 
15030 		/*
15031 		 * A handcrafted service, one that has no instance containing
15032 		 * last-import snapshot, should get unsupported flag.
15033 		 */
15034 		instances = create_instance_list(svc, 1);
15035 		if (instances == NULL) {
15036 			uu_warn(gettext("Unable to create instance list %s\n"),
15037 			    svcname);
15038 			return;
15039 		}
15040 
15041 		if (uu_list_numnodes(instances) == 0) {
15042 			svc_add_no_support(svc);
15043 			return;
15044 		}
15045 
15046 		/*
15047 		 * If the service is in the history file, and its supporting
15048 		 * manifests are not found, we can safely delete the service
15049 		 * because its manifests are removed from the system.
15050 		 *
15051 		 * Services not found in the history file are not delivered by
15052 		 * Solaris and/or delivered outside supported directories, set
15053 		 * unsupported flag for these services.
15054 		 */
15055 		r = check_mfst_history(svcname);
15056 		if (r == -1)
15057 			return;
15058 
15059 		if (r) {
15060 			/* Set unsupported flag for service  */
15061 			svc_add_no_support(svc);
15062 		} else {
15063 			/* Delete the service */
15064 			teardown_service(svc, svcname);
15065 		}
15066 
15067 		return;
15068 	}
15069 
15070 	/*
15071 	 * Walk through the list of manifests and add them
15072 	 * to the service.
15073 	 *
15074 	 * Create a manifestfiles pg and add the property.
15075 	 */
15076 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
15077 	if (mfwalk == NULL)
15078 		return;
15079 
15080 	cur_svc = svc;
15081 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
15082 	if (r != 0) {
15083 		cur_svc = NULL;
15084 		return;
15085 	}
15086 
15087 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
15088 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
15089 		    mhash_filename_to_propname(mfile->str, 0));
15090 		if (pname == NULL)
15091 			uu_die(gettext("Out of memory.\n"));
15092 
15093 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
15094 		uu_free(pname);
15095 	}
15096 	uu_list_walk_end(mfwalk);
15097 
15098 	cur_svc = NULL;
15099 }
15100 
15101 /*
15102  * Take a service and process the manifest file entires to see if
15103  * there is continued support for the service and instances.  If
15104  * not cleanup as appropriate.
15105  *
15106  * If a service does not have a manifest files entry flag it for
15107  * upgrade and return.
15108  *
15109  * For each manifestfiles property check if the manifest file is
15110  * under the supported /lib/svc/manifest or /var/svc/manifest path
15111  * and if not then return immediately as this service is not supported
15112  * by the cleanup mechanism and should be ignored.
15113  *
15114  * For each manifest file that is supported, check to see if the
15115  * file exists.  If not then remove the manifest file property
15116  * from the service and the smf/manifest hash table.  If the manifest
15117  * file exists then verify that it supports the instances that are
15118  * part of the service.
15119  *
15120  * Once all manifest files have been accounted for remove any instances
15121  * that are no longer supported in the service.
15122  *
15123  * Return values :
15124  * 0 - Successfully processed the service
15125  * non-zero - failed to process the service
15126  *
15127  * On most errors, will just return to wait and get the next service,
15128  * unless in case of unable to create the needed structures which is
15129  * most likely a fatal error that is not going to be recoverable.
15130  */
15131 int
15132 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
15133 {
15134 	struct mpg_mfile	*mpntov;
15135 	struct mpg_mfile	**mpvarry = NULL;
15136 	scf_service_t		*svc;
15137 	scf_propertygroup_t	*mpg;
15138 	scf_property_t		*mp;
15139 	scf_value_t		*mv;
15140 	scf_iter_t		*mi;
15141 	scf_instance_t		*instance;
15142 	uu_list_walk_t		*insts;
15143 	uu_list_t		*instances = NULL;
15144 	boolean_t		activity = (boolean_t)act;
15145 	char			*mpnbuf;
15146 	char			*mpvbuf;
15147 	char			*pgpropbuf;
15148 	int			mfstcnt, rminstct, instct, mfstmax;
15149 	int			index;
15150 	int			r = 0;
15151 
15152 	assert(g_hndl != NULL);
15153 	assert(wip->svc != NULL);
15154 	assert(wip->fmri != NULL);
15155 
15156 	svc = wip->svc;
15157 
15158 	mpg = scf_pg_create(g_hndl);
15159 	mp = scf_property_create(g_hndl);
15160 	mi = scf_iter_create(g_hndl);
15161 	mv = scf_value_create(g_hndl);
15162 	instance = scf_instance_create(g_hndl);
15163 
15164 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
15165 	    instance == NULL) {
15166 		uu_warn(gettext("Unable to create the supporting entities\n"));
15167 		uu_warn(gettext("scf error is : %s\n"),
15168 		    scf_strerror(scf_error()));
15169 		scfdie();
15170 	}
15171 
15172 	/*
15173 	 * Get the manifestfiles property group to be parsed for
15174 	 * files existence.
15175 	 */
15176 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
15177 		switch (scf_error()) {
15178 		case SCF_ERROR_NOT_FOUND:
15179 			upgrade_svc_mfst_connection(svc, wip->fmri);
15180 			break;
15181 		case SCF_ERROR_DELETED:
15182 		case SCF_ERROR_CONNECTION_BROKEN:
15183 			goto out;
15184 
15185 		case SCF_ERROR_HANDLE_MISMATCH:
15186 		case SCF_ERROR_NOT_BOUND:
15187 		case SCF_ERROR_NOT_SET:
15188 		default:
15189 			bad_error("scf_iter_pg_properties",
15190 			    scf_error());
15191 		}
15192 
15193 		goto out;
15194 	}
15195 
15196 	/*
15197 	 * Iterate through each of the manifestfiles properties
15198 	 * to determine what manifestfiles are available.
15199 	 *
15200 	 * If a manifest file is supported then increment the
15201 	 * count and therefore the service is safe.
15202 	 */
15203 	if (scf_iter_pg_properties(mi, mpg) != 0) {
15204 		switch (scf_error()) {
15205 		case SCF_ERROR_DELETED:
15206 		case SCF_ERROR_CONNECTION_BROKEN:
15207 			goto out;
15208 
15209 		case SCF_ERROR_HANDLE_MISMATCH:
15210 		case SCF_ERROR_NOT_BOUND:
15211 		case SCF_ERROR_NOT_SET:
15212 		default:
15213 			bad_error("scf_iter_pg_properties",
15214 			    scf_error());
15215 		}
15216 	}
15217 
15218 	mfstcnt = 0;
15219 	mfstmax = MFSTFILE_MAX;
15220 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
15221 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
15222 		if (r == -1)
15223 			bad_error(gettext("Unable to iterate through "
15224 			    "manifestfiles properties : %s"),
15225 			    scf_error());
15226 
15227 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
15228 		mpnbuf = safe_malloc(max_scf_name_len + 1);
15229 		mpvbuf = safe_malloc(max_scf_value_len + 1);
15230 		mpntov->mpg = mpnbuf;
15231 		mpntov->mfile = mpvbuf;
15232 		mpntov->access = 1;
15233 		if (scf_property_get_name(mp, mpnbuf,
15234 		    max_scf_name_len + 1) < 0) {
15235 			uu_warn(gettext("Unable to get manifest file "
15236 			    "property : %s\n"),
15237 			    scf_strerror(scf_error()));
15238 
15239 			switch (scf_error()) {
15240 			case SCF_ERROR_DELETED:
15241 			case SCF_ERROR_CONNECTION_BROKEN:
15242 				r = scferror2errno(scf_error());
15243 				goto out_free;
15244 
15245 			case SCF_ERROR_HANDLE_MISMATCH:
15246 			case SCF_ERROR_NOT_BOUND:
15247 			case SCF_ERROR_NOT_SET:
15248 			default:
15249 				bad_error("scf_iter_pg_properties",
15250 				    scf_error());
15251 			}
15252 		}
15253 
15254 		/*
15255 		 * The support property is a boolean value that indicates
15256 		 * if the service is supported for manifest file deletion.
15257 		 * Currently at this time there is no code that sets this
15258 		 * value to true.  So while we could just let this be caught
15259 		 * by the support check below, in the future this by be set
15260 		 * to true and require processing.  So for that, go ahead
15261 		 * and check here, and just return if false.  Otherwise,
15262 		 * fall through expecting that other support checks will
15263 		 * handle the entries.
15264 		 */
15265 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
15266 			uint8_t	support;
15267 
15268 			if (scf_property_get_value(mp, mv) != 0 ||
15269 			    scf_value_get_boolean(mv, &support) != 0) {
15270 				uu_warn(gettext("Unable to get the manifest "
15271 				    "support value: %s\n"),
15272 				    scf_strerror(scf_error()));
15273 
15274 				switch (scf_error()) {
15275 				case SCF_ERROR_DELETED:
15276 				case SCF_ERROR_CONNECTION_BROKEN:
15277 					r = scferror2errno(scf_error());
15278 					goto out_free;
15279 
15280 				case SCF_ERROR_HANDLE_MISMATCH:
15281 				case SCF_ERROR_NOT_BOUND:
15282 				case SCF_ERROR_NOT_SET:
15283 				default:
15284 					bad_error("scf_iter_pg_properties",
15285 					    scf_error());
15286 				}
15287 			}
15288 
15289 			if (support == B_FALSE)
15290 				goto out_free;
15291 		}
15292 
15293 		/*
15294 		 * Anything with a manifest outside of the supported
15295 		 * directories, immediately bail out because that makes
15296 		 * this service non-supported.  We don't even want
15297 		 * to do instance processing in this case because the
15298 		 * instances could be part of the non-supported manifest.
15299 		 */
15300 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
15301 			/*
15302 			 * Manifest is not in /lib/svc, so we need to
15303 			 * consider the /var/svc case.
15304 			 */
15305 			if (strncmp(mpnbuf, VARSVC_PR,
15306 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
15307 				/*
15308 				 * Either the manifest is not in /var/svc or
15309 				 * /var is not yet mounted.  We ignore the
15310 				 * manifest either because it is not in a
15311 				 * standard location or because we cannot
15312 				 * currently access the manifest.
15313 				 */
15314 				goto out_free;
15315 			}
15316 		}
15317 
15318 		/*
15319 		 * Get the value to of the manifest file for this entry
15320 		 * for access verification and instance support
15321 		 * verification if it still exists.
15322 		 *
15323 		 * During Early Manifest Import if the manifest is in
15324 		 * /var/svc then it may not yet be available for checking
15325 		 * so we must determine if /var/svc is available.  If not
15326 		 * then defer until Late Manifest Import to cleanup.
15327 		 */
15328 		if (scf_property_get_value(mp, mv) != 0) {
15329 			uu_warn(gettext("Unable to get the manifest file "
15330 			    "value: %s\n"),
15331 			    scf_strerror(scf_error()));
15332 
15333 			switch (scf_error()) {
15334 			case SCF_ERROR_DELETED:
15335 			case SCF_ERROR_CONNECTION_BROKEN:
15336 				r = scferror2errno(scf_error());
15337 				goto out_free;
15338 
15339 			case SCF_ERROR_HANDLE_MISMATCH:
15340 			case SCF_ERROR_NOT_BOUND:
15341 			case SCF_ERROR_NOT_SET:
15342 			default:
15343 				bad_error("scf_property_get_value",
15344 				    scf_error());
15345 			}
15346 		}
15347 
15348 		if (scf_value_get_astring(mv, mpvbuf,
15349 		    max_scf_value_len + 1) < 0) {
15350 			uu_warn(gettext("Unable to get the manifest "
15351 			    "file : %s\n"),
15352 			    scf_strerror(scf_error()));
15353 
15354 			switch (scf_error()) {
15355 			case SCF_ERROR_DELETED:
15356 			case SCF_ERROR_CONNECTION_BROKEN:
15357 				r = scferror2errno(scf_error());
15358 				goto out_free;
15359 
15360 			case SCF_ERROR_HANDLE_MISMATCH:
15361 			case SCF_ERROR_NOT_BOUND:
15362 			case SCF_ERROR_NOT_SET:
15363 			default:
15364 				bad_error("scf_value_get_astring",
15365 				    scf_error());
15366 			}
15367 		}
15368 
15369 		mpvarry[mfstcnt] = mpntov;
15370 		mfstcnt++;
15371 
15372 		/*
15373 		 * Check for the need to reallocate array
15374 		 */
15375 		if (mfstcnt >= (mfstmax - 1)) {
15376 			struct mpg_mfile **newmpvarry;
15377 
15378 			mfstmax = mfstmax * 2;
15379 			newmpvarry = realloc(mpvarry,
15380 			    sizeof (struct mpg_mfile *) * mfstmax);
15381 
15382 			if (newmpvarry == NULL)
15383 				goto out_free;
15384 
15385 			mpvarry = newmpvarry;
15386 		}
15387 
15388 		mpvarry[mfstcnt] = NULL;
15389 	}
15390 
15391 	for (index = 0; mpvarry[index]; index++) {
15392 		mpntov = mpvarry[index];
15393 
15394 		/*
15395 		 * Check to see if the manifestfile is accessable, if so hand
15396 		 * this service and manifestfile off to be processed for
15397 		 * instance support.
15398 		 */
15399 		mpnbuf = mpntov->mpg;
15400 		mpvbuf = mpntov->mfile;
15401 		if (access(mpvbuf, F_OK) != 0) {
15402 			mpntov->access = 0;
15403 			activity++;
15404 			mfstcnt--;
15405 			/* Remove the entry from the service */
15406 			cur_svc = svc;
15407 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
15408 			    mpnbuf);
15409 			if (pgpropbuf == NULL)
15410 				uu_die(gettext("Out of memory.\n"));
15411 
15412 			lscf_delprop(pgpropbuf);
15413 			cur_svc = NULL;
15414 
15415 			uu_free(pgpropbuf);
15416 		}
15417 	}
15418 
15419 	/*
15420 	 * If mfstcnt is 0, none of the manifests that supported the service
15421 	 * existed so remove the service.
15422 	 */
15423 	if (mfstcnt == 0) {
15424 		teardown_service(svc, wip->fmri);
15425 
15426 		goto out_free;
15427 	}
15428 
15429 	if (activity) {
15430 		int	nosvcsupport = 0;
15431 
15432 		/*
15433 		 * If the list of service instances is NULL then
15434 		 * create the list.
15435 		 */
15436 		instances = create_instance_list(svc, 1);
15437 		if (instances == NULL) {
15438 			uu_warn(gettext("Unable to create instance list %s\n"),
15439 			    wip->fmri);
15440 			goto out_free;
15441 		}
15442 
15443 		rminstct = uu_list_numnodes(instances);
15444 		instct = rminstct;
15445 
15446 		for (index = 0; mpvarry[index]; index++) {
15447 			mpntov = mpvarry[index];
15448 			if (mpntov->access == 0)
15449 				continue;
15450 
15451 			mpnbuf = mpntov->mpg;
15452 			mpvbuf = mpntov->mfile;
15453 			r = check_instance_support(mpvbuf, wip->fmri,
15454 			    instances);
15455 			if (r == -1) {
15456 				nosvcsupport++;
15457 			} else {
15458 				rminstct -= r;
15459 			}
15460 		}
15461 
15462 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
15463 			teardown_service(svc, wip->fmri);
15464 
15465 			goto out_free;
15466 		}
15467 	}
15468 
15469 	/*
15470 	 * If there are instances left on the instance list, then
15471 	 * we must remove them.
15472 	 */
15473 	if (instances != NULL && uu_list_numnodes(instances)) {
15474 		string_list_t *sp;
15475 
15476 		insts = uu_list_walk_start(instances, 0);
15477 		while ((sp = uu_list_walk_next(insts)) != NULL) {
15478 			/*
15479 			 * Remove the instance from the instances list.
15480 			 */
15481 			safe_printf(gettext("Delete instance %s from "
15482 			    "service %s\n"), sp->str, wip->fmri);
15483 			if (scf_service_get_instance(svc, sp->str,
15484 			    instance) != SCF_SUCCESS) {
15485 				(void) uu_warn("scf_error - %s\n",
15486 				    scf_strerror(scf_error()));
15487 
15488 				continue;
15489 			}
15490 
15491 			(void) disable_instance(instance);
15492 
15493 			(void) lscf_instance_delete(instance, 1);
15494 		}
15495 		scf_instance_destroy(instance);
15496 		uu_list_walk_end(insts);
15497 	}
15498 
15499 out_free:
15500 	if (mpvarry) {
15501 		struct mpg_mfile *fmpntov;
15502 
15503 		for (index = 0; mpvarry[index]; index++) {
15504 			fmpntov  = mpvarry[index];
15505 			if (fmpntov->mpg == mpnbuf)
15506 				mpnbuf = NULL;
15507 			free(fmpntov->mpg);
15508 
15509 			if (fmpntov->mfile == mpvbuf)
15510 				mpvbuf = NULL;
15511 			free(fmpntov->mfile);
15512 
15513 			if (fmpntov == mpntov)
15514 				mpntov = NULL;
15515 			free(fmpntov);
15516 		}
15517 		if (mpnbuf)
15518 			free(mpnbuf);
15519 		if (mpvbuf)
15520 			free(mpvbuf);
15521 		if (mpntov)
15522 			free(mpntov);
15523 
15524 		free(mpvarry);
15525 	}
15526 out:
15527 	scf_pg_destroy(mpg);
15528 	scf_property_destroy(mp);
15529 	scf_iter_destroy(mi);
15530 	scf_value_destroy(mv);
15531 
15532 	return (0);
15533 }
15534 
15535 /*
15536  * Take the service and search for the manifestfiles property
15537  * in each of the property groups.  If the manifest file
15538  * associated with the property does not exist then remove
15539  * the property group.
15540  */
15541 int
15542 lscf_hash_cleanup()
15543 {
15544 	scf_service_t		*svc;
15545 	scf_scope_t		*scope;
15546 	scf_propertygroup_t	*pg;
15547 	scf_property_t		*prop;
15548 	scf_value_t		*val;
15549 	scf_iter_t		*iter;
15550 	char			*pgname;
15551 	char			*mfile;
15552 	int			r;
15553 
15554 	svc = scf_service_create(g_hndl);
15555 	scope = scf_scope_create(g_hndl);
15556 	pg = scf_pg_create(g_hndl);
15557 	prop = scf_property_create(g_hndl);
15558 	val = scf_value_create(g_hndl);
15559 	iter = scf_iter_create(g_hndl);
15560 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
15561 	    svc == NULL || scope == NULL) {
15562 		uu_warn(gettext("Unable to create a property group, or "
15563 		    "property\n"));
15564 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
15565 		    "pg is not NULL");
15566 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
15567 		    "prop is not NULL");
15568 		uu_warn("%s\n", val == NULL ? "val is NULL" :
15569 		    "val is not NULL");
15570 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
15571 		    "iter is not NULL");
15572 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
15573 		    "svc is not NULL");
15574 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
15575 		    "scope is not NULL");
15576 		uu_warn(gettext("scf error is : %s\n"),
15577 		    scf_strerror(scf_error()));
15578 		scfdie();
15579 	}
15580 
15581 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
15582 		switch (scf_error()) {
15583 		case SCF_ERROR_CONNECTION_BROKEN:
15584 		case SCF_ERROR_NOT_FOUND:
15585 			goto out;
15586 
15587 		case SCF_ERROR_HANDLE_MISMATCH:
15588 		case SCF_ERROR_NOT_BOUND:
15589 		case SCF_ERROR_INVALID_ARGUMENT:
15590 		default:
15591 			bad_error("scf_handle_get_scope", scf_error());
15592 		}
15593 	}
15594 
15595 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
15596 		uu_warn(gettext("Unable to process the hash service, %s\n"),
15597 		    HASH_SVC);
15598 		goto out;
15599 	}
15600 
15601 	pgname = safe_malloc(max_scf_name_len + 1);
15602 	mfile = safe_malloc(max_scf_value_len + 1);
15603 
15604 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
15605 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
15606 		    scf_strerror(scf_error()));
15607 		goto out;
15608 	}
15609 
15610 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
15611 		if (r == -1)
15612 			goto out;
15613 
15614 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
15615 			switch (scf_error()) {
15616 			case SCF_ERROR_DELETED:
15617 				return (ENODEV);
15618 
15619 			case SCF_ERROR_CONNECTION_BROKEN:
15620 				return (ECONNABORTED);
15621 
15622 			case SCF_ERROR_NOT_SET:
15623 			case SCF_ERROR_NOT_BOUND:
15624 			default:
15625 				bad_error("scf_pg_get_name", scf_error());
15626 			}
15627 		}
15628 		if (IGNORE_VAR) {
15629 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
15630 				continue;
15631 		}
15632 
15633 		/*
15634 		 * If unable to get the property continue as this is an
15635 		 * entry that has no location to check against.
15636 		 */
15637 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
15638 			continue;
15639 		}
15640 
15641 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
15642 			uu_warn(gettext("Unable to get value from %s\n"),
15643 			    pgname);
15644 			goto error_handle;
15645 		}
15646 
15647 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1) ==
15648 		    -1) {
15649 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
15650 			    pgname, scf_strerror(scf_error()));
15651 			goto error_handle;
15652 		}
15653 
15654 		if (access(mfile, F_OK) == 0)
15655 			continue;
15656 
15657 		(void) scf_pg_delete(pg);
15658 
15659 error_handle:
15660 		switch (scf_error()) {
15661 		case SCF_ERROR_DELETED:
15662 		case SCF_ERROR_CONSTRAINT_VIOLATED:
15663 		case SCF_ERROR_NOT_FOUND:
15664 		case SCF_ERROR_NOT_SET:
15665 			continue;
15666 
15667 		case SCF_ERROR_CONNECTION_BROKEN:
15668 			r = scferror2errno(scf_error());
15669 			goto out;
15670 
15671 		case SCF_ERROR_HANDLE_MISMATCH:
15672 		case SCF_ERROR_NOT_BOUND:
15673 		default:
15674 			bad_error("scf_value_get_astring",
15675 			    scf_error());
15676 		}
15677 	}
15678 
15679 out:
15680 	scf_scope_destroy(scope);
15681 	scf_service_destroy(svc);
15682 	scf_pg_destroy(pg);
15683 	scf_property_destroy(prop);
15684 	scf_value_destroy(val);
15685 	scf_iter_destroy(iter);
15686 	free(pgname);
15687 	free(mfile);
15688 
15689 	return (0);
15690 }
15691 
15692 #ifndef NATIVE_BUILD
15693 /* ARGSUSED */
15694 CPL_MATCH_FN(complete_select)
15695 {
15696 	const char *arg0, *arg1, *arg1end;
15697 	int word_start, err = 0, r;
15698 	size_t len;
15699 	char *buf;
15700 
15701 	lscf_prep_hndl();
15702 
15703 	arg0 = line + strspn(line, " \t");
15704 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
15705 
15706 	arg1 = arg0 + sizeof ("select") - 1;
15707 	arg1 += strspn(arg1, " \t");
15708 	word_start = arg1 - line;
15709 
15710 	arg1end = arg1 + strcspn(arg1, " \t");
15711 	if (arg1end < line + word_end)
15712 		return (0);
15713 
15714 	len = line + word_end - arg1;
15715 
15716 	buf = safe_malloc(max_scf_name_len + 1);
15717 
15718 	if (cur_snap != NULL) {
15719 		return (0);
15720 	} else if (cur_inst != NULL) {
15721 		return (0);
15722 	} else if (cur_svc != NULL) {
15723 		scf_instance_t *inst;
15724 		scf_iter_t *iter;
15725 
15726 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
15727 		    (iter = scf_iter_create(g_hndl)) == NULL)
15728 			scfdie();
15729 
15730 		if (scf_iter_service_instances(iter, cur_svc) != 0)
15731 			scfdie();
15732 
15733 		for (;;) {
15734 			r = scf_iter_next_instance(iter, inst);
15735 			if (r == 0)
15736 				break;
15737 			if (r != 1)
15738 				scfdie();
15739 
15740 			if (scf_instance_get_name(inst, buf,
15741 			    max_scf_name_len + 1) < 0)
15742 				scfdie();
15743 
15744 			if (strncmp(buf, arg1, len) == 0) {
15745 				err = cpl_add_completion(cpl, line, word_start,
15746 				    word_end, buf + len, "", " ");
15747 				if (err != 0)
15748 					break;
15749 			}
15750 		}
15751 
15752 		scf_iter_destroy(iter);
15753 		scf_instance_destroy(inst);
15754 
15755 		return (err);
15756 	} else {
15757 		scf_service_t *svc;
15758 		scf_iter_t *iter;
15759 
15760 		assert(cur_scope != NULL);
15761 
15762 		if ((svc = scf_service_create(g_hndl)) == NULL ||
15763 		    (iter = scf_iter_create(g_hndl)) == NULL)
15764 			scfdie();
15765 
15766 		if (scf_iter_scope_services(iter, cur_scope) != 0)
15767 			scfdie();
15768 
15769 		for (;;) {
15770 			r = scf_iter_next_service(iter, svc);
15771 			if (r == 0)
15772 				break;
15773 			if (r != 1)
15774 				scfdie();
15775 
15776 			if (scf_service_get_name(svc, buf,
15777 			    max_scf_name_len + 1) < 0)
15778 				scfdie();
15779 
15780 			if (strncmp(buf, arg1, len) == 0) {
15781 				err = cpl_add_completion(cpl, line, word_start,
15782 				    word_end, buf + len, "", " ");
15783 				if (err != 0)
15784 					break;
15785 			}
15786 		}
15787 
15788 		scf_iter_destroy(iter);
15789 		scf_service_destroy(svc);
15790 
15791 		return (err);
15792 	}
15793 }
15794 
15795 /* ARGSUSED */
15796 CPL_MATCH_FN(complete_command)
15797 {
15798 	uint32_t scope = 0;
15799 
15800 	if (cur_snap != NULL)
15801 		scope = CS_SNAP;
15802 	else if (cur_inst != NULL)
15803 		scope = CS_INST;
15804 	else if (cur_svc != NULL)
15805 		scope = CS_SVC;
15806 	else
15807 		scope = CS_SCOPE;
15808 
15809 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
15810 }
15811 #endif	/* NATIVE_BUILD */
15812