xref: /illumos-gate/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision bf5d9f18edeb77c14df996d367853599bdd43fd1)
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 (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2015 Joyent, Inc.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  * Copyright 2017 RackTop Systems.
27  */
28 
29 
30 #include <alloca.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <door.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <fnmatch.h>
37 #include <inttypes.h>
38 #include <libintl.h>
39 #include <libnvpair.h>
40 #include <libscf.h>
41 #include <libscf_priv.h>
42 #include <libtecla.h>
43 #include <libuutil.h>
44 #include <limits.h>
45 #include <locale.h>
46 #include <stdarg.h>
47 #include <string.h>
48 #include <strings.h>
49 #include <time.h>
50 #include <unistd.h>
51 #include <wait.h>
52 #include <poll.h>
53 
54 #include <libxml/tree.h>
55 
56 #include <sys/param.h>
57 
58 #include <sys/stat.h>
59 #include <sys/mman.h>
60 
61 #include "svccfg.h"
62 #include "notify_params.h"
63 #include "manifest_hash.h"
64 #include "manifest_find.h"
65 
66 /* The colon namespaces in each entity (each followed by a newline). */
67 #define	COLON_NAMESPACES	":properties\n"
68 
69 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
70 
71 /* These are characters which the lexer requires to be in double-quotes. */
72 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
73 
74 #define	HASH_SIZE		16
75 #define	HASH_PG_TYPE		"framework"
76 #define	HASH_PG_FLAGS		0
77 #define	HASH_PROP		"md5sum"
78 
79 /*
80  * Indentation used in the output of the describe subcommand.
81  */
82 #define	TMPL_VALUE_INDENT	"  "
83 #define	TMPL_INDENT		"    "
84 #define	TMPL_INDENT_2X		"        "
85 #define	TMPL_CHOICE_INDENT	"      "
86 
87 /*
88  * Directory locations for manifests
89  */
90 #define	VARSVC_DIR		"/var/svc/manifest"
91 #define	LIBSVC_DIR		"/lib/svc/manifest"
92 #define	VARSVC_PR		"var_svc_manifest"
93 #define	LIBSVC_PR		"lib_svc_manifest"
94 #define	MFSTFILEPR		"manifestfile"
95 
96 #define	SUPPORTPROP		"support"
97 
98 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
99 
100 #define	MFSTFILE_MAX		16
101 
102 /*
103  * These are the classes of elements which may appear as children of service
104  * or instance elements in XML manifests.
105  */
106 struct entity_elts {
107 	xmlNodePtr	create_default_instance;
108 	xmlNodePtr	single_instance;
109 	xmlNodePtr	restarter;
110 	xmlNodePtr	dependencies;
111 	xmlNodePtr	dependents;
112 	xmlNodePtr	method_context;
113 	xmlNodePtr	exec_methods;
114 	xmlNodePtr	notify_params;
115 	xmlNodePtr	property_groups;
116 	xmlNodePtr	instances;
117 	xmlNodePtr	stability;
118 	xmlNodePtr	template;
119 };
120 
121 /*
122  * Likewise for property_group elements.
123  */
124 struct pg_elts {
125 	xmlNodePtr	stability;
126 	xmlNodePtr	propvals;
127 	xmlNodePtr	properties;
128 };
129 
130 /*
131  * Likewise for template elements.
132  */
133 struct template_elts {
134 	xmlNodePtr	common_name;
135 	xmlNodePtr	description;
136 	xmlNodePtr	documentation;
137 };
138 
139 /*
140  * Likewise for type (for notification parameters) elements.
141  */
142 struct params_elts {
143 	xmlNodePtr	paramval;
144 	xmlNodePtr	parameter;
145 };
146 
147 /*
148  * This structure is for snaplevel lists.  They are convenient because libscf
149  * only allows traversing snaplevels in one direction.
150  */
151 struct snaplevel {
152 	uu_list_node_t	list_node;
153 	scf_snaplevel_t	*sl;
154 };
155 
156 /*
157  * This is used for communication between lscf_service_export and
158  * export_callback.
159  */
160 struct export_args {
161 	const char	*filename;
162 	int 		flags;
163 };
164 
165 /*
166  * The service_manifest structure is used by the upgrade process
167  * to create a list of service to manifest linkages from the manifests
168  * in a set of given directories.
169  */
170 typedef struct service_manifest {
171 	const char 	*servicename;
172 	uu_list_t	*mfstlist;
173 	size_t	mfstlist_sz;
174 
175 	uu_avl_node_t	svcmfst_node;
176 } service_manifest_t;
177 
178 /*
179  * Structure to track the manifest file property group
180  * and the manifest file associated with that property
181  * group.  Also, a flag to keep the access once it has
182  * been checked.
183  */
184 struct mpg_mfile {
185 	char	*mpg;
186 	char	*mfile;
187 	int	access;
188 };
189 
190 const char * const scf_pg_general = SCF_PG_GENERAL;
191 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
192 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
193 const char * const scf_property_external = "external";
194 
195 const char * const snap_initial = "initial";
196 const char * const snap_lastimport = "last-import";
197 const char * const snap_previous = "previous";
198 const char * const snap_running = "running";
199 
200 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
201 
202 ssize_t max_scf_fmri_len;
203 ssize_t max_scf_name_len;
204 ssize_t max_scf_pg_type_len;
205 ssize_t max_scf_value_len;
206 static size_t max_scf_len;
207 
208 static scf_scope_t *cur_scope;
209 static scf_service_t *cur_svc = NULL;
210 static scf_instance_t *cur_inst = NULL;
211 static scf_snapshot_t *cur_snap = NULL;
212 static scf_snaplevel_t *cur_level = NULL;
213 
214 static uu_list_pool_t *snaplevel_pool;
215 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
216 static uu_list_t *cur_levels;
217 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
218 
219 static FILE *tempfile = NULL;
220 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
221 
222 static const char *emsg_entity_not_selected;
223 static const char *emsg_permission_denied;
224 static const char *emsg_create_xml;
225 static const char *emsg_cant_modify_snapshots;
226 static const char *emsg_invalid_for_snapshot;
227 static const char *emsg_read_only;
228 static const char *emsg_deleted;
229 static const char *emsg_invalid_pg_name;
230 static const char *emsg_invalid_prop_name;
231 static const char *emsg_no_such_pg;
232 static const char *emsg_fmri_invalid_pg_name;
233 static const char *emsg_fmri_invalid_pg_name_type;
234 static const char *emsg_pg_added;
235 static const char *emsg_pg_changed;
236 static const char *emsg_pg_deleted;
237 static const char *emsg_pg_mod_perm;
238 static const char *emsg_pg_add_perm;
239 static const char *emsg_pg_del_perm;
240 static const char *emsg_snap_perm;
241 static const char *emsg_dpt_dangling;
242 static const char *emsg_dpt_no_dep;
243 
244 static int li_only = 0;
245 static int no_refresh = 0;
246 
247 /* how long in ns we should wait between checks for a pg */
248 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
249 
250 /* import globals, to minimize allocations */
251 static scf_scope_t *imp_scope = NULL;
252 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
253 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
254 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
255 static scf_snapshot_t *imp_rsnap = NULL;
256 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
257 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
258 static scf_property_t *imp_prop = NULL;
259 static scf_iter_t *imp_iter = NULL;
260 static scf_iter_t *imp_rpg_iter = NULL;
261 static scf_iter_t *imp_up_iter = NULL;
262 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
263 static char *imp_str = NULL;
264 static size_t imp_str_sz;
265 static char *imp_tsname = NULL;
266 static char *imp_fe1 = NULL;		/* for fmri_equal() */
267 static char *imp_fe2 = NULL;
268 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
269 
270 /* upgrade_dependents() globals */
271 static scf_instance_t *ud_inst = NULL;
272 static scf_snaplevel_t *ud_snpl = NULL;
273 static scf_propertygroup_t *ud_pg = NULL;
274 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
275 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
276 static int ud_run_dpts_pg_set = 0;
277 static scf_property_t *ud_prop = NULL;
278 static scf_property_t *ud_dpt_prop = NULL;
279 static scf_value_t *ud_val = NULL;
280 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
281 static scf_transaction_t *ud_tx = NULL;
282 static char *ud_ctarg = NULL;
283 static char *ud_oldtarg = NULL;
284 static char *ud_name = NULL;
285 
286 /* export globals */
287 static scf_instance_t *exp_inst;
288 static scf_propertygroup_t *exp_pg;
289 static scf_property_t *exp_prop;
290 static scf_value_t *exp_val;
291 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
292 static char *exp_str;
293 static size_t exp_str_sz;
294 
295 /* cleanup globals */
296 static uu_avl_pool_t *service_manifest_pool = NULL;
297 static uu_avl_t *service_manifest_tree = NULL;
298 
299 static void scfdie_lineno(int lineno) __NORETURN;
300 
301 static char *start_method_names[] = {
302 	"start",
303 	"inetd_start",
304 	NULL
305 };
306 
307 static struct uri_scheme {
308 	const char *scheme;
309 	const char *protocol;
310 } uri_scheme[] = {
311 	{ "mailto", "smtp" },
312 	{ "snmp", "snmp" },
313 	{ "syslog", "syslog" },
314 	{ NULL, NULL }
315 };
316 #define	URI_SCHEME_NUM ((sizeof (uri_scheme) / \
317     sizeof (struct uri_scheme)) - 1)
318 
319 static int
320 check_uri_scheme(const char *scheme)
321 {
322 	int i;
323 
324 	for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
325 		if (strcmp(scheme, uri_scheme[i].scheme) == 0)
326 			return (i);
327 	}
328 
329 	return (-1);
330 }
331 
332 static int
333 check_uri_protocol(const char *p)
334 {
335 	int i;
336 
337 	for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
338 		if (strcmp(p, uri_scheme[i].protocol) == 0)
339 			return (i);
340 	}
341 
342 	return (-1);
343 }
344 
345 /*
346  * For unexpected libscf errors.
347  */
348 #ifdef NDEBUG
349 
350 static void scfdie(void) __NORETURN;
351 
352 static void
353 scfdie(void)
354 {
355 	scf_error_t err = scf_error();
356 
357 	if (err == SCF_ERROR_CONNECTION_BROKEN)
358 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
359 
360 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
361 	    scf_strerror(err));
362 }
363 
364 #else
365 
366 #define	scfdie()	scfdie_lineno(__LINE__)
367 
368 static void
369 scfdie_lineno(int lineno)
370 {
371 	scf_error_t err = scf_error();
372 
373 	if (err == SCF_ERROR_CONNECTION_BROKEN)
374 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
375 
376 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
377 	    ": %s.\n"), lineno, scf_strerror(err));
378 }
379 
380 #endif
381 
382 static void
383 scfwarn(void)
384 {
385 	warn(gettext("Unexpected libscf error: %s.\n"),
386 	    scf_strerror(scf_error()));
387 }
388 
389 /*
390  * Clear a field of a structure.
391  */
392 static int
393 clear_int(void *a, void *b)
394 {
395 	/* LINTED */
396 	*(int *)((char *)a + (size_t)b) = 0;
397 
398 	return (UU_WALK_NEXT);
399 }
400 
401 static int
402 scferror2errno(scf_error_t err)
403 {
404 	switch (err) {
405 	case SCF_ERROR_BACKEND_ACCESS:
406 		return (EACCES);
407 
408 	case SCF_ERROR_BACKEND_READONLY:
409 		return (EROFS);
410 
411 	case SCF_ERROR_CONNECTION_BROKEN:
412 		return (ECONNABORTED);
413 
414 	case SCF_ERROR_CONSTRAINT_VIOLATED:
415 	case SCF_ERROR_INVALID_ARGUMENT:
416 		return (EINVAL);
417 
418 	case SCF_ERROR_DELETED:
419 		return (ECANCELED);
420 
421 	case SCF_ERROR_EXISTS:
422 		return (EEXIST);
423 
424 	case SCF_ERROR_NO_MEMORY:
425 		return (ENOMEM);
426 
427 	case SCF_ERROR_NO_RESOURCES:
428 		return (ENOSPC);
429 
430 	case SCF_ERROR_NOT_FOUND:
431 		return (ENOENT);
432 
433 	case SCF_ERROR_PERMISSION_DENIED:
434 		return (EPERM);
435 
436 	default:
437 #ifndef NDEBUG
438 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
439 		    __FILE__, __LINE__, err);
440 #else
441 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
442 #endif
443 		abort();
444 		/* NOTREACHED */
445 	}
446 }
447 
448 static int
449 entity_get_pg(void *ent, int issvc, const char *name,
450     scf_propertygroup_t *pg)
451 {
452 	if (issvc)
453 		return (scf_service_get_pg(ent, name, pg));
454 	else
455 		return (scf_instance_get_pg(ent, name, pg));
456 }
457 
458 static void
459 entity_destroy(void *ent, int issvc)
460 {
461 	if (issvc)
462 		scf_service_destroy(ent);
463 	else
464 		scf_instance_destroy(ent);
465 }
466 
467 static int
468 get_pg(const char *pg_name, scf_propertygroup_t *pg)
469 {
470 	int ret;
471 
472 	if (cur_level != NULL)
473 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
474 	else if (cur_inst != NULL)
475 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
476 	else
477 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
478 
479 	return (ret);
480 }
481 
482 /*
483  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
484  * snaplevel.  Otherwise find the instance snaplevel.
485  *
486  * Returns
487  *   0 - success
488  *   ECONNABORTED - repository connection broken
489  *   ECANCELED - instance containing snap was deleted
490  *   ENOENT - snap has no snaplevels
491  *	    - requested snaplevel not found
492  */
493 static int
494 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
495 {
496 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
497 		switch (scf_error()) {
498 		case SCF_ERROR_CONNECTION_BROKEN:
499 		case SCF_ERROR_DELETED:
500 		case SCF_ERROR_NOT_FOUND:
501 			return (scferror2errno(scf_error()));
502 
503 		case SCF_ERROR_HANDLE_MISMATCH:
504 		case SCF_ERROR_NOT_BOUND:
505 		case SCF_ERROR_NOT_SET:
506 		default:
507 			bad_error("scf_snapshot_get_base_snaplevel",
508 			    scf_error());
509 		}
510 	}
511 
512 	for (;;) {
513 		ssize_t ssz;
514 
515 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
516 		if (ssz >= 0) {
517 			if (!get_svc)
518 				return (0);
519 		} else {
520 			switch (scf_error()) {
521 			case SCF_ERROR_CONSTRAINT_VIOLATED:
522 				if (get_svc)
523 					return (0);
524 				break;
525 
526 			case SCF_ERROR_DELETED:
527 			case SCF_ERROR_CONNECTION_BROKEN:
528 				return (scferror2errno(scf_error()));
529 
530 			case SCF_ERROR_NOT_SET:
531 			case SCF_ERROR_NOT_BOUND:
532 			default:
533 				bad_error("scf_snaplevel_get_instance_name",
534 				    scf_error());
535 			}
536 		}
537 
538 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
539 			switch (scf_error()) {
540 			case SCF_ERROR_NOT_FOUND:
541 			case SCF_ERROR_CONNECTION_BROKEN:
542 			case SCF_ERROR_DELETED:
543 				return (scferror2errno(scf_error()));
544 
545 			case SCF_ERROR_HANDLE_MISMATCH:
546 			case SCF_ERROR_NOT_BOUND:
547 			case SCF_ERROR_NOT_SET:
548 			case SCF_ERROR_INVALID_ARGUMENT:
549 			default:
550 				bad_error("scf_snaplevel_get_next_snaplevel",
551 				    scf_error());
552 			}
553 		}
554 	}
555 }
556 
557 /*
558  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
559  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
560  * the property group named name in it.  If it doesn't have a running
561  * snapshot, set pg to the instance's current property group named name.
562  *
563  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
564  * its instances.  If one has a running snapshot with a service snaplevel, set
565  * pg to the property group named name in it.  If no such snaplevel could be
566  * found, set pg to the service's current property group named name.
567  *
568  * iter, inst, snap, and snpl are required scratch objects.
569  *
570  * Returns
571  *   0 - success
572  *   ECONNABORTED - repository connection broken
573  *   ECANCELED - ent was deleted
574  *   ENOENT - no such property group
575  *   EINVAL - name is an invalid property group name
576  *   EBADF - found running snapshot is missing a snaplevel
577  */
578 static int
579 entity_get_running_pg(void *ent, int issvc, const char *name,
580     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
581     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
582 {
583 	int r;
584 
585 	if (issvc) {
586 		/* Search for an instance with a running snapshot. */
587 		if (scf_iter_service_instances(iter, ent) != 0) {
588 			switch (scf_error()) {
589 			case SCF_ERROR_DELETED:
590 			case SCF_ERROR_CONNECTION_BROKEN:
591 				return (scferror2errno(scf_error()));
592 
593 			case SCF_ERROR_NOT_SET:
594 			case SCF_ERROR_NOT_BOUND:
595 			case SCF_ERROR_HANDLE_MISMATCH:
596 			default:
597 				bad_error("scf_iter_service_instances",
598 				    scf_error());
599 			}
600 		}
601 
602 		for (;;) {
603 			r = scf_iter_next_instance(iter, inst);
604 			if (r == 0) {
605 				if (scf_service_get_pg(ent, name, pg) == 0)
606 					return (0);
607 
608 				switch (scf_error()) {
609 				case SCF_ERROR_DELETED:
610 				case SCF_ERROR_NOT_FOUND:
611 				case SCF_ERROR_INVALID_ARGUMENT:
612 				case SCF_ERROR_CONNECTION_BROKEN:
613 					return (scferror2errno(scf_error()));
614 
615 				case SCF_ERROR_NOT_BOUND:
616 				case SCF_ERROR_HANDLE_MISMATCH:
617 				case SCF_ERROR_NOT_SET:
618 				default:
619 					bad_error("scf_service_get_pg",
620 					    scf_error());
621 				}
622 			}
623 			if (r != 1) {
624 				switch (scf_error()) {
625 				case SCF_ERROR_DELETED:
626 				case SCF_ERROR_CONNECTION_BROKEN:
627 					return (scferror2errno(scf_error()));
628 
629 				case SCF_ERROR_INVALID_ARGUMENT:
630 				case SCF_ERROR_NOT_SET:
631 				case SCF_ERROR_NOT_BOUND:
632 				case SCF_ERROR_HANDLE_MISMATCH:
633 				default:
634 					bad_error("scf_iter_next_instance",
635 					    scf_error());
636 				}
637 			}
638 
639 			if (scf_instance_get_snapshot(inst, snap_running,
640 			    snap) == 0)
641 				break;
642 
643 			switch (scf_error()) {
644 			case SCF_ERROR_NOT_FOUND:
645 			case SCF_ERROR_DELETED:
646 				continue;
647 
648 			case SCF_ERROR_CONNECTION_BROKEN:
649 				return (ECONNABORTED);
650 
651 			case SCF_ERROR_HANDLE_MISMATCH:
652 			case SCF_ERROR_INVALID_ARGUMENT:
653 			case SCF_ERROR_NOT_SET:
654 			case SCF_ERROR_NOT_BOUND:
655 			default:
656 				bad_error("scf_instance_get_snapshot",
657 				    scf_error());
658 			}
659 		}
660 	} else {
661 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
662 			switch (scf_error()) {
663 			case SCF_ERROR_NOT_FOUND:
664 				break;
665 
666 			case SCF_ERROR_DELETED:
667 			case SCF_ERROR_CONNECTION_BROKEN:
668 				return (scferror2errno(scf_error()));
669 
670 			case SCF_ERROR_NOT_BOUND:
671 			case SCF_ERROR_HANDLE_MISMATCH:
672 			case SCF_ERROR_INVALID_ARGUMENT:
673 			case SCF_ERROR_NOT_SET:
674 			default:
675 				bad_error("scf_instance_get_snapshot",
676 				    scf_error());
677 			}
678 
679 			if (scf_instance_get_pg(ent, name, pg) == 0)
680 				return (0);
681 
682 			switch (scf_error()) {
683 			case SCF_ERROR_DELETED:
684 			case SCF_ERROR_NOT_FOUND:
685 			case SCF_ERROR_INVALID_ARGUMENT:
686 			case SCF_ERROR_CONNECTION_BROKEN:
687 				return (scferror2errno(scf_error()));
688 
689 			case SCF_ERROR_NOT_BOUND:
690 			case SCF_ERROR_HANDLE_MISMATCH:
691 			case SCF_ERROR_NOT_SET:
692 			default:
693 				bad_error("scf_instance_get_pg", scf_error());
694 			}
695 		}
696 	}
697 
698 	r = get_snaplevel(snap, issvc, snpl);
699 	switch (r) {
700 	case 0:
701 		break;
702 
703 	case ECONNABORTED:
704 	case ECANCELED:
705 		return (r);
706 
707 	case ENOENT:
708 		return (EBADF);
709 
710 	default:
711 		bad_error("get_snaplevel", r);
712 	}
713 
714 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
715 		return (0);
716 
717 	switch (scf_error()) {
718 	case SCF_ERROR_DELETED:
719 	case SCF_ERROR_INVALID_ARGUMENT:
720 	case SCF_ERROR_CONNECTION_BROKEN:
721 	case SCF_ERROR_NOT_FOUND:
722 		return (scferror2errno(scf_error()));
723 
724 	case SCF_ERROR_NOT_BOUND:
725 	case SCF_ERROR_HANDLE_MISMATCH:
726 	case SCF_ERROR_NOT_SET:
727 	default:
728 		bad_error("scf_snaplevel_get_pg", scf_error());
729 		/* NOTREACHED */
730 	}
731 }
732 
733 /*
734  * To be registered with atexit().
735  */
736 static void
737 remove_tempfile(void)
738 {
739 	int ret;
740 
741 	if (tempfile != NULL) {
742 		if (fclose(tempfile) == EOF)
743 			(void) warn(gettext("Could not close temporary file"));
744 		tempfile = NULL;
745 	}
746 
747 	if (tempfilename[0] != '\0') {
748 		do {
749 			ret = remove(tempfilename);
750 		} while (ret == -1 && errno == EINTR);
751 		if (ret == -1)
752 			warn(gettext("Could not remove temporary file"));
753 		tempfilename[0] = '\0';
754 	}
755 }
756 
757 /*
758  * Launch private svc.configd(1M) for manipulating alternate repositories.
759  */
760 static void
761 start_private_repository(engine_state_t *est)
762 {
763 	int fd, stat;
764 	struct door_info info;
765 	pid_t pid;
766 
767 	/*
768 	 * 1.  Create a temporary file for the door.
769 	 */
770 	if (est->sc_repo_doorname != NULL)
771 		free((void *)est->sc_repo_doorname);
772 
773 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
774 	if (est->sc_repo_doorname == NULL)
775 		uu_die(gettext("Could not acquire temporary filename"));
776 
777 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
778 	if (fd < 0)
779 		uu_die(gettext("Could not create temporary file for "
780 		    "repository server"));
781 
782 	(void) close(fd);
783 
784 	/*
785 	 * 2.  Launch a configd with that door, using the specified
786 	 * repository.
787 	 */
788 	if ((est->sc_repo_pid = fork()) == 0) {
789 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
790 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
791 		    NULL);
792 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
793 	} else if (est->sc_repo_pid == -1)
794 		uu_die(gettext("Attempt to fork failed"));
795 
796 	do {
797 		pid = waitpid(est->sc_repo_pid, &stat, 0);
798 	} while (pid == -1 && errno == EINTR);
799 
800 	if (pid == -1)
801 		uu_die(gettext("Could not waitpid() for repository server"));
802 
803 	if (!WIFEXITED(stat)) {
804 		uu_die(gettext("Repository server failed (status %d).\n"),
805 		    stat);
806 	} else if (WEXITSTATUS(stat) != 0) {
807 		uu_die(gettext("Repository server failed (exit %d).\n"),
808 		    WEXITSTATUS(stat));
809 	}
810 
811 	/*
812 	 * See if it was successful by checking if the door is a door.
813 	 */
814 
815 	fd = open(est->sc_repo_doorname, O_RDWR);
816 	if (fd < 0)
817 		uu_die(gettext("Could not open door \"%s\""),
818 		    est->sc_repo_doorname);
819 
820 	if (door_info(fd, &info) < 0)
821 		uu_die(gettext("Unexpected door_info() error"));
822 
823 	if (close(fd) == -1)
824 		warn(gettext("Could not close repository door"),
825 		    strerror(errno));
826 
827 	est->sc_repo_pid = info.di_target;
828 }
829 
830 void
831 lscf_cleanup(void)
832 {
833 	/*
834 	 * In the case where we've launched a private svc.configd(1M)
835 	 * instance, we must terminate our child and remove the temporary
836 	 * rendezvous point.
837 	 */
838 	if (est->sc_repo_pid > 0) {
839 		(void) kill(est->sc_repo_pid, SIGTERM);
840 		(void) waitpid(est->sc_repo_pid, NULL, 0);
841 		(void) unlink(est->sc_repo_doorname);
842 
843 		est->sc_repo_pid = 0;
844 	}
845 }
846 
847 void
848 unselect_cursnap(void)
849 {
850 	void *cookie;
851 
852 	cur_level = NULL;
853 
854 	cookie = NULL;
855 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
856 		scf_snaplevel_destroy(cur_elt->sl);
857 		free(cur_elt);
858 	}
859 
860 	scf_snapshot_destroy(cur_snap);
861 	cur_snap = NULL;
862 }
863 
864 void
865 lscf_prep_hndl(void)
866 {
867 	if (g_hndl != NULL)
868 		return;
869 
870 	g_hndl = scf_handle_create(SCF_VERSION);
871 	if (g_hndl == NULL)
872 		scfdie();
873 
874 	if (est->sc_repo_filename != NULL)
875 		start_private_repository(est);
876 
877 	if (est->sc_repo_doorname != NULL) {
878 		scf_value_t *repo_value;
879 		int ret;
880 
881 		repo_value = scf_value_create(g_hndl);
882 		if (repo_value == NULL)
883 			scfdie();
884 
885 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
886 		assert(ret == SCF_SUCCESS);
887 
888 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
889 		    SCF_SUCCESS)
890 			scfdie();
891 
892 		scf_value_destroy(repo_value);
893 	}
894 
895 	if (scf_handle_bind(g_hndl) != 0)
896 		uu_die(gettext("Could not connect to repository server: %s.\n"),
897 		    scf_strerror(scf_error()));
898 
899 	cur_scope = scf_scope_create(g_hndl);
900 	if (cur_scope == NULL)
901 		scfdie();
902 
903 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
904 		scfdie();
905 }
906 
907 static void
908 repository_teardown(void)
909 {
910 	if (g_hndl != NULL) {
911 		if (cur_snap != NULL)
912 			unselect_cursnap();
913 		scf_instance_destroy(cur_inst);
914 		scf_service_destroy(cur_svc);
915 		scf_scope_destroy(cur_scope);
916 		scf_handle_destroy(g_hndl);
917 		cur_inst = NULL;
918 		cur_svc = NULL;
919 		cur_scope = NULL;
920 		g_hndl = NULL;
921 		lscf_cleanup();
922 	}
923 }
924 
925 void
926 lscf_set_repository(const char *repfile, int force)
927 {
928 	repository_teardown();
929 
930 	if (est->sc_repo_filename != NULL) {
931 		free((void *)est->sc_repo_filename);
932 		est->sc_repo_filename = NULL;
933 	}
934 
935 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
936 		/*
937 		 * Repository file does not exist
938 		 * or has no read permission.
939 		 */
940 		warn(gettext("Cannot access \"%s\": %s\n"),
941 		    repfile, strerror(errno));
942 	} else {
943 		est->sc_repo_filename = safe_strdup(repfile);
944 	}
945 
946 	lscf_prep_hndl();
947 }
948 
949 void
950 lscf_init()
951 {
952 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
953 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
954 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
955 	    0 ||
956 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
957 		scfdie();
958 
959 	max_scf_len = max_scf_fmri_len;
960 	if (max_scf_name_len > max_scf_len)
961 		max_scf_len = max_scf_name_len;
962 	if (max_scf_pg_type_len > max_scf_len)
963 		max_scf_len = max_scf_pg_type_len;
964 	/*
965 	 * When a value of type opaque is represented as a string, the
966 	 * string contains 2 characters for every byte of data.  That is
967 	 * because the string contains the hex representation of the opaque
968 	 * value.
969 	 */
970 	if (2 * max_scf_value_len > max_scf_len)
971 		max_scf_len = 2 * max_scf_value_len;
972 
973 	if (atexit(remove_tempfile) != 0)
974 		uu_die(gettext("Could not register atexit() function"));
975 
976 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
977 	emsg_permission_denied = gettext("Permission denied.\n");
978 	emsg_create_xml = gettext("Could not create XML node.\n");
979 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
980 	emsg_invalid_for_snapshot =
981 	    gettext("Invalid operation on a snapshot.\n");
982 	emsg_read_only = gettext("Backend read-only.\n");
983 	emsg_deleted = gettext("Current selection has been deleted.\n");
984 	emsg_invalid_pg_name =
985 	    gettext("Invalid property group name \"%s\".\n");
986 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
987 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
988 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
989 	    "with invalid name \"%s\".\n");
990 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
991 	    "group with invalid name \"%s\" or type \"%s\".\n");
992 	emsg_pg_added = gettext("%s changed unexpectedly "
993 	    "(property group \"%s\" added).\n");
994 	emsg_pg_changed = gettext("%s changed unexpectedly "
995 	    "(property group \"%s\" changed).\n");
996 	emsg_pg_deleted = gettext("%s changed unexpectedly "
997 	    "(property group \"%s\" or an ancestor was deleted).\n");
998 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
999 	    "in %s (permission denied).\n");
1000 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1001 	    "in %s (permission denied).\n");
1002 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1003 	    "in %s (permission denied).\n");
1004 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1005 	    "(permission denied).\n");
1006 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1007 	    "new dependent \"%s\" because it already exists).  Warning: The "
1008 	    "current dependent's target (%s) does not exist.\n");
1009 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1010 	    "dependent \"%s\" because it already exists).  Warning: The "
1011 	    "current dependent's target (%s) does not have a dependency named "
1012 	    "\"%s\" as expected.\n");
1013 
1014 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1015 	    offsetof(string_list_t, node), NULL, 0);
1016 	snaplevel_pool = uu_list_pool_create("snaplevels",
1017 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1018 	    NULL, 0);
1019 }
1020 
1021 
1022 static const char *
1023 prop_to_typestr(const scf_property_t *prop)
1024 {
1025 	scf_type_t ty;
1026 
1027 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1028 		scfdie();
1029 
1030 	return (scf_type_to_string(ty));
1031 }
1032 
1033 static scf_type_t
1034 string_to_type(const char *type)
1035 {
1036 	size_t len = strlen(type);
1037 	char *buf;
1038 
1039 	if (len == 0 || type[len - 1] != ':')
1040 		return (SCF_TYPE_INVALID);
1041 
1042 	buf = (char *)alloca(len + 1);
1043 	(void) strlcpy(buf, type, len + 1);
1044 	buf[len - 1] = 0;
1045 
1046 	return (scf_string_to_type(buf));
1047 }
1048 
1049 static scf_value_t *
1050 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1051 {
1052 	scf_value_t *v;
1053 	char *dup, *nstr;
1054 	size_t len;
1055 
1056 	v = scf_value_create(g_hndl);
1057 	if (v == NULL)
1058 		scfdie();
1059 
1060 	len = strlen(str);
1061 	if (require_quotes &&
1062 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1063 		semerr(gettext("Multiple string values or string values "
1064 		    "with spaces must be quoted with '\"'.\n"));
1065 		scf_value_destroy(v);
1066 		return (NULL);
1067 	}
1068 
1069 	nstr = dup = safe_strdup(str);
1070 	if (dup[0] == '\"') {
1071 		/*
1072 		 * Strip out the first and the last quote.
1073 		 */
1074 		dup[len - 1] = '\0';
1075 		nstr = dup + 1;
1076 	}
1077 
1078 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1079 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1080 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1081 		    scf_type_to_string(ty), nstr);
1082 		scf_value_destroy(v);
1083 		v = NULL;
1084 	}
1085 	free(dup);
1086 	return (v);
1087 }
1088 
1089 /*
1090  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1091  * Optionally append a comment prefix ('#') to newlines ('\n').
1092  */
1093 static int
1094 quote_and_print(const char *str, FILE *strm, int commentnl)
1095 {
1096 	const char *cp;
1097 
1098 	for (cp = str; *cp != '\0'; ++cp) {
1099 		if (*cp == '"' || *cp == '\\')
1100 			(void) putc('\\', strm);
1101 
1102 		(void) putc(*cp, strm);
1103 
1104 		if (commentnl && *cp == '\n') {
1105 			(void) putc('#', strm);
1106 		}
1107 	}
1108 
1109 	return (ferror(strm));
1110 }
1111 
1112 /*
1113  * These wrappers around lowlevel functions provide consistent error checking
1114  * and warnings.
1115  */
1116 static int
1117 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1118 {
1119 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1120 		return (0);
1121 
1122 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1123 		scfdie();
1124 
1125 	if (g_verbose) {
1126 		ssize_t len;
1127 		char *fmri;
1128 
1129 		len = scf_pg_to_fmri(pg, NULL, 0);
1130 		if (len < 0)
1131 			scfdie();
1132 
1133 		fmri = safe_malloc(len + 1);
1134 
1135 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1136 			scfdie();
1137 
1138 		warn(gettext("Expected property %s of property group %s is "
1139 		    "missing.\n"), propname, fmri);
1140 
1141 		free(fmri);
1142 	}
1143 
1144 	return (-1);
1145 }
1146 
1147 static int
1148 prop_check_type(scf_property_t *prop, scf_type_t ty)
1149 {
1150 	scf_type_t pty;
1151 
1152 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1153 		scfdie();
1154 
1155 	if (ty == pty)
1156 		return (0);
1157 
1158 	if (g_verbose) {
1159 		ssize_t len;
1160 		char *fmri;
1161 		const char *tystr;
1162 
1163 		len = scf_property_to_fmri(prop, NULL, 0);
1164 		if (len < 0)
1165 			scfdie();
1166 
1167 		fmri = safe_malloc(len + 1);
1168 
1169 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1170 			scfdie();
1171 
1172 		tystr = scf_type_to_string(ty);
1173 		if (tystr == NULL)
1174 			tystr = "?";
1175 
1176 		warn(gettext("Property %s is not of expected type %s.\n"),
1177 		    fmri, tystr);
1178 
1179 		free(fmri);
1180 	}
1181 
1182 	return (-1);
1183 }
1184 
1185 static int
1186 prop_get_val(scf_property_t *prop, scf_value_t *val)
1187 {
1188 	scf_error_t err;
1189 
1190 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1191 		return (0);
1192 
1193 	err = scf_error();
1194 
1195 	if (err != SCF_ERROR_NOT_FOUND &&
1196 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1197 	    err != SCF_ERROR_PERMISSION_DENIED)
1198 		scfdie();
1199 
1200 	if (g_verbose) {
1201 		ssize_t len;
1202 		char *fmri, *emsg;
1203 
1204 		len = scf_property_to_fmri(prop, NULL, 0);
1205 		if (len < 0)
1206 			scfdie();
1207 
1208 		fmri = safe_malloc(len + 1);
1209 
1210 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1211 			scfdie();
1212 
1213 		if (err == SCF_ERROR_NOT_FOUND)
1214 			emsg = gettext("Property %s has no values; expected "
1215 			    "one.\n");
1216 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1217 			emsg = gettext("Property %s has multiple values; "
1218 			    "expected one.\n");
1219 		else
1220 			emsg = gettext("No permission to read property %s.\n");
1221 
1222 		warn(emsg, fmri);
1223 
1224 		free(fmri);
1225 	}
1226 
1227 	return (-1);
1228 }
1229 
1230 
1231 static boolean_t
1232 snaplevel_is_instance(const scf_snaplevel_t *level)
1233 {
1234 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1235 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1236 			scfdie();
1237 		return (0);
1238 	} else {
1239 		return (1);
1240 	}
1241 }
1242 
1243 /*
1244  * Decode FMRI into a service or instance, and put the result in *ep.  If
1245  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1246  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1247  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1248  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1249  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1250  * whether *ep is a service.
1251  */
1252 static scf_error_t
1253 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1254 {
1255 	char *fmri_copy;
1256 	const char *sstr, *istr, *pgstr;
1257 	scf_service_t *svc;
1258 	scf_instance_t *inst;
1259 
1260 	fmri_copy = strdup(fmri);
1261 	if (fmri_copy == NULL)
1262 		return (SCF_ERROR_NO_MEMORY);
1263 
1264 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1265 	    SCF_SUCCESS) {
1266 		free(fmri_copy);
1267 		return (SCF_ERROR_INVALID_ARGUMENT);
1268 	}
1269 
1270 	free(fmri_copy);
1271 
1272 	if (sstr == NULL || pgstr != NULL)
1273 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1274 
1275 	if (istr == NULL) {
1276 		svc = scf_service_create(h);
1277 		if (svc == NULL)
1278 			return (SCF_ERROR_NO_MEMORY);
1279 
1280 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1281 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1282 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1283 				scfdie();
1284 
1285 			return (SCF_ERROR_NOT_FOUND);
1286 		}
1287 
1288 		*ep = svc;
1289 		*isservice = 1;
1290 	} else {
1291 		inst = scf_instance_create(h);
1292 		if (inst == NULL)
1293 			return (SCF_ERROR_NO_MEMORY);
1294 
1295 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1296 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1297 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1298 				scfdie();
1299 
1300 			return (SCF_ERROR_NOT_FOUND);
1301 		}
1302 
1303 		*ep = inst;
1304 		*isservice = 0;
1305 	}
1306 
1307 	return (SCF_ERROR_NONE);
1308 }
1309 
1310 /*
1311  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1312  * *ep, and set or clear *isservicep if it is a service or an instance.
1313  * Returns
1314  *   SCF_ERROR_NONE - success
1315  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1316  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1317  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1318  *   SCF_ERROR_NOT_FOUND - no such scope
1319  *   SCF_ERROR_PERMISSION_DENIED
1320  *   SCF_ERROR_BACKEND_READONLY
1321  *   SCF_ERROR_BACKEND_ACCESS
1322  */
1323 static scf_error_t
1324 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1325 {
1326 	char *fmri_copy;
1327 	const char *scstr, *sstr, *istr, *pgstr;
1328 	scf_scope_t *scope = NULL;
1329 	scf_service_t *svc = NULL;
1330 	scf_instance_t *inst = NULL;
1331 	scf_error_t scfe;
1332 
1333 	fmri_copy = safe_strdup(fmri);
1334 
1335 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1336 	    0) {
1337 		free(fmri_copy);
1338 		return (SCF_ERROR_INVALID_ARGUMENT);
1339 	}
1340 
1341 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1342 		free(fmri_copy);
1343 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1344 	}
1345 
1346 	*ep = NULL;
1347 
1348 	if ((scope = scf_scope_create(h)) == NULL ||
1349 	    (svc = scf_service_create(h)) == NULL ||
1350 	    (inst = scf_instance_create(h)) == NULL) {
1351 		scfe = SCF_ERROR_NO_MEMORY;
1352 		goto out;
1353 	}
1354 
1355 get_scope:
1356 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1357 		switch (scf_error()) {
1358 		case SCF_ERROR_CONNECTION_BROKEN:
1359 			scfdie();
1360 			/* NOTREACHED */
1361 
1362 		case SCF_ERROR_NOT_FOUND:
1363 			scfe = SCF_ERROR_NOT_FOUND;
1364 			goto out;
1365 
1366 		case SCF_ERROR_HANDLE_MISMATCH:
1367 		case SCF_ERROR_NOT_BOUND:
1368 		case SCF_ERROR_INVALID_ARGUMENT:
1369 		default:
1370 			bad_error("scf_handle_get_scope", scf_error());
1371 		}
1372 	}
1373 
1374 get_svc:
1375 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1376 		switch (scf_error()) {
1377 		case SCF_ERROR_CONNECTION_BROKEN:
1378 			scfdie();
1379 			/* NOTREACHED */
1380 
1381 		case SCF_ERROR_DELETED:
1382 			goto get_scope;
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_scope_get_service", scf_error());
1393 		}
1394 
1395 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1396 			switch (scf_error()) {
1397 			case SCF_ERROR_CONNECTION_BROKEN:
1398 				scfdie();
1399 				/* NOTREACHED */
1400 
1401 			case SCF_ERROR_DELETED:
1402 				goto get_scope;
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_scope_get_service", scf_error());
1416 			}
1417 		}
1418 	}
1419 
1420 	if (istr == NULL) {
1421 		scfe = SCF_ERROR_NONE;
1422 		*ep = svc;
1423 		*isservicep = 1;
1424 		goto out;
1425 	}
1426 
1427 get_inst:
1428 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1429 		switch (scf_error()) {
1430 		case SCF_ERROR_CONNECTION_BROKEN:
1431 			scfdie();
1432 			/* NOTREACHED */
1433 
1434 		case SCF_ERROR_DELETED:
1435 			goto get_svc;
1436 
1437 		case SCF_ERROR_NOT_FOUND:
1438 			break;
1439 
1440 		case SCF_ERROR_HANDLE_MISMATCH:
1441 		case SCF_ERROR_INVALID_ARGUMENT:
1442 		case SCF_ERROR_NOT_BOUND:
1443 		case SCF_ERROR_NOT_SET:
1444 		default:
1445 			bad_error("scf_service_get_instance", scf_error());
1446 		}
1447 
1448 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1449 			switch (scf_error()) {
1450 			case SCF_ERROR_CONNECTION_BROKEN:
1451 				scfdie();
1452 				/* NOTREACHED */
1453 
1454 			case SCF_ERROR_DELETED:
1455 				goto get_svc;
1456 
1457 			case SCF_ERROR_PERMISSION_DENIED:
1458 			case SCF_ERROR_BACKEND_READONLY:
1459 			case SCF_ERROR_BACKEND_ACCESS:
1460 				scfe = scf_error();
1461 				goto out;
1462 
1463 			case SCF_ERROR_HANDLE_MISMATCH:
1464 			case SCF_ERROR_INVALID_ARGUMENT:
1465 			case SCF_ERROR_NOT_BOUND:
1466 			case SCF_ERROR_NOT_SET:
1467 			default:
1468 				bad_error("scf_service_add_instance",
1469 				    scf_error());
1470 			}
1471 		}
1472 	}
1473 
1474 	scfe = SCF_ERROR_NONE;
1475 	*ep = inst;
1476 	*isservicep = 0;
1477 
1478 out:
1479 	if (*ep != inst)
1480 		scf_instance_destroy(inst);
1481 	if (*ep != svc)
1482 		scf_service_destroy(svc);
1483 	scf_scope_destroy(scope);
1484 	free(fmri_copy);
1485 	return (scfe);
1486 }
1487 
1488 /*
1489  * Create or update a snapshot of inst.  snap is a required scratch object.
1490  *
1491  * Returns
1492  *   0 - success
1493  *   ECONNABORTED - repository connection broken
1494  *   EPERM - permission denied
1495  *   ENOSPC - configd is out of resources
1496  *   ECANCELED - inst was deleted
1497  *   -1 - unknown libscf error (message printed)
1498  */
1499 static int
1500 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1501 {
1502 again:
1503 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1504 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1505 			switch (scf_error()) {
1506 			case SCF_ERROR_CONNECTION_BROKEN:
1507 			case SCF_ERROR_PERMISSION_DENIED:
1508 			case SCF_ERROR_NO_RESOURCES:
1509 				return (scferror2errno(scf_error()));
1510 
1511 			case SCF_ERROR_NOT_SET:
1512 			case SCF_ERROR_INVALID_ARGUMENT:
1513 			default:
1514 				bad_error("_scf_snapshot_take_attach",
1515 				    scf_error());
1516 			}
1517 		}
1518 	} else {
1519 		switch (scf_error()) {
1520 		case SCF_ERROR_NOT_FOUND:
1521 			break;
1522 
1523 		case SCF_ERROR_DELETED:
1524 		case SCF_ERROR_CONNECTION_BROKEN:
1525 			return (scferror2errno(scf_error()));
1526 
1527 		case SCF_ERROR_HANDLE_MISMATCH:
1528 		case SCF_ERROR_NOT_BOUND:
1529 		case SCF_ERROR_INVALID_ARGUMENT:
1530 		case SCF_ERROR_NOT_SET:
1531 		default:
1532 			bad_error("scf_instance_get_snapshot", scf_error());
1533 		}
1534 
1535 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1536 			switch (scf_error()) {
1537 			case SCF_ERROR_EXISTS:
1538 				goto again;
1539 
1540 			case SCF_ERROR_CONNECTION_BROKEN:
1541 			case SCF_ERROR_NO_RESOURCES:
1542 			case SCF_ERROR_PERMISSION_DENIED:
1543 				return (scferror2errno(scf_error()));
1544 
1545 			default:
1546 				scfwarn();
1547 				return (-1);
1548 
1549 			case SCF_ERROR_NOT_SET:
1550 			case SCF_ERROR_INTERNAL:
1551 			case SCF_ERROR_INVALID_ARGUMENT:
1552 			case SCF_ERROR_HANDLE_MISMATCH:
1553 				bad_error("_scf_snapshot_take_new",
1554 				    scf_error());
1555 			}
1556 		}
1557 	}
1558 
1559 	return (0);
1560 }
1561 
1562 static int
1563 refresh_running_snapshot(void *entity)
1564 {
1565 	scf_snapshot_t *snap;
1566 	int r;
1567 
1568 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1569 		scfdie();
1570 	r = take_snap(entity, snap_running, snap);
1571 	scf_snapshot_destroy(snap);
1572 
1573 	return (r);
1574 }
1575 
1576 /*
1577  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1578  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1579  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1580  * for scratch space.  Returns
1581  *   0 - success
1582  *   ECONNABORTED - repository connection broken
1583  *   ECANCELED - entity was deleted
1584  *   EACCES - backend denied access
1585  *   EPERM - permission denied
1586  *   ENOSPC - repository server out of resources
1587  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1588  */
1589 static int
1590 refresh_entity(int isservice, void *entity, const char *fmri,
1591     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1592 {
1593 	scf_error_t scfe;
1594 	int r;
1595 
1596 	if (!isservice) {
1597 		/*
1598 		 * Let restarter handles refreshing and making new running
1599 		 * snapshot only if operating on a live repository and not
1600 		 * running in early import.
1601 		 */
1602 		if (est->sc_repo_filename == NULL &&
1603 		    est->sc_repo_doorname == NULL &&
1604 		    est->sc_in_emi == 0) {
1605 			if (_smf_refresh_instance_i(entity) == 0) {
1606 				if (g_verbose)
1607 					warn(gettext("Refreshed %s.\n"), fmri);
1608 				return (0);
1609 			}
1610 
1611 			switch (scf_error()) {
1612 			case SCF_ERROR_BACKEND_ACCESS:
1613 				return (EACCES);
1614 
1615 			case SCF_ERROR_PERMISSION_DENIED:
1616 				return (EPERM);
1617 
1618 			default:
1619 				return (-1);
1620 			}
1621 		} else {
1622 			r = refresh_running_snapshot(entity);
1623 			switch (r) {
1624 			case 0:
1625 				break;
1626 
1627 			case ECONNABORTED:
1628 			case ECANCELED:
1629 			case EPERM:
1630 			case ENOSPC:
1631 				break;
1632 
1633 			default:
1634 				bad_error("refresh_running_snapshot",
1635 				    scf_error());
1636 			}
1637 
1638 			return (r);
1639 		}
1640 	}
1641 
1642 	if (scf_iter_service_instances(iter, entity) != 0) {
1643 		switch (scf_error()) {
1644 		case SCF_ERROR_CONNECTION_BROKEN:
1645 			return (ECONNABORTED);
1646 
1647 		case SCF_ERROR_DELETED:
1648 			return (ECANCELED);
1649 
1650 		case SCF_ERROR_HANDLE_MISMATCH:
1651 		case SCF_ERROR_NOT_BOUND:
1652 		case SCF_ERROR_NOT_SET:
1653 		default:
1654 			bad_error("scf_iter_service_instances", scf_error());
1655 		}
1656 	}
1657 
1658 	for (;;) {
1659 		r = scf_iter_next_instance(iter, inst);
1660 		if (r == 0)
1661 			break;
1662 		if (r != 1) {
1663 			switch (scf_error()) {
1664 			case SCF_ERROR_CONNECTION_BROKEN:
1665 				return (ECONNABORTED);
1666 
1667 			case SCF_ERROR_DELETED:
1668 				return (ECANCELED);
1669 
1670 			case SCF_ERROR_HANDLE_MISMATCH:
1671 			case SCF_ERROR_NOT_BOUND:
1672 			case SCF_ERROR_NOT_SET:
1673 			case SCF_ERROR_INVALID_ARGUMENT:
1674 			default:
1675 				bad_error("scf_iter_next_instance",
1676 				    scf_error());
1677 			}
1678 		}
1679 
1680 		/*
1681 		 * Similarly, just take a new running snapshot if operating on
1682 		 * a non-live repository or running during early import.
1683 		 */
1684 		if (est->sc_repo_filename != NULL ||
1685 		    est->sc_repo_doorname != NULL ||
1686 		    est->sc_in_emi == 1) {
1687 			r = refresh_running_snapshot(inst);
1688 			switch (r) {
1689 			case 0:
1690 				continue;
1691 
1692 			case ECONNABORTED:
1693 			case ECANCELED:
1694 			case EPERM:
1695 			case ENOSPC:
1696 				break;
1697 			default:
1698 				bad_error("refresh_running_snapshot",
1699 				    scf_error());
1700 			}
1701 
1702 			return (r);
1703 
1704 		}
1705 
1706 		if (_smf_refresh_instance_i(inst) == 0) {
1707 			if (g_verbose) {
1708 				if (scf_instance_get_name(inst, name_buf,
1709 				    max_scf_name_len + 1) < 0)
1710 					(void) strcpy(name_buf, "?");
1711 
1712 				warn(gettext("Refreshed %s:%s.\n"),
1713 				    fmri, name_buf);
1714 			}
1715 		} else {
1716 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1717 			    g_verbose) {
1718 				scfe = scf_error();
1719 
1720 				if (scf_instance_to_fmri(inst, name_buf,
1721 				    max_scf_name_len + 1) < 0)
1722 					(void) strcpy(name_buf, "?");
1723 
1724 				warn(gettext(
1725 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1726 				    name_buf, scf_strerror(scfe));
1727 			}
1728 		}
1729 	}
1730 
1731 	return (0);
1732 }
1733 
1734 static void
1735 private_refresh(void)
1736 {
1737 	scf_instance_t *pinst = NULL;
1738 	scf_iter_t *piter = NULL;
1739 	ssize_t fmrilen;
1740 	size_t bufsz;
1741 	char *fmribuf;
1742 	void *ent;
1743 	int issvc;
1744 	int r;
1745 
1746 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1747 		return;
1748 
1749 	assert(cur_svc != NULL);
1750 
1751 	bufsz = max_scf_fmri_len + 1;
1752 	fmribuf = safe_malloc(bufsz);
1753 	if (cur_inst) {
1754 		issvc = 0;
1755 		ent = cur_inst;
1756 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1757 	} else {
1758 		issvc = 1;
1759 		ent = cur_svc;
1760 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1761 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1762 			scfdie();
1763 
1764 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1765 			scfdie();
1766 	}
1767 	if (fmrilen < 0) {
1768 		free(fmribuf);
1769 		if (scf_error() != SCF_ERROR_DELETED)
1770 			scfdie();
1771 
1772 		warn(emsg_deleted);
1773 		return;
1774 	}
1775 	assert(fmrilen < bufsz);
1776 
1777 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1778 	switch (r) {
1779 	case 0:
1780 		break;
1781 
1782 	case ECONNABORTED:
1783 		warn(gettext("Could not refresh %s "
1784 		    "(repository connection broken).\n"), fmribuf);
1785 		break;
1786 
1787 	case ECANCELED:
1788 		warn(emsg_deleted);
1789 		break;
1790 
1791 	case EPERM:
1792 		warn(gettext("Could not refresh %s "
1793 		    "(permission denied).\n"), fmribuf);
1794 		break;
1795 
1796 	case ENOSPC:
1797 		warn(gettext("Could not refresh %s "
1798 		    "(repository server out of resources).\n"),
1799 		    fmribuf);
1800 		break;
1801 
1802 	case EACCES:
1803 	default:
1804 		bad_error("refresh_entity", scf_error());
1805 	}
1806 
1807 	if (issvc) {
1808 		scf_instance_destroy(pinst);
1809 		scf_iter_destroy(piter);
1810 	}
1811 
1812 	free(fmribuf);
1813 }
1814 
1815 
1816 static int
1817 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1818 {
1819 	cbp->sc_err = scferror2errno(err);
1820 	return (UU_WALK_ERROR);
1821 }
1822 
1823 static int
1824 stash_scferror(scf_callback_t *cbp)
1825 {
1826 	return (stash_scferror_err(cbp, scf_error()));
1827 }
1828 
1829 static int select_inst(const char *);
1830 static int select_svc(const char *);
1831 
1832 /*
1833  * Take a property that does not have a type and check to see if a type
1834  * exists or can be gleened from the current data.  Set the type.
1835  *
1836  * Check the current level (instance) and then check the higher level
1837  * (service).  This could be the case for adding a new property to
1838  * the instance that's going to "override" a service level property.
1839  *
1840  * For a property :
1841  * 1. Take the type from an existing property
1842  * 2. Take the type from a template entry
1843  *
1844  * If the type can not be found, then leave the type as is, and let the import
1845  * report the problem of the missing type.
1846  */
1847 static int
1848 find_current_prop_type(void *p, void *g)
1849 {
1850 	property_t *prop = p;
1851 	scf_callback_t *lcb = g;
1852 	pgroup_t *pg = NULL;
1853 
1854 	const char *fmri = NULL;
1855 	char *lfmri = NULL;
1856 	char *cur_selection = NULL;
1857 
1858 	scf_propertygroup_t *sc_pg = NULL;
1859 	scf_property_t *sc_prop = NULL;
1860 	scf_pg_tmpl_t *t_pg = NULL;
1861 	scf_prop_tmpl_t *t_prop = NULL;
1862 	scf_type_t prop_type;
1863 
1864 	value_t *vp;
1865 	int issvc = lcb->sc_service;
1866 	int r = UU_WALK_ERROR;
1867 
1868 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1869 		return (UU_WALK_NEXT);
1870 
1871 	t_prop = scf_tmpl_prop_create(g_hndl);
1872 	sc_prop = scf_property_create(g_hndl);
1873 	if (sc_prop == NULL || t_prop == NULL) {
1874 		warn(gettext("Unable to create the property to attempt and "
1875 		    "find a missing type.\n"));
1876 
1877 		scf_property_destroy(sc_prop);
1878 		scf_tmpl_prop_destroy(t_prop);
1879 
1880 		return (UU_WALK_ERROR);
1881 	}
1882 
1883 	if (lcb->sc_flags == 1) {
1884 		pg = lcb->sc_parent;
1885 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1886 		fmri = pg->sc_parent->sc_fmri;
1887 retry_pg:
1888 		if (cur_svc && cur_selection == NULL) {
1889 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1890 			lscf_get_selection_str(cur_selection,
1891 			    max_scf_fmri_len + 1);
1892 
1893 			if (strcmp(cur_selection, fmri) != 0) {
1894 				lscf_select(fmri);
1895 			} else {
1896 				free(cur_selection);
1897 				cur_selection = NULL;
1898 			}
1899 		} else {
1900 			lscf_select(fmri);
1901 		}
1902 
1903 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1904 			warn(gettext("Unable to create property group to "
1905 			    "find a missing property type.\n"));
1906 
1907 			goto out;
1908 		}
1909 
1910 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1911 			/*
1912 			 * If this is the sc_pg from the parent
1913 			 * let the caller clean up the sc_pg,
1914 			 * and just throw it away in this case.
1915 			 */
1916 			if (sc_pg != lcb->sc_parent)
1917 				scf_pg_destroy(sc_pg);
1918 
1919 			sc_pg = NULL;
1920 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1921 				warn(gettext("Unable to create template "
1922 				    "property group to find a property "
1923 				    "type.\n"));
1924 
1925 				goto out;
1926 			}
1927 
1928 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1929 			    pg->sc_pgroup_name, NULL, t_pg,
1930 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1931 				/*
1932 				 * if instance get service and jump back
1933 				 */
1934 				scf_tmpl_pg_destroy(t_pg);
1935 				t_pg = NULL;
1936 				if (issvc == 0) {
1937 					entity_t *e = pg->sc_parent->sc_parent;
1938 
1939 					fmri = e->sc_fmri;
1940 					issvc = 1;
1941 					goto retry_pg;
1942 				} else {
1943 					goto out;
1944 				}
1945 			}
1946 		}
1947 	} else {
1948 		sc_pg = lcb->sc_parent;
1949 	}
1950 
1951 	/*
1952 	 * Attempt to get the type from an existing property.  If the property
1953 	 * cannot be found then attempt to get the type from a template entry
1954 	 * for the property.
1955 	 *
1956 	 * Finally, if at the instance level look at the service level.
1957 	 */
1958 	if (sc_pg != NULL &&
1959 	    pg_get_prop(sc_pg, prop->sc_property_name,
1960 	    sc_prop) == SCF_SUCCESS &&
1961 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1962 		prop->sc_value_type = prop_type;
1963 
1964 		/*
1965 		 * Found a type, update the value types and validate
1966 		 * the actual value against this type.
1967 		 */
1968 		for (vp = uu_list_first(prop->sc_property_values);
1969 		    vp != NULL;
1970 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1971 			vp->sc_type = prop->sc_value_type;
1972 			lxml_store_value(vp, 0, NULL);
1973 		}
1974 
1975 		r = UU_WALK_NEXT;
1976 		goto out;
1977 	}
1978 
1979 	/*
1980 	 * If we get here with t_pg set to NULL then we had to have
1981 	 * gotten an sc_pg but that sc_pg did not have the property
1982 	 * we are looking for.   So if the t_pg is not null look up
1983 	 * the template entry for the property.
1984 	 *
1985 	 * If the t_pg is null then need to attempt to get a matching
1986 	 * template entry for the sc_pg, and see if there is a property
1987 	 * entry for that template entry.
1988 	 */
1989 do_tmpl :
1990 	if (t_pg != NULL &&
1991 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1992 	    t_prop, 0) == SCF_SUCCESS) {
1993 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1994 			prop->sc_value_type = prop_type;
1995 
1996 			/*
1997 			 * Found a type, update the value types and validate
1998 			 * the actual value against this type.
1999 			 */
2000 			for (vp = uu_list_first(prop->sc_property_values);
2001 			    vp != NULL;
2002 			    vp = uu_list_next(prop->sc_property_values, vp)) {
2003 				vp->sc_type = prop->sc_value_type;
2004 				lxml_store_value(vp, 0, NULL);
2005 			}
2006 
2007 			r = UU_WALK_NEXT;
2008 			goto out;
2009 		}
2010 	} else {
2011 		if (t_pg == NULL && sc_pg) {
2012 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2013 				warn(gettext("Unable to create template "
2014 				    "property group to find a property "
2015 				    "type.\n"));
2016 
2017 				goto out;
2018 			}
2019 
2020 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2021 				scf_tmpl_pg_destroy(t_pg);
2022 				t_pg = NULL;
2023 			} else {
2024 				goto do_tmpl;
2025 			}
2026 		}
2027 	}
2028 
2029 	if (issvc == 0) {
2030 		scf_instance_t *i;
2031 		scf_service_t *s;
2032 
2033 		issvc = 1;
2034 		if (lcb->sc_flags == 1) {
2035 			entity_t *e = pg->sc_parent->sc_parent;
2036 
2037 			fmri = e->sc_fmri;
2038 			goto retry_pg;
2039 		}
2040 
2041 		/*
2042 		 * because lcb->sc_flags was not set then this means
2043 		 * the pg was not used and can be used here.
2044 		 */
2045 		if ((pg = internal_pgroup_new()) == NULL) {
2046 			warn(gettext("Could not create internal property group "
2047 			    "to find a missing type."));
2048 
2049 			goto out;
2050 		}
2051 
2052 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2053 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2054 		    max_scf_name_len + 1) < 0)
2055 				goto out;
2056 
2057 		i = scf_instance_create(g_hndl);
2058 		s = scf_service_create(g_hndl);
2059 		if (i == NULL || s == NULL ||
2060 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2061 			warn(gettext("Could not get a service for the instance "
2062 			    "to find a missing type."));
2063 
2064 			goto out;
2065 		}
2066 
2067 		/*
2068 		 * Check to see truly at the instance level.
2069 		 */
2070 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2071 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2072 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2073 			goto out;
2074 		else
2075 			fmri = (const char *)lfmri;
2076 
2077 		goto retry_pg;
2078 	}
2079 
2080 out :
2081 	if (sc_pg != lcb->sc_parent) {
2082 		scf_pg_destroy(sc_pg);
2083 	}
2084 
2085 	/*
2086 	 * If this is true then the pg was allocated
2087 	 * here, and the name was set so need to free
2088 	 * the name and the pg.
2089 	 */
2090 	if (pg != NULL && pg != lcb->sc_parent) {
2091 		free((char *)pg->sc_pgroup_name);
2092 		internal_pgroup_free(pg);
2093 	}
2094 
2095 	if (cur_selection) {
2096 		lscf_select(cur_selection);
2097 		free(cur_selection);
2098 	}
2099 
2100 	scf_tmpl_pg_destroy(t_pg);
2101 	scf_tmpl_prop_destroy(t_prop);
2102 	scf_property_destroy(sc_prop);
2103 
2104 	if (r != UU_WALK_NEXT)
2105 		warn(gettext("Could not find property type for \"%s\" "
2106 		    "from \"%s\"\n"), prop->sc_property_name,
2107 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2108 
2109 	free(lfmri);
2110 
2111 	return (r);
2112 }
2113 
2114 /*
2115  * Take a property group that does not have a type and check to see if a type
2116  * exists or can be gleened from the current data.  Set the type.
2117  *
2118  * Check the current level (instance) and then check the higher level
2119  * (service).  This could be the case for adding a new property to
2120  * the instance that's going to "override" a service level property.
2121  *
2122  * For a property group
2123  * 1. Take the type from an existing property group
2124  * 2. Take the type from a template entry
2125  *
2126  * If the type can not be found, then leave the type as is, and let the import
2127  * report the problem of the missing type.
2128  */
2129 static int
2130 find_current_pg_type(void *p, void *sori)
2131 {
2132 	entity_t *si = sori;
2133 	pgroup_t *pg = p;
2134 
2135 	const char *ofmri, *fmri;
2136 	char *cur_selection = NULL;
2137 	char *pg_type = NULL;
2138 
2139 	scf_propertygroup_t *sc_pg = NULL;
2140 	scf_pg_tmpl_t *t_pg = NULL;
2141 
2142 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2143 	int r = UU_WALK_ERROR;
2144 
2145 	ofmri = fmri = si->sc_fmri;
2146 	if (pg->sc_pgroup_type != NULL) {
2147 		r = UU_WALK_NEXT;
2148 
2149 		goto out;
2150 	}
2151 
2152 	sc_pg = scf_pg_create(g_hndl);
2153 	if (sc_pg == NULL) {
2154 		warn(gettext("Unable to create property group to attempt "
2155 		    "and find a missing type.\n"));
2156 
2157 		return (UU_WALK_ERROR);
2158 	}
2159 
2160 	/*
2161 	 * Using get_pg() requires that the cur_svc/cur_inst be
2162 	 * via lscf_select.  Need to preserve the current selection
2163 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2164 	 */
2165 	if (cur_svc) {
2166 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2167 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2168 	}
2169 
2170 	/*
2171 	 * If the property group exists get the type, and set
2172 	 * the pgroup_t type of that type.
2173 	 *
2174 	 * If not the check for a template pg_pattern entry
2175 	 * and take the type from that.
2176 	 */
2177 retry_svc:
2178 	lscf_select(fmri);
2179 
2180 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2181 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2182 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2183 		    max_scf_pg_type_len + 1) != -1) {
2184 			pg->sc_pgroup_type = pg_type;
2185 
2186 			r = UU_WALK_NEXT;
2187 			goto out;
2188 		} else {
2189 			free(pg_type);
2190 		}
2191 	} else {
2192 		if ((t_pg == NULL) &&
2193 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2194 			goto out;
2195 
2196 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2197 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2198 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2199 			pg->sc_pgroup_type = pg_type;
2200 
2201 			r = UU_WALK_NEXT;
2202 			goto out;
2203 		}
2204 	}
2205 
2206 	/*
2207 	 * If type is not found at the instance level then attempt to
2208 	 * find the type at the service level.
2209 	 */
2210 	if (!issvc) {
2211 		si = si->sc_parent;
2212 		fmri = si->sc_fmri;
2213 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2214 		goto retry_svc;
2215 	}
2216 
2217 out :
2218 	if (cur_selection) {
2219 		lscf_select(cur_selection);
2220 		free(cur_selection);
2221 	}
2222 
2223 	/*
2224 	 * Now walk the properties of the property group to make sure that
2225 	 * all properties have the correct type and values are valid for
2226 	 * those types.
2227 	 */
2228 	if (r == UU_WALK_NEXT) {
2229 		scf_callback_t cb;
2230 
2231 		cb.sc_service = issvc;
2232 		cb.sc_source_fmri = ofmri;
2233 		if (sc_pg != NULL) {
2234 			cb.sc_parent = sc_pg;
2235 			cb.sc_flags = 0;
2236 		} else {
2237 			cb.sc_parent = pg;
2238 			cb.sc_flags = 1;
2239 		}
2240 
2241 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2242 		    &cb, UU_DEFAULT) != 0) {
2243 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2244 				bad_error("uu_list_walk", uu_error());
2245 
2246 			r = UU_WALK_ERROR;
2247 		}
2248 	} else {
2249 		warn(gettext("Could not find property group type for "
2250 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2251 	}
2252 
2253 	scf_tmpl_pg_destroy(t_pg);
2254 	scf_pg_destroy(sc_pg);
2255 
2256 	return (r);
2257 }
2258 
2259 /*
2260  * Import.  These functions import a bundle into the repository.
2261  */
2262 
2263 /*
2264  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2265  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2266  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2267  * lcbdata->sc_err to
2268  *   ENOMEM - out of memory
2269  *   ECONNABORTED - repository connection broken
2270  *   ECANCELED - sc_trans's property group was deleted
2271  *   EINVAL - p's name is invalid (error printed)
2272  *	    - p has an invalid value (error printed)
2273  */
2274 static int
2275 lscf_property_import(void *v, void *pvt)
2276 {
2277 	property_t *p = v;
2278 	scf_callback_t *lcbdata = pvt;
2279 	value_t *vp;
2280 	scf_transaction_t *trans = lcbdata->sc_trans;
2281 	scf_transaction_entry_t *entr;
2282 	scf_value_t *val;
2283 	scf_type_t tp;
2284 
2285 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2286 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2287 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2288 		lcbdata->sc_enable = p;
2289 		return (UU_WALK_NEXT);
2290 	}
2291 
2292 	entr = scf_entry_create(lcbdata->sc_handle);
2293 	if (entr == NULL) {
2294 		switch (scf_error()) {
2295 		case SCF_ERROR_NO_MEMORY:
2296 			return (stash_scferror(lcbdata));
2297 
2298 		case SCF_ERROR_INVALID_ARGUMENT:
2299 		default:
2300 			bad_error("scf_entry_create", scf_error());
2301 		}
2302 	}
2303 
2304 	tp = p->sc_value_type;
2305 
2306 	if (scf_transaction_property_new(trans, entr,
2307 	    p->sc_property_name, tp) != 0) {
2308 		switch (scf_error()) {
2309 		case SCF_ERROR_INVALID_ARGUMENT:
2310 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2311 			scf_entry_destroy(entr);
2312 			return (stash_scferror(lcbdata));
2313 
2314 		case SCF_ERROR_EXISTS:
2315 			break;
2316 
2317 		case SCF_ERROR_DELETED:
2318 		case SCF_ERROR_CONNECTION_BROKEN:
2319 			scf_entry_destroy(entr);
2320 			return (stash_scferror(lcbdata));
2321 
2322 		case SCF_ERROR_NOT_BOUND:
2323 		case SCF_ERROR_HANDLE_MISMATCH:
2324 		case SCF_ERROR_NOT_SET:
2325 		default:
2326 			bad_error("scf_transaction_property_new", scf_error());
2327 		}
2328 
2329 		if (scf_transaction_property_change_type(trans, entr,
2330 		    p->sc_property_name, tp) != 0) {
2331 			switch (scf_error()) {
2332 			case SCF_ERROR_DELETED:
2333 			case SCF_ERROR_CONNECTION_BROKEN:
2334 				scf_entry_destroy(entr);
2335 				return (stash_scferror(lcbdata));
2336 
2337 			case SCF_ERROR_INVALID_ARGUMENT:
2338 				semerr(emsg_invalid_prop_name,
2339 				    p->sc_property_name);
2340 				scf_entry_destroy(entr);
2341 				return (stash_scferror(lcbdata));
2342 
2343 			case SCF_ERROR_NOT_FOUND:
2344 			case SCF_ERROR_NOT_SET:
2345 			case SCF_ERROR_HANDLE_MISMATCH:
2346 			case SCF_ERROR_NOT_BOUND:
2347 			default:
2348 				bad_error(
2349 				    "scf_transaction_property_change_type",
2350 				    scf_error());
2351 			}
2352 		}
2353 	}
2354 
2355 	for (vp = uu_list_first(p->sc_property_values);
2356 	    vp != NULL;
2357 	    vp = uu_list_next(p->sc_property_values, vp)) {
2358 		val = scf_value_create(g_hndl);
2359 		if (val == NULL) {
2360 			switch (scf_error()) {
2361 			case SCF_ERROR_NO_MEMORY:
2362 				return (stash_scferror(lcbdata));
2363 
2364 			case SCF_ERROR_INVALID_ARGUMENT:
2365 			default:
2366 				bad_error("scf_value_create", scf_error());
2367 			}
2368 		}
2369 
2370 		switch (tp) {
2371 		case SCF_TYPE_BOOLEAN:
2372 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2373 			break;
2374 		case SCF_TYPE_COUNT:
2375 			scf_value_set_count(val, vp->sc_u.sc_count);
2376 			break;
2377 		case SCF_TYPE_INTEGER:
2378 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2379 			break;
2380 		default:
2381 			assert(vp->sc_u.sc_string != NULL);
2382 			if (scf_value_set_from_string(val, tp,
2383 			    vp->sc_u.sc_string) != 0) {
2384 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2385 					bad_error("scf_value_set_from_string",
2386 					    scf_error());
2387 
2388 				warn(gettext("Value \"%s\" is not a valid "
2389 				    "%s.\n"), vp->sc_u.sc_string,
2390 				    scf_type_to_string(tp));
2391 				scf_value_destroy(val);
2392 				return (stash_scferror(lcbdata));
2393 			}
2394 			break;
2395 		}
2396 
2397 		if (scf_entry_add_value(entr, val) != 0)
2398 			bad_error("scf_entry_add_value", scf_error());
2399 	}
2400 
2401 	return (UU_WALK_NEXT);
2402 }
2403 
2404 /*
2405  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2406  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2407  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2408  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2409  * lcbdata->sc_err to
2410  *   ECONNABORTED - repository connection broken
2411  *   ENOMEM - out of memory
2412  *   ENOSPC - svc.configd is out of resources
2413  *   ECANCELED - sc_parent was deleted
2414  *   EPERM - could not create property group (permission denied) (error printed)
2415  *	   - could not modify property group (permission denied) (error printed)
2416  *	   - could not delete property group (permission denied) (error	printed)
2417  *   EROFS - could not create property group (repository is read-only)
2418  *	   - could not delete property group (repository is read-only)
2419  *   EACCES - could not create property group (backend access denied)
2420  *	    - could not delete property group (backend access denied)
2421  *   EEXIST - could not create property group (already exists)
2422  *   EINVAL - invalid property group name (error printed)
2423  *	    - invalid property name (error printed)
2424  *	    - invalid value (error printed)
2425  *   EBUSY - new property group deleted (error printed)
2426  *	   - new property group changed (error printed)
2427  *	   - property group added (error printed)
2428  *	   - property group deleted (error printed)
2429  */
2430 static int
2431 entity_pgroup_import(void *v, void *pvt)
2432 {
2433 	pgroup_t *p = v;
2434 	scf_callback_t cbdata;
2435 	scf_callback_t *lcbdata = pvt;
2436 	void *ent = lcbdata->sc_parent;
2437 	int issvc = lcbdata->sc_service;
2438 	int r;
2439 
2440 	const char * const pg_changed = gettext("%s changed unexpectedly "
2441 	    "(new property group \"%s\" changed).\n");
2442 
2443 	/* Never import deleted property groups. */
2444 	if (p->sc_pgroup_delete) {
2445 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2446 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2447 			goto delete_pg;
2448 		}
2449 		return (UU_WALK_NEXT);
2450 	}
2451 
2452 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2453 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2454 		lcbdata->sc_general = p;
2455 		return (UU_WALK_NEXT);
2456 	}
2457 
2458 add_pg:
2459 	if (issvc)
2460 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2461 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2462 	else
2463 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2464 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2465 	if (r != 0) {
2466 		switch (scf_error()) {
2467 		case SCF_ERROR_DELETED:
2468 		case SCF_ERROR_CONNECTION_BROKEN:
2469 		case SCF_ERROR_BACKEND_READONLY:
2470 		case SCF_ERROR_BACKEND_ACCESS:
2471 		case SCF_ERROR_NO_RESOURCES:
2472 			return (stash_scferror(lcbdata));
2473 
2474 		case SCF_ERROR_EXISTS:
2475 			if (lcbdata->sc_flags & SCI_FORCE)
2476 				break;
2477 			return (stash_scferror(lcbdata));
2478 
2479 		case SCF_ERROR_INVALID_ARGUMENT:
2480 			warn(emsg_fmri_invalid_pg_name_type,
2481 			    lcbdata->sc_source_fmri,
2482 			    p->sc_pgroup_name, p->sc_pgroup_type);
2483 			return (stash_scferror(lcbdata));
2484 
2485 		case SCF_ERROR_PERMISSION_DENIED:
2486 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2487 			    lcbdata->sc_target_fmri);
2488 			return (stash_scferror(lcbdata));
2489 
2490 		case SCF_ERROR_NOT_BOUND:
2491 		case SCF_ERROR_HANDLE_MISMATCH:
2492 		case SCF_ERROR_NOT_SET:
2493 		default:
2494 			bad_error("scf_service_add_pg", scf_error());
2495 		}
2496 
2497 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2498 			switch (scf_error()) {
2499 			case SCF_ERROR_CONNECTION_BROKEN:
2500 			case SCF_ERROR_DELETED:
2501 				return (stash_scferror(lcbdata));
2502 
2503 			case SCF_ERROR_INVALID_ARGUMENT:
2504 				warn(emsg_fmri_invalid_pg_name,
2505 				    lcbdata->sc_source_fmri,
2506 				    p->sc_pgroup_name);
2507 				return (stash_scferror(lcbdata));
2508 
2509 			case SCF_ERROR_NOT_FOUND:
2510 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2511 				    p->sc_pgroup_name);
2512 				lcbdata->sc_err = EBUSY;
2513 				return (UU_WALK_ERROR);
2514 
2515 			case SCF_ERROR_NOT_BOUND:
2516 			case SCF_ERROR_HANDLE_MISMATCH:
2517 			case SCF_ERROR_NOT_SET:
2518 			default:
2519 				bad_error("entity_get_pg", scf_error());
2520 			}
2521 		}
2522 
2523 		if (lcbdata->sc_flags & SCI_KEEP)
2524 			goto props;
2525 
2526 delete_pg:
2527 		if (scf_pg_delete(imp_pg) != 0) {
2528 			switch (scf_error()) {
2529 			case SCF_ERROR_DELETED:
2530 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2531 				    p->sc_pgroup_name);
2532 				lcbdata->sc_err = EBUSY;
2533 				return (UU_WALK_ERROR);
2534 
2535 			case SCF_ERROR_PERMISSION_DENIED:
2536 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2537 				    lcbdata->sc_target_fmri);
2538 				return (stash_scferror(lcbdata));
2539 
2540 			case SCF_ERROR_BACKEND_READONLY:
2541 			case SCF_ERROR_BACKEND_ACCESS:
2542 			case SCF_ERROR_CONNECTION_BROKEN:
2543 				return (stash_scferror(lcbdata));
2544 
2545 			case SCF_ERROR_NOT_SET:
2546 			default:
2547 				bad_error("scf_pg_delete", scf_error());
2548 			}
2549 		}
2550 
2551 		if (p->sc_pgroup_delete)
2552 			return (UU_WALK_NEXT);
2553 
2554 		goto add_pg;
2555 	}
2556 
2557 props:
2558 
2559 	/*
2560 	 * Add properties to property group, if any.
2561 	 */
2562 	cbdata.sc_handle = lcbdata->sc_handle;
2563 	cbdata.sc_parent = imp_pg;
2564 	cbdata.sc_flags = lcbdata->sc_flags;
2565 	cbdata.sc_trans = imp_tx;
2566 	cbdata.sc_enable = NULL;
2567 
2568 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2569 		switch (scf_error()) {
2570 		case SCF_ERROR_BACKEND_ACCESS:
2571 		case SCF_ERROR_BACKEND_READONLY:
2572 		case SCF_ERROR_CONNECTION_BROKEN:
2573 			return (stash_scferror(lcbdata));
2574 
2575 		case SCF_ERROR_DELETED:
2576 			warn(pg_changed, lcbdata->sc_target_fmri,
2577 			    p->sc_pgroup_name);
2578 			lcbdata->sc_err = EBUSY;
2579 			return (UU_WALK_ERROR);
2580 
2581 		case SCF_ERROR_PERMISSION_DENIED:
2582 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2583 			    lcbdata->sc_target_fmri);
2584 			return (stash_scferror(lcbdata));
2585 
2586 		case SCF_ERROR_NOT_BOUND:
2587 		case SCF_ERROR_NOT_SET:
2588 		case SCF_ERROR_IN_USE:
2589 		case SCF_ERROR_HANDLE_MISMATCH:
2590 		default:
2591 			bad_error("scf_transaction_start", scf_error());
2592 		}
2593 	}
2594 
2595 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2596 	    UU_DEFAULT) != 0) {
2597 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2598 			bad_error("uu_list_walk", uu_error());
2599 		scf_transaction_reset(imp_tx);
2600 
2601 		lcbdata->sc_err = cbdata.sc_err;
2602 		if (cbdata.sc_err == ECANCELED) {
2603 			warn(pg_changed, lcbdata->sc_target_fmri,
2604 			    p->sc_pgroup_name);
2605 			lcbdata->sc_err = EBUSY;
2606 		}
2607 		return (UU_WALK_ERROR);
2608 	}
2609 
2610 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2611 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2612 
2613 		/*
2614 		 * take the snapshot running snapshot then
2615 		 * import the stored general/enable property
2616 		 */
2617 		r = take_snap(ent, snap_running, imp_rsnap);
2618 		switch (r) {
2619 		case 0:
2620 			break;
2621 
2622 		case ECONNABORTED:
2623 			warn(gettext("Could not take %s snapshot on import "
2624 			    "(repository connection broken).\n"),
2625 			    snap_running);
2626 			lcbdata->sc_err = r;
2627 			return (UU_WALK_ERROR);
2628 		case ECANCELED:
2629 			warn(emsg_deleted);
2630 			lcbdata->sc_err = r;
2631 			return (UU_WALK_ERROR);
2632 
2633 		case EPERM:
2634 			warn(gettext("Could not take %s snapshot "
2635 			    "(permission denied).\n"), snap_running);
2636 			lcbdata->sc_err = r;
2637 			return (UU_WALK_ERROR);
2638 
2639 		case ENOSPC:
2640 			warn(gettext("Could not take %s snapshot"
2641 			    "(repository server out of resources).\n"),
2642 			    snap_running);
2643 			lcbdata->sc_err = r;
2644 			return (UU_WALK_ERROR);
2645 
2646 		default:
2647 			bad_error("take_snap", r);
2648 		}
2649 
2650 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2651 		if (r != UU_WALK_NEXT) {
2652 			if (r != UU_WALK_ERROR)
2653 				bad_error("lscf_property_import", r);
2654 			return (EINVAL);
2655 		}
2656 	}
2657 
2658 	r = scf_transaction_commit(imp_tx);
2659 	switch (r) {
2660 	case 1:
2661 		r = UU_WALK_NEXT;
2662 		break;
2663 
2664 	case 0:
2665 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2666 		lcbdata->sc_err = EBUSY;
2667 		r = UU_WALK_ERROR;
2668 		break;
2669 
2670 	case -1:
2671 		switch (scf_error()) {
2672 		case SCF_ERROR_BACKEND_READONLY:
2673 		case SCF_ERROR_BACKEND_ACCESS:
2674 		case SCF_ERROR_CONNECTION_BROKEN:
2675 		case SCF_ERROR_NO_RESOURCES:
2676 			r = stash_scferror(lcbdata);
2677 			break;
2678 
2679 		case SCF_ERROR_DELETED:
2680 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2681 			    p->sc_pgroup_name);
2682 			lcbdata->sc_err = EBUSY;
2683 			r = UU_WALK_ERROR;
2684 			break;
2685 
2686 		case SCF_ERROR_PERMISSION_DENIED:
2687 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2688 			    lcbdata->sc_target_fmri);
2689 			r = stash_scferror(lcbdata);
2690 			break;
2691 
2692 		case SCF_ERROR_NOT_SET:
2693 		case SCF_ERROR_INVALID_ARGUMENT:
2694 		case SCF_ERROR_NOT_BOUND:
2695 		default:
2696 			bad_error("scf_transaction_commit", scf_error());
2697 		}
2698 		break;
2699 
2700 	default:
2701 		bad_error("scf_transaction_commit", r);
2702 	}
2703 
2704 	scf_transaction_destroy_children(imp_tx);
2705 
2706 	return (r);
2707 }
2708 
2709 /*
2710  * Returns
2711  *   0 - success
2712  *   ECONNABORTED - repository connection broken
2713  *   ENOMEM - out of memory
2714  *   ENOSPC - svc.configd is out of resources
2715  *   ECANCELED - inst was deleted
2716  *   EPERM - could not create property group (permission denied) (error printed)
2717  *	   - could not modify property group (permission denied) (error printed)
2718  *   EROFS - could not create property group (repository is read-only)
2719  *   EACCES - could not create property group (backend access denied)
2720  *   EEXIST - could not create property group (already exists)
2721  *   EINVAL - invalid property group name (error printed)
2722  *	    - invalid property name (error printed)
2723  *	    - invalid value (error printed)
2724  *   EBUSY - new property group changed (error printed)
2725  */
2726 static int
2727 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2728     const entity_t *isvc, int flags)
2729 {
2730 	scf_callback_t cbdata;
2731 
2732 	cbdata.sc_handle = scf_service_handle(svc);
2733 	cbdata.sc_parent = svc;
2734 	cbdata.sc_service = 1;
2735 	cbdata.sc_general = 0;
2736 	cbdata.sc_enable = 0;
2737 	cbdata.sc_flags = flags;
2738 	cbdata.sc_source_fmri = isvc->sc_fmri;
2739 	cbdata.sc_target_fmri = target_fmri;
2740 
2741 	/*
2742 	 * If the op is set, then add the flag to the callback
2743 	 * flags for later use.
2744 	 */
2745 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2746 		switch (isvc->sc_op) {
2747 		case SVCCFG_OP_IMPORT :
2748 			cbdata.sc_flags |= SCI_OP_IMPORT;
2749 			break;
2750 		case SVCCFG_OP_APPLY :
2751 			cbdata.sc_flags |= SCI_OP_APPLY;
2752 			break;
2753 		case SVCCFG_OP_RESTORE :
2754 			cbdata.sc_flags |= SCI_OP_RESTORE;
2755 			break;
2756 		default :
2757 			uu_die(gettext("lscf_import_service_pgs : "
2758 			    "Unknown op stored in the service entity\n"));
2759 
2760 		}
2761 	}
2762 
2763 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2764 	    UU_DEFAULT) != 0) {
2765 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2766 			bad_error("uu_list_walk", uu_error());
2767 
2768 		return (cbdata.sc_err);
2769 	}
2770 
2771 	return (0);
2772 }
2773 
2774 /*
2775  * Returns
2776  *   0 - success
2777  *   ECONNABORTED - repository connection broken
2778  *   ENOMEM - out of memory
2779  *   ENOSPC - svc.configd is out of resources
2780  *   ECANCELED - inst was deleted
2781  *   EPERM - could not create property group (permission denied) (error printed)
2782  *	   - could not modify property group (permission denied) (error printed)
2783  *   EROFS - could not create property group (repository is read-only)
2784  *   EACCES - could not create property group (backend access denied)
2785  *   EEXIST - could not create property group (already exists)
2786  *   EINVAL - invalid property group name (error printed)
2787  *	    - invalid property name (error printed)
2788  *	    - invalid value (error printed)
2789  *   EBUSY - new property group changed (error printed)
2790  */
2791 static int
2792 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2793     const entity_t *iinst, int flags)
2794 {
2795 	scf_callback_t cbdata;
2796 
2797 	cbdata.sc_handle = scf_instance_handle(inst);
2798 	cbdata.sc_parent = inst;
2799 	cbdata.sc_service = 0;
2800 	cbdata.sc_general = NULL;
2801 	cbdata.sc_enable = NULL;
2802 	cbdata.sc_flags = flags;
2803 	cbdata.sc_source_fmri = iinst->sc_fmri;
2804 	cbdata.sc_target_fmri = target_fmri;
2805 
2806 	/*
2807 	 * If the op is set, then add the flag to the callback
2808 	 * flags for later use.
2809 	 */
2810 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2811 		switch (iinst->sc_op) {
2812 		case SVCCFG_OP_IMPORT :
2813 			cbdata.sc_flags |= SCI_OP_IMPORT;
2814 			break;
2815 		case SVCCFG_OP_APPLY :
2816 			cbdata.sc_flags |= SCI_OP_APPLY;
2817 			break;
2818 		case SVCCFG_OP_RESTORE :
2819 			cbdata.sc_flags |= SCI_OP_RESTORE;
2820 			break;
2821 		default :
2822 			uu_die(gettext("lscf_import_instance_pgs : "
2823 			    "Unknown op stored in the instance entity\n"));
2824 		}
2825 	}
2826 
2827 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2828 	    UU_DEFAULT) != 0) {
2829 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2830 			bad_error("uu_list_walk", uu_error());
2831 
2832 		return (cbdata.sc_err);
2833 	}
2834 
2835 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2836 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2837 		/*
2838 		 * If importing with the SCI_NOENABLED flag then
2839 		 * skip the delay, but if not then add the delay
2840 		 * of the enable property.
2841 		 */
2842 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2843 			cbdata.sc_flags |= SCI_DELAYENABLE;
2844 		}
2845 
2846 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2847 		    != UU_WALK_NEXT)
2848 			return (cbdata.sc_err);
2849 	}
2850 
2851 	return (0);
2852 }
2853 
2854 /*
2855  * Report the reasons why we can't upgrade pg2 to pg1.
2856  */
2857 static void
2858 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2859     int new)
2860 {
2861 	property_t *p1, *p2;
2862 
2863 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2864 
2865 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2866 		return;
2867 
2868 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2869 	    p1 != NULL;
2870 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2871 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2872 		if (p2 != NULL) {
2873 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2874 			    new);
2875 			continue;
2876 		}
2877 
2878 		if (new)
2879 			warn(gettext("Conflict upgrading %s (new property "
2880 			    "group \"%s\" is missing property \"%s\").\n"),
2881 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2882 		else
2883 			warn(gettext("Conflict upgrading %s (property "
2884 			    "\"%s/%s\" is missing).\n"), fmri,
2885 			    pg1->sc_pgroup_name, p1->sc_property_name);
2886 	}
2887 
2888 	/*
2889 	 * Since pg1 should be from the manifest, any properties in pg2 which
2890 	 * aren't in pg1 shouldn't be reported as conflicts.
2891 	 */
2892 }
2893 
2894 /*
2895  * Add transaction entries to tx which will upgrade cur's pg according to old
2896  * & new.
2897  *
2898  * Returns
2899  *   0 - success
2900  *   EINVAL - new has a property with an invalid name or value (message emitted)
2901  *   ENOMEM - out of memory
2902  */
2903 static int
2904 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2905     pgroup_t *cur, int speak, const char *fmri)
2906 {
2907 	property_t *p, *new_p, *cur_p;
2908 	scf_transaction_entry_t *e;
2909 	int r;
2910 	int is_general;
2911 	int is_protected;
2912 
2913 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2914 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2915 		bad_error("uu_list_walk", uu_error());
2916 
2917 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2918 
2919 	for (p = uu_list_first(old->sc_pgroup_props);
2920 	    p != NULL;
2921 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2922 		/* p is a property in the old property group. */
2923 
2924 		/* Protect live properties. */
2925 		is_protected = 0;
2926 		if (is_general) {
2927 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2928 			    0 ||
2929 			    strcmp(p->sc_property_name,
2930 			    SCF_PROPERTY_RESTARTER) == 0)
2931 				is_protected = 1;
2932 		}
2933 
2934 		/* Look for the same property in the new properties. */
2935 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2936 		if (new_p != NULL) {
2937 			new_p->sc_seen = 1;
2938 
2939 			/*
2940 			 * If the new property is the same as the old, don't do
2941 			 * anything (leave any user customizations).
2942 			 */
2943 			if (prop_equal(p, new_p, NULL, NULL, 0))
2944 				continue;
2945 
2946 			if (new_p->sc_property_override)
2947 				goto upgrade;
2948 		}
2949 
2950 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2951 		if (cur_p == NULL) {
2952 			/*
2953 			 * p has been deleted from the repository.  If we were
2954 			 * going to delete it anyway, do nothing.  Otherwise
2955 			 * report a conflict.
2956 			 */
2957 			if (new_p == NULL)
2958 				continue;
2959 
2960 			if (is_protected)
2961 				continue;
2962 
2963 			warn(gettext("Conflict upgrading %s "
2964 			    "(property \"%s/%s\" is missing).\n"), fmri,
2965 			    old->sc_pgroup_name, p->sc_property_name);
2966 			continue;
2967 		}
2968 
2969 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2970 			/*
2971 			 * Conflict.  Don't warn if the property is already the
2972 			 * way we want it, though.
2973 			 */
2974 			if (is_protected)
2975 				continue;
2976 
2977 			if (new_p == NULL)
2978 				(void) prop_equal(p, cur_p, fmri,
2979 				    old->sc_pgroup_name, 0);
2980 			else
2981 				(void) prop_equal(cur_p, new_p, fmri,
2982 				    old->sc_pgroup_name, 0);
2983 			continue;
2984 		}
2985 
2986 		if (is_protected) {
2987 			if (speak)
2988 				warn(gettext("%s: Refusing to upgrade "
2989 				    "\"%s/%s\" (live property).\n"), fmri,
2990 				    old->sc_pgroup_name, p->sc_property_name);
2991 			continue;
2992 		}
2993 
2994 upgrade:
2995 		/* p hasn't been customized in the repository.  Upgrade it. */
2996 		if (new_p == NULL) {
2997 			/* p was deleted.  Delete from cur if unchanged. */
2998 			if (speak)
2999 				warn(gettext(
3000 				    "%s: Deleting property \"%s/%s\".\n"),
3001 				    fmri, old->sc_pgroup_name,
3002 				    p->sc_property_name);
3003 
3004 			e = scf_entry_create(g_hndl);
3005 			if (e == NULL)
3006 				return (ENOMEM);
3007 
3008 			if (scf_transaction_property_delete(tx, e,
3009 			    p->sc_property_name) != 0) {
3010 				switch (scf_error()) {
3011 				case SCF_ERROR_DELETED:
3012 					scf_entry_destroy(e);
3013 					return (ECANCELED);
3014 
3015 				case SCF_ERROR_CONNECTION_BROKEN:
3016 					scf_entry_destroy(e);
3017 					return (ECONNABORTED);
3018 
3019 				case SCF_ERROR_NOT_FOUND:
3020 					/*
3021 					 * This can happen if cur is from the
3022 					 * running snapshot (and it differs
3023 					 * from the live properties).
3024 					 */
3025 					scf_entry_destroy(e);
3026 					break;
3027 
3028 				case SCF_ERROR_HANDLE_MISMATCH:
3029 				case SCF_ERROR_NOT_BOUND:
3030 				case SCF_ERROR_NOT_SET:
3031 				case SCF_ERROR_INVALID_ARGUMENT:
3032 				default:
3033 					bad_error(
3034 					    "scf_transaction_property_delete",
3035 					    scf_error());
3036 				}
3037 			}
3038 		} else {
3039 			scf_callback_t ctx;
3040 
3041 			if (speak)
3042 				warn(gettext(
3043 				    "%s: Upgrading property \"%s/%s\".\n"),
3044 				    fmri, old->sc_pgroup_name,
3045 				    p->sc_property_name);
3046 
3047 			ctx.sc_handle = g_hndl;
3048 			ctx.sc_trans = tx;
3049 			ctx.sc_flags = 0;
3050 
3051 			r = lscf_property_import(new_p, &ctx);
3052 			if (r != UU_WALK_NEXT) {
3053 				if (r != UU_WALK_ERROR)
3054 					bad_error("lscf_property_import", r);
3055 				return (EINVAL);
3056 			}
3057 		}
3058 	}
3059 
3060 	/* Go over the properties which were added. */
3061 	for (new_p = uu_list_first(new->sc_pgroup_props);
3062 	    new_p != NULL;
3063 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3064 		if (new_p->sc_seen)
3065 			continue;
3066 
3067 		/* This is a new property. */
3068 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3069 		if (cur_p == NULL) {
3070 			scf_callback_t ctx;
3071 
3072 			ctx.sc_handle = g_hndl;
3073 			ctx.sc_trans = tx;
3074 			ctx.sc_flags = 0;
3075 
3076 			r = lscf_property_import(new_p, &ctx);
3077 			if (r != UU_WALK_NEXT) {
3078 				if (r != UU_WALK_ERROR)
3079 					bad_error("lscf_property_import", r);
3080 				return (EINVAL);
3081 			}
3082 			continue;
3083 		}
3084 
3085 		/*
3086 		 * Report a conflict if the new property differs from the
3087 		 * current one.  Unless it's general/enabled, since that's
3088 		 * never in the last-import snapshot.
3089 		 */
3090 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3091 		    0 &&
3092 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3093 			continue;
3094 
3095 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3096 	}
3097 
3098 	return (0);
3099 }
3100 
3101 /*
3102  * Upgrade pg according to old & new.
3103  *
3104  * Returns
3105  *   0 - success
3106  *   ECONNABORTED - repository connection broken
3107  *   ENOMEM - out of memory
3108  *   ENOSPC - svc.configd is out of resources
3109  *   ECANCELED - pg was deleted
3110  *   EPERM - couldn't modify pg (permission denied)
3111  *   EROFS - couldn't modify pg (backend read-only)
3112  *   EACCES - couldn't modify pg (backend access denied)
3113  *   EINVAL - new has a property with invalid name or value (error printed)
3114  *   EBUSY - pg changed unexpectedly
3115  */
3116 static int
3117 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3118     pgroup_t *new, int speak, const char *fmri)
3119 {
3120 	int r;
3121 
3122 	if (scf_transaction_start(imp_tx, pg) != 0) {
3123 		switch (scf_error()) {
3124 		case SCF_ERROR_CONNECTION_BROKEN:
3125 		case SCF_ERROR_DELETED:
3126 		case SCF_ERROR_PERMISSION_DENIED:
3127 		case SCF_ERROR_BACKEND_READONLY:
3128 		case SCF_ERROR_BACKEND_ACCESS:
3129 			return (scferror2errno(scf_error()));
3130 
3131 		case SCF_ERROR_HANDLE_MISMATCH:
3132 		case SCF_ERROR_IN_USE:
3133 		case SCF_ERROR_NOT_BOUND:
3134 		case SCF_ERROR_NOT_SET:
3135 		default:
3136 			bad_error("scf_transaction_start", scf_error());
3137 		}
3138 	}
3139 
3140 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3141 	switch (r) {
3142 	case 0:
3143 		break;
3144 
3145 	case EINVAL:
3146 	case ENOMEM:
3147 		scf_transaction_destroy_children(imp_tx);
3148 		return (r);
3149 
3150 	default:
3151 		bad_error("add_upgrade_entries", r);
3152 	}
3153 
3154 	r = scf_transaction_commit(imp_tx);
3155 
3156 	scf_transaction_destroy_children(imp_tx);
3157 
3158 	switch (r) {
3159 	case 1:
3160 		break;
3161 
3162 	case 0:
3163 		return (EBUSY);
3164 
3165 	case -1:
3166 		switch (scf_error()) {
3167 		case SCF_ERROR_CONNECTION_BROKEN:
3168 		case SCF_ERROR_NO_RESOURCES:
3169 		case SCF_ERROR_PERMISSION_DENIED:
3170 		case SCF_ERROR_BACKEND_READONLY:
3171 		case SCF_ERROR_BACKEND_ACCESS:
3172 		case SCF_ERROR_DELETED:
3173 			return (scferror2errno(scf_error()));
3174 
3175 		case SCF_ERROR_NOT_BOUND:
3176 		case SCF_ERROR_INVALID_ARGUMENT:
3177 		case SCF_ERROR_NOT_SET:
3178 		default:
3179 			bad_error("scf_transaction_commit", scf_error());
3180 		}
3181 
3182 	default:
3183 		bad_error("scf_transaction_commit", r);
3184 	}
3185 
3186 	return (0);
3187 }
3188 
3189 /*
3190  * Compares two entity FMRIs.  Returns
3191  *
3192  *   1 - equal
3193  *   0 - not equal
3194  *   -1 - f1 is invalid or not an entity
3195  *   -2 - f2 is invalid or not an entity
3196  */
3197 static int
3198 fmri_equal(const char *f1, const char *f2)
3199 {
3200 	int r;
3201 	const char *s1, *i1, *pg1;
3202 	const char *s2, *i2, *pg2;
3203 
3204 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3205 		return (-1);
3206 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3207 		return (-1);
3208 
3209 	if (s1 == NULL || pg1 != NULL)
3210 		return (-1);
3211 
3212 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3213 		return (-2);
3214 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3215 		return (-2);
3216 
3217 	if (s2 == NULL || pg2 != NULL)
3218 		return (-2);
3219 
3220 	r = strcmp(s1, s2);
3221 	if (r != 0)
3222 		return (0);
3223 
3224 	if (i1 == NULL && i2 == NULL)
3225 		return (1);
3226 
3227 	if (i1 == NULL || i2 == NULL)
3228 		return (0);
3229 
3230 	return (strcmp(i1, i2) == 0);
3231 }
3232 
3233 /*
3234  * Import a dependent by creating a dependency property group in the dependent
3235  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3236  * dependents pg, and add an entry to create a new property for this
3237  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3238  *
3239  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3240  * lcbdata->sc_err to
3241  *   ECONNABORTED - repository connection broken
3242  *   ENOMEM - out of memory
3243  *   ENOSPC - configd is out of resources
3244  *   EINVAL - target is invalid (error printed)
3245  *	    - target is not an entity (error printed)
3246  *	    - dependent has invalid name (error printed)
3247  *	    - invalid property name (error printed)
3248  *	    - invalid value (error printed)
3249  *	    - scope of target does not exist (error printed)
3250  *   EPERM - couldn't create target (permission denied) (error printed)
3251  *	   - couldn't create dependency pg (permission denied) (error printed)
3252  *	   - couldn't modify dependency pg (permission denied) (error printed)
3253  *   EROFS - couldn't create target (repository read-only)
3254  *	   - couldn't create dependency pg (repository read-only)
3255  *   EACCES - couldn't create target (backend access denied)
3256  *	    - couldn't create dependency pg (backend access denied)
3257  *   ECANCELED - sc_trans's pg was deleted
3258  *   EALREADY - property for dependent already exists in sc_trans's pg
3259  *   EEXIST - dependency pg already exists in target (error printed)
3260  *   EBUSY - target deleted (error printed)
3261  *         - property group changed during import (error printed)
3262  */
3263 static int
3264 lscf_dependent_import(void *a1, void *pvt)
3265 {
3266 	pgroup_t *pgrp = a1;
3267 	scf_callback_t *lcbdata = pvt;
3268 
3269 	int isservice;
3270 	int ret;
3271 	scf_transaction_entry_t *e;
3272 	scf_value_t *val;
3273 	scf_callback_t dependent_cbdata;
3274 	scf_error_t scfe;
3275 
3276 	/*
3277 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3278 	 * it's invalid, we fail before modifying the repository.
3279 	 */
3280 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3281 	    &dependent_cbdata.sc_parent, &isservice);
3282 	switch (scfe) {
3283 	case SCF_ERROR_NONE:
3284 		break;
3285 
3286 	case SCF_ERROR_NO_MEMORY:
3287 		return (stash_scferror_err(lcbdata, scfe));
3288 
3289 	case SCF_ERROR_INVALID_ARGUMENT:
3290 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3291 		    "invalid.\n"), pgrp->sc_pgroup_name);
3292 		return (stash_scferror_err(lcbdata, scfe));
3293 
3294 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3295 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3296 		    "specifies neither a service nor an instance.\n"),
3297 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3298 		return (stash_scferror_err(lcbdata, scfe));
3299 
3300 	case SCF_ERROR_NOT_FOUND:
3301 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3302 		    &dependent_cbdata.sc_parent, &isservice);
3303 		switch (scfe) {
3304 		case SCF_ERROR_NONE:
3305 			break;
3306 
3307 		case SCF_ERROR_NO_MEMORY:
3308 		case SCF_ERROR_BACKEND_READONLY:
3309 		case SCF_ERROR_BACKEND_ACCESS:
3310 			return (stash_scferror_err(lcbdata, scfe));
3311 
3312 		case SCF_ERROR_NOT_FOUND:
3313 			semerr(gettext("The scope in FMRI \"%s\" for the "
3314 			    "\"%s\" dependent does not exist.\n"),
3315 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3316 			lcbdata->sc_err = EINVAL;
3317 			return (UU_WALK_ERROR);
3318 
3319 		case SCF_ERROR_PERMISSION_DENIED:
3320 			warn(gettext(
3321 			    "Could not create %s (permission denied).\n"),
3322 			    pgrp->sc_pgroup_fmri);
3323 			return (stash_scferror_err(lcbdata, scfe));
3324 
3325 		case SCF_ERROR_INVALID_ARGUMENT:
3326 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3327 		default:
3328 			bad_error("create_entity", scfe);
3329 		}
3330 		break;
3331 
3332 	default:
3333 		bad_error("fmri_to_entity", scfe);
3334 	}
3335 
3336 	if (lcbdata->sc_trans != NULL) {
3337 		e = scf_entry_create(lcbdata->sc_handle);
3338 		if (e == NULL) {
3339 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3340 				bad_error("scf_entry_create", scf_error());
3341 
3342 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3343 			return (stash_scferror(lcbdata));
3344 		}
3345 
3346 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3347 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3348 			switch (scf_error()) {
3349 			case SCF_ERROR_INVALID_ARGUMENT:
3350 				warn(gettext("Dependent of %s has invalid name "
3351 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3352 				    pgrp->sc_pgroup_name);
3353 				/* FALLTHROUGH */
3354 
3355 			case SCF_ERROR_DELETED:
3356 			case SCF_ERROR_CONNECTION_BROKEN:
3357 				scf_entry_destroy(e);
3358 				entity_destroy(dependent_cbdata.sc_parent,
3359 				    isservice);
3360 				return (stash_scferror(lcbdata));
3361 
3362 			case SCF_ERROR_EXISTS:
3363 				scf_entry_destroy(e);
3364 				entity_destroy(dependent_cbdata.sc_parent,
3365 				    isservice);
3366 				lcbdata->sc_err = EALREADY;
3367 				return (UU_WALK_ERROR);
3368 
3369 			case SCF_ERROR_NOT_BOUND:
3370 			case SCF_ERROR_HANDLE_MISMATCH:
3371 			case SCF_ERROR_NOT_SET:
3372 			default:
3373 				bad_error("scf_transaction_property_new",
3374 				    scf_error());
3375 			}
3376 		}
3377 
3378 		val = scf_value_create(lcbdata->sc_handle);
3379 		if (val == NULL) {
3380 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3381 				bad_error("scf_value_create", scf_error());
3382 
3383 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3384 			return (stash_scferror(lcbdata));
3385 		}
3386 
3387 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3388 		    pgrp->sc_pgroup_fmri) != 0)
3389 			/* invalid should have been caught above */
3390 			bad_error("scf_value_set_from_string", scf_error());
3391 
3392 		if (scf_entry_add_value(e, val) != 0)
3393 			bad_error("scf_entry_add_value", scf_error());
3394 	}
3395 
3396 	/* Add the property group to the target entity. */
3397 
3398 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3399 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3400 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3401 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3402 
3403 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3404 
3405 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3406 
3407 	if (ret == UU_WALK_NEXT)
3408 		return (ret);
3409 
3410 	if (ret != UU_WALK_ERROR)
3411 		bad_error("entity_pgroup_import", ret);
3412 
3413 	switch (dependent_cbdata.sc_err) {
3414 	case ECANCELED:
3415 		warn(gettext("%s deleted unexpectedly.\n"),
3416 		    pgrp->sc_pgroup_fmri);
3417 		lcbdata->sc_err = EBUSY;
3418 		break;
3419 
3420 	case EEXIST:
3421 		warn(gettext("Could not create \"%s\" dependency in %s "
3422 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3423 		    pgrp->sc_pgroup_fmri);
3424 		/* FALLTHROUGH */
3425 
3426 	default:
3427 		lcbdata->sc_err = dependent_cbdata.sc_err;
3428 	}
3429 
3430 	return (UU_WALK_ERROR);
3431 }
3432 
3433 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3434     const scf_snaplevel_t *, scf_transaction_t *);
3435 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3436     const pgroup_t *);
3437 
3438 /*
3439  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3440  * the current dependent targets from running (the snaplevel of a running
3441  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3442  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3443  * dependent targets and dependency properties from li_dpts_pg (the
3444  * "dependents" property group in snpl) and snpl (the snaplevel which
3445  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3446  * snpl doesn't have a "dependents" property group, and any dependents in ient
3447  * are new.
3448  *
3449  * Returns
3450  *   0 - success
3451  *   ECONNABORTED - repository connection broken
3452  *   ENOMEM - out of memory
3453  *   ENOSPC - configd is out of resources
3454  *   ECANCELED - ent was deleted
3455  *   ENODEV - the entity containing li_dpts_pg was deleted
3456  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3457  *	   - couldn't upgrade dependent (permission denied) (error printed)
3458  *	   - couldn't create dependent (permission denied) (error printed)
3459  *   EROFS - could not modify dependents pg (repository read-only)
3460  *	   - couldn't upgrade dependent (repository read-only)
3461  *	   - couldn't create dependent (repository read-only)
3462  *   EACCES - could not modify dependents pg (backend access denied)
3463  *	    - could not upgrade dependent (backend access denied)
3464  *	    - could not create dependent (backend access denied)
3465  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3466  *	   - dependent target deleted (error printed)
3467  *	   - dependent pg changed (error printed)
3468  *   EINVAL - new dependent is invalid (error printed)
3469  *   EBADF - snpl is corrupt (error printed)
3470  *	   - snpl has corrupt pg (error printed)
3471  *	   - dependency pg in target is corrupt (error printed)
3472  *	   - target has corrupt snapshot (error printed)
3473  *   EEXIST - dependency pg already existed in target service (error printed)
3474  */
3475 static int
3476 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3477     const scf_snaplevel_t *snpl, const entity_t *ient,
3478     const scf_snaplevel_t *running, void *ent)
3479 {
3480 	pgroup_t *new_dpt_pgroup;
3481 	scf_callback_t cbdata;
3482 	int r, unseen, tx_started = 0;
3483 	int have_cur_depts;
3484 
3485 	const char * const dependents = "dependents";
3486 
3487 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3488 
3489 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3490 		/* Nothing to do. */
3491 		return (0);
3492 
3493 	/* Fetch the current version of the "dependents" property group. */
3494 	have_cur_depts = 1;
3495 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3496 		switch (scf_error()) {
3497 		case SCF_ERROR_NOT_FOUND:
3498 			break;
3499 
3500 		case SCF_ERROR_DELETED:
3501 		case SCF_ERROR_CONNECTION_BROKEN:
3502 			return (scferror2errno(scf_error()));
3503 
3504 		case SCF_ERROR_NOT_SET:
3505 		case SCF_ERROR_INVALID_ARGUMENT:
3506 		case SCF_ERROR_HANDLE_MISMATCH:
3507 		case SCF_ERROR_NOT_BOUND:
3508 		default:
3509 			bad_error("entity_get_pg", scf_error());
3510 		}
3511 
3512 		have_cur_depts = 0;
3513 	}
3514 
3515 	/* Fetch the running version of the "dependents" property group. */
3516 	ud_run_dpts_pg_set = 0;
3517 	if (running != NULL)
3518 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3519 	else
3520 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3521 	if (r == 0) {
3522 		ud_run_dpts_pg_set = 1;
3523 	} else {
3524 		switch (scf_error()) {
3525 		case SCF_ERROR_NOT_FOUND:
3526 			break;
3527 
3528 		case SCF_ERROR_DELETED:
3529 		case SCF_ERROR_CONNECTION_BROKEN:
3530 			return (scferror2errno(scf_error()));
3531 
3532 		case SCF_ERROR_NOT_SET:
3533 		case SCF_ERROR_INVALID_ARGUMENT:
3534 		case SCF_ERROR_HANDLE_MISMATCH:
3535 		case SCF_ERROR_NOT_BOUND:
3536 		default:
3537 			bad_error(running ? "scf_snaplevel_get_pg" :
3538 			    "entity_get_pg", scf_error());
3539 		}
3540 	}
3541 
3542 	/*
3543 	 * Clear the seen fields of the dependents, so we can tell which ones
3544 	 * are new.
3545 	 */
3546 	if (uu_list_walk(ient->sc_dependents, clear_int,
3547 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3548 		bad_error("uu_list_walk", uu_error());
3549 
3550 	if (li_dpts_pg != NULL) {
3551 		/*
3552 		 * Each property in li_dpts_pg represents a dependent tag in
3553 		 * the old manifest.  For each, call upgrade_dependent(),
3554 		 * which will change ud_cur_depts_pg or dependencies in other
3555 		 * services as appropriate.  Note (a) that changes to
3556 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3557 		 * made en masse, and (b) it's ok if the entity doesn't have
3558 		 * a current version of the "dependents" property group,
3559 		 * because we'll just consider all dependents as customized
3560 		 * (by being deleted).
3561 		 */
3562 
3563 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3564 			switch (scf_error()) {
3565 			case SCF_ERROR_DELETED:
3566 				return (ENODEV);
3567 
3568 			case SCF_ERROR_CONNECTION_BROKEN:
3569 				return (ECONNABORTED);
3570 
3571 			case SCF_ERROR_HANDLE_MISMATCH:
3572 			case SCF_ERROR_NOT_BOUND:
3573 			case SCF_ERROR_NOT_SET:
3574 			default:
3575 				bad_error("scf_iter_pg_properties",
3576 				    scf_error());
3577 			}
3578 		}
3579 
3580 		if (have_cur_depts &&
3581 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3582 			switch (scf_error()) {
3583 			case SCF_ERROR_BACKEND_ACCESS:
3584 			case SCF_ERROR_BACKEND_READONLY:
3585 			case SCF_ERROR_CONNECTION_BROKEN:
3586 				return (scferror2errno(scf_error()));
3587 
3588 			case SCF_ERROR_DELETED:
3589 				warn(emsg_pg_deleted, ient->sc_fmri,
3590 				    dependents);
3591 				return (EBUSY);
3592 
3593 			case SCF_ERROR_PERMISSION_DENIED:
3594 				warn(emsg_pg_mod_perm, dependents,
3595 				    ient->sc_fmri);
3596 				return (scferror2errno(scf_error()));
3597 
3598 			case SCF_ERROR_HANDLE_MISMATCH:
3599 			case SCF_ERROR_IN_USE:
3600 			case SCF_ERROR_NOT_BOUND:
3601 			case SCF_ERROR_NOT_SET:
3602 			default:
3603 				bad_error("scf_transaction_start", scf_error());
3604 			}
3605 		}
3606 		tx_started = have_cur_depts;
3607 
3608 		for (;;) {
3609 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3610 			if (r == 0)
3611 				break;
3612 			if (r == 1) {
3613 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3614 				    tx_started ? ud_tx : NULL);
3615 				switch (r) {
3616 				case 0:
3617 					continue;
3618 
3619 				case ECONNABORTED:
3620 				case ENOMEM:
3621 				case ENOSPC:
3622 				case EBADF:
3623 				case EBUSY:
3624 				case EINVAL:
3625 				case EPERM:
3626 				case EROFS:
3627 				case EACCES:
3628 				case EEXIST:
3629 					break;
3630 
3631 				case ECANCELED:
3632 					r = ENODEV;
3633 					break;
3634 
3635 				default:
3636 					bad_error("upgrade_dependent", r);
3637 				}
3638 
3639 				if (tx_started)
3640 					scf_transaction_destroy_children(ud_tx);
3641 				return (r);
3642 			}
3643 			if (r != -1)
3644 				bad_error("scf_iter_next_property", r);
3645 
3646 			switch (scf_error()) {
3647 			case SCF_ERROR_DELETED:
3648 				r = ENODEV;
3649 				break;
3650 
3651 			case SCF_ERROR_CONNECTION_BROKEN:
3652 				r = ECONNABORTED;
3653 				break;
3654 
3655 			case SCF_ERROR_NOT_SET:
3656 			case SCF_ERROR_INVALID_ARGUMENT:
3657 			case SCF_ERROR_NOT_BOUND:
3658 			case SCF_ERROR_HANDLE_MISMATCH:
3659 			default:
3660 				bad_error("scf_iter_next_property",
3661 				    scf_error());
3662 			}
3663 
3664 			if (tx_started)
3665 				scf_transaction_destroy_children(ud_tx);
3666 			return (r);
3667 		}
3668 	}
3669 
3670 	/* import unseen dependents */
3671 	unseen = 0;
3672 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3673 	    new_dpt_pgroup != NULL;
3674 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3675 	    new_dpt_pgroup)) {
3676 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3677 			unseen = 1;
3678 			break;
3679 		}
3680 	}
3681 
3682 	/* If there are none, exit early. */
3683 	if (unseen == 0)
3684 		goto commit;
3685 
3686 	/* Set up for lscf_dependent_import() */
3687 	cbdata.sc_handle = g_hndl;
3688 	cbdata.sc_parent = ent;
3689 	cbdata.sc_service = issvc;
3690 	cbdata.sc_flags = 0;
3691 
3692 	if (!have_cur_depts) {
3693 		/*
3694 		 * We have new dependents to import, so we need a "dependents"
3695 		 * property group.
3696 		 */
3697 		if (issvc)
3698 			r = scf_service_add_pg(ent, dependents,
3699 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3700 		else
3701 			r = scf_instance_add_pg(ent, dependents,
3702 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3703 		if (r != 0) {
3704 			switch (scf_error()) {
3705 			case SCF_ERROR_DELETED:
3706 			case SCF_ERROR_CONNECTION_BROKEN:
3707 			case SCF_ERROR_BACKEND_READONLY:
3708 			case SCF_ERROR_BACKEND_ACCESS:
3709 			case SCF_ERROR_NO_RESOURCES:
3710 				return (scferror2errno(scf_error()));
3711 
3712 			case SCF_ERROR_EXISTS:
3713 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3714 				return (EBUSY);
3715 
3716 			case SCF_ERROR_PERMISSION_DENIED:
3717 				warn(emsg_pg_add_perm, dependents,
3718 				    ient->sc_fmri);
3719 				return (scferror2errno(scf_error()));
3720 
3721 			case SCF_ERROR_NOT_BOUND:
3722 			case SCF_ERROR_HANDLE_MISMATCH:
3723 			case SCF_ERROR_INVALID_ARGUMENT:
3724 			case SCF_ERROR_NOT_SET:
3725 			default:
3726 				bad_error("scf_service_add_pg", scf_error());
3727 			}
3728 		}
3729 	}
3730 
3731 	cbdata.sc_trans = ud_tx;
3732 
3733 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3734 		switch (scf_error()) {
3735 		case SCF_ERROR_CONNECTION_BROKEN:
3736 		case SCF_ERROR_BACKEND_ACCESS:
3737 		case SCF_ERROR_BACKEND_READONLY:
3738 			return (scferror2errno(scf_error()));
3739 
3740 		case SCF_ERROR_DELETED:
3741 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3742 			return (EBUSY);
3743 
3744 		case SCF_ERROR_PERMISSION_DENIED:
3745 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3746 			return (scferror2errno(scf_error()));
3747 
3748 		case SCF_ERROR_HANDLE_MISMATCH:
3749 		case SCF_ERROR_IN_USE:
3750 		case SCF_ERROR_NOT_BOUND:
3751 		case SCF_ERROR_NOT_SET:
3752 		default:
3753 			bad_error("scf_transaction_start", scf_error());
3754 		}
3755 	}
3756 	tx_started = 1;
3757 
3758 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3759 	    new_dpt_pgroup != NULL;
3760 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3761 	    new_dpt_pgroup)) {
3762 		if (new_dpt_pgroup->sc_pgroup_seen)
3763 			continue;
3764 
3765 		if (ud_run_dpts_pg_set) {
3766 			/*
3767 			 * If the dependent is already there, then we have
3768 			 * a conflict.
3769 			 */
3770 			if (scf_pg_get_property(ud_run_dpts_pg,
3771 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3772 				r = handle_dependent_conflict(ient, ud_prop,
3773 				    new_dpt_pgroup);
3774 				switch (r) {
3775 				case 0:
3776 					continue;
3777 
3778 				case ECONNABORTED:
3779 				case ENOMEM:
3780 				case EBUSY:
3781 				case EBADF:
3782 				case EINVAL:
3783 					scf_transaction_destroy_children(ud_tx);
3784 					return (r);
3785 
3786 				default:
3787 					bad_error("handle_dependent_conflict",
3788 					    r);
3789 				}
3790 			} else {
3791 				switch (scf_error()) {
3792 				case SCF_ERROR_NOT_FOUND:
3793 					break;
3794 
3795 				case SCF_ERROR_INVALID_ARGUMENT:
3796 					warn(emsg_fmri_invalid_pg_name,
3797 					    ient->sc_fmri,
3798 					    new_dpt_pgroup->sc_pgroup_name);
3799 					scf_transaction_destroy_children(ud_tx);
3800 					return (EINVAL);
3801 
3802 				case SCF_ERROR_DELETED:
3803 					warn(emsg_pg_deleted, ient->sc_fmri,
3804 					    new_dpt_pgroup->sc_pgroup_name);
3805 					scf_transaction_destroy_children(ud_tx);
3806 					return (EBUSY);
3807 
3808 				case SCF_ERROR_CONNECTION_BROKEN:
3809 					scf_transaction_destroy_children(ud_tx);
3810 					return (ECONNABORTED);
3811 
3812 				case SCF_ERROR_NOT_BOUND:
3813 				case SCF_ERROR_HANDLE_MISMATCH:
3814 				case SCF_ERROR_NOT_SET:
3815 				default:
3816 					bad_error("scf_pg_get_property",
3817 					    scf_error());
3818 				}
3819 			}
3820 		}
3821 
3822 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3823 		if (r != UU_WALK_NEXT) {
3824 			if (r != UU_WALK_ERROR)
3825 				bad_error("lscf_dependent_import", r);
3826 
3827 			if (cbdata.sc_err == EALREADY) {
3828 				/* Collisions were handled preemptively. */
3829 				bad_error("lscf_dependent_import",
3830 				    cbdata.sc_err);
3831 			}
3832 
3833 			scf_transaction_destroy_children(ud_tx);
3834 			return (cbdata.sc_err);
3835 		}
3836 	}
3837 
3838 commit:
3839 	if (!tx_started)
3840 		return (0);
3841 
3842 	r = scf_transaction_commit(ud_tx);
3843 
3844 	scf_transaction_destroy_children(ud_tx);
3845 
3846 	switch (r) {
3847 	case 1:
3848 		return (0);
3849 
3850 	case 0:
3851 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3852 		return (EBUSY);
3853 
3854 	case -1:
3855 		break;
3856 
3857 	default:
3858 		bad_error("scf_transaction_commit", r);
3859 	}
3860 
3861 	switch (scf_error()) {
3862 	case SCF_ERROR_CONNECTION_BROKEN:
3863 	case SCF_ERROR_BACKEND_READONLY:
3864 	case SCF_ERROR_BACKEND_ACCESS:
3865 	case SCF_ERROR_NO_RESOURCES:
3866 		return (scferror2errno(scf_error()));
3867 
3868 	case SCF_ERROR_DELETED:
3869 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3870 		return (EBUSY);
3871 
3872 	case SCF_ERROR_PERMISSION_DENIED:
3873 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3874 		return (scferror2errno(scf_error()));
3875 
3876 	case SCF_ERROR_NOT_BOUND:
3877 	case SCF_ERROR_INVALID_ARGUMENT:
3878 	case SCF_ERROR_NOT_SET:
3879 	default:
3880 		bad_error("scf_transaction_destroy", scf_error());
3881 		/* NOTREACHED */
3882 	}
3883 }
3884 
3885 /*
3886  * Used to add the manifests to the list of currently supported manifests.
3887  * We can modify the existing manifest list removing entries if the files
3888  * don't exist.
3889  *
3890  * Get the old list and the new file name
3891  * If the new file name is in the list return
3892  * If not then add the file to the list.
3893  * As we process the list check to see if the files in the old list exist
3894  * 	if not then remove the file from the list.
3895  * Commit the list of manifest file names.
3896  *
3897  */
3898 static int
3899 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3900     const scf_snaplevel_t *running, void *ent)
3901 {
3902 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3903 	scf_property_t *ud_prop = NULL;
3904 	scf_iter_t *ud_prop_iter;
3905 	scf_value_t *fname_value;
3906 	scf_callback_t cbdata;
3907 	pgroup_t *mfst_pgroup;
3908 	property_t *mfst_prop;
3909 	property_t *old_prop;
3910 	char *pname;
3911 	char *fval;
3912 	char *old_pname;
3913 	char *old_fval;
3914 	int no_upgrade_pg;
3915 	int mfst_seen;
3916 	int r;
3917 
3918 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3919 
3920 	/*
3921 	 * This should always be the service base on the code
3922 	 * path, and the fact that the manifests pg is a service
3923 	 * level property group only.
3924 	 */
3925 	ud_mfsts_pg = scf_pg_create(g_hndl);
3926 	ud_prop = scf_property_create(g_hndl);
3927 	ud_prop_iter = scf_iter_create(g_hndl);
3928 	fname_value = scf_value_create(g_hndl);
3929 
3930 	/* Fetch the "manifests" property group */
3931 	no_upgrade_pg = 0;
3932 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3933 	    ud_mfsts_pg);
3934 	if (r != 0) {
3935 		switch (scf_error()) {
3936 		case SCF_ERROR_NOT_FOUND:
3937 			no_upgrade_pg = 1;
3938 			break;
3939 
3940 		case SCF_ERROR_DELETED:
3941 		case SCF_ERROR_CONNECTION_BROKEN:
3942 			return (scferror2errno(scf_error()));
3943 
3944 		case SCF_ERROR_NOT_SET:
3945 		case SCF_ERROR_INVALID_ARGUMENT:
3946 		case SCF_ERROR_HANDLE_MISMATCH:
3947 		case SCF_ERROR_NOT_BOUND:
3948 		default:
3949 			bad_error(running ? "scf_snaplevel_get_pg" :
3950 			    "entity_get_pg", scf_error());
3951 		}
3952 	}
3953 
3954 	if (no_upgrade_pg) {
3955 		cbdata.sc_handle = g_hndl;
3956 		cbdata.sc_parent = ent;
3957 		cbdata.sc_service = issvc;
3958 		cbdata.sc_flags = SCI_FORCE;
3959 		cbdata.sc_source_fmri = ient->sc_fmri;
3960 		cbdata.sc_target_fmri = ient->sc_fmri;
3961 
3962 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3963 			return (cbdata.sc_err);
3964 
3965 		return (0);
3966 	}
3967 
3968 	/* Fetch the new manifests property group */
3969 	mfst_pgroup = internal_pgroup_find_or_create(ient,
3970 	    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3971 	assert(mfst_pgroup != NULL);
3972 
3973 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3974 	    SCF_SUCCESS)
3975 		return (-1);
3976 
3977 	if ((pname = malloc(MAXPATHLEN)) == NULL)
3978 		return (ENOMEM);
3979 	if ((fval = malloc(MAXPATHLEN)) == NULL) {
3980 		free(pname);
3981 		return (ENOMEM);
3982 	}
3983 
3984 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3985 		mfst_seen = 0;
3986 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3987 			continue;
3988 
3989 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3990 		    mfst_prop != NULL;
3991 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3992 		    mfst_prop)) {
3993 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3994 				mfst_seen = 1;
3995 			}
3996 		}
3997 
3998 		/*
3999 		 * If the manifest is not seen then add it to the new mfst
4000 		 * property list to get proccessed into the repo.
4001 		 */
4002 		if (mfst_seen == 0) {
4003 			/*
4004 			 * If we cannot get the value then there is no
4005 			 * reason to attempt to attach the value to
4006 			 * the property group
4007 			 */
4008 			if (prop_get_val(ud_prop, fname_value) == 0 &&
4009 			    scf_value_get_astring(fname_value, fval,
4010 			    MAXPATHLEN) != -1)  {
4011 				old_pname = safe_strdup(pname);
4012 				old_fval = safe_strdup(fval);
4013 				old_prop = internal_property_create(old_pname,
4014 				    SCF_TYPE_ASTRING, 1, old_fval);
4015 
4016 				/*
4017 				 * Already checked to see if the property exists
4018 				 * in the group, and it does not.
4019 				 */
4020 				(void) internal_attach_property(mfst_pgroup,
4021 				    old_prop);
4022 			}
4023 		}
4024 	}
4025 	free(pname);
4026 	free(fval);
4027 
4028 	cbdata.sc_handle = g_hndl;
4029 	cbdata.sc_parent = ent;
4030 	cbdata.sc_service = issvc;
4031 	cbdata.sc_flags = SCI_FORCE;
4032 	cbdata.sc_source_fmri = ient->sc_fmri;
4033 	cbdata.sc_target_fmri = ient->sc_fmri;
4034 
4035 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4036 		return (cbdata.sc_err);
4037 
4038 	return (r);
4039 }
4040 
4041 /*
4042  * prop is taken to be a property in the "dependents" property group of snpl,
4043  * which is taken to be the snaplevel of a last-import snapshot corresponding
4044  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4045  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4046  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4047  * of the entity ient represents (possibly in the running snapshot).  If it
4048  * needs to be changed, an entry will be added to tx, if not NULL.
4049  *
4050  * Returns
4051  *   0 - success
4052  *   ECONNABORTED - repository connection broken
4053  *   ENOMEM - out of memory
4054  *   ENOSPC - configd was out of resources
4055  *   ECANCELED - snpl's entity was deleted
4056  *   EINVAL - dependent target is invalid (error printed)
4057  *	    - dependent is invalid (error printed)
4058  *   EBADF - snpl is corrupt (error printed)
4059  *	   - snpl has corrupt pg (error printed)
4060  *	   - dependency pg in target is corrupt (error printed)
4061  *	   - running snapshot in dependent is missing snaplevel (error printed)
4062  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4063  *	   - couldn't create dependent (permission denied) (error printed)
4064  *	   - couldn't modify dependent pg (permission denied) (error printed)
4065  *   EROFS - couldn't delete dependency pg (repository read-only)
4066  *	   - couldn't create dependent (repository read-only)
4067  *   EACCES - couldn't delete dependency pg (backend access denied)
4068  *	    - couldn't create dependent (backend access denied)
4069  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4070  *	   - tx's pg was deleted (error printed)
4071  *	   - dependent pg was changed or deleted (error printed)
4072  *   EEXIST - dependency pg already exists in new target (error printed)
4073  */
4074 static int
4075 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4076     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4077 {
4078 	pgroup_t pgrp;
4079 	scf_type_t ty;
4080 	pgroup_t *new_dpt_pgroup;
4081 	pgroup_t *old_dpt_pgroup = NULL;
4082 	pgroup_t *current_pg;
4083 	pgroup_t *dpt;
4084 	scf_callback_t cbdata;
4085 	int tissvc;
4086 	void *target_ent;
4087 	scf_error_t serr;
4088 	int r;
4089 	scf_transaction_entry_t *ent;
4090 
4091 	const char * const cf_inval = gettext("Conflict upgrading %s "
4092 	    "(dependent \"%s\" has invalid dependents property).\n");
4093 	const char * const cf_missing = gettext("Conflict upgrading %s "
4094 	    "(dependent \"%s\" is missing).\n");
4095 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4096 	    "(dependent \"%s\" has new dependency property group).\n");
4097 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4098 	    "(dependent \"%s\" has new target).\n");
4099 	const char * const li_corrupt =
4100 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4101 	const char * const upgrading =
4102 	    gettext("%s: Upgrading dependent \"%s\".\n");
4103 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4104 	    "corrupt (missing snaplevel).\n");
4105 
4106 	if (scf_property_type(prop, &ty) != 0) {
4107 		switch (scf_error()) {
4108 		case SCF_ERROR_DELETED:
4109 		case SCF_ERROR_CONNECTION_BROKEN:
4110 			return (scferror2errno(scf_error()));
4111 
4112 		case SCF_ERROR_NOT_BOUND:
4113 		case SCF_ERROR_NOT_SET:
4114 		default:
4115 			bad_error("scf_property_type", scf_error());
4116 		}
4117 	}
4118 
4119 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4120 		warn(li_corrupt, ient->sc_fmri);
4121 		return (EBADF);
4122 	}
4123 
4124 	/*
4125 	 * prop represents a dependent in the old manifest.  It is named after
4126 	 * the dependent.
4127 	 */
4128 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4129 		switch (scf_error()) {
4130 		case SCF_ERROR_DELETED:
4131 		case SCF_ERROR_CONNECTION_BROKEN:
4132 			return (scferror2errno(scf_error()));
4133 
4134 		case SCF_ERROR_NOT_BOUND:
4135 		case SCF_ERROR_NOT_SET:
4136 		default:
4137 			bad_error("scf_property_get_name", scf_error());
4138 		}
4139 	}
4140 
4141 	/* See if it's in the new manifest. */
4142 	pgrp.sc_pgroup_name = ud_name;
4143 	new_dpt_pgroup =
4144 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4145 
4146 	/* If it's not, delete it... if it hasn't been customized. */
4147 	if (new_dpt_pgroup == NULL) {
4148 		if (!ud_run_dpts_pg_set)
4149 			return (0);
4150 
4151 		if (scf_property_get_value(prop, ud_val) != 0) {
4152 			switch (scf_error()) {
4153 			case SCF_ERROR_NOT_FOUND:
4154 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4155 				warn(li_corrupt, ient->sc_fmri);
4156 				return (EBADF);
4157 
4158 			case SCF_ERROR_DELETED:
4159 			case SCF_ERROR_CONNECTION_BROKEN:
4160 				return (scferror2errno(scf_error()));
4161 
4162 			case SCF_ERROR_HANDLE_MISMATCH:
4163 			case SCF_ERROR_NOT_BOUND:
4164 			case SCF_ERROR_NOT_SET:
4165 			case SCF_ERROR_PERMISSION_DENIED:
4166 			default:
4167 				bad_error("scf_property_get_value",
4168 				    scf_error());
4169 			}
4170 		}
4171 
4172 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4173 		    max_scf_value_len + 1) < 0)
4174 			bad_error("scf_value_get_as_string", scf_error());
4175 
4176 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4177 		    0) {
4178 			switch (scf_error()) {
4179 			case SCF_ERROR_NOT_FOUND:
4180 				return (0);
4181 
4182 			case SCF_ERROR_CONNECTION_BROKEN:
4183 				return (scferror2errno(scf_error()));
4184 
4185 			case SCF_ERROR_DELETED:
4186 				warn(emsg_pg_deleted, ient->sc_fmri,
4187 				    "dependents");
4188 				return (EBUSY);
4189 
4190 			case SCF_ERROR_INVALID_ARGUMENT:
4191 			case SCF_ERROR_NOT_BOUND:
4192 			case SCF_ERROR_HANDLE_MISMATCH:
4193 			case SCF_ERROR_NOT_SET:
4194 			default:
4195 				bad_error("scf_pg_get_property", scf_error());
4196 			}
4197 		}
4198 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4199 			switch (scf_error()) {
4200 			case SCF_ERROR_NOT_FOUND:
4201 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4202 				warn(cf_inval, ient->sc_fmri, ud_name);
4203 				return (0);
4204 
4205 			case SCF_ERROR_DELETED:
4206 			case SCF_ERROR_CONNECTION_BROKEN:
4207 				return (scferror2errno(scf_error()));
4208 
4209 			case SCF_ERROR_HANDLE_MISMATCH:
4210 			case SCF_ERROR_NOT_BOUND:
4211 			case SCF_ERROR_NOT_SET:
4212 			case SCF_ERROR_PERMISSION_DENIED:
4213 			default:
4214 				bad_error("scf_property_get_value",
4215 				    scf_error());
4216 			}
4217 		}
4218 
4219 		ty = scf_value_type(ud_val);
4220 		assert(ty != SCF_TYPE_INVALID);
4221 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4222 			warn(cf_inval, ient->sc_fmri, ud_name);
4223 			return (0);
4224 		}
4225 
4226 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4227 		    max_scf_value_len + 1) < 0)
4228 			bad_error("scf_value_get_as_string", scf_error());
4229 
4230 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4231 		switch (r) {
4232 		case 1:
4233 			break;
4234 
4235 		case 0:
4236 		case -1:	/* warn? */
4237 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4238 			return (0);
4239 
4240 		case -2:
4241 			warn(li_corrupt, ient->sc_fmri);
4242 			return (EBADF);
4243 
4244 		default:
4245 			bad_error("fmri_equal", r);
4246 		}
4247 
4248 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4249 			switch (scf_error()) {
4250 			case SCF_ERROR_NOT_FOUND:
4251 				warn(li_corrupt, ient->sc_fmri);
4252 				return (EBADF);
4253 
4254 			case SCF_ERROR_DELETED:
4255 			case SCF_ERROR_CONNECTION_BROKEN:
4256 				return (scferror2errno(scf_error()));
4257 
4258 			case SCF_ERROR_NOT_BOUND:
4259 			case SCF_ERROR_HANDLE_MISMATCH:
4260 			case SCF_ERROR_INVALID_ARGUMENT:
4261 			case SCF_ERROR_NOT_SET:
4262 			default:
4263 				bad_error("scf_snaplevel_get_pg", scf_error());
4264 			}
4265 		}
4266 
4267 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4268 		    snap_lastimport);
4269 		switch (r) {
4270 		case 0:
4271 			break;
4272 
4273 		case ECANCELED:
4274 		case ECONNABORTED:
4275 		case ENOMEM:
4276 		case EBADF:
4277 			return (r);
4278 
4279 		case EACCES:
4280 		default:
4281 			bad_error("load_pg", r);
4282 		}
4283 
4284 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4285 		switch (serr) {
4286 		case SCF_ERROR_NONE:
4287 			break;
4288 
4289 		case SCF_ERROR_NO_MEMORY:
4290 			internal_pgroup_free(old_dpt_pgroup);
4291 			return (ENOMEM);
4292 
4293 		case SCF_ERROR_NOT_FOUND:
4294 			internal_pgroup_free(old_dpt_pgroup);
4295 			goto delprop;
4296 
4297 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4298 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4299 		default:
4300 			bad_error("fmri_to_entity", serr);
4301 		}
4302 
4303 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4304 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4305 		switch (r) {
4306 		case 0:
4307 			break;
4308 
4309 		case ECONNABORTED:
4310 			internal_pgroup_free(old_dpt_pgroup);
4311 			return (r);
4312 
4313 		case ECANCELED:
4314 		case ENOENT:
4315 			internal_pgroup_free(old_dpt_pgroup);
4316 			goto delprop;
4317 
4318 		case EBADF:
4319 			warn(r_no_lvl, ud_ctarg);
4320 			internal_pgroup_free(old_dpt_pgroup);
4321 			return (r);
4322 
4323 		case EINVAL:
4324 		default:
4325 			bad_error("entity_get_running_pg", r);
4326 		}
4327 
4328 		/* load it */
4329 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4330 		switch (r) {
4331 		case 0:
4332 			break;
4333 
4334 		case ECANCELED:
4335 			internal_pgroup_free(old_dpt_pgroup);
4336 			goto delprop;
4337 
4338 		case ECONNABORTED:
4339 		case ENOMEM:
4340 		case EBADF:
4341 			internal_pgroup_free(old_dpt_pgroup);
4342 			return (r);
4343 
4344 		case EACCES:
4345 		default:
4346 			bad_error("load_pg", r);
4347 		}
4348 
4349 		/* compare property groups */
4350 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4351 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4352 			internal_pgroup_free(old_dpt_pgroup);
4353 			internal_pgroup_free(current_pg);
4354 			return (0);
4355 		}
4356 
4357 		internal_pgroup_free(old_dpt_pgroup);
4358 		internal_pgroup_free(current_pg);
4359 
4360 		if (g_verbose)
4361 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4362 			    ient->sc_fmri, ud_name);
4363 
4364 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4365 			switch (scf_error()) {
4366 			case SCF_ERROR_NOT_FOUND:
4367 			case SCF_ERROR_DELETED:
4368 				internal_pgroup_free(old_dpt_pgroup);
4369 				goto delprop;
4370 
4371 			case SCF_ERROR_CONNECTION_BROKEN:
4372 				internal_pgroup_free(old_dpt_pgroup);
4373 				return (ECONNABORTED);
4374 
4375 			case SCF_ERROR_NOT_SET:
4376 			case SCF_ERROR_INVALID_ARGUMENT:
4377 			case SCF_ERROR_HANDLE_MISMATCH:
4378 			case SCF_ERROR_NOT_BOUND:
4379 			default:
4380 				bad_error("entity_get_pg", scf_error());
4381 			}
4382 		}
4383 
4384 		if (scf_pg_delete(ud_pg) != 0) {
4385 			switch (scf_error()) {
4386 			case SCF_ERROR_DELETED:
4387 				break;
4388 
4389 			case SCF_ERROR_CONNECTION_BROKEN:
4390 			case SCF_ERROR_BACKEND_READONLY:
4391 			case SCF_ERROR_BACKEND_ACCESS:
4392 				return (scferror2errno(scf_error()));
4393 
4394 			case SCF_ERROR_PERMISSION_DENIED:
4395 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4396 				return (scferror2errno(scf_error()));
4397 
4398 			case SCF_ERROR_NOT_SET:
4399 			default:
4400 				bad_error("scf_pg_delete", scf_error());
4401 			}
4402 		}
4403 
4404 		/*
4405 		 * This service was changed, so it must be refreshed.  But
4406 		 * since it's not mentioned in the new manifest, we have to
4407 		 * record its FMRI here for use later.  We record the name
4408 		 * & the entity (via sc_parent) in case we need to print error
4409 		 * messages during the refresh.
4410 		 */
4411 		dpt = internal_pgroup_new();
4412 		if (dpt == NULL)
4413 			return (ENOMEM);
4414 		dpt->sc_pgroup_name = strdup(ud_name);
4415 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4416 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4417 			return (ENOMEM);
4418 		dpt->sc_parent = (entity_t *)ient;
4419 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4420 			uu_die(gettext("libuutil error: %s\n"),
4421 			    uu_strerror(uu_error()));
4422 
4423 delprop:
4424 		if (tx == NULL)
4425 			return (0);
4426 
4427 		ent = scf_entry_create(g_hndl);
4428 		if (ent == NULL)
4429 			return (ENOMEM);
4430 
4431 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4432 			scf_entry_destroy(ent);
4433 			switch (scf_error()) {
4434 			case SCF_ERROR_DELETED:
4435 				warn(emsg_pg_deleted, ient->sc_fmri,
4436 				    "dependents");
4437 				return (EBUSY);
4438 
4439 			case SCF_ERROR_CONNECTION_BROKEN:
4440 				return (scferror2errno(scf_error()));
4441 
4442 			case SCF_ERROR_NOT_FOUND:
4443 				break;
4444 
4445 			case SCF_ERROR_HANDLE_MISMATCH:
4446 			case SCF_ERROR_NOT_BOUND:
4447 			case SCF_ERROR_INVALID_ARGUMENT:
4448 			case SCF_ERROR_NOT_SET:
4449 			default:
4450 				bad_error("scf_transaction_property_delete",
4451 				    scf_error());
4452 			}
4453 		}
4454 
4455 		return (0);
4456 	}
4457 
4458 	new_dpt_pgroup->sc_pgroup_seen = 1;
4459 
4460 	/*
4461 	 * Decide whether the dependent has changed in the manifest.
4462 	 */
4463 	/* Compare the target. */
4464 	if (scf_property_get_value(prop, ud_val) != 0) {
4465 		switch (scf_error()) {
4466 		case SCF_ERROR_NOT_FOUND:
4467 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4468 			warn(li_corrupt, ient->sc_fmri);
4469 			return (EBADF);
4470 
4471 		case SCF_ERROR_DELETED:
4472 		case SCF_ERROR_CONNECTION_BROKEN:
4473 			return (scferror2errno(scf_error()));
4474 
4475 		case SCF_ERROR_HANDLE_MISMATCH:
4476 		case SCF_ERROR_NOT_BOUND:
4477 		case SCF_ERROR_NOT_SET:
4478 		case SCF_ERROR_PERMISSION_DENIED:
4479 		default:
4480 			bad_error("scf_property_get_value", scf_error());
4481 		}
4482 	}
4483 
4484 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4485 	    0)
4486 		bad_error("scf_value_get_as_string", scf_error());
4487 
4488 	/*
4489 	 * If the fmri's are not equal then the old fmri will need to
4490 	 * be refreshed to ensure that the changes are properly updated
4491 	 * in that service.
4492 	 */
4493 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4494 	switch (r) {
4495 	case 0:
4496 		dpt = internal_pgroup_new();
4497 		if (dpt == NULL)
4498 			return (ENOMEM);
4499 		dpt->sc_pgroup_name = strdup(ud_name);
4500 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4501 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4502 			return (ENOMEM);
4503 		dpt->sc_parent = (entity_t *)ient;
4504 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4505 			uu_die(gettext("libuutil error: %s\n"),
4506 			    uu_strerror(uu_error()));
4507 		break;
4508 
4509 	case 1:
4510 		/* Compare the dependency pgs. */
4511 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4512 			switch (scf_error()) {
4513 			case SCF_ERROR_NOT_FOUND:
4514 				warn(li_corrupt, ient->sc_fmri);
4515 				return (EBADF);
4516 
4517 			case SCF_ERROR_DELETED:
4518 			case SCF_ERROR_CONNECTION_BROKEN:
4519 				return (scferror2errno(scf_error()));
4520 
4521 			case SCF_ERROR_NOT_BOUND:
4522 			case SCF_ERROR_HANDLE_MISMATCH:
4523 			case SCF_ERROR_INVALID_ARGUMENT:
4524 			case SCF_ERROR_NOT_SET:
4525 			default:
4526 				bad_error("scf_snaplevel_get_pg", scf_error());
4527 			}
4528 		}
4529 
4530 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4531 		    snap_lastimport);
4532 		switch (r) {
4533 		case 0:
4534 			break;
4535 
4536 		case ECANCELED:
4537 		case ECONNABORTED:
4538 		case ENOMEM:
4539 		case EBADF:
4540 			return (r);
4541 
4542 		case EACCES:
4543 		default:
4544 			bad_error("load_pg", r);
4545 		}
4546 
4547 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4548 			/* no change, leave customizations */
4549 			internal_pgroup_free(old_dpt_pgroup);
4550 			return (0);
4551 		}
4552 		break;
4553 
4554 	case -1:
4555 		warn(li_corrupt, ient->sc_fmri);
4556 		return (EBADF);
4557 
4558 	case -2:
4559 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4560 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4561 		return (EINVAL);
4562 
4563 	default:
4564 		bad_error("fmri_equal", r);
4565 	}
4566 
4567 	/*
4568 	 * The dependent has changed in the manifest.  Upgrade the current
4569 	 * properties if they haven't been customized.
4570 	 */
4571 
4572 	/*
4573 	 * If new_dpt_pgroup->sc_override, then act as though the property
4574 	 * group hasn't been customized.
4575 	 */
4576 	if (new_dpt_pgroup->sc_pgroup_override) {
4577 		(void) strcpy(ud_ctarg, ud_oldtarg);
4578 		goto nocust;
4579 	}
4580 
4581 	if (!ud_run_dpts_pg_set) {
4582 		warn(cf_missing, ient->sc_fmri, ud_name);
4583 		r = 0;
4584 		goto out;
4585 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4586 		switch (scf_error()) {
4587 		case SCF_ERROR_NOT_FOUND:
4588 			warn(cf_missing, ient->sc_fmri, ud_name);
4589 			r = 0;
4590 			goto out;
4591 
4592 		case SCF_ERROR_CONNECTION_BROKEN:
4593 			r = scferror2errno(scf_error());
4594 			goto out;
4595 
4596 		case SCF_ERROR_DELETED:
4597 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4598 			r = EBUSY;
4599 			goto out;
4600 
4601 		case SCF_ERROR_INVALID_ARGUMENT:
4602 		case SCF_ERROR_NOT_BOUND:
4603 		case SCF_ERROR_HANDLE_MISMATCH:
4604 		case SCF_ERROR_NOT_SET:
4605 		default:
4606 			bad_error("scf_pg_get_property", scf_error());
4607 		}
4608 	}
4609 
4610 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4611 		switch (scf_error()) {
4612 		case SCF_ERROR_NOT_FOUND:
4613 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4614 			warn(cf_inval, ient->sc_fmri, ud_name);
4615 			r = 0;
4616 			goto out;
4617 
4618 		case SCF_ERROR_DELETED:
4619 		case SCF_ERROR_CONNECTION_BROKEN:
4620 			r = scferror2errno(scf_error());
4621 			goto out;
4622 
4623 		case SCF_ERROR_HANDLE_MISMATCH:
4624 		case SCF_ERROR_NOT_BOUND:
4625 		case SCF_ERROR_NOT_SET:
4626 		case SCF_ERROR_PERMISSION_DENIED:
4627 		default:
4628 			bad_error("scf_property_get_value", scf_error());
4629 		}
4630 	}
4631 
4632 	ty = scf_value_type(ud_val);
4633 	assert(ty != SCF_TYPE_INVALID);
4634 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4635 		warn(cf_inval, ient->sc_fmri, ud_name);
4636 		r = 0;
4637 		goto out;
4638 	}
4639 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4640 	    0)
4641 		bad_error("scf_value_get_as_string", scf_error());
4642 
4643 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4644 	if (r == -1) {
4645 		warn(cf_inval, ient->sc_fmri, ud_name);
4646 		r = 0;
4647 		goto out;
4648 	} else if (r == -2) {
4649 		warn(li_corrupt, ient->sc_fmri);
4650 		r = EBADF;
4651 		goto out;
4652 	} else if (r == 0) {
4653 		/*
4654 		 * Target has been changed.  Only abort now if it's been
4655 		 * changed to something other than what's in the manifest.
4656 		 */
4657 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4658 		if (r == -1) {
4659 			warn(cf_inval, ient->sc_fmri, ud_name);
4660 			r = 0;
4661 			goto out;
4662 		} else if (r == 0) {
4663 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4664 			r = 0;
4665 			goto out;
4666 		} else if (r != 1) {
4667 			/* invalid sc_pgroup_fmri caught above */
4668 			bad_error("fmri_equal", r);
4669 		}
4670 
4671 		/*
4672 		 * Fetch the current dependency pg.  If it's what the manifest
4673 		 * says, then no problem.
4674 		 */
4675 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4676 		switch (serr) {
4677 		case SCF_ERROR_NONE:
4678 			break;
4679 
4680 		case SCF_ERROR_NOT_FOUND:
4681 			warn(cf_missing, ient->sc_fmri, ud_name);
4682 			r = 0;
4683 			goto out;
4684 
4685 		case SCF_ERROR_NO_MEMORY:
4686 			r = ENOMEM;
4687 			goto out;
4688 
4689 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4690 		case SCF_ERROR_INVALID_ARGUMENT:
4691 		default:
4692 			bad_error("fmri_to_entity", serr);
4693 		}
4694 
4695 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4696 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4697 		switch (r) {
4698 		case 0:
4699 			break;
4700 
4701 		case ECONNABORTED:
4702 			goto out;
4703 
4704 		case ECANCELED:
4705 		case ENOENT:
4706 			warn(cf_missing, ient->sc_fmri, ud_name);
4707 			r = 0;
4708 			goto out;
4709 
4710 		case EBADF:
4711 			warn(r_no_lvl, ud_ctarg);
4712 			goto out;
4713 
4714 		case EINVAL:
4715 		default:
4716 			bad_error("entity_get_running_pg", r);
4717 		}
4718 
4719 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4720 		switch (r) {
4721 		case 0:
4722 			break;
4723 
4724 		case ECANCELED:
4725 			warn(cf_missing, ient->sc_fmri, ud_name);
4726 			r = 0;
4727 			goto out;
4728 
4729 		case ECONNABORTED:
4730 		case ENOMEM:
4731 		case EBADF:
4732 			goto out;
4733 
4734 		case EACCES:
4735 		default:
4736 			bad_error("load_pg", r);
4737 		}
4738 
4739 		if (!pg_equal(current_pg, new_dpt_pgroup))
4740 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4741 		internal_pgroup_free(current_pg);
4742 		r = 0;
4743 		goto out;
4744 	} else if (r != 1) {
4745 		bad_error("fmri_equal", r);
4746 	}
4747 
4748 nocust:
4749 	/*
4750 	 * Target has not been customized.  Check the dependency property
4751 	 * group.
4752 	 */
4753 
4754 	if (old_dpt_pgroup == NULL) {
4755 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4756 		    ud_pg) != 0) {
4757 			switch (scf_error()) {
4758 			case SCF_ERROR_NOT_FOUND:
4759 				warn(li_corrupt, ient->sc_fmri);
4760 				return (EBADF);
4761 
4762 			case SCF_ERROR_DELETED:
4763 			case SCF_ERROR_CONNECTION_BROKEN:
4764 				return (scferror2errno(scf_error()));
4765 
4766 			case SCF_ERROR_NOT_BOUND:
4767 			case SCF_ERROR_HANDLE_MISMATCH:
4768 			case SCF_ERROR_INVALID_ARGUMENT:
4769 			case SCF_ERROR_NOT_SET:
4770 			default:
4771 				bad_error("scf_snaplevel_get_pg", scf_error());
4772 			}
4773 		}
4774 
4775 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4776 		    snap_lastimport);
4777 		switch (r) {
4778 		case 0:
4779 			break;
4780 
4781 		case ECANCELED:
4782 		case ECONNABORTED:
4783 		case ENOMEM:
4784 		case EBADF:
4785 			return (r);
4786 
4787 		case EACCES:
4788 		default:
4789 			bad_error("load_pg", r);
4790 		}
4791 	}
4792 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4793 	switch (serr) {
4794 	case SCF_ERROR_NONE:
4795 		break;
4796 
4797 	case SCF_ERROR_NOT_FOUND:
4798 		warn(cf_missing, ient->sc_fmri, ud_name);
4799 		r = 0;
4800 		goto out;
4801 
4802 	case SCF_ERROR_NO_MEMORY:
4803 		r = ENOMEM;
4804 		goto out;
4805 
4806 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4807 	case SCF_ERROR_INVALID_ARGUMENT:
4808 	default:
4809 		bad_error("fmri_to_entity", serr);
4810 	}
4811 
4812 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4813 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4814 	switch (r) {
4815 	case 0:
4816 		break;
4817 
4818 	case ECONNABORTED:
4819 		goto out;
4820 
4821 	case ECANCELED:
4822 	case ENOENT:
4823 		warn(cf_missing, ient->sc_fmri, ud_name);
4824 		r = 0;
4825 		goto out;
4826 
4827 	case EBADF:
4828 		warn(r_no_lvl, ud_ctarg);
4829 		goto out;
4830 
4831 	case EINVAL:
4832 	default:
4833 		bad_error("entity_get_running_pg", r);
4834 	}
4835 
4836 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4837 	switch (r) {
4838 	case 0:
4839 		break;
4840 
4841 	case ECANCELED:
4842 		warn(cf_missing, ient->sc_fmri, ud_name);
4843 		goto out;
4844 
4845 	case ECONNABORTED:
4846 	case ENOMEM:
4847 	case EBADF:
4848 		goto out;
4849 
4850 	case EACCES:
4851 	default:
4852 		bad_error("load_pg", r);
4853 	}
4854 
4855 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4856 		if (!pg_equal(current_pg, new_dpt_pgroup))
4857 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4858 		internal_pgroup_free(current_pg);
4859 		r = 0;
4860 		goto out;
4861 	}
4862 
4863 	/* Uncustomized.  Upgrade. */
4864 
4865 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4866 	switch (r) {
4867 	case 1:
4868 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4869 			/* Already upgraded. */
4870 			internal_pgroup_free(current_pg);
4871 			r = 0;
4872 			goto out;
4873 		}
4874 
4875 		internal_pgroup_free(current_pg);
4876 
4877 		/* upgrade current_pg */
4878 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4879 			switch (scf_error()) {
4880 			case SCF_ERROR_CONNECTION_BROKEN:
4881 				r = scferror2errno(scf_error());
4882 				goto out;
4883 
4884 			case SCF_ERROR_DELETED:
4885 				warn(cf_missing, ient->sc_fmri, ud_name);
4886 				r = 0;
4887 				goto out;
4888 
4889 			case SCF_ERROR_NOT_FOUND:
4890 				break;
4891 
4892 			case SCF_ERROR_INVALID_ARGUMENT:
4893 			case SCF_ERROR_NOT_BOUND:
4894 			case SCF_ERROR_NOT_SET:
4895 			case SCF_ERROR_HANDLE_MISMATCH:
4896 			default:
4897 				bad_error("entity_get_pg", scf_error());
4898 			}
4899 
4900 			if (tissvc)
4901 				r = scf_service_add_pg(target_ent, ud_name,
4902 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4903 			else
4904 				r = scf_instance_add_pg(target_ent, ud_name,
4905 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 			if (r != 0) {
4907 				switch (scf_error()) {
4908 				case SCF_ERROR_CONNECTION_BROKEN:
4909 				case SCF_ERROR_NO_RESOURCES:
4910 				case SCF_ERROR_BACKEND_READONLY:
4911 				case SCF_ERROR_BACKEND_ACCESS:
4912 					r = scferror2errno(scf_error());
4913 					goto out;
4914 
4915 				case SCF_ERROR_DELETED:
4916 					warn(cf_missing, ient->sc_fmri,
4917 					    ud_name);
4918 					r = 0;
4919 					goto out;
4920 
4921 				case SCF_ERROR_PERMISSION_DENIED:
4922 					warn(emsg_pg_deleted, ud_ctarg,
4923 					    ud_name);
4924 					r = EPERM;
4925 					goto out;
4926 
4927 				case SCF_ERROR_EXISTS:
4928 					warn(emsg_pg_added, ud_ctarg, ud_name);
4929 					r = EBUSY;
4930 					goto out;
4931 
4932 				case SCF_ERROR_NOT_BOUND:
4933 				case SCF_ERROR_HANDLE_MISMATCH:
4934 				case SCF_ERROR_INVALID_ARGUMENT:
4935 				case SCF_ERROR_NOT_SET:
4936 				default:
4937 					bad_error("entity_add_pg", scf_error());
4938 				}
4939 			}
4940 		}
4941 
4942 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4943 		switch (r) {
4944 		case 0:
4945 			break;
4946 
4947 		case ECANCELED:
4948 			warn(cf_missing, ient->sc_fmri, ud_name);
4949 			goto out;
4950 
4951 		case ECONNABORTED:
4952 		case ENOMEM:
4953 		case EBADF:
4954 			goto out;
4955 
4956 		case EACCES:
4957 		default:
4958 			bad_error("load_pg", r);
4959 		}
4960 
4961 		if (g_verbose)
4962 			warn(upgrading, ient->sc_fmri, ud_name);
4963 
4964 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4965 		    new_dpt_pgroup, 0, ient->sc_fmri);
4966 		switch (r) {
4967 		case 0:
4968 			break;
4969 
4970 		case ECANCELED:
4971 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4972 			r = EBUSY;
4973 			goto out;
4974 
4975 		case EPERM:
4976 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4977 			goto out;
4978 
4979 		case EBUSY:
4980 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4981 			goto out;
4982 
4983 		case ECONNABORTED:
4984 		case ENOMEM:
4985 		case ENOSPC:
4986 		case EROFS:
4987 		case EACCES:
4988 		case EINVAL:
4989 			goto out;
4990 
4991 		default:
4992 			bad_error("upgrade_pg", r);
4993 		}
4994 		break;
4995 
4996 	case 0: {
4997 		scf_transaction_entry_t *ent;
4998 		scf_value_t *val;
4999 
5000 		internal_pgroup_free(current_pg);
5001 
5002 		/* delete old pg */
5003 		if (g_verbose)
5004 			warn(upgrading, ient->sc_fmri, ud_name);
5005 
5006 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5007 			switch (scf_error()) {
5008 			case SCF_ERROR_CONNECTION_BROKEN:
5009 				r = scferror2errno(scf_error());
5010 				goto out;
5011 
5012 			case SCF_ERROR_DELETED:
5013 				warn(cf_missing, ient->sc_fmri, ud_name);
5014 				r = 0;
5015 				goto out;
5016 
5017 			case SCF_ERROR_NOT_FOUND:
5018 				break;
5019 
5020 			case SCF_ERROR_INVALID_ARGUMENT:
5021 			case SCF_ERROR_NOT_BOUND:
5022 			case SCF_ERROR_NOT_SET:
5023 			case SCF_ERROR_HANDLE_MISMATCH:
5024 			default:
5025 				bad_error("entity_get_pg", scf_error());
5026 			}
5027 		} else if (scf_pg_delete(ud_pg) != 0) {
5028 			switch (scf_error()) {
5029 			case SCF_ERROR_DELETED:
5030 				break;
5031 
5032 			case SCF_ERROR_CONNECTION_BROKEN:
5033 			case SCF_ERROR_BACKEND_READONLY:
5034 			case SCF_ERROR_BACKEND_ACCESS:
5035 				r = scferror2errno(scf_error());
5036 				goto out;
5037 
5038 			case SCF_ERROR_PERMISSION_DENIED:
5039 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5040 				r = scferror2errno(scf_error());
5041 				goto out;
5042 
5043 			case SCF_ERROR_NOT_SET:
5044 			default:
5045 				bad_error("scf_pg_delete", scf_error());
5046 			}
5047 		}
5048 
5049 		/* import new one */
5050 		cbdata.sc_handle = g_hndl;
5051 		cbdata.sc_trans = NULL;		/* handled below */
5052 		cbdata.sc_flags = 0;
5053 
5054 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5055 		if (r != UU_WALK_NEXT) {
5056 			if (r != UU_WALK_ERROR)
5057 				bad_error("lscf_dependent_import", r);
5058 
5059 			r = cbdata.sc_err;
5060 			goto out;
5061 		}
5062 
5063 		if (tx == NULL)
5064 			break;
5065 
5066 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5067 		    (val = scf_value_create(g_hndl)) == NULL) {
5068 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5069 				return (ENOMEM);
5070 
5071 			bad_error("scf_entry_create", scf_error());
5072 		}
5073 
5074 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5075 		    SCF_TYPE_FMRI) != 0) {
5076 			switch (scf_error()) {
5077 			case SCF_ERROR_CONNECTION_BROKEN:
5078 				r = scferror2errno(scf_error());
5079 				goto out;
5080 
5081 			case SCF_ERROR_DELETED:
5082 				warn(emsg_pg_deleted, ient->sc_fmri,
5083 				    "dependents");
5084 				r = EBUSY;
5085 				goto out;
5086 
5087 			case SCF_ERROR_NOT_FOUND:
5088 				break;
5089 
5090 			case SCF_ERROR_NOT_BOUND:
5091 			case SCF_ERROR_HANDLE_MISMATCH:
5092 			case SCF_ERROR_INVALID_ARGUMENT:
5093 			case SCF_ERROR_NOT_SET:
5094 			default:
5095 				bad_error("scf_transaction_property_"
5096 				    "change_type", scf_error());
5097 			}
5098 
5099 			if (scf_transaction_property_new(tx, ent, ud_name,
5100 			    SCF_TYPE_FMRI) != 0) {
5101 				switch (scf_error()) {
5102 				case SCF_ERROR_CONNECTION_BROKEN:
5103 					r = scferror2errno(scf_error());
5104 					goto out;
5105 
5106 				case SCF_ERROR_DELETED:
5107 					warn(emsg_pg_deleted, ient->sc_fmri,
5108 					    "dependents");
5109 					r = EBUSY;
5110 					goto out;
5111 
5112 				case SCF_ERROR_EXISTS:
5113 					warn(emsg_pg_changed, ient->sc_fmri,
5114 					    "dependents");
5115 					r = EBUSY;
5116 					goto out;
5117 
5118 				case SCF_ERROR_INVALID_ARGUMENT:
5119 				case SCF_ERROR_HANDLE_MISMATCH:
5120 				case SCF_ERROR_NOT_BOUND:
5121 				case SCF_ERROR_NOT_SET:
5122 				default:
5123 					bad_error("scf_transaction_property_"
5124 					    "new", scf_error());
5125 				}
5126 			}
5127 		}
5128 
5129 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5130 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5131 			/* invalid sc_pgroup_fmri caught above */
5132 			bad_error("scf_value_set_from_string",
5133 			    scf_error());
5134 
5135 		if (scf_entry_add_value(ent, val) != 0)
5136 			bad_error("scf_entry_add_value", scf_error());
5137 		break;
5138 	}
5139 
5140 	case -2:
5141 		warn(li_corrupt, ient->sc_fmri);
5142 		internal_pgroup_free(current_pg);
5143 		r = EBADF;
5144 		goto out;
5145 
5146 	case -1:
5147 	default:
5148 		/* invalid sc_pgroup_fmri caught above */
5149 		bad_error("fmri_equal", r);
5150 	}
5151 
5152 	r = 0;
5153 
5154 out:
5155 	if (old_dpt_pgroup != NULL)
5156 		internal_pgroup_free(old_dpt_pgroup);
5157 
5158 	return (r);
5159 }
5160 
5161 /*
5162  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5163  * would import it, except it seems to exist in the service anyway.  Compare
5164  * the existent dependent with the one we would import, and report any
5165  * differences (if there are none, be silent).  prop is the property which
5166  * represents the existent dependent (in the dependents property group) in the
5167  * entity corresponding to ient.
5168  *
5169  * Returns
5170  *   0 - success (Sort of.  At least, we can continue importing.)
5171  *   ECONNABORTED - repository connection broken
5172  *   EBUSY - ancestor of prop was deleted (error printed)
5173  *   ENOMEM - out of memory
5174  *   EBADF - corrupt property group (error printed)
5175  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5176  */
5177 static int
5178 handle_dependent_conflict(const entity_t * const ient,
5179     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5180 {
5181 	int r;
5182 	scf_type_t ty;
5183 	scf_error_t scfe;
5184 	void *tptr;
5185 	int tissvc;
5186 	pgroup_t *pgroup;
5187 
5188 	if (scf_property_get_value(prop, ud_val) != 0) {
5189 		switch (scf_error()) {
5190 		case SCF_ERROR_CONNECTION_BROKEN:
5191 			return (scferror2errno(scf_error()));
5192 
5193 		case SCF_ERROR_DELETED:
5194 			warn(emsg_pg_deleted, ient->sc_fmri,
5195 			    new_dpt_pgroup->sc_pgroup_name);
5196 			return (EBUSY);
5197 
5198 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5199 		case SCF_ERROR_NOT_FOUND:
5200 			warn(gettext("Conflict upgrading %s (not importing "
5201 			    "dependent \"%s\" because it already exists.)  "
5202 			    "Warning: The \"%s/%2$s\" property has more or "
5203 			    "fewer than one value)).\n"), ient->sc_fmri,
5204 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5205 			return (0);
5206 
5207 		case SCF_ERROR_HANDLE_MISMATCH:
5208 		case SCF_ERROR_NOT_BOUND:
5209 		case SCF_ERROR_NOT_SET:
5210 		case SCF_ERROR_PERMISSION_DENIED:
5211 		default:
5212 			bad_error("scf_property_get_value",
5213 			    scf_error());
5214 		}
5215 	}
5216 
5217 	ty = scf_value_type(ud_val);
5218 	assert(ty != SCF_TYPE_INVALID);
5219 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5220 		warn(gettext("Conflict upgrading %s (not importing dependent "
5221 		    "\"%s\" because it already exists).  Warning: The "
5222 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5223 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5224 		    scf_type_to_string(ty), "dependents");
5225 		return (0);
5226 	}
5227 
5228 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5229 	    0)
5230 		bad_error("scf_value_get_as_string", scf_error());
5231 
5232 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5233 	switch (r) {
5234 	case 0:
5235 		warn(gettext("Conflict upgrading %s (not importing dependent "
5236 		    "\"%s\" (target \"%s\") because it already exists with "
5237 		    "target \"%s\").\n"), ient->sc_fmri,
5238 		    new_dpt_pgroup->sc_pgroup_name,
5239 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5240 		return (0);
5241 
5242 	case 1:
5243 		break;
5244 
5245 	case -1:
5246 		warn(gettext("Conflict upgrading %s (not importing dependent "
5247 		    "\"%s\" because it already exists).  Warning: The current "
5248 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5249 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5250 		return (0);
5251 
5252 	case -2:
5253 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5254 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5255 		    new_dpt_pgroup->sc_pgroup_fmri);
5256 		return (EINVAL);
5257 
5258 	default:
5259 		bad_error("fmri_equal", r);
5260 	}
5261 
5262 	/* compare dependency pgs in target */
5263 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5264 	switch (scfe) {
5265 	case SCF_ERROR_NONE:
5266 		break;
5267 
5268 	case SCF_ERROR_NO_MEMORY:
5269 		return (ENOMEM);
5270 
5271 	case SCF_ERROR_NOT_FOUND:
5272 		warn(emsg_dpt_dangling, ient->sc_fmri,
5273 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5274 		return (0);
5275 
5276 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5277 	case SCF_ERROR_INVALID_ARGUMENT:
5278 	default:
5279 		bad_error("fmri_to_entity", scfe);
5280 	}
5281 
5282 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5283 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5284 	switch (r) {
5285 	case 0:
5286 		break;
5287 
5288 	case ECONNABORTED:
5289 		return (r);
5290 
5291 	case ECANCELED:
5292 		warn(emsg_dpt_dangling, ient->sc_fmri,
5293 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5294 		return (0);
5295 
5296 	case EBADF:
5297 		if (tissvc)
5298 			warn(gettext("%s has an instance with a \"%s\" "
5299 			    "snapshot which is missing a snaplevel.\n"),
5300 			    ud_ctarg, "running");
5301 		else
5302 			warn(gettext("%s has a \"%s\" snapshot which is "
5303 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5304 		/* FALLTHROUGH */
5305 
5306 	case ENOENT:
5307 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5308 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5309 		    new_dpt_pgroup->sc_pgroup_name);
5310 		return (0);
5311 
5312 	case EINVAL:
5313 	default:
5314 		bad_error("entity_get_running_pg", r);
5315 	}
5316 
5317 	pgroup = internal_pgroup_new();
5318 	if (pgroup == NULL)
5319 		return (ENOMEM);
5320 
5321 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5322 	switch (r) {
5323 	case 0:
5324 		break;
5325 
5326 	case ECONNABORTED:
5327 	case EBADF:
5328 	case ENOMEM:
5329 		internal_pgroup_free(pgroup);
5330 		return (r);
5331 
5332 	case ECANCELED:
5333 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5334 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5335 		    new_dpt_pgroup->sc_pgroup_name);
5336 		internal_pgroup_free(pgroup);
5337 		return (0);
5338 
5339 	case EACCES:
5340 	default:
5341 		bad_error("load_pg", r);
5342 	}
5343 
5344 	/* report differences */
5345 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5346 	internal_pgroup_free(pgroup);
5347 	return (0);
5348 }
5349 
5350 /*
5351  * lipg is a property group in the last-import snapshot of ent, which is an
5352  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5353  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5354  * in ents's property groups, compare and upgrade ent appropriately.
5355  *
5356  * Returns
5357  *   0 - success
5358  *   ECONNABORTED - repository connection broken
5359  *   ENOMEM - out of memory
5360  *   ENOSPC - configd is out of resources
5361  *   EINVAL - ient has invalid dependent (error printed)
5362  *	    - ient has invalid pgroup_t (error printed)
5363  *   ECANCELED - ent has been deleted
5364  *   ENODEV - entity containing lipg has been deleted
5365  *	    - entity containing running has been deleted
5366  *   EPERM - could not delete pg (permission denied) (error printed)
5367  *	   - couldn't upgrade dependents (permission denied) (error printed)
5368  *	   - couldn't import pg (permission denied) (error printed)
5369  *	   - couldn't upgrade pg (permission denied) (error printed)
5370  *   EROFS - could not delete pg (repository read-only)
5371  *	   - couldn't upgrade dependents (repository read-only)
5372  *	   - couldn't import pg (repository read-only)
5373  *	   - couldn't upgrade pg (repository read-only)
5374  *   EACCES - could not delete pg (backend access denied)
5375  *	    - couldn't upgrade dependents (backend access denied)
5376  *	    - couldn't import pg (backend access denied)
5377  *	    - couldn't upgrade pg (backend access denied)
5378  *	    - couldn't read property (backend access denied)
5379  *   EBUSY - property group was added (error printed)
5380  *	   - property group was deleted (error printed)
5381  *	   - property group changed (error printed)
5382  *	   - "dependents" pg was added, changed, or deleted (error printed)
5383  *	   - dependent target deleted (error printed)
5384  *	   - dependent pg changed (error printed)
5385  *   EBADF - imp_snpl is corrupt (error printed)
5386  *	   - ent has bad pg (error printed)
5387  *   EEXIST - dependent collision in target service (error printed)
5388  */
5389 static int
5390 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5391     const scf_snaplevel_t *running)
5392 {
5393 	int r;
5394 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5395 	scf_callback_t cbdata;
5396 
5397 	const char * const cf_pg_missing =
5398 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5399 	const char * const deleting =
5400 	    gettext("%s: Deleting property group \"%s\".\n");
5401 
5402 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5403 
5404 	/* Skip dependent property groups. */
5405 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5406 		switch (scf_error()) {
5407 		case SCF_ERROR_DELETED:
5408 			return (ENODEV);
5409 
5410 		case SCF_ERROR_CONNECTION_BROKEN:
5411 			return (ECONNABORTED);
5412 
5413 		case SCF_ERROR_NOT_SET:
5414 		case SCF_ERROR_NOT_BOUND:
5415 		default:
5416 			bad_error("scf_pg_get_type", scf_error());
5417 		}
5418 	}
5419 
5420 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5421 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5422 			return (0);
5423 
5424 		switch (scf_error()) {
5425 		case SCF_ERROR_NOT_FOUND:
5426 			break;
5427 
5428 		case SCF_ERROR_CONNECTION_BROKEN:
5429 			return (ECONNABORTED);
5430 
5431 		case SCF_ERROR_DELETED:
5432 			return (ENODEV);
5433 
5434 		case SCF_ERROR_INVALID_ARGUMENT:
5435 		case SCF_ERROR_NOT_BOUND:
5436 		case SCF_ERROR_HANDLE_MISMATCH:
5437 		case SCF_ERROR_NOT_SET:
5438 		default:
5439 			bad_error("scf_pg_get_property", scf_error());
5440 		}
5441 	}
5442 
5443 	/* lookup pg in new properties */
5444 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5445 		switch (scf_error()) {
5446 		case SCF_ERROR_DELETED:
5447 			return (ENODEV);
5448 
5449 		case SCF_ERROR_CONNECTION_BROKEN:
5450 			return (ECONNABORTED);
5451 
5452 		case SCF_ERROR_NOT_SET:
5453 		case SCF_ERROR_NOT_BOUND:
5454 		default:
5455 			bad_error("scf_pg_get_name", scf_error());
5456 		}
5457 	}
5458 
5459 	pgrp.sc_pgroup_name = imp_str;
5460 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5461 
5462 	if (mpg != NULL)
5463 		mpg->sc_pgroup_seen = 1;
5464 
5465 	/* Special handling for dependents */
5466 	if (strcmp(imp_str, "dependents") == 0)
5467 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5468 
5469 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5470 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5471 
5472 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5473 		/* property group was deleted from manifest */
5474 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5475 			switch (scf_error()) {
5476 			case SCF_ERROR_NOT_FOUND:
5477 				return (0);
5478 
5479 			case SCF_ERROR_DELETED:
5480 			case SCF_ERROR_CONNECTION_BROKEN:
5481 				return (scferror2errno(scf_error()));
5482 
5483 			case SCF_ERROR_INVALID_ARGUMENT:
5484 			case SCF_ERROR_HANDLE_MISMATCH:
5485 			case SCF_ERROR_NOT_BOUND:
5486 			case SCF_ERROR_NOT_SET:
5487 			default:
5488 				bad_error("entity_get_pg", scf_error());
5489 			}
5490 		}
5491 
5492 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5493 			if (g_verbose)
5494 				warn(deleting, ient->sc_fmri, imp_str);
5495 			if (scf_pg_delete(imp_pg2) == 0)
5496 				return (0);
5497 
5498 			switch (scf_error()) {
5499 			case SCF_ERROR_DELETED:
5500 				return (0);
5501 
5502 			case SCF_ERROR_CONNECTION_BROKEN:
5503 			case SCF_ERROR_BACKEND_READONLY:
5504 			case SCF_ERROR_BACKEND_ACCESS:
5505 				return (scferror2errno(scf_error()));
5506 
5507 			case SCF_ERROR_PERMISSION_DENIED:
5508 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5509 				return (scferror2errno(scf_error()));
5510 
5511 			case SCF_ERROR_NOT_SET:
5512 			default:
5513 				bad_error("scf_pg_delete", scf_error());
5514 			}
5515 		}
5516 
5517 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5518 		switch (r) {
5519 		case 0:
5520 			break;
5521 
5522 		case ECANCELED:
5523 			return (ENODEV);
5524 
5525 		case ECONNABORTED:
5526 		case ENOMEM:
5527 		case EBADF:
5528 		case EACCES:
5529 			return (r);
5530 
5531 		default:
5532 			bad_error("load_pg", r);
5533 		}
5534 
5535 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5536 		switch (r) {
5537 		case 0:
5538 			break;
5539 
5540 		case ECANCELED:
5541 		case ECONNABORTED:
5542 		case ENOMEM:
5543 		case EBADF:
5544 		case EACCES:
5545 			internal_pgroup_free(lipg_i);
5546 			return (r);
5547 
5548 		default:
5549 			bad_error("load_pg", r);
5550 		}
5551 
5552 		if (pg_equal(lipg_i, curpg_i)) {
5553 			if (g_verbose)
5554 				warn(deleting, ient->sc_fmri, imp_str);
5555 			if (scf_pg_delete(imp_pg2) != 0) {
5556 				switch (scf_error()) {
5557 				case SCF_ERROR_DELETED:
5558 					break;
5559 
5560 				case SCF_ERROR_CONNECTION_BROKEN:
5561 					internal_pgroup_free(lipg_i);
5562 					internal_pgroup_free(curpg_i);
5563 					return (ECONNABORTED);
5564 
5565 				case SCF_ERROR_NOT_SET:
5566 				case SCF_ERROR_NOT_BOUND:
5567 				default:
5568 					bad_error("scf_pg_delete", scf_error());
5569 				}
5570 			}
5571 		} else {
5572 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5573 		}
5574 
5575 		internal_pgroup_free(lipg_i);
5576 		internal_pgroup_free(curpg_i);
5577 
5578 		return (0);
5579 	}
5580 
5581 	/*
5582 	 * Only dependent pgs can have override set, and we skipped those
5583 	 * above.
5584 	 */
5585 	assert(!mpg->sc_pgroup_override);
5586 
5587 	/* compare */
5588 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5589 	switch (r) {
5590 	case 0:
5591 		break;
5592 
5593 	case ECANCELED:
5594 		return (ENODEV);
5595 
5596 	case ECONNABORTED:
5597 	case EBADF:
5598 	case ENOMEM:
5599 	case EACCES:
5600 		return (r);
5601 
5602 	default:
5603 		bad_error("load_pg", r);
5604 	}
5605 
5606 	if (pg_equal(mpg, lipg_i)) {
5607 		/* The manifest pg has not changed.  Move on. */
5608 		r = 0;
5609 		goto out;
5610 	}
5611 
5612 	/* upgrade current properties according to lipg & mpg */
5613 	if (running != NULL)
5614 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5615 	else
5616 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5617 	if (r != 0) {
5618 		switch (scf_error()) {
5619 		case SCF_ERROR_CONNECTION_BROKEN:
5620 			r = scferror2errno(scf_error());
5621 			goto out;
5622 
5623 		case SCF_ERROR_DELETED:
5624 			if (running != NULL)
5625 				r = ENODEV;
5626 			else
5627 				r = ECANCELED;
5628 			goto out;
5629 
5630 		case SCF_ERROR_NOT_FOUND:
5631 			break;
5632 
5633 		case SCF_ERROR_INVALID_ARGUMENT:
5634 		case SCF_ERROR_HANDLE_MISMATCH:
5635 		case SCF_ERROR_NOT_BOUND:
5636 		case SCF_ERROR_NOT_SET:
5637 		default:
5638 			bad_error("entity_get_pg", scf_error());
5639 		}
5640 
5641 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5642 
5643 		r = 0;
5644 		goto out;
5645 	}
5646 
5647 	r = load_pg_attrs(imp_pg2, &curpg_i);
5648 	switch (r) {
5649 	case 0:
5650 		break;
5651 
5652 	case ECANCELED:
5653 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5654 		r = 0;
5655 		goto out;
5656 
5657 	case ECONNABORTED:
5658 	case ENOMEM:
5659 		goto out;
5660 
5661 	default:
5662 		bad_error("load_pg_attrs", r);
5663 	}
5664 
5665 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5666 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5667 		internal_pgroup_free(curpg_i);
5668 		r = 0;
5669 		goto out;
5670 	}
5671 
5672 	internal_pgroup_free(curpg_i);
5673 
5674 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5675 	switch (r) {
5676 	case 0:
5677 		break;
5678 
5679 	case ECANCELED:
5680 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5681 		r = 0;
5682 		goto out;
5683 
5684 	case ECONNABORTED:
5685 	case EBADF:
5686 	case ENOMEM:
5687 	case EACCES:
5688 		goto out;
5689 
5690 	default:
5691 		bad_error("load_pg", r);
5692 	}
5693 
5694 	if (pg_equal(lipg_i, curpg_i) &&
5695 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5696 		int do_delete = 1;
5697 
5698 		if (g_verbose)
5699 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5700 			    ient->sc_fmri, mpg->sc_pgroup_name);
5701 
5702 		internal_pgroup_free(curpg_i);
5703 
5704 		if (running != NULL &&
5705 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5706 			switch (scf_error()) {
5707 			case SCF_ERROR_DELETED:
5708 				r = ECANCELED;
5709 				goto out;
5710 
5711 			case SCF_ERROR_NOT_FOUND:
5712 				do_delete = 0;
5713 				break;
5714 
5715 			case SCF_ERROR_CONNECTION_BROKEN:
5716 				r = scferror2errno(scf_error());
5717 				goto out;
5718 
5719 			case SCF_ERROR_HANDLE_MISMATCH:
5720 			case SCF_ERROR_INVALID_ARGUMENT:
5721 			case SCF_ERROR_NOT_SET:
5722 			case SCF_ERROR_NOT_BOUND:
5723 			default:
5724 				bad_error("entity_get_pg", scf_error());
5725 			}
5726 		}
5727 
5728 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5729 			switch (scf_error()) {
5730 			case SCF_ERROR_DELETED:
5731 				break;
5732 
5733 			case SCF_ERROR_CONNECTION_BROKEN:
5734 			case SCF_ERROR_BACKEND_READONLY:
5735 			case SCF_ERROR_BACKEND_ACCESS:
5736 				r = scferror2errno(scf_error());
5737 				goto out;
5738 
5739 			case SCF_ERROR_PERMISSION_DENIED:
5740 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5741 				    ient->sc_fmri);
5742 				r = scferror2errno(scf_error());
5743 				goto out;
5744 
5745 			case SCF_ERROR_NOT_SET:
5746 			case SCF_ERROR_NOT_BOUND:
5747 			default:
5748 				bad_error("scf_pg_delete", scf_error());
5749 			}
5750 		}
5751 
5752 		cbdata.sc_handle = g_hndl;
5753 		cbdata.sc_parent = ent;
5754 		cbdata.sc_service = issvc;
5755 		cbdata.sc_flags = 0;
5756 		cbdata.sc_source_fmri = ient->sc_fmri;
5757 		cbdata.sc_target_fmri = ient->sc_fmri;
5758 
5759 		r = entity_pgroup_import(mpg, &cbdata);
5760 		switch (r) {
5761 		case UU_WALK_NEXT:
5762 			r = 0;
5763 			goto out;
5764 
5765 		case UU_WALK_ERROR:
5766 			if (cbdata.sc_err == EEXIST) {
5767 				warn(emsg_pg_added, ient->sc_fmri,
5768 				    mpg->sc_pgroup_name);
5769 				r = EBUSY;
5770 			} else {
5771 				r = cbdata.sc_err;
5772 			}
5773 			goto out;
5774 
5775 		default:
5776 			bad_error("entity_pgroup_import", r);
5777 		}
5778 	}
5779 
5780 	if (running != NULL &&
5781 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5782 		switch (scf_error()) {
5783 		case SCF_ERROR_CONNECTION_BROKEN:
5784 		case SCF_ERROR_DELETED:
5785 			r = scferror2errno(scf_error());
5786 			goto out;
5787 
5788 		case SCF_ERROR_NOT_FOUND:
5789 			break;
5790 
5791 		case SCF_ERROR_HANDLE_MISMATCH:
5792 		case SCF_ERROR_INVALID_ARGUMENT:
5793 		case SCF_ERROR_NOT_SET:
5794 		case SCF_ERROR_NOT_BOUND:
5795 		default:
5796 			bad_error("entity_get_pg", scf_error());
5797 		}
5798 
5799 		cbdata.sc_handle = g_hndl;
5800 		cbdata.sc_parent = ent;
5801 		cbdata.sc_service = issvc;
5802 		cbdata.sc_flags = SCI_FORCE;
5803 		cbdata.sc_source_fmri = ient->sc_fmri;
5804 		cbdata.sc_target_fmri = ient->sc_fmri;
5805 
5806 		r = entity_pgroup_import(mpg, &cbdata);
5807 		switch (r) {
5808 		case UU_WALK_NEXT:
5809 			r = 0;
5810 			goto out;
5811 
5812 		case UU_WALK_ERROR:
5813 			if (cbdata.sc_err == EEXIST) {
5814 				warn(emsg_pg_added, ient->sc_fmri,
5815 				    mpg->sc_pgroup_name);
5816 				r = EBUSY;
5817 			} else {
5818 				r = cbdata.sc_err;
5819 			}
5820 			goto out;
5821 
5822 		default:
5823 			bad_error("entity_pgroup_import", r);
5824 		}
5825 	}
5826 
5827 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5828 	internal_pgroup_free(curpg_i);
5829 	switch (r) {
5830 	case 0:
5831 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5832 		break;
5833 
5834 	case ECANCELED:
5835 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5836 		r = EBUSY;
5837 		break;
5838 
5839 	case EPERM:
5840 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5841 		break;
5842 
5843 	case EBUSY:
5844 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5845 		break;
5846 
5847 	case ECONNABORTED:
5848 	case ENOMEM:
5849 	case ENOSPC:
5850 	case EROFS:
5851 	case EACCES:
5852 	case EINVAL:
5853 		break;
5854 
5855 	default:
5856 		bad_error("upgrade_pg", r);
5857 	}
5858 
5859 out:
5860 	internal_pgroup_free(lipg_i);
5861 	return (r);
5862 }
5863 
5864 /*
5865  * Upgrade the properties of ent according to snpl & ient.
5866  *
5867  * Returns
5868  *   0 - success
5869  *   ECONNABORTED - repository connection broken
5870  *   ENOMEM - out of memory
5871  *   ENOSPC - configd is out of resources
5872  *   ECANCELED - ent was deleted
5873  *   ENODEV - entity containing snpl was deleted
5874  *	    - entity containing running was deleted
5875  *   EBADF - imp_snpl is corrupt (error printed)
5876  *	   - ent has corrupt pg (error printed)
5877  *	   - dependent has corrupt pg (error printed)
5878  *	   - dependent target has a corrupt snapshot (error printed)
5879  *   EBUSY - pg was added, changed, or deleted (error printed)
5880  *	   - dependent target was deleted (error printed)
5881  *	   - dependent pg changed (error printed)
5882  *   EINVAL - invalid property group name (error printed)
5883  *	    - invalid property name (error printed)
5884  *	    - invalid value (error printed)
5885  *	    - ient has invalid pgroup or dependent (error printed)
5886  *   EPERM - could not create property group (permission denied) (error printed)
5887  *	   - could not modify property group (permission denied) (error printed)
5888  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5889  *   EROFS - could not create property group (repository read-only)
5890  *	   - couldn't delete, upgrade, or import pg or dependent
5891  *   EACCES - could not create property group (backend access denied)
5892  *	    - couldn't delete, upgrade, or import pg or dependent
5893  *   EEXIST - dependent collision in target service (error printed)
5894  */
5895 static int
5896 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5897     entity_t *ient)
5898 {
5899 	pgroup_t *pg, *rpg;
5900 	int r;
5901 	uu_list_t *pgs = ient->sc_pgroups;
5902 
5903 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5904 
5905 	/* clear sc_sceen for pgs */
5906 	if (uu_list_walk(pgs, clear_int,
5907 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5908 		bad_error("uu_list_walk", uu_error());
5909 
5910 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5911 		switch (scf_error()) {
5912 		case SCF_ERROR_DELETED:
5913 			return (ENODEV);
5914 
5915 		case SCF_ERROR_CONNECTION_BROKEN:
5916 			return (ECONNABORTED);
5917 
5918 		case SCF_ERROR_NOT_SET:
5919 		case SCF_ERROR_NOT_BOUND:
5920 		case SCF_ERROR_HANDLE_MISMATCH:
5921 		default:
5922 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5923 		}
5924 	}
5925 
5926 	for (;;) {
5927 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5928 		if (r == 0)
5929 			break;
5930 		if (r == 1) {
5931 			r = process_old_pg(imp_pg, ient, ent, running);
5932 			switch (r) {
5933 			case 0:
5934 				break;
5935 
5936 			case ECONNABORTED:
5937 			case ENOMEM:
5938 			case ENOSPC:
5939 			case ECANCELED:
5940 			case ENODEV:
5941 			case EPERM:
5942 			case EROFS:
5943 			case EACCES:
5944 			case EBADF:
5945 			case EBUSY:
5946 			case EINVAL:
5947 			case EEXIST:
5948 				return (r);
5949 
5950 			default:
5951 				bad_error("process_old_pg", r);
5952 			}
5953 			continue;
5954 		}
5955 		if (r != -1)
5956 			bad_error("scf_iter_next_pg", r);
5957 
5958 		switch (scf_error()) {
5959 		case SCF_ERROR_DELETED:
5960 			return (ENODEV);
5961 
5962 		case SCF_ERROR_CONNECTION_BROKEN:
5963 			return (ECONNABORTED);
5964 
5965 		case SCF_ERROR_HANDLE_MISMATCH:
5966 		case SCF_ERROR_NOT_BOUND:
5967 		case SCF_ERROR_NOT_SET:
5968 		case SCF_ERROR_INVALID_ARGUMENT:
5969 		default:
5970 			bad_error("scf_iter_next_pg", scf_error());
5971 		}
5972 	}
5973 
5974 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5975 		if (pg->sc_pgroup_seen)
5976 			continue;
5977 
5978 		/* pg is new */
5979 
5980 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5981 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5982 			    ent);
5983 			switch (r) {
5984 			case 0:
5985 				break;
5986 
5987 			case ECONNABORTED:
5988 			case ENOMEM:
5989 			case ENOSPC:
5990 			case ECANCELED:
5991 			case ENODEV:
5992 			case EBADF:
5993 			case EBUSY:
5994 			case EINVAL:
5995 			case EPERM:
5996 			case EROFS:
5997 			case EACCES:
5998 			case EEXIST:
5999 				return (r);
6000 
6001 			default:
6002 				bad_error("upgrade_dependents", r);
6003 			}
6004 			continue;
6005 		}
6006 
6007 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6008 			r = upgrade_manifestfiles(pg, ient, running, ent);
6009 			switch (r) {
6010 			case 0:
6011 				break;
6012 
6013 			case ECONNABORTED:
6014 			case ENOMEM:
6015 			case ENOSPC:
6016 			case ECANCELED:
6017 			case ENODEV:
6018 			case EBADF:
6019 			case EBUSY:
6020 			case EINVAL:
6021 			case EPERM:
6022 			case EROFS:
6023 			case EACCES:
6024 			case EEXIST:
6025 				return (r);
6026 
6027 			default:
6028 				bad_error("upgrade_manifestfiles", r);
6029 			}
6030 			continue;
6031 		}
6032 
6033 		if (running != NULL) {
6034 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6035 			    imp_pg);
6036 		} else {
6037 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6038 			    imp_pg);
6039 		}
6040 		if (r != 0) {
6041 			scf_callback_t cbdata;
6042 
6043 			switch (scf_error()) {
6044 			case SCF_ERROR_NOT_FOUND:
6045 				break;
6046 
6047 			case SCF_ERROR_CONNECTION_BROKEN:
6048 				return (scferror2errno(scf_error()));
6049 
6050 			case SCF_ERROR_DELETED:
6051 				if (running != NULL)
6052 					return (ENODEV);
6053 				else
6054 					return (scferror2errno(scf_error()));
6055 
6056 			case SCF_ERROR_INVALID_ARGUMENT:
6057 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6058 				    pg->sc_pgroup_name);
6059 				return (EINVAL);
6060 
6061 			case SCF_ERROR_NOT_SET:
6062 			case SCF_ERROR_HANDLE_MISMATCH:
6063 			case SCF_ERROR_NOT_BOUND:
6064 			default:
6065 				bad_error("entity_get_pg", scf_error());
6066 			}
6067 
6068 			/* User doesn't have pg, so import it. */
6069 
6070 			cbdata.sc_handle = g_hndl;
6071 			cbdata.sc_parent = ent;
6072 			cbdata.sc_service = issvc;
6073 			cbdata.sc_flags = SCI_FORCE;
6074 			cbdata.sc_source_fmri = ient->sc_fmri;
6075 			cbdata.sc_target_fmri = ient->sc_fmri;
6076 
6077 			r = entity_pgroup_import(pg, &cbdata);
6078 			switch (r) {
6079 			case UU_WALK_NEXT:
6080 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6081 				continue;
6082 
6083 			case UU_WALK_ERROR:
6084 				if (cbdata.sc_err == EEXIST) {
6085 					warn(emsg_pg_added, ient->sc_fmri,
6086 					    pg->sc_pgroup_name);
6087 					return (EBUSY);
6088 				}
6089 				return (cbdata.sc_err);
6090 
6091 			default:
6092 				bad_error("entity_pgroup_import", r);
6093 			}
6094 		}
6095 
6096 		/* report differences between pg & current */
6097 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6098 		switch (r) {
6099 		case 0:
6100 			break;
6101 
6102 		case ECANCELED:
6103 			warn(emsg_pg_deleted, ient->sc_fmri,
6104 			    pg->sc_pgroup_name);
6105 			return (EBUSY);
6106 
6107 		case ECONNABORTED:
6108 		case EBADF:
6109 		case ENOMEM:
6110 		case EACCES:
6111 			return (r);
6112 
6113 		default:
6114 			bad_error("load_pg", r);
6115 		}
6116 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6117 		internal_pgroup_free(rpg);
6118 		rpg = NULL;
6119 	}
6120 
6121 	return (0);
6122 }
6123 
6124 /*
6125  * Import an instance.  If it doesn't exist, create it.  If it has
6126  * a last-import snapshot, upgrade its properties.  Finish by updating its
6127  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6128  * could have been created for a dependent tag in another manifest.  Import the
6129  * new properties.  If there's a conflict, don't override, like now?
6130  *
6131  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6132  * lcbdata->sc_err to
6133  *   ECONNABORTED - repository connection broken
6134  *   ENOMEM - out of memory
6135  *   ENOSPC - svc.configd is out of resources
6136  *   EEXIST - dependency collision in dependent service (error printed)
6137  *   EPERM - couldn't create temporary instance (permission denied)
6138  *	   - couldn't import into temporary instance (permission denied)
6139  *	   - couldn't take snapshot (permission denied)
6140  *	   - couldn't upgrade properties (permission denied)
6141  *	   - couldn't import properties (permission denied)
6142  *	   - couldn't import dependents (permission denied)
6143  *   EROFS - couldn't create temporary instance (repository read-only)
6144  *	   - couldn't import into temporary instance (repository read-only)
6145  *	   - couldn't upgrade properties (repository read-only)
6146  *	   - couldn't import properties (repository read-only)
6147  *	   - couldn't import dependents (repository read-only)
6148  *   EACCES - couldn't create temporary instance (backend access denied)
6149  *	    - couldn't import into temporary instance (backend access denied)
6150  *	    - couldn't upgrade properties (backend access denied)
6151  *	    - couldn't import properties (backend access denied)
6152  *	    - couldn't import dependents (backend access denied)
6153  *   EINVAL - invalid instance name (error printed)
6154  *	    - invalid pgroup_t's (error printed)
6155  *	    - invalid dependents (error printed)
6156  *   EBUSY - temporary service deleted (error printed)
6157  *	   - temporary instance deleted (error printed)
6158  *	   - temporary instance changed (error printed)
6159  *	   - temporary instance already exists (error printed)
6160  *	   - instance deleted (error printed)
6161  *   EBADF - instance has corrupt last-import snapshot (error printed)
6162  *	   - instance is corrupt (error printed)
6163  *	   - dependent has corrupt pg (error printed)
6164  *	   - dependent target has a corrupt snapshot (error printed)
6165  *   -1 - unknown libscf error (error printed)
6166  */
6167 static int
6168 lscf_instance_import(void *v, void *pvt)
6169 {
6170 	entity_t *inst = v;
6171 	scf_callback_t ctx;
6172 	scf_callback_t *lcbdata = pvt;
6173 	scf_service_t *rsvc = lcbdata->sc_parent;
6174 	int r;
6175 	scf_snaplevel_t *running;
6176 	int flags = lcbdata->sc_flags;
6177 
6178 	const char * const emsg_tdel =
6179 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6180 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6181 	    "changed unexpectedly.\n");
6182 	const char * const emsg_del = gettext("%s changed unexpectedly "
6183 	    "(instance \"%s\" was deleted.)\n");
6184 	const char * const emsg_badsnap = gettext(
6185 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6186 
6187 	/*
6188 	 * prepare last-import snapshot:
6189 	 * create temporary instance (service was precreated)
6190 	 * populate with properties from bundle
6191 	 * take snapshot
6192 	 */
6193 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6194 		switch (scf_error()) {
6195 		case SCF_ERROR_CONNECTION_BROKEN:
6196 		case SCF_ERROR_NO_RESOURCES:
6197 		case SCF_ERROR_BACKEND_READONLY:
6198 		case SCF_ERROR_BACKEND_ACCESS:
6199 			return (stash_scferror(lcbdata));
6200 
6201 		case SCF_ERROR_EXISTS:
6202 			warn(gettext("Temporary service svc:/%s "
6203 			    "changed unexpectedly (instance \"%s\" added).\n"),
6204 			    imp_tsname, inst->sc_name);
6205 			lcbdata->sc_err = EBUSY;
6206 			return (UU_WALK_ERROR);
6207 
6208 		case SCF_ERROR_DELETED:
6209 			warn(gettext("Temporary service svc:/%s "
6210 			    "was deleted unexpectedly.\n"), imp_tsname);
6211 			lcbdata->sc_err = EBUSY;
6212 			return (UU_WALK_ERROR);
6213 
6214 		case SCF_ERROR_INVALID_ARGUMENT:
6215 			warn(gettext("Invalid instance name \"%s\".\n"),
6216 			    inst->sc_name);
6217 			return (stash_scferror(lcbdata));
6218 
6219 		case SCF_ERROR_PERMISSION_DENIED:
6220 			warn(gettext("Could not create temporary instance "
6221 			    "\"%s\" in svc:/%s (permission denied).\n"),
6222 			    inst->sc_name, imp_tsname);
6223 			return (stash_scferror(lcbdata));
6224 
6225 		case SCF_ERROR_HANDLE_MISMATCH:
6226 		case SCF_ERROR_NOT_BOUND:
6227 		case SCF_ERROR_NOT_SET:
6228 		default:
6229 			bad_error("scf_service_add_instance", scf_error());
6230 		}
6231 	}
6232 
6233 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6234 	    inst->sc_name);
6235 	if (r < 0)
6236 		bad_error("snprintf", errno);
6237 
6238 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6239 	    lcbdata->sc_flags | SCI_NOENABLED);
6240 	switch (r) {
6241 	case 0:
6242 		break;
6243 
6244 	case ECANCELED:
6245 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6246 		lcbdata->sc_err = EBUSY;
6247 		r = UU_WALK_ERROR;
6248 		goto deltemp;
6249 
6250 	case EEXIST:
6251 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6252 		lcbdata->sc_err = EBUSY;
6253 		r = UU_WALK_ERROR;
6254 		goto deltemp;
6255 
6256 	case ECONNABORTED:
6257 		goto connaborted;
6258 
6259 	case ENOMEM:
6260 	case ENOSPC:
6261 	case EPERM:
6262 	case EROFS:
6263 	case EACCES:
6264 	case EINVAL:
6265 	case EBUSY:
6266 		lcbdata->sc_err = r;
6267 		r = UU_WALK_ERROR;
6268 		goto deltemp;
6269 
6270 	default:
6271 		bad_error("lscf_import_instance_pgs", r);
6272 	}
6273 
6274 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6275 	    inst->sc_name);
6276 	if (r < 0)
6277 		bad_error("snprintf", errno);
6278 
6279 	ctx.sc_handle = lcbdata->sc_handle;
6280 	ctx.sc_parent = imp_tinst;
6281 	ctx.sc_service = 0;
6282 	ctx.sc_source_fmri = inst->sc_fmri;
6283 	ctx.sc_target_fmri = imp_str;
6284 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6285 	    UU_DEFAULT) != 0) {
6286 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6287 			bad_error("uu_list_walk", uu_error());
6288 
6289 		switch (ctx.sc_err) {
6290 		case ECONNABORTED:
6291 			goto connaborted;
6292 
6293 		case ECANCELED:
6294 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6295 			lcbdata->sc_err = EBUSY;
6296 			break;
6297 
6298 		case EEXIST:
6299 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6300 			lcbdata->sc_err = EBUSY;
6301 			break;
6302 
6303 		default:
6304 			lcbdata->sc_err = ctx.sc_err;
6305 		}
6306 		r = UU_WALK_ERROR;
6307 		goto deltemp;
6308 	}
6309 
6310 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6311 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6312 		switch (scf_error()) {
6313 		case SCF_ERROR_CONNECTION_BROKEN:
6314 			goto connaborted;
6315 
6316 		case SCF_ERROR_NO_RESOURCES:
6317 			r = stash_scferror(lcbdata);
6318 			goto deltemp;
6319 
6320 		case SCF_ERROR_EXISTS:
6321 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6322 			lcbdata->sc_err = EBUSY;
6323 			r = UU_WALK_ERROR;
6324 			goto deltemp;
6325 
6326 		case SCF_ERROR_PERMISSION_DENIED:
6327 			warn(gettext("Could not take \"%s\" snapshot of %s "
6328 			    "(permission denied).\n"), snap_lastimport,
6329 			    imp_str);
6330 			r = stash_scferror(lcbdata);
6331 			goto deltemp;
6332 
6333 		default:
6334 			scfwarn();
6335 			lcbdata->sc_err = -1;
6336 			r = UU_WALK_ERROR;
6337 			goto deltemp;
6338 
6339 		case SCF_ERROR_HANDLE_MISMATCH:
6340 		case SCF_ERROR_INVALID_ARGUMENT:
6341 		case SCF_ERROR_NOT_SET:
6342 			bad_error("_scf_snapshot_take_new_named", scf_error());
6343 		}
6344 	}
6345 
6346 	if (lcbdata->sc_flags & SCI_FRESH)
6347 		goto fresh;
6348 
6349 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6350 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6351 		    imp_lisnap) != 0) {
6352 			switch (scf_error()) {
6353 			case SCF_ERROR_DELETED:
6354 				warn(emsg_del, inst->sc_parent->sc_fmri,
6355 				    inst->sc_name);
6356 				lcbdata->sc_err = EBUSY;
6357 				r = UU_WALK_ERROR;
6358 				goto deltemp;
6359 
6360 			case SCF_ERROR_NOT_FOUND:
6361 				flags |= SCI_FORCE;
6362 				goto nosnap;
6363 
6364 			case SCF_ERROR_CONNECTION_BROKEN:
6365 				goto connaborted;
6366 
6367 			case SCF_ERROR_INVALID_ARGUMENT:
6368 			case SCF_ERROR_HANDLE_MISMATCH:
6369 			case SCF_ERROR_NOT_BOUND:
6370 			case SCF_ERROR_NOT_SET:
6371 			default:
6372 				bad_error("scf_instance_get_snapshot",
6373 				    scf_error());
6374 			}
6375 		}
6376 
6377 		/* upgrade */
6378 
6379 		/*
6380 		 * compare new properties with last-import properties
6381 		 * upgrade current properties
6382 		 */
6383 		/* clear sc_sceen for pgs */
6384 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6385 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6386 		    0)
6387 			bad_error("uu_list_walk", uu_error());
6388 
6389 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6390 		switch (r) {
6391 		case 0:
6392 			break;
6393 
6394 		case ECONNABORTED:
6395 			goto connaborted;
6396 
6397 		case ECANCELED:
6398 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6399 			lcbdata->sc_err = EBUSY;
6400 			r = UU_WALK_ERROR;
6401 			goto deltemp;
6402 
6403 		case ENOENT:
6404 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6405 			lcbdata->sc_err = EBADF;
6406 			r = UU_WALK_ERROR;
6407 			goto deltemp;
6408 
6409 		default:
6410 			bad_error("get_snaplevel", r);
6411 		}
6412 
6413 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6414 		    imp_rsnap) != 0) {
6415 			switch (scf_error()) {
6416 			case SCF_ERROR_DELETED:
6417 				warn(emsg_del, inst->sc_parent->sc_fmri,
6418 				    inst->sc_name);
6419 				lcbdata->sc_err = EBUSY;
6420 				r = UU_WALK_ERROR;
6421 				goto deltemp;
6422 
6423 			case SCF_ERROR_NOT_FOUND:
6424 				break;
6425 
6426 			case SCF_ERROR_CONNECTION_BROKEN:
6427 				goto connaborted;
6428 
6429 			case SCF_ERROR_INVALID_ARGUMENT:
6430 			case SCF_ERROR_HANDLE_MISMATCH:
6431 			case SCF_ERROR_NOT_BOUND:
6432 			case SCF_ERROR_NOT_SET:
6433 			default:
6434 				bad_error("scf_instance_get_snapshot",
6435 				    scf_error());
6436 			}
6437 
6438 			running = NULL;
6439 		} else {
6440 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6441 			switch (r) {
6442 			case 0:
6443 				running = imp_rsnpl;
6444 				break;
6445 
6446 			case ECONNABORTED:
6447 				goto connaborted;
6448 
6449 			case ECANCELED:
6450 				warn(emsg_del, inst->sc_parent->sc_fmri,
6451 				    inst->sc_name);
6452 				lcbdata->sc_err = EBUSY;
6453 				r = UU_WALK_ERROR;
6454 				goto deltemp;
6455 
6456 			case ENOENT:
6457 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6458 				lcbdata->sc_err = EBADF;
6459 				r = UU_WALK_ERROR;
6460 				goto deltemp;
6461 
6462 			default:
6463 				bad_error("get_snaplevel", r);
6464 			}
6465 		}
6466 
6467 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6468 		switch (r) {
6469 		case 0:
6470 			break;
6471 
6472 		case ECANCELED:
6473 		case ENODEV:
6474 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6475 			lcbdata->sc_err = EBUSY;
6476 			r = UU_WALK_ERROR;
6477 			goto deltemp;
6478 
6479 		case ECONNABORTED:
6480 			goto connaborted;
6481 
6482 		case ENOMEM:
6483 		case ENOSPC:
6484 		case EBADF:
6485 		case EBUSY:
6486 		case EINVAL:
6487 		case EPERM:
6488 		case EROFS:
6489 		case EACCES:
6490 		case EEXIST:
6491 			lcbdata->sc_err = r;
6492 			r = UU_WALK_ERROR;
6493 			goto deltemp;
6494 
6495 		default:
6496 			bad_error("upgrade_props", r);
6497 		}
6498 
6499 		inst->sc_import_state = IMPORT_PROP_DONE;
6500 	} else {
6501 		switch (scf_error()) {
6502 		case SCF_ERROR_CONNECTION_BROKEN:
6503 			goto connaborted;
6504 
6505 		case SCF_ERROR_NOT_FOUND:
6506 			break;
6507 
6508 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6509 		case SCF_ERROR_HANDLE_MISMATCH:
6510 		case SCF_ERROR_NOT_BOUND:
6511 		case SCF_ERROR_NOT_SET:
6512 		default:
6513 			bad_error("scf_service_get_instance", scf_error());
6514 		}
6515 
6516 fresh:
6517 		/* create instance */
6518 		if (scf_service_add_instance(rsvc, inst->sc_name,
6519 		    imp_inst) != 0) {
6520 			switch (scf_error()) {
6521 			case SCF_ERROR_CONNECTION_BROKEN:
6522 				goto connaborted;
6523 
6524 			case SCF_ERROR_NO_RESOURCES:
6525 			case SCF_ERROR_BACKEND_READONLY:
6526 			case SCF_ERROR_BACKEND_ACCESS:
6527 				r = stash_scferror(lcbdata);
6528 				goto deltemp;
6529 
6530 			case SCF_ERROR_EXISTS:
6531 				warn(gettext("%s changed unexpectedly "
6532 				    "(instance \"%s\" added).\n"),
6533 				    inst->sc_parent->sc_fmri, inst->sc_name);
6534 				lcbdata->sc_err = EBUSY;
6535 				r = UU_WALK_ERROR;
6536 				goto deltemp;
6537 
6538 			case SCF_ERROR_PERMISSION_DENIED:
6539 				warn(gettext("Could not create \"%s\" instance "
6540 				    "in %s (permission denied).\n"),
6541 				    inst->sc_name, inst->sc_parent->sc_fmri);
6542 				r = stash_scferror(lcbdata);
6543 				goto deltemp;
6544 
6545 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6546 			case SCF_ERROR_HANDLE_MISMATCH:
6547 			case SCF_ERROR_NOT_BOUND:
6548 			case SCF_ERROR_NOT_SET:
6549 			default:
6550 				bad_error("scf_service_add_instance",
6551 				    scf_error());
6552 			}
6553 		}
6554 
6555 nosnap:
6556 		/*
6557 		 * Create a last-import snapshot to serve as an attachment
6558 		 * point for the real one from the temporary instance.  Since
6559 		 * the contents is irrelevant, take it now, while the instance
6560 		 * is empty, to minimize svc.configd's work.
6561 		 */
6562 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6563 		    imp_lisnap) != 0) {
6564 			switch (scf_error()) {
6565 			case SCF_ERROR_CONNECTION_BROKEN:
6566 				goto connaborted;
6567 
6568 			case SCF_ERROR_NO_RESOURCES:
6569 				r = stash_scferror(lcbdata);
6570 				goto deltemp;
6571 
6572 			case SCF_ERROR_EXISTS:
6573 				warn(gettext("%s changed unexpectedly "
6574 				    "(snapshot \"%s\" added).\n"),
6575 				    inst->sc_fmri, snap_lastimport);
6576 				lcbdata->sc_err = EBUSY;
6577 				r = UU_WALK_ERROR;
6578 				goto deltemp;
6579 
6580 			case SCF_ERROR_PERMISSION_DENIED:
6581 				warn(gettext("Could not take \"%s\" snapshot "
6582 				    "of %s (permission denied).\n"),
6583 				    snap_lastimport, inst->sc_fmri);
6584 				r = stash_scferror(lcbdata);
6585 				goto deltemp;
6586 
6587 			default:
6588 				scfwarn();
6589 				lcbdata->sc_err = -1;
6590 				r = UU_WALK_ERROR;
6591 				goto deltemp;
6592 
6593 			case SCF_ERROR_NOT_SET:
6594 			case SCF_ERROR_INTERNAL:
6595 			case SCF_ERROR_INVALID_ARGUMENT:
6596 			case SCF_ERROR_HANDLE_MISMATCH:
6597 				bad_error("_scf_snapshot_take_new",
6598 				    scf_error());
6599 			}
6600 		}
6601 
6602 		if (li_only)
6603 			goto lionly;
6604 
6605 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6606 
6607 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6608 		    flags);
6609 		switch (r) {
6610 		case 0:
6611 			break;
6612 
6613 		case ECONNABORTED:
6614 			goto connaborted;
6615 
6616 		case ECANCELED:
6617 			warn(gettext("%s changed unexpectedly "
6618 			    "(instance \"%s\" deleted).\n"),
6619 			    inst->sc_parent->sc_fmri, inst->sc_name);
6620 			lcbdata->sc_err = EBUSY;
6621 			r = UU_WALK_ERROR;
6622 			goto deltemp;
6623 
6624 		case EEXIST:
6625 			warn(gettext("%s changed unexpectedly "
6626 			    "(property group added).\n"), inst->sc_fmri);
6627 			lcbdata->sc_err = EBUSY;
6628 			r = UU_WALK_ERROR;
6629 			goto deltemp;
6630 
6631 		default:
6632 			lcbdata->sc_err = r;
6633 			r = UU_WALK_ERROR;
6634 			goto deltemp;
6635 
6636 		case EINVAL:	/* caught above */
6637 			bad_error("lscf_import_instance_pgs", r);
6638 		}
6639 
6640 		ctx.sc_parent = imp_inst;
6641 		ctx.sc_service = 0;
6642 		ctx.sc_trans = NULL;
6643 		ctx.sc_flags = 0;
6644 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6645 		    &ctx, UU_DEFAULT) != 0) {
6646 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6647 				bad_error("uu_list_walk", uu_error());
6648 
6649 			if (ctx.sc_err == ECONNABORTED)
6650 				goto connaborted;
6651 			lcbdata->sc_err = ctx.sc_err;
6652 			r = UU_WALK_ERROR;
6653 			goto deltemp;
6654 		}
6655 
6656 		inst->sc_import_state = IMPORT_PROP_DONE;
6657 
6658 		if (g_verbose)
6659 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6660 			    snap_initial, inst->sc_fmri);
6661 		r = take_snap(imp_inst, snap_initial, imp_snap);
6662 		switch (r) {
6663 		case 0:
6664 			break;
6665 
6666 		case ECONNABORTED:
6667 			goto connaborted;
6668 
6669 		case ENOSPC:
6670 		case -1:
6671 			lcbdata->sc_err = r;
6672 			r = UU_WALK_ERROR;
6673 			goto deltemp;
6674 
6675 		case ECANCELED:
6676 			warn(gettext("%s changed unexpectedly "
6677 			    "(instance %s deleted).\n"),
6678 			    inst->sc_parent->sc_fmri, inst->sc_name);
6679 			lcbdata->sc_err = r;
6680 			r = UU_WALK_ERROR;
6681 			goto deltemp;
6682 
6683 		case EPERM:
6684 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6685 			lcbdata->sc_err = r;
6686 			r = UU_WALK_ERROR;
6687 			goto deltemp;
6688 
6689 		default:
6690 			bad_error("take_snap", r);
6691 		}
6692 	}
6693 
6694 lionly:
6695 	if (lcbdata->sc_flags & SCI_NOSNAP)
6696 		goto deltemp;
6697 
6698 	/* transfer snapshot from temporary instance */
6699 	if (g_verbose)
6700 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6701 		    snap_lastimport, inst->sc_fmri);
6702 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6703 		switch (scf_error()) {
6704 		case SCF_ERROR_CONNECTION_BROKEN:
6705 			goto connaborted;
6706 
6707 		case SCF_ERROR_NO_RESOURCES:
6708 			r = stash_scferror(lcbdata);
6709 			goto deltemp;
6710 
6711 		case SCF_ERROR_PERMISSION_DENIED:
6712 			warn(gettext("Could not take \"%s\" snapshot for %s "
6713 			    "(permission denied).\n"), snap_lastimport,
6714 			    inst->sc_fmri);
6715 			r = stash_scferror(lcbdata);
6716 			goto deltemp;
6717 
6718 		case SCF_ERROR_NOT_SET:
6719 		case SCF_ERROR_HANDLE_MISMATCH:
6720 		default:
6721 			bad_error("_scf_snapshot_attach", scf_error());
6722 		}
6723 	}
6724 
6725 	inst->sc_import_state = IMPORT_COMPLETE;
6726 
6727 	r = UU_WALK_NEXT;
6728 
6729 deltemp:
6730 	/* delete temporary instance */
6731 	if (scf_instance_delete(imp_tinst) != 0) {
6732 		switch (scf_error()) {
6733 		case SCF_ERROR_DELETED:
6734 			break;
6735 
6736 		case SCF_ERROR_CONNECTION_BROKEN:
6737 			goto connaborted;
6738 
6739 		case SCF_ERROR_NOT_SET:
6740 		case SCF_ERROR_NOT_BOUND:
6741 		default:
6742 			bad_error("scf_instance_delete", scf_error());
6743 		}
6744 	}
6745 
6746 	return (r);
6747 
6748 connaborted:
6749 	warn(gettext("Could not delete svc:/%s:%s "
6750 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6751 	lcbdata->sc_err = ECONNABORTED;
6752 	return (UU_WALK_ERROR);
6753 }
6754 
6755 /*
6756  * When an instance is imported we end up telling configd about it. Once we tell
6757  * configd about these changes, startd eventually notices. If this is a new
6758  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6759  * property group. However, many of the other tools expect that this property
6760  * group exists and has certain values.
6761  *
6762  * These values are added asynchronously by startd. We should not return from
6763  * this routine until we can verify that the property group we need is there.
6764  *
6765  * Before we go ahead and verify this, we have to ask ourselves an important
6766  * question: Is the early manifest service currently running?  Because if it is
6767  * running and it has invoked us, then the service will never get a restarter
6768  * property because svc.startd is blocked on EMI finishing before it lets itself
6769  * fully connect to svc.configd. Of course, this means that this race condition
6770  * is in fact impossible to 100% eliminate.
6771  *
6772  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6773  * the state of the EMI instance. If it is online it bails out and makes sure
6774  * that it doesn't run again. In this case, we're going to do something similar,
6775  * only if the state is online, then we're going to actually verify. EMI always
6776  * has to be present, but it can be explicitly disabled to reduce the amount of
6777  * damage it can cause. If EMI has been disabled then we no longer have to worry
6778  * about the implicit race condition and can go ahead and check things. If EMI
6779  * is in some state that isn't online or disabled and isn't runinng, then we
6780  * assume that things are rather bad and we're not going to get in your way,
6781  * even if the rest of SMF does.
6782  *
6783  * Returns 0 on success or returns an errno.
6784  */
6785 #ifndef NATIVE_BUILD
6786 static int
6787 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6788 {
6789 	int ret, err;
6790 	struct timespec ts;
6791 	char *emi_state;
6792 
6793 	/*
6794 	 * smf_get_state does not distinguish between its different failure
6795 	 * modes: memory allocation failures, SMF internal failures, and a lack
6796 	 * of EMI entirely because it's been removed. In these cases, we're
6797 	 * going to be conservative and opt to say that if we don't know, better
6798 	 * to not block import or falsely warn to the user.
6799 	 */
6800 	if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6801 		return (0);
6802 	}
6803 
6804 	/*
6805 	 * As per the block comment for this function check the state of EMI
6806 	 */
6807 	if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6808 	    strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6809 		warn(gettext("Not validating instance %s:%s because EMI's "
6810 		    "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6811 		free(emi_state);
6812 		return (0);
6813 	}
6814 
6815 	free(emi_state);
6816 
6817 	/*
6818 	 * First we have to get the property.
6819 	 */
6820 	if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6821 		ret = scf_error();
6822 		warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6823 		return (ret);
6824 	}
6825 
6826 	/*
6827 	 * We should always be able to get the instance. It should already
6828 	 * exist because we just created it or got it. There probably is a
6829 	 * slim chance that someone may have come in and deleted it though from
6830 	 * under us.
6831 	 */
6832 	if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6833 	    != 0) {
6834 		ret = scf_error();
6835 		warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6836 		switch (ret) {
6837 		case SCF_ERROR_DELETED:
6838 			err = ENODEV;
6839 			break;
6840 		case SCF_ERROR_CONNECTION_BROKEN:
6841 			warn(gettext("Lost repository connection\n"));
6842 			err = ECONNABORTED;
6843 			break;
6844 		case SCF_ERROR_NOT_FOUND:
6845 			warn(gettext("Instance \"%s\" disappeared out from "
6846 			    "under us.\n"), inst->sc_name);
6847 			err = ENOENT;
6848 			break;
6849 		default:
6850 			bad_error("scf_service_get_instance", ret);
6851 		}
6852 
6853 		return (err);
6854 	}
6855 
6856 	/*
6857 	 * An astute observer may want to use _scf_wait_pg which would notify us
6858 	 * of a property group change, unfortunately that does not work if the
6859 	 * property group in question does not exist. So instead we have to
6860 	 * manually poll and ask smf the best way to get to it.
6861 	 */
6862 	while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6863 	    != SCF_SUCCESS) {
6864 		ret = scf_error();
6865 		if (ret != SCF_ERROR_NOT_FOUND) {
6866 			warn(gettext("Failed to get restarter property "
6867 			    "group for instance: %s\n"), inst->sc_name);
6868 			switch (ret) {
6869 			case SCF_ERROR_DELETED:
6870 				err = ENODEV;
6871 				break;
6872 			case SCF_ERROR_CONNECTION_BROKEN:
6873 				warn(gettext("Lost repository connection\n"));
6874 				err = ECONNABORTED;
6875 				break;
6876 			default:
6877 				bad_error("scf_service_get_instance", ret);
6878 			}
6879 
6880 			return (err);
6881 		}
6882 
6883 		ts.tv_sec = pg_timeout / NANOSEC;
6884 		ts.tv_nsec = pg_timeout % NANOSEC;
6885 
6886 		(void) nanosleep(&ts, NULL);
6887 	}
6888 
6889 	/*
6890 	 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6891 	 * So in addition to the property group being present, we need to wait
6892 	 * for the property to be there in some form.
6893 	 *
6894 	 * Note that a property group is a frozen snapshot in time. To properly
6895 	 * get beyond this, you have to refresh the property group each time.
6896 	 */
6897 	while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6898 	    imp_prop)) != 0) {
6899 
6900 		ret = scf_error();
6901 		if (ret != SCF_ERROR_NOT_FOUND) {
6902 			warn(gettext("Failed to get property %s from the "
6903 			    "restarter property group of instance %s\n"),
6904 			    SCF_PROPERTY_STATE, inst->sc_name);
6905 			switch (ret) {
6906 			case SCF_ERROR_CONNECTION_BROKEN:
6907 				warn(gettext("Lost repository connection\n"));
6908 				err = ECONNABORTED;
6909 				break;
6910 			case SCF_ERROR_DELETED:
6911 				err = ENODEV;
6912 				break;
6913 			default:
6914 				bad_error("scf_pg_get_property", ret);
6915 			}
6916 
6917 			return (err);
6918 		}
6919 
6920 		ts.tv_sec = pg_timeout / NANOSEC;
6921 		ts.tv_nsec = pg_timeout % NANOSEC;
6922 
6923 		(void) nanosleep(&ts, NULL);
6924 
6925 		ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6926 		if (ret != SCF_SUCCESS) {
6927 			warn(gettext("Failed to get restarter property "
6928 			    "group for instance: %s\n"), inst->sc_name);
6929 			switch (ret) {
6930 			case SCF_ERROR_DELETED:
6931 				err = ENODEV;
6932 				break;
6933 			case SCF_ERROR_CONNECTION_BROKEN:
6934 				warn(gettext("Lost repository connection\n"));
6935 				err = ECONNABORTED;
6936 				break;
6937 			default:
6938 				bad_error("scf_service_get_instance", ret);
6939 			}
6940 
6941 			return (err);
6942 		}
6943 	}
6944 
6945 	/*
6946 	 * We don't have to free the property groups or other values that we got
6947 	 * because we stored them in global variables that are allocated and
6948 	 * freed by the routines that call into these functions. Unless of
6949 	 * course the rest of the code here that we are basing this on is
6950 	 * mistaken.
6951 	 */
6952 	return (0);
6953 }
6954 #endif
6955 
6956 /*
6957  * If the service is missing, create it, import its properties, and import the
6958  * instances.  Since the service is brand new, it should be empty, and if we
6959  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6960  *
6961  * If the service exists, we want to upgrade its properties and import the
6962  * instances.  Upgrade requires a last-import snapshot, though, which are
6963  * children of instances, so first we'll have to go through the instances
6964  * looking for a last-import snapshot.  If we don't find one then we'll just
6965  * override-import the service properties (but don't delete existing
6966  * properties: another service might have declared us as a dependent).  Before
6967  * we change anything, though, we want to take the previous snapshots.  We
6968  * also give lscf_instance_import() a leg up on taking last-import snapshots
6969  * by importing the manifest's service properties into a temporary service.
6970  *
6971  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6972  * sets lcbdata->sc_err to
6973  *   ECONNABORTED - repository connection broken
6974  *   ENOMEM - out of memory
6975  *   ENOSPC - svc.configd is out of resources
6976  *   EPERM - couldn't create temporary service (error printed)
6977  *	   - couldn't import into temp service (error printed)
6978  *	   - couldn't create service (error printed)
6979  *	   - couldn't import dependent (error printed)
6980  *	   - couldn't take snapshot (error printed)
6981  *	   - couldn't create instance (error printed)
6982  *	   - couldn't create, modify, or delete pg (error printed)
6983  *	   - couldn't create, modify, or delete dependent (error printed)
6984  *	   - couldn't import instance (error printed)
6985  *   EROFS - couldn't create temporary service (repository read-only)
6986  *	   - couldn't import into temporary service (repository read-only)
6987  *	   - couldn't create service (repository read-only)
6988  *	   - couldn't import dependent (repository read-only)
6989  *	   - couldn't create instance (repository read-only)
6990  *	   - couldn't create, modify, or delete pg or dependent
6991  *	   - couldn't import instance (repository read-only)
6992  *   EACCES - couldn't create temporary service (backend access denied)
6993  *	    - couldn't import into temporary service (backend access denied)
6994  *	    - couldn't create service (backend access denied)
6995  *	    - couldn't import dependent (backend access denied)
6996  *	    - couldn't create instance (backend access denied)
6997  *	    - couldn't create, modify, or delete pg or dependent
6998  *	    - couldn't import instance (backend access denied)
6999  *   EINVAL - service name is invalid (error printed)
7000  *	    - service name is too long (error printed)
7001  *	    - s has invalid pgroup (error printed)
7002  *	    - s has invalid dependent (error printed)
7003  *	    - instance name is invalid (error printed)
7004  *	    - instance entity_t is invalid (error printed)
7005  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7006  *	    - couldn't import dependent (dependency pg already exists) (printed)
7007  *	    - dependency collision in dependent service (error printed)
7008  *   EBUSY - temporary service deleted (error printed)
7009  *	   - property group added to temporary service (error printed)
7010  *	   - new property group changed or was deleted (error printed)
7011  *	   - service was added unexpectedly (error printed)
7012  *	   - service was deleted unexpectedly (error printed)
7013  *	   - property group added to new service (error printed)
7014  *	   - instance added unexpectedly (error printed)
7015  *	   - instance deleted unexpectedly (error printed)
7016  *	   - dependent service deleted unexpectedly (error printed)
7017  *	   - pg was added, changed, or deleted (error printed)
7018  *	   - dependent pg changed (error printed)
7019  *	   - temporary instance added, changed, or deleted (error printed)
7020  *   EBADF - a last-import snapshot is corrupt (error printed)
7021  *	   - the service is corrupt (error printed)
7022  *	   - a dependent is corrupt (error printed)
7023  *	   - an instance is corrupt (error printed)
7024  *	   - an instance has a corrupt last-import snapshot (error printed)
7025  *	   - dependent target has a corrupt snapshot (error printed)
7026  *   -1 - unknown libscf error (error printed)
7027  */
7028 static int
7029 lscf_service_import(void *v, void *pvt)
7030 {
7031 	entity_t *s = v;
7032 	scf_callback_t cbdata;
7033 	scf_callback_t *lcbdata = pvt;
7034 	scf_scope_t *scope = lcbdata->sc_parent;
7035 	entity_t *inst, linst;
7036 	int r;
7037 	int fresh = 0;
7038 	scf_snaplevel_t *running;
7039 	int have_ge = 0;
7040 	boolean_t retried = B_FALSE;
7041 
7042 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
7043 	    "was deleted unexpectedly.\n");
7044 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7045 	    "changed unexpectedly (property group added).\n");
7046 	const char * const s_deleted =
7047 	    gettext("%s was deleted unexpectedly.\n");
7048 	const char * const i_deleted =
7049 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7050 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7051 	    "is corrupt (missing service snaplevel).\n");
7052 	const char * const s_mfile_upd =
7053 	    gettext("Unable to update the manifest file connection "
7054 	    "for %s\n");
7055 
7056 	li_only = 0;
7057 	/* Validate the service name */
7058 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7059 		switch (scf_error()) {
7060 		case SCF_ERROR_CONNECTION_BROKEN:
7061 			return (stash_scferror(lcbdata));
7062 
7063 		case SCF_ERROR_INVALID_ARGUMENT:
7064 			warn(gettext("\"%s\" is an invalid service name.  "
7065 			    "Cannot import.\n"), s->sc_name);
7066 			return (stash_scferror(lcbdata));
7067 
7068 		case SCF_ERROR_NOT_FOUND:
7069 			break;
7070 
7071 		case SCF_ERROR_HANDLE_MISMATCH:
7072 		case SCF_ERROR_NOT_BOUND:
7073 		case SCF_ERROR_NOT_SET:
7074 		default:
7075 			bad_error("scf_scope_get_service", scf_error());
7076 		}
7077 	}
7078 
7079 	/* create temporary service */
7080 	/*
7081 	 * the size of the buffer was reduced to max_scf_name_len to prevent
7082 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
7083 	 * should be restored to its original value (max_scf_name_len +1)
7084 	 */
7085 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7086 	if (r < 0)
7087 		bad_error("snprintf", errno);
7088 	if (r > max_scf_name_len) {
7089 		warn(gettext(
7090 		    "Service name \"%s\" is too long.  Cannot import.\n"),
7091 		    s->sc_name);
7092 		lcbdata->sc_err = EINVAL;
7093 		return (UU_WALK_ERROR);
7094 	}
7095 
7096 retry:
7097 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7098 		switch (scf_error()) {
7099 		case SCF_ERROR_CONNECTION_BROKEN:
7100 		case SCF_ERROR_NO_RESOURCES:
7101 		case SCF_ERROR_BACKEND_READONLY:
7102 		case SCF_ERROR_BACKEND_ACCESS:
7103 			return (stash_scferror(lcbdata));
7104 
7105 		case SCF_ERROR_EXISTS:
7106 			if (!retried) {
7107 				lscf_delete(imp_tsname, 0);
7108 				retried = B_TRUE;
7109 				goto retry;
7110 			}
7111 			warn(gettext(
7112 			    "Temporary service \"%s\" must be deleted before "
7113 			    "this manifest can be imported.\n"), imp_tsname);
7114 			return (stash_scferror(lcbdata));
7115 
7116 		case SCF_ERROR_PERMISSION_DENIED:
7117 			warn(gettext("Could not create temporary service "
7118 			    "\"%s\" (permission denied).\n"), imp_tsname);
7119 			return (stash_scferror(lcbdata));
7120 
7121 		case SCF_ERROR_INVALID_ARGUMENT:
7122 		case SCF_ERROR_HANDLE_MISMATCH:
7123 		case SCF_ERROR_NOT_BOUND:
7124 		case SCF_ERROR_NOT_SET:
7125 		default:
7126 			bad_error("scf_scope_add_service", scf_error());
7127 		}
7128 	}
7129 
7130 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7131 	if (r < 0)
7132 		bad_error("snprintf", errno);
7133 
7134 	cbdata.sc_handle = lcbdata->sc_handle;
7135 	cbdata.sc_parent = imp_tsvc;
7136 	cbdata.sc_service = 1;
7137 	cbdata.sc_source_fmri = s->sc_fmri;
7138 	cbdata.sc_target_fmri = imp_str;
7139 	cbdata.sc_flags = 0;
7140 
7141 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7142 	    UU_DEFAULT) != 0) {
7143 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7144 			bad_error("uu_list_walk", uu_error());
7145 
7146 		lcbdata->sc_err = cbdata.sc_err;
7147 		switch (cbdata.sc_err) {
7148 		case ECONNABORTED:
7149 			goto connaborted;
7150 
7151 		case ECANCELED:
7152 			warn(ts_deleted, imp_tsname);
7153 			lcbdata->sc_err = EBUSY;
7154 			return (UU_WALK_ERROR);
7155 
7156 		case EEXIST:
7157 			warn(ts_pg_added, imp_tsname);
7158 			lcbdata->sc_err = EBUSY;
7159 			return (UU_WALK_ERROR);
7160 		}
7161 
7162 		r = UU_WALK_ERROR;
7163 		goto deltemp;
7164 	}
7165 
7166 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7167 	    UU_DEFAULT) != 0) {
7168 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7169 			bad_error("uu_list_walk", uu_error());
7170 
7171 		lcbdata->sc_err = cbdata.sc_err;
7172 		switch (cbdata.sc_err) {
7173 		case ECONNABORTED:
7174 			goto connaborted;
7175 
7176 		case ECANCELED:
7177 			warn(ts_deleted, imp_tsname);
7178 			lcbdata->sc_err = EBUSY;
7179 			return (UU_WALK_ERROR);
7180 
7181 		case EEXIST:
7182 			warn(ts_pg_added, imp_tsname);
7183 			lcbdata->sc_err = EBUSY;
7184 			return (UU_WALK_ERROR);
7185 		}
7186 
7187 		r = UU_WALK_ERROR;
7188 		goto deltemp;
7189 	}
7190 
7191 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7192 		switch (scf_error()) {
7193 		case SCF_ERROR_NOT_FOUND:
7194 			break;
7195 
7196 		case SCF_ERROR_CONNECTION_BROKEN:
7197 			goto connaborted;
7198 
7199 		case SCF_ERROR_INVALID_ARGUMENT:
7200 		case SCF_ERROR_HANDLE_MISMATCH:
7201 		case SCF_ERROR_NOT_BOUND:
7202 		case SCF_ERROR_NOT_SET:
7203 		default:
7204 			bad_error("scf_scope_get_service", scf_error());
7205 		}
7206 
7207 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7208 			switch (scf_error()) {
7209 			case SCF_ERROR_CONNECTION_BROKEN:
7210 				goto connaborted;
7211 
7212 			case SCF_ERROR_NO_RESOURCES:
7213 			case SCF_ERROR_BACKEND_READONLY:
7214 			case SCF_ERROR_BACKEND_ACCESS:
7215 				r = stash_scferror(lcbdata);
7216 				goto deltemp;
7217 
7218 			case SCF_ERROR_EXISTS:
7219 				warn(gettext("Scope \"%s\" changed unexpectedly"
7220 				    " (service \"%s\" added).\n"),
7221 				    SCF_SCOPE_LOCAL, s->sc_name);
7222 				lcbdata->sc_err = EBUSY;
7223 				goto deltemp;
7224 
7225 			case SCF_ERROR_PERMISSION_DENIED:
7226 				warn(gettext("Could not create service \"%s\" "
7227 				    "(permission denied).\n"), s->sc_name);
7228 				goto deltemp;
7229 
7230 			case SCF_ERROR_INVALID_ARGUMENT:
7231 			case SCF_ERROR_HANDLE_MISMATCH:
7232 			case SCF_ERROR_NOT_BOUND:
7233 			case SCF_ERROR_NOT_SET:
7234 			default:
7235 				bad_error("scf_scope_add_service", scf_error());
7236 			}
7237 		}
7238 
7239 		s->sc_import_state = IMPORT_PROP_BEGUN;
7240 
7241 		/* import service properties */
7242 		cbdata.sc_handle = lcbdata->sc_handle;
7243 		cbdata.sc_parent = imp_svc;
7244 		cbdata.sc_service = 1;
7245 		cbdata.sc_flags = lcbdata->sc_flags;
7246 		cbdata.sc_source_fmri = s->sc_fmri;
7247 		cbdata.sc_target_fmri = s->sc_fmri;
7248 
7249 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7250 		    &cbdata, UU_DEFAULT) != 0) {
7251 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7252 				bad_error("uu_list_walk", uu_error());
7253 
7254 			lcbdata->sc_err = cbdata.sc_err;
7255 			switch (cbdata.sc_err) {
7256 			case ECONNABORTED:
7257 				goto connaborted;
7258 
7259 			case ECANCELED:
7260 				warn(s_deleted, s->sc_fmri);
7261 				lcbdata->sc_err = EBUSY;
7262 				return (UU_WALK_ERROR);
7263 
7264 			case EEXIST:
7265 				warn(gettext("%s changed unexpectedly "
7266 				    "(property group added).\n"), s->sc_fmri);
7267 				lcbdata->sc_err = EBUSY;
7268 				return (UU_WALK_ERROR);
7269 
7270 			case EINVAL:
7271 				/* caught above */
7272 				bad_error("entity_pgroup_import",
7273 				    cbdata.sc_err);
7274 			}
7275 
7276 			r = UU_WALK_ERROR;
7277 			goto deltemp;
7278 		}
7279 
7280 		cbdata.sc_trans = NULL;
7281 		cbdata.sc_flags = 0;
7282 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7283 		    &cbdata, UU_DEFAULT) != 0) {
7284 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7285 				bad_error("uu_list_walk", uu_error());
7286 
7287 			lcbdata->sc_err = cbdata.sc_err;
7288 			if (cbdata.sc_err == ECONNABORTED)
7289 				goto connaborted;
7290 			r = UU_WALK_ERROR;
7291 			goto deltemp;
7292 		}
7293 
7294 		s->sc_import_state = IMPORT_PROP_DONE;
7295 
7296 		/*
7297 		 * This is a new service, so we can't take previous snapshots
7298 		 * or upgrade service properties.
7299 		 */
7300 		fresh = 1;
7301 		goto instances;
7302 	}
7303 
7304 	/* Clear sc_seen for the instances. */
7305 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7306 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7307 		bad_error("uu_list_walk", uu_error());
7308 
7309 	/*
7310 	 * Take previous snapshots for all instances.  Even for ones not
7311 	 * mentioned in the bundle, since we might change their service
7312 	 * properties.
7313 	 */
7314 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7315 		switch (scf_error()) {
7316 		case SCF_ERROR_CONNECTION_BROKEN:
7317 			goto connaborted;
7318 
7319 		case SCF_ERROR_DELETED:
7320 			warn(s_deleted, s->sc_fmri);
7321 			lcbdata->sc_err = EBUSY;
7322 			r = UU_WALK_ERROR;
7323 			goto deltemp;
7324 
7325 		case SCF_ERROR_HANDLE_MISMATCH:
7326 		case SCF_ERROR_NOT_BOUND:
7327 		case SCF_ERROR_NOT_SET:
7328 		default:
7329 			bad_error("scf_iter_service_instances", scf_error());
7330 		}
7331 	}
7332 
7333 	for (;;) {
7334 		r = scf_iter_next_instance(imp_iter, imp_inst);
7335 		if (r == 0)
7336 			break;
7337 		if (r != 1) {
7338 			switch (scf_error()) {
7339 			case SCF_ERROR_DELETED:
7340 				warn(s_deleted, s->sc_fmri);
7341 				lcbdata->sc_err = EBUSY;
7342 				r = UU_WALK_ERROR;
7343 				goto deltemp;
7344 
7345 			case SCF_ERROR_CONNECTION_BROKEN:
7346 				goto connaborted;
7347 
7348 			case SCF_ERROR_NOT_BOUND:
7349 			case SCF_ERROR_HANDLE_MISMATCH:
7350 			case SCF_ERROR_INVALID_ARGUMENT:
7351 			case SCF_ERROR_NOT_SET:
7352 			default:
7353 				bad_error("scf_iter_next_instance",
7354 				    scf_error());
7355 			}
7356 		}
7357 
7358 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7359 			switch (scf_error()) {
7360 			case SCF_ERROR_DELETED:
7361 				continue;
7362 
7363 			case SCF_ERROR_CONNECTION_BROKEN:
7364 				goto connaborted;
7365 
7366 			case SCF_ERROR_NOT_SET:
7367 			case SCF_ERROR_NOT_BOUND:
7368 			default:
7369 				bad_error("scf_instance_get_name", scf_error());
7370 			}
7371 		}
7372 
7373 		if (g_verbose)
7374 			warn(gettext(
7375 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7376 			    snap_previous, s->sc_name, imp_str);
7377 
7378 		r = take_snap(imp_inst, snap_previous, imp_snap);
7379 		switch (r) {
7380 		case 0:
7381 			break;
7382 
7383 		case ECANCELED:
7384 			continue;
7385 
7386 		case ECONNABORTED:
7387 			goto connaborted;
7388 
7389 		case EPERM:
7390 			warn(gettext("Could not take \"%s\" snapshot of "
7391 			    "svc:/%s:%s (permission denied).\n"),
7392 			    snap_previous, s->sc_name, imp_str);
7393 			lcbdata->sc_err = r;
7394 			return (UU_WALK_ERROR);
7395 
7396 		case ENOSPC:
7397 		case -1:
7398 			lcbdata->sc_err = r;
7399 			r = UU_WALK_ERROR;
7400 			goto deltemp;
7401 
7402 		default:
7403 			bad_error("take_snap", r);
7404 		}
7405 
7406 		linst.sc_name = imp_str;
7407 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7408 		    &linst, NULL, NULL);
7409 		if (inst != NULL) {
7410 			inst->sc_import_state = IMPORT_PREVIOUS;
7411 			inst->sc_seen = 1;
7412 		}
7413 	}
7414 
7415 	/*
7416 	 * Create the new instances and take previous snapshots of
7417 	 * them.  This is not necessary, but it maximizes data preservation.
7418 	 */
7419 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7420 	    inst != NULL;
7421 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7422 	    inst)) {
7423 		if (inst->sc_seen)
7424 			continue;
7425 
7426 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7427 		    imp_inst) != 0) {
7428 			switch (scf_error()) {
7429 			case SCF_ERROR_CONNECTION_BROKEN:
7430 				goto connaborted;
7431 
7432 			case SCF_ERROR_BACKEND_READONLY:
7433 			case SCF_ERROR_BACKEND_ACCESS:
7434 			case SCF_ERROR_NO_RESOURCES:
7435 				r = stash_scferror(lcbdata);
7436 				goto deltemp;
7437 
7438 			case SCF_ERROR_EXISTS:
7439 				warn(gettext("%s changed unexpectedly "
7440 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7441 				    inst->sc_name);
7442 				lcbdata->sc_err = EBUSY;
7443 				r = UU_WALK_ERROR;
7444 				goto deltemp;
7445 
7446 			case SCF_ERROR_INVALID_ARGUMENT:
7447 				warn(gettext("Service \"%s\" has instance with "
7448 				    "invalid name \"%s\".\n"), s->sc_name,
7449 				    inst->sc_name);
7450 				r = stash_scferror(lcbdata);
7451 				goto deltemp;
7452 
7453 			case SCF_ERROR_PERMISSION_DENIED:
7454 				warn(gettext("Could not create instance \"%s\" "
7455 				    "in %s (permission denied).\n"),
7456 				    inst->sc_name, s->sc_fmri);
7457 				r = stash_scferror(lcbdata);
7458 				goto deltemp;
7459 
7460 			case SCF_ERROR_HANDLE_MISMATCH:
7461 			case SCF_ERROR_NOT_BOUND:
7462 			case SCF_ERROR_NOT_SET:
7463 			default:
7464 				bad_error("scf_service_add_instance",
7465 				    scf_error());
7466 			}
7467 		}
7468 
7469 		if (g_verbose)
7470 			warn(gettext("Taking \"%s\" snapshot for "
7471 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7472 		r = take_snap(imp_inst, snap_previous, imp_snap);
7473 		switch (r) {
7474 		case 0:
7475 			break;
7476 
7477 		case ECANCELED:
7478 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7479 			lcbdata->sc_err = EBUSY;
7480 			r = UU_WALK_ERROR;
7481 			goto deltemp;
7482 
7483 		case ECONNABORTED:
7484 			goto connaborted;
7485 
7486 		case EPERM:
7487 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7488 			lcbdata->sc_err = r;
7489 			r = UU_WALK_ERROR;
7490 			goto deltemp;
7491 
7492 		case ENOSPC:
7493 		case -1:
7494 			r = UU_WALK_ERROR;
7495 			goto deltemp;
7496 
7497 		default:
7498 			bad_error("take_snap", r);
7499 		}
7500 	}
7501 
7502 	s->sc_import_state = IMPORT_PREVIOUS;
7503 
7504 	/*
7505 	 * Upgrade service properties, if we can find a last-import snapshot.
7506 	 * Any will do because we don't support different service properties
7507 	 * in different manifests, so all snaplevels of the service in all of
7508 	 * the last-import snapshots of the instances should be the same.
7509 	 */
7510 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7511 		switch (scf_error()) {
7512 		case SCF_ERROR_CONNECTION_BROKEN:
7513 			goto connaborted;
7514 
7515 		case SCF_ERROR_DELETED:
7516 			warn(s_deleted, s->sc_fmri);
7517 			lcbdata->sc_err = EBUSY;
7518 			r = UU_WALK_ERROR;
7519 			goto deltemp;
7520 
7521 		case SCF_ERROR_HANDLE_MISMATCH:
7522 		case SCF_ERROR_NOT_BOUND:
7523 		case SCF_ERROR_NOT_SET:
7524 		default:
7525 			bad_error("scf_iter_service_instances", scf_error());
7526 		}
7527 	}
7528 
7529 	for (;;) {
7530 		r = scf_iter_next_instance(imp_iter, imp_inst);
7531 		if (r == -1) {
7532 			switch (scf_error()) {
7533 			case SCF_ERROR_DELETED:
7534 				warn(s_deleted, s->sc_fmri);
7535 				lcbdata->sc_err = EBUSY;
7536 				r = UU_WALK_ERROR;
7537 				goto deltemp;
7538 
7539 			case SCF_ERROR_CONNECTION_BROKEN:
7540 				goto connaborted;
7541 
7542 			case SCF_ERROR_NOT_BOUND:
7543 			case SCF_ERROR_HANDLE_MISMATCH:
7544 			case SCF_ERROR_INVALID_ARGUMENT:
7545 			case SCF_ERROR_NOT_SET:
7546 			default:
7547 				bad_error("scf_iter_next_instance",
7548 				    scf_error());
7549 			}
7550 		}
7551 
7552 		if (r == 0) {
7553 			/*
7554 			 * Didn't find any last-import snapshots.  Override-
7555 			 * import the properties.  Unless one of the instances
7556 			 * has a general/enabled property, in which case we're
7557 			 * probably running a last-import-capable svccfg for
7558 			 * the first time, and we should only take the
7559 			 * last-import snapshot.
7560 			 */
7561 			if (have_ge) {
7562 				pgroup_t *mfpg;
7563 				scf_callback_t mfcbdata;
7564 
7565 				li_only = 1;
7566 				no_refresh = 1;
7567 				/*
7568 				 * Need to go ahead and import the manifestfiles
7569 				 * pg if it exists. If the last-import snapshot
7570 				 * upgrade code is ever removed this code can
7571 				 * be removed as well.
7572 				 */
7573 				mfpg = internal_pgroup_find(s,
7574 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7575 
7576 				if (mfpg) {
7577 					mfcbdata.sc_handle = g_hndl;
7578 					mfcbdata.sc_parent = imp_svc;
7579 					mfcbdata.sc_service = 1;
7580 					mfcbdata.sc_flags = SCI_FORCE;
7581 					mfcbdata.sc_source_fmri = s->sc_fmri;
7582 					mfcbdata.sc_target_fmri = s->sc_fmri;
7583 					if (entity_pgroup_import(mfpg,
7584 					    &mfcbdata) != UU_WALK_NEXT) {
7585 						warn(s_mfile_upd, s->sc_fmri);
7586 						r = UU_WALK_ERROR;
7587 						goto deltemp;
7588 					}
7589 				}
7590 				break;
7591 			}
7592 
7593 			s->sc_import_state = IMPORT_PROP_BEGUN;
7594 
7595 			cbdata.sc_handle = g_hndl;
7596 			cbdata.sc_parent = imp_svc;
7597 			cbdata.sc_service = 1;
7598 			cbdata.sc_flags = SCI_FORCE;
7599 			cbdata.sc_source_fmri = s->sc_fmri;
7600 			cbdata.sc_target_fmri = s->sc_fmri;
7601 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7602 			    &cbdata, UU_DEFAULT) != 0) {
7603 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7604 					bad_error("uu_list_walk", uu_error());
7605 				lcbdata->sc_err = cbdata.sc_err;
7606 				switch (cbdata.sc_err) {
7607 				case ECONNABORTED:
7608 					goto connaborted;
7609 
7610 				case ECANCELED:
7611 					warn(s_deleted, s->sc_fmri);
7612 					lcbdata->sc_err = EBUSY;
7613 					break;
7614 
7615 				case EINVAL:	/* caught above */
7616 				case EEXIST:
7617 					bad_error("entity_pgroup_import",
7618 					    cbdata.sc_err);
7619 				}
7620 
7621 				r = UU_WALK_ERROR;
7622 				goto deltemp;
7623 			}
7624 
7625 			cbdata.sc_trans = NULL;
7626 			cbdata.sc_flags = 0;
7627 			if (uu_list_walk(s->sc_dependents,
7628 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7629 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7630 					bad_error("uu_list_walk", uu_error());
7631 				lcbdata->sc_err = cbdata.sc_err;
7632 				if (cbdata.sc_err == ECONNABORTED)
7633 					goto connaborted;
7634 				r = UU_WALK_ERROR;
7635 				goto deltemp;
7636 			}
7637 			break;
7638 		}
7639 
7640 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7641 		    imp_snap) != 0) {
7642 			switch (scf_error()) {
7643 			case SCF_ERROR_DELETED:
7644 				continue;
7645 
7646 			case SCF_ERROR_NOT_FOUND:
7647 				break;
7648 
7649 			case SCF_ERROR_CONNECTION_BROKEN:
7650 				goto connaborted;
7651 
7652 			case SCF_ERROR_HANDLE_MISMATCH:
7653 			case SCF_ERROR_NOT_BOUND:
7654 			case SCF_ERROR_INVALID_ARGUMENT:
7655 			case SCF_ERROR_NOT_SET:
7656 			default:
7657 				bad_error("scf_instance_get_snapshot",
7658 				    scf_error());
7659 			}
7660 
7661 			if (have_ge)
7662 				continue;
7663 
7664 			/*
7665 			 * Check for a general/enabled property.  This is how
7666 			 * we tell whether to import if there turn out to be
7667 			 * no last-import snapshots.
7668 			 */
7669 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7670 			    imp_pg) == 0) {
7671 				if (scf_pg_get_property(imp_pg,
7672 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7673 					have_ge = 1;
7674 				} else {
7675 					switch (scf_error()) {
7676 					case SCF_ERROR_DELETED:
7677 					case SCF_ERROR_NOT_FOUND:
7678 						continue;
7679 
7680 					case SCF_ERROR_INVALID_ARGUMENT:
7681 					case SCF_ERROR_HANDLE_MISMATCH:
7682 					case SCF_ERROR_CONNECTION_BROKEN:
7683 					case SCF_ERROR_NOT_BOUND:
7684 					case SCF_ERROR_NOT_SET:
7685 					default:
7686 						bad_error("scf_pg_get_property",
7687 						    scf_error());
7688 					}
7689 				}
7690 			} else {
7691 				switch (scf_error()) {
7692 				case SCF_ERROR_DELETED:
7693 				case SCF_ERROR_NOT_FOUND:
7694 					continue;
7695 
7696 				case SCF_ERROR_CONNECTION_BROKEN:
7697 					goto connaborted;
7698 
7699 				case SCF_ERROR_NOT_BOUND:
7700 				case SCF_ERROR_NOT_SET:
7701 				case SCF_ERROR_INVALID_ARGUMENT:
7702 				case SCF_ERROR_HANDLE_MISMATCH:
7703 				default:
7704 					bad_error("scf_instance_get_pg",
7705 					    scf_error());
7706 				}
7707 			}
7708 			continue;
7709 		}
7710 
7711 		/* find service snaplevel */
7712 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7713 		switch (r) {
7714 		case 0:
7715 			break;
7716 
7717 		case ECONNABORTED:
7718 			goto connaborted;
7719 
7720 		case ECANCELED:
7721 			continue;
7722 
7723 		case ENOENT:
7724 			if (scf_instance_get_name(imp_inst, imp_str,
7725 			    imp_str_sz) < 0)
7726 				(void) strcpy(imp_str, "?");
7727 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7728 			lcbdata->sc_err = EBADF;
7729 			r = UU_WALK_ERROR;
7730 			goto deltemp;
7731 
7732 		default:
7733 			bad_error("get_snaplevel", r);
7734 		}
7735 
7736 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7737 		    imp_rsnap) != 0) {
7738 			switch (scf_error()) {
7739 			case SCF_ERROR_DELETED:
7740 				continue;
7741 
7742 			case SCF_ERROR_NOT_FOUND:
7743 				break;
7744 
7745 			case SCF_ERROR_CONNECTION_BROKEN:
7746 				goto connaborted;
7747 
7748 			case SCF_ERROR_INVALID_ARGUMENT:
7749 			case SCF_ERROR_HANDLE_MISMATCH:
7750 			case SCF_ERROR_NOT_BOUND:
7751 			case SCF_ERROR_NOT_SET:
7752 			default:
7753 				bad_error("scf_instance_get_snapshot",
7754 				    scf_error());
7755 			}
7756 			running = NULL;
7757 		} else {
7758 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7759 			switch (r) {
7760 			case 0:
7761 				running = imp_rsnpl;
7762 				break;
7763 
7764 			case ECONNABORTED:
7765 				goto connaborted;
7766 
7767 			case ECANCELED:
7768 				continue;
7769 
7770 			case ENOENT:
7771 				if (scf_instance_get_name(imp_inst, imp_str,
7772 				    imp_str_sz) < 0)
7773 					(void) strcpy(imp_str, "?");
7774 				warn(badsnap, snap_running, s->sc_name,
7775 				    imp_str);
7776 				lcbdata->sc_err = EBADF;
7777 				r = UU_WALK_ERROR;
7778 				goto deltemp;
7779 
7780 			default:
7781 				bad_error("get_snaplevel", r);
7782 			}
7783 		}
7784 
7785 		if (g_verbose) {
7786 			if (scf_instance_get_name(imp_inst, imp_str,
7787 			    imp_str_sz) < 0)
7788 				(void) strcpy(imp_str, "?");
7789 			warn(gettext("Upgrading properties of %s according to "
7790 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7791 		}
7792 
7793 		/* upgrade service properties */
7794 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7795 		if (r == 0)
7796 			break;
7797 
7798 		switch (r) {
7799 		case ECONNABORTED:
7800 			goto connaborted;
7801 
7802 		case ECANCELED:
7803 			warn(s_deleted, s->sc_fmri);
7804 			lcbdata->sc_err = EBUSY;
7805 			break;
7806 
7807 		case ENODEV:
7808 			if (scf_instance_get_name(imp_inst, imp_str,
7809 			    imp_str_sz) < 0)
7810 				(void) strcpy(imp_str, "?");
7811 			warn(i_deleted, s->sc_fmri, imp_str);
7812 			lcbdata->sc_err = EBUSY;
7813 			break;
7814 
7815 		default:
7816 			lcbdata->sc_err = r;
7817 		}
7818 
7819 		r = UU_WALK_ERROR;
7820 		goto deltemp;
7821 	}
7822 
7823 	s->sc_import_state = IMPORT_PROP_DONE;
7824 
7825 instances:
7826 	/* import instances */
7827 	cbdata.sc_handle = lcbdata->sc_handle;
7828 	cbdata.sc_parent = imp_svc;
7829 	cbdata.sc_service = 1;
7830 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7831 	cbdata.sc_general = NULL;
7832 
7833 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7834 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7835 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7836 			bad_error("uu_list_walk", uu_error());
7837 
7838 		lcbdata->sc_err = cbdata.sc_err;
7839 		if (cbdata.sc_err == ECONNABORTED)
7840 			goto connaborted;
7841 		r = UU_WALK_ERROR;
7842 		goto deltemp;
7843 	}
7844 
7845 	s->sc_import_state = IMPORT_COMPLETE;
7846 	r = UU_WALK_NEXT;
7847 
7848 deltemp:
7849 	/* delete temporary service */
7850 	if (scf_service_delete(imp_tsvc) != 0) {
7851 		switch (scf_error()) {
7852 		case SCF_ERROR_DELETED:
7853 			break;
7854 
7855 		case SCF_ERROR_CONNECTION_BROKEN:
7856 			goto connaborted;
7857 
7858 		case SCF_ERROR_EXISTS:
7859 			warn(gettext(
7860 			    "Could not delete svc:/%s (instances exist).\n"),
7861 			    imp_tsname);
7862 			break;
7863 
7864 		case SCF_ERROR_NOT_SET:
7865 		case SCF_ERROR_NOT_BOUND:
7866 		default:
7867 			bad_error("scf_service_delete", scf_error());
7868 		}
7869 	}
7870 
7871 	return (r);
7872 
7873 connaborted:
7874 	warn(gettext("Could not delete svc:/%s "
7875 	    "(repository connection broken).\n"), imp_tsname);
7876 	lcbdata->sc_err = ECONNABORTED;
7877 	return (UU_WALK_ERROR);
7878 }
7879 
7880 static const char *
7881 import_progress(int st)
7882 {
7883 	switch (st) {
7884 	case 0:
7885 		return (gettext("not reached."));
7886 
7887 	case IMPORT_PREVIOUS:
7888 		return (gettext("previous snapshot taken."));
7889 
7890 	case IMPORT_PROP_BEGUN:
7891 		return (gettext("some properties imported."));
7892 
7893 	case IMPORT_PROP_DONE:
7894 		return (gettext("properties imported."));
7895 
7896 	case IMPORT_COMPLETE:
7897 		return (gettext("imported."));
7898 
7899 	case IMPORT_REFRESHED:
7900 		return (gettext("refresh requested."));
7901 
7902 	default:
7903 #ifndef NDEBUG
7904 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7905 		    __FILE__, __LINE__, st);
7906 #endif
7907 		abort();
7908 		/* NOTREACHED */
7909 	}
7910 }
7911 
7912 /*
7913  * Returns
7914  *   0 - success
7915  *     - fmri wasn't found (error printed)
7916  *     - entity was deleted (error printed)
7917  *     - backend denied access (error printed)
7918  *   ENOMEM - out of memory (error printed)
7919  *   ECONNABORTED - repository connection broken (error printed)
7920  *   EPERM - permission denied (error printed)
7921  *   -1 - unknown libscf error (error printed)
7922  */
7923 static int
7924 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7925 {
7926 	scf_error_t serr;
7927 	void *ent;
7928 	int issvc;
7929 	int r;
7930 
7931 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7932 	const char *dpt_deleted = gettext("Could not refresh %s "
7933 	    "(dependent \"%s\" of %s) (deleted).\n");
7934 
7935 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7936 	switch (serr) {
7937 	case SCF_ERROR_NONE:
7938 		break;
7939 
7940 	case SCF_ERROR_NO_MEMORY:
7941 		if (name == NULL)
7942 			warn(gettext("Could not refresh %s (out of memory).\n"),
7943 			    fmri);
7944 		else
7945 			warn(gettext("Could not refresh %s "
7946 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7947 			    fmri, name, d_fmri);
7948 		return (ENOMEM);
7949 
7950 	case SCF_ERROR_NOT_FOUND:
7951 		if (name == NULL)
7952 			warn(deleted, fmri);
7953 		else
7954 			warn(dpt_deleted, fmri, name, d_fmri);
7955 		return (0);
7956 
7957 	case SCF_ERROR_INVALID_ARGUMENT:
7958 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7959 	default:
7960 		bad_error("fmri_to_entity", serr);
7961 	}
7962 
7963 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7964 	switch (r) {
7965 	case 0:
7966 		break;
7967 
7968 	case ECONNABORTED:
7969 		if (name != NULL)
7970 			warn(gettext("Could not refresh %s "
7971 			    "(dependent \"%s\" of %s) "
7972 			    "(repository connection broken).\n"), fmri, name,
7973 			    d_fmri);
7974 		return (r);
7975 
7976 	case ECANCELED:
7977 		if (name == NULL)
7978 			warn(deleted, fmri);
7979 		else
7980 			warn(dpt_deleted, fmri, name, d_fmri);
7981 		return (0);
7982 
7983 	case EACCES:
7984 		if (!g_verbose)
7985 			return (0);
7986 		if (name == NULL)
7987 			warn(gettext("Could not refresh %s "
7988 			    "(backend access denied).\n"), fmri);
7989 		else
7990 			warn(gettext("Could not refresh %s "
7991 			    "(dependent \"%s\" of %s) "
7992 			    "(backend access denied).\n"), fmri, name, d_fmri);
7993 		return (0);
7994 
7995 	case EPERM:
7996 		if (name == NULL)
7997 			warn(gettext("Could not refresh %s "
7998 			    "(permission denied).\n"), fmri);
7999 		else
8000 			warn(gettext("Could not refresh %s "
8001 			    "(dependent \"%s\" of %s) "
8002 			    "(permission denied).\n"), fmri, name, d_fmri);
8003 		return (r);
8004 
8005 	case ENOSPC:
8006 		if (name == NULL)
8007 			warn(gettext("Could not refresh %s "
8008 			    "(repository server out of resources).\n"),
8009 			    fmri);
8010 		else
8011 			warn(gettext("Could not refresh %s "
8012 			    "(dependent \"%s\" of %s) "
8013 			    "(repository server out of resources).\n"),
8014 			    fmri, name, d_fmri);
8015 		return (r);
8016 
8017 	case -1:
8018 		scfwarn();
8019 		return (r);
8020 
8021 	default:
8022 		bad_error("refresh_entity", r);
8023 	}
8024 
8025 	if (issvc)
8026 		scf_service_destroy(ent);
8027 	else
8028 		scf_instance_destroy(ent);
8029 
8030 	return (0);
8031 }
8032 
8033 static int
8034 alloc_imp_globals()
8035 {
8036 	int r;
8037 
8038 	const char * const emsg_nomem = gettext("Out of memory.\n");
8039 	const char * const emsg_nores =
8040 	    gettext("svc.configd is out of resources.\n");
8041 
8042 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8043 	    max_scf_name_len : max_scf_fmri_len) + 1;
8044 
8045 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8046 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
8047 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8048 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8049 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8050 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8051 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8052 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8053 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8054 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8055 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8056 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8057 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8058 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
8059 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8060 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8061 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8062 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8063 	    (imp_str = malloc(imp_str_sz)) == NULL ||
8064 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8065 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8066 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8067 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8068 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8069 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8070 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8071 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8072 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8073 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
8074 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8075 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
8076 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8077 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8078 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8079 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8080 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8081 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8082 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
8083 			warn(emsg_nores);
8084 		else
8085 			warn(emsg_nomem);
8086 
8087 		return (-1);
8088 	}
8089 
8090 	r = load_init();
8091 	switch (r) {
8092 	case 0:
8093 		break;
8094 
8095 	case ENOMEM:
8096 		warn(emsg_nomem);
8097 		return (-1);
8098 
8099 	default:
8100 		bad_error("load_init", r);
8101 	}
8102 
8103 	return (0);
8104 }
8105 
8106 static void
8107 free_imp_globals()
8108 {
8109 	pgroup_t *old_dpt;
8110 	void *cookie;
8111 
8112 	load_fini();
8113 
8114 	free(ud_ctarg);
8115 	free(ud_oldtarg);
8116 	free(ud_name);
8117 	ud_ctarg = ud_oldtarg = ud_name = NULL;
8118 
8119 	scf_transaction_destroy(ud_tx);
8120 	ud_tx = NULL;
8121 	scf_iter_destroy(ud_iter);
8122 	scf_iter_destroy(ud_iter2);
8123 	ud_iter = ud_iter2 = NULL;
8124 	scf_value_destroy(ud_val);
8125 	ud_val = NULL;
8126 	scf_property_destroy(ud_prop);
8127 	scf_property_destroy(ud_dpt_prop);
8128 	ud_prop = ud_dpt_prop = NULL;
8129 	scf_pg_destroy(ud_pg);
8130 	scf_pg_destroy(ud_cur_depts_pg);
8131 	scf_pg_destroy(ud_run_dpts_pg);
8132 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8133 	scf_snaplevel_destroy(ud_snpl);
8134 	ud_snpl = NULL;
8135 	scf_instance_destroy(ud_inst);
8136 	ud_inst = NULL;
8137 
8138 	free(imp_str);
8139 	free(imp_tsname);
8140 	free(imp_fe1);
8141 	free(imp_fe2);
8142 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8143 
8144 	cookie = NULL;
8145 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8146 	    NULL) {
8147 		free((char *)old_dpt->sc_pgroup_name);
8148 		free((char *)old_dpt->sc_pgroup_fmri);
8149 		internal_pgroup_free(old_dpt);
8150 	}
8151 	uu_list_destroy(imp_deleted_dpts);
8152 
8153 	scf_transaction_destroy(imp_tx);
8154 	imp_tx = NULL;
8155 	scf_iter_destroy(imp_iter);
8156 	scf_iter_destroy(imp_rpg_iter);
8157 	scf_iter_destroy(imp_up_iter);
8158 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8159 	scf_property_destroy(imp_prop);
8160 	imp_prop = NULL;
8161 	scf_pg_destroy(imp_pg);
8162 	scf_pg_destroy(imp_pg2);
8163 	imp_pg = imp_pg2 = NULL;
8164 	scf_snaplevel_destroy(imp_snpl);
8165 	scf_snaplevel_destroy(imp_rsnpl);
8166 	imp_snpl = imp_rsnpl = NULL;
8167 	scf_snapshot_destroy(imp_snap);
8168 	scf_snapshot_destroy(imp_lisnap);
8169 	scf_snapshot_destroy(imp_tlisnap);
8170 	scf_snapshot_destroy(imp_rsnap);
8171 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8172 	scf_instance_destroy(imp_inst);
8173 	scf_instance_destroy(imp_tinst);
8174 	imp_inst = imp_tinst = NULL;
8175 	scf_service_destroy(imp_svc);
8176 	scf_service_destroy(imp_tsvc);
8177 	imp_svc = imp_tsvc = NULL;
8178 	scf_scope_destroy(imp_scope);
8179 	imp_scope = NULL;
8180 
8181 	load_fini();
8182 }
8183 
8184 int
8185 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8186 {
8187 	scf_callback_t cbdata;
8188 	int result = 0;
8189 	entity_t *svc, *inst;
8190 	uu_list_t *insts;
8191 	int r;
8192 	pgroup_t *old_dpt;
8193 	int annotation_set = 0;
8194 
8195 	const char * const emsg_nomem = gettext("Out of memory.\n");
8196 	const char * const emsg_nores =
8197 	    gettext("svc.configd is out of resources.\n");
8198 
8199 	lscf_prep_hndl();
8200 
8201 	if (alloc_imp_globals())
8202 		goto out;
8203 
8204 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8205 		switch (scf_error()) {
8206 		case SCF_ERROR_CONNECTION_BROKEN:
8207 			warn(gettext("Repository connection broken.\n"));
8208 			repository_teardown();
8209 			result = -1;
8210 			goto out;
8211 
8212 		case SCF_ERROR_NOT_FOUND:
8213 		case SCF_ERROR_INVALID_ARGUMENT:
8214 		case SCF_ERROR_NOT_BOUND:
8215 		case SCF_ERROR_HANDLE_MISMATCH:
8216 		default:
8217 			bad_error("scf_handle_get_scope", scf_error());
8218 		}
8219 	}
8220 
8221 	/* Set up the auditing annotation. */
8222 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8223 		annotation_set = 1;
8224 	} else {
8225 		switch (scf_error()) {
8226 		case SCF_ERROR_CONNECTION_BROKEN:
8227 			warn(gettext("Repository connection broken.\n"));
8228 			repository_teardown();
8229 			result = -1;
8230 			goto out;
8231 
8232 		case SCF_ERROR_INVALID_ARGUMENT:
8233 		case SCF_ERROR_NOT_BOUND:
8234 		case SCF_ERROR_NO_RESOURCES:
8235 		case SCF_ERROR_INTERNAL:
8236 			bad_error("_scf_set_annotation", scf_error());
8237 			/* NOTREACHED */
8238 
8239 		default:
8240 			/*
8241 			 * Do not terminate import because of inability to
8242 			 * generate annotation audit event.
8243 			 */
8244 			warn(gettext("_scf_set_annotation() unexpectedly "
8245 			    "failed with return code of %d\n"), scf_error());
8246 			break;
8247 		}
8248 	}
8249 
8250 	/*
8251 	 * Clear the sc_import_state's of all services & instances so we can
8252 	 * report how far we got if we fail.
8253 	 */
8254 	for (svc = uu_list_first(bndl->sc_bundle_services);
8255 	    svc != NULL;
8256 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8257 		svc->sc_import_state = 0;
8258 
8259 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8260 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8261 		    UU_DEFAULT) != 0)
8262 			bad_error("uu_list_walk", uu_error());
8263 	}
8264 
8265 	cbdata.sc_handle = g_hndl;
8266 	cbdata.sc_parent = imp_scope;
8267 	cbdata.sc_flags = flags;
8268 	cbdata.sc_general = NULL;
8269 
8270 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8271 	    &cbdata, UU_DEFAULT) == 0) {
8272 		char *eptr;
8273 		/* Success.  Refresh everything. */
8274 
8275 		if (flags & SCI_NOREFRESH || no_refresh) {
8276 			no_refresh = 0;
8277 			result = 0;
8278 			goto out;
8279 		}
8280 
8281 		for (svc = uu_list_first(bndl->sc_bundle_services);
8282 		    svc != NULL;
8283 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8284 			pgroup_t *dpt;
8285 
8286 			insts = svc->sc_u.sc_service.sc_service_instances;
8287 
8288 			for (inst = uu_list_first(insts);
8289 			    inst != NULL;
8290 			    inst = uu_list_next(insts, inst)) {
8291 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8292 				switch (r) {
8293 				case 0:
8294 					break;
8295 
8296 				case ENOMEM:
8297 				case ECONNABORTED:
8298 				case EPERM:
8299 				case -1:
8300 					goto progress;
8301 
8302 				default:
8303 					bad_error("imp_refresh_fmri", r);
8304 				}
8305 
8306 				inst->sc_import_state = IMPORT_REFRESHED;
8307 
8308 				for (dpt = uu_list_first(inst->sc_dependents);
8309 				    dpt != NULL;
8310 				    dpt = uu_list_next(inst->sc_dependents,
8311 				    dpt))
8312 					if (imp_refresh_fmri(
8313 					    dpt->sc_pgroup_fmri,
8314 					    dpt->sc_pgroup_name,
8315 					    inst->sc_fmri) != 0)
8316 						goto progress;
8317 			}
8318 
8319 			for (dpt = uu_list_first(svc->sc_dependents);
8320 			    dpt != NULL;
8321 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8322 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8323 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8324 					goto progress;
8325 		}
8326 
8327 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8328 		    old_dpt != NULL;
8329 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8330 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8331 			    old_dpt->sc_pgroup_name,
8332 			    old_dpt->sc_parent->sc_fmri) != 0)
8333 				goto progress;
8334 
8335 		result = 0;
8336 
8337 		/*
8338 		 * This snippet of code assumes that we are running svccfg as we
8339 		 * normally do -- witih svc.startd running. Of course, that is
8340 		 * not actually the case all the time because we also use a
8341 		 * varient of svc.configd and svccfg which are only meant to
8342 		 * run during the build process. During this time we have no
8343 		 * svc.startd, so this check would hang the build process.
8344 		 *
8345 		 * However, we've also given other consolidations, a bit of a
8346 		 * means to tie themselves into a knot. They're not properly
8347 		 * using the native build equivalents, but they've been getting
8348 		 * away with it anyways. Therefore, if we've found that
8349 		 * SVCCFG_REPOSITORY is set indicating that a separate configd
8350 		 * should be spun up, then we have to assume it's not using a
8351 		 * startd and we should not do this check.
8352 		 */
8353 #ifndef NATIVE_BUILD
8354 		/*
8355 		 * Verify that the restarter group is preset
8356 		 */
8357 		eptr = getenv("SVCCFG_REPOSITORY");
8358 		for (svc = uu_list_first(bndl->sc_bundle_services);
8359 		    svc != NULL && eptr == NULL;
8360 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8361 
8362 			insts = svc->sc_u.sc_service.sc_service_instances;
8363 
8364 			for (inst = uu_list_first(insts);
8365 			    inst != NULL;
8366 			    inst = uu_list_next(insts, inst)) {
8367 				if (lscf_instance_verify(imp_scope, svc,
8368 				    inst) != 0)
8369 					goto progress;
8370 			}
8371 		}
8372 #endif
8373 		goto out;
8374 
8375 	}
8376 
8377 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8378 		bad_error("uu_list_walk", uu_error());
8379 
8380 printerr:
8381 	/* If the error hasn't been printed yet, do so here. */
8382 	switch (cbdata.sc_err) {
8383 	case ECONNABORTED:
8384 		warn(gettext("Repository connection broken.\n"));
8385 		break;
8386 
8387 	case ENOMEM:
8388 		warn(emsg_nomem);
8389 		break;
8390 
8391 	case ENOSPC:
8392 		warn(emsg_nores);
8393 		break;
8394 
8395 	case EROFS:
8396 		warn(gettext("Repository is read-only.\n"));
8397 		break;
8398 
8399 	case EACCES:
8400 		warn(gettext("Repository backend denied access.\n"));
8401 		break;
8402 
8403 	case EPERM:
8404 	case EINVAL:
8405 	case EEXIST:
8406 	case EBUSY:
8407 	case EBADF:
8408 	case -1:
8409 		break;
8410 
8411 	default:
8412 		bad_error("lscf_service_import", cbdata.sc_err);
8413 	}
8414 
8415 progress:
8416 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8417 
8418 	for (svc = uu_list_first(bndl->sc_bundle_services);
8419 	    svc != NULL;
8420 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8421 		insts = svc->sc_u.sc_service.sc_service_instances;
8422 
8423 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8424 		    import_progress(svc->sc_import_state));
8425 
8426 		for (inst = uu_list_first(insts);
8427 		    inst != NULL;
8428 		    inst = uu_list_next(insts, inst))
8429 			warn(gettext("    Instance \"%s\": %s\n"),
8430 			    inst->sc_name,
8431 			    import_progress(inst->sc_import_state));
8432 	}
8433 
8434 	if (cbdata.sc_err == ECONNABORTED)
8435 		repository_teardown();
8436 
8437 
8438 	result = -1;
8439 
8440 out:
8441 	if (annotation_set != 0) {
8442 		/* Turn off annotation.  It is no longer needed. */
8443 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8444 	}
8445 
8446 	free_imp_globals();
8447 
8448 	return (result);
8449 }
8450 
8451 /*
8452  * _lscf_import_err() summarize the error handling returned by
8453  * lscf_import_{instance | service}_pgs
8454  * Return values are:
8455  * IMPORT_NEXT
8456  * IMPORT_OUT
8457  * IMPORT_BAD
8458  */
8459 
8460 #define	IMPORT_BAD	-1
8461 #define	IMPORT_NEXT	0
8462 #define	IMPORT_OUT	1
8463 
8464 static int
8465 _lscf_import_err(int err, const char *fmri)
8466 {
8467 	switch (err) {
8468 	case 0:
8469 		if (g_verbose)
8470 			warn(gettext("%s updated.\n"), fmri);
8471 		return (IMPORT_NEXT);
8472 
8473 	case ECONNABORTED:
8474 		warn(gettext("Could not update %s "
8475 		    "(repository connection broken).\n"), fmri);
8476 		return (IMPORT_OUT);
8477 
8478 	case ENOMEM:
8479 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8480 		return (IMPORT_OUT);
8481 
8482 	case ENOSPC:
8483 		warn(gettext("Could not update %s "
8484 		    "(repository server out of resources).\n"), fmri);
8485 		return (IMPORT_OUT);
8486 
8487 	case ECANCELED:
8488 		warn(gettext(
8489 		    "Could not update %s (deleted).\n"), fmri);
8490 		return (IMPORT_NEXT);
8491 
8492 	case EPERM:
8493 	case EINVAL:
8494 	case EBUSY:
8495 		return (IMPORT_NEXT);
8496 
8497 	case EROFS:
8498 		warn(gettext("Could not update %s (repository read-only).\n"),
8499 		    fmri);
8500 		return (IMPORT_OUT);
8501 
8502 	case EACCES:
8503 		warn(gettext("Could not update %s "
8504 		    "(backend access denied).\n"), fmri);
8505 		return (IMPORT_NEXT);
8506 
8507 	case EEXIST:
8508 	default:
8509 		return (IMPORT_BAD);
8510 	}
8511 
8512 	/*NOTREACHED*/
8513 }
8514 
8515 /*
8516  * The global imp_svc and imp_inst should be set by the caller in the
8517  * check to make sure the service and instance exist that the apply is
8518  * working on.
8519  */
8520 static int
8521 lscf_dependent_apply(void *dpg, void *e)
8522 {
8523 	scf_callback_t cb;
8524 	pgroup_t *dpt_pgroup = dpg;
8525 	pgroup_t *deldpt;
8526 	entity_t *ent = e;
8527 	int tissvc;
8528 	void *sc_ent, *tent;
8529 	scf_error_t serr;
8530 	int r;
8531 
8532 	const char * const dependents = "dependents";
8533 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8534 
8535 	if (issvc)
8536 		sc_ent = imp_svc;
8537 	else
8538 		sc_ent = imp_inst;
8539 
8540 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8541 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8542 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8543 	    imp_prop) != 0) {
8544 		switch (scf_error()) {
8545 		case SCF_ERROR_NOT_FOUND:
8546 		case SCF_ERROR_DELETED:
8547 			break;
8548 
8549 		case SCF_ERROR_CONNECTION_BROKEN:
8550 		case SCF_ERROR_NOT_SET:
8551 		case SCF_ERROR_INVALID_ARGUMENT:
8552 		case SCF_ERROR_HANDLE_MISMATCH:
8553 		case SCF_ERROR_NOT_BOUND:
8554 		default:
8555 			bad_error("entity_get_pg", scf_error());
8556 		}
8557 	} else {
8558 		/*
8559 		 * Found the dependents/<wip dep> so check to
8560 		 * see if the service is different.  If so
8561 		 * store the service for later refresh, and
8562 		 * delete the wip dependency from the service
8563 		 */
8564 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8565 			switch (scf_error()) {
8566 				case SCF_ERROR_DELETED:
8567 					break;
8568 
8569 				case SCF_ERROR_CONNECTION_BROKEN:
8570 				case SCF_ERROR_NOT_SET:
8571 				case SCF_ERROR_INVALID_ARGUMENT:
8572 				case SCF_ERROR_HANDLE_MISMATCH:
8573 				case SCF_ERROR_NOT_BOUND:
8574 				default:
8575 					bad_error("scf_property_get_value",
8576 					    scf_error());
8577 			}
8578 		}
8579 
8580 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8581 		    max_scf_value_len + 1) < 0)
8582 			bad_error("scf_value_get_as_string", scf_error());
8583 
8584 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8585 		switch (r) {
8586 		case 1:
8587 			break;
8588 		case 0:
8589 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8590 			    &tissvc)) != SCF_ERROR_NONE) {
8591 				if (serr == SCF_ERROR_NOT_FOUND) {
8592 					break;
8593 				} else {
8594 					bad_error("fmri_to_entity", serr);
8595 				}
8596 			}
8597 
8598 			if (entity_get_pg(tent, tissvc,
8599 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8600 				serr = scf_error();
8601 				if (serr == SCF_ERROR_NOT_FOUND ||
8602 				    serr == SCF_ERROR_DELETED) {
8603 					break;
8604 				} else {
8605 					bad_error("entity_get_pg", scf_error());
8606 				}
8607 			}
8608 
8609 			if (scf_pg_delete(imp_pg) != 0) {
8610 				serr = scf_error();
8611 				if (serr == SCF_ERROR_NOT_FOUND ||
8612 				    serr == SCF_ERROR_DELETED) {
8613 					break;
8614 				} else {
8615 					bad_error("scf_pg_delete", scf_error());
8616 				}
8617 			}
8618 
8619 			deldpt = internal_pgroup_new();
8620 			if (deldpt == NULL)
8621 				return (ENOMEM);
8622 			deldpt->sc_pgroup_name =
8623 			    strdup(dpt_pgroup->sc_pgroup_name);
8624 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8625 			if (deldpt->sc_pgroup_name == NULL ||
8626 			    deldpt->sc_pgroup_fmri == NULL)
8627 				return (ENOMEM);
8628 			deldpt->sc_parent = (entity_t *)ent;
8629 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8630 			    deldpt) != 0)
8631 				uu_die(gettext("libuutil error: %s\n"),
8632 				    uu_strerror(uu_error()));
8633 
8634 			break;
8635 		default:
8636 			bad_error("fmri_equal", r);
8637 		}
8638 	}
8639 
8640 	cb.sc_handle = g_hndl;
8641 	cb.sc_parent = ent;
8642 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8643 	cb.sc_source_fmri = ent->sc_fmri;
8644 	cb.sc_target_fmri = ent->sc_fmri;
8645 	cb.sc_trans = NULL;
8646 	cb.sc_flags = SCI_FORCE;
8647 
8648 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8649 		return (UU_WALK_ERROR);
8650 
8651 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8652 	switch (r) {
8653 	case 0:
8654 		break;
8655 
8656 	case ENOMEM:
8657 	case ECONNABORTED:
8658 	case EPERM:
8659 	case -1:
8660 		warn(gettext("Unable to refresh \"%s\"\n"),
8661 		    dpt_pgroup->sc_pgroup_fmri);
8662 		return (UU_WALK_ERROR);
8663 
8664 	default:
8665 		bad_error("imp_refresh_fmri", r);
8666 	}
8667 
8668 	return (UU_WALK_NEXT);
8669 }
8670 
8671 /*
8672  * Returns
8673  *   0 - success
8674  *   -1 - lscf_import_instance_pgs() failed.
8675  */
8676 int
8677 lscf_bundle_apply(bundle_t *bndl, const char *file)
8678 {
8679 	pgroup_t *old_dpt;
8680 	entity_t *svc, *inst;
8681 	int annotation_set = 0;
8682 	int ret = 0;
8683 	int r = 0;
8684 
8685 	lscf_prep_hndl();
8686 
8687 	if ((ret = alloc_imp_globals()))
8688 		goto out;
8689 
8690 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8691 		scfdie();
8692 
8693 	/*
8694 	 * Set the strings to be used for the security audit annotation
8695 	 * event.
8696 	 */
8697 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8698 		annotation_set = 1;
8699 	} else {
8700 		switch (scf_error()) {
8701 		case SCF_ERROR_CONNECTION_BROKEN:
8702 			warn(gettext("Repository connection broken.\n"));
8703 			goto out;
8704 
8705 		case SCF_ERROR_INVALID_ARGUMENT:
8706 		case SCF_ERROR_NOT_BOUND:
8707 		case SCF_ERROR_NO_RESOURCES:
8708 		case SCF_ERROR_INTERNAL:
8709 			bad_error("_scf_set_annotation", scf_error());
8710 			/* NOTREACHED */
8711 
8712 		default:
8713 			/*
8714 			 * Do not abort apply operation because of
8715 			 * inability to create annotation audit event.
8716 			 */
8717 			warn(gettext("_scf_set_annotation() unexpectedly "
8718 			    "failed with return code of %d\n"), scf_error());
8719 			break;
8720 		}
8721 	}
8722 
8723 	for (svc = uu_list_first(bndl->sc_bundle_services);
8724 	    svc != NULL;
8725 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8726 		int refresh = 0;
8727 
8728 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8729 		    imp_svc) != 0) {
8730 			switch (scf_error()) {
8731 			case SCF_ERROR_NOT_FOUND:
8732 				if (g_verbose)
8733 					warn(gettext("Ignoring nonexistent "
8734 					    "service %s.\n"), svc->sc_name);
8735 				continue;
8736 
8737 			default:
8738 				scfdie();
8739 			}
8740 		}
8741 
8742 		/*
8743 		 * If there were missing types in the profile, then need to
8744 		 * attempt to find the types.
8745 		 */
8746 		if (svc->sc_miss_type) {
8747 			if (uu_list_numnodes(svc->sc_pgroups) &&
8748 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8749 			    svc, UU_DEFAULT) != 0) {
8750 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8751 					bad_error("uu_list_walk", uu_error());
8752 
8753 				ret = -1;
8754 				continue;
8755 			}
8756 
8757 			for (inst = uu_list_first(
8758 			    svc->sc_u.sc_service.sc_service_instances);
8759 			    inst != NULL;
8760 			    inst = uu_list_next(
8761 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8762 				/*
8763 				 * If the instance doesn't exist just
8764 				 * skip to the next instance and let the
8765 				 * import note the missing instance.
8766 				 */
8767 				if (scf_service_get_instance(imp_svc,
8768 				    inst->sc_name, imp_inst) != 0)
8769 					continue;
8770 
8771 				if (uu_list_walk(inst->sc_pgroups,
8772 				    find_current_pg_type, inst,
8773 				    UU_DEFAULT) != 0) {
8774 					if (uu_error() !=
8775 					    UU_ERROR_CALLBACK_FAILED)
8776 						bad_error("uu_list_walk",
8777 						    uu_error());
8778 
8779 					ret = -1;
8780 					inst->sc_miss_type = B_TRUE;
8781 				}
8782 			}
8783 		}
8784 
8785 		/*
8786 		 * if we have pgs in the profile, we need to refresh ALL
8787 		 * instances of the service
8788 		 */
8789 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8790 			refresh = 1;
8791 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8792 			    SCI_FORCE | SCI_KEEP);
8793 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8794 			case IMPORT_NEXT:
8795 				break;
8796 
8797 			case IMPORT_OUT:
8798 				goto out;
8799 
8800 			case IMPORT_BAD:
8801 			default:
8802 				bad_error("lscf_import_service_pgs", r);
8803 			}
8804 		}
8805 
8806 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8807 			uu_list_walk(svc->sc_dependents,
8808 			    lscf_dependent_apply, svc, UU_DEFAULT);
8809 		}
8810 
8811 		for (inst = uu_list_first(
8812 		    svc->sc_u.sc_service.sc_service_instances);
8813 		    inst != NULL;
8814 		    inst = uu_list_next(
8815 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8816 			/*
8817 			 * This instance still has missing types
8818 			 * so skip it.
8819 			 */
8820 			if (inst->sc_miss_type) {
8821 				if (g_verbose)
8822 					warn(gettext("Ignoring instance "
8823 					    "%s:%s with missing types\n"),
8824 					    inst->sc_parent->sc_name,
8825 					    inst->sc_name);
8826 
8827 				continue;
8828 			}
8829 
8830 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8831 			    imp_inst) != 0) {
8832 				switch (scf_error()) {
8833 				case SCF_ERROR_NOT_FOUND:
8834 					if (g_verbose)
8835 						warn(gettext("Ignoring "
8836 						    "nonexistant instance "
8837 						    "%s:%s.\n"),
8838 						    inst->sc_parent->sc_name,
8839 						    inst->sc_name);
8840 					continue;
8841 
8842 				default:
8843 					scfdie();
8844 				}
8845 			}
8846 
8847 			/*
8848 			 * If the instance does not have a general/enabled
8849 			 * property and no last-import snapshot then the
8850 			 * instance is not a fully installed instance and
8851 			 * should not have a profile applied to it.
8852 			 *
8853 			 * This could happen if a service/instance declares
8854 			 * a dependent on behalf of another service/instance.
8855 			 *
8856 			 */
8857 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8858 			    imp_snap) != 0) {
8859 				if (scf_instance_get_pg(imp_inst,
8860 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8861 				    scf_pg_get_property(imp_pg,
8862 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8863 					if (g_verbose)
8864 						warn(gettext("Ignoreing "
8865 						    "partial instance "
8866 						    "%s:%s.\n"),
8867 						    inst->sc_parent->sc_name,
8868 						    inst->sc_name);
8869 					continue;
8870 				}
8871 			}
8872 
8873 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8874 			    inst, SCI_FORCE | SCI_KEEP);
8875 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8876 			case IMPORT_NEXT:
8877 				break;
8878 
8879 			case IMPORT_OUT:
8880 				goto out;
8881 
8882 			case IMPORT_BAD:
8883 			default:
8884 				bad_error("lscf_import_instance_pgs", r);
8885 			}
8886 
8887 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8888 				uu_list_walk(inst->sc_dependents,
8889 				    lscf_dependent_apply, inst, UU_DEFAULT);
8890 			}
8891 
8892 			/* refresh only if there is no pgs in the service */
8893 			if (refresh == 0)
8894 				(void) refresh_entity(0, imp_inst,
8895 				    inst->sc_fmri, NULL, NULL, NULL);
8896 		}
8897 
8898 		if (refresh == 1) {
8899 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8900 
8901 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8902 			    imp_inst, imp_iter, name_buf);
8903 			free(name_buf);
8904 		}
8905 
8906 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8907 		    old_dpt != NULL;
8908 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8909 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8910 			    old_dpt->sc_pgroup_name,
8911 			    old_dpt->sc_parent->sc_fmri) != 0) {
8912 				warn(gettext("Unable to refresh \"%s\"\n"),
8913 				    old_dpt->sc_pgroup_fmri);
8914 			}
8915 		}
8916 	}
8917 
8918 out:
8919 	if (annotation_set) {
8920 		/* Remove security audit annotation strings. */
8921 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8922 	}
8923 
8924 	free_imp_globals();
8925 	return (ret);
8926 }
8927 
8928 
8929 /*
8930  * Export.  These functions create and output an XML tree of a service
8931  * description from the repository.  This is largely the inverse of
8932  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8933  *
8934  * - We must include any properties which are not represented specifically by
8935  *   a service manifest, e.g., properties created by an admin post-import.  To
8936  *   do so we'll iterate through all properties and deal with each
8937  *   apropriately.
8938  *
8939  * - Children of services and instances must must be in the order set by the
8940  *   DTD, but we iterate over the properties in undefined order.  The elements
8941  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8942  *   number of classes of them, however, we'll keep the classes separate and
8943  *   assemble them in order.
8944  */
8945 
8946 /*
8947  * Convenience function to handle xmlSetProp errors (and type casting).
8948  */
8949 static void
8950 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8951 {
8952 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8953 		uu_die(gettext("Could not set XML property.\n"));
8954 }
8955 
8956 /*
8957  * Convenience function to set an XML attribute to the single value of an
8958  * astring property.  If the value happens to be the default, don't set the
8959  * attribute.  "dval" should be the default value supplied by the DTD, or
8960  * NULL for no default.
8961  */
8962 static int
8963 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8964     const char *name, const char *dval)
8965 {
8966 	scf_value_t *val;
8967 	ssize_t len;
8968 	char *str;
8969 
8970 	val = scf_value_create(g_hndl);
8971 	if (val == NULL)
8972 		scfdie();
8973 
8974 	if (prop_get_val(prop, val) != 0) {
8975 		scf_value_destroy(val);
8976 		return (-1);
8977 	}
8978 
8979 	len = scf_value_get_as_string(val, NULL, 0);
8980 	if (len < 0)
8981 		scfdie();
8982 
8983 	str = safe_malloc(len + 1);
8984 
8985 	if (scf_value_get_as_string(val, str, len + 1) < 0)
8986 		scfdie();
8987 
8988 	scf_value_destroy(val);
8989 
8990 	if (dval == NULL || strcmp(str, dval) != 0)
8991 		safe_setprop(n, name, str);
8992 
8993 	free(str);
8994 
8995 	return (0);
8996 }
8997 
8998 /*
8999  * As above, but the attribute is always set.
9000  */
9001 static int
9002 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9003 {
9004 	return (set_attr_from_prop_default(prop, n, name, NULL));
9005 }
9006 
9007 /*
9008  * Dump the given document onto f, with "'s replaced by ''s.
9009  */
9010 static int
9011 write_service_bundle(xmlDocPtr doc, FILE *f)
9012 {
9013 	xmlChar *mem;
9014 	int sz, i;
9015 
9016 	mem = NULL;
9017 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9018 
9019 	if (mem == NULL) {
9020 		semerr(gettext("Could not dump XML tree.\n"));
9021 		return (-1);
9022 	}
9023 
9024 	/*
9025 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
9026 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9027 	 * &apos; code?!
9028 	 */
9029 	for (i = 0; i < sz; ++i) {
9030 		char c = (char)mem[i];
9031 
9032 		if (c == '"')
9033 			(void) fputc('\'', f);
9034 		else if (c == '\'')
9035 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9036 		else
9037 			(void) fputc(c, f);
9038 	}
9039 
9040 	return (0);
9041 }
9042 
9043 /*
9044  * Create the DOM elements in elts necessary to (generically) represent prop
9045  * (i.e., a property or propval element).  If the name of the property is
9046  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9047  */
9048 static void
9049 export_property(scf_property_t *prop, const char *name_arg,
9050     struct pg_elts *elts, int flags)
9051 {
9052 	const char *type;
9053 	scf_error_t err = 0;
9054 	xmlNodePtr pnode, lnode;
9055 	char *lnname;
9056 	int ret;
9057 
9058 	/* name */
9059 	if (name_arg != NULL) {
9060 		(void) strcpy(exp_str, name_arg);
9061 	} else {
9062 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9063 			scfdie();
9064 	}
9065 
9066 	/* type */
9067 	type = prop_to_typestr(prop);
9068 	if (type == NULL)
9069 		uu_die(gettext("Can't export property %s: unknown type.\n"),
9070 		    exp_str);
9071 
9072 	/* If we're exporting values, and there's just one, export it here. */
9073 	if (!(flags & SCE_ALL_VALUES))
9074 		goto empty;
9075 
9076 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9077 		xmlNodePtr n;
9078 
9079 		/* Single value, so use propval */
9080 		n = xmlNewNode(NULL, (xmlChar *)"propval");
9081 		if (n == NULL)
9082 			uu_die(emsg_create_xml);
9083 
9084 		safe_setprop(n, name_attr, exp_str);
9085 		safe_setprop(n, type_attr, type);
9086 
9087 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9088 			scfdie();
9089 		safe_setprop(n, value_attr, exp_str);
9090 
9091 		if (elts->propvals == NULL)
9092 			elts->propvals = n;
9093 		else
9094 			(void) xmlAddSibling(elts->propvals, n);
9095 
9096 		return;
9097 	}
9098 
9099 	err = scf_error();
9100 
9101 	if (err == SCF_ERROR_PERMISSION_DENIED) {
9102 		semerr(emsg_permission_denied);
9103 		return;
9104 	}
9105 
9106 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9107 	    err != SCF_ERROR_NOT_FOUND &&
9108 	    err != SCF_ERROR_PERMISSION_DENIED)
9109 		scfdie();
9110 
9111 empty:
9112 	/* Multiple (or no) values, so use property */
9113 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
9114 	if (pnode == NULL)
9115 		uu_die(emsg_create_xml);
9116 
9117 	safe_setprop(pnode, name_attr, exp_str);
9118 	safe_setprop(pnode, type_attr, type);
9119 
9120 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9121 		lnname = uu_msprintf("%s_list", type);
9122 		if (lnname == NULL)
9123 			uu_die(gettext("Could not create string"));
9124 
9125 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9126 		if (lnode == NULL)
9127 			uu_die(emsg_create_xml);
9128 
9129 		uu_free(lnname);
9130 
9131 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9132 			scfdie();
9133 
9134 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9135 		    1) {
9136 			xmlNodePtr vn;
9137 
9138 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9139 			    NULL);
9140 			if (vn == NULL)
9141 				uu_die(emsg_create_xml);
9142 
9143 			if (scf_value_get_as_string(exp_val, exp_str,
9144 			    exp_str_sz) < 0)
9145 				scfdie();
9146 			safe_setprop(vn, value_attr, exp_str);
9147 		}
9148 		if (ret != 0)
9149 			scfdie();
9150 	}
9151 
9152 	if (elts->properties == NULL)
9153 		elts->properties = pnode;
9154 	else
9155 		(void) xmlAddSibling(elts->properties, pnode);
9156 }
9157 
9158 /*
9159  * Add a property_group element for this property group to elts.
9160  */
9161 static void
9162 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9163 {
9164 	xmlNodePtr n;
9165 	struct pg_elts elts;
9166 	int ret;
9167 	boolean_t read_protected;
9168 
9169 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
9170 
9171 	/* name */
9172 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9173 		scfdie();
9174 	safe_setprop(n, name_attr, exp_str);
9175 
9176 	/* type */
9177 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9178 		scfdie();
9179 	safe_setprop(n, type_attr, exp_str);
9180 
9181 	/* properties */
9182 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9183 		scfdie();
9184 
9185 	(void) memset(&elts, 0, sizeof (elts));
9186 
9187 	/*
9188 	 * If this property group is not read protected, we always want to
9189 	 * output all the values.  Otherwise, we only output the values if the
9190 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9191 	 */
9192 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9193 		scfdie();
9194 
9195 	if (!read_protected)
9196 		flags |= SCE_ALL_VALUES;
9197 
9198 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9199 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9200 			scfdie();
9201 
9202 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9203 			xmlNodePtr m;
9204 
9205 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9206 			if (m == NULL)
9207 				uu_die(emsg_create_xml);
9208 
9209 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9210 				elts.stability = m;
9211 				continue;
9212 			}
9213 
9214 			xmlFreeNode(m);
9215 		}
9216 
9217 		export_property(exp_prop, NULL, &elts, flags);
9218 	}
9219 	if (ret == -1)
9220 		scfdie();
9221 
9222 	(void) xmlAddChild(n, elts.stability);
9223 	(void) xmlAddChildList(n, elts.propvals);
9224 	(void) xmlAddChildList(n, elts.properties);
9225 
9226 	if (eelts->property_groups == NULL)
9227 		eelts->property_groups = n;
9228 	else
9229 		(void) xmlAddSibling(eelts->property_groups, n);
9230 }
9231 
9232 /*
9233  * Create an XML node representing the dependency described by the given
9234  * property group and put it in eelts.  Unless the dependency is not valid, in
9235  * which case create a generic property_group element which represents it and
9236  * put it in eelts.
9237  */
9238 static void
9239 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9240 {
9241 	xmlNodePtr n;
9242 	int err = 0, ret;
9243 	struct pg_elts elts;
9244 
9245 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
9246 	if (n == NULL)
9247 		uu_die(emsg_create_xml);
9248 
9249 	/*
9250 	 * If the external flag is present, skip this dependency because it
9251 	 * should have been created by another manifest.
9252 	 */
9253 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9254 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9255 		    prop_get_val(exp_prop, exp_val) == 0) {
9256 			uint8_t b;
9257 
9258 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9259 				scfdie();
9260 
9261 			if (b)
9262 				return;
9263 		}
9264 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
9265 		scfdie();
9266 
9267 	/* Get the required attributes. */
9268 
9269 	/* name */
9270 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9271 		scfdie();
9272 	safe_setprop(n, name_attr, exp_str);
9273 
9274 	/* grouping */
9275 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9276 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9277 		err = 1;
9278 
9279 	/* restart_on */
9280 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9281 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9282 		err = 1;
9283 
9284 	/* type */
9285 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9286 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9287 		err = 1;
9288 
9289 	/*
9290 	 * entities: Not required, but if we create no children, it will be
9291 	 * created as empty on import, so fail if it's missing.
9292 	 */
9293 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9294 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9295 		scf_iter_t *eiter;
9296 		int ret2;
9297 
9298 		eiter = scf_iter_create(g_hndl);
9299 		if (eiter == NULL)
9300 			scfdie();
9301 
9302 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9303 			scfdie();
9304 
9305 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9306 			xmlNodePtr ch;
9307 
9308 			if (scf_value_get_astring(exp_val, exp_str,
9309 			    exp_str_sz) < 0)
9310 				scfdie();
9311 
9312 			/*
9313 			 * service_fmri's must be first, so we can add them
9314 			 * here.
9315 			 */
9316 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9317 			    NULL);
9318 			if (ch == NULL)
9319 				uu_die(emsg_create_xml);
9320 
9321 			safe_setprop(ch, value_attr, exp_str);
9322 		}
9323 		if (ret2 == -1)
9324 			scfdie();
9325 
9326 		scf_iter_destroy(eiter);
9327 	} else
9328 		err = 1;
9329 
9330 	if (err) {
9331 		xmlFreeNode(n);
9332 
9333 		export_pg(pg, eelts, SCE_ALL_VALUES);
9334 
9335 		return;
9336 	}
9337 
9338 	/* Iterate through the properties & handle each. */
9339 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9340 		scfdie();
9341 
9342 	(void) memset(&elts, 0, sizeof (elts));
9343 
9344 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9345 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9346 			scfdie();
9347 
9348 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9349 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9350 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9351 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9352 			continue;
9353 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9354 			xmlNodePtr m;
9355 
9356 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9357 			if (m == NULL)
9358 				uu_die(emsg_create_xml);
9359 
9360 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9361 				elts.stability = m;
9362 				continue;
9363 			}
9364 
9365 			xmlFreeNode(m);
9366 		}
9367 
9368 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9369 	}
9370 	if (ret == -1)
9371 		scfdie();
9372 
9373 	(void) xmlAddChild(n, elts.stability);
9374 	(void) xmlAddChildList(n, elts.propvals);
9375 	(void) xmlAddChildList(n, elts.properties);
9376 
9377 	if (eelts->dependencies == NULL)
9378 		eelts->dependencies = n;
9379 	else
9380 		(void) xmlAddSibling(eelts->dependencies, n);
9381 }
9382 
9383 static xmlNodePtr
9384 export_method_environment(scf_propertygroup_t *pg)
9385 {
9386 	xmlNodePtr env;
9387 	int ret;
9388 	int children = 0;
9389 
9390 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9391 		return (NULL);
9392 
9393 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9394 	if (env == NULL)
9395 		uu_die(emsg_create_xml);
9396 
9397 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9398 		scfdie();
9399 
9400 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9401 		scfdie();
9402 
9403 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9404 		xmlNodePtr ev;
9405 		char *cp;
9406 
9407 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9408 			scfdie();
9409 
9410 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9411 			warn(gettext("Invalid environment variable \"%s\".\n"),
9412 			    exp_str);
9413 			continue;
9414 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9415 			warn(gettext("Invalid environment variable \"%s\"; "
9416 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9417 			continue;
9418 		}
9419 
9420 		*cp = '\0';
9421 		cp++;
9422 
9423 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9424 		if (ev == NULL)
9425 			uu_die(emsg_create_xml);
9426 
9427 		safe_setprop(ev, name_attr, exp_str);
9428 		safe_setprop(ev, value_attr, cp);
9429 		children++;
9430 	}
9431 
9432 	if (ret != 0)
9433 		scfdie();
9434 
9435 	if (children == 0) {
9436 		xmlFreeNode(env);
9437 		return (NULL);
9438 	}
9439 
9440 	return (env);
9441 }
9442 
9443 /*
9444  * As above, but for a method property group.
9445  */
9446 static void
9447 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9448 {
9449 	xmlNodePtr n, env;
9450 	char *str;
9451 	int err = 0, nonenv, ret;
9452 	uint8_t use_profile;
9453 	struct pg_elts elts;
9454 	xmlNodePtr ctxt = NULL;
9455 
9456 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9457 
9458 	/* Get the required attributes. */
9459 
9460 	/* name */
9461 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9462 		scfdie();
9463 	safe_setprop(n, name_attr, exp_str);
9464 
9465 	/* type */
9466 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9467 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9468 		err = 1;
9469 
9470 	/* exec */
9471 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9472 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9473 		err = 1;
9474 
9475 	/* timeout */
9476 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9477 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9478 	    prop_get_val(exp_prop, exp_val) == 0) {
9479 		uint64_t c;
9480 
9481 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9482 			scfdie();
9483 
9484 		str = uu_msprintf("%llu", c);
9485 		if (str == NULL)
9486 			uu_die(gettext("Could not create string"));
9487 
9488 		safe_setprop(n, "timeout_seconds", str);
9489 		free(str);
9490 	} else
9491 		err = 1;
9492 
9493 	if (err) {
9494 		xmlFreeNode(n);
9495 
9496 		export_pg(pg, eelts, SCE_ALL_VALUES);
9497 
9498 		return;
9499 	}
9500 
9501 
9502 	/*
9503 	 * If we're going to have a method_context child, we need to know
9504 	 * before we iterate through the properties.  Since method_context's
9505 	 * are optional, we don't want to complain about any properties
9506 	 * missing if none of them are there.  Thus we can't use the
9507 	 * convenience functions.
9508 	 */
9509 	nonenv =
9510 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9511 	    SCF_SUCCESS ||
9512 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9513 	    SCF_SUCCESS ||
9514 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9515 	    SCF_SUCCESS ||
9516 	    scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9517 	    SCF_SUCCESS ||
9518 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9519 	    SCF_SUCCESS;
9520 
9521 	if (nonenv) {
9522 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9523 		if (ctxt == NULL)
9524 			uu_die(emsg_create_xml);
9525 
9526 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9527 		    0 &&
9528 		    set_attr_from_prop_default(exp_prop, ctxt,
9529 		    "working_directory", ":default") != 0)
9530 			err = 1;
9531 
9532 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9533 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9534 		    ":default") != 0)
9535 			err = 1;
9536 
9537 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9538 		    0 &&
9539 		    set_attr_from_prop_default(exp_prop, ctxt,
9540 		    "resource_pool", ":default") != 0)
9541 			err = 1;
9542 
9543 		if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9544 		    set_attr_from_prop_default(exp_prop, ctxt,
9545 		    "security_flags", ":default") != 0)
9546 			err = 1;
9547 
9548 		/*
9549 		 * We only want to complain about profile or credential
9550 		 * properties if we will use them.  To determine that we must
9551 		 * examine USE_PROFILE.
9552 		 */
9553 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9554 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9555 		    prop_get_val(exp_prop, exp_val) == 0) {
9556 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9557 			    SCF_SUCCESS) {
9558 				scfdie();
9559 			}
9560 
9561 			if (use_profile) {
9562 				xmlNodePtr prof;
9563 
9564 				prof = xmlNewChild(ctxt, NULL,
9565 				    (xmlChar *)"method_profile", NULL);
9566 				if (prof == NULL)
9567 					uu_die(emsg_create_xml);
9568 
9569 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9570 				    exp_prop) != 0 ||
9571 				    set_attr_from_prop(exp_prop, prof,
9572 				    name_attr) != 0)
9573 					err = 1;
9574 			} else {
9575 				xmlNodePtr cred;
9576 
9577 				cred = xmlNewChild(ctxt, NULL,
9578 				    (xmlChar *)"method_credential", NULL);
9579 				if (cred == NULL)
9580 					uu_die(emsg_create_xml);
9581 
9582 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9583 				    exp_prop) != 0 ||
9584 				    set_attr_from_prop(exp_prop, cred,
9585 				    "user") != 0) {
9586 					err = 1;
9587 				}
9588 
9589 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9590 				    exp_prop) == 0 &&
9591 				    set_attr_from_prop_default(exp_prop, cred,
9592 				    "group", ":default") != 0)
9593 					err = 1;
9594 
9595 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9596 				    exp_prop) == 0 &&
9597 				    set_attr_from_prop_default(exp_prop, cred,
9598 				    "supp_groups", ":default") != 0)
9599 					err = 1;
9600 
9601 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9602 				    exp_prop) == 0 &&
9603 				    set_attr_from_prop_default(exp_prop, cred,
9604 				    "privileges", ":default") != 0)
9605 					err = 1;
9606 
9607 				if (pg_get_prop(pg,
9608 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9609 				    exp_prop) == 0 &&
9610 				    set_attr_from_prop_default(exp_prop, cred,
9611 				    "limit_privileges", ":default") != 0)
9612 					err = 1;
9613 			}
9614 		}
9615 	}
9616 
9617 	if ((env = export_method_environment(pg)) != NULL) {
9618 		if (ctxt == NULL) {
9619 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9620 			if (ctxt == NULL)
9621 				uu_die(emsg_create_xml);
9622 		}
9623 		(void) xmlAddChild(ctxt, env);
9624 	}
9625 
9626 	if (env != NULL || (nonenv && err == 0))
9627 		(void) xmlAddChild(n, ctxt);
9628 	else
9629 		xmlFreeNode(ctxt);
9630 
9631 	nonenv = (err == 0);
9632 
9633 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9634 		scfdie();
9635 
9636 	(void) memset(&elts, 0, sizeof (elts));
9637 
9638 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9639 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9640 			scfdie();
9641 
9642 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9643 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9644 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9645 			continue;
9646 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9647 			xmlNodePtr m;
9648 
9649 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9650 			if (m == NULL)
9651 				uu_die(emsg_create_xml);
9652 
9653 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9654 				elts.stability = m;
9655 				continue;
9656 			}
9657 
9658 			xmlFreeNode(m);
9659 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9660 		    0 ||
9661 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9662 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9663 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9664 			if (nonenv)
9665 				continue;
9666 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9667 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9668 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9669 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9670 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9671 		    strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9672 			if (nonenv && !use_profile)
9673 				continue;
9674 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9675 			if (nonenv && use_profile)
9676 				continue;
9677 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9678 			if (env != NULL)
9679 				continue;
9680 		}
9681 
9682 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9683 	}
9684 	if (ret == -1)
9685 		scfdie();
9686 
9687 	(void) xmlAddChild(n, elts.stability);
9688 	(void) xmlAddChildList(n, elts.propvals);
9689 	(void) xmlAddChildList(n, elts.properties);
9690 
9691 	if (eelts->exec_methods == NULL)
9692 		eelts->exec_methods = n;
9693 	else
9694 		(void) xmlAddSibling(eelts->exec_methods, n);
9695 }
9696 
9697 static void
9698 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9699     struct entity_elts *eelts)
9700 {
9701 	xmlNodePtr pgnode;
9702 
9703 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9704 	if (pgnode == NULL)
9705 		uu_die(emsg_create_xml);
9706 
9707 	safe_setprop(pgnode, name_attr, name);
9708 	safe_setprop(pgnode, type_attr, type);
9709 
9710 	(void) xmlAddChildList(pgnode, elts->propvals);
9711 	(void) xmlAddChildList(pgnode, elts->properties);
9712 
9713 	if (eelts->property_groups == NULL)
9714 		eelts->property_groups = pgnode;
9715 	else
9716 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9717 }
9718 
9719 /*
9720  * Process the general property group for a service.  This is the one with the
9721  * goodies.
9722  */
9723 static void
9724 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9725 {
9726 	struct pg_elts elts;
9727 	int ret;
9728 
9729 	/*
9730 	 * In case there are properties which don't correspond to child
9731 	 * entities of the service entity, we'll set up a pg_elts structure to
9732 	 * put them in.
9733 	 */
9734 	(void) memset(&elts, 0, sizeof (elts));
9735 
9736 	/* Walk the properties, looking for special ones. */
9737 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9738 		scfdie();
9739 
9740 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9741 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9742 			scfdie();
9743 
9744 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9745 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9746 			    prop_get_val(exp_prop, exp_val) == 0) {
9747 				uint8_t b;
9748 
9749 				if (scf_value_get_boolean(exp_val, &b) !=
9750 				    SCF_SUCCESS)
9751 					scfdie();
9752 
9753 				if (b) {
9754 					selts->single_instance =
9755 					    xmlNewNode(NULL,
9756 					    (xmlChar *)"single_instance");
9757 					if (selts->single_instance == NULL)
9758 						uu_die(emsg_create_xml);
9759 				}
9760 
9761 				continue;
9762 			}
9763 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9764 			xmlNodePtr rnode, sfnode;
9765 
9766 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9767 			if (rnode == NULL)
9768 				uu_die(emsg_create_xml);
9769 
9770 			sfnode = xmlNewChild(rnode, NULL,
9771 			    (xmlChar *)"service_fmri", NULL);
9772 			if (sfnode == NULL)
9773 				uu_die(emsg_create_xml);
9774 
9775 			if (set_attr_from_prop(exp_prop, sfnode,
9776 			    value_attr) == 0) {
9777 				selts->restarter = rnode;
9778 				continue;
9779 			}
9780 
9781 			xmlFreeNode(rnode);
9782 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9783 		    0) {
9784 			xmlNodePtr s;
9785 
9786 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9787 			if (s == NULL)
9788 				uu_die(emsg_create_xml);
9789 
9790 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9791 				selts->stability = s;
9792 				continue;
9793 			}
9794 
9795 			xmlFreeNode(s);
9796 		}
9797 
9798 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9799 	}
9800 	if (ret == -1)
9801 		scfdie();
9802 
9803 	if (elts.propvals != NULL || elts.properties != NULL)
9804 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9805 		    selts);
9806 }
9807 
9808 static void
9809 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9810 {
9811 	xmlNodePtr n, prof, cred, env;
9812 	uint8_t use_profile;
9813 	int ret, err = 0;
9814 
9815 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9816 
9817 	env = export_method_environment(pg);
9818 
9819 	/* Need to know whether we'll use a profile or not. */
9820 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9821 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9822 	    prop_get_val(exp_prop, exp_val) == 0) {
9823 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9824 			scfdie();
9825 
9826 		if (use_profile)
9827 			prof =
9828 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9829 			    NULL);
9830 		else
9831 			cred =
9832 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9833 			    NULL);
9834 	}
9835 
9836 	if (env != NULL)
9837 		(void) xmlAddChild(n, env);
9838 
9839 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9840 		scfdie();
9841 
9842 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9843 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9844 			scfdie();
9845 
9846 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9847 			if (set_attr_from_prop(exp_prop, n,
9848 			    "working_directory") != 0)
9849 				err = 1;
9850 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9851 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9852 				err = 1;
9853 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9854 			if (set_attr_from_prop(exp_prop, n,
9855 			    "resource_pool") != 0)
9856 				err = 1;
9857 		} else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9858 			if (set_attr_from_prop(exp_prop, n,
9859 			    "security_flags") != 0)
9860 				err = 1;
9861 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9862 			/* EMPTY */
9863 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9864 			if (use_profile ||
9865 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9866 				err = 1;
9867 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9868 			if (use_profile ||
9869 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9870 				err = 1;
9871 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9872 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9873 			    "supp_groups") != 0)
9874 				err = 1;
9875 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9876 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9877 			    "privileges") != 0)
9878 				err = 1;
9879 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9880 		    0) {
9881 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9882 			    "limit_privileges") != 0)
9883 				err = 1;
9884 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9885 			if (!use_profile || set_attr_from_prop(exp_prop,
9886 			    prof, name_attr) != 0)
9887 				err = 1;
9888 		} else {
9889 			/* Can't have generic properties in method_context's */
9890 			err = 1;
9891 		}
9892 	}
9893 	if (ret == -1)
9894 		scfdie();
9895 
9896 	if (err && env == NULL) {
9897 		xmlFreeNode(n);
9898 		export_pg(pg, elts, SCE_ALL_VALUES);
9899 		return;
9900 	}
9901 
9902 	elts->method_context = n;
9903 }
9904 
9905 /*
9906  * Given a dependency property group in the tfmri entity (target fmri), return
9907  * a dependent element which represents it.
9908  */
9909 static xmlNodePtr
9910 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9911 {
9912 	uint8_t b;
9913 	xmlNodePtr n, sf;
9914 	int err = 0, ret;
9915 	struct pg_elts pgelts;
9916 
9917 	/*
9918 	 * If external isn't set to true then exporting the service will
9919 	 * export this as a normal dependency, so we should stop to avoid
9920 	 * duplication.
9921 	 */
9922 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9923 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9924 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9925 		if (g_verbose) {
9926 			warn(gettext("Dependent \"%s\" cannot be exported "
9927 			    "properly because the \"%s\" property of the "
9928 			    "\"%s\" dependency of %s is not set to true.\n"),
9929 			    name, scf_property_external, name, tfmri);
9930 		}
9931 
9932 		return (NULL);
9933 	}
9934 
9935 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9936 	if (n == NULL)
9937 		uu_die(emsg_create_xml);
9938 
9939 	safe_setprop(n, name_attr, name);
9940 
9941 	/* Get the required attributes */
9942 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9943 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9944 		err = 1;
9945 
9946 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9947 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9948 		err = 1;
9949 
9950 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9951 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9952 	    prop_get_val(exp_prop, exp_val) == 0) {
9953 		/* EMPTY */
9954 	} else
9955 		err = 1;
9956 
9957 	if (err) {
9958 		xmlFreeNode(n);
9959 		return (NULL);
9960 	}
9961 
9962 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9963 	if (sf == NULL)
9964 		uu_die(emsg_create_xml);
9965 
9966 	safe_setprop(sf, value_attr, tfmri);
9967 
9968 	/*
9969 	 * Now add elements for the other properties.
9970 	 */
9971 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9972 		scfdie();
9973 
9974 	(void) memset(&pgelts, 0, sizeof (pgelts));
9975 
9976 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9977 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9978 			scfdie();
9979 
9980 		if (strcmp(exp_str, scf_property_external) == 0 ||
9981 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9982 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9983 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9984 			continue;
9985 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9986 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9987 			    prop_get_val(exp_prop, exp_val) == 0) {
9988 				char type[sizeof ("service") + 1];
9989 
9990 				if (scf_value_get_astring(exp_val, type,
9991 				    sizeof (type)) < 0)
9992 					scfdie();
9993 
9994 				if (strcmp(type, "service") == 0)
9995 					continue;
9996 			}
9997 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9998 			xmlNodePtr s;
9999 
10000 			s = xmlNewNode(NULL, (xmlChar *)"stability");
10001 			if (s == NULL)
10002 				uu_die(emsg_create_xml);
10003 
10004 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10005 				pgelts.stability = s;
10006 				continue;
10007 			}
10008 
10009 			xmlFreeNode(s);
10010 		}
10011 
10012 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10013 	}
10014 	if (ret == -1)
10015 		scfdie();
10016 
10017 	(void) xmlAddChild(n, pgelts.stability);
10018 	(void) xmlAddChildList(n, pgelts.propvals);
10019 	(void) xmlAddChildList(n, pgelts.properties);
10020 
10021 	return (n);
10022 }
10023 
10024 static void
10025 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10026 {
10027 	scf_propertygroup_t *opg;
10028 	scf_iter_t *iter;
10029 	char *type, *fmri;
10030 	int ret;
10031 	struct pg_elts pgelts;
10032 	xmlNodePtr n;
10033 	scf_error_t serr;
10034 
10035 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
10036 	    (iter = scf_iter_create(g_hndl)) == NULL)
10037 		scfdie();
10038 
10039 	/* Can't use exp_prop_iter due to export_dependent(). */
10040 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10041 		scfdie();
10042 
10043 	type = safe_malloc(max_scf_pg_type_len + 1);
10044 
10045 	/* Get an extra byte so we can tell if values are too long. */
10046 	fmri = safe_malloc(max_scf_fmri_len + 2);
10047 
10048 	(void) memset(&pgelts, 0, sizeof (pgelts));
10049 
10050 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10051 		void *entity;
10052 		int isservice;
10053 		scf_type_t ty;
10054 
10055 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10056 			scfdie();
10057 
10058 		if ((ty != SCF_TYPE_ASTRING &&
10059 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10060 		    prop_get_val(exp_prop, exp_val) != 0) {
10061 			export_property(exp_prop, NULL, &pgelts,
10062 			    SCE_ALL_VALUES);
10063 			continue;
10064 		}
10065 
10066 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10067 			scfdie();
10068 
10069 		if (scf_value_get_astring(exp_val, fmri,
10070 		    max_scf_fmri_len + 2) < 0)
10071 			scfdie();
10072 
10073 		/* Look for a dependency group in the target fmri. */
10074 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10075 		switch (serr) {
10076 		case SCF_ERROR_NONE:
10077 			break;
10078 
10079 		case SCF_ERROR_NO_MEMORY:
10080 			uu_die(gettext("Out of memory.\n"));
10081 			/* NOTREACHED */
10082 
10083 		case SCF_ERROR_INVALID_ARGUMENT:
10084 			if (g_verbose) {
10085 				if (scf_property_to_fmri(exp_prop, fmri,
10086 				    max_scf_fmri_len + 2) < 0)
10087 					scfdie();
10088 
10089 				warn(gettext("The value of %s is not a valid "
10090 				    "FMRI.\n"), fmri);
10091 			}
10092 
10093 			export_property(exp_prop, exp_str, &pgelts,
10094 			    SCE_ALL_VALUES);
10095 			continue;
10096 
10097 		case SCF_ERROR_CONSTRAINT_VIOLATED:
10098 			if (g_verbose) {
10099 				if (scf_property_to_fmri(exp_prop, fmri,
10100 				    max_scf_fmri_len + 2) < 0)
10101 					scfdie();
10102 
10103 				warn(gettext("The value of %s does not specify "
10104 				    "a service or an instance.\n"), fmri);
10105 			}
10106 
10107 			export_property(exp_prop, exp_str, &pgelts,
10108 			    SCE_ALL_VALUES);
10109 			continue;
10110 
10111 		case SCF_ERROR_NOT_FOUND:
10112 			if (g_verbose) {
10113 				if (scf_property_to_fmri(exp_prop, fmri,
10114 				    max_scf_fmri_len + 2) < 0)
10115 					scfdie();
10116 
10117 				warn(gettext("The entity specified by %s does "
10118 				    "not exist.\n"), fmri);
10119 			}
10120 
10121 			export_property(exp_prop, exp_str, &pgelts,
10122 			    SCE_ALL_VALUES);
10123 			continue;
10124 
10125 		default:
10126 #ifndef NDEBUG
10127 			(void) fprintf(stderr, "%s:%d: %s() failed with "
10128 			    "unexpected error %d.\n", __FILE__, __LINE__,
10129 			    "fmri_to_entity", serr);
10130 #endif
10131 			abort();
10132 		}
10133 
10134 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10135 			if (scf_error() != SCF_ERROR_NOT_FOUND)
10136 				scfdie();
10137 
10138 			warn(gettext("Entity %s is missing dependency property "
10139 			    "group %s.\n"), fmri, exp_str);
10140 
10141 			export_property(exp_prop, NULL, &pgelts,
10142 			    SCE_ALL_VALUES);
10143 			continue;
10144 		}
10145 
10146 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10147 			scfdie();
10148 
10149 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10150 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10151 				scfdie();
10152 
10153 			warn(gettext("Property group %s is not of "
10154 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10155 
10156 			export_property(exp_prop, NULL, &pgelts,
10157 			    SCE_ALL_VALUES);
10158 			continue;
10159 		}
10160 
10161 		n = export_dependent(opg, exp_str, fmri);
10162 		if (n == NULL) {
10163 			export_property(exp_prop, exp_str, &pgelts,
10164 			    SCE_ALL_VALUES);
10165 		} else {
10166 			if (eelts->dependents == NULL)
10167 				eelts->dependents = n;
10168 			else
10169 				(void) xmlAddSibling(eelts->dependents,
10170 				    n);
10171 		}
10172 	}
10173 	if (ret == -1)
10174 		scfdie();
10175 
10176 	free(fmri);
10177 	free(type);
10178 
10179 	scf_iter_destroy(iter);
10180 	scf_pg_destroy(opg);
10181 
10182 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10183 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10184 		    eelts);
10185 }
10186 
10187 static void
10188 make_node(xmlNodePtr *nodep, const char *name)
10189 {
10190 	if (*nodep == NULL) {
10191 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
10192 		if (*nodep == NULL)
10193 			uu_die(emsg_create_xml);
10194 	}
10195 }
10196 
10197 static xmlNodePtr
10198 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10199 {
10200 	int ret;
10201 	xmlNodePtr parent = NULL;
10202 	xmlNodePtr loctext = NULL;
10203 
10204 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10205 		scfdie();
10206 
10207 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10208 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10209 		    prop_get_val(exp_prop, exp_val) != 0)
10210 			continue;
10211 
10212 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10213 			scfdie();
10214 
10215 		make_node(&parent, parname);
10216 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10217 		    (xmlChar *)exp_str);
10218 		if (loctext == NULL)
10219 			uu_die(emsg_create_xml);
10220 
10221 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10222 			scfdie();
10223 
10224 		safe_setprop(loctext, "xml:lang", exp_str);
10225 	}
10226 
10227 	if (ret == -1)
10228 		scfdie();
10229 
10230 	return (parent);
10231 }
10232 
10233 static xmlNodePtr
10234 export_tm_manpage(scf_propertygroup_t *pg)
10235 {
10236 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10237 	if (manpage == NULL)
10238 		uu_die(emsg_create_xml);
10239 
10240 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10241 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10242 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10243 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10244 		xmlFreeNode(manpage);
10245 		return (NULL);
10246 	}
10247 
10248 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10249 		(void) set_attr_from_prop_default(exp_prop,
10250 		    manpage, "manpath", ":default");
10251 
10252 	return (manpage);
10253 }
10254 
10255 static xmlNodePtr
10256 export_tm_doc_link(scf_propertygroup_t *pg)
10257 {
10258 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10259 	if (doc_link == NULL)
10260 		uu_die(emsg_create_xml);
10261 
10262 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10263 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10264 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10265 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10266 		xmlFreeNode(doc_link);
10267 		return (NULL);
10268 	}
10269 	return (doc_link);
10270 }
10271 
10272 /*
10273  * Process template information for a service or instances.
10274  */
10275 static void
10276 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10277     struct template_elts *telts)
10278 {
10279 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10280 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10281 	xmlNodePtr child = NULL;
10282 
10283 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10284 		scfdie();
10285 
10286 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10287 		telts->common_name = export_tm_loctext(pg, "common_name");
10288 		if (telts->common_name == NULL)
10289 			export_pg(pg, elts, SCE_ALL_VALUES);
10290 		return;
10291 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10292 		telts->description = export_tm_loctext(pg, "description");
10293 		if (telts->description == NULL)
10294 			export_pg(pg, elts, SCE_ALL_VALUES);
10295 		return;
10296 	}
10297 
10298 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10299 		child = export_tm_manpage(pg);
10300 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10301 		child = export_tm_doc_link(pg);
10302 	}
10303 
10304 	if (child != NULL) {
10305 		make_node(&telts->documentation, "documentation");
10306 		(void) xmlAddChild(telts->documentation, child);
10307 	} else {
10308 		export_pg(pg, elts, SCE_ALL_VALUES);
10309 	}
10310 }
10311 
10312 /*
10313  * Process parameter and paramval elements
10314  */
10315 static void
10316 export_parameter(scf_property_t *prop, const char *name,
10317     struct params_elts *elts)
10318 {
10319 	xmlNodePtr param;
10320 	scf_error_t err = 0;
10321 	int ret;
10322 
10323 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10324 		if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10325 			uu_die(emsg_create_xml);
10326 
10327 		safe_setprop(param, name_attr, name);
10328 
10329 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10330 			scfdie();
10331 		safe_setprop(param, value_attr, exp_str);
10332 
10333 		if (elts->paramval == NULL)
10334 			elts->paramval = param;
10335 		else
10336 			(void) xmlAddSibling(elts->paramval, param);
10337 
10338 		return;
10339 	}
10340 
10341 	err = scf_error();
10342 
10343 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10344 	    err != SCF_ERROR_NOT_FOUND)
10345 		scfdie();
10346 
10347 	if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10348 		uu_die(emsg_create_xml);
10349 
10350 	safe_setprop(param, name_attr, name);
10351 
10352 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10353 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10354 			scfdie();
10355 
10356 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10357 		    1) {
10358 			xmlNodePtr vn;
10359 
10360 			if ((vn = xmlNewChild(param, NULL,
10361 			    (xmlChar *)"value_node", NULL)) == NULL)
10362 				uu_die(emsg_create_xml);
10363 
10364 			if (scf_value_get_as_string(exp_val, exp_str,
10365 			    exp_str_sz) < 0)
10366 				scfdie();
10367 
10368 			safe_setprop(vn, value_attr, exp_str);
10369 		}
10370 		if (ret != 0)
10371 			scfdie();
10372 	}
10373 
10374 	if (elts->parameter == NULL)
10375 		elts->parameter = param;
10376 	else
10377 		(void) xmlAddSibling(elts->parameter, param);
10378 }
10379 
10380 /*
10381  * Process notification parameters for a service or instance
10382  */
10383 static void
10384 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10385 {
10386 	xmlNodePtr n, event, *type;
10387 	struct params_elts *eelts;
10388 	int ret, err, i;
10389 	char *s;
10390 
10391 	n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10392 	event = xmlNewNode(NULL, (xmlChar *)"event");
10393 	if (n == NULL || event == NULL)
10394 		uu_die(emsg_create_xml);
10395 
10396 	/* event value */
10397 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10398 		scfdie();
10399 	/* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10400 	if ((s = strchr(exp_str, ',')) != NULL)
10401 		*s = '\0';
10402 	safe_setprop(event, value_attr, exp_str);
10403 
10404 	(void) xmlAddChild(n, event);
10405 
10406 	if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10407 	    (eelts = calloc(URI_SCHEME_NUM,
10408 	    sizeof (struct params_elts))) == NULL)
10409 		uu_die(gettext("Out of memory.\n"));
10410 
10411 	err = 0;
10412 
10413 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10414 		scfdie();
10415 
10416 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10417 		char *t, *p;
10418 
10419 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10420 			scfdie();
10421 
10422 		if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10423 			/*
10424 			 * this is not a well formed notification parameters
10425 			 * element, we should export as regular pg
10426 			 */
10427 			err = 1;
10428 			break;
10429 		}
10430 
10431 		if ((i = check_uri_protocol(t)) < 0) {
10432 			err = 1;
10433 			break;
10434 		}
10435 
10436 		if (type[i] == NULL) {
10437 			if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10438 			    NULL)
10439 				uu_die(emsg_create_xml);
10440 
10441 			safe_setprop(type[i], name_attr, t);
10442 		}
10443 		if (strcmp(p, active_attr) == 0) {
10444 			if (set_attr_from_prop(exp_prop, type[i],
10445 			    active_attr) != 0) {
10446 				err = 1;
10447 				break;
10448 			}
10449 			continue;
10450 		}
10451 		/*
10452 		 * We export the parameter
10453 		 */
10454 		export_parameter(exp_prop, p, &eelts[i]);
10455 	}
10456 
10457 	if (ret == -1)
10458 		scfdie();
10459 
10460 	if (err == 1) {
10461 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10462 			xmlFree(type[i]);
10463 		free(type);
10464 
10465 		export_pg(pg, elts, SCE_ALL_VALUES);
10466 
10467 		return;
10468 	} else {
10469 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10470 			if (type[i] != NULL) {
10471 				(void) xmlAddChildList(type[i],
10472 				    eelts[i].paramval);
10473 				(void) xmlAddChildList(type[i],
10474 				    eelts[i].parameter);
10475 				(void) xmlAddSibling(event, type[i]);
10476 			}
10477 	}
10478 	free(type);
10479 
10480 	if (elts->notify_params == NULL)
10481 		elts->notify_params = n;
10482 	else
10483 		(void) xmlAddSibling(elts->notify_params, n);
10484 }
10485 
10486 /*
10487  * Process the general property group for an instance.
10488  */
10489 static void
10490 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10491     struct entity_elts *elts)
10492 {
10493 	uint8_t enabled;
10494 	struct pg_elts pgelts;
10495 	int ret;
10496 
10497 	/* enabled */
10498 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10499 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10500 	    prop_get_val(exp_prop, exp_val) == 0) {
10501 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10502 			scfdie();
10503 	} else {
10504 		enabled = 0;
10505 	}
10506 
10507 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10508 
10509 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10510 		scfdie();
10511 
10512 	(void) memset(&pgelts, 0, sizeof (pgelts));
10513 
10514 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10515 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10516 			scfdie();
10517 
10518 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10519 			continue;
10520 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10521 			xmlNodePtr rnode, sfnode;
10522 
10523 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10524 			if (rnode == NULL)
10525 				uu_die(emsg_create_xml);
10526 
10527 			sfnode = xmlNewChild(rnode, NULL,
10528 			    (xmlChar *)"service_fmri", NULL);
10529 			if (sfnode == NULL)
10530 				uu_die(emsg_create_xml);
10531 
10532 			if (set_attr_from_prop(exp_prop, sfnode,
10533 			    value_attr) == 0) {
10534 				elts->restarter = rnode;
10535 				continue;
10536 			}
10537 
10538 			xmlFreeNode(rnode);
10539 		}
10540 
10541 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10542 	}
10543 	if (ret == -1)
10544 		scfdie();
10545 
10546 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10547 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10548 		    elts);
10549 }
10550 
10551 /*
10552  * Put an instance element for the given instance into selts.
10553  */
10554 static void
10555 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10556 {
10557 	xmlNodePtr n;
10558 	boolean_t isdefault;
10559 	struct entity_elts elts;
10560 	struct template_elts template_elts;
10561 	int ret;
10562 
10563 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10564 	if (n == NULL)
10565 		uu_die(emsg_create_xml);
10566 
10567 	/* name */
10568 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10569 		scfdie();
10570 	safe_setprop(n, name_attr, exp_str);
10571 	isdefault = strcmp(exp_str, "default") == 0;
10572 
10573 	/* check existance of general pg (since general/enabled is required) */
10574 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10575 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10576 			scfdie();
10577 
10578 		if (g_verbose) {
10579 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10580 				scfdie();
10581 
10582 			warn(gettext("Instance %s has no general property "
10583 			    "group; it will be marked disabled.\n"), exp_str);
10584 		}
10585 
10586 		safe_setprop(n, enabled_attr, false);
10587 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10588 	    strcmp(exp_str, scf_group_framework) != 0) {
10589 		if (g_verbose) {
10590 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10591 				scfdie();
10592 
10593 			warn(gettext("Property group %s is not of type "
10594 			    "framework; the instance will be marked "
10595 			    "disabled.\n"), exp_str);
10596 		}
10597 
10598 		safe_setprop(n, enabled_attr, false);
10599 	}
10600 
10601 	/* property groups */
10602 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10603 		scfdie();
10604 
10605 	(void) memset(&elts, 0, sizeof (elts));
10606 	(void) memset(&template_elts, 0, sizeof (template_elts));
10607 
10608 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10609 		uint32_t pgflags;
10610 
10611 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10612 			scfdie();
10613 
10614 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10615 			continue;
10616 
10617 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10618 			scfdie();
10619 
10620 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10621 			export_dependency(exp_pg, &elts);
10622 			continue;
10623 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10624 			export_method(exp_pg, &elts);
10625 			continue;
10626 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10627 			if (scf_pg_get_name(exp_pg, exp_str,
10628 			    max_scf_name_len + 1) < 0)
10629 				scfdie();
10630 
10631 			if (strcmp(exp_str, scf_pg_general) == 0) {
10632 				export_inst_general(exp_pg, n, &elts);
10633 				continue;
10634 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10635 			    0) {
10636 				export_method_context(exp_pg, &elts);
10637 				continue;
10638 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10639 				export_dependents(exp_pg, &elts);
10640 				continue;
10641 			}
10642 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10643 			export_template(exp_pg, &elts, &template_elts);
10644 			continue;
10645 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10646 			export_notify_params(exp_pg, &elts);
10647 			continue;
10648 		}
10649 
10650 		/* Ordinary pg. */
10651 		export_pg(exp_pg, &elts, flags);
10652 	}
10653 	if (ret == -1)
10654 		scfdie();
10655 
10656 	if (template_elts.common_name != NULL) {
10657 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10658 		(void) xmlAddChild(elts.template, template_elts.common_name);
10659 		(void) xmlAddChild(elts.template, template_elts.description);
10660 		(void) xmlAddChild(elts.template, template_elts.documentation);
10661 	} else {
10662 		xmlFreeNode(template_elts.description);
10663 		xmlFreeNode(template_elts.documentation);
10664 	}
10665 
10666 	if (isdefault && elts.restarter == NULL &&
10667 	    elts.dependencies == NULL && elts.method_context == NULL &&
10668 	    elts.exec_methods == NULL && elts.notify_params == NULL &&
10669 	    elts.property_groups == NULL && elts.template == NULL) {
10670 		xmlChar *eval;
10671 
10672 		/* This is a default instance */
10673 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10674 
10675 		xmlFreeNode(n);
10676 
10677 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10678 		if (n == NULL)
10679 			uu_die(emsg_create_xml);
10680 
10681 		safe_setprop(n, enabled_attr, (char *)eval);
10682 		xmlFree(eval);
10683 
10684 		selts->create_default_instance = n;
10685 	} else {
10686 		/* Assemble the children in order. */
10687 		(void) xmlAddChild(n, elts.restarter);
10688 		(void) xmlAddChildList(n, elts.dependencies);
10689 		(void) xmlAddChildList(n, elts.dependents);
10690 		(void) xmlAddChild(n, elts.method_context);
10691 		(void) xmlAddChildList(n, elts.exec_methods);
10692 		(void) xmlAddChildList(n, elts.notify_params);
10693 		(void) xmlAddChildList(n, elts.property_groups);
10694 		(void) xmlAddChild(n, elts.template);
10695 
10696 		if (selts->instances == NULL)
10697 			selts->instances = n;
10698 		else
10699 			(void) xmlAddSibling(selts->instances, n);
10700 	}
10701 }
10702 
10703 /*
10704  * Return a service element for the given service.
10705  */
10706 static xmlNodePtr
10707 export_service(scf_service_t *svc, int flags)
10708 {
10709 	xmlNodePtr snode;
10710 	struct entity_elts elts;
10711 	struct template_elts template_elts;
10712 	int ret;
10713 
10714 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10715 	if (snode == NULL)
10716 		uu_die(emsg_create_xml);
10717 
10718 	/* Get & set name attribute */
10719 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10720 		scfdie();
10721 	safe_setprop(snode, name_attr, exp_str);
10722 
10723 	safe_setprop(snode, type_attr, "service");
10724 	safe_setprop(snode, "version", "0");
10725 
10726 	/* Acquire child elements. */
10727 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10728 		scfdie();
10729 
10730 	(void) memset(&elts, 0, sizeof (elts));
10731 	(void) memset(&template_elts, 0, sizeof (template_elts));
10732 
10733 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10734 		uint32_t pgflags;
10735 
10736 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10737 			scfdie();
10738 
10739 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10740 			continue;
10741 
10742 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10743 			scfdie();
10744 
10745 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10746 			export_dependency(exp_pg, &elts);
10747 			continue;
10748 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10749 			export_method(exp_pg, &elts);
10750 			continue;
10751 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10752 			if (scf_pg_get_name(exp_pg, exp_str,
10753 			    max_scf_name_len + 1) < 0)
10754 				scfdie();
10755 
10756 			if (strcmp(exp_str, scf_pg_general) == 0) {
10757 				export_svc_general(exp_pg, &elts);
10758 				continue;
10759 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10760 			    0) {
10761 				export_method_context(exp_pg, &elts);
10762 				continue;
10763 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10764 				export_dependents(exp_pg, &elts);
10765 				continue;
10766 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10767 				continue;
10768 			}
10769 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10770 			export_template(exp_pg, &elts, &template_elts);
10771 			continue;
10772 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10773 			export_notify_params(exp_pg, &elts);
10774 			continue;
10775 		}
10776 
10777 		export_pg(exp_pg, &elts, flags);
10778 	}
10779 	if (ret == -1)
10780 		scfdie();
10781 
10782 	if (template_elts.common_name != NULL) {
10783 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10784 		(void) xmlAddChild(elts.template, template_elts.common_name);
10785 		(void) xmlAddChild(elts.template, template_elts.description);
10786 		(void) xmlAddChild(elts.template, template_elts.documentation);
10787 	} else {
10788 		xmlFreeNode(template_elts.description);
10789 		xmlFreeNode(template_elts.documentation);
10790 	}
10791 
10792 	/* Iterate instances */
10793 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10794 		scfdie();
10795 
10796 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10797 		export_instance(exp_inst, &elts, flags);
10798 	if (ret == -1)
10799 		scfdie();
10800 
10801 	/* Now add all of the accumulated elements in order. */
10802 	(void) xmlAddChild(snode, elts.create_default_instance);
10803 	(void) xmlAddChild(snode, elts.single_instance);
10804 	(void) xmlAddChild(snode, elts.restarter);
10805 	(void) xmlAddChildList(snode, elts.dependencies);
10806 	(void) xmlAddChildList(snode, elts.dependents);
10807 	(void) xmlAddChild(snode, elts.method_context);
10808 	(void) xmlAddChildList(snode, elts.exec_methods);
10809 	(void) xmlAddChildList(snode, elts.notify_params);
10810 	(void) xmlAddChildList(snode, elts.property_groups);
10811 	(void) xmlAddChildList(snode, elts.instances);
10812 	(void) xmlAddChild(snode, elts.stability);
10813 	(void) xmlAddChild(snode, elts.template);
10814 
10815 	return (snode);
10816 }
10817 
10818 static int
10819 export_callback(void *data, scf_walkinfo_t *wip)
10820 {
10821 	FILE *f;
10822 	xmlDocPtr doc;
10823 	xmlNodePtr sb;
10824 	int result;
10825 	struct export_args *argsp = (struct export_args *)data;
10826 
10827 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10828 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10829 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10830 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10831 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10832 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10833 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10834 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10835 		scfdie();
10836 
10837 	exp_str_sz = max_scf_len + 1;
10838 	exp_str = safe_malloc(exp_str_sz);
10839 
10840 	if (argsp->filename != NULL) {
10841 		errno = 0;
10842 		f = fopen(argsp->filename, "wb");
10843 		if (f == NULL) {
10844 			if (errno == 0)
10845 				uu_die(gettext("Could not open \"%s\": no free "
10846 				    "stdio streams.\n"), argsp->filename);
10847 			else
10848 				uu_die(gettext("Could not open \"%s\""),
10849 				    argsp->filename);
10850 		}
10851 	} else
10852 		f = stdout;
10853 
10854 	doc = xmlNewDoc((xmlChar *)"1.0");
10855 	if (doc == NULL)
10856 		uu_die(gettext("Could not create XML document.\n"));
10857 
10858 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10859 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10860 		uu_die(emsg_create_xml);
10861 
10862 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10863 	if (sb == NULL)
10864 		uu_die(emsg_create_xml);
10865 	safe_setprop(sb, type_attr, "manifest");
10866 	safe_setprop(sb, name_attr, "export");
10867 	(void) xmlAddSibling(doc->children, sb);
10868 
10869 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10870 
10871 	result = write_service_bundle(doc, f);
10872 
10873 	free(exp_str);
10874 	scf_iter_destroy(exp_val_iter);
10875 	scf_iter_destroy(exp_prop_iter);
10876 	scf_iter_destroy(exp_pg_iter);
10877 	scf_iter_destroy(exp_inst_iter);
10878 	scf_value_destroy(exp_val);
10879 	scf_property_destroy(exp_prop);
10880 	scf_pg_destroy(exp_pg);
10881 	scf_instance_destroy(exp_inst);
10882 
10883 	xmlFreeDoc(doc);
10884 
10885 	if (f != stdout)
10886 		(void) fclose(f);
10887 
10888 	return (result);
10889 }
10890 
10891 /*
10892  * Get the service named by fmri, build an XML tree which represents it, and
10893  * dump it into filename (or stdout if filename is NULL).
10894  */
10895 int
10896 lscf_service_export(char *fmri, const char *filename, int flags)
10897 {
10898 	struct export_args args;
10899 	char *fmridup;
10900 	const char *scope, *svc, *inst;
10901 	size_t cblen = 3 * max_scf_name_len;
10902 	char *canonbuf = alloca(cblen);
10903 	int ret, err;
10904 
10905 	lscf_prep_hndl();
10906 
10907 	bzero(&args, sizeof (args));
10908 	args.filename = filename;
10909 	args.flags = flags;
10910 
10911 	/*
10912 	 * If some poor user has passed an exact instance FMRI, of the sort
10913 	 * one might cut and paste from svcs(1) or an error message, warn
10914 	 * and chop off the instance instead of failing.
10915 	 */
10916 	fmridup = alloca(strlen(fmri) + 1);
10917 	(void) strcpy(fmridup, fmri);
10918 	if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10919 	    sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10920 	    scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10921 	    inst != NULL) {
10922 		(void) strlcpy(canonbuf, "svc:/", cblen);
10923 		if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10924 			(void) strlcat(canonbuf, "/", cblen);
10925 			(void) strlcat(canonbuf, scope, cblen);
10926 		}
10927 		(void) strlcat(canonbuf, svc, cblen);
10928 		fmri = canonbuf;
10929 
10930 		warn(gettext("Only services may be exported; ignoring "
10931 		    "instance portion of argument.\n"));
10932 	}
10933 
10934 	err = 0;
10935 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10936 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10937 	    &args, &err, semerr)) != 0) {
10938 		if (ret != -1)
10939 			semerr(gettext("Failed to walk instances: %s\n"),
10940 			    scf_strerror(ret));
10941 		return (-1);
10942 	}
10943 
10944 	/*
10945 	 * Error message has already been printed.
10946 	 */
10947 	if (err != 0)
10948 		return (-1);
10949 
10950 	return (0);
10951 }
10952 
10953 
10954 /*
10955  * Archive
10956  */
10957 
10958 static xmlNodePtr
10959 make_archive(int flags)
10960 {
10961 	xmlNodePtr sb;
10962 	scf_scope_t *scope;
10963 	scf_service_t *svc;
10964 	scf_iter_t *iter;
10965 	int r;
10966 
10967 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10968 	    (svc = scf_service_create(g_hndl)) == NULL ||
10969 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10970 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10971 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10972 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10973 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10974 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10975 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10976 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10977 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10978 		scfdie();
10979 
10980 	exp_str_sz = max_scf_len + 1;
10981 	exp_str = safe_malloc(exp_str_sz);
10982 
10983 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10984 	if (sb == NULL)
10985 		uu_die(emsg_create_xml);
10986 	safe_setprop(sb, type_attr, "archive");
10987 	safe_setprop(sb, name_attr, "none");
10988 
10989 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10990 		scfdie();
10991 	if (scf_iter_scope_services(iter, scope) != 0)
10992 		scfdie();
10993 
10994 	for (;;) {
10995 		r = scf_iter_next_service(iter, svc);
10996 		if (r == 0)
10997 			break;
10998 		if (r != 1)
10999 			scfdie();
11000 
11001 		if (scf_service_get_name(svc, exp_str,
11002 		    max_scf_name_len + 1) < 0)
11003 			scfdie();
11004 
11005 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11006 			continue;
11007 
11008 		(void) xmlAddChild(sb, export_service(svc, flags));
11009 	}
11010 
11011 	free(exp_str);
11012 
11013 	scf_iter_destroy(exp_val_iter);
11014 	scf_iter_destroy(exp_prop_iter);
11015 	scf_iter_destroy(exp_pg_iter);
11016 	scf_iter_destroy(exp_inst_iter);
11017 	scf_value_destroy(exp_val);
11018 	scf_property_destroy(exp_prop);
11019 	scf_pg_destroy(exp_pg);
11020 	scf_instance_destroy(exp_inst);
11021 	scf_iter_destroy(iter);
11022 	scf_service_destroy(svc);
11023 	scf_scope_destroy(scope);
11024 
11025 	return (sb);
11026 }
11027 
11028 int
11029 lscf_archive(const char *filename, int flags)
11030 {
11031 	FILE *f;
11032 	xmlDocPtr doc;
11033 	int result;
11034 
11035 	lscf_prep_hndl();
11036 
11037 	if (filename != NULL) {
11038 		errno = 0;
11039 		f = fopen(filename, "wb");
11040 		if (f == NULL) {
11041 			if (errno == 0)
11042 				uu_die(gettext("Could not open \"%s\": no free "
11043 				    "stdio streams.\n"), filename);
11044 			else
11045 				uu_die(gettext("Could not open \"%s\""),
11046 				    filename);
11047 		}
11048 	} else
11049 		f = stdout;
11050 
11051 	doc = xmlNewDoc((xmlChar *)"1.0");
11052 	if (doc == NULL)
11053 		uu_die(gettext("Could not create XML document.\n"));
11054 
11055 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11056 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11057 		uu_die(emsg_create_xml);
11058 
11059 	(void) xmlAddSibling(doc->children, make_archive(flags));
11060 
11061 	result = write_service_bundle(doc, f);
11062 
11063 	xmlFreeDoc(doc);
11064 
11065 	if (f != stdout)
11066 		(void) fclose(f);
11067 
11068 	return (result);
11069 }
11070 
11071 
11072 /*
11073  * "Extract" a profile.
11074  */
11075 int
11076 lscf_profile_extract(const char *filename)
11077 {
11078 	FILE *f;
11079 	xmlDocPtr doc;
11080 	xmlNodePtr sb, snode, inode;
11081 	scf_scope_t *scope;
11082 	scf_service_t *svc;
11083 	scf_instance_t *inst;
11084 	scf_propertygroup_t *pg;
11085 	scf_property_t *prop;
11086 	scf_value_t *val;
11087 	scf_iter_t *siter, *iiter;
11088 	int r, s;
11089 	char *namebuf;
11090 	uint8_t b;
11091 	int result;
11092 
11093 	lscf_prep_hndl();
11094 
11095 	if (filename != NULL) {
11096 		errno = 0;
11097 		f = fopen(filename, "wb");
11098 		if (f == NULL) {
11099 			if (errno == 0)
11100 				uu_die(gettext("Could not open \"%s\": no "
11101 				    "free stdio streams.\n"), filename);
11102 			else
11103 				uu_die(gettext("Could not open \"%s\""),
11104 				    filename);
11105 		}
11106 	} else
11107 		f = stdout;
11108 
11109 	doc = xmlNewDoc((xmlChar *)"1.0");
11110 	if (doc == NULL)
11111 		uu_die(gettext("Could not create XML document.\n"));
11112 
11113 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11114 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11115 		uu_die(emsg_create_xml);
11116 
11117 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11118 	if (sb == NULL)
11119 		uu_die(emsg_create_xml);
11120 	safe_setprop(sb, type_attr, "profile");
11121 	safe_setprop(sb, name_attr, "extract");
11122 	(void) xmlAddSibling(doc->children, sb);
11123 
11124 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
11125 	    (svc = scf_service_create(g_hndl)) == NULL ||
11126 	    (inst = scf_instance_create(g_hndl)) == NULL ||
11127 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11128 	    (prop = scf_property_create(g_hndl)) == NULL ||
11129 	    (val = scf_value_create(g_hndl)) == NULL ||
11130 	    (siter = scf_iter_create(g_hndl)) == NULL ||
11131 	    (iiter = scf_iter_create(g_hndl)) == NULL)
11132 		scfdie();
11133 
11134 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11135 		scfdie();
11136 
11137 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11138 		scfdie();
11139 
11140 	namebuf = safe_malloc(max_scf_name_len + 1);
11141 
11142 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
11143 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11144 			scfdie();
11145 
11146 		snode = xmlNewNode(NULL, (xmlChar *)"service");
11147 		if (snode == NULL)
11148 			uu_die(emsg_create_xml);
11149 
11150 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11151 		    0)
11152 			scfdie();
11153 
11154 		safe_setprop(snode, name_attr, namebuf);
11155 
11156 		safe_setprop(snode, type_attr, "service");
11157 		safe_setprop(snode, "version", "0");
11158 
11159 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11160 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11161 			    SCF_SUCCESS) {
11162 				if (scf_error() != SCF_ERROR_NOT_FOUND)
11163 					scfdie();
11164 
11165 				if (g_verbose) {
11166 					ssize_t len;
11167 					char *fmri;
11168 
11169 					len =
11170 					    scf_instance_to_fmri(inst, NULL, 0);
11171 					if (len < 0)
11172 						scfdie();
11173 
11174 					fmri = safe_malloc(len + 1);
11175 
11176 					if (scf_instance_to_fmri(inst, fmri,
11177 					    len + 1) < 0)
11178 						scfdie();
11179 
11180 					warn("Instance %s has no \"%s\" "
11181 					    "property group.\n", fmri,
11182 					    scf_pg_general);
11183 
11184 					free(fmri);
11185 				}
11186 
11187 				continue;
11188 			}
11189 
11190 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11191 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11192 			    prop_get_val(prop, val) != 0)
11193 				continue;
11194 
11195 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11196 			    NULL);
11197 			if (inode == NULL)
11198 				uu_die(emsg_create_xml);
11199 
11200 			if (scf_instance_get_name(inst, namebuf,
11201 			    max_scf_name_len + 1) < 0)
11202 				scfdie();
11203 
11204 			safe_setprop(inode, name_attr, namebuf);
11205 
11206 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11207 				scfdie();
11208 
11209 			safe_setprop(inode, enabled_attr, b ? true : false);
11210 		}
11211 		if (s < 0)
11212 			scfdie();
11213 
11214 		if (snode->children != NULL)
11215 			(void) xmlAddChild(sb, snode);
11216 		else
11217 			xmlFreeNode(snode);
11218 	}
11219 	if (r < 0)
11220 		scfdie();
11221 
11222 	free(namebuf);
11223 
11224 	result = write_service_bundle(doc, f);
11225 
11226 	xmlFreeDoc(doc);
11227 
11228 	if (f != stdout)
11229 		(void) fclose(f);
11230 
11231 	return (result);
11232 }
11233 
11234 
11235 /*
11236  * Entity manipulation commands
11237  */
11238 
11239 /*
11240  * Entity selection.  If no entity is selected, then the current scope is in
11241  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11242  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11243  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11244  * cur_inst will be non-NULL.
11245  */
11246 
11247 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11248 static int
11249 select_inst(const char *name)
11250 {
11251 	scf_instance_t *inst;
11252 	scf_error_t err;
11253 
11254 	assert(cur_svc != NULL);
11255 
11256 	inst = scf_instance_create(g_hndl);
11257 	if (inst == NULL)
11258 		scfdie();
11259 
11260 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11261 		cur_inst = inst;
11262 		return (0);
11263 	}
11264 
11265 	err = scf_error();
11266 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11267 		scfdie();
11268 
11269 	scf_instance_destroy(inst);
11270 	return (1);
11271 }
11272 
11273 /* Returns as above. */
11274 static int
11275 select_svc(const char *name)
11276 {
11277 	scf_service_t *svc;
11278 	scf_error_t err;
11279 
11280 	assert(cur_scope != NULL);
11281 
11282 	svc = scf_service_create(g_hndl);
11283 	if (svc == NULL)
11284 		scfdie();
11285 
11286 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11287 		cur_svc = svc;
11288 		return (0);
11289 	}
11290 
11291 	err = scf_error();
11292 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11293 		scfdie();
11294 
11295 	scf_service_destroy(svc);
11296 	return (1);
11297 }
11298 
11299 /* ARGSUSED */
11300 static int
11301 select_callback(void *unused, scf_walkinfo_t *wip)
11302 {
11303 	scf_instance_t *inst;
11304 	scf_service_t *svc;
11305 	scf_scope_t *scope;
11306 
11307 	if (wip->inst != NULL) {
11308 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11309 		    (svc = scf_service_create(g_hndl)) == NULL ||
11310 		    (inst = scf_instance_create(g_hndl)) == NULL)
11311 			scfdie();
11312 
11313 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11314 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11315 			scfdie();
11316 	} else {
11317 		assert(wip->svc != NULL);
11318 
11319 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11320 		    (svc = scf_service_create(g_hndl)) == NULL)
11321 			scfdie();
11322 
11323 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11324 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11325 			scfdie();
11326 
11327 		inst = NULL;
11328 	}
11329 
11330 	/* Clear out the current selection */
11331 	assert(cur_scope != NULL);
11332 	scf_scope_destroy(cur_scope);
11333 	scf_service_destroy(cur_svc);
11334 	scf_instance_destroy(cur_inst);
11335 
11336 	cur_scope = scope;
11337 	cur_svc = svc;
11338 	cur_inst = inst;
11339 
11340 	return (0);
11341 }
11342 
11343 static int
11344 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11345 {
11346 	char **fmri = fmri_p;
11347 
11348 	*fmri = strdup(wip->fmri);
11349 	if (*fmri == NULL)
11350 		uu_die(gettext("Out of memory.\n"));
11351 
11352 	return (0);
11353 }
11354 
11355 /*
11356  * validate [fmri]
11357  * Perform the validation of an FMRI instance.
11358  */
11359 void
11360 lscf_validate_fmri(const char *fmri)
11361 {
11362 	int ret = 0;
11363 	size_t inst_sz;
11364 	char *inst_fmri = NULL;
11365 	scf_tmpl_errors_t *errs = NULL;
11366 	char *snapbuf = NULL;
11367 
11368 	lscf_prep_hndl();
11369 
11370 	if (fmri == NULL) {
11371 		inst_sz = max_scf_fmri_len + 1;
11372 		inst_fmri = safe_malloc(inst_sz);
11373 
11374 		if (cur_snap != NULL) {
11375 			snapbuf = safe_malloc(max_scf_name_len + 1);
11376 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11377 			    max_scf_name_len + 1) < 0)
11378 				scfdie();
11379 		}
11380 		if (cur_inst == NULL) {
11381 			semerr(gettext("No instance selected\n"));
11382 			goto cleanup;
11383 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11384 		    inst_sz) >= inst_sz) {
11385 			/* sanity check. Should never get here */
11386 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11387 			    __FILE__, __LINE__);
11388 		}
11389 	} else {
11390 		scf_error_t scf_err;
11391 		int err = 0;
11392 
11393 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11394 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11395 			uu_warn("Failed to walk instances: %s\n",
11396 			    scf_strerror(scf_err));
11397 			goto cleanup;
11398 		}
11399 		if (err != 0) {
11400 			/* error message displayed by scf_walk_fmri */
11401 			goto cleanup;
11402 		}
11403 	}
11404 
11405 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11406 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11407 	if (ret == -1) {
11408 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11409 			warn(gettext("Template data for %s is invalid. "
11410 			    "Consider reverting to a previous snapshot or "
11411 			    "restoring original configuration.\n"), inst_fmri);
11412 		} else {
11413 			uu_warn("%s: %s\n",
11414 			    gettext("Error validating the instance"),
11415 			    scf_strerror(scf_error()));
11416 		}
11417 	} else if (ret == 1 && errs != NULL) {
11418 		scf_tmpl_error_t *err = NULL;
11419 		char *msg;
11420 		size_t len = 256;	/* initial error buffer size */
11421 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11422 		    SCF_TMPL_STRERROR_HUMAN : 0;
11423 
11424 		msg = safe_malloc(len);
11425 
11426 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11427 			int ret;
11428 
11429 			if ((ret = scf_tmpl_strerror(err, msg, len,
11430 			    flag)) >= len) {
11431 				len = ret + 1;
11432 				msg = realloc(msg, len);
11433 				if (msg == NULL)
11434 					uu_die(gettext(
11435 					    "Out of memory.\n"));
11436 				(void) scf_tmpl_strerror(err, msg, len,
11437 				    flag);
11438 			}
11439 			(void) fprintf(stderr, "%s\n", msg);
11440 		}
11441 		if (msg != NULL)
11442 			free(msg);
11443 	}
11444 	if (errs != NULL)
11445 		scf_tmpl_errors_destroy(errs);
11446 
11447 cleanup:
11448 	free(inst_fmri);
11449 	free(snapbuf);
11450 }
11451 
11452 static void
11453 lscf_validate_file(const char *filename)
11454 {
11455 	tmpl_errors_t *errs;
11456 
11457 	bundle_t *b = internal_bundle_new();
11458 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11459 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11460 			tmpl_errors_print(stderr, errs, "");
11461 			semerr(gettext("Validation failed.\n"));
11462 		}
11463 		tmpl_errors_destroy(errs);
11464 	}
11465 	(void) internal_bundle_free(b);
11466 }
11467 
11468 /*
11469  * validate [fmri|file]
11470  */
11471 void
11472 lscf_validate(const char *arg)
11473 {
11474 	const char *str;
11475 
11476 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11477 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11478 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11479 		lscf_validate_file(str);
11480 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11481 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11482 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11483 		lscf_validate_fmri(str);
11484 	} else if (access(arg, R_OK | F_OK) == 0) {
11485 		lscf_validate_file(arg);
11486 	} else {
11487 		lscf_validate_fmri(arg);
11488 	}
11489 }
11490 
11491 void
11492 lscf_select(const char *fmri)
11493 {
11494 	int ret, err;
11495 
11496 	lscf_prep_hndl();
11497 
11498 	if (cur_snap != NULL) {
11499 		struct snaplevel *elt;
11500 		char *buf;
11501 
11502 		/* Error unless name is that of the next level. */
11503 		elt = uu_list_next(cur_levels, cur_elt);
11504 		if (elt == NULL) {
11505 			semerr(gettext("No children.\n"));
11506 			return;
11507 		}
11508 
11509 		buf = safe_malloc(max_scf_name_len + 1);
11510 
11511 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11512 		    max_scf_name_len + 1) < 0)
11513 			scfdie();
11514 
11515 		if (strcmp(buf, fmri) != 0) {
11516 			semerr(gettext("No such child.\n"));
11517 			free(buf);
11518 			return;
11519 		}
11520 
11521 		free(buf);
11522 
11523 		cur_elt = elt;
11524 		cur_level = elt->sl;
11525 		return;
11526 	}
11527 
11528 	/*
11529 	 * Special case for 'svc:', which takes the user to the scope level.
11530 	 */
11531 	if (strcmp(fmri, "svc:") == 0) {
11532 		scf_instance_destroy(cur_inst);
11533 		scf_service_destroy(cur_svc);
11534 		cur_inst = NULL;
11535 		cur_svc = NULL;
11536 		return;
11537 	}
11538 
11539 	/*
11540 	 * Special case for ':properties'.  This appears as part of 'list' but
11541 	 * can't be selected.  Give a more helpful error message in this case.
11542 	 */
11543 	if (strcmp(fmri, ":properties") == 0) {
11544 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11545 		    "to list properties.\n"));
11546 		return;
11547 	}
11548 
11549 	/*
11550 	 * First try the argument as relative to the current selection.
11551 	 */
11552 	if (cur_inst != NULL) {
11553 		/* EMPTY */;
11554 	} else if (cur_svc != NULL) {
11555 		if (select_inst(fmri) != 1)
11556 			return;
11557 	} else {
11558 		if (select_svc(fmri) != 1)
11559 			return;
11560 	}
11561 
11562 	err = 0;
11563 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11564 	    select_callback, NULL, &err, semerr)) != 0) {
11565 		semerr(gettext("Failed to walk instances: %s\n"),
11566 		    scf_strerror(ret));
11567 	}
11568 }
11569 
11570 void
11571 lscf_unselect(void)
11572 {
11573 	lscf_prep_hndl();
11574 
11575 	if (cur_snap != NULL) {
11576 		struct snaplevel *elt;
11577 
11578 		elt = uu_list_prev(cur_levels, cur_elt);
11579 		if (elt == NULL) {
11580 			semerr(gettext("No parent levels.\n"));
11581 		} else {
11582 			cur_elt = elt;
11583 			cur_level = elt->sl;
11584 		}
11585 	} else if (cur_inst != NULL) {
11586 		scf_instance_destroy(cur_inst);
11587 		cur_inst = NULL;
11588 	} else if (cur_svc != NULL) {
11589 		scf_service_destroy(cur_svc);
11590 		cur_svc = NULL;
11591 	} else {
11592 		semerr(gettext("Cannot unselect at scope level.\n"));
11593 	}
11594 }
11595 
11596 /*
11597  * Return the FMRI of the current selection, for the prompt.
11598  */
11599 void
11600 lscf_get_selection_str(char *buf, size_t bufsz)
11601 {
11602 	char *cp;
11603 	ssize_t fmrilen, szret;
11604 	boolean_t deleted = B_FALSE;
11605 
11606 	if (g_hndl == NULL) {
11607 		(void) strlcpy(buf, "svc:", bufsz);
11608 		return;
11609 	}
11610 
11611 	if (cur_level != NULL) {
11612 		assert(cur_snap != NULL);
11613 
11614 		/* [ snapshot ] FMRI [: instance ] */
11615 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11616 		    + 2 + max_scf_name_len + 1 + 1);
11617 
11618 		buf[0] = '[';
11619 
11620 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11621 		    max_scf_name_len + 1);
11622 		if (szret < 0) {
11623 			if (scf_error() != SCF_ERROR_DELETED)
11624 				scfdie();
11625 
11626 			goto snap_deleted;
11627 		}
11628 
11629 		(void) strcat(buf, "]svc:/");
11630 
11631 		cp = strchr(buf, '\0');
11632 
11633 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11634 		    max_scf_name_len + 1);
11635 		if (szret < 0) {
11636 			if (scf_error() != SCF_ERROR_DELETED)
11637 				scfdie();
11638 
11639 			goto snap_deleted;
11640 		}
11641 
11642 		cp = strchr(cp, '\0');
11643 
11644 		if (snaplevel_is_instance(cur_level)) {
11645 			*cp++ = ':';
11646 
11647 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11648 			    max_scf_name_len + 1) < 0) {
11649 				if (scf_error() != SCF_ERROR_DELETED)
11650 					scfdie();
11651 
11652 				goto snap_deleted;
11653 			}
11654 		} else {
11655 			*cp++ = '[';
11656 			*cp++ = ':';
11657 
11658 			if (scf_instance_get_name(cur_inst, cp,
11659 			    max_scf_name_len + 1) < 0) {
11660 				if (scf_error() != SCF_ERROR_DELETED)
11661 					scfdie();
11662 
11663 				goto snap_deleted;
11664 			}
11665 
11666 			(void) strcat(buf, "]");
11667 		}
11668 
11669 		return;
11670 
11671 snap_deleted:
11672 		deleted = B_TRUE;
11673 		free(buf);
11674 		unselect_cursnap();
11675 	}
11676 
11677 	assert(cur_snap == NULL);
11678 
11679 	if (cur_inst != NULL) {
11680 		assert(cur_svc != NULL);
11681 		assert(cur_scope != NULL);
11682 
11683 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11684 		if (fmrilen >= 0) {
11685 			assert(fmrilen < bufsz);
11686 			if (deleted)
11687 				warn(emsg_deleted);
11688 			return;
11689 		}
11690 
11691 		if (scf_error() != SCF_ERROR_DELETED)
11692 			scfdie();
11693 
11694 		deleted = B_TRUE;
11695 
11696 		scf_instance_destroy(cur_inst);
11697 		cur_inst = NULL;
11698 	}
11699 
11700 	if (cur_svc != NULL) {
11701 		assert(cur_scope != NULL);
11702 
11703 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11704 		if (szret >= 0) {
11705 			assert(szret < bufsz);
11706 			if (deleted)
11707 				warn(emsg_deleted);
11708 			return;
11709 		}
11710 
11711 		if (scf_error() != SCF_ERROR_DELETED)
11712 			scfdie();
11713 
11714 		deleted = B_TRUE;
11715 		scf_service_destroy(cur_svc);
11716 		cur_svc = NULL;
11717 	}
11718 
11719 	assert(cur_scope != NULL);
11720 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11721 
11722 	if (fmrilen < 0)
11723 		scfdie();
11724 
11725 	assert(fmrilen < bufsz);
11726 	if (deleted)
11727 		warn(emsg_deleted);
11728 }
11729 
11730 /*
11731  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11732  * :statistics) are listed for the current selection.
11733  */
11734 void
11735 lscf_list(const char *pattern)
11736 {
11737 	scf_iter_t *iter;
11738 	char *buf;
11739 	int ret;
11740 
11741 	lscf_prep_hndl();
11742 
11743 	if (cur_level != NULL) {
11744 		struct snaplevel *elt;
11745 
11746 		(void) fputs(COLON_NAMESPACES, stdout);
11747 
11748 		elt = uu_list_next(cur_levels, cur_elt);
11749 		if (elt == NULL)
11750 			return;
11751 
11752 		/*
11753 		 * For now, we know that the next level is an instance.  But
11754 		 * if we ever have multiple scopes, this could be complicated.
11755 		 */
11756 		buf = safe_malloc(max_scf_name_len + 1);
11757 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11758 		    max_scf_name_len + 1) >= 0) {
11759 			(void) puts(buf);
11760 		} else {
11761 			if (scf_error() != SCF_ERROR_DELETED)
11762 				scfdie();
11763 		}
11764 
11765 		free(buf);
11766 
11767 		return;
11768 	}
11769 
11770 	if (cur_inst != NULL) {
11771 		(void) fputs(COLON_NAMESPACES, stdout);
11772 		return;
11773 	}
11774 
11775 	iter = scf_iter_create(g_hndl);
11776 	if (iter == NULL)
11777 		scfdie();
11778 
11779 	buf = safe_malloc(max_scf_name_len + 1);
11780 
11781 	if (cur_svc != NULL) {
11782 		/* List the instances in this service. */
11783 		scf_instance_t *inst;
11784 
11785 		inst = scf_instance_create(g_hndl);
11786 		if (inst == NULL)
11787 			scfdie();
11788 
11789 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11790 			safe_printf(COLON_NAMESPACES);
11791 
11792 			for (;;) {
11793 				ret = scf_iter_next_instance(iter, inst);
11794 				if (ret == 0)
11795 					break;
11796 				if (ret != 1) {
11797 					if (scf_error() != SCF_ERROR_DELETED)
11798 						scfdie();
11799 
11800 					break;
11801 				}
11802 
11803 				if (scf_instance_get_name(inst, buf,
11804 				    max_scf_name_len + 1) >= 0) {
11805 					if (pattern == NULL ||
11806 					    fnmatch(pattern, buf, 0) == 0)
11807 						(void) puts(buf);
11808 				} else {
11809 					if (scf_error() != SCF_ERROR_DELETED)
11810 						scfdie();
11811 				}
11812 			}
11813 		} else {
11814 			if (scf_error() != SCF_ERROR_DELETED)
11815 				scfdie();
11816 		}
11817 
11818 		scf_instance_destroy(inst);
11819 	} else {
11820 		/* List the services in this scope. */
11821 		scf_service_t *svc;
11822 
11823 		assert(cur_scope != NULL);
11824 
11825 		svc = scf_service_create(g_hndl);
11826 		if (svc == NULL)
11827 			scfdie();
11828 
11829 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11830 			scfdie();
11831 
11832 		for (;;) {
11833 			ret = scf_iter_next_service(iter, svc);
11834 			if (ret == 0)
11835 				break;
11836 			if (ret != 1)
11837 				scfdie();
11838 
11839 			if (scf_service_get_name(svc, buf,
11840 			    max_scf_name_len + 1) >= 0) {
11841 				if (pattern == NULL ||
11842 				    fnmatch(pattern, buf, 0) == 0)
11843 					safe_printf("%s\n", buf);
11844 			} else {
11845 				if (scf_error() != SCF_ERROR_DELETED)
11846 					scfdie();
11847 			}
11848 		}
11849 
11850 		scf_service_destroy(svc);
11851 	}
11852 
11853 	free(buf);
11854 	scf_iter_destroy(iter);
11855 }
11856 
11857 /*
11858  * Entity addition.  Creates an empty entity in the current selection.
11859  */
11860 void
11861 lscf_add(const char *name)
11862 {
11863 	lscf_prep_hndl();
11864 
11865 	if (cur_snap != NULL) {
11866 		semerr(emsg_cant_modify_snapshots);
11867 	} else if (cur_inst != NULL) {
11868 		semerr(gettext("Cannot add entities to an instance.\n"));
11869 	} else if (cur_svc != NULL) {
11870 
11871 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11872 		    SCF_SUCCESS) {
11873 			switch (scf_error()) {
11874 			case SCF_ERROR_INVALID_ARGUMENT:
11875 				semerr(gettext("Invalid name.\n"));
11876 				break;
11877 
11878 			case SCF_ERROR_EXISTS:
11879 				semerr(gettext("Instance already exists.\n"));
11880 				break;
11881 
11882 			case SCF_ERROR_PERMISSION_DENIED:
11883 				semerr(emsg_permission_denied);
11884 				break;
11885 
11886 			default:
11887 				scfdie();
11888 			}
11889 		}
11890 	} else {
11891 		assert(cur_scope != NULL);
11892 
11893 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11894 		    SCF_SUCCESS) {
11895 			switch (scf_error()) {
11896 			case SCF_ERROR_INVALID_ARGUMENT:
11897 				semerr(gettext("Invalid name.\n"));
11898 				break;
11899 
11900 			case SCF_ERROR_EXISTS:
11901 				semerr(gettext("Service already exists.\n"));
11902 				break;
11903 
11904 			case SCF_ERROR_PERMISSION_DENIED:
11905 				semerr(emsg_permission_denied);
11906 				break;
11907 
11908 			case SCF_ERROR_BACKEND_READONLY:
11909 				semerr(emsg_read_only);
11910 				break;
11911 
11912 			default:
11913 				scfdie();
11914 			}
11915 		}
11916 	}
11917 }
11918 
11919 /* return 1 if the entity has no persistent pgs, else return 0 */
11920 static int
11921 entity_has_no_pgs(void *ent, int isservice)
11922 {
11923 	scf_iter_t *iter = NULL;
11924 	scf_propertygroup_t *pg = NULL;
11925 	uint32_t flags;
11926 	int err;
11927 	int ret = 1;
11928 
11929 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11930 	    (pg = scf_pg_create(g_hndl)) == NULL)
11931 		scfdie();
11932 
11933 	if (isservice) {
11934 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11935 			scfdie();
11936 	} else {
11937 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11938 			scfdie();
11939 	}
11940 
11941 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11942 		if (scf_pg_get_flags(pg, &flags) != 0)
11943 			scfdie();
11944 
11945 		/* skip nonpersistent pgs */
11946 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11947 			continue;
11948 
11949 		ret = 0;
11950 		break;
11951 	}
11952 
11953 	if (err == -1)
11954 		scfdie();
11955 
11956 	scf_pg_destroy(pg);
11957 	scf_iter_destroy(iter);
11958 
11959 	return (ret);
11960 }
11961 
11962 /* return 1 if the service has no instances, else return 0 */
11963 static int
11964 svc_has_no_insts(scf_service_t *svc)
11965 {
11966 	scf_instance_t *inst;
11967 	scf_iter_t *iter;
11968 	int r;
11969 	int ret = 1;
11970 
11971 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11972 	    (iter = scf_iter_create(g_hndl)) == NULL)
11973 		scfdie();
11974 
11975 	if (scf_iter_service_instances(iter, svc) != 0)
11976 		scfdie();
11977 
11978 	r = scf_iter_next_instance(iter, inst);
11979 	if (r == 1) {
11980 		ret = 0;
11981 	} else if (r == 0) {
11982 		ret = 1;
11983 	} else if (r == -1) {
11984 		scfdie();
11985 	} else {
11986 		bad_error("scf_iter_next_instance", r);
11987 	}
11988 
11989 	scf_iter_destroy(iter);
11990 	scf_instance_destroy(inst);
11991 
11992 	return (ret);
11993 }
11994 
11995 /*
11996  * Entity deletion.
11997  */
11998 
11999 /*
12000  * Delete the property group <fmri>/:properties/<name>.  Returns
12001  * SCF_ERROR_NONE on success (or if the entity is not found),
12002  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12003  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12004  * denied.
12005  */
12006 static scf_error_t
12007 delete_dependency_pg(const char *fmri, const char *name)
12008 {
12009 	void *entity = NULL;
12010 	int isservice;
12011 	scf_propertygroup_t *pg = NULL;
12012 	scf_error_t result;
12013 	char *pgty;
12014 	scf_service_t *svc = NULL;
12015 	scf_instance_t *inst = NULL;
12016 	scf_iter_t *iter = NULL;
12017 	char *name_buf = NULL;
12018 
12019 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12020 	switch (result) {
12021 	case SCF_ERROR_NONE:
12022 		break;
12023 
12024 	case SCF_ERROR_NO_MEMORY:
12025 		uu_die(gettext("Out of memory.\n"));
12026 		/* NOTREACHED */
12027 
12028 	case SCF_ERROR_INVALID_ARGUMENT:
12029 	case SCF_ERROR_CONSTRAINT_VIOLATED:
12030 		return (SCF_ERROR_INVALID_ARGUMENT);
12031 
12032 	case SCF_ERROR_NOT_FOUND:
12033 		result = SCF_ERROR_NONE;
12034 		goto out;
12035 
12036 	default:
12037 		bad_error("fmri_to_entity", result);
12038 	}
12039 
12040 	pg = scf_pg_create(g_hndl);
12041 	if (pg == NULL)
12042 		scfdie();
12043 
12044 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
12045 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12046 			scfdie();
12047 
12048 		result = SCF_ERROR_NONE;
12049 		goto out;
12050 	}
12051 
12052 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12053 
12054 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12055 		scfdie();
12056 
12057 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12058 		result = SCF_ERROR_TYPE_MISMATCH;
12059 		free(pgty);
12060 		goto out;
12061 	}
12062 
12063 	free(pgty);
12064 
12065 	if (scf_pg_delete(pg) != 0) {
12066 		result = scf_error();
12067 		if (result != SCF_ERROR_PERMISSION_DENIED)
12068 			scfdie();
12069 		goto out;
12070 	}
12071 
12072 	/*
12073 	 * We have to handle the case where we've just deleted the last
12074 	 * property group of a "dummy" entity (instance or service).
12075 	 * A "dummy" entity is an entity only present to hold an
12076 	 * external dependency.
12077 	 * So, in the case we deleted the last property group then we
12078 	 * can also delete the entity. If the entity is an instance then
12079 	 * we must verify if this was the last instance for the service
12080 	 * and if it is, we can also delete the service if it doesn't
12081 	 * have any property group either.
12082 	 */
12083 
12084 	result = SCF_ERROR_NONE;
12085 
12086 	if (isservice) {
12087 		svc = (scf_service_t *)entity;
12088 
12089 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
12090 		    (iter = scf_iter_create(g_hndl)) == NULL)
12091 			scfdie();
12092 
12093 		name_buf = safe_malloc(max_scf_name_len + 1);
12094 	} else {
12095 		inst = (scf_instance_t *)entity;
12096 	}
12097 
12098 	/*
12099 	 * If the entity is an instance and we've just deleted its last
12100 	 * property group then we should delete it.
12101 	 */
12102 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
12103 		/* find the service before deleting the inst. - needed later */
12104 		if ((svc = scf_service_create(g_hndl)) == NULL)
12105 			scfdie();
12106 
12107 		if (scf_instance_get_parent(inst, svc) != 0)
12108 			scfdie();
12109 
12110 		/* delete the instance */
12111 		if (scf_instance_delete(inst) != 0) {
12112 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12113 				scfdie();
12114 
12115 			result = SCF_ERROR_PERMISSION_DENIED;
12116 			goto out;
12117 		}
12118 		/* no need to refresh the instance */
12119 		inst = NULL;
12120 	}
12121 
12122 	/*
12123 	 * If the service has no more instances and pgs or we just deleted the
12124 	 * last instance and the service doesn't have anymore propery groups
12125 	 * then the service should be deleted.
12126 	 */
12127 	if (svc != NULL &&
12128 	    svc_has_no_insts(svc) &&
12129 	    entity_has_no_pgs((void *)svc, 1)) {
12130 		if (scf_service_delete(svc) == 0) {
12131 			if (isservice) {
12132 				/* no need to refresh the service */
12133 				svc = NULL;
12134 			}
12135 
12136 			goto out;
12137 		}
12138 
12139 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12140 			scfdie();
12141 
12142 		result = SCF_ERROR_PERMISSION_DENIED;
12143 	}
12144 
12145 	/* if the entity has not been deleted, refresh it */
12146 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12147 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
12148 		    name_buf);
12149 	}
12150 
12151 out:
12152 	if (isservice && (inst != NULL && iter != NULL)) {
12153 		free(name_buf);
12154 		scf_iter_destroy(iter);
12155 		scf_instance_destroy(inst);
12156 	}
12157 
12158 	if (!isservice && svc != NULL) {
12159 		scf_service_destroy(svc);
12160 	}
12161 
12162 	scf_pg_destroy(pg);
12163 	if (entity != NULL)
12164 		entity_destroy(entity, isservice);
12165 
12166 	return (result);
12167 }
12168 
12169 static int
12170 delete_dependents(scf_propertygroup_t *pg)
12171 {
12172 	char *pgty, *name, *fmri;
12173 	scf_property_t *prop;
12174 	scf_value_t *val;
12175 	scf_iter_t *iter;
12176 	int r;
12177 	scf_error_t err;
12178 
12179 	/* Verify that the pg has the correct type. */
12180 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12181 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12182 		scfdie();
12183 
12184 	if (strcmp(pgty, scf_group_framework) != 0) {
12185 		if (g_verbose) {
12186 			fmri = safe_malloc(max_scf_fmri_len + 1);
12187 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12188 				scfdie();
12189 
12190 			warn(gettext("Property group %s is not of expected "
12191 			    "type %s.\n"), fmri, scf_group_framework);
12192 
12193 			free(fmri);
12194 		}
12195 
12196 		free(pgty);
12197 		return (-1);
12198 	}
12199 
12200 	free(pgty);
12201 
12202 	/* map delete_dependency_pg onto the properties. */
12203 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12204 	    (val = scf_value_create(g_hndl)) == NULL ||
12205 	    (iter = scf_iter_create(g_hndl)) == NULL)
12206 		scfdie();
12207 
12208 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12209 		scfdie();
12210 
12211 	name = safe_malloc(max_scf_name_len + 1);
12212 	fmri = safe_malloc(max_scf_fmri_len + 2);
12213 
12214 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
12215 		scf_type_t ty;
12216 
12217 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12218 			scfdie();
12219 
12220 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12221 			scfdie();
12222 
12223 		if ((ty != SCF_TYPE_ASTRING &&
12224 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12225 		    prop_get_val(prop, val) != 0)
12226 			continue;
12227 
12228 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12229 			scfdie();
12230 
12231 		err = delete_dependency_pg(fmri, name);
12232 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12233 			if (scf_property_to_fmri(prop, fmri,
12234 			    max_scf_fmri_len + 2) < 0)
12235 				scfdie();
12236 
12237 			warn(gettext("Value of %s is not a valid FMRI.\n"),
12238 			    fmri);
12239 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12240 			warn(gettext("Property group \"%s\" of entity \"%s\" "
12241 			    "does not have dependency type.\n"), name, fmri);
12242 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12243 			warn(gettext("Could not delete property group \"%s\" "
12244 			    "of entity \"%s\" (permission denied).\n"), name,
12245 			    fmri);
12246 		}
12247 	}
12248 	if (r == -1)
12249 		scfdie();
12250 
12251 	scf_value_destroy(val);
12252 	scf_property_destroy(prop);
12253 
12254 	return (0);
12255 }
12256 
12257 /*
12258  * Returns 1 if the instance may be running, and 0 otherwise.
12259  */
12260 static int
12261 inst_is_running(scf_instance_t *inst)
12262 {
12263 	scf_propertygroup_t *pg;
12264 	scf_property_t *prop;
12265 	scf_value_t *val;
12266 	char buf[MAX_SCF_STATE_STRING_SZ];
12267 	int ret = 0;
12268 	ssize_t szret;
12269 
12270 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12271 	    (prop = scf_property_create(g_hndl)) == NULL ||
12272 	    (val = scf_value_create(g_hndl)) == NULL)
12273 		scfdie();
12274 
12275 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12276 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12277 			scfdie();
12278 		goto out;
12279 	}
12280 
12281 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12282 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12283 	    prop_get_val(prop, val) != 0)
12284 		goto out;
12285 
12286 	szret = scf_value_get_astring(val, buf, sizeof (buf));
12287 	assert(szret >= 0);
12288 
12289 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12290 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12291 
12292 out:
12293 	scf_value_destroy(val);
12294 	scf_property_destroy(prop);
12295 	scf_pg_destroy(pg);
12296 	return (ret);
12297 }
12298 
12299 static uint8_t
12300 pg_is_external_dependency(scf_propertygroup_t *pg)
12301 {
12302 	char *type;
12303 	scf_value_t *val;
12304 	scf_property_t *prop;
12305 	uint8_t b = B_FALSE;
12306 
12307 	type = safe_malloc(max_scf_pg_type_len + 1);
12308 
12309 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12310 		scfdie();
12311 
12312 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12313 	    (val = scf_value_create(g_hndl)) == NULL)
12314 		scfdie();
12315 
12316 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12317 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12318 			if (scf_property_get_value(prop, val) != 0)
12319 				scfdie();
12320 			if (scf_value_get_boolean(val, &b) != 0)
12321 				scfdie();
12322 		}
12323 	}
12324 
12325 	free(type);
12326 	(void) scf_value_destroy(val);
12327 	(void) scf_property_destroy(prop);
12328 
12329 	return (b);
12330 }
12331 
12332 #define	DELETE_FAILURE			-1
12333 #define	DELETE_SUCCESS_NOEXTDEPS	0
12334 #define	DELETE_SUCCESS_EXTDEPS		1
12335 
12336 /*
12337  * lscf_instance_delete() deletes an instance.  Before calling
12338  * scf_instance_delete(), though, we make sure the instance isn't
12339  * running and delete dependencies in other entities which the instance
12340  * declared as "dependents".  If there are dependencies which were
12341  * created for other entities, then instead of deleting the instance we
12342  * make it "empty" by deleting all other property groups and all
12343  * snapshots.
12344  *
12345  * lscf_instance_delete() verifies that there is no external dependency pgs
12346  * before suppressing the instance. If there is, then we must not remove them
12347  * now in case the instance is re-created otherwise the dependencies would be
12348  * lost. The external dependency pgs will be removed if the dependencies are
12349  * removed.
12350  *
12351  * Returns:
12352  *  DELETE_FAILURE		on failure
12353  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12354  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12355  */
12356 static int
12357 lscf_instance_delete(scf_instance_t *inst, int force)
12358 {
12359 	scf_propertygroup_t *pg;
12360 	scf_snapshot_t *snap;
12361 	scf_iter_t *iter;
12362 	int err;
12363 	int external = 0;
12364 
12365 	/* If we're not forcing and the instance is running, refuse. */
12366 	if (!force && inst_is_running(inst)) {
12367 		char *fmri;
12368 
12369 		fmri = safe_malloc(max_scf_fmri_len + 1);
12370 
12371 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12372 			scfdie();
12373 
12374 		semerr(gettext("Instance %s may be running.  "
12375 		    "Use delete -f if it is not.\n"), fmri);
12376 
12377 		free(fmri);
12378 		return (DELETE_FAILURE);
12379 	}
12380 
12381 	pg = scf_pg_create(g_hndl);
12382 	if (pg == NULL)
12383 		scfdie();
12384 
12385 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12386 		(void) delete_dependents(pg);
12387 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12388 		scfdie();
12389 
12390 	scf_pg_destroy(pg);
12391 
12392 	/*
12393 	 * If the instance has some external dependencies then we must
12394 	 * keep them in case the instance is reimported otherwise the
12395 	 * dependencies would be lost on reimport.
12396 	 */
12397 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12398 	    (pg = scf_pg_create(g_hndl)) == NULL)
12399 		scfdie();
12400 
12401 	if (scf_iter_instance_pgs(iter, inst) < 0)
12402 		scfdie();
12403 
12404 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12405 		if (pg_is_external_dependency(pg)) {
12406 			external = 1;
12407 			continue;
12408 		}
12409 
12410 		if (scf_pg_delete(pg) != 0) {
12411 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12412 				scfdie();
12413 			else {
12414 				semerr(emsg_permission_denied);
12415 
12416 				(void) scf_iter_destroy(iter);
12417 				(void) scf_pg_destroy(pg);
12418 				return (DELETE_FAILURE);
12419 			}
12420 		}
12421 	}
12422 
12423 	if (err == -1)
12424 		scfdie();
12425 
12426 	(void) scf_iter_destroy(iter);
12427 	(void) scf_pg_destroy(pg);
12428 
12429 	if (external) {
12430 		/*
12431 		 * All the pgs have been deleted for the instance except
12432 		 * the ones holding the external dependencies.
12433 		 * For the job to be complete, we must also delete the
12434 		 * snapshots associated with the instance.
12435 		 */
12436 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12437 		    NULL)
12438 			scfdie();
12439 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12440 			scfdie();
12441 
12442 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12443 			scfdie();
12444 
12445 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12446 			if (_scf_snapshot_delete(snap) != 0) {
12447 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12448 					scfdie();
12449 
12450 				semerr(emsg_permission_denied);
12451 
12452 				(void) scf_iter_destroy(iter);
12453 				(void) scf_snapshot_destroy(snap);
12454 				return (DELETE_FAILURE);
12455 			}
12456 		}
12457 
12458 		if (err == -1)
12459 			scfdie();
12460 
12461 		(void) scf_iter_destroy(iter);
12462 		(void) scf_snapshot_destroy(snap);
12463 		return (DELETE_SUCCESS_EXTDEPS);
12464 	}
12465 
12466 	if (scf_instance_delete(inst) != 0) {
12467 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12468 			scfdie();
12469 
12470 		semerr(emsg_permission_denied);
12471 
12472 		return (DELETE_FAILURE);
12473 	}
12474 
12475 	return (DELETE_SUCCESS_NOEXTDEPS);
12476 }
12477 
12478 /*
12479  * lscf_service_delete() deletes a service.  Before calling
12480  * scf_service_delete(), though, we call lscf_instance_delete() for
12481  * each of the instances and delete dependencies in other entities
12482  * which were created as "dependents" of this service.  If there are
12483  * dependencies which were created for other entities, then we delete
12484  * all other property groups in the service and leave it as "empty".
12485  *
12486  * lscf_service_delete() verifies that there is no external dependency
12487  * pgs at the instance & service level before suppressing the service.
12488  * If there is, then we must not remove them now in case the service
12489  * is re-imported otherwise the dependencies would be lost. The external
12490  * dependency pgs will be removed if the dependencies are removed.
12491  *
12492  * Returns:
12493  *   DELETE_FAILURE		on failure
12494  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12495  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12496  */
12497 static int
12498 lscf_service_delete(scf_service_t *svc, int force)
12499 {
12500 	int r;
12501 	scf_instance_t *inst;
12502 	scf_propertygroup_t *pg;
12503 	scf_iter_t *iter;
12504 	int ret;
12505 	int external = 0;
12506 
12507 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12508 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12509 	    (iter = scf_iter_create(g_hndl)) == NULL)
12510 		scfdie();
12511 
12512 	if (scf_iter_service_instances(iter, svc) != 0)
12513 		scfdie();
12514 
12515 	for (r = scf_iter_next_instance(iter, inst);
12516 	    r == 1;
12517 	    r = scf_iter_next_instance(iter, inst)) {
12518 
12519 		ret = lscf_instance_delete(inst, force);
12520 		if (ret == DELETE_FAILURE) {
12521 			scf_iter_destroy(iter);
12522 			scf_pg_destroy(pg);
12523 			scf_instance_destroy(inst);
12524 			return (DELETE_FAILURE);
12525 		}
12526 
12527 		/*
12528 		 * Record the fact that there is some external dependencies
12529 		 * at the instance level.
12530 		 */
12531 		if (ret == DELETE_SUCCESS_EXTDEPS)
12532 			external |= 1;
12533 	}
12534 
12535 	if (r != 0)
12536 		scfdie();
12537 
12538 	/* Delete dependency property groups in dependent services. */
12539 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12540 		(void) delete_dependents(pg);
12541 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12542 		scfdie();
12543 
12544 	scf_iter_destroy(iter);
12545 	scf_pg_destroy(pg);
12546 	scf_instance_destroy(inst);
12547 
12548 	/*
12549 	 * If the service has some external dependencies then we don't
12550 	 * want to remove them in case the service is re-imported.
12551 	 */
12552 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12553 	    (iter = scf_iter_create(g_hndl)) == NULL)
12554 		scfdie();
12555 
12556 	if (scf_iter_service_pgs(iter, svc) < 0)
12557 		scfdie();
12558 
12559 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12560 		if (pg_is_external_dependency(pg)) {
12561 			external |= 2;
12562 			continue;
12563 		}
12564 
12565 		if (scf_pg_delete(pg) != 0) {
12566 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12567 				scfdie();
12568 			else {
12569 				semerr(emsg_permission_denied);
12570 
12571 				(void) scf_iter_destroy(iter);
12572 				(void) scf_pg_destroy(pg);
12573 				return (DELETE_FAILURE);
12574 			}
12575 		}
12576 	}
12577 
12578 	if (r == -1)
12579 		scfdie();
12580 
12581 	(void) scf_iter_destroy(iter);
12582 	(void) scf_pg_destroy(pg);
12583 
12584 	if (external != 0)
12585 		return (DELETE_SUCCESS_EXTDEPS);
12586 
12587 	if (scf_service_delete(svc) == 0)
12588 		return (DELETE_SUCCESS_NOEXTDEPS);
12589 
12590 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12591 		scfdie();
12592 
12593 	semerr(emsg_permission_denied);
12594 	return (DELETE_FAILURE);
12595 }
12596 
12597 static int
12598 delete_callback(void *data, scf_walkinfo_t *wip)
12599 {
12600 	int force = (int)data;
12601 
12602 	if (wip->inst != NULL)
12603 		(void) lscf_instance_delete(wip->inst, force);
12604 	else
12605 		(void) lscf_service_delete(wip->svc, force);
12606 
12607 	return (0);
12608 }
12609 
12610 void
12611 lscf_delete(const char *fmri, int force)
12612 {
12613 	scf_service_t *svc;
12614 	scf_instance_t *inst;
12615 	int ret;
12616 
12617 	lscf_prep_hndl();
12618 
12619 	if (cur_snap != NULL) {
12620 		if (!snaplevel_is_instance(cur_level)) {
12621 			char *buf;
12622 
12623 			buf = safe_malloc(max_scf_name_len + 1);
12624 			if (scf_instance_get_name(cur_inst, buf,
12625 			    max_scf_name_len + 1) >= 0) {
12626 				if (strcmp(buf, fmri) == 0) {
12627 					semerr(emsg_cant_modify_snapshots);
12628 					free(buf);
12629 					return;
12630 				}
12631 			} else if (scf_error() != SCF_ERROR_DELETED) {
12632 				scfdie();
12633 			}
12634 			free(buf);
12635 		}
12636 	} else if (cur_inst != NULL) {
12637 		/* EMPTY */;
12638 	} else if (cur_svc != NULL) {
12639 		inst = scf_instance_create(g_hndl);
12640 		if (inst == NULL)
12641 			scfdie();
12642 
12643 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12644 		    SCF_SUCCESS) {
12645 			(void) lscf_instance_delete(inst, force);
12646 			scf_instance_destroy(inst);
12647 			return;
12648 		}
12649 
12650 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12651 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12652 			scfdie();
12653 
12654 		scf_instance_destroy(inst);
12655 	} else {
12656 		assert(cur_scope != NULL);
12657 
12658 		svc = scf_service_create(g_hndl);
12659 		if (svc == NULL)
12660 			scfdie();
12661 
12662 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12663 		    SCF_SUCCESS) {
12664 			(void) lscf_service_delete(svc, force);
12665 			scf_service_destroy(svc);
12666 			return;
12667 		}
12668 
12669 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12670 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12671 			scfdie();
12672 
12673 		scf_service_destroy(svc);
12674 	}
12675 
12676 	/*
12677 	 * Match FMRI to entity.
12678 	 */
12679 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12680 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12681 		semerr(gettext("Failed to walk instances: %s\n"),
12682 		    scf_strerror(ret));
12683 	}
12684 }
12685 
12686 
12687 
12688 /*
12689  * :properties commands.  These all end with "pg" or "prop" and generally
12690  * operate on the currently selected entity.
12691  */
12692 
12693 /*
12694  * Property listing.  List the property groups, properties, their types and
12695  * their values for the currently selected entity.
12696  */
12697 static void
12698 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12699 {
12700 	char *buf;
12701 	uint32_t flags;
12702 
12703 	buf = safe_malloc(max_scf_pg_type_len + 1);
12704 
12705 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12706 		scfdie();
12707 
12708 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12709 		scfdie();
12710 
12711 	safe_printf("%-*s  %s", namewidth, name, buf);
12712 
12713 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12714 		safe_printf("\tNONPERSISTENT");
12715 
12716 	safe_printf("\n");
12717 
12718 	free(buf);
12719 }
12720 
12721 static boolean_t
12722 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12723 {
12724 	if (scf_property_get_value(prop, val) == 0) {
12725 		return (B_FALSE);
12726 	} else {
12727 		switch (scf_error()) {
12728 		case SCF_ERROR_NOT_FOUND:
12729 			return (B_FALSE);
12730 		case SCF_ERROR_PERMISSION_DENIED:
12731 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12732 			return (B_TRUE);
12733 		default:
12734 			scfdie();
12735 			/*NOTREACHED*/
12736 		}
12737 	}
12738 }
12739 
12740 static void
12741 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12742 {
12743 	scf_iter_t *iter;
12744 	scf_value_t *val;
12745 	const char *type;
12746 	int multiple_strings = 0;
12747 	int ret;
12748 
12749 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12750 	    (val = scf_value_create(g_hndl)) == NULL)
12751 		scfdie();
12752 
12753 	type = prop_to_typestr(prop);
12754 	assert(type != NULL);
12755 
12756 	safe_printf("%-*s  %-7s ", len, name, type);
12757 
12758 	if (prop_has_multiple_values(prop, val) &&
12759 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12760 	    scf_value_type(val) == SCF_TYPE_USTRING))
12761 		multiple_strings = 1;
12762 
12763 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12764 		scfdie();
12765 
12766 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12767 		char *buf;
12768 		ssize_t vlen, szret;
12769 
12770 		vlen = scf_value_get_as_string(val, NULL, 0);
12771 		if (vlen < 0)
12772 			scfdie();
12773 
12774 		buf = safe_malloc(vlen + 1);
12775 
12776 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12777 		if (szret < 0)
12778 			scfdie();
12779 		assert(szret <= vlen);
12780 
12781 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12782 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12783 			safe_printf(" \"");
12784 			(void) quote_and_print(buf, stdout, 0);
12785 			(void) putchar('"');
12786 			if (ferror(stdout)) {
12787 				(void) putchar('\n');
12788 				uu_die(gettext("Error writing to stdout.\n"));
12789 			}
12790 		} else {
12791 			safe_printf(" %s", buf);
12792 		}
12793 
12794 		free(buf);
12795 	}
12796 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12797 		scfdie();
12798 
12799 	if (putchar('\n') != '\n')
12800 		uu_die(gettext("Could not output newline"));
12801 }
12802 
12803 /*
12804  * Outputs template property group info for the describe subcommand.
12805  * If 'templates' == 2, verbose output is printed in the format expected
12806  * for describe -v, which includes all templates fields.  If pg is
12807  * not NULL, we're describing the template data, not an existing property
12808  * group, and formatting should be appropriate for describe -t.
12809  */
12810 static void
12811 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12812 {
12813 	char *buf;
12814 	uint8_t required;
12815 	scf_property_t *stability_prop;
12816 	scf_value_t *stability_val;
12817 
12818 	if (templates == 0)
12819 		return;
12820 
12821 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12822 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12823 		scfdie();
12824 
12825 	if (templates == 2 && pg != NULL) {
12826 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12827 		    stability_prop) == 0) {
12828 			if (prop_check_type(stability_prop,
12829 			    SCF_TYPE_ASTRING) == 0 &&
12830 			    prop_get_val(stability_prop, stability_val) == 0) {
12831 				char *stability;
12832 
12833 				stability = safe_malloc(max_scf_value_len + 1);
12834 
12835 				if (scf_value_get_astring(stability_val,
12836 				    stability, max_scf_value_len + 1) == -1 &&
12837 				    scf_error() != SCF_ERROR_NOT_FOUND)
12838 					scfdie();
12839 
12840 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12841 				    gettext("stability"), stability);
12842 
12843 				free(stability);
12844 			}
12845 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12846 			scfdie();
12847 	}
12848 
12849 	scf_property_destroy(stability_prop);
12850 	scf_value_destroy(stability_val);
12851 
12852 	if (pgt == NULL)
12853 		return;
12854 
12855 	if (pg == NULL || templates == 2) {
12856 		/* print type info only if scf_tmpl_pg_name succeeds */
12857 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12858 			if (pg != NULL)
12859 				safe_printf("%s", TMPL_INDENT);
12860 			safe_printf("%s: ", gettext("name"));
12861 			safe_printf("%s\n", buf);
12862 			free(buf);
12863 		}
12864 
12865 		/* print type info only if scf_tmpl_pg_type succeeds */
12866 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12867 			if (pg != NULL)
12868 				safe_printf("%s", TMPL_INDENT);
12869 			safe_printf("%s: ", gettext("type"));
12870 			safe_printf("%s\n", buf);
12871 			free(buf);
12872 		}
12873 	}
12874 
12875 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12876 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12877 		    required ? "true" : "false");
12878 
12879 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12880 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12881 		    buf);
12882 		free(buf);
12883 	}
12884 
12885 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12886 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12887 		    buf);
12888 		free(buf);
12889 	}
12890 
12891 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12892 		if (templates == 2)
12893 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12894 			    gettext("description"), buf);
12895 		else
12896 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12897 		free(buf);
12898 	}
12899 
12900 }
12901 
12902 /*
12903  * With as_value set to true, indent as appropriate for the value level.
12904  * If false, indent to appropriate level for inclusion in constraint
12905  * or choice printout.
12906  */
12907 static void
12908 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12909     int as_value)
12910 {
12911 	char *buf;
12912 
12913 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12914 		if (as_value == 0)
12915 			safe_printf("%s", TMPL_CHOICE_INDENT);
12916 		else
12917 			safe_printf("%s", TMPL_INDENT);
12918 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12919 		free(buf);
12920 	}
12921 
12922 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12923 		if (as_value == 0)
12924 			safe_printf("%s", TMPL_CHOICE_INDENT);
12925 		else
12926 			safe_printf("%s", TMPL_INDENT);
12927 		safe_printf("%s: %s\n", gettext("value description"), buf);
12928 		free(buf);
12929 	}
12930 }
12931 
12932 static void
12933 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12934 {
12935 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12936 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12937 	safe_printf("%s\n", val_buf);
12938 
12939 	print_template_value_details(prt, val_buf, 1);
12940 }
12941 
12942 static void
12943 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12944 {
12945 	int i, printed = 0;
12946 	scf_values_t values;
12947 	scf_count_ranges_t c_ranges;
12948 	scf_int_ranges_t i_ranges;
12949 
12950 	printed = 0;
12951 	i = 0;
12952 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12953 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12954 		    gettext("value constraints"));
12955 		printed++;
12956 		for (i = 0; i < values.value_count; ++i) {
12957 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12958 			    gettext("value name"), values.values_as_strings[i]);
12959 			if (verbose == 1)
12960 				print_template_value_details(prt,
12961 				    values.values_as_strings[i], 0);
12962 		}
12963 
12964 		scf_values_destroy(&values);
12965 	}
12966 
12967 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12968 		if (printed++ == 0)
12969 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12970 			    gettext("value constraints"));
12971 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12972 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12973 			    gettext("range"), c_ranges.scr_min[i],
12974 			    c_ranges.scr_max[i]);
12975 		}
12976 		scf_count_ranges_destroy(&c_ranges);
12977 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12978 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12979 		if (printed++ == 0)
12980 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12981 			    gettext("value constraints"));
12982 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12983 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12984 			    gettext("range"), i_ranges.sir_min[i],
12985 			    i_ranges.sir_max[i]);
12986 		}
12987 		scf_int_ranges_destroy(&i_ranges);
12988 	}
12989 }
12990 
12991 static void
12992 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12993 {
12994 	int i = 0, printed = 0;
12995 	scf_values_t values;
12996 	scf_count_ranges_t c_ranges;
12997 	scf_int_ranges_t i_ranges;
12998 
12999 	printed = 0;
13000 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13001 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13002 		    gettext("value constraints"));
13003 		printed++;
13004 		for (i = 0; i < values.value_count; i++) {
13005 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13006 			    gettext("value name"), values.values_as_strings[i]);
13007 			if (verbose == 1)
13008 				print_template_value_details(prt,
13009 				    values.values_as_strings[i], 0);
13010 		}
13011 
13012 		scf_values_destroy(&values);
13013 	}
13014 
13015 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13016 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13017 			if (printed++ == 0)
13018 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13019 				    gettext("value choices"));
13020 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13021 			    gettext("range"), c_ranges.scr_min[i],
13022 			    c_ranges.scr_max[i]);
13023 		}
13024 		scf_count_ranges_destroy(&c_ranges);
13025 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13026 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13027 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13028 			if (printed++ == 0)
13029 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13030 				    gettext("value choices"));
13031 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13032 			    gettext("range"), i_ranges.sir_min[i],
13033 			    i_ranges.sir_max[i]);
13034 		}
13035 		scf_int_ranges_destroy(&i_ranges);
13036 	}
13037 }
13038 
13039 static void
13040 list_values_by_template(scf_prop_tmpl_t *prt)
13041 {
13042 	print_template_constraints(prt, 1);
13043 	print_template_choices(prt, 1);
13044 }
13045 
13046 static void
13047 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13048 {
13049 	char *val_buf;
13050 	scf_iter_t *iter;
13051 	scf_value_t *val;
13052 	int ret;
13053 
13054 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13055 	    (val = scf_value_create(g_hndl)) == NULL)
13056 		scfdie();
13057 
13058 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13059 		scfdie();
13060 
13061 	val_buf = safe_malloc(max_scf_value_len + 1);
13062 
13063 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13064 		if (scf_value_get_as_string(val, val_buf,
13065 		    max_scf_value_len + 1) < 0)
13066 			scfdie();
13067 
13068 		print_template_value(prt, val_buf);
13069 	}
13070 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13071 		scfdie();
13072 	free(val_buf);
13073 
13074 	print_template_constraints(prt, 0);
13075 	print_template_choices(prt, 0);
13076 
13077 }
13078 
13079 /*
13080  * Outputs property info for the describe subcommand
13081  * Verbose output if templates == 2, -v option of svccfg describe
13082  * Displays template data if prop is not NULL, -t option of svccfg describe
13083  */
13084 static void
13085 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13086 {
13087 	char *buf;
13088 	uint8_t u_buf;
13089 	int i;
13090 	uint64_t min, max;
13091 	scf_values_t values;
13092 
13093 	if (prt == NULL || templates == 0)
13094 		return;
13095 
13096 	if (prop == NULL) {
13097 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13098 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
13099 			safe_printf("%s\n", buf);
13100 			free(buf);
13101 		} else
13102 			safe_printf("(%s)\n", gettext("any"));
13103 	}
13104 
13105 	if (prop == NULL || templates == 2) {
13106 		if (prop != NULL)
13107 			safe_printf("%s", TMPL_INDENT);
13108 		else
13109 			safe_printf("%s", TMPL_VALUE_INDENT);
13110 		safe_printf("%s: ", gettext("type"));
13111 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13112 			safe_printf("%s\n", buf);
13113 			free(buf);
13114 		} else
13115 			safe_printf("(%s)\n", gettext("any"));
13116 	}
13117 
13118 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13119 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13120 		    u_buf ? "true" : "false");
13121 
13122 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13123 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13124 		    buf);
13125 		free(buf);
13126 	}
13127 
13128 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13129 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13130 		    buf);
13131 		free(buf);
13132 	}
13133 
13134 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13135 		safe_printf("%s%s\n", TMPL_INDENT, buf);
13136 		free(buf);
13137 	}
13138 
13139 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13140 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13141 		    scf_tmpl_visibility_to_string(u_buf));
13142 
13143 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13144 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13145 		    gettext("minimum number of values"), min);
13146 		if (max == ULLONG_MAX) {
13147 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13148 			    gettext("maximum number of values"),
13149 			    gettext("unlimited"));
13150 		} else {
13151 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13152 			    gettext("maximum number of values"), max);
13153 		}
13154 	}
13155 
13156 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13157 		for (i = 0; i < values.value_count; i++) {
13158 			if (i == 0) {
13159 				safe_printf("%s%s:", TMPL_INDENT,
13160 				    gettext("internal separators"));
13161 			}
13162 			safe_printf(" \"%s\"", values.values_as_strings[i]);
13163 		}
13164 		safe_printf("\n");
13165 	}
13166 
13167 	if (templates != 2)
13168 		return;
13169 
13170 	if (prop != NULL)
13171 		list_values_tmpl(prt, prop);
13172 	else
13173 		list_values_by_template(prt);
13174 }
13175 
13176 static char *
13177 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13178 {
13179 	char *rv;
13180 
13181 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
13182 	if (rv == NULL) {
13183 		switch (scf_error()) {
13184 		case SCF_ERROR_NOT_FOUND:
13185 			break;
13186 		default:
13187 			scfdie();
13188 		}
13189 	}
13190 	return (rv);
13191 }
13192 
13193 static void
13194 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13195 {
13196 	size_t doc_len;
13197 	size_t man_len;
13198 	char *pg_name;
13199 	char *text = NULL;
13200 	int rv;
13201 
13202 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13203 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13204 	pg_name = safe_malloc(max_scf_name_len + 1);
13205 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13206 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13207 			scfdie();
13208 		}
13209 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13210 			/* Display doc_link and and uri */
13211 			safe_printf("%s%s:\n", TMPL_INDENT,
13212 			    gettext("doc_link"));
13213 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13214 			if (text != NULL) {
13215 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13216 				    TMPL_INDENT, gettext("name"), text);
13217 				uu_free(text);
13218 			}
13219 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
13220 			if (text != NULL) {
13221 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13222 				    gettext("uri"), text);
13223 				uu_free(text);
13224 			}
13225 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13226 		    man_len) == 0) {
13227 			/* Display manpage title, section and path */
13228 			safe_printf("%s%s:\n", TMPL_INDENT,
13229 			    gettext("manpage"));
13230 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13231 			if (text != NULL) {
13232 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13233 				    TMPL_INDENT, gettext("title"), text);
13234 				uu_free(text);
13235 			}
13236 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13237 			if (text != NULL) {
13238 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13239 				    TMPL_INDENT, gettext("section"), text);
13240 				uu_free(text);
13241 			}
13242 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13243 			if (text != NULL) {
13244 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13245 				    TMPL_INDENT, gettext("manpath"), text);
13246 				uu_free(text);
13247 			}
13248 		}
13249 	}
13250 	if (rv == -1)
13251 		scfdie();
13252 
13253 done:
13254 	free(pg_name);
13255 }
13256 
13257 static void
13258 list_entity_tmpl(int templates)
13259 {
13260 	char *common_name = NULL;
13261 	char *description = NULL;
13262 	char *locale = NULL;
13263 	scf_iter_t *iter;
13264 	scf_propertygroup_t *pg;
13265 	scf_property_t *prop;
13266 	int r;
13267 	scf_value_t *val;
13268 
13269 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13270 	    (prop = scf_property_create(g_hndl)) == NULL ||
13271 	    (val = scf_value_create(g_hndl)) == NULL ||
13272 	    (iter = scf_iter_create(g_hndl)) == NULL)
13273 		scfdie();
13274 
13275 	locale = setlocale(LC_MESSAGES, NULL);
13276 
13277 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13278 		common_name = safe_malloc(max_scf_value_len + 1);
13279 
13280 		/* Try both the current locale and the "C" locale. */
13281 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
13282 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
13283 		    scf_pg_get_property(pg, "C", prop) == 0)) {
13284 			if (prop_get_val(prop, val) == 0 &&
13285 			    scf_value_get_ustring(val, common_name,
13286 			    max_scf_value_len + 1) != -1) {
13287 				safe_printf("%s%s: %s\n", TMPL_INDENT,
13288 				    gettext("common name"), common_name);
13289 			}
13290 		}
13291 	}
13292 
13293 	/*
13294 	 * Do description, manpages, and doc links if templates == 2.
13295 	 */
13296 	if (templates == 2) {
13297 		/* Get the description. */
13298 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13299 			description = safe_malloc(max_scf_value_len + 1);
13300 
13301 			/* Try both the current locale and the "C" locale. */
13302 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
13303 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
13304 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13305 				if (prop_get_val(prop, val) == 0 &&
13306 				    scf_value_get_ustring(val, description,
13307 				    max_scf_value_len + 1) != -1) {
13308 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13309 					    gettext("description"),
13310 					    description);
13311 				}
13312 			}
13313 		}
13314 
13315 		/* Process doc_link & manpage elements. */
13316 		if (cur_level != NULL) {
13317 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13318 			    SCF_GROUP_TEMPLATE);
13319 		} else if (cur_inst != NULL) {
13320 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13321 			    SCF_GROUP_TEMPLATE);
13322 		} else {
13323 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13324 			    SCF_GROUP_TEMPLATE);
13325 		}
13326 		if (r == 0) {
13327 			display_documentation(iter, pg);
13328 		}
13329 	}
13330 
13331 	free(common_name);
13332 	free(description);
13333 	scf_pg_destroy(pg);
13334 	scf_property_destroy(prop);
13335 	scf_value_destroy(val);
13336 	scf_iter_destroy(iter);
13337 }
13338 
13339 static void
13340 listtmpl(const char *pattern, int templates)
13341 {
13342 	scf_pg_tmpl_t *pgt;
13343 	scf_prop_tmpl_t *prt;
13344 	char *snapbuf = NULL;
13345 	char *fmribuf;
13346 	char *pg_name = NULL, *prop_name = NULL;
13347 	ssize_t prop_name_size;
13348 	char *qual_prop_name;
13349 	char *search_name;
13350 	int listed = 0;
13351 
13352 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13353 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13354 		scfdie();
13355 
13356 	fmribuf = safe_malloc(max_scf_name_len + 1);
13357 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13358 
13359 	if (cur_snap != NULL) {
13360 		snapbuf = safe_malloc(max_scf_name_len + 1);
13361 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13362 		    max_scf_name_len + 1) < 0)
13363 			scfdie();
13364 	}
13365 
13366 	if (cur_inst != NULL) {
13367 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13368 		    max_scf_name_len + 1) < 0)
13369 			scfdie();
13370 	} else if (cur_svc != NULL) {
13371 		if (scf_service_to_fmri(cur_svc, fmribuf,
13372 		    max_scf_name_len + 1) < 0)
13373 			scfdie();
13374 	} else
13375 		abort();
13376 
13377 	/* If pattern is specified, we want to list only those items. */
13378 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13379 		listed = 0;
13380 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13381 		    fnmatch(pattern, pg_name, 0) == 0)) {
13382 			list_pg_tmpl(pgt, NULL, templates);
13383 			listed++;
13384 		}
13385 
13386 		scf_tmpl_prop_reset(prt);
13387 
13388 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13389 			search_name = NULL;
13390 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13391 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13392 				if (snprintf(qual_prop_name,
13393 				    max_scf_name_len + 1, "%s/%s",
13394 				    pg_name, prop_name) >=
13395 				    max_scf_name_len + 1) {
13396 					prop_name_size = -1;
13397 				} else {
13398 					search_name = qual_prop_name;
13399 				}
13400 			}
13401 			if (listed > 0 || pattern == NULL ||
13402 			    (prop_name_size > 0 &&
13403 			    fnmatch(pattern, search_name,
13404 			    FNM_PATHNAME) == 0))
13405 				list_prop_tmpl(prt, NULL, templates);
13406 			if (prop_name != NULL) {
13407 				free(prop_name);
13408 				prop_name = NULL;
13409 			}
13410 		}
13411 		if (pg_name != NULL) {
13412 			free(pg_name);
13413 			pg_name = NULL;
13414 		}
13415 	}
13416 
13417 	scf_tmpl_prop_destroy(prt);
13418 	scf_tmpl_pg_destroy(pgt);
13419 	free(snapbuf);
13420 	free(fmribuf);
13421 	free(qual_prop_name);
13422 }
13423 
13424 static void
13425 listprop(const char *pattern, int only_pgs, int templates)
13426 {
13427 	scf_propertygroup_t *pg;
13428 	scf_property_t *prop;
13429 	scf_iter_t *iter, *piter;
13430 	char *pgnbuf, *prnbuf, *ppnbuf;
13431 	scf_pg_tmpl_t *pgt, *pgtp;
13432 	scf_prop_tmpl_t *prt;
13433 
13434 	void **objects;
13435 	char **names;
13436 	void **tmpls;
13437 	int allocd, i;
13438 
13439 	int ret;
13440 	ssize_t pgnlen, prnlen, szret;
13441 	size_t max_len = 0;
13442 
13443 	if (cur_svc == NULL && cur_inst == NULL) {
13444 		semerr(emsg_entity_not_selected);
13445 		return;
13446 	}
13447 
13448 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13449 	    (prop = scf_property_create(g_hndl)) == NULL ||
13450 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13451 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13452 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13453 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13454 		scfdie();
13455 
13456 	prnbuf = safe_malloc(max_scf_name_len + 1);
13457 
13458 	if (cur_level != NULL)
13459 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13460 	else if (cur_inst != NULL)
13461 		ret = scf_iter_instance_pgs(iter, cur_inst);
13462 	else
13463 		ret = scf_iter_service_pgs(iter, cur_svc);
13464 	if (ret != 0) {
13465 		return;
13466 	}
13467 
13468 	/*
13469 	 * We want to only list items which match pattern, and we want the
13470 	 * second column to line up, so during the first pass we'll save
13471 	 * matching items, their names, and their templates in objects,
13472 	 * names, and tmpls, computing the maximum name length as we go,
13473 	 * and then we'll print them out.
13474 	 *
13475 	 * Note: We always keep an extra slot available so the array can be
13476 	 * NULL-terminated.
13477 	 */
13478 	i = 0;
13479 	allocd = 1;
13480 	objects = safe_malloc(sizeof (*objects));
13481 	names = safe_malloc(sizeof (*names));
13482 	tmpls = safe_malloc(sizeof (*tmpls));
13483 
13484 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13485 		int new_pg = 0;
13486 		int print_props = 0;
13487 		pgtp = NULL;
13488 
13489 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13490 		if (pgnlen < 0)
13491 			scfdie();
13492 
13493 		pgnbuf = safe_malloc(pgnlen + 1);
13494 
13495 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13496 		if (szret < 0)
13497 			scfdie();
13498 		assert(szret <= pgnlen);
13499 
13500 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13501 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13502 				scfdie();
13503 			pgtp = NULL;
13504 		} else {
13505 			pgtp = pgt;
13506 		}
13507 
13508 		if (pattern == NULL ||
13509 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13510 			if (i+1 >= allocd) {
13511 				allocd *= 2;
13512 				objects = realloc(objects,
13513 				    sizeof (*objects) * allocd);
13514 				names =
13515 				    realloc(names, sizeof (*names) * allocd);
13516 				tmpls = realloc(tmpls,
13517 				    sizeof (*tmpls) * allocd);
13518 				if (objects == NULL || names == NULL ||
13519 				    tmpls == NULL)
13520 					uu_die(gettext("Out of memory"));
13521 			}
13522 			objects[i] = pg;
13523 			names[i] = pgnbuf;
13524 
13525 			if (pgtp == NULL)
13526 				tmpls[i] = NULL;
13527 			else
13528 				tmpls[i] = pgt;
13529 
13530 			++i;
13531 
13532 			if (pgnlen > max_len)
13533 				max_len = pgnlen;
13534 
13535 			new_pg = 1;
13536 			print_props = 1;
13537 		}
13538 
13539 		if (only_pgs) {
13540 			if (new_pg) {
13541 				pg = scf_pg_create(g_hndl);
13542 				if (pg == NULL)
13543 					scfdie();
13544 				pgt = scf_tmpl_pg_create(g_hndl);
13545 				if (pgt == NULL)
13546 					scfdie();
13547 			} else
13548 				free(pgnbuf);
13549 
13550 			continue;
13551 		}
13552 
13553 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13554 			scfdie();
13555 
13556 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13557 			prnlen = scf_property_get_name(prop, prnbuf,
13558 			    max_scf_name_len + 1);
13559 			if (prnlen < 0)
13560 				scfdie();
13561 
13562 			/* Will prepend the property group name and a slash. */
13563 			prnlen += pgnlen + 1;
13564 
13565 			ppnbuf = safe_malloc(prnlen + 1);
13566 
13567 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13568 			    prnbuf) < 0)
13569 				uu_die("snprintf");
13570 
13571 			if (pattern == NULL || print_props == 1 ||
13572 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13573 				if (i+1 >= allocd) {
13574 					allocd *= 2;
13575 					objects = realloc(objects,
13576 					    sizeof (*objects) * allocd);
13577 					names = realloc(names,
13578 					    sizeof (*names) * allocd);
13579 					tmpls = realloc(tmpls,
13580 					    sizeof (*tmpls) * allocd);
13581 					if (objects == NULL || names == NULL ||
13582 					    tmpls == NULL)
13583 						uu_die(gettext(
13584 						    "Out of memory"));
13585 				}
13586 
13587 				objects[i] = prop;
13588 				names[i] = ppnbuf;
13589 
13590 				if (pgtp != NULL) {
13591 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13592 					    prt, 0) < 0) {
13593 						if (scf_error() !=
13594 						    SCF_ERROR_NOT_FOUND)
13595 							scfdie();
13596 						tmpls[i] = NULL;
13597 					} else {
13598 						tmpls[i] = prt;
13599 					}
13600 				} else {
13601 					tmpls[i] = NULL;
13602 				}
13603 
13604 				++i;
13605 
13606 				if (prnlen > max_len)
13607 					max_len = prnlen;
13608 
13609 				prop = scf_property_create(g_hndl);
13610 				prt = scf_tmpl_prop_create(g_hndl);
13611 			} else {
13612 				free(ppnbuf);
13613 			}
13614 		}
13615 
13616 		if (new_pg) {
13617 			pg = scf_pg_create(g_hndl);
13618 			if (pg == NULL)
13619 				scfdie();
13620 			pgt = scf_tmpl_pg_create(g_hndl);
13621 			if (pgt == NULL)
13622 				scfdie();
13623 		} else
13624 			free(pgnbuf);
13625 	}
13626 	if (ret != 0)
13627 		scfdie();
13628 
13629 	objects[i] = NULL;
13630 
13631 	scf_pg_destroy(pg);
13632 	scf_tmpl_pg_destroy(pgt);
13633 	scf_property_destroy(prop);
13634 	scf_tmpl_prop_destroy(prt);
13635 
13636 	for (i = 0; objects[i] != NULL; ++i) {
13637 		if (strchr(names[i], '/') == NULL) {
13638 			/* property group */
13639 			pg = (scf_propertygroup_t *)objects[i];
13640 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13641 			list_pg_info(pg, names[i], max_len);
13642 			list_pg_tmpl(pgt, pg, templates);
13643 			free(names[i]);
13644 			scf_pg_destroy(pg);
13645 			if (pgt != NULL)
13646 				scf_tmpl_pg_destroy(pgt);
13647 		} else {
13648 			/* property */
13649 			prop = (scf_property_t *)objects[i];
13650 			prt = (scf_prop_tmpl_t *)tmpls[i];
13651 			list_prop_info(prop, names[i], max_len);
13652 			list_prop_tmpl(prt, prop, templates);
13653 			free(names[i]);
13654 			scf_property_destroy(prop);
13655 			if (prt != NULL)
13656 				scf_tmpl_prop_destroy(prt);
13657 		}
13658 	}
13659 
13660 	free(names);
13661 	free(objects);
13662 	free(tmpls);
13663 }
13664 
13665 void
13666 lscf_listpg(const char *pattern)
13667 {
13668 	lscf_prep_hndl();
13669 
13670 	listprop(pattern, 1, 0);
13671 }
13672 
13673 /*
13674  * Property group and property creation, setting, and deletion.  setprop (and
13675  * its alias, addprop) can either create a property group of a given type, or
13676  * it can create or set a property to a given type and list of values.
13677  */
13678 void
13679 lscf_addpg(const char *name, const char *type, const char *flags)
13680 {
13681 	scf_propertygroup_t *pg;
13682 	int ret;
13683 	uint32_t flgs = 0;
13684 	const char *cp;
13685 
13686 
13687 	lscf_prep_hndl();
13688 
13689 	if (cur_snap != NULL) {
13690 		semerr(emsg_cant_modify_snapshots);
13691 		return;
13692 	}
13693 
13694 	if (cur_inst == NULL && cur_svc == NULL) {
13695 		semerr(emsg_entity_not_selected);
13696 		return;
13697 	}
13698 
13699 	if (flags != NULL) {
13700 		for (cp = flags; *cp != '\0'; ++cp) {
13701 			switch (*cp) {
13702 			case 'P':
13703 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13704 				break;
13705 
13706 			case 'p':
13707 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13708 				break;
13709 
13710 			default:
13711 				semerr(gettext("Invalid property group flag "
13712 				    "%c."), *cp);
13713 				return;
13714 			}
13715 		}
13716 	}
13717 
13718 	pg = scf_pg_create(g_hndl);
13719 	if (pg == NULL)
13720 		scfdie();
13721 
13722 	if (cur_inst != NULL)
13723 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13724 	else
13725 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13726 
13727 	if (ret != SCF_SUCCESS) {
13728 		switch (scf_error()) {
13729 		case SCF_ERROR_INVALID_ARGUMENT:
13730 			semerr(gettext("Name, type, or flags are invalid.\n"));
13731 			break;
13732 
13733 		case SCF_ERROR_EXISTS:
13734 			semerr(gettext("Property group already exists.\n"));
13735 			break;
13736 
13737 		case SCF_ERROR_PERMISSION_DENIED:
13738 			semerr(emsg_permission_denied);
13739 			break;
13740 
13741 		case SCF_ERROR_BACKEND_ACCESS:
13742 			semerr(gettext("Backend refused access.\n"));
13743 			break;
13744 
13745 		default:
13746 			scfdie();
13747 		}
13748 	}
13749 
13750 	scf_pg_destroy(pg);
13751 
13752 	private_refresh();
13753 }
13754 
13755 void
13756 lscf_delpg(char *name)
13757 {
13758 	lscf_prep_hndl();
13759 
13760 	if (cur_snap != NULL) {
13761 		semerr(emsg_cant_modify_snapshots);
13762 		return;
13763 	}
13764 
13765 	if (cur_inst == NULL && cur_svc == NULL) {
13766 		semerr(emsg_entity_not_selected);
13767 		return;
13768 	}
13769 
13770 	if (strchr(name, '/') != NULL) {
13771 		semerr(emsg_invalid_pg_name, name);
13772 		return;
13773 	}
13774 
13775 	lscf_delprop(name);
13776 }
13777 
13778 /*
13779  * scf_delhash() is used to remove the property group related to the
13780  * hash entry for a specific manifest in the repository. pgname will be
13781  * constructed from the location of the manifest file. If deathrow isn't 0,
13782  * manifest file doesn't need to exist (manifest string will be used as
13783  * an absolute path).
13784  */
13785 void
13786 lscf_delhash(char *manifest, int deathrow)
13787 {
13788 	char *pgname;
13789 
13790 	if (cur_snap != NULL ||
13791 	    cur_inst != NULL || cur_svc != NULL) {
13792 		warn(gettext("error, an entity is selected\n"));
13793 		return;
13794 	}
13795 
13796 	/* select smf/manifest */
13797 	lscf_select(HASH_SVC);
13798 	/*
13799 	 * Translate the manifest file name to property name. In the deathrow
13800 	 * case, the manifest file does not need to exist.
13801 	 */
13802 	pgname = mhash_filename_to_propname(manifest,
13803 	    deathrow ? B_TRUE : B_FALSE);
13804 	if (pgname == NULL) {
13805 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13806 		return;
13807 	}
13808 	/* delete the hash property name */
13809 	lscf_delpg(pgname);
13810 }
13811 
13812 void
13813 lscf_listprop(const char *pattern)
13814 {
13815 	lscf_prep_hndl();
13816 
13817 	listprop(pattern, 0, 0);
13818 }
13819 
13820 int
13821 lscf_setprop(const char *pgname, const char *type, const char *value,
13822     const uu_list_t *values)
13823 {
13824 	scf_type_t ty, current_ty;
13825 	scf_service_t *svc;
13826 	scf_propertygroup_t *pg, *parent_pg;
13827 	scf_property_t *prop, *parent_prop;
13828 	scf_pg_tmpl_t *pgt;
13829 	scf_prop_tmpl_t *prt;
13830 	int ret, result = 0;
13831 	scf_transaction_t *tx;
13832 	scf_transaction_entry_t *e;
13833 	scf_value_t *v;
13834 	uu_list_walk_t *walk;
13835 	string_list_t *sp;
13836 	char *propname;
13837 	int req_quotes = 0;
13838 
13839 	lscf_prep_hndl();
13840 
13841 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13842 	    (svc = scf_service_create(g_hndl)) == NULL ||
13843 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13844 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13845 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13846 	    (prop = scf_property_create(g_hndl)) == NULL ||
13847 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13848 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13849 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13850 		scfdie();
13851 
13852 	if (cur_snap != NULL) {
13853 		semerr(emsg_cant_modify_snapshots);
13854 		goto fail;
13855 	}
13856 
13857 	if (cur_inst == NULL && cur_svc == NULL) {
13858 		semerr(emsg_entity_not_selected);
13859 		goto fail;
13860 	}
13861 
13862 	propname = strchr(pgname, '/');
13863 	if (propname == NULL) {
13864 		semerr(gettext("Property names must contain a `/'.\n"));
13865 		goto fail;
13866 	}
13867 
13868 	*propname = '\0';
13869 	++propname;
13870 
13871 	if (type != NULL) {
13872 		ty = string_to_type(type);
13873 		if (ty == SCF_TYPE_INVALID) {
13874 			semerr(gettext("Unknown type \"%s\".\n"), type);
13875 			goto fail;
13876 		}
13877 	}
13878 
13879 	if (cur_inst != NULL)
13880 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13881 	else
13882 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13883 	if (ret != SCF_SUCCESS) {
13884 		switch (scf_error()) {
13885 		case SCF_ERROR_NOT_FOUND:
13886 			semerr(emsg_no_such_pg, pgname);
13887 			goto fail;
13888 
13889 		case SCF_ERROR_INVALID_ARGUMENT:
13890 			semerr(emsg_invalid_pg_name, pgname);
13891 			goto fail;
13892 
13893 		default:
13894 			scfdie();
13895 			break;
13896 		}
13897 	}
13898 
13899 	do {
13900 		if (scf_pg_update(pg) == -1)
13901 			scfdie();
13902 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13903 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13904 				scfdie();
13905 
13906 			semerr(emsg_permission_denied);
13907 			goto fail;
13908 		}
13909 
13910 		ret = scf_pg_get_property(pg, propname, prop);
13911 		if (ret == SCF_SUCCESS) {
13912 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13913 				scfdie();
13914 
13915 			if (type == NULL)
13916 				ty = current_ty;
13917 			if (scf_transaction_property_change_type(tx, e,
13918 			    propname, ty) == -1)
13919 				scfdie();
13920 
13921 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13922 			/* Infer the type, if possible. */
13923 			if (type == NULL) {
13924 				/*
13925 				 * First check if we're an instance and the
13926 				 * property is set on the service.
13927 				 */
13928 				if (cur_inst != NULL &&
13929 				    scf_instance_get_parent(cur_inst,
13930 				    svc) == 0 &&
13931 				    scf_service_get_pg(cur_svc, pgname,
13932 				    parent_pg) == 0 &&
13933 				    scf_pg_get_property(parent_pg, propname,
13934 				    parent_prop) == 0 &&
13935 				    scf_property_type(parent_prop,
13936 				    &current_ty) == 0) {
13937 					ty = current_ty;
13938 
13939 				/* Then check for a type set in a template. */
13940 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13941 				    0) == 0 &&
13942 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13943 				    0) == 0 &&
13944 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13945 					ty = current_ty;
13946 
13947 				/* If type can't be inferred, fail. */
13948 				} else {
13949 					semerr(gettext("Type required for new "
13950 					    "properties.\n"));
13951 					goto fail;
13952 				}
13953 			}
13954 			if (scf_transaction_property_new(tx, e, propname,
13955 			    ty) == -1)
13956 				scfdie();
13957 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13958 			semerr(emsg_invalid_prop_name, propname);
13959 			goto fail;
13960 		} else {
13961 			scfdie();
13962 		}
13963 
13964 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13965 			req_quotes = 1;
13966 
13967 		if (value != NULL) {
13968 			v = string_to_value(value, ty, 0);
13969 
13970 			if (v == NULL)
13971 				goto fail;
13972 
13973 			ret = scf_entry_add_value(e, v);
13974 			assert(ret == SCF_SUCCESS);
13975 		} else {
13976 			assert(values != NULL);
13977 
13978 			walk = uu_list_walk_start((uu_list_t *)values,
13979 			    UU_DEFAULT);
13980 			if (walk == NULL)
13981 				uu_die(gettext("Could not walk list"));
13982 
13983 			for (sp = uu_list_walk_next(walk); sp != NULL;
13984 			    sp = uu_list_walk_next(walk)) {
13985 				v = string_to_value(sp->str, ty, req_quotes);
13986 
13987 				if (v == NULL) {
13988 					scf_entry_destroy_children(e);
13989 					goto fail;
13990 				}
13991 
13992 				ret = scf_entry_add_value(e, v);
13993 				assert(ret == SCF_SUCCESS);
13994 			}
13995 			uu_list_walk_end(walk);
13996 		}
13997 		result = scf_transaction_commit(tx);
13998 
13999 		scf_transaction_reset(tx);
14000 		scf_entry_destroy_children(e);
14001 	} while (result == 0);
14002 
14003 	if (result < 0) {
14004 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14005 			scfdie();
14006 
14007 		semerr(emsg_permission_denied);
14008 		goto fail;
14009 	}
14010 
14011 	ret = 0;
14012 
14013 	private_refresh();
14014 
14015 	goto cleanup;
14016 
14017 fail:
14018 	ret = -1;
14019 
14020 cleanup:
14021 	scf_transaction_destroy(tx);
14022 	scf_entry_destroy(e);
14023 	scf_service_destroy(svc);
14024 	scf_pg_destroy(parent_pg);
14025 	scf_pg_destroy(pg);
14026 	scf_property_destroy(parent_prop);
14027 	scf_property_destroy(prop);
14028 	scf_tmpl_pg_destroy(pgt);
14029 	scf_tmpl_prop_destroy(prt);
14030 
14031 	return (ret);
14032 }
14033 
14034 void
14035 lscf_delprop(char *pgn)
14036 {
14037 	char *slash, *pn;
14038 	scf_propertygroup_t *pg;
14039 	scf_transaction_t *tx;
14040 	scf_transaction_entry_t *e;
14041 	int ret;
14042 
14043 
14044 	lscf_prep_hndl();
14045 
14046 	if (cur_snap != NULL) {
14047 		semerr(emsg_cant_modify_snapshots);
14048 		return;
14049 	}
14050 
14051 	if (cur_inst == NULL && cur_svc == NULL) {
14052 		semerr(emsg_entity_not_selected);
14053 		return;
14054 	}
14055 
14056 	pg = scf_pg_create(g_hndl);
14057 	if (pg == NULL)
14058 		scfdie();
14059 
14060 	slash = strchr(pgn, '/');
14061 	if (slash == NULL) {
14062 		pn = NULL;
14063 	} else {
14064 		*slash = '\0';
14065 		pn = slash + 1;
14066 	}
14067 
14068 	if (cur_inst != NULL)
14069 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
14070 	else
14071 		ret = scf_service_get_pg(cur_svc, pgn, pg);
14072 	if (ret != SCF_SUCCESS) {
14073 		switch (scf_error()) {
14074 		case SCF_ERROR_NOT_FOUND:
14075 			semerr(emsg_no_such_pg, pgn);
14076 			break;
14077 
14078 		case SCF_ERROR_INVALID_ARGUMENT:
14079 			semerr(emsg_invalid_pg_name, pgn);
14080 			break;
14081 
14082 		default:
14083 			scfdie();
14084 		}
14085 
14086 		scf_pg_destroy(pg);
14087 
14088 		return;
14089 	}
14090 
14091 	if (pn == NULL) {
14092 		/* Try to delete the property group. */
14093 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
14094 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14095 				scfdie();
14096 
14097 			semerr(emsg_permission_denied);
14098 		} else {
14099 			private_refresh();
14100 		}
14101 
14102 		scf_pg_destroy(pg);
14103 		return;
14104 	}
14105 
14106 	e = scf_entry_create(g_hndl);
14107 	tx = scf_transaction_create(g_hndl);
14108 
14109 	do {
14110 		if (scf_pg_update(pg) == -1)
14111 			scfdie();
14112 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14113 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14114 				scfdie();
14115 
14116 			semerr(emsg_permission_denied);
14117 			break;
14118 		}
14119 
14120 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14121 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
14122 				semerr(gettext("No such property %s/%s.\n"),
14123 				    pgn, pn);
14124 				break;
14125 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14126 				semerr(emsg_invalid_prop_name, pn);
14127 				break;
14128 			} else {
14129 				scfdie();
14130 			}
14131 		}
14132 
14133 		ret = scf_transaction_commit(tx);
14134 
14135 		if (ret == 0)
14136 			scf_transaction_reset(tx);
14137 	} while (ret == 0);
14138 
14139 	if (ret < 0) {
14140 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14141 			scfdie();
14142 
14143 		semerr(emsg_permission_denied);
14144 	} else {
14145 		private_refresh();
14146 	}
14147 
14148 	scf_transaction_destroy(tx);
14149 	scf_entry_destroy(e);
14150 	scf_pg_destroy(pg);
14151 }
14152 
14153 /*
14154  * Property editing.
14155  */
14156 
14157 static int
14158 write_edit_script(FILE *strm)
14159 {
14160 	char *fmribuf;
14161 	ssize_t fmrilen;
14162 
14163 	scf_propertygroup_t *pg;
14164 	scf_property_t *prop;
14165 	scf_value_t *val;
14166 	scf_type_t ty;
14167 	int ret, result = 0;
14168 	scf_iter_t *iter, *piter, *viter;
14169 	char *buf, *tybuf, *pname;
14170 	const char *emsg_write_error;
14171 
14172 
14173 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14174 
14175 
14176 	/* select fmri */
14177 	if (cur_inst != NULL) {
14178 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14179 		if (fmrilen < 0)
14180 			scfdie();
14181 		fmribuf = safe_malloc(fmrilen + 1);
14182 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14183 			scfdie();
14184 	} else {
14185 		assert(cur_svc != NULL);
14186 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14187 		if (fmrilen < 0)
14188 			scfdie();
14189 		fmribuf = safe_malloc(fmrilen + 1);
14190 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14191 			scfdie();
14192 	}
14193 
14194 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14195 		warn(emsg_write_error, strerror(errno));
14196 		free(fmribuf);
14197 		return (-1);
14198 	}
14199 
14200 	free(fmribuf);
14201 
14202 
14203 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
14204 	    (prop = scf_property_create(g_hndl)) == NULL ||
14205 	    (val = scf_value_create(g_hndl)) == NULL ||
14206 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14207 	    (piter = scf_iter_create(g_hndl)) == NULL ||
14208 	    (viter = scf_iter_create(g_hndl)) == NULL)
14209 		scfdie();
14210 
14211 	buf = safe_malloc(max_scf_name_len + 1);
14212 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
14213 	pname = safe_malloc(max_scf_name_len + 1);
14214 
14215 	if (cur_inst != NULL)
14216 		ret = scf_iter_instance_pgs(iter, cur_inst);
14217 	else
14218 		ret = scf_iter_service_pgs(iter, cur_svc);
14219 	if (ret != SCF_SUCCESS)
14220 		scfdie();
14221 
14222 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14223 		int ret2;
14224 
14225 		/*
14226 		 * # delprop pg
14227 		 * # addpg pg type
14228 		 */
14229 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14230 			scfdie();
14231 
14232 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14233 			scfdie();
14234 
14235 		if (fprintf(strm, "# Property group \"%s\"\n"
14236 		    "# delprop %s\n"
14237 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14238 			warn(emsg_write_error, strerror(errno));
14239 			result = -1;
14240 			goto out;
14241 		}
14242 
14243 		/* # setprop pg/prop = (values) */
14244 
14245 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14246 			scfdie();
14247 
14248 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14249 			int first = 1;
14250 			int ret3;
14251 			int multiple;
14252 			int is_str;
14253 			scf_type_t bty;
14254 
14255 			if (scf_property_get_name(prop, pname,
14256 			    max_scf_name_len + 1) < 0)
14257 				scfdie();
14258 
14259 			if (scf_property_type(prop, &ty) != 0)
14260 				scfdie();
14261 
14262 			multiple = prop_has_multiple_values(prop, val);
14263 
14264 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14265 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
14266 			    < 0) {
14267 				warn(emsg_write_error, strerror(errno));
14268 				result = -1;
14269 				goto out;
14270 			}
14271 
14272 			(void) scf_type_base_type(ty, &bty);
14273 			is_str = (bty == SCF_TYPE_ASTRING);
14274 
14275 			if (scf_iter_property_values(viter, prop) !=
14276 			    SCF_SUCCESS)
14277 				scfdie();
14278 
14279 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14280 				char *buf;
14281 				ssize_t buflen;
14282 
14283 				buflen = scf_value_get_as_string(val, NULL, 0);
14284 				if (buflen < 0)
14285 					scfdie();
14286 
14287 				buf = safe_malloc(buflen + 1);
14288 
14289 				if (scf_value_get_as_string(val, buf,
14290 				    buflen + 1) < 0)
14291 					scfdie();
14292 
14293 				if (first)
14294 					first = 0;
14295 				else {
14296 					if (putc(' ', strm) != ' ') {
14297 						warn(emsg_write_error,
14298 						    strerror(errno));
14299 						result = -1;
14300 						goto out;
14301 					}
14302 				}
14303 
14304 				if ((is_str && multiple) ||
14305 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14306 					(void) putc('"', strm);
14307 					(void) quote_and_print(buf, strm, 1);
14308 					(void) putc('"', strm);
14309 
14310 					if (ferror(strm)) {
14311 						warn(emsg_write_error,
14312 						    strerror(errno));
14313 						result = -1;
14314 						goto out;
14315 					}
14316 				} else {
14317 					if (fprintf(strm, "%s", buf) < 0) {
14318 						warn(emsg_write_error,
14319 						    strerror(errno));
14320 						result = -1;
14321 						goto out;
14322 					}
14323 				}
14324 
14325 				free(buf);
14326 			}
14327 			if (ret3 < 0 &&
14328 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14329 				scfdie();
14330 
14331 			/* Write closing paren if mult-value property */
14332 			if ((multiple && putc(')', strm) == EOF) ||
14333 
14334 			    /* Write final newline */
14335 			    fputc('\n', strm) == EOF) {
14336 				warn(emsg_write_error, strerror(errno));
14337 				result = -1;
14338 				goto out;
14339 			}
14340 		}
14341 		if (ret2 < 0)
14342 			scfdie();
14343 
14344 		if (fputc('\n', strm) == EOF) {
14345 			warn(emsg_write_error, strerror(errno));
14346 			result = -1;
14347 			goto out;
14348 		}
14349 	}
14350 	if (ret < 0)
14351 		scfdie();
14352 
14353 out:
14354 	free(pname);
14355 	free(tybuf);
14356 	free(buf);
14357 	scf_iter_destroy(viter);
14358 	scf_iter_destroy(piter);
14359 	scf_iter_destroy(iter);
14360 	scf_value_destroy(val);
14361 	scf_property_destroy(prop);
14362 	scf_pg_destroy(pg);
14363 
14364 	if (result == 0) {
14365 		if (fflush(strm) != 0) {
14366 			warn(emsg_write_error, strerror(errno));
14367 			return (-1);
14368 		}
14369 	}
14370 
14371 	return (result);
14372 }
14373 
14374 int
14375 lscf_editprop()
14376 {
14377 	char *buf, *editor;
14378 	size_t bufsz;
14379 	int tmpfd;
14380 	char tempname[] = TEMP_FILE_PATTERN;
14381 
14382 	lscf_prep_hndl();
14383 
14384 	if (cur_snap != NULL) {
14385 		semerr(emsg_cant_modify_snapshots);
14386 		return (-1);
14387 	}
14388 
14389 	if (cur_svc == NULL && cur_inst == NULL) {
14390 		semerr(emsg_entity_not_selected);
14391 		return (-1);
14392 	}
14393 
14394 	tmpfd = mkstemp(tempname);
14395 	if (tmpfd == -1) {
14396 		semerr(gettext("Could not create temporary file.\n"));
14397 		return (-1);
14398 	}
14399 
14400 	(void) strcpy(tempfilename, tempname);
14401 
14402 	tempfile = fdopen(tmpfd, "r+");
14403 	if (tempfile == NULL) {
14404 		warn(gettext("Could not create temporary file.\n"));
14405 		if (close(tmpfd) == -1)
14406 			warn(gettext("Could not close temporary file: %s.\n"),
14407 			    strerror(errno));
14408 
14409 		remove_tempfile();
14410 
14411 		return (-1);
14412 	}
14413 
14414 	if (write_edit_script(tempfile) == -1) {
14415 		remove_tempfile();
14416 		return (-1);
14417 	}
14418 
14419 	editor = getenv("EDITOR");
14420 	if (editor == NULL)
14421 		editor = "vi";
14422 
14423 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14424 	buf = safe_malloc(bufsz);
14425 
14426 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14427 		uu_die(gettext("Error creating editor command"));
14428 
14429 	if (system(buf) == -1) {
14430 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14431 		    strerror(errno));
14432 		free(buf);
14433 		remove_tempfile();
14434 		return (-1);
14435 	}
14436 
14437 	free(buf);
14438 
14439 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14440 
14441 	remove_tempfile();
14442 
14443 	return (0);
14444 }
14445 
14446 static void
14447 add_string(uu_list_t *strlist, const char *str)
14448 {
14449 	string_list_t *elem;
14450 	elem = safe_malloc(sizeof (*elem));
14451 	uu_list_node_init(elem, &elem->node, string_pool);
14452 	elem->str = safe_strdup(str);
14453 	if (uu_list_append(strlist, elem) != 0)
14454 		uu_die(gettext("libuutil error: %s\n"),
14455 		    uu_strerror(uu_error()));
14456 }
14457 
14458 static int
14459 remove_string(uu_list_t *strlist, const char *str)
14460 {
14461 	uu_list_walk_t	*elems;
14462 	string_list_t	*sp;
14463 
14464 	/*
14465 	 * Find the element that needs to be removed.
14466 	 */
14467 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14468 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14469 		if (strcmp(sp->str, str) == 0)
14470 			break;
14471 	}
14472 	uu_list_walk_end(elems);
14473 
14474 	/*
14475 	 * Returning 1 here as the value was not found, this
14476 	 * might not be an error.  Leave it to the caller to
14477 	 * decide.
14478 	 */
14479 	if (sp == NULL) {
14480 		return (1);
14481 	}
14482 
14483 	uu_list_remove(strlist, sp);
14484 
14485 	free(sp->str);
14486 	free(sp);
14487 
14488 	return (0);
14489 }
14490 
14491 /*
14492  * Get all property values that don't match the given glob pattern,
14493  * if a pattern is specified.
14494  */
14495 static void
14496 get_prop_values(scf_property_t *prop, uu_list_t *values,
14497     const char *pattern)
14498 {
14499 	scf_iter_t *iter;
14500 	scf_value_t *val;
14501 	int ret;
14502 
14503 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14504 	    (val = scf_value_create(g_hndl)) == NULL)
14505 		scfdie();
14506 
14507 	if (scf_iter_property_values(iter, prop) != 0)
14508 		scfdie();
14509 
14510 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14511 		char *buf;
14512 		ssize_t vlen, szret;
14513 
14514 		vlen = scf_value_get_as_string(val, NULL, 0);
14515 		if (vlen < 0)
14516 			scfdie();
14517 
14518 		buf = safe_malloc(vlen + 1);
14519 
14520 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14521 		if (szret < 0)
14522 			scfdie();
14523 		assert(szret <= vlen);
14524 
14525 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14526 			add_string(values, buf);
14527 
14528 		free(buf);
14529 	}
14530 
14531 	if (ret == -1)
14532 		scfdie();
14533 
14534 	scf_value_destroy(val);
14535 	scf_iter_destroy(iter);
14536 }
14537 
14538 static int
14539 lscf_setpropvalue(const char *pgname, const char *type,
14540     const char *arg, int isadd, int isnotfoundok)
14541 {
14542 	scf_type_t ty;
14543 	scf_propertygroup_t *pg;
14544 	scf_property_t *prop;
14545 	int ret, result = 0;
14546 	scf_transaction_t *tx;
14547 	scf_transaction_entry_t *e;
14548 	scf_value_t *v;
14549 	string_list_t *sp;
14550 	char *propname;
14551 	uu_list_t *values;
14552 	uu_list_walk_t *walk;
14553 	void *cookie = NULL;
14554 	char *pattern = NULL;
14555 
14556 	lscf_prep_hndl();
14557 
14558 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14559 		uu_die(gettext("Could not create property list: %s\n"),
14560 		    uu_strerror(uu_error()));
14561 
14562 	if (!isadd)
14563 		pattern = safe_strdup(arg);
14564 
14565 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14566 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14567 	    (prop = scf_property_create(g_hndl)) == NULL ||
14568 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14569 		scfdie();
14570 
14571 	if (cur_snap != NULL) {
14572 		semerr(emsg_cant_modify_snapshots);
14573 		goto fail;
14574 	}
14575 
14576 	if (cur_inst == NULL && cur_svc == NULL) {
14577 		semerr(emsg_entity_not_selected);
14578 		goto fail;
14579 	}
14580 
14581 	propname = strchr(pgname, '/');
14582 	if (propname == NULL) {
14583 		semerr(gettext("Property names must contain a `/'.\n"));
14584 		goto fail;
14585 	}
14586 
14587 	*propname = '\0';
14588 	++propname;
14589 
14590 	if (type != NULL) {
14591 		ty = string_to_type(type);
14592 		if (ty == SCF_TYPE_INVALID) {
14593 			semerr(gettext("Unknown type \"%s\".\n"), type);
14594 			goto fail;
14595 		}
14596 	}
14597 
14598 	if (cur_inst != NULL)
14599 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14600 	else
14601 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14602 	if (ret != 0) {
14603 		switch (scf_error()) {
14604 		case SCF_ERROR_NOT_FOUND:
14605 			if (isnotfoundok) {
14606 				result = 0;
14607 			} else {
14608 				semerr(emsg_no_such_pg, pgname);
14609 				result = -1;
14610 			}
14611 			goto out;
14612 
14613 		case SCF_ERROR_INVALID_ARGUMENT:
14614 			semerr(emsg_invalid_pg_name, pgname);
14615 			goto fail;
14616 
14617 		default:
14618 			scfdie();
14619 		}
14620 	}
14621 
14622 	do {
14623 		if (scf_pg_update(pg) == -1)
14624 			scfdie();
14625 		if (scf_transaction_start(tx, pg) != 0) {
14626 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14627 				scfdie();
14628 
14629 			semerr(emsg_permission_denied);
14630 			goto fail;
14631 		}
14632 
14633 		ret = scf_pg_get_property(pg, propname, prop);
14634 		if (ret == 0) {
14635 			scf_type_t ptype;
14636 			char *pat = pattern;
14637 
14638 			if (scf_property_type(prop, &ptype) != 0)
14639 				scfdie();
14640 
14641 			if (isadd) {
14642 				if (type != NULL && ptype != ty) {
14643 					semerr(gettext("Property \"%s\" is not "
14644 					    "of type \"%s\".\n"), propname,
14645 					    type);
14646 					goto fail;
14647 				}
14648 
14649 				pat = NULL;
14650 			} else {
14651 				size_t len = strlen(pat);
14652 				if (len > 0 && pat[len - 1] == '\"')
14653 					pat[len - 1] = '\0';
14654 				if (len > 0 && pat[0] == '\"')
14655 					pat++;
14656 			}
14657 
14658 			ty = ptype;
14659 
14660 			get_prop_values(prop, values, pat);
14661 
14662 			if (isadd)
14663 				add_string(values, arg);
14664 
14665 			if (scf_transaction_property_change(tx, e,
14666 			    propname, ty) == -1)
14667 				scfdie();
14668 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14669 			if (isadd) {
14670 				if (type == NULL) {
14671 					semerr(gettext("Type required "
14672 					    "for new properties.\n"));
14673 					goto fail;
14674 				}
14675 
14676 				add_string(values, arg);
14677 
14678 				if (scf_transaction_property_new(tx, e,
14679 				    propname, ty) == -1)
14680 					scfdie();
14681 			} else if (isnotfoundok) {
14682 				result = 0;
14683 				goto out;
14684 			} else {
14685 				semerr(gettext("No such property %s/%s.\n"),
14686 				    pgname, propname);
14687 				result = -1;
14688 				goto out;
14689 			}
14690 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14691 			semerr(emsg_invalid_prop_name, propname);
14692 			goto fail;
14693 		} else {
14694 			scfdie();
14695 		}
14696 
14697 		walk = uu_list_walk_start(values, UU_DEFAULT);
14698 		if (walk == NULL)
14699 			uu_die(gettext("Could not walk property list.\n"));
14700 
14701 		for (sp = uu_list_walk_next(walk); sp != NULL;
14702 		    sp = uu_list_walk_next(walk)) {
14703 			v = string_to_value(sp->str, ty, 0);
14704 
14705 			if (v == NULL) {
14706 				scf_entry_destroy_children(e);
14707 				goto fail;
14708 			}
14709 			ret = scf_entry_add_value(e, v);
14710 			assert(ret == 0);
14711 		}
14712 		uu_list_walk_end(walk);
14713 
14714 		result = scf_transaction_commit(tx);
14715 
14716 		scf_transaction_reset(tx);
14717 		scf_entry_destroy_children(e);
14718 	} while (result == 0);
14719 
14720 	if (result < 0) {
14721 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14722 			scfdie();
14723 
14724 		semerr(emsg_permission_denied);
14725 		goto fail;
14726 	}
14727 
14728 	result = 0;
14729 
14730 	private_refresh();
14731 
14732 out:
14733 	scf_transaction_destroy(tx);
14734 	scf_entry_destroy(e);
14735 	scf_pg_destroy(pg);
14736 	scf_property_destroy(prop);
14737 	free(pattern);
14738 
14739 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14740 		free(sp->str);
14741 		free(sp);
14742 	}
14743 
14744 	uu_list_destroy(values);
14745 
14746 	return (result);
14747 
14748 fail:
14749 	result = -1;
14750 	goto out;
14751 }
14752 
14753 int
14754 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14755 {
14756 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14757 }
14758 
14759 int
14760 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14761 {
14762 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14763 }
14764 
14765 /*
14766  * Look for a standard start method, first in the instance (if any),
14767  * then the service.
14768  */
14769 static const char *
14770 start_method_name(int *in_instance)
14771 {
14772 	scf_propertygroup_t *pg;
14773 	char **p;
14774 	int ret;
14775 	scf_instance_t *inst = cur_inst;
14776 
14777 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14778 		scfdie();
14779 
14780 again:
14781 	for (p = start_method_names; *p != NULL; p++) {
14782 		if (inst != NULL)
14783 			ret = scf_instance_get_pg(inst, *p, pg);
14784 		else
14785 			ret = scf_service_get_pg(cur_svc, *p, pg);
14786 
14787 		if (ret == 0) {
14788 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14789 			char *buf = safe_malloc(bufsz);
14790 
14791 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14792 				free(buf);
14793 				continue;
14794 			}
14795 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14796 				free(buf);
14797 				continue;
14798 			}
14799 
14800 			free(buf);
14801 			*in_instance = (inst != NULL);
14802 			scf_pg_destroy(pg);
14803 			return (*p);
14804 		}
14805 
14806 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14807 			continue;
14808 
14809 		scfdie();
14810 	}
14811 
14812 	if (inst != NULL) {
14813 		inst = NULL;
14814 		goto again;
14815 	}
14816 
14817 	scf_pg_destroy(pg);
14818 	return (NULL);
14819 }
14820 
14821 static int
14822 addpg(const char *name, const char *type)
14823 {
14824 	scf_propertygroup_t *pg;
14825 	int ret;
14826 
14827 	pg = scf_pg_create(g_hndl);
14828 	if (pg == NULL)
14829 		scfdie();
14830 
14831 	if (cur_inst != NULL)
14832 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14833 	else
14834 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14835 
14836 	if (ret != 0) {
14837 		switch (scf_error()) {
14838 		case SCF_ERROR_EXISTS:
14839 			ret = 0;
14840 			break;
14841 
14842 		case SCF_ERROR_PERMISSION_DENIED:
14843 			semerr(emsg_permission_denied);
14844 			break;
14845 
14846 		default:
14847 			scfdie();
14848 		}
14849 	}
14850 
14851 	scf_pg_destroy(pg);
14852 	return (ret);
14853 }
14854 
14855 int
14856 lscf_setenv(uu_list_t *args, int isunset)
14857 {
14858 	int ret = 0;
14859 	size_t i;
14860 	int argc;
14861 	char **argv = NULL;
14862 	string_list_t *slp;
14863 	char *pattern;
14864 	char *prop;
14865 	int do_service = 0;
14866 	int do_instance = 0;
14867 	const char *method = NULL;
14868 	const char *name = NULL;
14869 	const char *value = NULL;
14870 	scf_instance_t *saved_cur_inst = cur_inst;
14871 
14872 	lscf_prep_hndl();
14873 
14874 	argc = uu_list_numnodes(args);
14875 	if (argc < 1)
14876 		goto usage;
14877 
14878 	argv = calloc(argc + 1, sizeof (char *));
14879 	if (argv == NULL)
14880 		uu_die(gettext("Out of memory.\n"));
14881 
14882 	for (slp = uu_list_first(args), i = 0;
14883 	    slp != NULL;
14884 	    slp = uu_list_next(args, slp), ++i)
14885 		argv[i] = slp->str;
14886 
14887 	argv[i] = NULL;
14888 
14889 	opterr = 0;
14890 	optind = 0;
14891 	for (;;) {
14892 		ret = getopt(argc, argv, "sim:");
14893 		if (ret == -1)
14894 			break;
14895 
14896 		switch (ret) {
14897 		case 's':
14898 			do_service = 1;
14899 			cur_inst = NULL;
14900 			break;
14901 
14902 		case 'i':
14903 			do_instance = 1;
14904 			break;
14905 
14906 		case 'm':
14907 			method = optarg;
14908 			break;
14909 
14910 		case '?':
14911 			goto usage;
14912 
14913 		default:
14914 			bad_error("getopt", ret);
14915 		}
14916 	}
14917 
14918 	argc -= optind;
14919 	if ((do_service && do_instance) ||
14920 	    (isunset && argc != 1) ||
14921 	    (!isunset && argc != 2))
14922 		goto usage;
14923 
14924 	name = argv[optind];
14925 	if (!isunset)
14926 		value = argv[optind + 1];
14927 
14928 	if (cur_snap != NULL) {
14929 		semerr(emsg_cant_modify_snapshots);
14930 		ret = -1;
14931 		goto out;
14932 	}
14933 
14934 	if (cur_inst == NULL && cur_svc == NULL) {
14935 		semerr(emsg_entity_not_selected);
14936 		ret = -1;
14937 		goto out;
14938 	}
14939 
14940 	if (do_instance && cur_inst == NULL) {
14941 		semerr(gettext("No instance is selected.\n"));
14942 		ret = -1;
14943 		goto out;
14944 	}
14945 
14946 	if (do_service && cur_svc == NULL) {
14947 		semerr(gettext("No service is selected.\n"));
14948 		ret = -1;
14949 		goto out;
14950 	}
14951 
14952 	if (method == NULL) {
14953 		if (do_instance || do_service) {
14954 			method = "method_context";
14955 			if (!isunset) {
14956 				ret = addpg("method_context",
14957 				    SCF_GROUP_FRAMEWORK);
14958 				if (ret != 0)
14959 					goto out;
14960 			}
14961 		} else {
14962 			int in_instance;
14963 			method = start_method_name(&in_instance);
14964 			if (method == NULL) {
14965 				semerr(gettext(
14966 				    "Couldn't find start method; please "
14967 				    "specify a method with '-m'.\n"));
14968 				ret = -1;
14969 				goto out;
14970 			}
14971 			if (!in_instance)
14972 				cur_inst = NULL;
14973 		}
14974 	} else {
14975 		scf_propertygroup_t *pg;
14976 		size_t bufsz;
14977 		char *buf;
14978 		int ret;
14979 
14980 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14981 			scfdie();
14982 
14983 		if (cur_inst != NULL)
14984 			ret = scf_instance_get_pg(cur_inst, method, pg);
14985 		else
14986 			ret = scf_service_get_pg(cur_svc, method, pg);
14987 
14988 		if (ret != 0) {
14989 			scf_pg_destroy(pg);
14990 			switch (scf_error()) {
14991 			case SCF_ERROR_NOT_FOUND:
14992 				semerr(gettext("Couldn't find the method "
14993 				    "\"%s\".\n"), method);
14994 				goto out;
14995 
14996 			case SCF_ERROR_INVALID_ARGUMENT:
14997 				semerr(gettext("Invalid method name \"%s\".\n"),
14998 				    method);
14999 				goto out;
15000 
15001 			default:
15002 				scfdie();
15003 			}
15004 		}
15005 
15006 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
15007 		buf = safe_malloc(bufsz);
15008 
15009 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15010 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
15011 			semerr(gettext("Property group \"%s\" is not of type "
15012 			    "\"method\".\n"), method);
15013 			ret = -1;
15014 			free(buf);
15015 			scf_pg_destroy(pg);
15016 			goto out;
15017 		}
15018 
15019 		free(buf);
15020 		scf_pg_destroy(pg);
15021 	}
15022 
15023 	prop = uu_msprintf("%s/environment", method);
15024 	pattern = uu_msprintf("%s=*", name);
15025 
15026 	if (prop == NULL || pattern == NULL)
15027 		uu_die(gettext("Out of memory.\n"));
15028 
15029 	ret = lscf_delpropvalue(prop, pattern, !isunset);
15030 
15031 	if (ret == 0 && !isunset) {
15032 		uu_free(pattern);
15033 		uu_free(prop);
15034 		prop = uu_msprintf("%s/environment", method);
15035 		pattern = uu_msprintf("%s=%s", name, value);
15036 		if (prop == NULL || pattern == NULL)
15037 			uu_die(gettext("Out of memory.\n"));
15038 		ret = lscf_addpropvalue(prop, "astring:", pattern);
15039 	}
15040 	uu_free(pattern);
15041 	uu_free(prop);
15042 
15043 out:
15044 	cur_inst = saved_cur_inst;
15045 
15046 	free(argv);
15047 	return (ret);
15048 usage:
15049 	ret = -2;
15050 	goto out;
15051 }
15052 
15053 /*
15054  * Snapshot commands
15055  */
15056 
15057 void
15058 lscf_listsnap()
15059 {
15060 	scf_snapshot_t *snap;
15061 	scf_iter_t *iter;
15062 	char *nb;
15063 	int r;
15064 
15065 	lscf_prep_hndl();
15066 
15067 	if (cur_inst == NULL) {
15068 		semerr(gettext("Instance not selected.\n"));
15069 		return;
15070 	}
15071 
15072 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15073 	    (iter = scf_iter_create(g_hndl)) == NULL)
15074 		scfdie();
15075 
15076 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15077 		scfdie();
15078 
15079 	nb = safe_malloc(max_scf_name_len + 1);
15080 
15081 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15082 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15083 			scfdie();
15084 
15085 		(void) puts(nb);
15086 	}
15087 	if (r < 0)
15088 		scfdie();
15089 
15090 	free(nb);
15091 	scf_iter_destroy(iter);
15092 	scf_snapshot_destroy(snap);
15093 }
15094 
15095 void
15096 lscf_selectsnap(const char *name)
15097 {
15098 	scf_snapshot_t *snap;
15099 	scf_snaplevel_t *level;
15100 
15101 	lscf_prep_hndl();
15102 
15103 	if (cur_inst == NULL) {
15104 		semerr(gettext("Instance not selected.\n"));
15105 		return;
15106 	}
15107 
15108 	if (cur_snap != NULL) {
15109 		if (name != NULL) {
15110 			char *cur_snap_name;
15111 			boolean_t nochange;
15112 
15113 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
15114 
15115 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15116 			    max_scf_name_len + 1) < 0)
15117 				scfdie();
15118 
15119 			nochange = strcmp(name, cur_snap_name) == 0;
15120 
15121 			free(cur_snap_name);
15122 
15123 			if (nochange)
15124 				return;
15125 		}
15126 
15127 		unselect_cursnap();
15128 	}
15129 
15130 	if (name == NULL)
15131 		return;
15132 
15133 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15134 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
15135 		scfdie();
15136 
15137 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15138 	    SCF_SUCCESS) {
15139 		switch (scf_error()) {
15140 		case SCF_ERROR_INVALID_ARGUMENT:
15141 			semerr(gettext("Invalid name \"%s\".\n"), name);
15142 			break;
15143 
15144 		case SCF_ERROR_NOT_FOUND:
15145 			semerr(gettext("No such snapshot \"%s\".\n"), name);
15146 			break;
15147 
15148 		default:
15149 			scfdie();
15150 		}
15151 
15152 		scf_snaplevel_destroy(level);
15153 		scf_snapshot_destroy(snap);
15154 		return;
15155 	}
15156 
15157 	/* Load the snaplevels into our list. */
15158 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15159 	if (cur_levels == NULL)
15160 		uu_die(gettext("Could not create list: %s\n"),
15161 		    uu_strerror(uu_error()));
15162 
15163 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15164 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15165 			scfdie();
15166 
15167 		semerr(gettext("Snapshot has no snaplevels.\n"));
15168 
15169 		scf_snaplevel_destroy(level);
15170 		scf_snapshot_destroy(snap);
15171 		return;
15172 	}
15173 
15174 	cur_snap = snap;
15175 
15176 	for (;;) {
15177 		cur_elt = safe_malloc(sizeof (*cur_elt));
15178 		uu_list_node_init(cur_elt, &cur_elt->list_node,
15179 		    snaplevel_pool);
15180 		cur_elt->sl = level;
15181 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15182 			uu_die(gettext("libuutil error: %s\n"),
15183 			    uu_strerror(uu_error()));
15184 
15185 		level = scf_snaplevel_create(g_hndl);
15186 		if (level == NULL)
15187 			scfdie();
15188 
15189 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15190 		    level) != SCF_SUCCESS) {
15191 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15192 				scfdie();
15193 
15194 			scf_snaplevel_destroy(level);
15195 			break;
15196 		}
15197 	}
15198 
15199 	cur_elt = uu_list_last(cur_levels);
15200 	cur_level = cur_elt->sl;
15201 }
15202 
15203 /*
15204  * Copies the properties & values in src to dst.  Assumes src won't change.
15205  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15206  * and 0 on success.
15207  *
15208  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15209  * property, if it is copied and has type boolean.  (See comment in
15210  * lscf_revert()).
15211  */
15212 static int
15213 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15214     uint8_t enabled)
15215 {
15216 	scf_transaction_t *tx;
15217 	scf_iter_t *iter, *viter;
15218 	scf_property_t *prop;
15219 	scf_value_t *v;
15220 	char *nbuf;
15221 	int r;
15222 
15223 	tx = scf_transaction_create(g_hndl);
15224 	if (tx == NULL)
15225 		scfdie();
15226 
15227 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15228 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15229 			scfdie();
15230 
15231 		scf_transaction_destroy(tx);
15232 
15233 		return (-1);
15234 	}
15235 
15236 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
15237 	    (prop = scf_property_create(g_hndl)) == NULL ||
15238 	    (viter = scf_iter_create(g_hndl)) == NULL)
15239 		scfdie();
15240 
15241 	nbuf = safe_malloc(max_scf_name_len + 1);
15242 
15243 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15244 		scfdie();
15245 
15246 	for (;;) {
15247 		scf_transaction_entry_t *e;
15248 		scf_type_t ty;
15249 
15250 		r = scf_iter_next_property(iter, prop);
15251 		if (r == -1)
15252 			scfdie();
15253 		if (r == 0)
15254 			break;
15255 
15256 		e = scf_entry_create(g_hndl);
15257 		if (e == NULL)
15258 			scfdie();
15259 
15260 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15261 			scfdie();
15262 
15263 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15264 			scfdie();
15265 
15266 		if (scf_transaction_property_new(tx, e, nbuf,
15267 		    ty) != SCF_SUCCESS)
15268 			scfdie();
15269 
15270 		if ((enabled == 0 || enabled == 1) &&
15271 		    strcmp(nbuf, scf_property_enabled) == 0 &&
15272 		    ty == SCF_TYPE_BOOLEAN) {
15273 			v = scf_value_create(g_hndl);
15274 			if (v == NULL)
15275 				scfdie();
15276 
15277 			scf_value_set_boolean(v, enabled);
15278 
15279 			if (scf_entry_add_value(e, v) != 0)
15280 				scfdie();
15281 		} else {
15282 			if (scf_iter_property_values(viter, prop) != 0)
15283 				scfdie();
15284 
15285 			for (;;) {
15286 				v = scf_value_create(g_hndl);
15287 				if (v == NULL)
15288 					scfdie();
15289 
15290 				r = scf_iter_next_value(viter, v);
15291 				if (r == -1)
15292 					scfdie();
15293 				if (r == 0) {
15294 					scf_value_destroy(v);
15295 					break;
15296 				}
15297 
15298 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15299 					scfdie();
15300 			}
15301 		}
15302 	}
15303 
15304 	free(nbuf);
15305 	scf_iter_destroy(viter);
15306 	scf_property_destroy(prop);
15307 	scf_iter_destroy(iter);
15308 
15309 	r = scf_transaction_commit(tx);
15310 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15311 		scfdie();
15312 
15313 	scf_transaction_destroy_children(tx);
15314 	scf_transaction_destroy(tx);
15315 
15316 	switch (r) {
15317 	case 1:		return (0);
15318 	case 0:		return (-2);
15319 	case -1:	return (-1);
15320 
15321 	default:
15322 		abort();
15323 	}
15324 
15325 	/* NOTREACHED */
15326 }
15327 
15328 void
15329 lscf_revert(const char *snapname)
15330 {
15331 	scf_snapshot_t *snap, *prev;
15332 	scf_snaplevel_t *level, *nlevel;
15333 	scf_iter_t *iter;
15334 	scf_propertygroup_t *pg, *npg;
15335 	scf_property_t *prop;
15336 	scf_value_t *val;
15337 	char *nbuf, *tbuf;
15338 	uint8_t enabled;
15339 
15340 	lscf_prep_hndl();
15341 
15342 	if (cur_inst == NULL) {
15343 		semerr(gettext("Instance not selected.\n"));
15344 		return;
15345 	}
15346 
15347 	if (snapname != NULL) {
15348 		snap = scf_snapshot_create(g_hndl);
15349 		if (snap == NULL)
15350 			scfdie();
15351 
15352 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15353 		    SCF_SUCCESS) {
15354 			switch (scf_error()) {
15355 			case SCF_ERROR_INVALID_ARGUMENT:
15356 				semerr(gettext("Invalid snapshot name "
15357 				    "\"%s\".\n"), snapname);
15358 				break;
15359 
15360 			case SCF_ERROR_NOT_FOUND:
15361 				semerr(gettext("No such snapshot.\n"));
15362 				break;
15363 
15364 			default:
15365 				scfdie();
15366 			}
15367 
15368 			scf_snapshot_destroy(snap);
15369 			return;
15370 		}
15371 	} else {
15372 		if (cur_snap != NULL) {
15373 			snap = cur_snap;
15374 		} else {
15375 			semerr(gettext("No snapshot selected.\n"));
15376 			return;
15377 		}
15378 	}
15379 
15380 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15381 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15382 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15383 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15384 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15385 	    (prop = scf_property_create(g_hndl)) == NULL ||
15386 	    (val = scf_value_create(g_hndl)) == NULL)
15387 		scfdie();
15388 
15389 	nbuf = safe_malloc(max_scf_name_len + 1);
15390 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15391 
15392 	/* Take the "previous" snapshot before we blow away the properties. */
15393 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15394 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15395 			scfdie();
15396 	} else {
15397 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15398 			scfdie();
15399 
15400 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15401 			scfdie();
15402 	}
15403 
15404 	/* Save general/enabled, since we're probably going to replace it. */
15405 	enabled = 2;
15406 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15407 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15408 	    scf_property_get_value(prop, val) == 0)
15409 		(void) scf_value_get_boolean(val, &enabled);
15410 
15411 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15412 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15413 			scfdie();
15414 
15415 		goto out;
15416 	}
15417 
15418 	for (;;) {
15419 		boolean_t isinst;
15420 		uint32_t flags;
15421 		int r;
15422 
15423 		/* Clear the properties from the corresponding entity. */
15424 		isinst = snaplevel_is_instance(level);
15425 
15426 		if (!isinst)
15427 			r = scf_iter_service_pgs(iter, cur_svc);
15428 		else
15429 			r = scf_iter_instance_pgs(iter, cur_inst);
15430 		if (r != SCF_SUCCESS)
15431 			scfdie();
15432 
15433 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15434 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15435 				scfdie();
15436 
15437 			/* Skip nonpersistent pgs. */
15438 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15439 				continue;
15440 
15441 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15442 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15443 					scfdie();
15444 
15445 				semerr(emsg_permission_denied);
15446 				goto out;
15447 			}
15448 		}
15449 		if (r == -1)
15450 			scfdie();
15451 
15452 		/* Copy the properties to the corresponding entity. */
15453 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15454 			scfdie();
15455 
15456 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15457 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15458 				scfdie();
15459 
15460 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15461 			    0)
15462 				scfdie();
15463 
15464 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15465 				scfdie();
15466 
15467 			if (!isinst)
15468 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15469 				    flags, npg);
15470 			else
15471 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15472 				    flags, npg);
15473 			if (r != SCF_SUCCESS) {
15474 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15475 					scfdie();
15476 
15477 				semerr(emsg_permission_denied);
15478 				goto out;
15479 			}
15480 
15481 			if ((enabled == 0 || enabled == 1) &&
15482 			    strcmp(nbuf, scf_pg_general) == 0)
15483 				r = pg_copy(pg, npg, enabled);
15484 			else
15485 				r = pg_copy(pg, npg, 2);
15486 
15487 			switch (r) {
15488 			case 0:
15489 				break;
15490 
15491 			case -1:
15492 				semerr(emsg_permission_denied);
15493 				goto out;
15494 
15495 			case -2:
15496 				semerr(gettext(
15497 				    "Interrupted by another change.\n"));
15498 				goto out;
15499 
15500 			default:
15501 				abort();
15502 			}
15503 		}
15504 		if (r == -1)
15505 			scfdie();
15506 
15507 		/* Get next level. */
15508 		nlevel = scf_snaplevel_create(g_hndl);
15509 		if (nlevel == NULL)
15510 			scfdie();
15511 
15512 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15513 		    SCF_SUCCESS) {
15514 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15515 				scfdie();
15516 
15517 			scf_snaplevel_destroy(nlevel);
15518 			break;
15519 		}
15520 
15521 		scf_snaplevel_destroy(level);
15522 		level = nlevel;
15523 	}
15524 
15525 	if (snapname == NULL) {
15526 		lscf_selectsnap(NULL);
15527 		snap = NULL;		/* cur_snap has been destroyed */
15528 	}
15529 
15530 out:
15531 	free(tbuf);
15532 	free(nbuf);
15533 	scf_value_destroy(val);
15534 	scf_property_destroy(prop);
15535 	scf_pg_destroy(npg);
15536 	scf_pg_destroy(pg);
15537 	scf_iter_destroy(iter);
15538 	scf_snaplevel_destroy(level);
15539 	scf_snapshot_destroy(prev);
15540 	if (snap != cur_snap)
15541 		scf_snapshot_destroy(snap);
15542 }
15543 
15544 void
15545 lscf_refresh(void)
15546 {
15547 	ssize_t fmrilen;
15548 	size_t bufsz;
15549 	char *fmribuf;
15550 	int r;
15551 
15552 	lscf_prep_hndl();
15553 
15554 	if (cur_inst == NULL) {
15555 		semerr(gettext("Instance not selected.\n"));
15556 		return;
15557 	}
15558 
15559 	bufsz = max_scf_fmri_len + 1;
15560 	fmribuf = safe_malloc(bufsz);
15561 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15562 	if (fmrilen < 0) {
15563 		free(fmribuf);
15564 		if (scf_error() != SCF_ERROR_DELETED)
15565 			scfdie();
15566 		scf_instance_destroy(cur_inst);
15567 		cur_inst = NULL;
15568 		warn(emsg_deleted);
15569 		return;
15570 	}
15571 	assert(fmrilen < bufsz);
15572 
15573 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15574 	switch (r) {
15575 	case 0:
15576 		break;
15577 
15578 	case ECONNABORTED:
15579 		warn(gettext("Could not refresh %s "
15580 		    "(repository connection broken).\n"), fmribuf);
15581 		break;
15582 
15583 	case ECANCELED:
15584 		warn(emsg_deleted);
15585 		break;
15586 
15587 	case EPERM:
15588 		warn(gettext("Could not refresh %s "
15589 		    "(permission denied).\n"), fmribuf);
15590 		break;
15591 
15592 	case ENOSPC:
15593 		warn(gettext("Could not refresh %s "
15594 		    "(repository server out of resources).\n"),
15595 		    fmribuf);
15596 		break;
15597 
15598 	case EACCES:
15599 	default:
15600 		bad_error("refresh_entity", scf_error());
15601 	}
15602 
15603 	free(fmribuf);
15604 }
15605 
15606 /*
15607  * describe [-v] [-t] [pg/prop]
15608  */
15609 int
15610 lscf_describe(uu_list_t *args, int hasargs)
15611 {
15612 	int ret = 0;
15613 	size_t i;
15614 	int argc;
15615 	char **argv = NULL;
15616 	string_list_t *slp;
15617 	int do_verbose = 0;
15618 	int do_templates = 0;
15619 	char *pattern = NULL;
15620 
15621 	lscf_prep_hndl();
15622 
15623 	if (hasargs != 0)  {
15624 		argc = uu_list_numnodes(args);
15625 		if (argc < 1)
15626 			goto usage;
15627 
15628 		argv = calloc(argc + 1, sizeof (char *));
15629 		if (argv == NULL)
15630 			uu_die(gettext("Out of memory.\n"));
15631 
15632 		for (slp = uu_list_first(args), i = 0;
15633 		    slp != NULL;
15634 		    slp = uu_list_next(args, slp), ++i)
15635 			argv[i] = slp->str;
15636 
15637 		argv[i] = NULL;
15638 
15639 		/*
15640 		 * We start optind = 0 because our list of arguments
15641 		 * starts at argv[0]
15642 		 */
15643 		optind = 0;
15644 		opterr = 0;
15645 		for (;;) {
15646 			ret = getopt(argc, argv, "vt");
15647 			if (ret == -1)
15648 				break;
15649 
15650 			switch (ret) {
15651 			case 'v':
15652 				do_verbose = 1;
15653 				break;
15654 
15655 			case 't':
15656 				do_templates = 1;
15657 				break;
15658 
15659 			case '?':
15660 				goto usage;
15661 
15662 			default:
15663 				bad_error("getopt", ret);
15664 			}
15665 		}
15666 
15667 		pattern = argv[optind];
15668 	}
15669 
15670 	if (cur_inst == NULL && cur_svc == NULL) {
15671 		semerr(emsg_entity_not_selected);
15672 		ret = -1;
15673 		goto out;
15674 	}
15675 
15676 	/*
15677 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15678 	 * output if their last parameter is set to 2.  Less information is
15679 	 * produced if the parameter is set to 1.
15680 	 */
15681 	if (pattern == NULL) {
15682 		if (do_verbose == 1)
15683 			list_entity_tmpl(2);
15684 		else
15685 			list_entity_tmpl(1);
15686 	}
15687 
15688 	if (do_templates == 0) {
15689 		if (do_verbose == 1)
15690 			listprop(pattern, 0, 2);
15691 		else
15692 			listprop(pattern, 0, 1);
15693 	} else {
15694 		if (do_verbose == 1)
15695 			listtmpl(pattern, 2);
15696 		else
15697 			listtmpl(pattern, 1);
15698 	}
15699 
15700 	ret = 0;
15701 out:
15702 	if (argv != NULL)
15703 		free(argv);
15704 	return (ret);
15705 usage:
15706 	ret = -2;
15707 	goto out;
15708 }
15709 
15710 #define	PARAM_ACTIVE	((const char *) "active")
15711 #define	PARAM_INACTIVE	((const char *) "inactive")
15712 #define	PARAM_SMTP_TO	((const char *) "to")
15713 
15714 /*
15715  * tokenize()
15716  * Breaks down the string according to the tokens passed.
15717  * Caller is responsible for freeing array of pointers returned.
15718  * Returns NULL on failure
15719  */
15720 char **
15721 tokenize(char *str, const char *sep)
15722 {
15723 	char *token, *lasts;
15724 	char **buf;
15725 	int n = 0;	/* number of elements */
15726 	int size = 8;	/* size of the array (initial) */
15727 
15728 	buf = safe_malloc(size * sizeof (char *));
15729 
15730 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15731 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15732 		if (n + 1 >= size) {
15733 			size *= 2;
15734 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15735 			    NULL) {
15736 				uu_die(gettext("Out of memory"));
15737 			}
15738 		}
15739 		buf[n] = token;
15740 	}
15741 	/* NULL terminate the pointer array */
15742 	buf[n] = NULL;
15743 
15744 	return (buf);
15745 }
15746 
15747 int32_t
15748 check_tokens(char **p)
15749 {
15750 	int32_t smf = 0;
15751 	int32_t fma = 0;
15752 
15753 	while (*p) {
15754 		int32_t t = string_to_tset(*p);
15755 
15756 		if (t == 0) {
15757 			if (is_fma_token(*p) == 0)
15758 				return (INVALID_TOKENS);
15759 			fma = 1; /* this token is an fma event */
15760 		} else {
15761 			smf |= t;
15762 		}
15763 
15764 		if (smf != 0 && fma == 1)
15765 			return (MIXED_TOKENS);
15766 		++p;
15767 	}
15768 
15769 	if (smf > 0)
15770 		return (smf);
15771 	else if (fma == 1)
15772 		return (FMA_TOKENS);
15773 
15774 	return (INVALID_TOKENS);
15775 }
15776 
15777 static int
15778 get_selection_str(char *fmri, size_t sz)
15779 {
15780 	if (g_hndl == NULL) {
15781 		semerr(emsg_entity_not_selected);
15782 		return (-1);
15783 	} else if (cur_level != NULL) {
15784 		semerr(emsg_invalid_for_snapshot);
15785 		return (-1);
15786 	} else {
15787 		lscf_get_selection_str(fmri, sz);
15788 	}
15789 
15790 	return (0);
15791 }
15792 
15793 void
15794 lscf_delnotify(const char *set, int global)
15795 {
15796 	char *str = strdup(set);
15797 	char **pgs;
15798 	char **p;
15799 	int32_t tset;
15800 	char *fmri = NULL;
15801 
15802 	if (str == NULL)
15803 		uu_die(gettext("Out of memory.\n"));
15804 
15805 	pgs = tokenize(str, ",");
15806 
15807 	if ((tset = check_tokens(pgs)) > 0) {
15808 		size_t sz = max_scf_fmri_len + 1;
15809 
15810 		fmri = safe_malloc(sz);
15811 		if (global) {
15812 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15813 		} else if (get_selection_str(fmri, sz) != 0) {
15814 			goto out;
15815 		}
15816 
15817 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15818 		    tset) != SCF_SUCCESS) {
15819 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15820 			    scf_strerror(scf_error()));
15821 		}
15822 	} else if (tset == FMA_TOKENS) {
15823 		if (global) {
15824 			semerr(gettext("Can't use option '-g' with FMA event "
15825 			    "definitions\n"));
15826 			goto out;
15827 		}
15828 
15829 		for (p = pgs; *p; ++p) {
15830 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15831 			    SCF_SUCCESS) {
15832 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15833 				    scf_strerror(scf_error()));
15834 				goto out;
15835 			}
15836 		}
15837 	} else if (tset == MIXED_TOKENS) {
15838 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15839 		goto out;
15840 	} else {
15841 		uu_die(gettext("Invalid input.\n"));
15842 	}
15843 
15844 out:
15845 	free(fmri);
15846 	free(pgs);
15847 	free(str);
15848 }
15849 
15850 void
15851 lscf_listnotify(const char *set, int global)
15852 {
15853 	char *str = safe_strdup(set);
15854 	char **pgs;
15855 	char **p;
15856 	int32_t tset;
15857 	nvlist_t *nvl;
15858 	char *fmri = NULL;
15859 
15860 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15861 		uu_die(gettext("Out of memory.\n"));
15862 
15863 	pgs = tokenize(str, ",");
15864 
15865 	if ((tset = check_tokens(pgs)) > 0) {
15866 		size_t sz = max_scf_fmri_len + 1;
15867 
15868 		fmri = safe_malloc(sz);
15869 		if (global) {
15870 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15871 		} else if (get_selection_str(fmri, sz) != 0) {
15872 			goto out;
15873 		}
15874 
15875 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15876 		    SCF_SUCCESS) {
15877 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15878 			    scf_error() != SCF_ERROR_DELETED)
15879 				uu_warn(gettext(
15880 				    "Failed listnotify: %s\n"),
15881 				    scf_strerror(scf_error()));
15882 			goto out;
15883 		}
15884 
15885 		listnotify_print(nvl, NULL);
15886 	} else if (tset == FMA_TOKENS) {
15887 		if (global) {
15888 			semerr(gettext("Can't use option '-g' with FMA event "
15889 			    "definitions\n"));
15890 			goto out;
15891 		}
15892 
15893 		for (p = pgs; *p; ++p) {
15894 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15895 			    SCF_SUCCESS) {
15896 				/*
15897 				 * if the preferences have just been deleted
15898 				 * or does not exist, just skip.
15899 				 */
15900 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15901 				    scf_error() == SCF_ERROR_DELETED)
15902 					continue;
15903 				uu_warn(gettext(
15904 				    "Failed listnotify: %s\n"),
15905 				    scf_strerror(scf_error()));
15906 				goto out;
15907 			}
15908 			listnotify_print(nvl, re_tag(*p));
15909 		}
15910 	} else if (tset == MIXED_TOKENS) {
15911 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15912 		goto out;
15913 	} else {
15914 		semerr(gettext("Invalid input.\n"));
15915 	}
15916 
15917 out:
15918 	nvlist_free(nvl);
15919 	free(fmri);
15920 	free(pgs);
15921 	free(str);
15922 }
15923 
15924 static char *
15925 strip_quotes_and_blanks(char *s)
15926 {
15927 	char *start = s;
15928 	char *end = strrchr(s, '\"');
15929 
15930 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15931 		start = s + 1;
15932 		while (isblank(*start))
15933 			start++;
15934 		while (isblank(*(end - 1)) && end > start) {
15935 			end--;
15936 		}
15937 		*end = '\0';
15938 	}
15939 
15940 	return (start);
15941 }
15942 
15943 static int
15944 set_active(nvlist_t *mech, const char *hier_part)
15945 {
15946 	boolean_t b;
15947 
15948 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15949 		b = B_TRUE;
15950 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15951 		b = B_FALSE;
15952 	} else {
15953 		return (-1);
15954 	}
15955 
15956 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15957 		uu_die(gettext("Out of memory.\n"));
15958 
15959 	return (0);
15960 }
15961 
15962 static int
15963 add_snmp_params(nvlist_t *mech, char *hier_part)
15964 {
15965 	return (set_active(mech, hier_part));
15966 }
15967 
15968 static int
15969 add_syslog_params(nvlist_t *mech, char *hier_part)
15970 {
15971 	return (set_active(mech, hier_part));
15972 }
15973 
15974 /*
15975  * add_mailto_paramas()
15976  * parse the hier_part of mailto URI
15977  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15978  * or mailto:{[active]|inactive}
15979  */
15980 static int
15981 add_mailto_params(nvlist_t *mech, char *hier_part)
15982 {
15983 	const char *tok = "?&";
15984 	char *p;
15985 	char *lasts;
15986 	char *param;
15987 	char *val;
15988 
15989 	/*
15990 	 * If the notification parametes are in the form of
15991 	 *
15992 	 *   malito:{[active]|inactive}
15993 	 *
15994 	 * we set the property accordingly and return.
15995 	 * Otherwise, we make the notification type active and
15996 	 * process the hier_part.
15997 	 */
15998 	if (set_active(mech, hier_part) == 0)
15999 		return (0);
16000 	else if (set_active(mech, PARAM_ACTIVE) != 0)
16001 		return (-1);
16002 
16003 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16004 		/*
16005 		 * sanity check: we only get here if hier_part = "", but
16006 		 * that's handled by set_active
16007 		 */
16008 		uu_die("strtok_r");
16009 	}
16010 
16011 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16012 		uu_die(gettext("Out of memory.\n"));
16013 
16014 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16015 		if ((param = strtok_r(p, "=", &val)) != NULL)
16016 			if (nvlist_add_string(mech, param, val) != 0)
16017 				uu_die(gettext("Out of memory.\n"));
16018 
16019 	return (0);
16020 }
16021 
16022 static int
16023 uri_split(char *uri, char **scheme, char **hier_part)
16024 {
16025 	int r = -1;
16026 
16027 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16028 	    *hier_part == NULL) {
16029 		semerr(gettext("'%s' is not an URI\n"), uri);
16030 		return (r);
16031 	}
16032 
16033 	if ((r = check_uri_scheme(*scheme)) < 0) {
16034 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16035 		return (r);
16036 	}
16037 
16038 	return (r);
16039 }
16040 
16041 static int
16042 process_uri(nvlist_t *params, char *uri)
16043 {
16044 	char *scheme;
16045 	char *hier_part;
16046 	nvlist_t *mech;
16047 	int index;
16048 	int r;
16049 
16050 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16051 		return (-1);
16052 
16053 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16054 		uu_die(gettext("Out of memory.\n"));
16055 
16056 	switch (index) {
16057 	case 0:
16058 		/* error messages displayed by called function */
16059 		r = add_mailto_params(mech, hier_part);
16060 		break;
16061 
16062 	case 1:
16063 		if ((r = add_snmp_params(mech, hier_part)) != 0)
16064 			semerr(gettext("Not valid parameters: '%s'\n"),
16065 			    hier_part);
16066 		break;
16067 
16068 	case 2:
16069 		if ((r = add_syslog_params(mech, hier_part)) != 0)
16070 			semerr(gettext("Not valid parameters: '%s'\n"),
16071 			    hier_part);
16072 		break;
16073 
16074 	default:
16075 		r = -1;
16076 	}
16077 
16078 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16079 	    mech) != 0)
16080 		uu_die(gettext("Out of memory.\n"));
16081 
16082 	nvlist_free(mech);
16083 	return (r);
16084 }
16085 
16086 static int
16087 set_params(nvlist_t *params, char **p)
16088 {
16089 	char *uri;
16090 
16091 	if (p == NULL)
16092 		/* sanity check */
16093 		uu_die("set_params");
16094 
16095 	while (*p) {
16096 		uri = strip_quotes_and_blanks(*p);
16097 		if (process_uri(params, uri) != 0)
16098 			return (-1);
16099 
16100 		++p;
16101 	}
16102 
16103 	return (0);
16104 }
16105 
16106 static int
16107 setnotify(const char *e, char **p, int global)
16108 {
16109 	char *str = safe_strdup(e);
16110 	char **events;
16111 	int32_t tset;
16112 	int r = -1;
16113 	nvlist_t *nvl, *params;
16114 	char *fmri = NULL;
16115 
16116 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16117 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16118 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16119 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
16120 		uu_die(gettext("Out of memory.\n"));
16121 
16122 	events = tokenize(str, ",");
16123 
16124 	if ((tset = check_tokens(events)) > 0) {
16125 		/* SMF state transitions parameters */
16126 		size_t sz = max_scf_fmri_len + 1;
16127 
16128 		fmri = safe_malloc(sz);
16129 		if (global) {
16130 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16131 		} else if (get_selection_str(fmri, sz) != 0) {
16132 			goto out;
16133 		}
16134 
16135 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16136 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16137 			uu_die(gettext("Out of memory.\n"));
16138 
16139 		if ((r = set_params(params, p)) == 0) {
16140 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16141 			    params) != 0)
16142 				uu_die(gettext("Out of memory.\n"));
16143 
16144 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16145 			    nvl) != SCF_SUCCESS) {
16146 				r = -1;
16147 				uu_warn(gettext(
16148 				    "Failed smf_notify_set_params(3SCF): %s\n"),
16149 				    scf_strerror(scf_error()));
16150 			}
16151 		}
16152 	} else if (tset == FMA_TOKENS) {
16153 		/* FMA event parameters */
16154 		if (global) {
16155 			semerr(gettext("Can't use option '-g' with FMA event "
16156 			    "definitions\n"));
16157 			goto out;
16158 		}
16159 
16160 		if ((r = set_params(params, p)) != 0)
16161 			goto out;
16162 
16163 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16164 			uu_die(gettext("Out of memory.\n"));
16165 
16166 		while (*events) {
16167 			if (smf_notify_set_params(de_tag(*events), nvl) !=
16168 			    SCF_SUCCESS)
16169 				uu_warn(gettext(
16170 				    "Failed smf_notify_set_params(3SCF) for "
16171 				    "event %s: %s\n"), *events,
16172 				    scf_strerror(scf_error()));
16173 			events++;
16174 		}
16175 	} else if (tset == MIXED_TOKENS) {
16176 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16177 	} else {
16178 		/* Sanity check */
16179 		uu_die(gettext("Invalid input.\n"));
16180 	}
16181 
16182 out:
16183 	nvlist_free(nvl);
16184 	nvlist_free(params);
16185 	free(fmri);
16186 	free(str);
16187 
16188 	return (r);
16189 }
16190 
16191 int
16192 lscf_setnotify(uu_list_t *args)
16193 {
16194 	int argc;
16195 	char **argv = NULL;
16196 	string_list_t *slp;
16197 	int global;
16198 	char *events;
16199 	char **p;
16200 	int i;
16201 	int ret;
16202 
16203 	if ((argc = uu_list_numnodes(args)) < 2)
16204 		goto usage;
16205 
16206 	argv = calloc(argc + 1, sizeof (char *));
16207 	if (argv == NULL)
16208 		uu_die(gettext("Out of memory.\n"));
16209 
16210 	for (slp = uu_list_first(args), i = 0;
16211 	    slp != NULL;
16212 	    slp = uu_list_next(args, slp), ++i)
16213 		argv[i] = slp->str;
16214 
16215 	argv[i] = NULL;
16216 
16217 	if (strcmp(argv[0], "-g") == 0) {
16218 		global = 1;
16219 		events = argv[1];
16220 		p = argv + 2;
16221 	} else {
16222 		global = 0;
16223 		events = argv[0];
16224 		p = argv + 1;
16225 	}
16226 
16227 	ret = setnotify(events, p, global);
16228 
16229 out:
16230 	free(argv);
16231 	return (ret);
16232 
16233 usage:
16234 	ret = -2;
16235 	goto out;
16236 }
16237 
16238 /*
16239  * Creates a list of instance name strings associated with a service. If
16240  * wohandcrafted flag is set, get only instances that have a last-import
16241  * snapshot, instances that were imported via svccfg.
16242  */
16243 static uu_list_t *
16244 create_instance_list(scf_service_t *svc, int wohandcrafted)
16245 {
16246 	scf_snapshot_t  *snap = NULL;
16247 	scf_instance_t  *inst;
16248 	scf_iter_t	*inst_iter;
16249 	uu_list_t	*instances;
16250 	char		*instname;
16251 	int		r;
16252 
16253 	inst_iter = scf_iter_create(g_hndl);
16254 	inst = scf_instance_create(g_hndl);
16255 	if (inst_iter == NULL || inst == NULL) {
16256 		uu_warn(gettext("Could not create instance or iterator\n"));
16257 		scfdie();
16258 	}
16259 
16260 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16261 		return (instances);
16262 
16263 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
16264 		switch (scf_error()) {
16265 		case SCF_ERROR_CONNECTION_BROKEN:
16266 		case SCF_ERROR_DELETED:
16267 			uu_list_destroy(instances);
16268 			instances = NULL;
16269 			goto out;
16270 
16271 		case SCF_ERROR_HANDLE_MISMATCH:
16272 		case SCF_ERROR_NOT_BOUND:
16273 		case SCF_ERROR_NOT_SET:
16274 		default:
16275 			bad_error("scf_iter_service_instances", scf_error());
16276 		}
16277 	}
16278 
16279 	instname = safe_malloc(max_scf_name_len + 1);
16280 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16281 		if (r == -1) {
16282 			(void) uu_warn(gettext("Unable to iterate through "
16283 			    "instances to create instance list : %s\n"),
16284 			    scf_strerror(scf_error()));
16285 
16286 			uu_list_destroy(instances);
16287 			instances = NULL;
16288 			goto out;
16289 		}
16290 
16291 		/*
16292 		 * If the instance does not have a last-import snapshot
16293 		 * then do not add it to the list as it is a hand-crafted
16294 		 * instance that should not be managed.
16295 		 */
16296 		if (wohandcrafted) {
16297 			if (snap == NULL &&
16298 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
16299 				uu_warn(gettext("Unable to create snapshot "
16300 				    "entity\n"));
16301 				scfdie();
16302 			}
16303 
16304 			if (scf_instance_get_snapshot(inst,
16305 			    snap_lastimport, snap) != 0) {
16306 				switch (scf_error()) {
16307 				case SCF_ERROR_NOT_FOUND :
16308 				case SCF_ERROR_DELETED:
16309 					continue;
16310 
16311 				case SCF_ERROR_CONNECTION_BROKEN:
16312 					uu_list_destroy(instances);
16313 					instances = NULL;
16314 					goto out;
16315 
16316 				case SCF_ERROR_HANDLE_MISMATCH:
16317 				case SCF_ERROR_NOT_BOUND:
16318 				case SCF_ERROR_NOT_SET:
16319 				default:
16320 					bad_error("scf_iter_service_instances",
16321 					    scf_error());
16322 				}
16323 			}
16324 		}
16325 
16326 		if (scf_instance_get_name(inst, instname,
16327 		    max_scf_name_len + 1) < 0) {
16328 			switch (scf_error()) {
16329 			case SCF_ERROR_NOT_FOUND :
16330 				continue;
16331 
16332 			case SCF_ERROR_CONNECTION_BROKEN:
16333 			case SCF_ERROR_DELETED:
16334 				uu_list_destroy(instances);
16335 				instances = NULL;
16336 				goto out;
16337 
16338 			case SCF_ERROR_HANDLE_MISMATCH:
16339 			case SCF_ERROR_NOT_BOUND:
16340 			case SCF_ERROR_NOT_SET:
16341 			default:
16342 				bad_error("scf_iter_service_instances",
16343 				    scf_error());
16344 			}
16345 		}
16346 
16347 		add_string(instances, instname);
16348 	}
16349 
16350 out:
16351 	if (snap)
16352 		scf_snapshot_destroy(snap);
16353 
16354 	scf_instance_destroy(inst);
16355 	scf_iter_destroy(inst_iter);
16356 	free(instname);
16357 	return (instances);
16358 }
16359 
16360 /*
16361  * disable an instance but wait for the instance to
16362  * move out of the running state.
16363  *
16364  * Returns 0 : if the instance did not disable
16365  * Returns non-zero : if the instance disabled.
16366  *
16367  */
16368 static int
16369 disable_instance(scf_instance_t *instance)
16370 {
16371 	char	*fmribuf;
16372 	int	enabled = 10000;
16373 
16374 	if (inst_is_running(instance)) {
16375 		fmribuf = safe_malloc(max_scf_name_len + 1);
16376 		if (scf_instance_to_fmri(instance, fmribuf,
16377 		    max_scf_name_len + 1) < 0) {
16378 			free(fmribuf);
16379 			return (0);
16380 		}
16381 
16382 		/*
16383 		 * If the instance cannot be disabled then return
16384 		 * failure to disable and let the caller decide
16385 		 * if that is of importance.
16386 		 */
16387 		if (smf_disable_instance(fmribuf, 0) != 0) {
16388 			free(fmribuf);
16389 			return (0);
16390 		}
16391 
16392 		while (enabled) {
16393 			if (!inst_is_running(instance))
16394 				break;
16395 
16396 			(void) poll(NULL, 0, 5);
16397 			enabled = enabled - 5;
16398 		}
16399 
16400 		free(fmribuf);
16401 	}
16402 
16403 	return (enabled);
16404 }
16405 
16406 /*
16407  * Function to compare two service_manifest structures.
16408  */
16409 /* ARGSUSED2 */
16410 static int
16411 service_manifest_compare(const void *left, const void *right, void *unused)
16412 {
16413 	service_manifest_t *l = (service_manifest_t *)left;
16414 	service_manifest_t *r = (service_manifest_t *)right;
16415 	int rc;
16416 
16417 	rc = strcmp(l->servicename, r->servicename);
16418 
16419 	return (rc);
16420 }
16421 
16422 /*
16423  * Look for the provided service in the service to manifest
16424  * tree.  If the service exists, and a manifest was provided
16425  * then add the manifest to that service.  If the service
16426  * does not exist, then add the service and manifest to the
16427  * list.
16428  *
16429  * If the manifest is NULL, return the element if found.  If
16430  * the service is not found return NULL.
16431  */
16432 service_manifest_t *
16433 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16434 {
16435 	service_manifest_t	elem;
16436 	service_manifest_t	*fnelem;
16437 	uu_avl_index_t		marker;
16438 
16439 	elem.servicename = svnbuf;
16440 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16441 
16442 	if (mfst) {
16443 		if (fnelem) {
16444 			add_string(fnelem->mfstlist, strdup(mfst));
16445 		} else {
16446 			fnelem = safe_malloc(sizeof (*fnelem));
16447 			fnelem->servicename = safe_strdup(svnbuf);
16448 			if ((fnelem->mfstlist =
16449 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16450 				uu_die(gettext("Could not create property "
16451 				    "list: %s\n"), uu_strerror(uu_error()));
16452 
16453 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16454 
16455 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16456 		}
16457 	}
16458 
16459 	return (fnelem);
16460 }
16461 
16462 /*
16463  * Create the service to manifest avl tree.
16464  *
16465  * Walk each of the manifests currently installed in the supported
16466  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16467  * each of the manifests, inventory the services and add them to
16468  * the tree.
16469  *
16470  * Code that calls this function should make sure fileystem/minimal is online,
16471  * /var is available, since this function walks the /var/svc/manifest directory.
16472  */
16473 static void
16474 create_manifest_tree(void)
16475 {
16476 	manifest_info_t **entry;
16477 	manifest_info_t **manifests;
16478 	uu_list_walk_t	*svcs;
16479 	bundle_t	*b;
16480 	entity_t	*mfsvc;
16481 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16482 	int		c, status;
16483 
16484 	if (service_manifest_pool)
16485 		return;
16486 
16487 	/*
16488 	 * Create the list pool for the service manifest list
16489 	 */
16490 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16491 	    sizeof (service_manifest_t),
16492 	    offsetof(service_manifest_t, svcmfst_node),
16493 	    service_manifest_compare, UU_DEFAULT);
16494 	if (service_manifest_pool == NULL)
16495 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16496 		    uu_strerror(uu_error()));
16497 
16498 	/*
16499 	 * Create the list
16500 	 */
16501 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16502 	    UU_DEFAULT);
16503 	if (service_manifest_tree == NULL)
16504 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16505 		    uu_strerror(uu_error()));
16506 
16507 	/*
16508 	 * Walk the manifests adding the service(s) from each manifest.
16509 	 *
16510 	 * If a service already exists add the manifest to the manifest
16511 	 * list for that service.  This covers the case of a service that
16512 	 * is supported by multiple manifest files.
16513 	 */
16514 	for (c = 0; dirs[c]; c++) {
16515 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16516 		if (status < 0) {
16517 			uu_warn(gettext("file tree walk of %s encountered "
16518 			    "error %s\n"), dirs[c], strerror(errno));
16519 
16520 			uu_avl_destroy(service_manifest_tree);
16521 			service_manifest_tree = NULL;
16522 			return;
16523 		}
16524 
16525 		/*
16526 		 * If a manifest that was in the list is not found
16527 		 * then skip and go to the next manifest file.
16528 		 */
16529 		if (manifests != NULL) {
16530 			for (entry = manifests; *entry != NULL; entry++) {
16531 				b = internal_bundle_new();
16532 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16533 				    SVCCFG_OP_IMPORT) != 0) {
16534 					internal_bundle_free(b);
16535 					continue;
16536 				}
16537 
16538 				svcs = uu_list_walk_start(b->sc_bundle_services,
16539 				    0);
16540 				if (svcs == NULL) {
16541 					internal_bundle_free(b);
16542 					continue;
16543 				}
16544 
16545 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16546 				    NULL) {
16547 					/* Add manifest to service */
16548 					(void) find_add_svc_mfst(mfsvc->sc_name,
16549 					    (*entry)->mi_path);
16550 				}
16551 
16552 				uu_list_walk_end(svcs);
16553 				internal_bundle_free(b);
16554 			}
16555 
16556 			free_manifest_array(manifests);
16557 		}
16558 	}
16559 }
16560 
16561 /*
16562  * Check the manifest history file to see
16563  * if the service was ever installed from
16564  * one of the supported directories.
16565  *
16566  * Return Values :
16567  * 	-1 - if there's error reading manifest history file
16568  *	 1 - if the service is not found
16569  *	 0 - if the service is found
16570  */
16571 static int
16572 check_mfst_history(const char *svcname)
16573 {
16574 	struct stat	st;
16575 	caddr_t		mfsthist_start;
16576 	char		*svnbuf;
16577 	int		fd;
16578 	int		r = 1;
16579 
16580 	fd = open(MFSTHISTFILE, O_RDONLY);
16581 	if (fd == -1) {
16582 		uu_warn(gettext("Unable to open the history file\n"));
16583 		return (-1);
16584 	}
16585 
16586 	if (fstat(fd, &st) == -1) {
16587 		uu_warn(gettext("Unable to stat the history file\n"));
16588 		return (-1);
16589 	}
16590 
16591 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16592 	    MAP_PRIVATE, fd, 0);
16593 
16594 	(void) close(fd);
16595 	if (mfsthist_start == MAP_FAILED ||
16596 	    *(mfsthist_start + st.st_size) != '\0') {
16597 		(void) munmap(mfsthist_start, st.st_size);
16598 		return (-1);
16599 	}
16600 
16601 	/*
16602 	 * The manifest history file is a space delimited list
16603 	 * of service and instance to manifest linkage.  Adding
16604 	 * a space to the end of the service name so to get only
16605 	 * the service that is being searched for.
16606 	 */
16607 	svnbuf = uu_msprintf("%s ", svcname);
16608 	if (svnbuf == NULL)
16609 		uu_die(gettext("Out of memory"));
16610 
16611 	if (strstr(mfsthist_start, svnbuf) != NULL)
16612 		r = 0;
16613 
16614 	(void) munmap(mfsthist_start, st.st_size);
16615 	uu_free(svnbuf);
16616 	return (r);
16617 }
16618 
16619 /*
16620  * Take down each of the instances in the service
16621  * and remove them, then delete the service.
16622  */
16623 static void
16624 teardown_service(scf_service_t *svc, const char *svnbuf)
16625 {
16626 	scf_instance_t	*instance;
16627 	scf_iter_t	*iter;
16628 	int		r;
16629 
16630 	safe_printf(gettext("Delete service %s as there are no "
16631 	    "supporting manifests\n"), svnbuf);
16632 
16633 	instance = scf_instance_create(g_hndl);
16634 	iter = scf_iter_create(g_hndl);
16635 	if (iter == NULL || instance == NULL) {
16636 		uu_warn(gettext("Unable to create supporting entities to "
16637 		    "teardown the service\n"));
16638 		uu_warn(gettext("scf error is : %s\n"),
16639 		    scf_strerror(scf_error()));
16640 		scfdie();
16641 	}
16642 
16643 	if (scf_iter_service_instances(iter, svc) != 0) {
16644 		switch (scf_error()) {
16645 		case SCF_ERROR_CONNECTION_BROKEN:
16646 		case SCF_ERROR_DELETED:
16647 			goto out;
16648 
16649 		case SCF_ERROR_HANDLE_MISMATCH:
16650 		case SCF_ERROR_NOT_BOUND:
16651 		case SCF_ERROR_NOT_SET:
16652 		default:
16653 			bad_error("scf_iter_service_instances",
16654 			    scf_error());
16655 		}
16656 	}
16657 
16658 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16659 		if (r == -1) {
16660 			uu_warn(gettext("Error - %s\n"),
16661 			    scf_strerror(scf_error()));
16662 			goto out;
16663 		}
16664 
16665 		(void) disable_instance(instance);
16666 	}
16667 
16668 	/*
16669 	 * Delete the service... forcing the deletion in case
16670 	 * any of the instances did not disable.
16671 	 */
16672 	(void) lscf_service_delete(svc, 1);
16673 out:
16674 	scf_instance_destroy(instance);
16675 	scf_iter_destroy(iter);
16676 }
16677 
16678 /*
16679  * Get the list of instances supported by the manifest
16680  * file.
16681  *
16682  * Return 0 if there are no instances.
16683  *
16684  * Return -1 if there are errors attempting to collect instances.
16685  *
16686  * Return the count of instances found if there are no errors.
16687  *
16688  */
16689 static int
16690 check_instance_support(char *mfstfile, const char *svcname,
16691     uu_list_t *instances)
16692 {
16693 	uu_list_walk_t	*svcs, *insts;
16694 	uu_list_t	*ilist;
16695 	bundle_t	*b;
16696 	entity_t	*mfsvc, *mfinst;
16697 	const char	*svcn;
16698 	int		rminstcnt = 0;
16699 
16700 
16701 	b = internal_bundle_new();
16702 
16703 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16704 		/*
16705 		 * Unable to process the manifest file for
16706 		 * instance support, so just return as
16707 		 * don't want to remove instances that could
16708 		 * not be accounted for that might exist here.
16709 		 */
16710 		internal_bundle_free(b);
16711 		return (0);
16712 	}
16713 
16714 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16715 	if (svcs == NULL) {
16716 		internal_bundle_free(b);
16717 		return (0);
16718 	}
16719 
16720 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16721 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16722 
16723 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16724 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16725 			break;
16726 	}
16727 	uu_list_walk_end(svcs);
16728 
16729 	if (mfsvc == NULL) {
16730 		internal_bundle_free(b);
16731 		return (-1);
16732 	}
16733 
16734 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16735 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16736 		internal_bundle_free(b);
16737 		return (0);
16738 	}
16739 
16740 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16741 		/*
16742 		 * Remove the instance from the instances list.
16743 		 * The unaccounted for instances will be removed
16744 		 * from the service once all manifests are
16745 		 * processed.
16746 		 */
16747 		(void) remove_string(instances,
16748 		    mfinst->sc_name);
16749 		rminstcnt++;
16750 	}
16751 
16752 	uu_list_walk_end(insts);
16753 	internal_bundle_free(b);
16754 
16755 	return (rminstcnt);
16756 }
16757 
16758 /*
16759  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16760  * 'false' to indicate there's no manifest file(s) found for the service.
16761  */
16762 static void
16763 svc_add_no_support(scf_service_t *svc)
16764 {
16765 	char	*pname;
16766 
16767 	/* Add no support */
16768 	cur_svc = svc;
16769 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16770 		return;
16771 
16772 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16773 	if (pname == NULL)
16774 		uu_die(gettext("Out of memory.\n"));
16775 
16776 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16777 
16778 	uu_free(pname);
16779 	cur_svc = NULL;
16780 }
16781 
16782 /*
16783  * This function handles all upgrade scenarios for a service that doesn't have
16784  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16785  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16786  * manifest(s) mapping. Manifests under supported directories are inventoried
16787  * and a property is added for each file that delivers configuration to the
16788  * service.  A service that has no corresponding manifest files (deleted) are
16789  * removed from repository.
16790  *
16791  * Unsupported services:
16792  *
16793  * A service is considered unsupported if there is no corresponding manifest
16794  * in the supported directories for that service and the service isn't in the
16795  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16796  * services and instances that were delivered by Solaris before the introduction
16797  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16798  * the path to the manifest file that defined the service or instance.
16799  *
16800  * Another type of unsupported services is 'handcrafted' services,
16801  * programmatically created services or services created by dependent entries
16802  * in other manifests. A handcrafted service is identified by its lack of any
16803  * instance containing last-import snapshot which is created during svccfg
16804  * import.
16805  *
16806  * This function sets a flag for unsupported services by setting services'
16807  * SCF_PG_MANIFESTFILES/support property to false.
16808  */
16809 static void
16810 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16811 {
16812 	service_manifest_t	*elem;
16813 	uu_list_walk_t		*mfwalk;
16814 	string_list_t		*mfile;
16815 	uu_list_t		*instances;
16816 	const char		*sname;
16817 	char			*pname;
16818 	int			r;
16819 
16820 	/*
16821 	 * Since there's no guarantee manifests under /var are available during
16822 	 * early import, don't perform any upgrade during early import.
16823 	 */
16824 	if (IGNORE_VAR)
16825 		return;
16826 
16827 	if (service_manifest_tree == NULL) {
16828 		create_manifest_tree();
16829 	}
16830 
16831 	/*
16832 	 * Find service's supporting manifest(s) after
16833 	 * stripping off the svc:/ prefix that is part
16834 	 * of the fmri that is not used in the service
16835 	 * manifest bundle list.
16836 	 */
16837 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16838 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16839 	elem = find_add_svc_mfst(sname, NULL);
16840 	if (elem == NULL) {
16841 
16842 		/*
16843 		 * A handcrafted service, one that has no instance containing
16844 		 * last-import snapshot, should get unsupported flag.
16845 		 */
16846 		instances = create_instance_list(svc, 1);
16847 		if (instances == NULL) {
16848 			uu_warn(gettext("Unable to create instance list %s\n"),
16849 			    svcname);
16850 			return;
16851 		}
16852 
16853 		if (uu_list_numnodes(instances) == 0) {
16854 			svc_add_no_support(svc);
16855 			return;
16856 		}
16857 
16858 		/*
16859 		 * If the service is in the history file, and its supporting
16860 		 * manifests are not found, we can safely delete the service
16861 		 * because its manifests are removed from the system.
16862 		 *
16863 		 * Services not found in the history file are not delivered by
16864 		 * Solaris and/or delivered outside supported directories, set
16865 		 * unsupported flag for these services.
16866 		 */
16867 		r = check_mfst_history(svcname);
16868 		if (r == -1)
16869 			return;
16870 
16871 		if (r) {
16872 			/* Set unsupported flag for service  */
16873 			svc_add_no_support(svc);
16874 		} else {
16875 			/* Delete the service */
16876 			teardown_service(svc, svcname);
16877 		}
16878 
16879 		return;
16880 	}
16881 
16882 	/*
16883 	 * Walk through the list of manifests and add them
16884 	 * to the service.
16885 	 *
16886 	 * Create a manifestfiles pg and add the property.
16887 	 */
16888 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16889 	if (mfwalk == NULL)
16890 		return;
16891 
16892 	cur_svc = svc;
16893 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16894 	if (r != 0) {
16895 		cur_svc = NULL;
16896 		return;
16897 	}
16898 
16899 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16900 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16901 		    mhash_filename_to_propname(mfile->str, 0));
16902 		if (pname == NULL)
16903 			uu_die(gettext("Out of memory.\n"));
16904 
16905 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16906 		uu_free(pname);
16907 	}
16908 	uu_list_walk_end(mfwalk);
16909 
16910 	cur_svc = NULL;
16911 }
16912 
16913 /*
16914  * Take a service and process the manifest file entires to see if
16915  * there is continued support for the service and instances.  If
16916  * not cleanup as appropriate.
16917  *
16918  * If a service does not have a manifest files entry flag it for
16919  * upgrade and return.
16920  *
16921  * For each manifestfiles property check if the manifest file is
16922  * under the supported /lib/svc/manifest or /var/svc/manifest path
16923  * and if not then return immediately as this service is not supported
16924  * by the cleanup mechanism and should be ignored.
16925  *
16926  * For each manifest file that is supported, check to see if the
16927  * file exists.  If not then remove the manifest file property
16928  * from the service and the smf/manifest hash table.  If the manifest
16929  * file exists then verify that it supports the instances that are
16930  * part of the service.
16931  *
16932  * Once all manifest files have been accounted for remove any instances
16933  * that are no longer supported in the service.
16934  *
16935  * Return values :
16936  * 0 - Successfully processed the service
16937  * non-zero - failed to process the service
16938  *
16939  * On most errors, will just return to wait and get the next service,
16940  * unless in case of unable to create the needed structures which is
16941  * most likely a fatal error that is not going to be recoverable.
16942  */
16943 int
16944 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16945 {
16946 	struct mpg_mfile	*mpntov;
16947 	struct mpg_mfile	**mpvarry = NULL;
16948 	scf_service_t		*svc;
16949 	scf_propertygroup_t	*mpg;
16950 	scf_property_t		*mp;
16951 	scf_value_t		*mv;
16952 	scf_iter_t		*mi;
16953 	scf_instance_t		*instance;
16954 	uu_list_walk_t		*insts;
16955 	uu_list_t		*instances = NULL;
16956 	boolean_t		activity = (boolean_t)act;
16957 	char			*mpnbuf;
16958 	char			*mpvbuf;
16959 	char			*pgpropbuf;
16960 	int			mfstcnt, rminstct, instct, mfstmax;
16961 	int			index;
16962 	int			r = 0;
16963 
16964 	assert(g_hndl != NULL);
16965 	assert(wip->svc != NULL);
16966 	assert(wip->fmri != NULL);
16967 
16968 	svc = wip->svc;
16969 
16970 	mpg = scf_pg_create(g_hndl);
16971 	mp = scf_property_create(g_hndl);
16972 	mi = scf_iter_create(g_hndl);
16973 	mv = scf_value_create(g_hndl);
16974 	instance = scf_instance_create(g_hndl);
16975 
16976 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16977 	    instance == NULL) {
16978 		uu_warn(gettext("Unable to create the supporting entities\n"));
16979 		uu_warn(gettext("scf error is : %s\n"),
16980 		    scf_strerror(scf_error()));
16981 		scfdie();
16982 	}
16983 
16984 	/*
16985 	 * Get the manifestfiles property group to be parsed for
16986 	 * files existence.
16987 	 */
16988 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16989 		switch (scf_error()) {
16990 		case SCF_ERROR_NOT_FOUND:
16991 			upgrade_svc_mfst_connection(svc, wip->fmri);
16992 			break;
16993 		case SCF_ERROR_DELETED:
16994 		case SCF_ERROR_CONNECTION_BROKEN:
16995 			goto out;
16996 
16997 		case SCF_ERROR_HANDLE_MISMATCH:
16998 		case SCF_ERROR_NOT_BOUND:
16999 		case SCF_ERROR_NOT_SET:
17000 		default:
17001 			bad_error("scf_iter_pg_properties",
17002 			    scf_error());
17003 		}
17004 
17005 		goto out;
17006 	}
17007 
17008 	/*
17009 	 * Iterate through each of the manifestfiles properties
17010 	 * to determine what manifestfiles are available.
17011 	 *
17012 	 * If a manifest file is supported then increment the
17013 	 * count and therefore the service is safe.
17014 	 */
17015 	if (scf_iter_pg_properties(mi, mpg) != 0) {
17016 		switch (scf_error()) {
17017 		case SCF_ERROR_DELETED:
17018 		case SCF_ERROR_CONNECTION_BROKEN:
17019 			goto out;
17020 
17021 		case SCF_ERROR_HANDLE_MISMATCH:
17022 		case SCF_ERROR_NOT_BOUND:
17023 		case SCF_ERROR_NOT_SET:
17024 		default:
17025 			bad_error("scf_iter_pg_properties",
17026 			    scf_error());
17027 		}
17028 	}
17029 
17030 	mfstcnt = 0;
17031 	mfstmax = MFSTFILE_MAX;
17032 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17033 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
17034 		if (r == -1)
17035 			bad_error(gettext("Unable to iterate through "
17036 			    "manifestfiles properties : %s"),
17037 			    scf_error());
17038 
17039 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
17040 		mpnbuf = safe_malloc(max_scf_name_len + 1);
17041 		mpvbuf = safe_malloc(max_scf_value_len + 1);
17042 		mpntov->mpg = mpnbuf;
17043 		mpntov->mfile = mpvbuf;
17044 		mpntov->access = 1;
17045 		if (scf_property_get_name(mp, mpnbuf,
17046 		    max_scf_name_len + 1) < 0) {
17047 			uu_warn(gettext("Unable to get manifest file "
17048 			    "property : %s\n"),
17049 			    scf_strerror(scf_error()));
17050 
17051 			switch (scf_error()) {
17052 			case SCF_ERROR_DELETED:
17053 			case SCF_ERROR_CONNECTION_BROKEN:
17054 				r = scferror2errno(scf_error());
17055 				goto out_free;
17056 
17057 			case SCF_ERROR_HANDLE_MISMATCH:
17058 			case SCF_ERROR_NOT_BOUND:
17059 			case SCF_ERROR_NOT_SET:
17060 			default:
17061 				bad_error("scf_iter_pg_properties",
17062 				    scf_error());
17063 			}
17064 		}
17065 
17066 		/*
17067 		 * The support property is a boolean value that indicates
17068 		 * if the service is supported for manifest file deletion.
17069 		 * Currently at this time there is no code that sets this
17070 		 * value to true.  So while we could just let this be caught
17071 		 * by the support check below, in the future this by be set
17072 		 * to true and require processing.  So for that, go ahead
17073 		 * and check here, and just return if false.  Otherwise,
17074 		 * fall through expecting that other support checks will
17075 		 * handle the entries.
17076 		 */
17077 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17078 			uint8_t	support;
17079 
17080 			if (scf_property_get_value(mp, mv) != 0 ||
17081 			    scf_value_get_boolean(mv, &support) != 0) {
17082 				uu_warn(gettext("Unable to get the manifest "
17083 				    "support value: %s\n"),
17084 				    scf_strerror(scf_error()));
17085 
17086 				switch (scf_error()) {
17087 				case SCF_ERROR_DELETED:
17088 				case SCF_ERROR_CONNECTION_BROKEN:
17089 					r = scferror2errno(scf_error());
17090 					goto out_free;
17091 
17092 				case SCF_ERROR_HANDLE_MISMATCH:
17093 				case SCF_ERROR_NOT_BOUND:
17094 				case SCF_ERROR_NOT_SET:
17095 				default:
17096 					bad_error("scf_iter_pg_properties",
17097 					    scf_error());
17098 				}
17099 			}
17100 
17101 			if (support == B_FALSE)
17102 				goto out_free;
17103 		}
17104 
17105 		/*
17106 		 * Anything with a manifest outside of the supported
17107 		 * directories, immediately bail out because that makes
17108 		 * this service non-supported.  We don't even want
17109 		 * to do instance processing in this case because the
17110 		 * instances could be part of the non-supported manifest.
17111 		 */
17112 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17113 			/*
17114 			 * Manifest is not in /lib/svc, so we need to
17115 			 * consider the /var/svc case.
17116 			 */
17117 			if (strncmp(mpnbuf, VARSVC_PR,
17118 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17119 				/*
17120 				 * Either the manifest is not in /var/svc or
17121 				 * /var is not yet mounted.  We ignore the
17122 				 * manifest either because it is not in a
17123 				 * standard location or because we cannot
17124 				 * currently access the manifest.
17125 				 */
17126 				goto out_free;
17127 			}
17128 		}
17129 
17130 		/*
17131 		 * Get the value to of the manifest file for this entry
17132 		 * for access verification and instance support
17133 		 * verification if it still exists.
17134 		 *
17135 		 * During Early Manifest Import if the manifest is in
17136 		 * /var/svc then it may not yet be available for checking
17137 		 * so we must determine if /var/svc is available.  If not
17138 		 * then defer until Late Manifest Import to cleanup.
17139 		 */
17140 		if (scf_property_get_value(mp, mv) != 0) {
17141 			uu_warn(gettext("Unable to get the manifest file "
17142 			    "value: %s\n"),
17143 			    scf_strerror(scf_error()));
17144 
17145 			switch (scf_error()) {
17146 			case SCF_ERROR_DELETED:
17147 			case SCF_ERROR_CONNECTION_BROKEN:
17148 				r = scferror2errno(scf_error());
17149 				goto out_free;
17150 
17151 			case SCF_ERROR_HANDLE_MISMATCH:
17152 			case SCF_ERROR_NOT_BOUND:
17153 			case SCF_ERROR_NOT_SET:
17154 			default:
17155 				bad_error("scf_property_get_value",
17156 				    scf_error());
17157 			}
17158 		}
17159 
17160 		if (scf_value_get_astring(mv, mpvbuf,
17161 		    max_scf_value_len + 1) < 0) {
17162 			uu_warn(gettext("Unable to get the manifest "
17163 			    "file : %s\n"),
17164 			    scf_strerror(scf_error()));
17165 
17166 			switch (scf_error()) {
17167 			case SCF_ERROR_DELETED:
17168 			case SCF_ERROR_CONNECTION_BROKEN:
17169 				r = scferror2errno(scf_error());
17170 				goto out_free;
17171 
17172 			case SCF_ERROR_HANDLE_MISMATCH:
17173 			case SCF_ERROR_NOT_BOUND:
17174 			case SCF_ERROR_NOT_SET:
17175 			default:
17176 				bad_error("scf_value_get_astring",
17177 				    scf_error());
17178 			}
17179 		}
17180 
17181 		mpvarry[mfstcnt] = mpntov;
17182 		mfstcnt++;
17183 
17184 		/*
17185 		 * Check for the need to reallocate array
17186 		 */
17187 		if (mfstcnt >= (mfstmax - 1)) {
17188 			struct mpg_mfile **newmpvarry;
17189 
17190 			mfstmax = mfstmax * 2;
17191 			newmpvarry = realloc(mpvarry,
17192 			    sizeof (struct mpg_mfile *) * mfstmax);
17193 
17194 			if (newmpvarry == NULL)
17195 				goto out_free;
17196 
17197 			mpvarry = newmpvarry;
17198 		}
17199 
17200 		mpvarry[mfstcnt] = NULL;
17201 	}
17202 
17203 	for (index = 0; mpvarry[index]; index++) {
17204 		mpntov = mpvarry[index];
17205 
17206 		/*
17207 		 * Check to see if the manifestfile is accessable, if so hand
17208 		 * this service and manifestfile off to be processed for
17209 		 * instance support.
17210 		 */
17211 		mpnbuf = mpntov->mpg;
17212 		mpvbuf = mpntov->mfile;
17213 		if (access(mpvbuf, F_OK) != 0) {
17214 			mpntov->access = 0;
17215 			activity++;
17216 			mfstcnt--;
17217 			/* Remove the entry from the service */
17218 			cur_svc = svc;
17219 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17220 			    mpnbuf);
17221 			if (pgpropbuf == NULL)
17222 				uu_die(gettext("Out of memory.\n"));
17223 
17224 			lscf_delprop(pgpropbuf);
17225 			cur_svc = NULL;
17226 
17227 			uu_free(pgpropbuf);
17228 		}
17229 	}
17230 
17231 	/*
17232 	 * If mfstcnt is 0, none of the manifests that supported the service
17233 	 * existed so remove the service.
17234 	 */
17235 	if (mfstcnt == 0) {
17236 		teardown_service(svc, wip->fmri);
17237 
17238 		goto out_free;
17239 	}
17240 
17241 	if (activity) {
17242 		int	nosvcsupport = 0;
17243 
17244 		/*
17245 		 * If the list of service instances is NULL then
17246 		 * create the list.
17247 		 */
17248 		instances = create_instance_list(svc, 1);
17249 		if (instances == NULL) {
17250 			uu_warn(gettext("Unable to create instance list %s\n"),
17251 			    wip->fmri);
17252 			goto out_free;
17253 		}
17254 
17255 		rminstct = uu_list_numnodes(instances);
17256 		instct = rminstct;
17257 
17258 		for (index = 0; mpvarry[index]; index++) {
17259 			mpntov = mpvarry[index];
17260 			if (mpntov->access == 0)
17261 				continue;
17262 
17263 			mpnbuf = mpntov->mpg;
17264 			mpvbuf = mpntov->mfile;
17265 			r = check_instance_support(mpvbuf, wip->fmri,
17266 			    instances);
17267 			if (r == -1) {
17268 				nosvcsupport++;
17269 			} else {
17270 				rminstct -= r;
17271 			}
17272 		}
17273 
17274 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17275 			teardown_service(svc, wip->fmri);
17276 
17277 			goto out_free;
17278 		}
17279 	}
17280 
17281 	/*
17282 	 * If there are instances left on the instance list, then
17283 	 * we must remove them.
17284 	 */
17285 	if (instances != NULL && uu_list_numnodes(instances)) {
17286 		string_list_t *sp;
17287 
17288 		insts = uu_list_walk_start(instances, 0);
17289 		while ((sp = uu_list_walk_next(insts)) != NULL) {
17290 			/*
17291 			 * Remove the instance from the instances list.
17292 			 */
17293 			safe_printf(gettext("Delete instance %s from "
17294 			    "service %s\n"), sp->str, wip->fmri);
17295 			if (scf_service_get_instance(svc, sp->str,
17296 			    instance) != SCF_SUCCESS) {
17297 				(void) uu_warn("scf_error - %s\n",
17298 				    scf_strerror(scf_error()));
17299 
17300 				continue;
17301 			}
17302 
17303 			(void) disable_instance(instance);
17304 
17305 			(void) lscf_instance_delete(instance, 1);
17306 		}
17307 		scf_instance_destroy(instance);
17308 		uu_list_walk_end(insts);
17309 	}
17310 
17311 out_free:
17312 	if (mpvarry) {
17313 		struct mpg_mfile *fmpntov;
17314 
17315 		for (index = 0; mpvarry[index]; index++) {
17316 			fmpntov  = mpvarry[index];
17317 			if (fmpntov->mpg == mpnbuf)
17318 				mpnbuf = NULL;
17319 			free(fmpntov->mpg);
17320 
17321 			if (fmpntov->mfile == mpvbuf)
17322 				mpvbuf = NULL;
17323 			free(fmpntov->mfile);
17324 
17325 			if (fmpntov == mpntov)
17326 				mpntov = NULL;
17327 			free(fmpntov);
17328 		}
17329 		if (mpnbuf)
17330 			free(mpnbuf);
17331 		if (mpvbuf)
17332 			free(mpvbuf);
17333 		if (mpntov)
17334 			free(mpntov);
17335 
17336 		free(mpvarry);
17337 	}
17338 out:
17339 	scf_pg_destroy(mpg);
17340 	scf_property_destroy(mp);
17341 	scf_iter_destroy(mi);
17342 	scf_value_destroy(mv);
17343 
17344 	return (0);
17345 }
17346 
17347 /*
17348  * Take the service and search for the manifestfiles property
17349  * in each of the property groups.  If the manifest file
17350  * associated with the property does not exist then remove
17351  * the property group.
17352  */
17353 int
17354 lscf_hash_cleanup()
17355 {
17356 	scf_service_t		*svc;
17357 	scf_scope_t		*scope;
17358 	scf_propertygroup_t	*pg;
17359 	scf_property_t		*prop;
17360 	scf_value_t		*val;
17361 	scf_iter_t		*iter;
17362 	char			*pgname = NULL;
17363 	char			*mfile = NULL;
17364 	int			r;
17365 
17366 	svc = scf_service_create(g_hndl);
17367 	scope = scf_scope_create(g_hndl);
17368 	pg = scf_pg_create(g_hndl);
17369 	prop = scf_property_create(g_hndl);
17370 	val = scf_value_create(g_hndl);
17371 	iter = scf_iter_create(g_hndl);
17372 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17373 	    svc == NULL || scope == NULL) {
17374 		uu_warn(gettext("Unable to create a property group, or "
17375 		    "property\n"));
17376 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17377 		    "pg is not NULL");
17378 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17379 		    "prop is not NULL");
17380 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17381 		    "val is not NULL");
17382 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17383 		    "iter is not NULL");
17384 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17385 		    "svc is not NULL");
17386 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17387 		    "scope is not NULL");
17388 		uu_warn(gettext("scf error is : %s\n"),
17389 		    scf_strerror(scf_error()));
17390 		scfdie();
17391 	}
17392 
17393 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17394 		switch (scf_error()) {
17395 		case SCF_ERROR_CONNECTION_BROKEN:
17396 		case SCF_ERROR_NOT_FOUND:
17397 			goto out;
17398 
17399 		case SCF_ERROR_HANDLE_MISMATCH:
17400 		case SCF_ERROR_NOT_BOUND:
17401 		case SCF_ERROR_INVALID_ARGUMENT:
17402 		default:
17403 			bad_error("scf_handle_get_scope", scf_error());
17404 		}
17405 	}
17406 
17407 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17408 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17409 		    HASH_SVC);
17410 		goto out;
17411 	}
17412 
17413 	pgname = safe_malloc(max_scf_name_len + 1);
17414 	mfile = safe_malloc(max_scf_value_len + 1);
17415 
17416 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17417 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17418 		    scf_strerror(scf_error()));
17419 		goto out;
17420 	}
17421 
17422 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17423 		if (r == -1)
17424 			goto out;
17425 
17426 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17427 			switch (scf_error()) {
17428 			case SCF_ERROR_DELETED:
17429 				return (ENODEV);
17430 
17431 			case SCF_ERROR_CONNECTION_BROKEN:
17432 				return (ECONNABORTED);
17433 
17434 			case SCF_ERROR_NOT_SET:
17435 			case SCF_ERROR_NOT_BOUND:
17436 			default:
17437 				bad_error("scf_pg_get_name", scf_error());
17438 			}
17439 		}
17440 		if (IGNORE_VAR) {
17441 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17442 				continue;
17443 		}
17444 
17445 		/*
17446 		 * If unable to get the property continue as this is an
17447 		 * entry that has no location to check against.
17448 		 */
17449 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17450 			continue;
17451 		}
17452 
17453 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17454 			uu_warn(gettext("Unable to get value from %s\n"),
17455 			    pgname);
17456 
17457 			switch (scf_error()) {
17458 			case SCF_ERROR_DELETED:
17459 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17460 			case SCF_ERROR_NOT_FOUND:
17461 			case SCF_ERROR_NOT_SET:
17462 				continue;
17463 
17464 			case SCF_ERROR_CONNECTION_BROKEN:
17465 				r = scferror2errno(scf_error());
17466 				goto out;
17467 
17468 			case SCF_ERROR_HANDLE_MISMATCH:
17469 			case SCF_ERROR_NOT_BOUND:
17470 			default:
17471 				bad_error("scf_property_get_value",
17472 				    scf_error());
17473 			}
17474 		}
17475 
17476 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17477 		    == -1) {
17478 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17479 			    pgname, scf_strerror(scf_error()));
17480 
17481 			switch (scf_error()) {
17482 			case SCF_ERROR_NOT_SET:
17483 			case SCF_ERROR_TYPE_MISMATCH:
17484 				continue;
17485 
17486 			default:
17487 				bad_error("scf_value_get_astring", scf_error());
17488 			}
17489 		}
17490 
17491 		if (access(mfile, F_OK) == 0)
17492 			continue;
17493 
17494 		(void) scf_pg_delete(pg);
17495 	}
17496 
17497 out:
17498 	scf_scope_destroy(scope);
17499 	scf_service_destroy(svc);
17500 	scf_pg_destroy(pg);
17501 	scf_property_destroy(prop);
17502 	scf_value_destroy(val);
17503 	scf_iter_destroy(iter);
17504 	free(pgname);
17505 	free(mfile);
17506 
17507 	return (0);
17508 }
17509 
17510 #ifndef NATIVE_BUILD
17511 /* ARGSUSED */
17512 CPL_MATCH_FN(complete_select)
17513 {
17514 	const char *arg0, *arg1, *arg1end;
17515 	int word_start, err = 0, r;
17516 	size_t len;
17517 	char *buf;
17518 
17519 	lscf_prep_hndl();
17520 
17521 	arg0 = line + strspn(line, " \t");
17522 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17523 
17524 	arg1 = arg0 + sizeof ("select") - 1;
17525 	arg1 += strspn(arg1, " \t");
17526 	word_start = arg1 - line;
17527 
17528 	arg1end = arg1 + strcspn(arg1, " \t");
17529 	if (arg1end < line + word_end)
17530 		return (0);
17531 
17532 	len = line + word_end - arg1;
17533 
17534 	buf = safe_malloc(max_scf_name_len + 1);
17535 
17536 	if (cur_snap != NULL) {
17537 		return (0);
17538 	} else if (cur_inst != NULL) {
17539 		return (0);
17540 	} else if (cur_svc != NULL) {
17541 		scf_instance_t *inst;
17542 		scf_iter_t *iter;
17543 
17544 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17545 		    (iter = scf_iter_create(g_hndl)) == NULL)
17546 			scfdie();
17547 
17548 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17549 			scfdie();
17550 
17551 		for (;;) {
17552 			r = scf_iter_next_instance(iter, inst);
17553 			if (r == 0)
17554 				break;
17555 			if (r != 1)
17556 				scfdie();
17557 
17558 			if (scf_instance_get_name(inst, buf,
17559 			    max_scf_name_len + 1) < 0)
17560 				scfdie();
17561 
17562 			if (strncmp(buf, arg1, len) == 0) {
17563 				err = cpl_add_completion(cpl, line, word_start,
17564 				    word_end, buf + len, "", " ");
17565 				if (err != 0)
17566 					break;
17567 			}
17568 		}
17569 
17570 		scf_iter_destroy(iter);
17571 		scf_instance_destroy(inst);
17572 
17573 		return (err);
17574 	} else {
17575 		scf_service_t *svc;
17576 		scf_iter_t *iter;
17577 
17578 		assert(cur_scope != NULL);
17579 
17580 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17581 		    (iter = scf_iter_create(g_hndl)) == NULL)
17582 			scfdie();
17583 
17584 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17585 			scfdie();
17586 
17587 		for (;;) {
17588 			r = scf_iter_next_service(iter, svc);
17589 			if (r == 0)
17590 				break;
17591 			if (r != 1)
17592 				scfdie();
17593 
17594 			if (scf_service_get_name(svc, buf,
17595 			    max_scf_name_len + 1) < 0)
17596 				scfdie();
17597 
17598 			if (strncmp(buf, arg1, len) == 0) {
17599 				err = cpl_add_completion(cpl, line, word_start,
17600 				    word_end, buf + len, "", " ");
17601 				if (err != 0)
17602 					break;
17603 			}
17604 		}
17605 
17606 		scf_iter_destroy(iter);
17607 		scf_service_destroy(svc);
17608 
17609 		return (err);
17610 	}
17611 }
17612 
17613 /* ARGSUSED */
17614 CPL_MATCH_FN(complete_command)
17615 {
17616 	uint32_t scope = 0;
17617 
17618 	if (cur_snap != NULL)
17619 		scope = CS_SNAP;
17620 	else if (cur_inst != NULL)
17621 		scope = CS_INST;
17622 	else if (cur_svc != NULL)
17623 		scope = CS_SVC;
17624 	else
17625 		scope = CS_SCOPE;
17626 
17627 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17628 }
17629 #endif	/* NATIVE_BUILD */
17630