xref: /illumos-gate/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision 99ea293e719ac006d413e4fde6ac0d5cd4dd6c59)
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 2020 Joyent, Inc.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  * Copyright 2017 RackTop Systems.
27  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
28  */
29 
30 
31 #include <alloca.h>
32 #include <assert.h>
33 #include <ctype.h>
34 #include <door.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <fnmatch.h>
38 #include <inttypes.h>
39 #include <libintl.h>
40 #include <libnvpair.h>
41 #include <libscf.h>
42 #include <libscf_priv.h>
43 #include <libtecla.h>
44 #include <libuutil.h>
45 #include <limits.h>
46 #include <locale.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include <strings.h>
50 #include <time.h>
51 #include <unistd.h>
52 #include <wait.h>
53 #include <poll.h>
54 
55 #include <libxml/tree.h>
56 
57 #include <sys/param.h>
58 
59 #include <sys/stat.h>
60 #include <sys/mman.h>
61 
62 #include "svccfg.h"
63 #include "notify_params.h"
64 #include "manifest_hash.h"
65 #include "manifest_find.h"
66 
67 /* The colon namespaces in each entity (each followed by a newline). */
68 #define	COLON_NAMESPACES	":properties\n"
69 
70 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
71 
72 /* These are characters which the lexer requires to be in double-quotes. */
73 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
74 
75 #define	HASH_SIZE		16
76 #define	HASH_PG_TYPE		"framework"
77 #define	HASH_PG_FLAGS		0
78 #define	HASH_PROP		"md5sum"
79 
80 /*
81  * Indentation used in the output of the describe subcommand.
82  */
83 #define	TMPL_VALUE_INDENT	"  "
84 #define	TMPL_INDENT		"    "
85 #define	TMPL_INDENT_2X		"        "
86 #define	TMPL_CHOICE_INDENT	"      "
87 
88 /*
89  * Directory locations for manifests
90  */
91 #define	VARSVC_DIR		"/var/svc/manifest"
92 #define	LIBSVC_DIR		"/lib/svc/manifest"
93 #define	VARSVC_PR		"var_svc_manifest"
94 #define	LIBSVC_PR		"lib_svc_manifest"
95 #define	MFSTFILEPR		"manifestfile"
96 
97 #define	SUPPORTPROP		"support"
98 
99 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
100 
101 #define	MFSTFILE_MAX		16
102 
103 /*
104  * These are the classes of elements which may appear as children of service
105  * or instance elements in XML manifests.
106  */
107 struct entity_elts {
108 	xmlNodePtr	create_default_instance;
109 	xmlNodePtr	single_instance;
110 	xmlNodePtr	restarter;
111 	xmlNodePtr	dependencies;
112 	xmlNodePtr	dependents;
113 	xmlNodePtr	method_context;
114 	xmlNodePtr	exec_methods;
115 	xmlNodePtr	notify_params;
116 	xmlNodePtr	property_groups;
117 	xmlNodePtr	instances;
118 	xmlNodePtr	stability;
119 	xmlNodePtr	template;
120 };
121 
122 /*
123  * Likewise for property_group elements.
124  */
125 struct pg_elts {
126 	xmlNodePtr	stability;
127 	xmlNodePtr	propvals;
128 	xmlNodePtr	properties;
129 };
130 
131 /*
132  * Likewise for template elements.
133  */
134 struct template_elts {
135 	xmlNodePtr	common_name;
136 	xmlNodePtr	description;
137 	xmlNodePtr	documentation;
138 };
139 
140 /*
141  * Likewise for type (for notification parameters) elements.
142  */
143 struct params_elts {
144 	xmlNodePtr	paramval;
145 	xmlNodePtr	parameter;
146 };
147 
148 /*
149  * This structure is for snaplevel lists.  They are convenient because libscf
150  * only allows traversing snaplevels in one direction.
151  */
152 struct snaplevel {
153 	uu_list_node_t	list_node;
154 	scf_snaplevel_t	*sl;
155 };
156 
157 /*
158  * This is used for communication between lscf_service_export and
159  * export_callback.
160  */
161 struct export_args {
162 	const char	*filename;
163 	int		flags;
164 };
165 
166 /*
167  * The service_manifest structure is used by the upgrade process
168  * to create a list of service to manifest linkages from the manifests
169  * in a set of given directories.
170  */
171 typedef struct service_manifest {
172 	const char	*servicename;
173 	uu_list_t	*mfstlist;
174 	size_t	mfstlist_sz;
175 
176 	uu_avl_node_t	svcmfst_node;
177 } service_manifest_t;
178 
179 /*
180  * Structure to track the manifest file property group
181  * and the manifest file associated with that property
182  * group.  Also, a flag to keep the access once it has
183  * been checked.
184  */
185 struct mpg_mfile {
186 	char	*mpg;
187 	char	*mfile;
188 	int	access;
189 };
190 
191 const char * const scf_pg_general = SCF_PG_GENERAL;
192 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
193 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
194 const char * const scf_property_external = "external";
195 
196 const char * const snap_initial = "initial";
197 const char * const snap_lastimport = "last-import";
198 const char * const snap_previous = "previous";
199 const char * const snap_running = "running";
200 
201 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
202 
203 ssize_t max_scf_fmri_len;
204 ssize_t max_scf_name_len;
205 ssize_t max_scf_pg_type_len;
206 ssize_t max_scf_value_len;
207 static size_t max_scf_len;
208 
209 static scf_scope_t *cur_scope;
210 static scf_service_t *cur_svc = NULL;
211 static scf_instance_t *cur_inst = NULL;
212 static scf_snapshot_t *cur_snap = NULL;
213 static scf_snaplevel_t *cur_level = NULL;
214 
215 static uu_list_pool_t *snaplevel_pool;
216 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
217 static uu_list_t *cur_levels;
218 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
219 
220 static FILE *tempfile = NULL;
221 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
222 
223 static const char *emsg_entity_not_selected;
224 static const char *emsg_permission_denied;
225 static const char *emsg_create_xml;
226 static const char *emsg_cant_modify_snapshots;
227 static const char *emsg_invalid_for_snapshot;
228 static const char *emsg_read_only;
229 static const char *emsg_deleted;
230 static const char *emsg_invalid_pg_name;
231 static const char *emsg_invalid_prop_name;
232 static const char *emsg_no_such_pg;
233 static const char *emsg_fmri_invalid_pg_name;
234 static const char *emsg_fmri_invalid_pg_name_type;
235 static const char *emsg_pg_added;
236 static const char *emsg_pg_changed;
237 static const char *emsg_pg_deleted;
238 static const char *emsg_pg_mod_perm;
239 static const char *emsg_pg_add_perm;
240 static const char *emsg_pg_del_perm;
241 static const char *emsg_snap_perm;
242 static const char *emsg_dpt_dangling;
243 static const char *emsg_dpt_no_dep;
244 
245 static int li_only = 0;
246 static int no_refresh = 0;
247 
248 /* how long in ns we should wait between checks for a pg */
249 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
250 
251 /* import globals, to minimize allocations */
252 static scf_scope_t *imp_scope = NULL;
253 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
254 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
255 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
256 static scf_snapshot_t *imp_rsnap = NULL;
257 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
258 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
259 static scf_property_t *imp_prop = NULL;
260 static scf_iter_t *imp_iter = NULL;
261 static scf_iter_t *imp_rpg_iter = NULL;
262 static scf_iter_t *imp_up_iter = NULL;
263 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
264 static char *imp_str = NULL;
265 static size_t imp_str_sz;
266 static char *imp_tsname = NULL;
267 static char *imp_fe1 = NULL;		/* for fmri_equal() */
268 static char *imp_fe2 = NULL;
269 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
270 
271 /* upgrade_dependents() globals */
272 static scf_instance_t *ud_inst = NULL;
273 static scf_snaplevel_t *ud_snpl = NULL;
274 static scf_propertygroup_t *ud_pg = NULL;
275 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
276 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
277 static int ud_run_dpts_pg_set = 0;
278 static scf_property_t *ud_prop = NULL;
279 static scf_property_t *ud_dpt_prop = NULL;
280 static scf_value_t *ud_val = NULL;
281 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
282 static scf_transaction_t *ud_tx = NULL;
283 static char *ud_ctarg = NULL;
284 static char *ud_oldtarg = NULL;
285 static char *ud_name = NULL;
286 
287 /* export globals */
288 static scf_instance_t *exp_inst;
289 static scf_propertygroup_t *exp_pg;
290 static scf_property_t *exp_prop;
291 static scf_value_t *exp_val;
292 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
293 static char *exp_str;
294 static size_t exp_str_sz;
295 
296 /* cleanup globals */
297 static uu_avl_pool_t *service_manifest_pool = NULL;
298 static uu_avl_t *service_manifest_tree = NULL;
299 
300 static void scfdie_lineno(int lineno) __NORETURN;
301 
302 static char *start_method_names[] = {
303 	"start",
304 	"inetd_start",
305 	NULL
306 };
307 
308 static struct uri_scheme {
309 	const char *scheme;
310 	const char *protocol;
311 } uri_scheme[] = {
312 	{ "mailto", "smtp" },
313 	{ "snmp", "snmp" },
314 	{ "syslog", "syslog" },
315 	{ NULL, NULL }
316 };
317 #define	URI_SCHEME_NUM ((sizeof (uri_scheme) / \
318     sizeof (struct uri_scheme)) - 1)
319 
320 static int
321 check_uri_scheme(const char *scheme)
322 {
323 	int i;
324 
325 	for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
326 		if (strcmp(scheme, uri_scheme[i].scheme) == 0)
327 			return (i);
328 	}
329 
330 	return (-1);
331 }
332 
333 static int
334 check_uri_protocol(const char *p)
335 {
336 	int i;
337 
338 	for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
339 		if (strcmp(p, uri_scheme[i].protocol) == 0)
340 			return (i);
341 	}
342 
343 	return (-1);
344 }
345 
346 /*
347  * For unexpected libscf errors.
348  */
349 #ifdef NDEBUG
350 
351 static void scfdie(void) __NORETURN;
352 
353 static void
354 scfdie(void)
355 {
356 	scf_error_t err = scf_error();
357 
358 	if (err == SCF_ERROR_CONNECTION_BROKEN)
359 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
360 
361 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
362 	    scf_strerror(err));
363 }
364 
365 #else
366 
367 #define	scfdie()	scfdie_lineno(__LINE__)
368 
369 static void
370 scfdie_lineno(int lineno)
371 {
372 	scf_error_t err = scf_error();
373 
374 	if (err == SCF_ERROR_CONNECTION_BROKEN)
375 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
376 
377 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
378 	    ": %s.\n"), lineno, scf_strerror(err));
379 }
380 
381 #endif
382 
383 static void
384 scfwarn(void)
385 {
386 	warn(gettext("Unexpected libscf error: %s.\n"),
387 	    scf_strerror(scf_error()));
388 }
389 
390 /*
391  * Clear a field of a structure.
392  */
393 static int
394 clear_int(void *a, void *b)
395 {
396 	/* LINTED */
397 	*(int *)((char *)a + (size_t)b) = 0;
398 
399 	return (UU_WALK_NEXT);
400 }
401 
402 static int
403 scferror2errno(scf_error_t err)
404 {
405 	switch (err) {
406 	case SCF_ERROR_BACKEND_ACCESS:
407 		return (EACCES);
408 
409 	case SCF_ERROR_BACKEND_READONLY:
410 		return (EROFS);
411 
412 	case SCF_ERROR_CONNECTION_BROKEN:
413 		return (ECONNABORTED);
414 
415 	case SCF_ERROR_CONSTRAINT_VIOLATED:
416 	case SCF_ERROR_INVALID_ARGUMENT:
417 		return (EINVAL);
418 
419 	case SCF_ERROR_DELETED:
420 		return (ECANCELED);
421 
422 	case SCF_ERROR_EXISTS:
423 		return (EEXIST);
424 
425 	case SCF_ERROR_NO_MEMORY:
426 		return (ENOMEM);
427 
428 	case SCF_ERROR_NO_RESOURCES:
429 		return (ENOSPC);
430 
431 	case SCF_ERROR_NOT_FOUND:
432 		return (ENOENT);
433 
434 	case SCF_ERROR_PERMISSION_DENIED:
435 		return (EPERM);
436 
437 	default:
438 #ifndef NDEBUG
439 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
440 		    __FILE__, __LINE__, err);
441 #else
442 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
443 #endif
444 		abort();
445 		/* NOTREACHED */
446 	}
447 }
448 
449 static int
450 entity_get_pg(void *ent, int issvc, const char *name,
451     scf_propertygroup_t *pg)
452 {
453 	if (issvc)
454 		return (scf_service_get_pg(ent, name, pg));
455 	else
456 		return (scf_instance_get_pg(ent, name, pg));
457 }
458 
459 static void
460 entity_destroy(void *ent, int issvc)
461 {
462 	if (issvc)
463 		scf_service_destroy(ent);
464 	else
465 		scf_instance_destroy(ent);
466 }
467 
468 static int
469 get_pg(const char *pg_name, scf_propertygroup_t *pg)
470 {
471 	int ret;
472 
473 	if (cur_level != NULL)
474 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
475 	else if (cur_inst != NULL)
476 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
477 	else
478 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
479 
480 	return (ret);
481 }
482 
483 /*
484  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
485  * snaplevel.  Otherwise find the instance snaplevel.
486  *
487  * Returns
488  *   0 - success
489  *   ECONNABORTED - repository connection broken
490  *   ECANCELED - instance containing snap was deleted
491  *   ENOENT - snap has no snaplevels
492  *	    - requested snaplevel not found
493  */
494 static int
495 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
496 {
497 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
498 		switch (scf_error()) {
499 		case SCF_ERROR_CONNECTION_BROKEN:
500 		case SCF_ERROR_DELETED:
501 		case SCF_ERROR_NOT_FOUND:
502 			return (scferror2errno(scf_error()));
503 
504 		case SCF_ERROR_HANDLE_MISMATCH:
505 		case SCF_ERROR_NOT_BOUND:
506 		case SCF_ERROR_NOT_SET:
507 		default:
508 			bad_error("scf_snapshot_get_base_snaplevel",
509 			    scf_error());
510 		}
511 	}
512 
513 	for (;;) {
514 		ssize_t ssz;
515 
516 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
517 		if (ssz >= 0) {
518 			if (!get_svc)
519 				return (0);
520 		} else {
521 			switch (scf_error()) {
522 			case SCF_ERROR_CONSTRAINT_VIOLATED:
523 				if (get_svc)
524 					return (0);
525 				break;
526 
527 			case SCF_ERROR_DELETED:
528 			case SCF_ERROR_CONNECTION_BROKEN:
529 				return (scferror2errno(scf_error()));
530 
531 			case SCF_ERROR_NOT_SET:
532 			case SCF_ERROR_NOT_BOUND:
533 			default:
534 				bad_error("scf_snaplevel_get_instance_name",
535 				    scf_error());
536 			}
537 		}
538 
539 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
540 			switch (scf_error()) {
541 			case SCF_ERROR_NOT_FOUND:
542 			case SCF_ERROR_CONNECTION_BROKEN:
543 			case SCF_ERROR_DELETED:
544 				return (scferror2errno(scf_error()));
545 
546 			case SCF_ERROR_HANDLE_MISMATCH:
547 			case SCF_ERROR_NOT_BOUND:
548 			case SCF_ERROR_NOT_SET:
549 			case SCF_ERROR_INVALID_ARGUMENT:
550 			default:
551 				bad_error("scf_snaplevel_get_next_snaplevel",
552 				    scf_error());
553 			}
554 		}
555 	}
556 }
557 
558 /*
559  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
560  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
561  * the property group named name in it.  If it doesn't have a running
562  * snapshot, set pg to the instance's current property group named name.
563  *
564  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
565  * its instances.  If one has a running snapshot with a service snaplevel, set
566  * pg to the property group named name in it.  If no such snaplevel could be
567  * found, set pg to the service's current property group named name.
568  *
569  * iter, inst, snap, and snpl are required scratch objects.
570  *
571  * Returns
572  *   0 - success
573  *   ECONNABORTED - repository connection broken
574  *   ECANCELED - ent was deleted
575  *   ENOENT - no such property group
576  *   EINVAL - name is an invalid property group name
577  *   EBADF - found running snapshot is missing a snaplevel
578  */
579 static int
580 entity_get_running_pg(void *ent, int issvc, const char *name,
581     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
582     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
583 {
584 	int r;
585 
586 	if (issvc) {
587 		/* Search for an instance with a running snapshot. */
588 		if (scf_iter_service_instances(iter, ent) != 0) {
589 			switch (scf_error()) {
590 			case SCF_ERROR_DELETED:
591 			case SCF_ERROR_CONNECTION_BROKEN:
592 				return (scferror2errno(scf_error()));
593 
594 			case SCF_ERROR_NOT_SET:
595 			case SCF_ERROR_NOT_BOUND:
596 			case SCF_ERROR_HANDLE_MISMATCH:
597 			default:
598 				bad_error("scf_iter_service_instances",
599 				    scf_error());
600 			}
601 		}
602 
603 		for (;;) {
604 			r = scf_iter_next_instance(iter, inst);
605 			if (r == 0) {
606 				if (scf_service_get_pg(ent, name, pg) == 0)
607 					return (0);
608 
609 				switch (scf_error()) {
610 				case SCF_ERROR_DELETED:
611 				case SCF_ERROR_NOT_FOUND:
612 				case SCF_ERROR_INVALID_ARGUMENT:
613 				case SCF_ERROR_CONNECTION_BROKEN:
614 					return (scferror2errno(scf_error()));
615 
616 				case SCF_ERROR_NOT_BOUND:
617 				case SCF_ERROR_HANDLE_MISMATCH:
618 				case SCF_ERROR_NOT_SET:
619 				default:
620 					bad_error("scf_service_get_pg",
621 					    scf_error());
622 				}
623 			}
624 			if (r != 1) {
625 				switch (scf_error()) {
626 				case SCF_ERROR_DELETED:
627 				case SCF_ERROR_CONNECTION_BROKEN:
628 					return (scferror2errno(scf_error()));
629 
630 				case SCF_ERROR_INVALID_ARGUMENT:
631 				case SCF_ERROR_NOT_SET:
632 				case SCF_ERROR_NOT_BOUND:
633 				case SCF_ERROR_HANDLE_MISMATCH:
634 				default:
635 					bad_error("scf_iter_next_instance",
636 					    scf_error());
637 				}
638 			}
639 
640 			if (scf_instance_get_snapshot(inst, snap_running,
641 			    snap) == 0)
642 				break;
643 
644 			switch (scf_error()) {
645 			case SCF_ERROR_NOT_FOUND:
646 			case SCF_ERROR_DELETED:
647 				continue;
648 
649 			case SCF_ERROR_CONNECTION_BROKEN:
650 				return (ECONNABORTED);
651 
652 			case SCF_ERROR_HANDLE_MISMATCH:
653 			case SCF_ERROR_INVALID_ARGUMENT:
654 			case SCF_ERROR_NOT_SET:
655 			case SCF_ERROR_NOT_BOUND:
656 			default:
657 				bad_error("scf_instance_get_snapshot",
658 				    scf_error());
659 			}
660 		}
661 	} else {
662 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
663 			switch (scf_error()) {
664 			case SCF_ERROR_NOT_FOUND:
665 				break;
666 
667 			case SCF_ERROR_DELETED:
668 			case SCF_ERROR_CONNECTION_BROKEN:
669 				return (scferror2errno(scf_error()));
670 
671 			case SCF_ERROR_NOT_BOUND:
672 			case SCF_ERROR_HANDLE_MISMATCH:
673 			case SCF_ERROR_INVALID_ARGUMENT:
674 			case SCF_ERROR_NOT_SET:
675 			default:
676 				bad_error("scf_instance_get_snapshot",
677 				    scf_error());
678 			}
679 
680 			if (scf_instance_get_pg(ent, name, pg) == 0)
681 				return (0);
682 
683 			switch (scf_error()) {
684 			case SCF_ERROR_DELETED:
685 			case SCF_ERROR_NOT_FOUND:
686 			case SCF_ERROR_INVALID_ARGUMENT:
687 			case SCF_ERROR_CONNECTION_BROKEN:
688 				return (scferror2errno(scf_error()));
689 
690 			case SCF_ERROR_NOT_BOUND:
691 			case SCF_ERROR_HANDLE_MISMATCH:
692 			case SCF_ERROR_NOT_SET:
693 			default:
694 				bad_error("scf_instance_get_pg", scf_error());
695 			}
696 		}
697 	}
698 
699 	r = get_snaplevel(snap, issvc, snpl);
700 	switch (r) {
701 	case 0:
702 		break;
703 
704 	case ECONNABORTED:
705 	case ECANCELED:
706 		return (r);
707 
708 	case ENOENT:
709 		return (EBADF);
710 
711 	default:
712 		bad_error("get_snaplevel", r);
713 	}
714 
715 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
716 		return (0);
717 
718 	switch (scf_error()) {
719 	case SCF_ERROR_DELETED:
720 	case SCF_ERROR_INVALID_ARGUMENT:
721 	case SCF_ERROR_CONNECTION_BROKEN:
722 	case SCF_ERROR_NOT_FOUND:
723 		return (scferror2errno(scf_error()));
724 
725 	case SCF_ERROR_NOT_BOUND:
726 	case SCF_ERROR_HANDLE_MISMATCH:
727 	case SCF_ERROR_NOT_SET:
728 	default:
729 		bad_error("scf_snaplevel_get_pg", scf_error());
730 		/* NOTREACHED */
731 	}
732 }
733 
734 /*
735  * To be registered with atexit().
736  */
737 static void
738 remove_tempfile(void)
739 {
740 	int ret;
741 
742 	if (tempfile != NULL) {
743 		if (fclose(tempfile) == EOF)
744 			(void) warn(gettext("Could not close temporary file"));
745 		tempfile = NULL;
746 	}
747 
748 	if (tempfilename[0] != '\0') {
749 		do {
750 			ret = remove(tempfilename);
751 		} while (ret == -1 && errno == EINTR);
752 		if (ret == -1)
753 			warn(gettext("Could not remove temporary file"));
754 		tempfilename[0] = '\0';
755 	}
756 }
757 
758 /*
759  * Launch private svc.configd(1M) for manipulating alternate repositories.
760  */
761 static void
762 start_private_repository(engine_state_t *est)
763 {
764 	int fd, stat;
765 	struct door_info info;
766 	pid_t pid;
767 
768 	/*
769 	 * 1.  Create a temporary file for the door.
770 	 */
771 	if (est->sc_repo_doorname != NULL)
772 		free((void *)est->sc_repo_doorname);
773 
774 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
775 	if (est->sc_repo_doorname == NULL)
776 		uu_die(gettext("Could not acquire temporary filename"));
777 
778 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
779 	if (fd < 0)
780 		uu_die(gettext("Could not create temporary file for "
781 		    "repository server"));
782 
783 	(void) close(fd);
784 
785 	/*
786 	 * 2.  Launch a configd with that door, using the specified
787 	 * repository.
788 	 */
789 	if ((est->sc_repo_pid = fork()) == 0) {
790 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
791 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
792 		    NULL);
793 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
794 	} else if (est->sc_repo_pid == -1)
795 		uu_die(gettext("Attempt to fork failed"));
796 
797 	do {
798 		pid = waitpid(est->sc_repo_pid, &stat, 0);
799 	} while (pid == -1 && errno == EINTR);
800 
801 	if (pid == -1)
802 		uu_die(gettext("Could not waitpid() for repository server"));
803 
804 	if (!WIFEXITED(stat)) {
805 		uu_die(gettext("Repository server failed (status %d).\n"),
806 		    stat);
807 	} else if (WEXITSTATUS(stat) != 0) {
808 		uu_die(gettext("Repository server failed (exit %d).\n"),
809 		    WEXITSTATUS(stat));
810 	}
811 
812 	/*
813 	 * See if it was successful by checking if the door is a door.
814 	 */
815 
816 	fd = open(est->sc_repo_doorname, O_RDWR);
817 	if (fd < 0)
818 		uu_die(gettext("Could not open door \"%s\""),
819 		    est->sc_repo_doorname);
820 
821 	if (door_info(fd, &info) < 0)
822 		uu_die(gettext("Unexpected door_info() error"));
823 
824 	if (close(fd) == -1)
825 		warn(gettext("Could not close repository door"),
826 		    strerror(errno));
827 
828 	est->sc_repo_pid = info.di_target;
829 }
830 
831 void
832 lscf_cleanup(void)
833 {
834 	/*
835 	 * In the case where we've launched a private svc.configd(1M)
836 	 * instance, we must terminate our child and remove the temporary
837 	 * rendezvous point.
838 	 */
839 	if (est->sc_repo_pid > 0) {
840 		(void) kill(est->sc_repo_pid, SIGTERM);
841 		(void) waitpid(est->sc_repo_pid, NULL, 0);
842 		(void) unlink(est->sc_repo_doorname);
843 
844 		est->sc_repo_pid = 0;
845 	}
846 }
847 
848 void
849 unselect_cursnap(void)
850 {
851 	void *cookie;
852 
853 	cur_level = NULL;
854 
855 	cookie = NULL;
856 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
857 		scf_snaplevel_destroy(cur_elt->sl);
858 		free(cur_elt);
859 	}
860 
861 	scf_snapshot_destroy(cur_snap);
862 	cur_snap = NULL;
863 }
864 
865 void
866 lscf_prep_hndl(void)
867 {
868 	if (g_hndl != NULL)
869 		return;
870 
871 	g_hndl = scf_handle_create(SCF_VERSION);
872 	if (g_hndl == NULL)
873 		scfdie();
874 
875 	if (est->sc_repo_filename != NULL)
876 		start_private_repository(est);
877 
878 	if (est->sc_repo_doorname != NULL) {
879 		scf_value_t *repo_value;
880 		int ret;
881 
882 		repo_value = scf_value_create(g_hndl);
883 		if (repo_value == NULL)
884 			scfdie();
885 
886 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
887 		assert(ret == SCF_SUCCESS);
888 
889 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
890 		    SCF_SUCCESS)
891 			scfdie();
892 
893 		scf_value_destroy(repo_value);
894 	}
895 
896 	if (scf_handle_bind(g_hndl) != 0)
897 		uu_die(gettext("Could not connect to repository server: %s.\n"),
898 		    scf_strerror(scf_error()));
899 
900 	cur_scope = scf_scope_create(g_hndl);
901 	if (cur_scope == NULL)
902 		scfdie();
903 
904 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
905 		scfdie();
906 }
907 
908 static void
909 repository_teardown(void)
910 {
911 	if (g_hndl != NULL) {
912 		if (cur_snap != NULL)
913 			unselect_cursnap();
914 		scf_instance_destroy(cur_inst);
915 		scf_service_destroy(cur_svc);
916 		scf_scope_destroy(cur_scope);
917 		scf_handle_destroy(g_hndl);
918 		cur_inst = NULL;
919 		cur_svc = NULL;
920 		cur_scope = NULL;
921 		g_hndl = NULL;
922 		lscf_cleanup();
923 	}
924 }
925 
926 void
927 lscf_set_repository(const char *repfile, int force)
928 {
929 	repository_teardown();
930 
931 	if (est->sc_repo_filename != NULL) {
932 		free((void *)est->sc_repo_filename);
933 		est->sc_repo_filename = NULL;
934 	}
935 
936 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
937 		/*
938 		 * Repository file does not exist
939 		 * or has no read permission.
940 		 */
941 		warn(gettext("Cannot access \"%s\": %s\n"),
942 		    repfile, strerror(errno));
943 	} else {
944 		est->sc_repo_filename = safe_strdup(repfile);
945 	}
946 
947 	lscf_prep_hndl();
948 }
949 
950 void
951 lscf_init()
952 {
953 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
954 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
955 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
956 	    0 ||
957 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
958 		scfdie();
959 
960 	max_scf_len = max_scf_fmri_len;
961 	if (max_scf_name_len > max_scf_len)
962 		max_scf_len = max_scf_name_len;
963 	if (max_scf_pg_type_len > max_scf_len)
964 		max_scf_len = max_scf_pg_type_len;
965 	/*
966 	 * When a value of type opaque is represented as a string, the
967 	 * string contains 2 characters for every byte of data.  That is
968 	 * because the string contains the hex representation of the opaque
969 	 * value.
970 	 */
971 	if (2 * max_scf_value_len > max_scf_len)
972 		max_scf_len = 2 * max_scf_value_len;
973 
974 	if (atexit(remove_tempfile) != 0)
975 		uu_die(gettext("Could not register atexit() function"));
976 
977 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
978 	emsg_permission_denied = gettext("Permission denied.\n");
979 	emsg_create_xml = gettext("Could not create XML node.\n");
980 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
981 	emsg_invalid_for_snapshot =
982 	    gettext("Invalid operation on a snapshot.\n");
983 	emsg_read_only = gettext("Backend read-only.\n");
984 	emsg_deleted = gettext("Current selection has been deleted.\n");
985 	emsg_invalid_pg_name =
986 	    gettext("Invalid property group name \"%s\".\n");
987 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
988 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
989 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
990 	    "with invalid name \"%s\".\n");
991 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
992 	    "group with invalid name \"%s\" or type \"%s\".\n");
993 	emsg_pg_added = gettext("%s changed unexpectedly "
994 	    "(property group \"%s\" added).\n");
995 	emsg_pg_changed = gettext("%s changed unexpectedly "
996 	    "(property group \"%s\" changed).\n");
997 	emsg_pg_deleted = gettext("%s changed unexpectedly "
998 	    "(property group \"%s\" or an ancestor was deleted).\n");
999 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
1000 	    "in %s (permission denied).\n");
1001 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1002 	    "in %s (permission denied).\n");
1003 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1004 	    "in %s (permission denied).\n");
1005 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1006 	    "(permission denied).\n");
1007 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1008 	    "new dependent \"%s\" because it already exists).  Warning: The "
1009 	    "current dependent's target (%s) does not exist.\n");
1010 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1011 	    "dependent \"%s\" because it already exists).  Warning: The "
1012 	    "current dependent's target (%s) does not have a dependency named "
1013 	    "\"%s\" as expected.\n");
1014 
1015 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1016 	    offsetof(string_list_t, node), NULL, 0);
1017 	snaplevel_pool = uu_list_pool_create("snaplevels",
1018 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1019 	    NULL, 0);
1020 }
1021 
1022 
1023 static const char *
1024 prop_to_typestr(const scf_property_t *prop)
1025 {
1026 	scf_type_t ty;
1027 
1028 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1029 		scfdie();
1030 
1031 	return (scf_type_to_string(ty));
1032 }
1033 
1034 static scf_type_t
1035 string_to_type(const char *type)
1036 {
1037 	size_t len = strlen(type);
1038 	char *buf;
1039 
1040 	if (len == 0 || type[len - 1] != ':')
1041 		return (SCF_TYPE_INVALID);
1042 
1043 	buf = (char *)alloca(len + 1);
1044 	(void) strlcpy(buf, type, len + 1);
1045 	buf[len - 1] = 0;
1046 
1047 	return (scf_string_to_type(buf));
1048 }
1049 
1050 static scf_value_t *
1051 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1052 {
1053 	scf_value_t *v;
1054 	char *dup, *nstr;
1055 	size_t len;
1056 
1057 	v = scf_value_create(g_hndl);
1058 	if (v == NULL)
1059 		scfdie();
1060 
1061 	len = strlen(str);
1062 	if (require_quotes &&
1063 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1064 		semerr(gettext("Multiple string values or string values "
1065 		    "with spaces must be quoted with '\"'.\n"));
1066 		scf_value_destroy(v);
1067 		return (NULL);
1068 	}
1069 
1070 	nstr = dup = safe_strdup(str);
1071 	if (dup[0] == '\"') {
1072 		/*
1073 		 * Strip out the first and the last quote.
1074 		 */
1075 		dup[len - 1] = '\0';
1076 		nstr = dup + 1;
1077 	}
1078 
1079 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1080 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1081 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1082 		    scf_type_to_string(ty), nstr);
1083 		scf_value_destroy(v);
1084 		v = NULL;
1085 	}
1086 	free(dup);
1087 	return (v);
1088 }
1089 
1090 /*
1091  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1092  * Optionally append a comment prefix ('#') to newlines ('\n').
1093  */
1094 static int
1095 quote_and_print(const char *str, FILE *strm, int commentnl)
1096 {
1097 	const char *cp;
1098 
1099 	for (cp = str; *cp != '\0'; ++cp) {
1100 		if (*cp == '"' || *cp == '\\')
1101 			(void) putc('\\', strm);
1102 
1103 		(void) putc(*cp, strm);
1104 
1105 		if (commentnl && *cp == '\n') {
1106 			(void) putc('#', strm);
1107 		}
1108 	}
1109 
1110 	return (ferror(strm));
1111 }
1112 
1113 /*
1114  * These wrappers around lowlevel functions provide consistent error checking
1115  * and warnings.
1116  */
1117 static int
1118 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1119 {
1120 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1121 		return (0);
1122 
1123 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1124 		scfdie();
1125 
1126 	if (g_verbose) {
1127 		ssize_t len;
1128 		char *fmri;
1129 
1130 		len = scf_pg_to_fmri(pg, NULL, 0);
1131 		if (len < 0)
1132 			scfdie();
1133 
1134 		fmri = safe_malloc(len + 1);
1135 
1136 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1137 			scfdie();
1138 
1139 		warn(gettext("Expected property %s of property group %s is "
1140 		    "missing.\n"), propname, fmri);
1141 
1142 		free(fmri);
1143 	}
1144 
1145 	return (-1);
1146 }
1147 
1148 static int
1149 prop_check_type(scf_property_t *prop, scf_type_t ty)
1150 {
1151 	scf_type_t pty;
1152 
1153 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1154 		scfdie();
1155 
1156 	if (ty == pty)
1157 		return (0);
1158 
1159 	if (g_verbose) {
1160 		ssize_t len;
1161 		char *fmri;
1162 		const char *tystr;
1163 
1164 		len = scf_property_to_fmri(prop, NULL, 0);
1165 		if (len < 0)
1166 			scfdie();
1167 
1168 		fmri = safe_malloc(len + 1);
1169 
1170 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1171 			scfdie();
1172 
1173 		tystr = scf_type_to_string(ty);
1174 		if (tystr == NULL)
1175 			tystr = "?";
1176 
1177 		warn(gettext("Property %s is not of expected type %s.\n"),
1178 		    fmri, tystr);
1179 
1180 		free(fmri);
1181 	}
1182 
1183 	return (-1);
1184 }
1185 
1186 static int
1187 prop_get_val(scf_property_t *prop, scf_value_t *val)
1188 {
1189 	scf_error_t err;
1190 
1191 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1192 		return (0);
1193 
1194 	err = scf_error();
1195 
1196 	if (err != SCF_ERROR_NOT_FOUND &&
1197 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1198 	    err != SCF_ERROR_PERMISSION_DENIED)
1199 		scfdie();
1200 
1201 	if (g_verbose) {
1202 		ssize_t len;
1203 		char *fmri, *emsg;
1204 
1205 		len = scf_property_to_fmri(prop, NULL, 0);
1206 		if (len < 0)
1207 			scfdie();
1208 
1209 		fmri = safe_malloc(len + 1);
1210 
1211 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1212 			scfdie();
1213 
1214 		if (err == SCF_ERROR_NOT_FOUND)
1215 			emsg = gettext("Property %s has no values; expected "
1216 			    "one.\n");
1217 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1218 			emsg = gettext("Property %s has multiple values; "
1219 			    "expected one.\n");
1220 		else
1221 			emsg = gettext("No permission to read property %s.\n");
1222 
1223 		warn(emsg, fmri);
1224 
1225 		free(fmri);
1226 	}
1227 
1228 	return (-1);
1229 }
1230 
1231 
1232 static boolean_t
1233 snaplevel_is_instance(const scf_snaplevel_t *level)
1234 {
1235 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1236 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1237 			scfdie();
1238 		return (0);
1239 	} else {
1240 		return (1);
1241 	}
1242 }
1243 
1244 /*
1245  * Decode FMRI into a service or instance, and put the result in *ep.  If
1246  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1247  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1248  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1249  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1250  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1251  * whether *ep is a service.
1252  */
1253 static scf_error_t
1254 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1255 {
1256 	char *fmri_copy;
1257 	const char *sstr, *istr, *pgstr;
1258 	scf_service_t *svc;
1259 	scf_instance_t *inst;
1260 
1261 	fmri_copy = strdup(fmri);
1262 	if (fmri_copy == NULL)
1263 		return (SCF_ERROR_NO_MEMORY);
1264 
1265 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1266 	    SCF_SUCCESS) {
1267 		free(fmri_copy);
1268 		return (SCF_ERROR_INVALID_ARGUMENT);
1269 	}
1270 
1271 	free(fmri_copy);
1272 
1273 	if (sstr == NULL || pgstr != NULL)
1274 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1275 
1276 	if (istr == NULL) {
1277 		svc = scf_service_create(h);
1278 		if (svc == NULL)
1279 			return (SCF_ERROR_NO_MEMORY);
1280 
1281 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1282 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1283 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1284 				scfdie();
1285 
1286 			return (SCF_ERROR_NOT_FOUND);
1287 		}
1288 
1289 		*ep = svc;
1290 		*isservice = 1;
1291 	} else {
1292 		inst = scf_instance_create(h);
1293 		if (inst == NULL)
1294 			return (SCF_ERROR_NO_MEMORY);
1295 
1296 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1297 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1298 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1299 				scfdie();
1300 
1301 			return (SCF_ERROR_NOT_FOUND);
1302 		}
1303 
1304 		*ep = inst;
1305 		*isservice = 0;
1306 	}
1307 
1308 	return (SCF_ERROR_NONE);
1309 }
1310 
1311 /*
1312  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1313  * *ep, and set or clear *isservicep if it is a service or an instance.
1314  * Returns
1315  *   SCF_ERROR_NONE - success
1316  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1317  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1318  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1319  *   SCF_ERROR_NOT_FOUND - no such scope
1320  *   SCF_ERROR_PERMISSION_DENIED
1321  *   SCF_ERROR_BACKEND_READONLY
1322  *   SCF_ERROR_BACKEND_ACCESS
1323  */
1324 static scf_error_t
1325 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1326 {
1327 	char *fmri_copy;
1328 	const char *scstr, *sstr, *istr, *pgstr;
1329 	scf_scope_t *scope = NULL;
1330 	scf_service_t *svc = NULL;
1331 	scf_instance_t *inst = NULL;
1332 	scf_error_t scfe;
1333 
1334 	fmri_copy = safe_strdup(fmri);
1335 
1336 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1337 	    0) {
1338 		free(fmri_copy);
1339 		return (SCF_ERROR_INVALID_ARGUMENT);
1340 	}
1341 
1342 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1343 		free(fmri_copy);
1344 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1345 	}
1346 
1347 	*ep = NULL;
1348 
1349 	if ((scope = scf_scope_create(h)) == NULL ||
1350 	    (svc = scf_service_create(h)) == NULL ||
1351 	    (inst = scf_instance_create(h)) == NULL) {
1352 		scfe = SCF_ERROR_NO_MEMORY;
1353 		goto out;
1354 	}
1355 
1356 get_scope:
1357 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1358 		switch (scf_error()) {
1359 		case SCF_ERROR_CONNECTION_BROKEN:
1360 			scfdie();
1361 			/* NOTREACHED */
1362 
1363 		case SCF_ERROR_NOT_FOUND:
1364 			scfe = SCF_ERROR_NOT_FOUND;
1365 			goto out;
1366 
1367 		case SCF_ERROR_HANDLE_MISMATCH:
1368 		case SCF_ERROR_NOT_BOUND:
1369 		case SCF_ERROR_INVALID_ARGUMENT:
1370 		default:
1371 			bad_error("scf_handle_get_scope", scf_error());
1372 		}
1373 	}
1374 
1375 get_svc:
1376 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1377 		switch (scf_error()) {
1378 		case SCF_ERROR_CONNECTION_BROKEN:
1379 			scfdie();
1380 			/* NOTREACHED */
1381 
1382 		case SCF_ERROR_DELETED:
1383 			goto get_scope;
1384 
1385 		case SCF_ERROR_NOT_FOUND:
1386 			break;
1387 
1388 		case SCF_ERROR_HANDLE_MISMATCH:
1389 		case SCF_ERROR_INVALID_ARGUMENT:
1390 		case SCF_ERROR_NOT_BOUND:
1391 		case SCF_ERROR_NOT_SET:
1392 		default:
1393 			bad_error("scf_scope_get_service", scf_error());
1394 		}
1395 
1396 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1397 			switch (scf_error()) {
1398 			case SCF_ERROR_CONNECTION_BROKEN:
1399 				scfdie();
1400 				/* NOTREACHED */
1401 
1402 			case SCF_ERROR_DELETED:
1403 				goto get_scope;
1404 
1405 			case SCF_ERROR_PERMISSION_DENIED:
1406 			case SCF_ERROR_BACKEND_READONLY:
1407 			case SCF_ERROR_BACKEND_ACCESS:
1408 				scfe = scf_error();
1409 				goto out;
1410 
1411 			case SCF_ERROR_HANDLE_MISMATCH:
1412 			case SCF_ERROR_INVALID_ARGUMENT:
1413 			case SCF_ERROR_NOT_BOUND:
1414 			case SCF_ERROR_NOT_SET:
1415 			default:
1416 				bad_error("scf_scope_get_service", scf_error());
1417 			}
1418 		}
1419 	}
1420 
1421 	if (istr == NULL) {
1422 		scfe = SCF_ERROR_NONE;
1423 		*ep = svc;
1424 		*isservicep = 1;
1425 		goto out;
1426 	}
1427 
1428 get_inst:
1429 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1430 		switch (scf_error()) {
1431 		case SCF_ERROR_CONNECTION_BROKEN:
1432 			scfdie();
1433 			/* NOTREACHED */
1434 
1435 		case SCF_ERROR_DELETED:
1436 			goto get_svc;
1437 
1438 		case SCF_ERROR_NOT_FOUND:
1439 			break;
1440 
1441 		case SCF_ERROR_HANDLE_MISMATCH:
1442 		case SCF_ERROR_INVALID_ARGUMENT:
1443 		case SCF_ERROR_NOT_BOUND:
1444 		case SCF_ERROR_NOT_SET:
1445 		default:
1446 			bad_error("scf_service_get_instance", scf_error());
1447 		}
1448 
1449 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1450 			switch (scf_error()) {
1451 			case SCF_ERROR_CONNECTION_BROKEN:
1452 				scfdie();
1453 				/* NOTREACHED */
1454 
1455 			case SCF_ERROR_DELETED:
1456 				goto get_svc;
1457 
1458 			case SCF_ERROR_PERMISSION_DENIED:
1459 			case SCF_ERROR_BACKEND_READONLY:
1460 			case SCF_ERROR_BACKEND_ACCESS:
1461 				scfe = scf_error();
1462 				goto out;
1463 
1464 			case SCF_ERROR_HANDLE_MISMATCH:
1465 			case SCF_ERROR_INVALID_ARGUMENT:
1466 			case SCF_ERROR_NOT_BOUND:
1467 			case SCF_ERROR_NOT_SET:
1468 			default:
1469 				bad_error("scf_service_add_instance",
1470 				    scf_error());
1471 			}
1472 		}
1473 	}
1474 
1475 	scfe = SCF_ERROR_NONE;
1476 	*ep = inst;
1477 	*isservicep = 0;
1478 
1479 out:
1480 	if (*ep != inst)
1481 		scf_instance_destroy(inst);
1482 	if (*ep != svc)
1483 		scf_service_destroy(svc);
1484 	scf_scope_destroy(scope);
1485 	free(fmri_copy);
1486 	return (scfe);
1487 }
1488 
1489 /*
1490  * Create or update a snapshot of inst.  snap is a required scratch object.
1491  *
1492  * Returns
1493  *   0 - success
1494  *   ECONNABORTED - repository connection broken
1495  *   EPERM - permission denied
1496  *   ENOSPC - configd is out of resources
1497  *   ECANCELED - inst was deleted
1498  *   -1 - unknown libscf error (message printed)
1499  */
1500 static int
1501 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1502 {
1503 again:
1504 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1505 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1506 			switch (scf_error()) {
1507 			case SCF_ERROR_CONNECTION_BROKEN:
1508 			case SCF_ERROR_PERMISSION_DENIED:
1509 			case SCF_ERROR_NO_RESOURCES:
1510 				return (scferror2errno(scf_error()));
1511 
1512 			case SCF_ERROR_NOT_SET:
1513 			case SCF_ERROR_INVALID_ARGUMENT:
1514 			default:
1515 				bad_error("_scf_snapshot_take_attach",
1516 				    scf_error());
1517 			}
1518 		}
1519 	} else {
1520 		switch (scf_error()) {
1521 		case SCF_ERROR_NOT_FOUND:
1522 			break;
1523 
1524 		case SCF_ERROR_DELETED:
1525 		case SCF_ERROR_CONNECTION_BROKEN:
1526 			return (scferror2errno(scf_error()));
1527 
1528 		case SCF_ERROR_HANDLE_MISMATCH:
1529 		case SCF_ERROR_NOT_BOUND:
1530 		case SCF_ERROR_INVALID_ARGUMENT:
1531 		case SCF_ERROR_NOT_SET:
1532 		default:
1533 			bad_error("scf_instance_get_snapshot", scf_error());
1534 		}
1535 
1536 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1537 			switch (scf_error()) {
1538 			case SCF_ERROR_EXISTS:
1539 				goto again;
1540 
1541 			case SCF_ERROR_CONNECTION_BROKEN:
1542 			case SCF_ERROR_NO_RESOURCES:
1543 			case SCF_ERROR_PERMISSION_DENIED:
1544 				return (scferror2errno(scf_error()));
1545 
1546 			default:
1547 				scfwarn();
1548 				return (-1);
1549 
1550 			case SCF_ERROR_NOT_SET:
1551 			case SCF_ERROR_INTERNAL:
1552 			case SCF_ERROR_INVALID_ARGUMENT:
1553 			case SCF_ERROR_HANDLE_MISMATCH:
1554 				bad_error("_scf_snapshot_take_new",
1555 				    scf_error());
1556 			}
1557 		}
1558 	}
1559 
1560 	return (0);
1561 }
1562 
1563 static int
1564 refresh_running_snapshot(void *entity)
1565 {
1566 	scf_snapshot_t *snap;
1567 	int r;
1568 
1569 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1570 		scfdie();
1571 	r = take_snap(entity, snap_running, snap);
1572 	scf_snapshot_destroy(snap);
1573 
1574 	return (r);
1575 }
1576 
1577 /*
1578  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1579  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1580  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1581  * for scratch space.  Returns
1582  *   0 - success
1583  *   ECONNABORTED - repository connection broken
1584  *   ECANCELED - entity was deleted
1585  *   EACCES - backend denied access
1586  *   EPERM - permission denied
1587  *   ENOSPC - repository server out of resources
1588  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1589  */
1590 static int
1591 refresh_entity(int isservice, void *entity, const char *fmri,
1592     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1593 {
1594 	scf_error_t scfe;
1595 	int r;
1596 
1597 	if (!isservice) {
1598 		/*
1599 		 * Let restarter handles refreshing and making new running
1600 		 * snapshot only if operating on a live repository and not
1601 		 * running in early import.
1602 		 */
1603 		if (est->sc_repo_filename == NULL &&
1604 		    est->sc_repo_doorname == NULL &&
1605 		    est->sc_in_emi == 0) {
1606 			if (_smf_refresh_instance_i(entity) == 0) {
1607 				if (g_verbose)
1608 					warn(gettext("Refreshed %s.\n"), fmri);
1609 				return (0);
1610 			}
1611 
1612 			switch (scf_error()) {
1613 			case SCF_ERROR_BACKEND_ACCESS:
1614 				return (EACCES);
1615 
1616 			case SCF_ERROR_PERMISSION_DENIED:
1617 				return (EPERM);
1618 
1619 			default:
1620 				return (-1);
1621 			}
1622 		} else {
1623 			r = refresh_running_snapshot(entity);
1624 			switch (r) {
1625 			case 0:
1626 				break;
1627 
1628 			case ECONNABORTED:
1629 			case ECANCELED:
1630 			case EPERM:
1631 			case ENOSPC:
1632 				break;
1633 
1634 			default:
1635 				bad_error("refresh_running_snapshot",
1636 				    scf_error());
1637 			}
1638 
1639 			return (r);
1640 		}
1641 	}
1642 
1643 	if (scf_iter_service_instances(iter, entity) != 0) {
1644 		switch (scf_error()) {
1645 		case SCF_ERROR_CONNECTION_BROKEN:
1646 			return (ECONNABORTED);
1647 
1648 		case SCF_ERROR_DELETED:
1649 			return (ECANCELED);
1650 
1651 		case SCF_ERROR_HANDLE_MISMATCH:
1652 		case SCF_ERROR_NOT_BOUND:
1653 		case SCF_ERROR_NOT_SET:
1654 		default:
1655 			bad_error("scf_iter_service_instances", scf_error());
1656 		}
1657 	}
1658 
1659 	for (;;) {
1660 		r = scf_iter_next_instance(iter, inst);
1661 		if (r == 0)
1662 			break;
1663 		if (r != 1) {
1664 			switch (scf_error()) {
1665 			case SCF_ERROR_CONNECTION_BROKEN:
1666 				return (ECONNABORTED);
1667 
1668 			case SCF_ERROR_DELETED:
1669 				return (ECANCELED);
1670 
1671 			case SCF_ERROR_HANDLE_MISMATCH:
1672 			case SCF_ERROR_NOT_BOUND:
1673 			case SCF_ERROR_NOT_SET:
1674 			case SCF_ERROR_INVALID_ARGUMENT:
1675 			default:
1676 				bad_error("scf_iter_next_instance",
1677 				    scf_error());
1678 			}
1679 		}
1680 
1681 		/*
1682 		 * Similarly, just take a new running snapshot if operating on
1683 		 * a non-live repository or running during early import.
1684 		 */
1685 		if (est->sc_repo_filename != NULL ||
1686 		    est->sc_repo_doorname != NULL ||
1687 		    est->sc_in_emi == 1) {
1688 			r = refresh_running_snapshot(inst);
1689 			switch (r) {
1690 			case 0:
1691 				continue;
1692 
1693 			case ECONNABORTED:
1694 			case ECANCELED:
1695 			case EPERM:
1696 			case ENOSPC:
1697 				break;
1698 			default:
1699 				bad_error("refresh_running_snapshot",
1700 				    scf_error());
1701 			}
1702 
1703 			return (r);
1704 
1705 		}
1706 
1707 		if (_smf_refresh_instance_i(inst) == 0) {
1708 			if (g_verbose) {
1709 				if (scf_instance_get_name(inst, name_buf,
1710 				    max_scf_name_len + 1) < 0)
1711 					(void) strcpy(name_buf, "?");
1712 
1713 				warn(gettext("Refreshed %s:%s.\n"),
1714 				    fmri, name_buf);
1715 			}
1716 		} else {
1717 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1718 			    g_verbose) {
1719 				scfe = scf_error();
1720 
1721 				if (scf_instance_to_fmri(inst, name_buf,
1722 				    max_scf_name_len + 1) < 0)
1723 					(void) strcpy(name_buf, "?");
1724 
1725 				warn(gettext(
1726 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1727 				    name_buf, scf_strerror(scfe));
1728 			}
1729 		}
1730 	}
1731 
1732 	return (0);
1733 }
1734 
1735 static void
1736 private_refresh(void)
1737 {
1738 	scf_instance_t *pinst = NULL;
1739 	scf_iter_t *piter = NULL;
1740 	ssize_t fmrilen;
1741 	size_t bufsz;
1742 	char *fmribuf;
1743 	void *ent;
1744 	int issvc;
1745 	int r;
1746 
1747 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1748 		return;
1749 
1750 	assert(cur_svc != NULL);
1751 
1752 	bufsz = max_scf_fmri_len + 1;
1753 	fmribuf = safe_malloc(bufsz);
1754 	if (cur_inst) {
1755 		issvc = 0;
1756 		ent = cur_inst;
1757 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1758 	} else {
1759 		issvc = 1;
1760 		ent = cur_svc;
1761 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1762 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1763 			scfdie();
1764 
1765 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1766 			scfdie();
1767 	}
1768 	if (fmrilen < 0) {
1769 		free(fmribuf);
1770 		if (scf_error() != SCF_ERROR_DELETED)
1771 			scfdie();
1772 
1773 		warn(emsg_deleted);
1774 		return;
1775 	}
1776 	assert(fmrilen < bufsz);
1777 
1778 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1779 	switch (r) {
1780 	case 0:
1781 		break;
1782 
1783 	case ECONNABORTED:
1784 		warn(gettext("Could not refresh %s "
1785 		    "(repository connection broken).\n"), fmribuf);
1786 		break;
1787 
1788 	case ECANCELED:
1789 		warn(emsg_deleted);
1790 		break;
1791 
1792 	case EPERM:
1793 		warn(gettext("Could not refresh %s "
1794 		    "(permission denied).\n"), fmribuf);
1795 		break;
1796 
1797 	case ENOSPC:
1798 		warn(gettext("Could not refresh %s "
1799 		    "(repository server out of resources).\n"),
1800 		    fmribuf);
1801 		break;
1802 
1803 	case EACCES:
1804 	default:
1805 		bad_error("refresh_entity", scf_error());
1806 	}
1807 
1808 	if (issvc) {
1809 		scf_instance_destroy(pinst);
1810 		scf_iter_destroy(piter);
1811 	}
1812 
1813 	free(fmribuf);
1814 }
1815 
1816 
1817 static int
1818 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1819 {
1820 	cbp->sc_err = scferror2errno(err);
1821 	return (UU_WALK_ERROR);
1822 }
1823 
1824 static int
1825 stash_scferror(scf_callback_t *cbp)
1826 {
1827 	return (stash_scferror_err(cbp, scf_error()));
1828 }
1829 
1830 static int select_inst(const char *);
1831 static int select_svc(const char *);
1832 
1833 /*
1834  * Take a property that does not have a type and check to see if a type
1835  * exists or can be gleened from the current data.  Set the type.
1836  *
1837  * Check the current level (instance) and then check the higher level
1838  * (service).  This could be the case for adding a new property to
1839  * the instance that's going to "override" a service level property.
1840  *
1841  * For a property :
1842  * 1. Take the type from an existing property
1843  * 2. Take the type from a template entry
1844  *
1845  * If the type can not be found, then leave the type as is, and let the import
1846  * report the problem of the missing type.
1847  */
1848 static int
1849 find_current_prop_type(void *p, void *g)
1850 {
1851 	property_t *prop = p;
1852 	scf_callback_t *lcb = g;
1853 	pgroup_t *pg = NULL;
1854 
1855 	const char *fmri = NULL;
1856 	char *lfmri = NULL;
1857 	char *cur_selection = NULL;
1858 
1859 	scf_propertygroup_t *sc_pg = NULL;
1860 	scf_property_t *sc_prop = NULL;
1861 	scf_pg_tmpl_t *t_pg = NULL;
1862 	scf_prop_tmpl_t *t_prop = NULL;
1863 	scf_type_t prop_type;
1864 
1865 	value_t *vp;
1866 	int issvc = lcb->sc_service;
1867 	int r = UU_WALK_ERROR;
1868 
1869 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1870 		return (UU_WALK_NEXT);
1871 
1872 	t_prop = scf_tmpl_prop_create(g_hndl);
1873 	sc_prop = scf_property_create(g_hndl);
1874 	if (sc_prop == NULL || t_prop == NULL) {
1875 		warn(gettext("Unable to create the property to attempt and "
1876 		    "find a missing type.\n"));
1877 
1878 		scf_property_destroy(sc_prop);
1879 		scf_tmpl_prop_destroy(t_prop);
1880 
1881 		return (UU_WALK_ERROR);
1882 	}
1883 
1884 	if (lcb->sc_flags == 1) {
1885 		pg = lcb->sc_parent;
1886 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1887 		fmri = pg->sc_parent->sc_fmri;
1888 retry_pg:
1889 		if (cur_svc && cur_selection == NULL) {
1890 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1891 			lscf_get_selection_str(cur_selection,
1892 			    max_scf_fmri_len + 1);
1893 
1894 			if (strcmp(cur_selection, fmri) != 0) {
1895 				lscf_select(fmri);
1896 			} else {
1897 				free(cur_selection);
1898 				cur_selection = NULL;
1899 			}
1900 		} else {
1901 			lscf_select(fmri);
1902 		}
1903 
1904 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1905 			warn(gettext("Unable to create property group to "
1906 			    "find a missing property type.\n"));
1907 
1908 			goto out;
1909 		}
1910 
1911 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1912 			/*
1913 			 * If this is the sc_pg from the parent
1914 			 * let the caller clean up the sc_pg,
1915 			 * and just throw it away in this case.
1916 			 */
1917 			if (sc_pg != lcb->sc_parent)
1918 				scf_pg_destroy(sc_pg);
1919 
1920 			sc_pg = NULL;
1921 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1922 				warn(gettext("Unable to create template "
1923 				    "property group to find a property "
1924 				    "type.\n"));
1925 
1926 				goto out;
1927 			}
1928 
1929 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1930 			    pg->sc_pgroup_name, NULL, t_pg,
1931 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1932 				/*
1933 				 * if instance get service and jump back
1934 				 */
1935 				scf_tmpl_pg_destroy(t_pg);
1936 				t_pg = NULL;
1937 				if (issvc == 0) {
1938 					entity_t *e = pg->sc_parent->sc_parent;
1939 
1940 					fmri = e->sc_fmri;
1941 					issvc = 1;
1942 					goto retry_pg;
1943 				} else {
1944 					goto out;
1945 				}
1946 			}
1947 		}
1948 	} else {
1949 		sc_pg = lcb->sc_parent;
1950 	}
1951 
1952 	/*
1953 	 * Attempt to get the type from an existing property.  If the property
1954 	 * cannot be found then attempt to get the type from a template entry
1955 	 * for the property.
1956 	 *
1957 	 * Finally, if at the instance level look at the service level.
1958 	 */
1959 	if (sc_pg != NULL &&
1960 	    pg_get_prop(sc_pg, prop->sc_property_name,
1961 	    sc_prop) == SCF_SUCCESS &&
1962 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1963 		prop->sc_value_type = prop_type;
1964 
1965 		/*
1966 		 * Found a type, update the value types and validate
1967 		 * the actual value against this type.
1968 		 */
1969 		for (vp = uu_list_first(prop->sc_property_values);
1970 		    vp != NULL;
1971 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1972 			vp->sc_type = prop->sc_value_type;
1973 			lxml_store_value(vp, 0, NULL);
1974 		}
1975 
1976 		r = UU_WALK_NEXT;
1977 		goto out;
1978 	}
1979 
1980 	/*
1981 	 * If we get here with t_pg set to NULL then we had to have
1982 	 * gotten an sc_pg but that sc_pg did not have the property
1983 	 * we are looking for.   So if the t_pg is not null look up
1984 	 * the template entry for the property.
1985 	 *
1986 	 * If the t_pg is null then need to attempt to get a matching
1987 	 * template entry for the sc_pg, and see if there is a property
1988 	 * entry for that template entry.
1989 	 */
1990 do_tmpl :
1991 	if (t_pg != NULL &&
1992 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1993 	    t_prop, 0) == SCF_SUCCESS) {
1994 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1995 			prop->sc_value_type = prop_type;
1996 
1997 			/*
1998 			 * Found a type, update the value types and validate
1999 			 * the actual value against this type.
2000 			 */
2001 			for (vp = uu_list_first(prop->sc_property_values);
2002 			    vp != NULL;
2003 			    vp = uu_list_next(prop->sc_property_values, vp)) {
2004 				vp->sc_type = prop->sc_value_type;
2005 				lxml_store_value(vp, 0, NULL);
2006 			}
2007 
2008 			r = UU_WALK_NEXT;
2009 			goto out;
2010 		}
2011 	} else {
2012 		if (t_pg == NULL && sc_pg) {
2013 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2014 				warn(gettext("Unable to create template "
2015 				    "property group to find a property "
2016 				    "type.\n"));
2017 
2018 				goto out;
2019 			}
2020 
2021 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2022 				scf_tmpl_pg_destroy(t_pg);
2023 				t_pg = NULL;
2024 			} else {
2025 				goto do_tmpl;
2026 			}
2027 		}
2028 	}
2029 
2030 	if (issvc == 0) {
2031 		scf_instance_t *i;
2032 		scf_service_t *s;
2033 
2034 		issvc = 1;
2035 		if (lcb->sc_flags == 1) {
2036 			entity_t *e = pg->sc_parent->sc_parent;
2037 
2038 			fmri = e->sc_fmri;
2039 			goto retry_pg;
2040 		}
2041 
2042 		/*
2043 		 * because lcb->sc_flags was not set then this means
2044 		 * the pg was not used and can be used here.
2045 		 */
2046 		if ((pg = internal_pgroup_new()) == NULL) {
2047 			warn(gettext("Could not create internal property group "
2048 			    "to find a missing type."));
2049 
2050 			goto out;
2051 		}
2052 
2053 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2054 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2055 		    max_scf_name_len + 1) < 0)
2056 				goto out;
2057 
2058 		i = scf_instance_create(g_hndl);
2059 		s = scf_service_create(g_hndl);
2060 		if (i == NULL || s == NULL ||
2061 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2062 			warn(gettext("Could not get a service for the instance "
2063 			    "to find a missing type."));
2064 
2065 			goto out;
2066 		}
2067 
2068 		/*
2069 		 * Check to see truly at the instance level.
2070 		 */
2071 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2072 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2073 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2074 			goto out;
2075 		else
2076 			fmri = (const char *)lfmri;
2077 
2078 		goto retry_pg;
2079 	}
2080 
2081 out :
2082 	if (sc_pg != lcb->sc_parent) {
2083 		scf_pg_destroy(sc_pg);
2084 	}
2085 
2086 	/*
2087 	 * If this is true then the pg was allocated
2088 	 * here, and the name was set so need to free
2089 	 * the name and the pg.
2090 	 */
2091 	if (pg != NULL && pg != lcb->sc_parent) {
2092 		free((char *)pg->sc_pgroup_name);
2093 		internal_pgroup_free(pg);
2094 	}
2095 
2096 	if (cur_selection) {
2097 		lscf_select(cur_selection);
2098 		free(cur_selection);
2099 	}
2100 
2101 	scf_tmpl_pg_destroy(t_pg);
2102 	scf_tmpl_prop_destroy(t_prop);
2103 	scf_property_destroy(sc_prop);
2104 
2105 	if (r != UU_WALK_NEXT)
2106 		warn(gettext("Could not find property type for \"%s\" "
2107 		    "from \"%s\"\n"), prop->sc_property_name,
2108 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2109 
2110 	free(lfmri);
2111 
2112 	return (r);
2113 }
2114 
2115 /*
2116  * Take a property group that does not have a type and check to see if a type
2117  * exists or can be gleened from the current data.  Set the type.
2118  *
2119  * Check the current level (instance) and then check the higher level
2120  * (service).  This could be the case for adding a new property to
2121  * the instance that's going to "override" a service level property.
2122  *
2123  * For a property group
2124  * 1. Take the type from an existing property group
2125  * 2. Take the type from a template entry
2126  *
2127  * If the type can not be found, then leave the type as is, and let the import
2128  * report the problem of the missing type.
2129  */
2130 static int
2131 find_current_pg_type(void *p, void *sori)
2132 {
2133 	entity_t *si = sori;
2134 	pgroup_t *pg = p;
2135 
2136 	const char *ofmri, *fmri;
2137 	char *cur_selection = NULL;
2138 	char *pg_type = NULL;
2139 
2140 	scf_propertygroup_t *sc_pg = NULL;
2141 	scf_pg_tmpl_t *t_pg = NULL;
2142 
2143 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2144 	int r = UU_WALK_ERROR;
2145 
2146 	ofmri = fmri = si->sc_fmri;
2147 	if (pg->sc_pgroup_type != NULL) {
2148 		r = UU_WALK_NEXT;
2149 
2150 		goto out;
2151 	}
2152 
2153 	sc_pg = scf_pg_create(g_hndl);
2154 	if (sc_pg == NULL) {
2155 		warn(gettext("Unable to create property group to attempt "
2156 		    "and find a missing type.\n"));
2157 
2158 		return (UU_WALK_ERROR);
2159 	}
2160 
2161 	/*
2162 	 * Using get_pg() requires that the cur_svc/cur_inst be
2163 	 * via lscf_select.  Need to preserve the current selection
2164 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2165 	 */
2166 	if (cur_svc) {
2167 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2168 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2169 	}
2170 
2171 	/*
2172 	 * If the property group exists get the type, and set
2173 	 * the pgroup_t type of that type.
2174 	 *
2175 	 * If not the check for a template pg_pattern entry
2176 	 * and take the type from that.
2177 	 */
2178 retry_svc:
2179 	lscf_select(fmri);
2180 
2181 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2182 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2183 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2184 		    max_scf_pg_type_len + 1) != -1) {
2185 			pg->sc_pgroup_type = pg_type;
2186 
2187 			r = UU_WALK_NEXT;
2188 			goto out;
2189 		} else {
2190 			free(pg_type);
2191 		}
2192 	} else {
2193 		if ((t_pg == NULL) &&
2194 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2195 			goto out;
2196 
2197 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2198 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2199 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2200 			pg->sc_pgroup_type = pg_type;
2201 
2202 			r = UU_WALK_NEXT;
2203 			goto out;
2204 		}
2205 	}
2206 
2207 	/*
2208 	 * If type is not found at the instance level then attempt to
2209 	 * find the type at the service level.
2210 	 */
2211 	if (!issvc) {
2212 		si = si->sc_parent;
2213 		fmri = si->sc_fmri;
2214 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2215 		goto retry_svc;
2216 	}
2217 
2218 out :
2219 	if (cur_selection) {
2220 		lscf_select(cur_selection);
2221 		free(cur_selection);
2222 	}
2223 
2224 	/*
2225 	 * Now walk the properties of the property group to make sure that
2226 	 * all properties have the correct type and values are valid for
2227 	 * those types.
2228 	 */
2229 	if (r == UU_WALK_NEXT) {
2230 		scf_callback_t cb;
2231 
2232 		cb.sc_service = issvc;
2233 		cb.sc_source_fmri = ofmri;
2234 		if (sc_pg != NULL) {
2235 			cb.sc_parent = sc_pg;
2236 			cb.sc_flags = 0;
2237 		} else {
2238 			cb.sc_parent = pg;
2239 			cb.sc_flags = 1;
2240 		}
2241 
2242 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2243 		    &cb, UU_DEFAULT) != 0) {
2244 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2245 				bad_error("uu_list_walk", uu_error());
2246 
2247 			r = UU_WALK_ERROR;
2248 		}
2249 	} else {
2250 		warn(gettext("Could not find property group type for "
2251 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2252 	}
2253 
2254 	scf_tmpl_pg_destroy(t_pg);
2255 	scf_pg_destroy(sc_pg);
2256 
2257 	return (r);
2258 }
2259 
2260 /*
2261  * Import.  These functions import a bundle into the repository.
2262  */
2263 
2264 /*
2265  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2266  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2267  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2268  * lcbdata->sc_err to
2269  *   ENOMEM - out of memory
2270  *   ECONNABORTED - repository connection broken
2271  *   ECANCELED - sc_trans's property group was deleted
2272  *   EINVAL - p's name is invalid (error printed)
2273  *	    - p has an invalid value (error printed)
2274  */
2275 static int
2276 lscf_property_import(void *v, void *pvt)
2277 {
2278 	property_t *p = v;
2279 	scf_callback_t *lcbdata = pvt;
2280 	value_t *vp;
2281 	scf_transaction_t *trans = lcbdata->sc_trans;
2282 	scf_transaction_entry_t *entr;
2283 	scf_value_t *val;
2284 	scf_type_t tp;
2285 
2286 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2287 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2288 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2289 		lcbdata->sc_enable = p;
2290 		return (UU_WALK_NEXT);
2291 	}
2292 
2293 	entr = scf_entry_create(lcbdata->sc_handle);
2294 	if (entr == NULL) {
2295 		switch (scf_error()) {
2296 		case SCF_ERROR_NO_MEMORY:
2297 			return (stash_scferror(lcbdata));
2298 
2299 		case SCF_ERROR_INVALID_ARGUMENT:
2300 		default:
2301 			bad_error("scf_entry_create", scf_error());
2302 		}
2303 	}
2304 
2305 	tp = p->sc_value_type;
2306 
2307 	if (scf_transaction_property_new(trans, entr,
2308 	    p->sc_property_name, tp) != 0) {
2309 		switch (scf_error()) {
2310 		case SCF_ERROR_INVALID_ARGUMENT:
2311 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2312 			scf_entry_destroy(entr);
2313 			return (stash_scferror(lcbdata));
2314 
2315 		case SCF_ERROR_EXISTS:
2316 			break;
2317 
2318 		case SCF_ERROR_DELETED:
2319 		case SCF_ERROR_CONNECTION_BROKEN:
2320 			scf_entry_destroy(entr);
2321 			return (stash_scferror(lcbdata));
2322 
2323 		case SCF_ERROR_NOT_BOUND:
2324 		case SCF_ERROR_HANDLE_MISMATCH:
2325 		case SCF_ERROR_NOT_SET:
2326 		default:
2327 			bad_error("scf_transaction_property_new", scf_error());
2328 		}
2329 
2330 		if (scf_transaction_property_change_type(trans, entr,
2331 		    p->sc_property_name, tp) != 0) {
2332 			switch (scf_error()) {
2333 			case SCF_ERROR_DELETED:
2334 			case SCF_ERROR_CONNECTION_BROKEN:
2335 				scf_entry_destroy(entr);
2336 				return (stash_scferror(lcbdata));
2337 
2338 			case SCF_ERROR_INVALID_ARGUMENT:
2339 				semerr(emsg_invalid_prop_name,
2340 				    p->sc_property_name);
2341 				scf_entry_destroy(entr);
2342 				return (stash_scferror(lcbdata));
2343 
2344 			case SCF_ERROR_NOT_FOUND:
2345 			case SCF_ERROR_NOT_SET:
2346 			case SCF_ERROR_HANDLE_MISMATCH:
2347 			case SCF_ERROR_NOT_BOUND:
2348 			default:
2349 				bad_error(
2350 				    "scf_transaction_property_change_type",
2351 				    scf_error());
2352 			}
2353 		}
2354 	}
2355 
2356 	for (vp = uu_list_first(p->sc_property_values);
2357 	    vp != NULL;
2358 	    vp = uu_list_next(p->sc_property_values, vp)) {
2359 		val = scf_value_create(g_hndl);
2360 		if (val == NULL) {
2361 			switch (scf_error()) {
2362 			case SCF_ERROR_NO_MEMORY:
2363 				return (stash_scferror(lcbdata));
2364 
2365 			case SCF_ERROR_INVALID_ARGUMENT:
2366 			default:
2367 				bad_error("scf_value_create", scf_error());
2368 			}
2369 		}
2370 
2371 		switch (tp) {
2372 		case SCF_TYPE_BOOLEAN:
2373 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2374 			break;
2375 		case SCF_TYPE_COUNT:
2376 			scf_value_set_count(val, vp->sc_u.sc_count);
2377 			break;
2378 		case SCF_TYPE_INTEGER:
2379 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2380 			break;
2381 		default:
2382 			assert(vp->sc_u.sc_string != NULL);
2383 			if (scf_value_set_from_string(val, tp,
2384 			    vp->sc_u.sc_string) != 0) {
2385 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2386 					bad_error("scf_value_set_from_string",
2387 					    scf_error());
2388 
2389 				warn(gettext("Value \"%s\" is not a valid "
2390 				    "%s.\n"), vp->sc_u.sc_string,
2391 				    scf_type_to_string(tp));
2392 				scf_value_destroy(val);
2393 				return (stash_scferror(lcbdata));
2394 			}
2395 			break;
2396 		}
2397 
2398 		if (scf_entry_add_value(entr, val) != 0)
2399 			bad_error("scf_entry_add_value", scf_error());
2400 	}
2401 
2402 	return (UU_WALK_NEXT);
2403 }
2404 
2405 /*
2406  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2407  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2408  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2409  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2410  * lcbdata->sc_err to
2411  *   ECONNABORTED - repository connection broken
2412  *   ENOMEM - out of memory
2413  *   ENOSPC - svc.configd is out of resources
2414  *   ECANCELED - sc_parent was deleted
2415  *   EPERM - could not create property group (permission denied) (error printed)
2416  *	   - could not modify property group (permission denied) (error printed)
2417  *	   - could not delete property group (permission denied) (error	printed)
2418  *   EROFS - could not create property group (repository is read-only)
2419  *	   - could not delete property group (repository is read-only)
2420  *   EACCES - could not create property group (backend access denied)
2421  *	    - could not delete property group (backend access denied)
2422  *   EEXIST - could not create property group (already exists)
2423  *   EINVAL - invalid property group name (error printed)
2424  *	    - invalid property name (error printed)
2425  *	    - invalid value (error printed)
2426  *   EBUSY - new property group deleted (error printed)
2427  *	   - new property group changed (error printed)
2428  *	   - property group added (error printed)
2429  *	   - property group deleted (error printed)
2430  */
2431 static int
2432 entity_pgroup_import(void *v, void *pvt)
2433 {
2434 	pgroup_t *p = v;
2435 	scf_callback_t cbdata;
2436 	scf_callback_t *lcbdata = pvt;
2437 	void *ent = lcbdata->sc_parent;
2438 	int issvc = lcbdata->sc_service;
2439 	int r;
2440 
2441 	const char * const pg_changed = gettext("%s changed unexpectedly "
2442 	    "(new property group \"%s\" changed).\n");
2443 
2444 	/* Never import deleted property groups. */
2445 	if (p->sc_pgroup_delete) {
2446 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2447 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2448 			goto delete_pg;
2449 		}
2450 		return (UU_WALK_NEXT);
2451 	}
2452 
2453 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2454 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2455 		lcbdata->sc_general = p;
2456 		return (UU_WALK_NEXT);
2457 	}
2458 
2459 add_pg:
2460 	if (issvc)
2461 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2462 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2463 	else
2464 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2465 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2466 	if (r != 0) {
2467 		switch (scf_error()) {
2468 		case SCF_ERROR_DELETED:
2469 		case SCF_ERROR_CONNECTION_BROKEN:
2470 		case SCF_ERROR_BACKEND_READONLY:
2471 		case SCF_ERROR_BACKEND_ACCESS:
2472 		case SCF_ERROR_NO_RESOURCES:
2473 			return (stash_scferror(lcbdata));
2474 
2475 		case SCF_ERROR_EXISTS:
2476 			if (lcbdata->sc_flags & SCI_FORCE)
2477 				break;
2478 			return (stash_scferror(lcbdata));
2479 
2480 		case SCF_ERROR_INVALID_ARGUMENT:
2481 			warn(emsg_fmri_invalid_pg_name_type,
2482 			    lcbdata->sc_source_fmri,
2483 			    p->sc_pgroup_name, p->sc_pgroup_type);
2484 			return (stash_scferror(lcbdata));
2485 
2486 		case SCF_ERROR_PERMISSION_DENIED:
2487 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2488 			    lcbdata->sc_target_fmri);
2489 			return (stash_scferror(lcbdata));
2490 
2491 		case SCF_ERROR_NOT_BOUND:
2492 		case SCF_ERROR_HANDLE_MISMATCH:
2493 		case SCF_ERROR_NOT_SET:
2494 		default:
2495 			bad_error("scf_service_add_pg", scf_error());
2496 		}
2497 
2498 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2499 			switch (scf_error()) {
2500 			case SCF_ERROR_CONNECTION_BROKEN:
2501 			case SCF_ERROR_DELETED:
2502 				return (stash_scferror(lcbdata));
2503 
2504 			case SCF_ERROR_INVALID_ARGUMENT:
2505 				warn(emsg_fmri_invalid_pg_name,
2506 				    lcbdata->sc_source_fmri,
2507 				    p->sc_pgroup_name);
2508 				return (stash_scferror(lcbdata));
2509 
2510 			case SCF_ERROR_NOT_FOUND:
2511 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2512 				    p->sc_pgroup_name);
2513 				lcbdata->sc_err = EBUSY;
2514 				return (UU_WALK_ERROR);
2515 
2516 			case SCF_ERROR_NOT_BOUND:
2517 			case SCF_ERROR_HANDLE_MISMATCH:
2518 			case SCF_ERROR_NOT_SET:
2519 			default:
2520 				bad_error("entity_get_pg", scf_error());
2521 			}
2522 		}
2523 
2524 		if (lcbdata->sc_flags & SCI_KEEP)
2525 			goto props;
2526 
2527 delete_pg:
2528 		if (scf_pg_delete(imp_pg) != 0) {
2529 			switch (scf_error()) {
2530 			case SCF_ERROR_DELETED:
2531 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2532 				    p->sc_pgroup_name);
2533 				lcbdata->sc_err = EBUSY;
2534 				return (UU_WALK_ERROR);
2535 
2536 			case SCF_ERROR_PERMISSION_DENIED:
2537 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2538 				    lcbdata->sc_target_fmri);
2539 				return (stash_scferror(lcbdata));
2540 
2541 			case SCF_ERROR_BACKEND_READONLY:
2542 			case SCF_ERROR_BACKEND_ACCESS:
2543 			case SCF_ERROR_CONNECTION_BROKEN:
2544 				return (stash_scferror(lcbdata));
2545 
2546 			case SCF_ERROR_NOT_SET:
2547 			default:
2548 				bad_error("scf_pg_delete", scf_error());
2549 			}
2550 		}
2551 
2552 		if (p->sc_pgroup_delete)
2553 			return (UU_WALK_NEXT);
2554 
2555 		goto add_pg;
2556 	}
2557 
2558 props:
2559 
2560 	/*
2561 	 * Add properties to property group, if any.
2562 	 */
2563 	cbdata.sc_handle = lcbdata->sc_handle;
2564 	cbdata.sc_parent = imp_pg;
2565 	cbdata.sc_flags = lcbdata->sc_flags;
2566 	cbdata.sc_trans = imp_tx;
2567 	cbdata.sc_enable = NULL;
2568 
2569 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2570 		switch (scf_error()) {
2571 		case SCF_ERROR_BACKEND_ACCESS:
2572 		case SCF_ERROR_BACKEND_READONLY:
2573 		case SCF_ERROR_CONNECTION_BROKEN:
2574 			return (stash_scferror(lcbdata));
2575 
2576 		case SCF_ERROR_DELETED:
2577 			warn(pg_changed, lcbdata->sc_target_fmri,
2578 			    p->sc_pgroup_name);
2579 			lcbdata->sc_err = EBUSY;
2580 			return (UU_WALK_ERROR);
2581 
2582 		case SCF_ERROR_PERMISSION_DENIED:
2583 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2584 			    lcbdata->sc_target_fmri);
2585 			return (stash_scferror(lcbdata));
2586 
2587 		case SCF_ERROR_NOT_BOUND:
2588 		case SCF_ERROR_NOT_SET:
2589 		case SCF_ERROR_IN_USE:
2590 		case SCF_ERROR_HANDLE_MISMATCH:
2591 		default:
2592 			bad_error("scf_transaction_start", scf_error());
2593 		}
2594 	}
2595 
2596 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2597 	    UU_DEFAULT) != 0) {
2598 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2599 			bad_error("uu_list_walk", uu_error());
2600 		scf_transaction_reset(imp_tx);
2601 
2602 		lcbdata->sc_err = cbdata.sc_err;
2603 		if (cbdata.sc_err == ECANCELED) {
2604 			warn(pg_changed, lcbdata->sc_target_fmri,
2605 			    p->sc_pgroup_name);
2606 			lcbdata->sc_err = EBUSY;
2607 		}
2608 		return (UU_WALK_ERROR);
2609 	}
2610 
2611 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2612 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2613 
2614 		/*
2615 		 * take the snapshot running snapshot then
2616 		 * import the stored general/enable property
2617 		 */
2618 		r = take_snap(ent, snap_running, imp_rsnap);
2619 		switch (r) {
2620 		case 0:
2621 			break;
2622 
2623 		case ECONNABORTED:
2624 			warn(gettext("Could not take %s snapshot on import "
2625 			    "(repository connection broken).\n"),
2626 			    snap_running);
2627 			lcbdata->sc_err = r;
2628 			return (UU_WALK_ERROR);
2629 		case ECANCELED:
2630 			warn(emsg_deleted);
2631 			lcbdata->sc_err = r;
2632 			return (UU_WALK_ERROR);
2633 
2634 		case EPERM:
2635 			warn(gettext("Could not take %s snapshot "
2636 			    "(permission denied).\n"), snap_running);
2637 			lcbdata->sc_err = r;
2638 			return (UU_WALK_ERROR);
2639 
2640 		case ENOSPC:
2641 			warn(gettext("Could not take %s snapshot"
2642 			    "(repository server out of resources).\n"),
2643 			    snap_running);
2644 			lcbdata->sc_err = r;
2645 			return (UU_WALK_ERROR);
2646 
2647 		default:
2648 			bad_error("take_snap", r);
2649 		}
2650 
2651 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2652 		if (r != UU_WALK_NEXT) {
2653 			if (r != UU_WALK_ERROR)
2654 				bad_error("lscf_property_import", r);
2655 			return (EINVAL);
2656 		}
2657 	}
2658 
2659 	r = scf_transaction_commit(imp_tx);
2660 	switch (r) {
2661 	case 1:
2662 		r = UU_WALK_NEXT;
2663 		break;
2664 
2665 	case 0:
2666 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2667 		lcbdata->sc_err = EBUSY;
2668 		r = UU_WALK_ERROR;
2669 		break;
2670 
2671 	case -1:
2672 		switch (scf_error()) {
2673 		case SCF_ERROR_BACKEND_READONLY:
2674 		case SCF_ERROR_BACKEND_ACCESS:
2675 		case SCF_ERROR_CONNECTION_BROKEN:
2676 		case SCF_ERROR_NO_RESOURCES:
2677 			r = stash_scferror(lcbdata);
2678 			break;
2679 
2680 		case SCF_ERROR_DELETED:
2681 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2682 			    p->sc_pgroup_name);
2683 			lcbdata->sc_err = EBUSY;
2684 			r = UU_WALK_ERROR;
2685 			break;
2686 
2687 		case SCF_ERROR_PERMISSION_DENIED:
2688 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2689 			    lcbdata->sc_target_fmri);
2690 			r = stash_scferror(lcbdata);
2691 			break;
2692 
2693 		case SCF_ERROR_NOT_SET:
2694 		case SCF_ERROR_INVALID_ARGUMENT:
2695 		case SCF_ERROR_NOT_BOUND:
2696 		default:
2697 			bad_error("scf_transaction_commit", scf_error());
2698 		}
2699 		break;
2700 
2701 	default:
2702 		bad_error("scf_transaction_commit", r);
2703 	}
2704 
2705 	scf_transaction_destroy_children(imp_tx);
2706 
2707 	return (r);
2708 }
2709 
2710 /*
2711  * Returns
2712  *   0 - success
2713  *   ECONNABORTED - repository connection broken
2714  *   ENOMEM - out of memory
2715  *   ENOSPC - svc.configd is out of resources
2716  *   ECANCELED - inst was deleted
2717  *   EPERM - could not create property group (permission denied) (error printed)
2718  *	   - could not modify property group (permission denied) (error printed)
2719  *   EROFS - could not create property group (repository is read-only)
2720  *   EACCES - could not create property group (backend access denied)
2721  *   EEXIST - could not create property group (already exists)
2722  *   EINVAL - invalid property group name (error printed)
2723  *	    - invalid property name (error printed)
2724  *	    - invalid value (error printed)
2725  *   EBUSY - new property group changed (error printed)
2726  */
2727 static int
2728 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2729     const entity_t *isvc, int flags)
2730 {
2731 	scf_callback_t cbdata;
2732 
2733 	cbdata.sc_handle = scf_service_handle(svc);
2734 	cbdata.sc_parent = svc;
2735 	cbdata.sc_service = 1;
2736 	cbdata.sc_general = 0;
2737 	cbdata.sc_enable = 0;
2738 	cbdata.sc_flags = flags;
2739 	cbdata.sc_source_fmri = isvc->sc_fmri;
2740 	cbdata.sc_target_fmri = target_fmri;
2741 
2742 	/*
2743 	 * If the op is set, then add the flag to the callback
2744 	 * flags for later use.
2745 	 */
2746 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2747 		switch (isvc->sc_op) {
2748 		case SVCCFG_OP_IMPORT :
2749 			cbdata.sc_flags |= SCI_OP_IMPORT;
2750 			break;
2751 		case SVCCFG_OP_APPLY :
2752 			cbdata.sc_flags |= SCI_OP_APPLY;
2753 			break;
2754 		case SVCCFG_OP_RESTORE :
2755 			cbdata.sc_flags |= SCI_OP_RESTORE;
2756 			break;
2757 		default :
2758 			uu_die(gettext("lscf_import_service_pgs : "
2759 			    "Unknown op stored in the service entity\n"));
2760 
2761 		}
2762 	}
2763 
2764 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2765 	    UU_DEFAULT) != 0) {
2766 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2767 			bad_error("uu_list_walk", uu_error());
2768 
2769 		return (cbdata.sc_err);
2770 	}
2771 
2772 	return (0);
2773 }
2774 
2775 /*
2776  * Returns
2777  *   0 - success
2778  *   ECONNABORTED - repository connection broken
2779  *   ENOMEM - out of memory
2780  *   ENOSPC - svc.configd is out of resources
2781  *   ECANCELED - inst was deleted
2782  *   EPERM - could not create property group (permission denied) (error printed)
2783  *	   - could not modify property group (permission denied) (error printed)
2784  *   EROFS - could not create property group (repository is read-only)
2785  *   EACCES - could not create property group (backend access denied)
2786  *   EEXIST - could not create property group (already exists)
2787  *   EINVAL - invalid property group name (error printed)
2788  *	    - invalid property name (error printed)
2789  *	    - invalid value (error printed)
2790  *   EBUSY - new property group changed (error printed)
2791  */
2792 static int
2793 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2794     const entity_t *iinst, int flags)
2795 {
2796 	scf_callback_t cbdata;
2797 
2798 	cbdata.sc_handle = scf_instance_handle(inst);
2799 	cbdata.sc_parent = inst;
2800 	cbdata.sc_service = 0;
2801 	cbdata.sc_general = NULL;
2802 	cbdata.sc_enable = NULL;
2803 	cbdata.sc_flags = flags;
2804 	cbdata.sc_source_fmri = iinst->sc_fmri;
2805 	cbdata.sc_target_fmri = target_fmri;
2806 
2807 	/*
2808 	 * If the op is set, then add the flag to the callback
2809 	 * flags for later use.
2810 	 */
2811 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2812 		switch (iinst->sc_op) {
2813 		case SVCCFG_OP_IMPORT :
2814 			cbdata.sc_flags |= SCI_OP_IMPORT;
2815 			break;
2816 		case SVCCFG_OP_APPLY :
2817 			cbdata.sc_flags |= SCI_OP_APPLY;
2818 			break;
2819 		case SVCCFG_OP_RESTORE :
2820 			cbdata.sc_flags |= SCI_OP_RESTORE;
2821 			break;
2822 		default :
2823 			uu_die(gettext("lscf_import_instance_pgs : "
2824 			    "Unknown op stored in the instance entity\n"));
2825 		}
2826 	}
2827 
2828 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2829 	    UU_DEFAULT) != 0) {
2830 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2831 			bad_error("uu_list_walk", uu_error());
2832 
2833 		return (cbdata.sc_err);
2834 	}
2835 
2836 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2837 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2838 		/*
2839 		 * If importing with the SCI_NOENABLED flag then
2840 		 * skip the delay, but if not then add the delay
2841 		 * of the enable property.
2842 		 */
2843 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2844 			cbdata.sc_flags |= SCI_DELAYENABLE;
2845 		}
2846 
2847 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2848 		    != UU_WALK_NEXT)
2849 			return (cbdata.sc_err);
2850 	}
2851 
2852 	return (0);
2853 }
2854 
2855 /*
2856  * Report the reasons why we can't upgrade pg2 to pg1.
2857  */
2858 static void
2859 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2860     int new)
2861 {
2862 	property_t *p1, *p2;
2863 
2864 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2865 
2866 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2867 		return;
2868 
2869 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2870 	    p1 != NULL;
2871 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2872 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2873 		if (p2 != NULL) {
2874 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2875 			    new);
2876 			continue;
2877 		}
2878 
2879 		if (new)
2880 			warn(gettext("Conflict upgrading %s (new property "
2881 			    "group \"%s\" is missing property \"%s\").\n"),
2882 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2883 		else
2884 			warn(gettext("Conflict upgrading %s (property "
2885 			    "\"%s/%s\" is missing).\n"), fmri,
2886 			    pg1->sc_pgroup_name, p1->sc_property_name);
2887 	}
2888 
2889 	/*
2890 	 * Since pg1 should be from the manifest, any properties in pg2 which
2891 	 * aren't in pg1 shouldn't be reported as conflicts.
2892 	 */
2893 }
2894 
2895 /*
2896  * Add transaction entries to tx which will upgrade cur's pg according to old
2897  * & new.
2898  *
2899  * Returns
2900  *   0 - success
2901  *   EINVAL - new has a property with an invalid name or value (message emitted)
2902  *   ENOMEM - out of memory
2903  */
2904 static int
2905 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2906     pgroup_t *cur, int speak, const char *fmri)
2907 {
2908 	property_t *p, *new_p, *cur_p;
2909 	scf_transaction_entry_t *e;
2910 	int r;
2911 	int is_general;
2912 	int is_protected;
2913 
2914 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2915 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2916 		bad_error("uu_list_walk", uu_error());
2917 
2918 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2919 
2920 	for (p = uu_list_first(old->sc_pgroup_props);
2921 	    p != NULL;
2922 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2923 		/* p is a property in the old property group. */
2924 
2925 		/* Protect live properties. */
2926 		is_protected = 0;
2927 		if (is_general) {
2928 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2929 			    0 ||
2930 			    strcmp(p->sc_property_name,
2931 			    SCF_PROPERTY_RESTARTER) == 0)
2932 				is_protected = 1;
2933 		}
2934 
2935 		/* Look for the same property in the new properties. */
2936 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2937 		if (new_p != NULL) {
2938 			new_p->sc_seen = 1;
2939 
2940 			/*
2941 			 * If the new property is the same as the old, don't do
2942 			 * anything (leave any user customizations).
2943 			 */
2944 			if (prop_equal(p, new_p, NULL, NULL, 0))
2945 				continue;
2946 
2947 			if (new_p->sc_property_override)
2948 				goto upgrade;
2949 		}
2950 
2951 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2952 		if (cur_p == NULL) {
2953 			/*
2954 			 * p has been deleted from the repository.  If we were
2955 			 * going to delete it anyway, do nothing.  Otherwise
2956 			 * report a conflict.
2957 			 */
2958 			if (new_p == NULL)
2959 				continue;
2960 
2961 			if (is_protected)
2962 				continue;
2963 
2964 			warn(gettext("Conflict upgrading %s "
2965 			    "(property \"%s/%s\" is missing).\n"), fmri,
2966 			    old->sc_pgroup_name, p->sc_property_name);
2967 			continue;
2968 		}
2969 
2970 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2971 			/*
2972 			 * Conflict.  Don't warn if the property is already the
2973 			 * way we want it, though.
2974 			 */
2975 			if (is_protected)
2976 				continue;
2977 
2978 			if (new_p == NULL)
2979 				(void) prop_equal(p, cur_p, fmri,
2980 				    old->sc_pgroup_name, 0);
2981 			else
2982 				(void) prop_equal(cur_p, new_p, fmri,
2983 				    old->sc_pgroup_name, 0);
2984 			continue;
2985 		}
2986 
2987 		if (is_protected) {
2988 			if (speak)
2989 				warn(gettext("%s: Refusing to upgrade "
2990 				    "\"%s/%s\" (live property).\n"), fmri,
2991 				    old->sc_pgroup_name, p->sc_property_name);
2992 			continue;
2993 		}
2994 
2995 upgrade:
2996 		/* p hasn't been customized in the repository.  Upgrade it. */
2997 		if (new_p == NULL) {
2998 			/* p was deleted.  Delete from cur if unchanged. */
2999 			if (speak)
3000 				warn(gettext(
3001 				    "%s: Deleting property \"%s/%s\".\n"),
3002 				    fmri, old->sc_pgroup_name,
3003 				    p->sc_property_name);
3004 
3005 			e = scf_entry_create(g_hndl);
3006 			if (e == NULL)
3007 				return (ENOMEM);
3008 
3009 			if (scf_transaction_property_delete(tx, e,
3010 			    p->sc_property_name) != 0) {
3011 				switch (scf_error()) {
3012 				case SCF_ERROR_DELETED:
3013 					scf_entry_destroy(e);
3014 					return (ECANCELED);
3015 
3016 				case SCF_ERROR_CONNECTION_BROKEN:
3017 					scf_entry_destroy(e);
3018 					return (ECONNABORTED);
3019 
3020 				case SCF_ERROR_NOT_FOUND:
3021 					/*
3022 					 * This can happen if cur is from the
3023 					 * running snapshot (and it differs
3024 					 * from the live properties).
3025 					 */
3026 					scf_entry_destroy(e);
3027 					break;
3028 
3029 				case SCF_ERROR_HANDLE_MISMATCH:
3030 				case SCF_ERROR_NOT_BOUND:
3031 				case SCF_ERROR_NOT_SET:
3032 				case SCF_ERROR_INVALID_ARGUMENT:
3033 				default:
3034 					bad_error(
3035 					    "scf_transaction_property_delete",
3036 					    scf_error());
3037 				}
3038 			}
3039 		} else {
3040 			scf_callback_t ctx;
3041 
3042 			if (speak)
3043 				warn(gettext(
3044 				    "%s: Upgrading property \"%s/%s\".\n"),
3045 				    fmri, old->sc_pgroup_name,
3046 				    p->sc_property_name);
3047 
3048 			ctx.sc_handle = g_hndl;
3049 			ctx.sc_trans = tx;
3050 			ctx.sc_flags = 0;
3051 
3052 			r = lscf_property_import(new_p, &ctx);
3053 			if (r != UU_WALK_NEXT) {
3054 				if (r != UU_WALK_ERROR)
3055 					bad_error("lscf_property_import", r);
3056 				return (EINVAL);
3057 			}
3058 		}
3059 	}
3060 
3061 	/* Go over the properties which were added. */
3062 	for (new_p = uu_list_first(new->sc_pgroup_props);
3063 	    new_p != NULL;
3064 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3065 		if (new_p->sc_seen)
3066 			continue;
3067 
3068 		/* This is a new property. */
3069 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3070 		if (cur_p == NULL) {
3071 			scf_callback_t ctx;
3072 
3073 			ctx.sc_handle = g_hndl;
3074 			ctx.sc_trans = tx;
3075 			ctx.sc_flags = 0;
3076 
3077 			r = lscf_property_import(new_p, &ctx);
3078 			if (r != UU_WALK_NEXT) {
3079 				if (r != UU_WALK_ERROR)
3080 					bad_error("lscf_property_import", r);
3081 				return (EINVAL);
3082 			}
3083 			continue;
3084 		}
3085 
3086 		/*
3087 		 * Report a conflict if the new property differs from the
3088 		 * current one.  Unless it's general/enabled, since that's
3089 		 * never in the last-import snapshot.
3090 		 */
3091 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3092 		    0 &&
3093 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3094 			continue;
3095 
3096 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3097 	}
3098 
3099 	return (0);
3100 }
3101 
3102 /*
3103  * Upgrade pg according to old & new.
3104  *
3105  * Returns
3106  *   0 - success
3107  *   ECONNABORTED - repository connection broken
3108  *   ENOMEM - out of memory
3109  *   ENOSPC - svc.configd is out of resources
3110  *   ECANCELED - pg was deleted
3111  *   EPERM - couldn't modify pg (permission denied)
3112  *   EROFS - couldn't modify pg (backend read-only)
3113  *   EACCES - couldn't modify pg (backend access denied)
3114  *   EINVAL - new has a property with invalid name or value (error printed)
3115  *   EBUSY - pg changed unexpectedly
3116  */
3117 static int
3118 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3119     pgroup_t *new, int speak, const char *fmri)
3120 {
3121 	int r;
3122 
3123 	if (scf_transaction_start(imp_tx, pg) != 0) {
3124 		switch (scf_error()) {
3125 		case SCF_ERROR_CONNECTION_BROKEN:
3126 		case SCF_ERROR_DELETED:
3127 		case SCF_ERROR_PERMISSION_DENIED:
3128 		case SCF_ERROR_BACKEND_READONLY:
3129 		case SCF_ERROR_BACKEND_ACCESS:
3130 			return (scferror2errno(scf_error()));
3131 
3132 		case SCF_ERROR_HANDLE_MISMATCH:
3133 		case SCF_ERROR_IN_USE:
3134 		case SCF_ERROR_NOT_BOUND:
3135 		case SCF_ERROR_NOT_SET:
3136 		default:
3137 			bad_error("scf_transaction_start", scf_error());
3138 		}
3139 	}
3140 
3141 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3142 	switch (r) {
3143 	case 0:
3144 		break;
3145 
3146 	case EINVAL:
3147 	case ENOMEM:
3148 		scf_transaction_destroy_children(imp_tx);
3149 		return (r);
3150 
3151 	default:
3152 		bad_error("add_upgrade_entries", r);
3153 	}
3154 
3155 	r = scf_transaction_commit(imp_tx);
3156 
3157 	scf_transaction_destroy_children(imp_tx);
3158 
3159 	switch (r) {
3160 	case 1:
3161 		break;
3162 
3163 	case 0:
3164 		return (EBUSY);
3165 
3166 	case -1:
3167 		switch (scf_error()) {
3168 		case SCF_ERROR_CONNECTION_BROKEN:
3169 		case SCF_ERROR_NO_RESOURCES:
3170 		case SCF_ERROR_PERMISSION_DENIED:
3171 		case SCF_ERROR_BACKEND_READONLY:
3172 		case SCF_ERROR_BACKEND_ACCESS:
3173 		case SCF_ERROR_DELETED:
3174 			return (scferror2errno(scf_error()));
3175 
3176 		case SCF_ERROR_NOT_BOUND:
3177 		case SCF_ERROR_INVALID_ARGUMENT:
3178 		case SCF_ERROR_NOT_SET:
3179 		default:
3180 			bad_error("scf_transaction_commit", scf_error());
3181 		}
3182 
3183 	default:
3184 		bad_error("scf_transaction_commit", r);
3185 	}
3186 
3187 	return (0);
3188 }
3189 
3190 /*
3191  * Compares two entity FMRIs.  Returns
3192  *
3193  *   1 - equal
3194  *   0 - not equal
3195  *   -1 - f1 is invalid or not an entity
3196  *   -2 - f2 is invalid or not an entity
3197  */
3198 static int
3199 fmri_equal(const char *f1, const char *f2)
3200 {
3201 	int r;
3202 	const char *s1, *i1, *pg1;
3203 	const char *s2, *i2, *pg2;
3204 
3205 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3206 		return (-1);
3207 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3208 		return (-1);
3209 
3210 	if (s1 == NULL || pg1 != NULL)
3211 		return (-1);
3212 
3213 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3214 		return (-2);
3215 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3216 		return (-2);
3217 
3218 	if (s2 == NULL || pg2 != NULL)
3219 		return (-2);
3220 
3221 	r = strcmp(s1, s2);
3222 	if (r != 0)
3223 		return (0);
3224 
3225 	if (i1 == NULL && i2 == NULL)
3226 		return (1);
3227 
3228 	if (i1 == NULL || i2 == NULL)
3229 		return (0);
3230 
3231 	return (strcmp(i1, i2) == 0);
3232 }
3233 
3234 /*
3235  * Import a dependent by creating a dependency property group in the dependent
3236  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3237  * dependents pg, and add an entry to create a new property for this
3238  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3239  *
3240  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3241  * lcbdata->sc_err to
3242  *   ECONNABORTED - repository connection broken
3243  *   ENOMEM - out of memory
3244  *   ENOSPC - configd is out of resources
3245  *   EINVAL - target is invalid (error printed)
3246  *	    - target is not an entity (error printed)
3247  *	    - dependent has invalid name (error printed)
3248  *	    - invalid property name (error printed)
3249  *	    - invalid value (error printed)
3250  *	    - scope of target does not exist (error printed)
3251  *   EPERM - couldn't create target (permission denied) (error printed)
3252  *	   - couldn't create dependency pg (permission denied) (error printed)
3253  *	   - couldn't modify dependency pg (permission denied) (error printed)
3254  *   EROFS - couldn't create target (repository read-only)
3255  *	   - couldn't create dependency pg (repository read-only)
3256  *   EACCES - couldn't create target (backend access denied)
3257  *	    - couldn't create dependency pg (backend access denied)
3258  *   ECANCELED - sc_trans's pg was deleted
3259  *   EALREADY - property for dependent already exists in sc_trans's pg
3260  *   EEXIST - dependency pg already exists in target (error printed)
3261  *   EBUSY - target deleted (error printed)
3262  *         - property group changed during import (error printed)
3263  */
3264 static int
3265 lscf_dependent_import(void *a1, void *pvt)
3266 {
3267 	pgroup_t *pgrp = a1;
3268 	scf_callback_t *lcbdata = pvt;
3269 
3270 	int isservice;
3271 	int ret;
3272 	scf_transaction_entry_t *e;
3273 	scf_value_t *val;
3274 	scf_callback_t dependent_cbdata;
3275 	scf_error_t scfe;
3276 
3277 	/*
3278 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3279 	 * it's invalid, we fail before modifying the repository.
3280 	 */
3281 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3282 	    &dependent_cbdata.sc_parent, &isservice);
3283 	switch (scfe) {
3284 	case SCF_ERROR_NONE:
3285 		break;
3286 
3287 	case SCF_ERROR_NO_MEMORY:
3288 		return (stash_scferror_err(lcbdata, scfe));
3289 
3290 	case SCF_ERROR_INVALID_ARGUMENT:
3291 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3292 		    "invalid.\n"), pgrp->sc_pgroup_name);
3293 		return (stash_scferror_err(lcbdata, scfe));
3294 
3295 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3296 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3297 		    "specifies neither a service nor an instance.\n"),
3298 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3299 		return (stash_scferror_err(lcbdata, scfe));
3300 
3301 	case SCF_ERROR_NOT_FOUND:
3302 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3303 		    &dependent_cbdata.sc_parent, &isservice);
3304 		switch (scfe) {
3305 		case SCF_ERROR_NONE:
3306 			break;
3307 
3308 		case SCF_ERROR_NO_MEMORY:
3309 		case SCF_ERROR_BACKEND_READONLY:
3310 		case SCF_ERROR_BACKEND_ACCESS:
3311 			return (stash_scferror_err(lcbdata, scfe));
3312 
3313 		case SCF_ERROR_NOT_FOUND:
3314 			semerr(gettext("The scope in FMRI \"%s\" for the "
3315 			    "\"%s\" dependent does not exist.\n"),
3316 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3317 			lcbdata->sc_err = EINVAL;
3318 			return (UU_WALK_ERROR);
3319 
3320 		case SCF_ERROR_PERMISSION_DENIED:
3321 			warn(gettext(
3322 			    "Could not create %s (permission denied).\n"),
3323 			    pgrp->sc_pgroup_fmri);
3324 			return (stash_scferror_err(lcbdata, scfe));
3325 
3326 		case SCF_ERROR_INVALID_ARGUMENT:
3327 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3328 		default:
3329 			bad_error("create_entity", scfe);
3330 		}
3331 		break;
3332 
3333 	default:
3334 		bad_error("fmri_to_entity", scfe);
3335 	}
3336 
3337 	if (lcbdata->sc_trans != NULL) {
3338 		e = scf_entry_create(lcbdata->sc_handle);
3339 		if (e == NULL) {
3340 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3341 				bad_error("scf_entry_create", scf_error());
3342 
3343 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3344 			return (stash_scferror(lcbdata));
3345 		}
3346 
3347 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3348 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3349 			switch (scf_error()) {
3350 			case SCF_ERROR_INVALID_ARGUMENT:
3351 				warn(gettext("Dependent of %s has invalid name "
3352 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3353 				    pgrp->sc_pgroup_name);
3354 				/* FALLTHROUGH */
3355 
3356 			case SCF_ERROR_DELETED:
3357 			case SCF_ERROR_CONNECTION_BROKEN:
3358 				scf_entry_destroy(e);
3359 				entity_destroy(dependent_cbdata.sc_parent,
3360 				    isservice);
3361 				return (stash_scferror(lcbdata));
3362 
3363 			case SCF_ERROR_EXISTS:
3364 				scf_entry_destroy(e);
3365 				entity_destroy(dependent_cbdata.sc_parent,
3366 				    isservice);
3367 				lcbdata->sc_err = EALREADY;
3368 				return (UU_WALK_ERROR);
3369 
3370 			case SCF_ERROR_NOT_BOUND:
3371 			case SCF_ERROR_HANDLE_MISMATCH:
3372 			case SCF_ERROR_NOT_SET:
3373 			default:
3374 				bad_error("scf_transaction_property_new",
3375 				    scf_error());
3376 			}
3377 		}
3378 
3379 		val = scf_value_create(lcbdata->sc_handle);
3380 		if (val == NULL) {
3381 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3382 				bad_error("scf_value_create", scf_error());
3383 
3384 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3385 			return (stash_scferror(lcbdata));
3386 		}
3387 
3388 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3389 		    pgrp->sc_pgroup_fmri) != 0)
3390 			/* invalid should have been caught above */
3391 			bad_error("scf_value_set_from_string", scf_error());
3392 
3393 		if (scf_entry_add_value(e, val) != 0)
3394 			bad_error("scf_entry_add_value", scf_error());
3395 	}
3396 
3397 	/* Add the property group to the target entity. */
3398 
3399 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3400 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3401 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3402 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3403 
3404 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3405 
3406 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3407 
3408 	if (ret == UU_WALK_NEXT)
3409 		return (ret);
3410 
3411 	if (ret != UU_WALK_ERROR)
3412 		bad_error("entity_pgroup_import", ret);
3413 
3414 	switch (dependent_cbdata.sc_err) {
3415 	case ECANCELED:
3416 		warn(gettext("%s deleted unexpectedly.\n"),
3417 		    pgrp->sc_pgroup_fmri);
3418 		lcbdata->sc_err = EBUSY;
3419 		break;
3420 
3421 	case EEXIST:
3422 		warn(gettext("Could not create \"%s\" dependency in %s "
3423 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3424 		    pgrp->sc_pgroup_fmri);
3425 		/* FALLTHROUGH */
3426 
3427 	default:
3428 		lcbdata->sc_err = dependent_cbdata.sc_err;
3429 	}
3430 
3431 	return (UU_WALK_ERROR);
3432 }
3433 
3434 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3435     const scf_snaplevel_t *, scf_transaction_t *);
3436 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3437     const pgroup_t *);
3438 
3439 /*
3440  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3441  * the current dependent targets from running (the snaplevel of a running
3442  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3443  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3444  * dependent targets and dependency properties from li_dpts_pg (the
3445  * "dependents" property group in snpl) and snpl (the snaplevel which
3446  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3447  * snpl doesn't have a "dependents" property group, and any dependents in ient
3448  * are new.
3449  *
3450  * Returns
3451  *   0 - success
3452  *   ECONNABORTED - repository connection broken
3453  *   ENOMEM - out of memory
3454  *   ENOSPC - configd is out of resources
3455  *   ECANCELED - ent was deleted
3456  *   ENODEV - the entity containing li_dpts_pg was deleted
3457  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3458  *	   - couldn't upgrade dependent (permission denied) (error printed)
3459  *	   - couldn't create dependent (permission denied) (error printed)
3460  *   EROFS - could not modify dependents pg (repository read-only)
3461  *	   - couldn't upgrade dependent (repository read-only)
3462  *	   - couldn't create dependent (repository read-only)
3463  *   EACCES - could not modify dependents pg (backend access denied)
3464  *	    - could not upgrade dependent (backend access denied)
3465  *	    - could not create dependent (backend access denied)
3466  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3467  *	   - dependent target deleted (error printed)
3468  *	   - dependent pg changed (error printed)
3469  *   EINVAL - new dependent is invalid (error printed)
3470  *   EBADF - snpl is corrupt (error printed)
3471  *	   - snpl has corrupt pg (error printed)
3472  *	   - dependency pg in target is corrupt (error printed)
3473  *	   - target has corrupt snapshot (error printed)
3474  *   EEXIST - dependency pg already existed in target service (error printed)
3475  */
3476 static int
3477 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3478     const scf_snaplevel_t *snpl, const entity_t *ient,
3479     const scf_snaplevel_t *running, void *ent)
3480 {
3481 	pgroup_t *new_dpt_pgroup;
3482 	scf_callback_t cbdata;
3483 	int r, unseen, tx_started = 0;
3484 	int have_cur_depts;
3485 
3486 	const char * const dependents = "dependents";
3487 
3488 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3489 
3490 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3491 		/* Nothing to do. */
3492 		return (0);
3493 
3494 	/* Fetch the current version of the "dependents" property group. */
3495 	have_cur_depts = 1;
3496 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3497 		switch (scf_error()) {
3498 		case SCF_ERROR_NOT_FOUND:
3499 			break;
3500 
3501 		case SCF_ERROR_DELETED:
3502 		case SCF_ERROR_CONNECTION_BROKEN:
3503 			return (scferror2errno(scf_error()));
3504 
3505 		case SCF_ERROR_NOT_SET:
3506 		case SCF_ERROR_INVALID_ARGUMENT:
3507 		case SCF_ERROR_HANDLE_MISMATCH:
3508 		case SCF_ERROR_NOT_BOUND:
3509 		default:
3510 			bad_error("entity_get_pg", scf_error());
3511 		}
3512 
3513 		have_cur_depts = 0;
3514 	}
3515 
3516 	/* Fetch the running version of the "dependents" property group. */
3517 	ud_run_dpts_pg_set = 0;
3518 	if (running != NULL)
3519 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3520 	else
3521 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3522 	if (r == 0) {
3523 		ud_run_dpts_pg_set = 1;
3524 	} else {
3525 		switch (scf_error()) {
3526 		case SCF_ERROR_NOT_FOUND:
3527 			break;
3528 
3529 		case SCF_ERROR_DELETED:
3530 		case SCF_ERROR_CONNECTION_BROKEN:
3531 			return (scferror2errno(scf_error()));
3532 
3533 		case SCF_ERROR_NOT_SET:
3534 		case SCF_ERROR_INVALID_ARGUMENT:
3535 		case SCF_ERROR_HANDLE_MISMATCH:
3536 		case SCF_ERROR_NOT_BOUND:
3537 		default:
3538 			bad_error(running ? "scf_snaplevel_get_pg" :
3539 			    "entity_get_pg", scf_error());
3540 		}
3541 	}
3542 
3543 	/*
3544 	 * Clear the seen fields of the dependents, so we can tell which ones
3545 	 * are new.
3546 	 */
3547 	if (uu_list_walk(ient->sc_dependents, clear_int,
3548 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3549 		bad_error("uu_list_walk", uu_error());
3550 
3551 	if (li_dpts_pg != NULL) {
3552 		/*
3553 		 * Each property in li_dpts_pg represents a dependent tag in
3554 		 * the old manifest.  For each, call upgrade_dependent(),
3555 		 * which will change ud_cur_depts_pg or dependencies in other
3556 		 * services as appropriate.  Note (a) that changes to
3557 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3558 		 * made en masse, and (b) it's ok if the entity doesn't have
3559 		 * a current version of the "dependents" property group,
3560 		 * because we'll just consider all dependents as customized
3561 		 * (by being deleted).
3562 		 */
3563 
3564 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3565 			switch (scf_error()) {
3566 			case SCF_ERROR_DELETED:
3567 				return (ENODEV);
3568 
3569 			case SCF_ERROR_CONNECTION_BROKEN:
3570 				return (ECONNABORTED);
3571 
3572 			case SCF_ERROR_HANDLE_MISMATCH:
3573 			case SCF_ERROR_NOT_BOUND:
3574 			case SCF_ERROR_NOT_SET:
3575 			default:
3576 				bad_error("scf_iter_pg_properties",
3577 				    scf_error());
3578 			}
3579 		}
3580 
3581 		if (have_cur_depts &&
3582 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3583 			switch (scf_error()) {
3584 			case SCF_ERROR_BACKEND_ACCESS:
3585 			case SCF_ERROR_BACKEND_READONLY:
3586 			case SCF_ERROR_CONNECTION_BROKEN:
3587 				return (scferror2errno(scf_error()));
3588 
3589 			case SCF_ERROR_DELETED:
3590 				warn(emsg_pg_deleted, ient->sc_fmri,
3591 				    dependents);
3592 				return (EBUSY);
3593 
3594 			case SCF_ERROR_PERMISSION_DENIED:
3595 				warn(emsg_pg_mod_perm, dependents,
3596 				    ient->sc_fmri);
3597 				return (scferror2errno(scf_error()));
3598 
3599 			case SCF_ERROR_HANDLE_MISMATCH:
3600 			case SCF_ERROR_IN_USE:
3601 			case SCF_ERROR_NOT_BOUND:
3602 			case SCF_ERROR_NOT_SET:
3603 			default:
3604 				bad_error("scf_transaction_start", scf_error());
3605 			}
3606 		}
3607 		tx_started = have_cur_depts;
3608 
3609 		for (;;) {
3610 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3611 			if (r == 0)
3612 				break;
3613 			if (r == 1) {
3614 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3615 				    tx_started ? ud_tx : NULL);
3616 				switch (r) {
3617 				case 0:
3618 					continue;
3619 
3620 				case ECONNABORTED:
3621 				case ENOMEM:
3622 				case ENOSPC:
3623 				case EBADF:
3624 				case EBUSY:
3625 				case EINVAL:
3626 				case EPERM:
3627 				case EROFS:
3628 				case EACCES:
3629 				case EEXIST:
3630 					break;
3631 
3632 				case ECANCELED:
3633 					r = ENODEV;
3634 					break;
3635 
3636 				default:
3637 					bad_error("upgrade_dependent", r);
3638 				}
3639 
3640 				if (tx_started)
3641 					scf_transaction_destroy_children(ud_tx);
3642 				return (r);
3643 			}
3644 			if (r != -1)
3645 				bad_error("scf_iter_next_property", r);
3646 
3647 			switch (scf_error()) {
3648 			case SCF_ERROR_DELETED:
3649 				r = ENODEV;
3650 				break;
3651 
3652 			case SCF_ERROR_CONNECTION_BROKEN:
3653 				r = ECONNABORTED;
3654 				break;
3655 
3656 			case SCF_ERROR_NOT_SET:
3657 			case SCF_ERROR_INVALID_ARGUMENT:
3658 			case SCF_ERROR_NOT_BOUND:
3659 			case SCF_ERROR_HANDLE_MISMATCH:
3660 			default:
3661 				bad_error("scf_iter_next_property",
3662 				    scf_error());
3663 			}
3664 
3665 			if (tx_started)
3666 				scf_transaction_destroy_children(ud_tx);
3667 			return (r);
3668 		}
3669 	}
3670 
3671 	/* import unseen dependents */
3672 	unseen = 0;
3673 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3674 	    new_dpt_pgroup != NULL;
3675 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3676 	    new_dpt_pgroup)) {
3677 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3678 			unseen = 1;
3679 			break;
3680 		}
3681 	}
3682 
3683 	/* If there are none, exit early. */
3684 	if (unseen == 0)
3685 		goto commit;
3686 
3687 	/* Set up for lscf_dependent_import() */
3688 	cbdata.sc_handle = g_hndl;
3689 	cbdata.sc_parent = ent;
3690 	cbdata.sc_service = issvc;
3691 	cbdata.sc_flags = 0;
3692 
3693 	if (!have_cur_depts) {
3694 		/*
3695 		 * We have new dependents to import, so we need a "dependents"
3696 		 * property group.
3697 		 */
3698 		if (issvc)
3699 			r = scf_service_add_pg(ent, dependents,
3700 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3701 		else
3702 			r = scf_instance_add_pg(ent, dependents,
3703 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3704 		if (r != 0) {
3705 			switch (scf_error()) {
3706 			case SCF_ERROR_DELETED:
3707 			case SCF_ERROR_CONNECTION_BROKEN:
3708 			case SCF_ERROR_BACKEND_READONLY:
3709 			case SCF_ERROR_BACKEND_ACCESS:
3710 			case SCF_ERROR_NO_RESOURCES:
3711 				return (scferror2errno(scf_error()));
3712 
3713 			case SCF_ERROR_EXISTS:
3714 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3715 				return (EBUSY);
3716 
3717 			case SCF_ERROR_PERMISSION_DENIED:
3718 				warn(emsg_pg_add_perm, dependents,
3719 				    ient->sc_fmri);
3720 				return (scferror2errno(scf_error()));
3721 
3722 			case SCF_ERROR_NOT_BOUND:
3723 			case SCF_ERROR_HANDLE_MISMATCH:
3724 			case SCF_ERROR_INVALID_ARGUMENT:
3725 			case SCF_ERROR_NOT_SET:
3726 			default:
3727 				bad_error("scf_service_add_pg", scf_error());
3728 			}
3729 		}
3730 	}
3731 
3732 	cbdata.sc_trans = ud_tx;
3733 
3734 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3735 		switch (scf_error()) {
3736 		case SCF_ERROR_CONNECTION_BROKEN:
3737 		case SCF_ERROR_BACKEND_ACCESS:
3738 		case SCF_ERROR_BACKEND_READONLY:
3739 			return (scferror2errno(scf_error()));
3740 
3741 		case SCF_ERROR_DELETED:
3742 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3743 			return (EBUSY);
3744 
3745 		case SCF_ERROR_PERMISSION_DENIED:
3746 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3747 			return (scferror2errno(scf_error()));
3748 
3749 		case SCF_ERROR_HANDLE_MISMATCH:
3750 		case SCF_ERROR_IN_USE:
3751 		case SCF_ERROR_NOT_BOUND:
3752 		case SCF_ERROR_NOT_SET:
3753 		default:
3754 			bad_error("scf_transaction_start", scf_error());
3755 		}
3756 	}
3757 	tx_started = 1;
3758 
3759 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3760 	    new_dpt_pgroup != NULL;
3761 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3762 	    new_dpt_pgroup)) {
3763 		if (new_dpt_pgroup->sc_pgroup_seen)
3764 			continue;
3765 
3766 		if (ud_run_dpts_pg_set) {
3767 			/*
3768 			 * If the dependent is already there, then we have
3769 			 * a conflict.
3770 			 */
3771 			if (scf_pg_get_property(ud_run_dpts_pg,
3772 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3773 				r = handle_dependent_conflict(ient, ud_prop,
3774 				    new_dpt_pgroup);
3775 				switch (r) {
3776 				case 0:
3777 					continue;
3778 
3779 				case ECONNABORTED:
3780 				case ENOMEM:
3781 				case EBUSY:
3782 				case EBADF:
3783 				case EINVAL:
3784 					scf_transaction_destroy_children(ud_tx);
3785 					return (r);
3786 
3787 				default:
3788 					bad_error("handle_dependent_conflict",
3789 					    r);
3790 				}
3791 			} else {
3792 				switch (scf_error()) {
3793 				case SCF_ERROR_NOT_FOUND:
3794 					break;
3795 
3796 				case SCF_ERROR_INVALID_ARGUMENT:
3797 					warn(emsg_fmri_invalid_pg_name,
3798 					    ient->sc_fmri,
3799 					    new_dpt_pgroup->sc_pgroup_name);
3800 					scf_transaction_destroy_children(ud_tx);
3801 					return (EINVAL);
3802 
3803 				case SCF_ERROR_DELETED:
3804 					warn(emsg_pg_deleted, ient->sc_fmri,
3805 					    new_dpt_pgroup->sc_pgroup_name);
3806 					scf_transaction_destroy_children(ud_tx);
3807 					return (EBUSY);
3808 
3809 				case SCF_ERROR_CONNECTION_BROKEN:
3810 					scf_transaction_destroy_children(ud_tx);
3811 					return (ECONNABORTED);
3812 
3813 				case SCF_ERROR_NOT_BOUND:
3814 				case SCF_ERROR_HANDLE_MISMATCH:
3815 				case SCF_ERROR_NOT_SET:
3816 				default:
3817 					bad_error("scf_pg_get_property",
3818 					    scf_error());
3819 				}
3820 			}
3821 		}
3822 
3823 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3824 		if (r != UU_WALK_NEXT) {
3825 			if (r != UU_WALK_ERROR)
3826 				bad_error("lscf_dependent_import", r);
3827 
3828 			if (cbdata.sc_err == EALREADY) {
3829 				/* Collisions were handled preemptively. */
3830 				bad_error("lscf_dependent_import",
3831 				    cbdata.sc_err);
3832 			}
3833 
3834 			scf_transaction_destroy_children(ud_tx);
3835 			return (cbdata.sc_err);
3836 		}
3837 	}
3838 
3839 commit:
3840 	if (!tx_started)
3841 		return (0);
3842 
3843 	r = scf_transaction_commit(ud_tx);
3844 
3845 	scf_transaction_destroy_children(ud_tx);
3846 
3847 	switch (r) {
3848 	case 1:
3849 		return (0);
3850 
3851 	case 0:
3852 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3853 		return (EBUSY);
3854 
3855 	case -1:
3856 		break;
3857 
3858 	default:
3859 		bad_error("scf_transaction_commit", r);
3860 	}
3861 
3862 	switch (scf_error()) {
3863 	case SCF_ERROR_CONNECTION_BROKEN:
3864 	case SCF_ERROR_BACKEND_READONLY:
3865 	case SCF_ERROR_BACKEND_ACCESS:
3866 	case SCF_ERROR_NO_RESOURCES:
3867 		return (scferror2errno(scf_error()));
3868 
3869 	case SCF_ERROR_DELETED:
3870 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3871 		return (EBUSY);
3872 
3873 	case SCF_ERROR_PERMISSION_DENIED:
3874 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3875 		return (scferror2errno(scf_error()));
3876 
3877 	case SCF_ERROR_NOT_BOUND:
3878 	case SCF_ERROR_INVALID_ARGUMENT:
3879 	case SCF_ERROR_NOT_SET:
3880 	default:
3881 		bad_error("scf_transaction_destroy", scf_error());
3882 		/* NOTREACHED */
3883 	}
3884 }
3885 
3886 /*
3887  * Used to add the manifests to the list of currently supported manifests.
3888  * We can modify the existing manifest list removing entries if the files
3889  * don't exist.
3890  *
3891  * Get the old list and the new file name
3892  * If the new file name is in the list return
3893  * If not then add the file to the list.
3894  * As we process the list check to see if the files in the old list exist
3895  *	if not then remove the file from the list.
3896  * Commit the list of manifest file names.
3897  *
3898  */
3899 static int
3900 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3901     const scf_snaplevel_t *running, void *ent)
3902 {
3903 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3904 	scf_property_t *ud_prop = NULL;
3905 	scf_iter_t *ud_prop_iter;
3906 	scf_value_t *fname_value;
3907 	scf_callback_t cbdata;
3908 	pgroup_t *mfst_pgroup;
3909 	property_t *mfst_prop;
3910 	property_t *old_prop;
3911 	char *pname;
3912 	char *fval;
3913 	char *old_pname;
3914 	char *old_fval;
3915 	int no_upgrade_pg;
3916 	int mfst_seen;
3917 	int r;
3918 
3919 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3920 
3921 	/*
3922 	 * This should always be the service base on the code
3923 	 * path, and the fact that the manifests pg is a service
3924 	 * level property group only.
3925 	 */
3926 	ud_mfsts_pg = scf_pg_create(g_hndl);
3927 	ud_prop = scf_property_create(g_hndl);
3928 	ud_prop_iter = scf_iter_create(g_hndl);
3929 	fname_value = scf_value_create(g_hndl);
3930 
3931 	/* Fetch the "manifests" property group */
3932 	no_upgrade_pg = 0;
3933 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3934 	    ud_mfsts_pg);
3935 	if (r != 0) {
3936 		switch (scf_error()) {
3937 		case SCF_ERROR_NOT_FOUND:
3938 			no_upgrade_pg = 1;
3939 			break;
3940 
3941 		case SCF_ERROR_DELETED:
3942 		case SCF_ERROR_CONNECTION_BROKEN:
3943 			return (scferror2errno(scf_error()));
3944 
3945 		case SCF_ERROR_NOT_SET:
3946 		case SCF_ERROR_INVALID_ARGUMENT:
3947 		case SCF_ERROR_HANDLE_MISMATCH:
3948 		case SCF_ERROR_NOT_BOUND:
3949 		default:
3950 			bad_error(running ? "scf_snaplevel_get_pg" :
3951 			    "entity_get_pg", scf_error());
3952 		}
3953 	}
3954 
3955 	if (no_upgrade_pg) {
3956 		cbdata.sc_handle = g_hndl;
3957 		cbdata.sc_parent = ent;
3958 		cbdata.sc_service = issvc;
3959 		cbdata.sc_flags = SCI_FORCE;
3960 		cbdata.sc_source_fmri = ient->sc_fmri;
3961 		cbdata.sc_target_fmri = ient->sc_fmri;
3962 
3963 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3964 			return (cbdata.sc_err);
3965 
3966 		return (0);
3967 	}
3968 
3969 	/* Fetch the new manifests property group */
3970 	mfst_pgroup = internal_pgroup_find_or_create(ient,
3971 	    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3972 	assert(mfst_pgroup != NULL);
3973 
3974 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3975 	    SCF_SUCCESS)
3976 		return (-1);
3977 
3978 	if ((pname = malloc(MAXPATHLEN)) == NULL)
3979 		return (ENOMEM);
3980 	if ((fval = malloc(MAXPATHLEN)) == NULL) {
3981 		free(pname);
3982 		return (ENOMEM);
3983 	}
3984 
3985 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3986 		mfst_seen = 0;
3987 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3988 			continue;
3989 
3990 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3991 		    mfst_prop != NULL;
3992 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3993 		    mfst_prop)) {
3994 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3995 				mfst_seen = 1;
3996 			}
3997 		}
3998 
3999 		/*
4000 		 * If the manifest is not seen then add it to the new mfst
4001 		 * property list to get proccessed into the repo.
4002 		 */
4003 		if (mfst_seen == 0) {
4004 			/*
4005 			 * If we cannot get the value then there is no
4006 			 * reason to attempt to attach the value to
4007 			 * the property group
4008 			 */
4009 			if (prop_get_val(ud_prop, fname_value) == 0 &&
4010 			    scf_value_get_astring(fname_value, fval,
4011 			    MAXPATHLEN) != -1)  {
4012 				old_pname = safe_strdup(pname);
4013 				old_fval = safe_strdup(fval);
4014 				old_prop = internal_property_create(old_pname,
4015 				    SCF_TYPE_ASTRING, 1, old_fval);
4016 
4017 				/*
4018 				 * Already checked to see if the property exists
4019 				 * in the group, and it does not.
4020 				 */
4021 				(void) internal_attach_property(mfst_pgroup,
4022 				    old_prop);
4023 			}
4024 		}
4025 	}
4026 	free(pname);
4027 	free(fval);
4028 
4029 	cbdata.sc_handle = g_hndl;
4030 	cbdata.sc_parent = ent;
4031 	cbdata.sc_service = issvc;
4032 	cbdata.sc_flags = SCI_FORCE;
4033 	cbdata.sc_source_fmri = ient->sc_fmri;
4034 	cbdata.sc_target_fmri = ient->sc_fmri;
4035 
4036 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4037 		return (cbdata.sc_err);
4038 
4039 	return (r);
4040 }
4041 
4042 /*
4043  * prop is taken to be a property in the "dependents" property group of snpl,
4044  * which is taken to be the snaplevel of a last-import snapshot corresponding
4045  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4046  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4047  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4048  * of the entity ient represents (possibly in the running snapshot).  If it
4049  * needs to be changed, an entry will be added to tx, if not NULL.
4050  *
4051  * Returns
4052  *   0 - success
4053  *   ECONNABORTED - repository connection broken
4054  *   ENOMEM - out of memory
4055  *   ENOSPC - configd was out of resources
4056  *   ECANCELED - snpl's entity was deleted
4057  *   EINVAL - dependent target is invalid (error printed)
4058  *	    - dependent is invalid (error printed)
4059  *   EBADF - snpl is corrupt (error printed)
4060  *	   - snpl has corrupt pg (error printed)
4061  *	   - dependency pg in target is corrupt (error printed)
4062  *	   - running snapshot in dependent is missing snaplevel (error printed)
4063  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4064  *	   - couldn't create dependent (permission denied) (error printed)
4065  *	   - couldn't modify dependent pg (permission denied) (error printed)
4066  *   EROFS - couldn't delete dependency pg (repository read-only)
4067  *	   - couldn't create dependent (repository read-only)
4068  *   EACCES - couldn't delete dependency pg (backend access denied)
4069  *	    - couldn't create dependent (backend access denied)
4070  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4071  *	   - tx's pg was deleted (error printed)
4072  *	   - dependent pg was changed or deleted (error printed)
4073  *   EEXIST - dependency pg already exists in new target (error printed)
4074  */
4075 static int
4076 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4077     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4078 {
4079 	pgroup_t pgrp;
4080 	scf_type_t ty;
4081 	pgroup_t *new_dpt_pgroup;
4082 	pgroup_t *old_dpt_pgroup = NULL;
4083 	pgroup_t *current_pg;
4084 	pgroup_t *dpt;
4085 	scf_callback_t cbdata;
4086 	int tissvc;
4087 	void *target_ent;
4088 	scf_error_t serr;
4089 	int r;
4090 	scf_transaction_entry_t *ent;
4091 
4092 	const char * const cf_inval = gettext("Conflict upgrading %s "
4093 	    "(dependent \"%s\" has invalid dependents property).\n");
4094 	const char * const cf_missing = gettext("Conflict upgrading %s "
4095 	    "(dependent \"%s\" is missing).\n");
4096 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4097 	    "(dependent \"%s\" has new dependency property group).\n");
4098 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4099 	    "(dependent \"%s\" has new target).\n");
4100 	const char * const li_corrupt =
4101 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4102 	const char * const upgrading =
4103 	    gettext("%s: Upgrading dependent \"%s\".\n");
4104 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4105 	    "corrupt (missing snaplevel).\n");
4106 
4107 	if (scf_property_type(prop, &ty) != 0) {
4108 		switch (scf_error()) {
4109 		case SCF_ERROR_DELETED:
4110 		case SCF_ERROR_CONNECTION_BROKEN:
4111 			return (scferror2errno(scf_error()));
4112 
4113 		case SCF_ERROR_NOT_BOUND:
4114 		case SCF_ERROR_NOT_SET:
4115 		default:
4116 			bad_error("scf_property_type", scf_error());
4117 		}
4118 	}
4119 
4120 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4121 		warn(li_corrupt, ient->sc_fmri);
4122 		return (EBADF);
4123 	}
4124 
4125 	/*
4126 	 * prop represents a dependent in the old manifest.  It is named after
4127 	 * the dependent.
4128 	 */
4129 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4130 		switch (scf_error()) {
4131 		case SCF_ERROR_DELETED:
4132 		case SCF_ERROR_CONNECTION_BROKEN:
4133 			return (scferror2errno(scf_error()));
4134 
4135 		case SCF_ERROR_NOT_BOUND:
4136 		case SCF_ERROR_NOT_SET:
4137 		default:
4138 			bad_error("scf_property_get_name", scf_error());
4139 		}
4140 	}
4141 
4142 	/* See if it's in the new manifest. */
4143 	pgrp.sc_pgroup_name = ud_name;
4144 	new_dpt_pgroup =
4145 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4146 
4147 	/* If it's not, delete it... if it hasn't been customized. */
4148 	if (new_dpt_pgroup == NULL) {
4149 		if (!ud_run_dpts_pg_set)
4150 			return (0);
4151 
4152 		if (scf_property_get_value(prop, ud_val) != 0) {
4153 			switch (scf_error()) {
4154 			case SCF_ERROR_NOT_FOUND:
4155 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4156 				warn(li_corrupt, ient->sc_fmri);
4157 				return (EBADF);
4158 
4159 			case SCF_ERROR_DELETED:
4160 			case SCF_ERROR_CONNECTION_BROKEN:
4161 				return (scferror2errno(scf_error()));
4162 
4163 			case SCF_ERROR_HANDLE_MISMATCH:
4164 			case SCF_ERROR_NOT_BOUND:
4165 			case SCF_ERROR_NOT_SET:
4166 			case SCF_ERROR_PERMISSION_DENIED:
4167 			default:
4168 				bad_error("scf_property_get_value",
4169 				    scf_error());
4170 			}
4171 		}
4172 
4173 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4174 		    max_scf_value_len + 1) < 0)
4175 			bad_error("scf_value_get_as_string", scf_error());
4176 
4177 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4178 		    0) {
4179 			switch (scf_error()) {
4180 			case SCF_ERROR_NOT_FOUND:
4181 				return (0);
4182 
4183 			case SCF_ERROR_CONNECTION_BROKEN:
4184 				return (scferror2errno(scf_error()));
4185 
4186 			case SCF_ERROR_DELETED:
4187 				warn(emsg_pg_deleted, ient->sc_fmri,
4188 				    "dependents");
4189 				return (EBUSY);
4190 
4191 			case SCF_ERROR_INVALID_ARGUMENT:
4192 			case SCF_ERROR_NOT_BOUND:
4193 			case SCF_ERROR_HANDLE_MISMATCH:
4194 			case SCF_ERROR_NOT_SET:
4195 			default:
4196 				bad_error("scf_pg_get_property", scf_error());
4197 			}
4198 		}
4199 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4200 			switch (scf_error()) {
4201 			case SCF_ERROR_NOT_FOUND:
4202 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4203 				warn(cf_inval, ient->sc_fmri, ud_name);
4204 				return (0);
4205 
4206 			case SCF_ERROR_DELETED:
4207 			case SCF_ERROR_CONNECTION_BROKEN:
4208 				return (scferror2errno(scf_error()));
4209 
4210 			case SCF_ERROR_HANDLE_MISMATCH:
4211 			case SCF_ERROR_NOT_BOUND:
4212 			case SCF_ERROR_NOT_SET:
4213 			case SCF_ERROR_PERMISSION_DENIED:
4214 			default:
4215 				bad_error("scf_property_get_value",
4216 				    scf_error());
4217 			}
4218 		}
4219 
4220 		ty = scf_value_type(ud_val);
4221 		assert(ty != SCF_TYPE_INVALID);
4222 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4223 			warn(cf_inval, ient->sc_fmri, ud_name);
4224 			return (0);
4225 		}
4226 
4227 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4228 		    max_scf_value_len + 1) < 0)
4229 			bad_error("scf_value_get_as_string", scf_error());
4230 
4231 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4232 		switch (r) {
4233 		case 1:
4234 			break;
4235 
4236 		case 0:
4237 		case -1:	/* warn? */
4238 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4239 			return (0);
4240 
4241 		case -2:
4242 			warn(li_corrupt, ient->sc_fmri);
4243 			return (EBADF);
4244 
4245 		default:
4246 			bad_error("fmri_equal", r);
4247 		}
4248 
4249 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4250 			switch (scf_error()) {
4251 			case SCF_ERROR_NOT_FOUND:
4252 				warn(li_corrupt, ient->sc_fmri);
4253 				return (EBADF);
4254 
4255 			case SCF_ERROR_DELETED:
4256 			case SCF_ERROR_CONNECTION_BROKEN:
4257 				return (scferror2errno(scf_error()));
4258 
4259 			case SCF_ERROR_NOT_BOUND:
4260 			case SCF_ERROR_HANDLE_MISMATCH:
4261 			case SCF_ERROR_INVALID_ARGUMENT:
4262 			case SCF_ERROR_NOT_SET:
4263 			default:
4264 				bad_error("scf_snaplevel_get_pg", scf_error());
4265 			}
4266 		}
4267 
4268 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4269 		    snap_lastimport);
4270 		switch (r) {
4271 		case 0:
4272 			break;
4273 
4274 		case ECANCELED:
4275 		case ECONNABORTED:
4276 		case ENOMEM:
4277 		case EBADF:
4278 			return (r);
4279 
4280 		case EACCES:
4281 		default:
4282 			bad_error("load_pg", r);
4283 		}
4284 
4285 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4286 		switch (serr) {
4287 		case SCF_ERROR_NONE:
4288 			break;
4289 
4290 		case SCF_ERROR_NO_MEMORY:
4291 			internal_pgroup_free(old_dpt_pgroup);
4292 			return (ENOMEM);
4293 
4294 		case SCF_ERROR_NOT_FOUND:
4295 			internal_pgroup_free(old_dpt_pgroup);
4296 			goto delprop;
4297 
4298 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4299 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4300 		default:
4301 			bad_error("fmri_to_entity", serr);
4302 		}
4303 
4304 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4305 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4306 		switch (r) {
4307 		case 0:
4308 			break;
4309 
4310 		case ECONNABORTED:
4311 			internal_pgroup_free(old_dpt_pgroup);
4312 			return (r);
4313 
4314 		case ECANCELED:
4315 		case ENOENT:
4316 			internal_pgroup_free(old_dpt_pgroup);
4317 			goto delprop;
4318 
4319 		case EBADF:
4320 			warn(r_no_lvl, ud_ctarg);
4321 			internal_pgroup_free(old_dpt_pgroup);
4322 			return (r);
4323 
4324 		case EINVAL:
4325 		default:
4326 			bad_error("entity_get_running_pg", r);
4327 		}
4328 
4329 		/* load it */
4330 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4331 		switch (r) {
4332 		case 0:
4333 			break;
4334 
4335 		case ECANCELED:
4336 			internal_pgroup_free(old_dpt_pgroup);
4337 			goto delprop;
4338 
4339 		case ECONNABORTED:
4340 		case ENOMEM:
4341 		case EBADF:
4342 			internal_pgroup_free(old_dpt_pgroup);
4343 			return (r);
4344 
4345 		case EACCES:
4346 		default:
4347 			bad_error("load_pg", r);
4348 		}
4349 
4350 		/* compare property groups */
4351 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4352 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4353 			internal_pgroup_free(old_dpt_pgroup);
4354 			internal_pgroup_free(current_pg);
4355 			return (0);
4356 		}
4357 
4358 		internal_pgroup_free(old_dpt_pgroup);
4359 		internal_pgroup_free(current_pg);
4360 
4361 		if (g_verbose)
4362 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4363 			    ient->sc_fmri, ud_name);
4364 
4365 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4366 			switch (scf_error()) {
4367 			case SCF_ERROR_NOT_FOUND:
4368 			case SCF_ERROR_DELETED:
4369 				internal_pgroup_free(old_dpt_pgroup);
4370 				goto delprop;
4371 
4372 			case SCF_ERROR_CONNECTION_BROKEN:
4373 				internal_pgroup_free(old_dpt_pgroup);
4374 				return (ECONNABORTED);
4375 
4376 			case SCF_ERROR_NOT_SET:
4377 			case SCF_ERROR_INVALID_ARGUMENT:
4378 			case SCF_ERROR_HANDLE_MISMATCH:
4379 			case SCF_ERROR_NOT_BOUND:
4380 			default:
4381 				bad_error("entity_get_pg", scf_error());
4382 			}
4383 		}
4384 
4385 		if (scf_pg_delete(ud_pg) != 0) {
4386 			switch (scf_error()) {
4387 			case SCF_ERROR_DELETED:
4388 				break;
4389 
4390 			case SCF_ERROR_CONNECTION_BROKEN:
4391 			case SCF_ERROR_BACKEND_READONLY:
4392 			case SCF_ERROR_BACKEND_ACCESS:
4393 				return (scferror2errno(scf_error()));
4394 
4395 			case SCF_ERROR_PERMISSION_DENIED:
4396 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4397 				return (scferror2errno(scf_error()));
4398 
4399 			case SCF_ERROR_NOT_SET:
4400 			default:
4401 				bad_error("scf_pg_delete", scf_error());
4402 			}
4403 		}
4404 
4405 		/*
4406 		 * This service was changed, so it must be refreshed.  But
4407 		 * since it's not mentioned in the new manifest, we have to
4408 		 * record its FMRI here for use later.  We record the name
4409 		 * & the entity (via sc_parent) in case we need to print error
4410 		 * messages during the refresh.
4411 		 */
4412 		dpt = internal_pgroup_new();
4413 		if (dpt == NULL)
4414 			return (ENOMEM);
4415 		dpt->sc_pgroup_name = strdup(ud_name);
4416 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4417 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4418 			return (ENOMEM);
4419 		dpt->sc_parent = (entity_t *)ient;
4420 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4421 			uu_die(gettext("libuutil error: %s\n"),
4422 			    uu_strerror(uu_error()));
4423 
4424 delprop:
4425 		if (tx == NULL)
4426 			return (0);
4427 
4428 		ent = scf_entry_create(g_hndl);
4429 		if (ent == NULL)
4430 			return (ENOMEM);
4431 
4432 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4433 			scf_entry_destroy(ent);
4434 			switch (scf_error()) {
4435 			case SCF_ERROR_DELETED:
4436 				warn(emsg_pg_deleted, ient->sc_fmri,
4437 				    "dependents");
4438 				return (EBUSY);
4439 
4440 			case SCF_ERROR_CONNECTION_BROKEN:
4441 				return (scferror2errno(scf_error()));
4442 
4443 			case SCF_ERROR_NOT_FOUND:
4444 				break;
4445 
4446 			case SCF_ERROR_HANDLE_MISMATCH:
4447 			case SCF_ERROR_NOT_BOUND:
4448 			case SCF_ERROR_INVALID_ARGUMENT:
4449 			case SCF_ERROR_NOT_SET:
4450 			default:
4451 				bad_error("scf_transaction_property_delete",
4452 				    scf_error());
4453 			}
4454 		}
4455 
4456 		return (0);
4457 	}
4458 
4459 	new_dpt_pgroup->sc_pgroup_seen = 1;
4460 
4461 	/*
4462 	 * Decide whether the dependent has changed in the manifest.
4463 	 */
4464 	/* Compare the target. */
4465 	if (scf_property_get_value(prop, ud_val) != 0) {
4466 		switch (scf_error()) {
4467 		case SCF_ERROR_NOT_FOUND:
4468 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4469 			warn(li_corrupt, ient->sc_fmri);
4470 			return (EBADF);
4471 
4472 		case SCF_ERROR_DELETED:
4473 		case SCF_ERROR_CONNECTION_BROKEN:
4474 			return (scferror2errno(scf_error()));
4475 
4476 		case SCF_ERROR_HANDLE_MISMATCH:
4477 		case SCF_ERROR_NOT_BOUND:
4478 		case SCF_ERROR_NOT_SET:
4479 		case SCF_ERROR_PERMISSION_DENIED:
4480 		default:
4481 			bad_error("scf_property_get_value", scf_error());
4482 		}
4483 	}
4484 
4485 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4486 	    0)
4487 		bad_error("scf_value_get_as_string", scf_error());
4488 
4489 	/*
4490 	 * If the fmri's are not equal then the old fmri will need to
4491 	 * be refreshed to ensure that the changes are properly updated
4492 	 * in that service.
4493 	 */
4494 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4495 	switch (r) {
4496 	case 0:
4497 		dpt = internal_pgroup_new();
4498 		if (dpt == NULL)
4499 			return (ENOMEM);
4500 		dpt->sc_pgroup_name = strdup(ud_name);
4501 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4502 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4503 			return (ENOMEM);
4504 		dpt->sc_parent = (entity_t *)ient;
4505 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4506 			uu_die(gettext("libuutil error: %s\n"),
4507 			    uu_strerror(uu_error()));
4508 		break;
4509 
4510 	case 1:
4511 		/* Compare the dependency pgs. */
4512 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4513 			switch (scf_error()) {
4514 			case SCF_ERROR_NOT_FOUND:
4515 				warn(li_corrupt, ient->sc_fmri);
4516 				return (EBADF);
4517 
4518 			case SCF_ERROR_DELETED:
4519 			case SCF_ERROR_CONNECTION_BROKEN:
4520 				return (scferror2errno(scf_error()));
4521 
4522 			case SCF_ERROR_NOT_BOUND:
4523 			case SCF_ERROR_HANDLE_MISMATCH:
4524 			case SCF_ERROR_INVALID_ARGUMENT:
4525 			case SCF_ERROR_NOT_SET:
4526 			default:
4527 				bad_error("scf_snaplevel_get_pg", scf_error());
4528 			}
4529 		}
4530 
4531 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4532 		    snap_lastimport);
4533 		switch (r) {
4534 		case 0:
4535 			break;
4536 
4537 		case ECANCELED:
4538 		case ECONNABORTED:
4539 		case ENOMEM:
4540 		case EBADF:
4541 			return (r);
4542 
4543 		case EACCES:
4544 		default:
4545 			bad_error("load_pg", r);
4546 		}
4547 
4548 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4549 			/* no change, leave customizations */
4550 			internal_pgroup_free(old_dpt_pgroup);
4551 			return (0);
4552 		}
4553 		break;
4554 
4555 	case -1:
4556 		warn(li_corrupt, ient->sc_fmri);
4557 		return (EBADF);
4558 
4559 	case -2:
4560 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4561 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4562 		return (EINVAL);
4563 
4564 	default:
4565 		bad_error("fmri_equal", r);
4566 	}
4567 
4568 	/*
4569 	 * The dependent has changed in the manifest.  Upgrade the current
4570 	 * properties if they haven't been customized.
4571 	 */
4572 
4573 	/*
4574 	 * If new_dpt_pgroup->sc_override, then act as though the property
4575 	 * group hasn't been customized.
4576 	 */
4577 	if (new_dpt_pgroup->sc_pgroup_override) {
4578 		(void) strcpy(ud_ctarg, ud_oldtarg);
4579 		goto nocust;
4580 	}
4581 
4582 	if (!ud_run_dpts_pg_set) {
4583 		warn(cf_missing, ient->sc_fmri, ud_name);
4584 		r = 0;
4585 		goto out;
4586 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4587 		switch (scf_error()) {
4588 		case SCF_ERROR_NOT_FOUND:
4589 			warn(cf_missing, ient->sc_fmri, ud_name);
4590 			r = 0;
4591 			goto out;
4592 
4593 		case SCF_ERROR_CONNECTION_BROKEN:
4594 			r = scferror2errno(scf_error());
4595 			goto out;
4596 
4597 		case SCF_ERROR_DELETED:
4598 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4599 			r = EBUSY;
4600 			goto out;
4601 
4602 		case SCF_ERROR_INVALID_ARGUMENT:
4603 		case SCF_ERROR_NOT_BOUND:
4604 		case SCF_ERROR_HANDLE_MISMATCH:
4605 		case SCF_ERROR_NOT_SET:
4606 		default:
4607 			bad_error("scf_pg_get_property", scf_error());
4608 		}
4609 	}
4610 
4611 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4612 		switch (scf_error()) {
4613 		case SCF_ERROR_NOT_FOUND:
4614 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4615 			warn(cf_inval, ient->sc_fmri, ud_name);
4616 			r = 0;
4617 			goto out;
4618 
4619 		case SCF_ERROR_DELETED:
4620 		case SCF_ERROR_CONNECTION_BROKEN:
4621 			r = scferror2errno(scf_error());
4622 			goto out;
4623 
4624 		case SCF_ERROR_HANDLE_MISMATCH:
4625 		case SCF_ERROR_NOT_BOUND:
4626 		case SCF_ERROR_NOT_SET:
4627 		case SCF_ERROR_PERMISSION_DENIED:
4628 		default:
4629 			bad_error("scf_property_get_value", scf_error());
4630 		}
4631 	}
4632 
4633 	ty = scf_value_type(ud_val);
4634 	assert(ty != SCF_TYPE_INVALID);
4635 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4636 		warn(cf_inval, ient->sc_fmri, ud_name);
4637 		r = 0;
4638 		goto out;
4639 	}
4640 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4641 	    0)
4642 		bad_error("scf_value_get_as_string", scf_error());
4643 
4644 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4645 	if (r == -1) {
4646 		warn(cf_inval, ient->sc_fmri, ud_name);
4647 		r = 0;
4648 		goto out;
4649 	} else if (r == -2) {
4650 		warn(li_corrupt, ient->sc_fmri);
4651 		r = EBADF;
4652 		goto out;
4653 	} else if (r == 0) {
4654 		/*
4655 		 * Target has been changed.  Only abort now if it's been
4656 		 * changed to something other than what's in the manifest.
4657 		 */
4658 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4659 		if (r == -1) {
4660 			warn(cf_inval, ient->sc_fmri, ud_name);
4661 			r = 0;
4662 			goto out;
4663 		} else if (r == 0) {
4664 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4665 			r = 0;
4666 			goto out;
4667 		} else if (r != 1) {
4668 			/* invalid sc_pgroup_fmri caught above */
4669 			bad_error("fmri_equal", r);
4670 		}
4671 
4672 		/*
4673 		 * Fetch the current dependency pg.  If it's what the manifest
4674 		 * says, then no problem.
4675 		 */
4676 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4677 		switch (serr) {
4678 		case SCF_ERROR_NONE:
4679 			break;
4680 
4681 		case SCF_ERROR_NOT_FOUND:
4682 			warn(cf_missing, ient->sc_fmri, ud_name);
4683 			r = 0;
4684 			goto out;
4685 
4686 		case SCF_ERROR_NO_MEMORY:
4687 			r = ENOMEM;
4688 			goto out;
4689 
4690 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4691 		case SCF_ERROR_INVALID_ARGUMENT:
4692 		default:
4693 			bad_error("fmri_to_entity", serr);
4694 		}
4695 
4696 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4697 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4698 		switch (r) {
4699 		case 0:
4700 			break;
4701 
4702 		case ECONNABORTED:
4703 			goto out;
4704 
4705 		case ECANCELED:
4706 		case ENOENT:
4707 			warn(cf_missing, ient->sc_fmri, ud_name);
4708 			r = 0;
4709 			goto out;
4710 
4711 		case EBADF:
4712 			warn(r_no_lvl, ud_ctarg);
4713 			goto out;
4714 
4715 		case EINVAL:
4716 		default:
4717 			bad_error("entity_get_running_pg", r);
4718 		}
4719 
4720 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4721 		switch (r) {
4722 		case 0:
4723 			break;
4724 
4725 		case ECANCELED:
4726 			warn(cf_missing, ient->sc_fmri, ud_name);
4727 			r = 0;
4728 			goto out;
4729 
4730 		case ECONNABORTED:
4731 		case ENOMEM:
4732 		case EBADF:
4733 			goto out;
4734 
4735 		case EACCES:
4736 		default:
4737 			bad_error("load_pg", r);
4738 		}
4739 
4740 		if (!pg_equal(current_pg, new_dpt_pgroup))
4741 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4742 		internal_pgroup_free(current_pg);
4743 		r = 0;
4744 		goto out;
4745 	} else if (r != 1) {
4746 		bad_error("fmri_equal", r);
4747 	}
4748 
4749 nocust:
4750 	/*
4751 	 * Target has not been customized.  Check the dependency property
4752 	 * group.
4753 	 */
4754 
4755 	if (old_dpt_pgroup == NULL) {
4756 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4757 		    ud_pg) != 0) {
4758 			switch (scf_error()) {
4759 			case SCF_ERROR_NOT_FOUND:
4760 				warn(li_corrupt, ient->sc_fmri);
4761 				return (EBADF);
4762 
4763 			case SCF_ERROR_DELETED:
4764 			case SCF_ERROR_CONNECTION_BROKEN:
4765 				return (scferror2errno(scf_error()));
4766 
4767 			case SCF_ERROR_NOT_BOUND:
4768 			case SCF_ERROR_HANDLE_MISMATCH:
4769 			case SCF_ERROR_INVALID_ARGUMENT:
4770 			case SCF_ERROR_NOT_SET:
4771 			default:
4772 				bad_error("scf_snaplevel_get_pg", scf_error());
4773 			}
4774 		}
4775 
4776 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4777 		    snap_lastimport);
4778 		switch (r) {
4779 		case 0:
4780 			break;
4781 
4782 		case ECANCELED:
4783 		case ECONNABORTED:
4784 		case ENOMEM:
4785 		case EBADF:
4786 			return (r);
4787 
4788 		case EACCES:
4789 		default:
4790 			bad_error("load_pg", r);
4791 		}
4792 	}
4793 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4794 	switch (serr) {
4795 	case SCF_ERROR_NONE:
4796 		break;
4797 
4798 	case SCF_ERROR_NOT_FOUND:
4799 		warn(cf_missing, ient->sc_fmri, ud_name);
4800 		r = 0;
4801 		goto out;
4802 
4803 	case SCF_ERROR_NO_MEMORY:
4804 		r = ENOMEM;
4805 		goto out;
4806 
4807 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4808 	case SCF_ERROR_INVALID_ARGUMENT:
4809 	default:
4810 		bad_error("fmri_to_entity", serr);
4811 	}
4812 
4813 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4814 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4815 	switch (r) {
4816 	case 0:
4817 		break;
4818 
4819 	case ECONNABORTED:
4820 		goto out;
4821 
4822 	case ECANCELED:
4823 	case ENOENT:
4824 		warn(cf_missing, ient->sc_fmri, ud_name);
4825 		r = 0;
4826 		goto out;
4827 
4828 	case EBADF:
4829 		warn(r_no_lvl, ud_ctarg);
4830 		goto out;
4831 
4832 	case EINVAL:
4833 	default:
4834 		bad_error("entity_get_running_pg", r);
4835 	}
4836 
4837 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4838 	switch (r) {
4839 	case 0:
4840 		break;
4841 
4842 	case ECANCELED:
4843 		warn(cf_missing, ient->sc_fmri, ud_name);
4844 		goto out;
4845 
4846 	case ECONNABORTED:
4847 	case ENOMEM:
4848 	case EBADF:
4849 		goto out;
4850 
4851 	case EACCES:
4852 	default:
4853 		bad_error("load_pg", r);
4854 	}
4855 
4856 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4857 		if (!pg_equal(current_pg, new_dpt_pgroup))
4858 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4859 		internal_pgroup_free(current_pg);
4860 		r = 0;
4861 		goto out;
4862 	}
4863 
4864 	/* Uncustomized.  Upgrade. */
4865 
4866 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4867 	switch (r) {
4868 	case 1:
4869 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4870 			/* Already upgraded. */
4871 			internal_pgroup_free(current_pg);
4872 			r = 0;
4873 			goto out;
4874 		}
4875 
4876 		internal_pgroup_free(current_pg);
4877 
4878 		/* upgrade current_pg */
4879 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4880 			switch (scf_error()) {
4881 			case SCF_ERROR_CONNECTION_BROKEN:
4882 				r = scferror2errno(scf_error());
4883 				goto out;
4884 
4885 			case SCF_ERROR_DELETED:
4886 				warn(cf_missing, ient->sc_fmri, ud_name);
4887 				r = 0;
4888 				goto out;
4889 
4890 			case SCF_ERROR_NOT_FOUND:
4891 				break;
4892 
4893 			case SCF_ERROR_INVALID_ARGUMENT:
4894 			case SCF_ERROR_NOT_BOUND:
4895 			case SCF_ERROR_NOT_SET:
4896 			case SCF_ERROR_HANDLE_MISMATCH:
4897 			default:
4898 				bad_error("entity_get_pg", scf_error());
4899 			}
4900 
4901 			if (tissvc)
4902 				r = scf_service_add_pg(target_ent, ud_name,
4903 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4904 			else
4905 				r = scf_instance_add_pg(target_ent, ud_name,
4906 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4907 			if (r != 0) {
4908 				switch (scf_error()) {
4909 				case SCF_ERROR_CONNECTION_BROKEN:
4910 				case SCF_ERROR_NO_RESOURCES:
4911 				case SCF_ERROR_BACKEND_READONLY:
4912 				case SCF_ERROR_BACKEND_ACCESS:
4913 					r = scferror2errno(scf_error());
4914 					goto out;
4915 
4916 				case SCF_ERROR_DELETED:
4917 					warn(cf_missing, ient->sc_fmri,
4918 					    ud_name);
4919 					r = 0;
4920 					goto out;
4921 
4922 				case SCF_ERROR_PERMISSION_DENIED:
4923 					warn(emsg_pg_deleted, ud_ctarg,
4924 					    ud_name);
4925 					r = EPERM;
4926 					goto out;
4927 
4928 				case SCF_ERROR_EXISTS:
4929 					warn(emsg_pg_added, ud_ctarg, ud_name);
4930 					r = EBUSY;
4931 					goto out;
4932 
4933 				case SCF_ERROR_NOT_BOUND:
4934 				case SCF_ERROR_HANDLE_MISMATCH:
4935 				case SCF_ERROR_INVALID_ARGUMENT:
4936 				case SCF_ERROR_NOT_SET:
4937 				default:
4938 					bad_error("entity_add_pg", scf_error());
4939 				}
4940 			}
4941 		}
4942 
4943 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4944 		switch (r) {
4945 		case 0:
4946 			break;
4947 
4948 		case ECANCELED:
4949 			warn(cf_missing, ient->sc_fmri, ud_name);
4950 			goto out;
4951 
4952 		case ECONNABORTED:
4953 		case ENOMEM:
4954 		case EBADF:
4955 			goto out;
4956 
4957 		case EACCES:
4958 		default:
4959 			bad_error("load_pg", r);
4960 		}
4961 
4962 		if (g_verbose)
4963 			warn(upgrading, ient->sc_fmri, ud_name);
4964 
4965 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4966 		    new_dpt_pgroup, 0, ient->sc_fmri);
4967 		switch (r) {
4968 		case 0:
4969 			break;
4970 
4971 		case ECANCELED:
4972 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4973 			r = EBUSY;
4974 			goto out;
4975 
4976 		case EPERM:
4977 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4978 			goto out;
4979 
4980 		case EBUSY:
4981 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4982 			goto out;
4983 
4984 		case ECONNABORTED:
4985 		case ENOMEM:
4986 		case ENOSPC:
4987 		case EROFS:
4988 		case EACCES:
4989 		case EINVAL:
4990 			goto out;
4991 
4992 		default:
4993 			bad_error("upgrade_pg", r);
4994 		}
4995 		break;
4996 
4997 	case 0: {
4998 		scf_transaction_entry_t *ent;
4999 		scf_value_t *val;
5000 
5001 		internal_pgroup_free(current_pg);
5002 
5003 		/* delete old pg */
5004 		if (g_verbose)
5005 			warn(upgrading, ient->sc_fmri, ud_name);
5006 
5007 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5008 			switch (scf_error()) {
5009 			case SCF_ERROR_CONNECTION_BROKEN:
5010 				r = scferror2errno(scf_error());
5011 				goto out;
5012 
5013 			case SCF_ERROR_DELETED:
5014 				warn(cf_missing, ient->sc_fmri, ud_name);
5015 				r = 0;
5016 				goto out;
5017 
5018 			case SCF_ERROR_NOT_FOUND:
5019 				break;
5020 
5021 			case SCF_ERROR_INVALID_ARGUMENT:
5022 			case SCF_ERROR_NOT_BOUND:
5023 			case SCF_ERROR_NOT_SET:
5024 			case SCF_ERROR_HANDLE_MISMATCH:
5025 			default:
5026 				bad_error("entity_get_pg", scf_error());
5027 			}
5028 		} else if (scf_pg_delete(ud_pg) != 0) {
5029 			switch (scf_error()) {
5030 			case SCF_ERROR_DELETED:
5031 				break;
5032 
5033 			case SCF_ERROR_CONNECTION_BROKEN:
5034 			case SCF_ERROR_BACKEND_READONLY:
5035 			case SCF_ERROR_BACKEND_ACCESS:
5036 				r = scferror2errno(scf_error());
5037 				goto out;
5038 
5039 			case SCF_ERROR_PERMISSION_DENIED:
5040 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5041 				r = scferror2errno(scf_error());
5042 				goto out;
5043 
5044 			case SCF_ERROR_NOT_SET:
5045 			default:
5046 				bad_error("scf_pg_delete", scf_error());
5047 			}
5048 		}
5049 
5050 		/* import new one */
5051 		cbdata.sc_handle = g_hndl;
5052 		cbdata.sc_trans = NULL;		/* handled below */
5053 		cbdata.sc_flags = 0;
5054 
5055 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5056 		if (r != UU_WALK_NEXT) {
5057 			if (r != UU_WALK_ERROR)
5058 				bad_error("lscf_dependent_import", r);
5059 
5060 			r = cbdata.sc_err;
5061 			goto out;
5062 		}
5063 
5064 		if (tx == NULL)
5065 			break;
5066 
5067 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5068 		    (val = scf_value_create(g_hndl)) == NULL) {
5069 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5070 				return (ENOMEM);
5071 
5072 			bad_error("scf_entry_create", scf_error());
5073 		}
5074 
5075 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5076 		    SCF_TYPE_FMRI) != 0) {
5077 			switch (scf_error()) {
5078 			case SCF_ERROR_CONNECTION_BROKEN:
5079 				r = scferror2errno(scf_error());
5080 				goto out;
5081 
5082 			case SCF_ERROR_DELETED:
5083 				warn(emsg_pg_deleted, ient->sc_fmri,
5084 				    "dependents");
5085 				r = EBUSY;
5086 				goto out;
5087 
5088 			case SCF_ERROR_NOT_FOUND:
5089 				break;
5090 
5091 			case SCF_ERROR_NOT_BOUND:
5092 			case SCF_ERROR_HANDLE_MISMATCH:
5093 			case SCF_ERROR_INVALID_ARGUMENT:
5094 			case SCF_ERROR_NOT_SET:
5095 			default:
5096 				bad_error("scf_transaction_property_"
5097 				    "change_type", scf_error());
5098 			}
5099 
5100 			if (scf_transaction_property_new(tx, ent, ud_name,
5101 			    SCF_TYPE_FMRI) != 0) {
5102 				switch (scf_error()) {
5103 				case SCF_ERROR_CONNECTION_BROKEN:
5104 					r = scferror2errno(scf_error());
5105 					goto out;
5106 
5107 				case SCF_ERROR_DELETED:
5108 					warn(emsg_pg_deleted, ient->sc_fmri,
5109 					    "dependents");
5110 					r = EBUSY;
5111 					goto out;
5112 
5113 				case SCF_ERROR_EXISTS:
5114 					warn(emsg_pg_changed, ient->sc_fmri,
5115 					    "dependents");
5116 					r = EBUSY;
5117 					goto out;
5118 
5119 				case SCF_ERROR_INVALID_ARGUMENT:
5120 				case SCF_ERROR_HANDLE_MISMATCH:
5121 				case SCF_ERROR_NOT_BOUND:
5122 				case SCF_ERROR_NOT_SET:
5123 				default:
5124 					bad_error("scf_transaction_property_"
5125 					    "new", scf_error());
5126 				}
5127 			}
5128 		}
5129 
5130 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5131 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5132 			/* invalid sc_pgroup_fmri caught above */
5133 			bad_error("scf_value_set_from_string",
5134 			    scf_error());
5135 
5136 		if (scf_entry_add_value(ent, val) != 0)
5137 			bad_error("scf_entry_add_value", scf_error());
5138 		break;
5139 	}
5140 
5141 	case -2:
5142 		warn(li_corrupt, ient->sc_fmri);
5143 		internal_pgroup_free(current_pg);
5144 		r = EBADF;
5145 		goto out;
5146 
5147 	case -1:
5148 	default:
5149 		/* invalid sc_pgroup_fmri caught above */
5150 		bad_error("fmri_equal", r);
5151 	}
5152 
5153 	r = 0;
5154 
5155 out:
5156 	if (old_dpt_pgroup != NULL)
5157 		internal_pgroup_free(old_dpt_pgroup);
5158 
5159 	return (r);
5160 }
5161 
5162 /*
5163  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5164  * would import it, except it seems to exist in the service anyway.  Compare
5165  * the existent dependent with the one we would import, and report any
5166  * differences (if there are none, be silent).  prop is the property which
5167  * represents the existent dependent (in the dependents property group) in the
5168  * entity corresponding to ient.
5169  *
5170  * Returns
5171  *   0 - success (Sort of.  At least, we can continue importing.)
5172  *   ECONNABORTED - repository connection broken
5173  *   EBUSY - ancestor of prop was deleted (error printed)
5174  *   ENOMEM - out of memory
5175  *   EBADF - corrupt property group (error printed)
5176  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5177  */
5178 static int
5179 handle_dependent_conflict(const entity_t * const ient,
5180     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5181 {
5182 	int r;
5183 	scf_type_t ty;
5184 	scf_error_t scfe;
5185 	void *tptr;
5186 	int tissvc;
5187 	pgroup_t *pgroup;
5188 
5189 	if (scf_property_get_value(prop, ud_val) != 0) {
5190 		switch (scf_error()) {
5191 		case SCF_ERROR_CONNECTION_BROKEN:
5192 			return (scferror2errno(scf_error()));
5193 
5194 		case SCF_ERROR_DELETED:
5195 			warn(emsg_pg_deleted, ient->sc_fmri,
5196 			    new_dpt_pgroup->sc_pgroup_name);
5197 			return (EBUSY);
5198 
5199 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5200 		case SCF_ERROR_NOT_FOUND:
5201 			warn(gettext("Conflict upgrading %s (not importing "
5202 			    "dependent \"%s\" because it already exists.)  "
5203 			    "Warning: The \"%s/%2$s\" property has more or "
5204 			    "fewer than one value)).\n"), ient->sc_fmri,
5205 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5206 			return (0);
5207 
5208 		case SCF_ERROR_HANDLE_MISMATCH:
5209 		case SCF_ERROR_NOT_BOUND:
5210 		case SCF_ERROR_NOT_SET:
5211 		case SCF_ERROR_PERMISSION_DENIED:
5212 		default:
5213 			bad_error("scf_property_get_value",
5214 			    scf_error());
5215 		}
5216 	}
5217 
5218 	ty = scf_value_type(ud_val);
5219 	assert(ty != SCF_TYPE_INVALID);
5220 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5221 		warn(gettext("Conflict upgrading %s (not importing dependent "
5222 		    "\"%s\" because it already exists).  Warning: The "
5223 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5224 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5225 		    scf_type_to_string(ty), "dependents");
5226 		return (0);
5227 	}
5228 
5229 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5230 	    0)
5231 		bad_error("scf_value_get_as_string", scf_error());
5232 
5233 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5234 	switch (r) {
5235 	case 0:
5236 		warn(gettext("Conflict upgrading %s (not importing dependent "
5237 		    "\"%s\" (target \"%s\") because it already exists with "
5238 		    "target \"%s\").\n"), ient->sc_fmri,
5239 		    new_dpt_pgroup->sc_pgroup_name,
5240 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5241 		return (0);
5242 
5243 	case 1:
5244 		break;
5245 
5246 	case -1:
5247 		warn(gettext("Conflict upgrading %s (not importing dependent "
5248 		    "\"%s\" because it already exists).  Warning: The current "
5249 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5250 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5251 		return (0);
5252 
5253 	case -2:
5254 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5255 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5256 		    new_dpt_pgroup->sc_pgroup_fmri);
5257 		return (EINVAL);
5258 
5259 	default:
5260 		bad_error("fmri_equal", r);
5261 	}
5262 
5263 	/* compare dependency pgs in target */
5264 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5265 	switch (scfe) {
5266 	case SCF_ERROR_NONE:
5267 		break;
5268 
5269 	case SCF_ERROR_NO_MEMORY:
5270 		return (ENOMEM);
5271 
5272 	case SCF_ERROR_NOT_FOUND:
5273 		warn(emsg_dpt_dangling, ient->sc_fmri,
5274 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5275 		return (0);
5276 
5277 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5278 	case SCF_ERROR_INVALID_ARGUMENT:
5279 	default:
5280 		bad_error("fmri_to_entity", scfe);
5281 	}
5282 
5283 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5284 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5285 	switch (r) {
5286 	case 0:
5287 		break;
5288 
5289 	case ECONNABORTED:
5290 		return (r);
5291 
5292 	case ECANCELED:
5293 		warn(emsg_dpt_dangling, ient->sc_fmri,
5294 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5295 		return (0);
5296 
5297 	case EBADF:
5298 		if (tissvc)
5299 			warn(gettext("%s has an instance with a \"%s\" "
5300 			    "snapshot which is missing a snaplevel.\n"),
5301 			    ud_ctarg, "running");
5302 		else
5303 			warn(gettext("%s has a \"%s\" snapshot which is "
5304 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5305 		/* FALLTHROUGH */
5306 
5307 	case ENOENT:
5308 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5309 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5310 		    new_dpt_pgroup->sc_pgroup_name);
5311 		return (0);
5312 
5313 	case EINVAL:
5314 	default:
5315 		bad_error("entity_get_running_pg", r);
5316 	}
5317 
5318 	pgroup = internal_pgroup_new();
5319 	if (pgroup == NULL)
5320 		return (ENOMEM);
5321 
5322 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5323 	switch (r) {
5324 	case 0:
5325 		break;
5326 
5327 	case ECONNABORTED:
5328 	case EBADF:
5329 	case ENOMEM:
5330 		internal_pgroup_free(pgroup);
5331 		return (r);
5332 
5333 	case ECANCELED:
5334 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5335 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5336 		    new_dpt_pgroup->sc_pgroup_name);
5337 		internal_pgroup_free(pgroup);
5338 		return (0);
5339 
5340 	case EACCES:
5341 	default:
5342 		bad_error("load_pg", r);
5343 	}
5344 
5345 	/* report differences */
5346 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5347 	internal_pgroup_free(pgroup);
5348 	return (0);
5349 }
5350 
5351 /*
5352  * lipg is a property group in the last-import snapshot of ent, which is an
5353  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5354  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5355  * in ents's property groups, compare and upgrade ent appropriately.
5356  *
5357  * Returns
5358  *   0 - success
5359  *   ECONNABORTED - repository connection broken
5360  *   ENOMEM - out of memory
5361  *   ENOSPC - configd is out of resources
5362  *   EINVAL - ient has invalid dependent (error printed)
5363  *	    - ient has invalid pgroup_t (error printed)
5364  *   ECANCELED - ent has been deleted
5365  *   ENODEV - entity containing lipg has been deleted
5366  *	    - entity containing running has been deleted
5367  *   EPERM - could not delete pg (permission denied) (error printed)
5368  *	   - couldn't upgrade dependents (permission denied) (error printed)
5369  *	   - couldn't import pg (permission denied) (error printed)
5370  *	   - couldn't upgrade pg (permission denied) (error printed)
5371  *   EROFS - could not delete pg (repository read-only)
5372  *	   - couldn't upgrade dependents (repository read-only)
5373  *	   - couldn't import pg (repository read-only)
5374  *	   - couldn't upgrade pg (repository read-only)
5375  *   EACCES - could not delete pg (backend access denied)
5376  *	    - couldn't upgrade dependents (backend access denied)
5377  *	    - couldn't import pg (backend access denied)
5378  *	    - couldn't upgrade pg (backend access denied)
5379  *	    - couldn't read property (backend access denied)
5380  *   EBUSY - property group was added (error printed)
5381  *	   - property group was deleted (error printed)
5382  *	   - property group changed (error printed)
5383  *	   - "dependents" pg was added, changed, or deleted (error printed)
5384  *	   - dependent target deleted (error printed)
5385  *	   - dependent pg changed (error printed)
5386  *   EBADF - imp_snpl is corrupt (error printed)
5387  *	   - ent has bad pg (error printed)
5388  *   EEXIST - dependent collision in target service (error printed)
5389  */
5390 static int
5391 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5392     const scf_snaplevel_t *running)
5393 {
5394 	int r;
5395 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5396 	scf_callback_t cbdata;
5397 
5398 	const char * const cf_pg_missing =
5399 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5400 	const char * const deleting =
5401 	    gettext("%s: Deleting property group \"%s\".\n");
5402 
5403 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5404 
5405 	/* Skip dependent property groups. */
5406 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5407 		switch (scf_error()) {
5408 		case SCF_ERROR_DELETED:
5409 			return (ENODEV);
5410 
5411 		case SCF_ERROR_CONNECTION_BROKEN:
5412 			return (ECONNABORTED);
5413 
5414 		case SCF_ERROR_NOT_SET:
5415 		case SCF_ERROR_NOT_BOUND:
5416 		default:
5417 			bad_error("scf_pg_get_type", scf_error());
5418 		}
5419 	}
5420 
5421 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5422 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5423 			return (0);
5424 
5425 		switch (scf_error()) {
5426 		case SCF_ERROR_NOT_FOUND:
5427 			break;
5428 
5429 		case SCF_ERROR_CONNECTION_BROKEN:
5430 			return (ECONNABORTED);
5431 
5432 		case SCF_ERROR_DELETED:
5433 			return (ENODEV);
5434 
5435 		case SCF_ERROR_INVALID_ARGUMENT:
5436 		case SCF_ERROR_NOT_BOUND:
5437 		case SCF_ERROR_HANDLE_MISMATCH:
5438 		case SCF_ERROR_NOT_SET:
5439 		default:
5440 			bad_error("scf_pg_get_property", scf_error());
5441 		}
5442 	}
5443 
5444 	/* lookup pg in new properties */
5445 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5446 		switch (scf_error()) {
5447 		case SCF_ERROR_DELETED:
5448 			return (ENODEV);
5449 
5450 		case SCF_ERROR_CONNECTION_BROKEN:
5451 			return (ECONNABORTED);
5452 
5453 		case SCF_ERROR_NOT_SET:
5454 		case SCF_ERROR_NOT_BOUND:
5455 		default:
5456 			bad_error("scf_pg_get_name", scf_error());
5457 		}
5458 	}
5459 
5460 	pgrp.sc_pgroup_name = imp_str;
5461 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5462 
5463 	if (mpg != NULL)
5464 		mpg->sc_pgroup_seen = 1;
5465 
5466 	/* Special handling for dependents */
5467 	if (strcmp(imp_str, "dependents") == 0)
5468 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5469 
5470 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5471 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5472 
5473 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5474 		/* property group was deleted from manifest */
5475 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5476 			switch (scf_error()) {
5477 			case SCF_ERROR_NOT_FOUND:
5478 				return (0);
5479 
5480 			case SCF_ERROR_DELETED:
5481 			case SCF_ERROR_CONNECTION_BROKEN:
5482 				return (scferror2errno(scf_error()));
5483 
5484 			case SCF_ERROR_INVALID_ARGUMENT:
5485 			case SCF_ERROR_HANDLE_MISMATCH:
5486 			case SCF_ERROR_NOT_BOUND:
5487 			case SCF_ERROR_NOT_SET:
5488 			default:
5489 				bad_error("entity_get_pg", scf_error());
5490 			}
5491 		}
5492 
5493 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5494 			if (g_verbose)
5495 				warn(deleting, ient->sc_fmri, imp_str);
5496 			if (scf_pg_delete(imp_pg2) == 0)
5497 				return (0);
5498 
5499 			switch (scf_error()) {
5500 			case SCF_ERROR_DELETED:
5501 				return (0);
5502 
5503 			case SCF_ERROR_CONNECTION_BROKEN:
5504 			case SCF_ERROR_BACKEND_READONLY:
5505 			case SCF_ERROR_BACKEND_ACCESS:
5506 				return (scferror2errno(scf_error()));
5507 
5508 			case SCF_ERROR_PERMISSION_DENIED:
5509 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5510 				return (scferror2errno(scf_error()));
5511 
5512 			case SCF_ERROR_NOT_SET:
5513 			default:
5514 				bad_error("scf_pg_delete", scf_error());
5515 			}
5516 		}
5517 
5518 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5519 		switch (r) {
5520 		case 0:
5521 			break;
5522 
5523 		case ECANCELED:
5524 			return (ENODEV);
5525 
5526 		case ECONNABORTED:
5527 		case ENOMEM:
5528 		case EBADF:
5529 		case EACCES:
5530 			return (r);
5531 
5532 		default:
5533 			bad_error("load_pg", r);
5534 		}
5535 
5536 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5537 		switch (r) {
5538 		case 0:
5539 			break;
5540 
5541 		case ECANCELED:
5542 		case ECONNABORTED:
5543 		case ENOMEM:
5544 		case EBADF:
5545 		case EACCES:
5546 			internal_pgroup_free(lipg_i);
5547 			return (r);
5548 
5549 		default:
5550 			bad_error("load_pg", r);
5551 		}
5552 
5553 		if (pg_equal(lipg_i, curpg_i)) {
5554 			if (g_verbose)
5555 				warn(deleting, ient->sc_fmri, imp_str);
5556 			if (scf_pg_delete(imp_pg2) != 0) {
5557 				switch (scf_error()) {
5558 				case SCF_ERROR_DELETED:
5559 					break;
5560 
5561 				case SCF_ERROR_CONNECTION_BROKEN:
5562 					internal_pgroup_free(lipg_i);
5563 					internal_pgroup_free(curpg_i);
5564 					return (ECONNABORTED);
5565 
5566 				case SCF_ERROR_NOT_SET:
5567 				case SCF_ERROR_NOT_BOUND:
5568 				default:
5569 					bad_error("scf_pg_delete", scf_error());
5570 				}
5571 			}
5572 		} else {
5573 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5574 		}
5575 
5576 		internal_pgroup_free(lipg_i);
5577 		internal_pgroup_free(curpg_i);
5578 
5579 		return (0);
5580 	}
5581 
5582 	/*
5583 	 * Only dependent pgs can have override set, and we skipped those
5584 	 * above.
5585 	 */
5586 	assert(!mpg->sc_pgroup_override);
5587 
5588 	/* compare */
5589 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5590 	switch (r) {
5591 	case 0:
5592 		break;
5593 
5594 	case ECANCELED:
5595 		return (ENODEV);
5596 
5597 	case ECONNABORTED:
5598 	case EBADF:
5599 	case ENOMEM:
5600 	case EACCES:
5601 		return (r);
5602 
5603 	default:
5604 		bad_error("load_pg", r);
5605 	}
5606 
5607 	if (pg_equal(mpg, lipg_i)) {
5608 		/* The manifest pg has not changed.  Move on. */
5609 		r = 0;
5610 		goto out;
5611 	}
5612 
5613 	/* upgrade current properties according to lipg & mpg */
5614 	if (running != NULL)
5615 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5616 	else
5617 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5618 	if (r != 0) {
5619 		switch (scf_error()) {
5620 		case SCF_ERROR_CONNECTION_BROKEN:
5621 			r = scferror2errno(scf_error());
5622 			goto out;
5623 
5624 		case SCF_ERROR_DELETED:
5625 			if (running != NULL)
5626 				r = ENODEV;
5627 			else
5628 				r = ECANCELED;
5629 			goto out;
5630 
5631 		case SCF_ERROR_NOT_FOUND:
5632 			break;
5633 
5634 		case SCF_ERROR_INVALID_ARGUMENT:
5635 		case SCF_ERROR_HANDLE_MISMATCH:
5636 		case SCF_ERROR_NOT_BOUND:
5637 		case SCF_ERROR_NOT_SET:
5638 		default:
5639 			bad_error("entity_get_pg", scf_error());
5640 		}
5641 
5642 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5643 
5644 		r = 0;
5645 		goto out;
5646 	}
5647 
5648 	r = load_pg_attrs(imp_pg2, &curpg_i);
5649 	switch (r) {
5650 	case 0:
5651 		break;
5652 
5653 	case ECANCELED:
5654 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5655 		r = 0;
5656 		goto out;
5657 
5658 	case ECONNABORTED:
5659 	case ENOMEM:
5660 		goto out;
5661 
5662 	default:
5663 		bad_error("load_pg_attrs", r);
5664 	}
5665 
5666 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5667 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5668 		internal_pgroup_free(curpg_i);
5669 		r = 0;
5670 		goto out;
5671 	}
5672 
5673 	internal_pgroup_free(curpg_i);
5674 
5675 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5676 	switch (r) {
5677 	case 0:
5678 		break;
5679 
5680 	case ECANCELED:
5681 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5682 		r = 0;
5683 		goto out;
5684 
5685 	case ECONNABORTED:
5686 	case EBADF:
5687 	case ENOMEM:
5688 	case EACCES:
5689 		goto out;
5690 
5691 	default:
5692 		bad_error("load_pg", r);
5693 	}
5694 
5695 	if (pg_equal(lipg_i, curpg_i) &&
5696 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5697 		int do_delete = 1;
5698 
5699 		if (g_verbose)
5700 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5701 			    ient->sc_fmri, mpg->sc_pgroup_name);
5702 
5703 		internal_pgroup_free(curpg_i);
5704 
5705 		if (running != NULL &&
5706 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5707 			switch (scf_error()) {
5708 			case SCF_ERROR_DELETED:
5709 				r = ECANCELED;
5710 				goto out;
5711 
5712 			case SCF_ERROR_NOT_FOUND:
5713 				do_delete = 0;
5714 				break;
5715 
5716 			case SCF_ERROR_CONNECTION_BROKEN:
5717 				r = scferror2errno(scf_error());
5718 				goto out;
5719 
5720 			case SCF_ERROR_HANDLE_MISMATCH:
5721 			case SCF_ERROR_INVALID_ARGUMENT:
5722 			case SCF_ERROR_NOT_SET:
5723 			case SCF_ERROR_NOT_BOUND:
5724 			default:
5725 				bad_error("entity_get_pg", scf_error());
5726 			}
5727 		}
5728 
5729 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5730 			switch (scf_error()) {
5731 			case SCF_ERROR_DELETED:
5732 				break;
5733 
5734 			case SCF_ERROR_CONNECTION_BROKEN:
5735 			case SCF_ERROR_BACKEND_READONLY:
5736 			case SCF_ERROR_BACKEND_ACCESS:
5737 				r = scferror2errno(scf_error());
5738 				goto out;
5739 
5740 			case SCF_ERROR_PERMISSION_DENIED:
5741 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5742 				    ient->sc_fmri);
5743 				r = scferror2errno(scf_error());
5744 				goto out;
5745 
5746 			case SCF_ERROR_NOT_SET:
5747 			case SCF_ERROR_NOT_BOUND:
5748 			default:
5749 				bad_error("scf_pg_delete", scf_error());
5750 			}
5751 		}
5752 
5753 		cbdata.sc_handle = g_hndl;
5754 		cbdata.sc_parent = ent;
5755 		cbdata.sc_service = issvc;
5756 		cbdata.sc_flags = 0;
5757 		cbdata.sc_source_fmri = ient->sc_fmri;
5758 		cbdata.sc_target_fmri = ient->sc_fmri;
5759 
5760 		r = entity_pgroup_import(mpg, &cbdata);
5761 		switch (r) {
5762 		case UU_WALK_NEXT:
5763 			r = 0;
5764 			goto out;
5765 
5766 		case UU_WALK_ERROR:
5767 			if (cbdata.sc_err == EEXIST) {
5768 				warn(emsg_pg_added, ient->sc_fmri,
5769 				    mpg->sc_pgroup_name);
5770 				r = EBUSY;
5771 			} else {
5772 				r = cbdata.sc_err;
5773 			}
5774 			goto out;
5775 
5776 		default:
5777 			bad_error("entity_pgroup_import", r);
5778 		}
5779 	}
5780 
5781 	if (running != NULL &&
5782 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5783 		switch (scf_error()) {
5784 		case SCF_ERROR_CONNECTION_BROKEN:
5785 		case SCF_ERROR_DELETED:
5786 			r = scferror2errno(scf_error());
5787 			goto out;
5788 
5789 		case SCF_ERROR_NOT_FOUND:
5790 			break;
5791 
5792 		case SCF_ERROR_HANDLE_MISMATCH:
5793 		case SCF_ERROR_INVALID_ARGUMENT:
5794 		case SCF_ERROR_NOT_SET:
5795 		case SCF_ERROR_NOT_BOUND:
5796 		default:
5797 			bad_error("entity_get_pg", scf_error());
5798 		}
5799 
5800 		cbdata.sc_handle = g_hndl;
5801 		cbdata.sc_parent = ent;
5802 		cbdata.sc_service = issvc;
5803 		cbdata.sc_flags = SCI_FORCE;
5804 		cbdata.sc_source_fmri = ient->sc_fmri;
5805 		cbdata.sc_target_fmri = ient->sc_fmri;
5806 
5807 		r = entity_pgroup_import(mpg, &cbdata);
5808 		switch (r) {
5809 		case UU_WALK_NEXT:
5810 			r = 0;
5811 			goto out;
5812 
5813 		case UU_WALK_ERROR:
5814 			if (cbdata.sc_err == EEXIST) {
5815 				warn(emsg_pg_added, ient->sc_fmri,
5816 				    mpg->sc_pgroup_name);
5817 				r = EBUSY;
5818 			} else {
5819 				r = cbdata.sc_err;
5820 			}
5821 			goto out;
5822 
5823 		default:
5824 			bad_error("entity_pgroup_import", r);
5825 		}
5826 	}
5827 
5828 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5829 	internal_pgroup_free(curpg_i);
5830 	switch (r) {
5831 	case 0:
5832 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5833 		break;
5834 
5835 	case ECANCELED:
5836 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5837 		r = EBUSY;
5838 		break;
5839 
5840 	case EPERM:
5841 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5842 		break;
5843 
5844 	case EBUSY:
5845 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5846 		break;
5847 
5848 	case ECONNABORTED:
5849 	case ENOMEM:
5850 	case ENOSPC:
5851 	case EROFS:
5852 	case EACCES:
5853 	case EINVAL:
5854 		break;
5855 
5856 	default:
5857 		bad_error("upgrade_pg", r);
5858 	}
5859 
5860 out:
5861 	internal_pgroup_free(lipg_i);
5862 	return (r);
5863 }
5864 
5865 /*
5866  * Upgrade the properties of ent according to snpl & ient.
5867  *
5868  * Returns
5869  *   0 - success
5870  *   ECONNABORTED - repository connection broken
5871  *   ENOMEM - out of memory
5872  *   ENOSPC - configd is out of resources
5873  *   ECANCELED - ent was deleted
5874  *   ENODEV - entity containing snpl was deleted
5875  *	    - entity containing running was deleted
5876  *   EBADF - imp_snpl is corrupt (error printed)
5877  *	   - ent has corrupt pg (error printed)
5878  *	   - dependent has corrupt pg (error printed)
5879  *	   - dependent target has a corrupt snapshot (error printed)
5880  *   EBUSY - pg was added, changed, or deleted (error printed)
5881  *	   - dependent target was deleted (error printed)
5882  *	   - dependent pg changed (error printed)
5883  *   EINVAL - invalid property group name (error printed)
5884  *	    - invalid property name (error printed)
5885  *	    - invalid value (error printed)
5886  *	    - ient has invalid pgroup or dependent (error printed)
5887  *   EPERM - could not create property group (permission denied) (error printed)
5888  *	   - could not modify property group (permission denied) (error printed)
5889  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5890  *   EROFS - could not create property group (repository read-only)
5891  *	   - couldn't delete, upgrade, or import pg or dependent
5892  *   EACCES - could not create property group (backend access denied)
5893  *	    - couldn't delete, upgrade, or import pg or dependent
5894  *   EEXIST - dependent collision in target service (error printed)
5895  */
5896 static int
5897 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5898     entity_t *ient)
5899 {
5900 	pgroup_t *pg, *rpg;
5901 	int r;
5902 	uu_list_t *pgs = ient->sc_pgroups;
5903 
5904 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5905 
5906 	/* clear sc_sceen for pgs */
5907 	if (uu_list_walk(pgs, clear_int,
5908 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5909 		bad_error("uu_list_walk", uu_error());
5910 
5911 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5912 		switch (scf_error()) {
5913 		case SCF_ERROR_DELETED:
5914 			return (ENODEV);
5915 
5916 		case SCF_ERROR_CONNECTION_BROKEN:
5917 			return (ECONNABORTED);
5918 
5919 		case SCF_ERROR_NOT_SET:
5920 		case SCF_ERROR_NOT_BOUND:
5921 		case SCF_ERROR_HANDLE_MISMATCH:
5922 		default:
5923 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5924 		}
5925 	}
5926 
5927 	for (;;) {
5928 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5929 		if (r == 0)
5930 			break;
5931 		if (r == 1) {
5932 			r = process_old_pg(imp_pg, ient, ent, running);
5933 			switch (r) {
5934 			case 0:
5935 				break;
5936 
5937 			case ECONNABORTED:
5938 			case ENOMEM:
5939 			case ENOSPC:
5940 			case ECANCELED:
5941 			case ENODEV:
5942 			case EPERM:
5943 			case EROFS:
5944 			case EACCES:
5945 			case EBADF:
5946 			case EBUSY:
5947 			case EINVAL:
5948 			case EEXIST:
5949 				return (r);
5950 
5951 			default:
5952 				bad_error("process_old_pg", r);
5953 			}
5954 			continue;
5955 		}
5956 		if (r != -1)
5957 			bad_error("scf_iter_next_pg", r);
5958 
5959 		switch (scf_error()) {
5960 		case SCF_ERROR_DELETED:
5961 			return (ENODEV);
5962 
5963 		case SCF_ERROR_CONNECTION_BROKEN:
5964 			return (ECONNABORTED);
5965 
5966 		case SCF_ERROR_HANDLE_MISMATCH:
5967 		case SCF_ERROR_NOT_BOUND:
5968 		case SCF_ERROR_NOT_SET:
5969 		case SCF_ERROR_INVALID_ARGUMENT:
5970 		default:
5971 			bad_error("scf_iter_next_pg", scf_error());
5972 		}
5973 	}
5974 
5975 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5976 		if (pg->sc_pgroup_seen)
5977 			continue;
5978 
5979 		/* pg is new */
5980 
5981 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5982 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5983 			    ent);
5984 			switch (r) {
5985 			case 0:
5986 				break;
5987 
5988 			case ECONNABORTED:
5989 			case ENOMEM:
5990 			case ENOSPC:
5991 			case ECANCELED:
5992 			case ENODEV:
5993 			case EBADF:
5994 			case EBUSY:
5995 			case EINVAL:
5996 			case EPERM:
5997 			case EROFS:
5998 			case EACCES:
5999 			case EEXIST:
6000 				return (r);
6001 
6002 			default:
6003 				bad_error("upgrade_dependents", r);
6004 			}
6005 			continue;
6006 		}
6007 
6008 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6009 			r = upgrade_manifestfiles(pg, ient, running, ent);
6010 			switch (r) {
6011 			case 0:
6012 				break;
6013 
6014 			case ECONNABORTED:
6015 			case ENOMEM:
6016 			case ENOSPC:
6017 			case ECANCELED:
6018 			case ENODEV:
6019 			case EBADF:
6020 			case EBUSY:
6021 			case EINVAL:
6022 			case EPERM:
6023 			case EROFS:
6024 			case EACCES:
6025 			case EEXIST:
6026 				return (r);
6027 
6028 			default:
6029 				bad_error("upgrade_manifestfiles", r);
6030 			}
6031 			continue;
6032 		}
6033 
6034 		if (running != NULL) {
6035 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6036 			    imp_pg);
6037 		} else {
6038 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6039 			    imp_pg);
6040 		}
6041 		if (r != 0) {
6042 			scf_callback_t cbdata;
6043 
6044 			switch (scf_error()) {
6045 			case SCF_ERROR_NOT_FOUND:
6046 				break;
6047 
6048 			case SCF_ERROR_CONNECTION_BROKEN:
6049 				return (scferror2errno(scf_error()));
6050 
6051 			case SCF_ERROR_DELETED:
6052 				if (running != NULL)
6053 					return (ENODEV);
6054 				else
6055 					return (scferror2errno(scf_error()));
6056 
6057 			case SCF_ERROR_INVALID_ARGUMENT:
6058 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6059 				    pg->sc_pgroup_name);
6060 				return (EINVAL);
6061 
6062 			case SCF_ERROR_NOT_SET:
6063 			case SCF_ERROR_HANDLE_MISMATCH:
6064 			case SCF_ERROR_NOT_BOUND:
6065 			default:
6066 				bad_error("entity_get_pg", scf_error());
6067 			}
6068 
6069 			/* User doesn't have pg, so import it. */
6070 
6071 			cbdata.sc_handle = g_hndl;
6072 			cbdata.sc_parent = ent;
6073 			cbdata.sc_service = issvc;
6074 			cbdata.sc_flags = SCI_FORCE;
6075 			cbdata.sc_source_fmri = ient->sc_fmri;
6076 			cbdata.sc_target_fmri = ient->sc_fmri;
6077 
6078 			r = entity_pgroup_import(pg, &cbdata);
6079 			switch (r) {
6080 			case UU_WALK_NEXT:
6081 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6082 				continue;
6083 
6084 			case UU_WALK_ERROR:
6085 				if (cbdata.sc_err == EEXIST) {
6086 					warn(emsg_pg_added, ient->sc_fmri,
6087 					    pg->sc_pgroup_name);
6088 					return (EBUSY);
6089 				}
6090 				return (cbdata.sc_err);
6091 
6092 			default:
6093 				bad_error("entity_pgroup_import", r);
6094 			}
6095 		}
6096 
6097 		/* report differences between pg & current */
6098 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6099 		switch (r) {
6100 		case 0:
6101 			break;
6102 
6103 		case ECANCELED:
6104 			warn(emsg_pg_deleted, ient->sc_fmri,
6105 			    pg->sc_pgroup_name);
6106 			return (EBUSY);
6107 
6108 		case ECONNABORTED:
6109 		case EBADF:
6110 		case ENOMEM:
6111 		case EACCES:
6112 			return (r);
6113 
6114 		default:
6115 			bad_error("load_pg", r);
6116 		}
6117 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6118 		internal_pgroup_free(rpg);
6119 		rpg = NULL;
6120 	}
6121 
6122 	return (0);
6123 }
6124 
6125 /*
6126  * Import an instance.  If it doesn't exist, create it.  If it has
6127  * a last-import snapshot, upgrade its properties.  Finish by updating its
6128  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6129  * could have been created for a dependent tag in another manifest.  Import the
6130  * new properties.  If there's a conflict, don't override, like now?
6131  *
6132  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6133  * lcbdata->sc_err to
6134  *   ECONNABORTED - repository connection broken
6135  *   ENOMEM - out of memory
6136  *   ENOSPC - svc.configd is out of resources
6137  *   EEXIST - dependency collision in dependent service (error printed)
6138  *   EPERM - couldn't create temporary instance (permission denied)
6139  *	   - couldn't import into temporary instance (permission denied)
6140  *	   - couldn't take snapshot (permission denied)
6141  *	   - couldn't upgrade properties (permission denied)
6142  *	   - couldn't import properties (permission denied)
6143  *	   - couldn't import dependents (permission denied)
6144  *   EROFS - couldn't create temporary instance (repository read-only)
6145  *	   - couldn't import into temporary instance (repository read-only)
6146  *	   - couldn't upgrade properties (repository read-only)
6147  *	   - couldn't import properties (repository read-only)
6148  *	   - couldn't import dependents (repository read-only)
6149  *   EACCES - couldn't create temporary instance (backend access denied)
6150  *	    - couldn't import into temporary instance (backend access denied)
6151  *	    - couldn't upgrade properties (backend access denied)
6152  *	    - couldn't import properties (backend access denied)
6153  *	    - couldn't import dependents (backend access denied)
6154  *   EINVAL - invalid instance name (error printed)
6155  *	    - invalid pgroup_t's (error printed)
6156  *	    - invalid dependents (error printed)
6157  *   EBUSY - temporary service deleted (error printed)
6158  *	   - temporary instance deleted (error printed)
6159  *	   - temporary instance changed (error printed)
6160  *	   - temporary instance already exists (error printed)
6161  *	   - instance deleted (error printed)
6162  *   EBADF - instance has corrupt last-import snapshot (error printed)
6163  *	   - instance is corrupt (error printed)
6164  *	   - dependent has corrupt pg (error printed)
6165  *	   - dependent target has a corrupt snapshot (error printed)
6166  *   -1 - unknown libscf error (error printed)
6167  */
6168 static int
6169 lscf_instance_import(void *v, void *pvt)
6170 {
6171 	entity_t *inst = v;
6172 	scf_callback_t ctx;
6173 	scf_callback_t *lcbdata = pvt;
6174 	scf_service_t *rsvc = lcbdata->sc_parent;
6175 	int r;
6176 	scf_snaplevel_t *running;
6177 	int flags = lcbdata->sc_flags;
6178 
6179 	const char * const emsg_tdel =
6180 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6181 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6182 	    "changed unexpectedly.\n");
6183 	const char * const emsg_del = gettext("%s changed unexpectedly "
6184 	    "(instance \"%s\" was deleted.)\n");
6185 	const char * const emsg_badsnap = gettext(
6186 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6187 
6188 	/*
6189 	 * prepare last-import snapshot:
6190 	 * create temporary instance (service was precreated)
6191 	 * populate with properties from bundle
6192 	 * take snapshot
6193 	 */
6194 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6195 		switch (scf_error()) {
6196 		case SCF_ERROR_CONNECTION_BROKEN:
6197 		case SCF_ERROR_NO_RESOURCES:
6198 		case SCF_ERROR_BACKEND_READONLY:
6199 		case SCF_ERROR_BACKEND_ACCESS:
6200 			return (stash_scferror(lcbdata));
6201 
6202 		case SCF_ERROR_EXISTS:
6203 			warn(gettext("Temporary service svc:/%s "
6204 			    "changed unexpectedly (instance \"%s\" added).\n"),
6205 			    imp_tsname, inst->sc_name);
6206 			lcbdata->sc_err = EBUSY;
6207 			return (UU_WALK_ERROR);
6208 
6209 		case SCF_ERROR_DELETED:
6210 			warn(gettext("Temporary service svc:/%s "
6211 			    "was deleted unexpectedly.\n"), imp_tsname);
6212 			lcbdata->sc_err = EBUSY;
6213 			return (UU_WALK_ERROR);
6214 
6215 		case SCF_ERROR_INVALID_ARGUMENT:
6216 			warn(gettext("Invalid instance name \"%s\".\n"),
6217 			    inst->sc_name);
6218 			return (stash_scferror(lcbdata));
6219 
6220 		case SCF_ERROR_PERMISSION_DENIED:
6221 			warn(gettext("Could not create temporary instance "
6222 			    "\"%s\" in svc:/%s (permission denied).\n"),
6223 			    inst->sc_name, imp_tsname);
6224 			return (stash_scferror(lcbdata));
6225 
6226 		case SCF_ERROR_HANDLE_MISMATCH:
6227 		case SCF_ERROR_NOT_BOUND:
6228 		case SCF_ERROR_NOT_SET:
6229 		default:
6230 			bad_error("scf_service_add_instance", scf_error());
6231 		}
6232 	}
6233 
6234 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6235 	    inst->sc_name);
6236 	if (r < 0)
6237 		bad_error("snprintf", errno);
6238 
6239 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6240 	    lcbdata->sc_flags | SCI_NOENABLED);
6241 	switch (r) {
6242 	case 0:
6243 		break;
6244 
6245 	case ECANCELED:
6246 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6247 		lcbdata->sc_err = EBUSY;
6248 		r = UU_WALK_ERROR;
6249 		goto deltemp;
6250 
6251 	case EEXIST:
6252 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6253 		lcbdata->sc_err = EBUSY;
6254 		r = UU_WALK_ERROR;
6255 		goto deltemp;
6256 
6257 	case ECONNABORTED:
6258 		goto connaborted;
6259 
6260 	case ENOMEM:
6261 	case ENOSPC:
6262 	case EPERM:
6263 	case EROFS:
6264 	case EACCES:
6265 	case EINVAL:
6266 	case EBUSY:
6267 		lcbdata->sc_err = r;
6268 		r = UU_WALK_ERROR;
6269 		goto deltemp;
6270 
6271 	default:
6272 		bad_error("lscf_import_instance_pgs", r);
6273 	}
6274 
6275 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6276 	    inst->sc_name);
6277 	if (r < 0)
6278 		bad_error("snprintf", errno);
6279 
6280 	ctx.sc_handle = lcbdata->sc_handle;
6281 	ctx.sc_parent = imp_tinst;
6282 	ctx.sc_service = 0;
6283 	ctx.sc_source_fmri = inst->sc_fmri;
6284 	ctx.sc_target_fmri = imp_str;
6285 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6286 	    UU_DEFAULT) != 0) {
6287 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6288 			bad_error("uu_list_walk", uu_error());
6289 
6290 		switch (ctx.sc_err) {
6291 		case ECONNABORTED:
6292 			goto connaborted;
6293 
6294 		case ECANCELED:
6295 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6296 			lcbdata->sc_err = EBUSY;
6297 			break;
6298 
6299 		case EEXIST:
6300 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6301 			lcbdata->sc_err = EBUSY;
6302 			break;
6303 
6304 		default:
6305 			lcbdata->sc_err = ctx.sc_err;
6306 		}
6307 		r = UU_WALK_ERROR;
6308 		goto deltemp;
6309 	}
6310 
6311 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6312 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6313 		switch (scf_error()) {
6314 		case SCF_ERROR_CONNECTION_BROKEN:
6315 			goto connaborted;
6316 
6317 		case SCF_ERROR_NO_RESOURCES:
6318 			r = stash_scferror(lcbdata);
6319 			goto deltemp;
6320 
6321 		case SCF_ERROR_EXISTS:
6322 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6323 			lcbdata->sc_err = EBUSY;
6324 			r = UU_WALK_ERROR;
6325 			goto deltemp;
6326 
6327 		case SCF_ERROR_PERMISSION_DENIED:
6328 			warn(gettext("Could not take \"%s\" snapshot of %s "
6329 			    "(permission denied).\n"), snap_lastimport,
6330 			    imp_str);
6331 			r = stash_scferror(lcbdata);
6332 			goto deltemp;
6333 
6334 		default:
6335 			scfwarn();
6336 			lcbdata->sc_err = -1;
6337 			r = UU_WALK_ERROR;
6338 			goto deltemp;
6339 
6340 		case SCF_ERROR_HANDLE_MISMATCH:
6341 		case SCF_ERROR_INVALID_ARGUMENT:
6342 		case SCF_ERROR_NOT_SET:
6343 			bad_error("_scf_snapshot_take_new_named", scf_error());
6344 		}
6345 	}
6346 
6347 	if (lcbdata->sc_flags & SCI_FRESH)
6348 		goto fresh;
6349 
6350 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6351 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6352 		    imp_lisnap) != 0) {
6353 			switch (scf_error()) {
6354 			case SCF_ERROR_DELETED:
6355 				warn(emsg_del, inst->sc_parent->sc_fmri,
6356 				    inst->sc_name);
6357 				lcbdata->sc_err = EBUSY;
6358 				r = UU_WALK_ERROR;
6359 				goto deltemp;
6360 
6361 			case SCF_ERROR_NOT_FOUND:
6362 				flags |= SCI_FORCE;
6363 				goto nosnap;
6364 
6365 			case SCF_ERROR_CONNECTION_BROKEN:
6366 				goto connaborted;
6367 
6368 			case SCF_ERROR_INVALID_ARGUMENT:
6369 			case SCF_ERROR_HANDLE_MISMATCH:
6370 			case SCF_ERROR_NOT_BOUND:
6371 			case SCF_ERROR_NOT_SET:
6372 			default:
6373 				bad_error("scf_instance_get_snapshot",
6374 				    scf_error());
6375 			}
6376 		}
6377 
6378 		/* upgrade */
6379 
6380 		/*
6381 		 * compare new properties with last-import properties
6382 		 * upgrade current properties
6383 		 */
6384 		/* clear sc_sceen for pgs */
6385 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6386 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6387 		    0)
6388 			bad_error("uu_list_walk", uu_error());
6389 
6390 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6391 		switch (r) {
6392 		case 0:
6393 			break;
6394 
6395 		case ECONNABORTED:
6396 			goto connaborted;
6397 
6398 		case ECANCELED:
6399 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6400 			lcbdata->sc_err = EBUSY;
6401 			r = UU_WALK_ERROR;
6402 			goto deltemp;
6403 
6404 		case ENOENT:
6405 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6406 			lcbdata->sc_err = EBADF;
6407 			r = UU_WALK_ERROR;
6408 			goto deltemp;
6409 
6410 		default:
6411 			bad_error("get_snaplevel", r);
6412 		}
6413 
6414 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6415 		    imp_rsnap) != 0) {
6416 			switch (scf_error()) {
6417 			case SCF_ERROR_DELETED:
6418 				warn(emsg_del, inst->sc_parent->sc_fmri,
6419 				    inst->sc_name);
6420 				lcbdata->sc_err = EBUSY;
6421 				r = UU_WALK_ERROR;
6422 				goto deltemp;
6423 
6424 			case SCF_ERROR_NOT_FOUND:
6425 				break;
6426 
6427 			case SCF_ERROR_CONNECTION_BROKEN:
6428 				goto connaborted;
6429 
6430 			case SCF_ERROR_INVALID_ARGUMENT:
6431 			case SCF_ERROR_HANDLE_MISMATCH:
6432 			case SCF_ERROR_NOT_BOUND:
6433 			case SCF_ERROR_NOT_SET:
6434 			default:
6435 				bad_error("scf_instance_get_snapshot",
6436 				    scf_error());
6437 			}
6438 
6439 			running = NULL;
6440 		} else {
6441 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6442 			switch (r) {
6443 			case 0:
6444 				running = imp_rsnpl;
6445 				break;
6446 
6447 			case ECONNABORTED:
6448 				goto connaborted;
6449 
6450 			case ECANCELED:
6451 				warn(emsg_del, inst->sc_parent->sc_fmri,
6452 				    inst->sc_name);
6453 				lcbdata->sc_err = EBUSY;
6454 				r = UU_WALK_ERROR;
6455 				goto deltemp;
6456 
6457 			case ENOENT:
6458 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6459 				lcbdata->sc_err = EBADF;
6460 				r = UU_WALK_ERROR;
6461 				goto deltemp;
6462 
6463 			default:
6464 				bad_error("get_snaplevel", r);
6465 			}
6466 		}
6467 
6468 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6469 		switch (r) {
6470 		case 0:
6471 			break;
6472 
6473 		case ECANCELED:
6474 		case ENODEV:
6475 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6476 			lcbdata->sc_err = EBUSY;
6477 			r = UU_WALK_ERROR;
6478 			goto deltemp;
6479 
6480 		case ECONNABORTED:
6481 			goto connaborted;
6482 
6483 		case ENOMEM:
6484 		case ENOSPC:
6485 		case EBADF:
6486 		case EBUSY:
6487 		case EINVAL:
6488 		case EPERM:
6489 		case EROFS:
6490 		case EACCES:
6491 		case EEXIST:
6492 			lcbdata->sc_err = r;
6493 			r = UU_WALK_ERROR;
6494 			goto deltemp;
6495 
6496 		default:
6497 			bad_error("upgrade_props", r);
6498 		}
6499 
6500 		inst->sc_import_state = IMPORT_PROP_DONE;
6501 	} else {
6502 		switch (scf_error()) {
6503 		case SCF_ERROR_CONNECTION_BROKEN:
6504 			goto connaborted;
6505 
6506 		case SCF_ERROR_NOT_FOUND:
6507 			break;
6508 
6509 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6510 		case SCF_ERROR_HANDLE_MISMATCH:
6511 		case SCF_ERROR_NOT_BOUND:
6512 		case SCF_ERROR_NOT_SET:
6513 		default:
6514 			bad_error("scf_service_get_instance", scf_error());
6515 		}
6516 
6517 fresh:
6518 		/* create instance */
6519 		if (scf_service_add_instance(rsvc, inst->sc_name,
6520 		    imp_inst) != 0) {
6521 			switch (scf_error()) {
6522 			case SCF_ERROR_CONNECTION_BROKEN:
6523 				goto connaborted;
6524 
6525 			case SCF_ERROR_NO_RESOURCES:
6526 			case SCF_ERROR_BACKEND_READONLY:
6527 			case SCF_ERROR_BACKEND_ACCESS:
6528 				r = stash_scferror(lcbdata);
6529 				goto deltemp;
6530 
6531 			case SCF_ERROR_EXISTS:
6532 				warn(gettext("%s changed unexpectedly "
6533 				    "(instance \"%s\" added).\n"),
6534 				    inst->sc_parent->sc_fmri, inst->sc_name);
6535 				lcbdata->sc_err = EBUSY;
6536 				r = UU_WALK_ERROR;
6537 				goto deltemp;
6538 
6539 			case SCF_ERROR_PERMISSION_DENIED:
6540 				warn(gettext("Could not create \"%s\" instance "
6541 				    "in %s (permission denied).\n"),
6542 				    inst->sc_name, inst->sc_parent->sc_fmri);
6543 				r = stash_scferror(lcbdata);
6544 				goto deltemp;
6545 
6546 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6547 			case SCF_ERROR_HANDLE_MISMATCH:
6548 			case SCF_ERROR_NOT_BOUND:
6549 			case SCF_ERROR_NOT_SET:
6550 			default:
6551 				bad_error("scf_service_add_instance",
6552 				    scf_error());
6553 			}
6554 		}
6555 
6556 nosnap:
6557 		/*
6558 		 * Create a last-import snapshot to serve as an attachment
6559 		 * point for the real one from the temporary instance.  Since
6560 		 * the contents is irrelevant, take it now, while the instance
6561 		 * is empty, to minimize svc.configd's work.
6562 		 */
6563 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6564 		    imp_lisnap) != 0) {
6565 			switch (scf_error()) {
6566 			case SCF_ERROR_CONNECTION_BROKEN:
6567 				goto connaborted;
6568 
6569 			case SCF_ERROR_NO_RESOURCES:
6570 				r = stash_scferror(lcbdata);
6571 				goto deltemp;
6572 
6573 			case SCF_ERROR_EXISTS:
6574 				warn(gettext("%s changed unexpectedly "
6575 				    "(snapshot \"%s\" added).\n"),
6576 				    inst->sc_fmri, snap_lastimport);
6577 				lcbdata->sc_err = EBUSY;
6578 				r = UU_WALK_ERROR;
6579 				goto deltemp;
6580 
6581 			case SCF_ERROR_PERMISSION_DENIED:
6582 				warn(gettext("Could not take \"%s\" snapshot "
6583 				    "of %s (permission denied).\n"),
6584 				    snap_lastimport, inst->sc_fmri);
6585 				r = stash_scferror(lcbdata);
6586 				goto deltemp;
6587 
6588 			default:
6589 				scfwarn();
6590 				lcbdata->sc_err = -1;
6591 				r = UU_WALK_ERROR;
6592 				goto deltemp;
6593 
6594 			case SCF_ERROR_NOT_SET:
6595 			case SCF_ERROR_INTERNAL:
6596 			case SCF_ERROR_INVALID_ARGUMENT:
6597 			case SCF_ERROR_HANDLE_MISMATCH:
6598 				bad_error("_scf_snapshot_take_new",
6599 				    scf_error());
6600 			}
6601 		}
6602 
6603 		if (li_only)
6604 			goto lionly;
6605 
6606 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6607 
6608 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6609 		    flags);
6610 		switch (r) {
6611 		case 0:
6612 			break;
6613 
6614 		case ECONNABORTED:
6615 			goto connaborted;
6616 
6617 		case ECANCELED:
6618 			warn(gettext("%s changed unexpectedly "
6619 			    "(instance \"%s\" deleted).\n"),
6620 			    inst->sc_parent->sc_fmri, inst->sc_name);
6621 			lcbdata->sc_err = EBUSY;
6622 			r = UU_WALK_ERROR;
6623 			goto deltemp;
6624 
6625 		case EEXIST:
6626 			warn(gettext("%s changed unexpectedly "
6627 			    "(property group added).\n"), inst->sc_fmri);
6628 			lcbdata->sc_err = EBUSY;
6629 			r = UU_WALK_ERROR;
6630 			goto deltemp;
6631 
6632 		default:
6633 			lcbdata->sc_err = r;
6634 			r = UU_WALK_ERROR;
6635 			goto deltemp;
6636 
6637 		case EINVAL:	/* caught above */
6638 			bad_error("lscf_import_instance_pgs", r);
6639 		}
6640 
6641 		ctx.sc_parent = imp_inst;
6642 		ctx.sc_service = 0;
6643 		ctx.sc_trans = NULL;
6644 		ctx.sc_flags = 0;
6645 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6646 		    &ctx, UU_DEFAULT) != 0) {
6647 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6648 				bad_error("uu_list_walk", uu_error());
6649 
6650 			if (ctx.sc_err == ECONNABORTED)
6651 				goto connaborted;
6652 			lcbdata->sc_err = ctx.sc_err;
6653 			r = UU_WALK_ERROR;
6654 			goto deltemp;
6655 		}
6656 
6657 		inst->sc_import_state = IMPORT_PROP_DONE;
6658 
6659 		if (g_verbose)
6660 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6661 			    snap_initial, inst->sc_fmri);
6662 		r = take_snap(imp_inst, snap_initial, imp_snap);
6663 		switch (r) {
6664 		case 0:
6665 			break;
6666 
6667 		case ECONNABORTED:
6668 			goto connaborted;
6669 
6670 		case ENOSPC:
6671 		case -1:
6672 			lcbdata->sc_err = r;
6673 			r = UU_WALK_ERROR;
6674 			goto deltemp;
6675 
6676 		case ECANCELED:
6677 			warn(gettext("%s changed unexpectedly "
6678 			    "(instance %s deleted).\n"),
6679 			    inst->sc_parent->sc_fmri, inst->sc_name);
6680 			lcbdata->sc_err = r;
6681 			r = UU_WALK_ERROR;
6682 			goto deltemp;
6683 
6684 		case EPERM:
6685 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6686 			lcbdata->sc_err = r;
6687 			r = UU_WALK_ERROR;
6688 			goto deltemp;
6689 
6690 		default:
6691 			bad_error("take_snap", r);
6692 		}
6693 	}
6694 
6695 lionly:
6696 	if (lcbdata->sc_flags & SCI_NOSNAP)
6697 		goto deltemp;
6698 
6699 	/* transfer snapshot from temporary instance */
6700 	if (g_verbose)
6701 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6702 		    snap_lastimport, inst->sc_fmri);
6703 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6704 		switch (scf_error()) {
6705 		case SCF_ERROR_CONNECTION_BROKEN:
6706 			goto connaborted;
6707 
6708 		case SCF_ERROR_NO_RESOURCES:
6709 			r = stash_scferror(lcbdata);
6710 			goto deltemp;
6711 
6712 		case SCF_ERROR_PERMISSION_DENIED:
6713 			warn(gettext("Could not take \"%s\" snapshot for %s "
6714 			    "(permission denied).\n"), snap_lastimport,
6715 			    inst->sc_fmri);
6716 			r = stash_scferror(lcbdata);
6717 			goto deltemp;
6718 
6719 		case SCF_ERROR_NOT_SET:
6720 		case SCF_ERROR_HANDLE_MISMATCH:
6721 		default:
6722 			bad_error("_scf_snapshot_attach", scf_error());
6723 		}
6724 	}
6725 
6726 	inst->sc_import_state = IMPORT_COMPLETE;
6727 
6728 	r = UU_WALK_NEXT;
6729 
6730 deltemp:
6731 	/* delete temporary instance */
6732 	if (scf_instance_delete(imp_tinst) != 0) {
6733 		switch (scf_error()) {
6734 		case SCF_ERROR_DELETED:
6735 			break;
6736 
6737 		case SCF_ERROR_CONNECTION_BROKEN:
6738 			goto connaborted;
6739 
6740 		case SCF_ERROR_NOT_SET:
6741 		case SCF_ERROR_NOT_BOUND:
6742 		default:
6743 			bad_error("scf_instance_delete", scf_error());
6744 		}
6745 	}
6746 
6747 	return (r);
6748 
6749 connaborted:
6750 	warn(gettext("Could not delete svc:/%s:%s "
6751 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6752 	lcbdata->sc_err = ECONNABORTED;
6753 	return (UU_WALK_ERROR);
6754 }
6755 
6756 /*
6757  * When an instance is imported we end up telling configd about it. Once we tell
6758  * configd about these changes, startd eventually notices. If this is a new
6759  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6760  * property group. However, many of the other tools expect that this property
6761  * group exists and has certain values.
6762  *
6763  * These values are added asynchronously by startd. We should not return from
6764  * this routine until we can verify that the property group we need is there.
6765  *
6766  * Before we go ahead and verify this, we have to ask ourselves an important
6767  * question: Is the early manifest service currently running?  Because if it is
6768  * running and it has invoked us, then the service will never get a restarter
6769  * property because svc.startd is blocked on EMI finishing before it lets itself
6770  * fully connect to svc.configd. Of course, this means that this race condition
6771  * is in fact impossible to 100% eliminate.
6772  *
6773  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6774  * the state of the EMI instance. If it is online it bails out and makes sure
6775  * that it doesn't run again. In this case, we're going to do something similar,
6776  * only if the state is online, then we're going to actually verify. EMI always
6777  * has to be present, but it can be explicitly disabled to reduce the amount of
6778  * damage it can cause. If EMI has been disabled then we no longer have to worry
6779  * about the implicit race condition and can go ahead and check things. If EMI
6780  * is in some state that isn't online or disabled and isn't runinng, then we
6781  * assume that things are rather bad and we're not going to get in your way,
6782  * even if the rest of SMF does.
6783  *
6784  * Returns 0 on success or returns an errno.
6785  */
6786 #ifndef NATIVE_BUILD
6787 static int
6788 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6789 {
6790 	int ret, err;
6791 	struct timespec ts;
6792 	char *emi_state;
6793 
6794 	/*
6795 	 * smf_get_state does not distinguish between its different failure
6796 	 * modes: memory allocation failures, SMF internal failures, and a lack
6797 	 * of EMI entirely because it's been removed. In these cases, we're
6798 	 * going to be conservative and opt to say that if we don't know, better
6799 	 * to not block import or falsely warn to the user.
6800 	 */
6801 	if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6802 		return (0);
6803 	}
6804 
6805 	/*
6806 	 * As per the block comment for this function check the state of EMI
6807 	 */
6808 	if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6809 	    strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6810 		warn(gettext("Not validating instance %s:%s because EMI's "
6811 		    "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6812 		free(emi_state);
6813 		return (0);
6814 	}
6815 
6816 	free(emi_state);
6817 
6818 	/*
6819 	 * First we have to get the property.
6820 	 */
6821 	if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6822 		ret = scf_error();
6823 		warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6824 		return (ret);
6825 	}
6826 
6827 	/*
6828 	 * We should always be able to get the instance. It should already
6829 	 * exist because we just created it or got it. There probably is a
6830 	 * slim chance that someone may have come in and deleted it though from
6831 	 * under us.
6832 	 */
6833 	if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6834 	    != 0) {
6835 		ret = scf_error();
6836 		warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6837 		switch (ret) {
6838 		case SCF_ERROR_DELETED:
6839 			err = ENODEV;
6840 			break;
6841 		case SCF_ERROR_CONNECTION_BROKEN:
6842 			warn(gettext("Lost repository connection\n"));
6843 			err = ECONNABORTED;
6844 			break;
6845 		case SCF_ERROR_NOT_FOUND:
6846 			warn(gettext("Instance \"%s\" disappeared out from "
6847 			    "under us.\n"), inst->sc_name);
6848 			err = ENOENT;
6849 			break;
6850 		default:
6851 			bad_error("scf_service_get_instance", ret);
6852 		}
6853 
6854 		return (err);
6855 	}
6856 
6857 	/*
6858 	 * An astute observer may want to use _scf_wait_pg which would notify us
6859 	 * of a property group change, unfortunately that does not work if the
6860 	 * property group in question does not exist. So instead we have to
6861 	 * manually poll and ask smf the best way to get to it.
6862 	 */
6863 	while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6864 	    != SCF_SUCCESS) {
6865 		ret = scf_error();
6866 		if (ret != SCF_ERROR_NOT_FOUND) {
6867 			warn(gettext("Failed to get restarter property "
6868 			    "group for instance: %s\n"), inst->sc_name);
6869 			switch (ret) {
6870 			case SCF_ERROR_DELETED:
6871 				err = ENODEV;
6872 				break;
6873 			case SCF_ERROR_CONNECTION_BROKEN:
6874 				warn(gettext("Lost repository connection\n"));
6875 				err = ECONNABORTED;
6876 				break;
6877 			default:
6878 				bad_error("scf_service_get_instance", ret);
6879 			}
6880 
6881 			return (err);
6882 		}
6883 
6884 		ts.tv_sec = pg_timeout / NANOSEC;
6885 		ts.tv_nsec = pg_timeout % NANOSEC;
6886 
6887 		(void) nanosleep(&ts, NULL);
6888 	}
6889 
6890 	/*
6891 	 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6892 	 * So in addition to the property group being present, we need to wait
6893 	 * for the property to be there in some form.
6894 	 *
6895 	 * Note that a property group is a frozen snapshot in time. To properly
6896 	 * get beyond this, you have to refresh the property group each time.
6897 	 */
6898 	while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6899 	    imp_prop)) != 0) {
6900 
6901 		ret = scf_error();
6902 		if (ret != SCF_ERROR_NOT_FOUND) {
6903 			warn(gettext("Failed to get property %s from the "
6904 			    "restarter property group of instance %s\n"),
6905 			    SCF_PROPERTY_STATE, inst->sc_name);
6906 			switch (ret) {
6907 			case SCF_ERROR_CONNECTION_BROKEN:
6908 				warn(gettext("Lost repository connection\n"));
6909 				err = ECONNABORTED;
6910 				break;
6911 			case SCF_ERROR_DELETED:
6912 				err = ENODEV;
6913 				break;
6914 			default:
6915 				bad_error("scf_pg_get_property", ret);
6916 			}
6917 
6918 			return (err);
6919 		}
6920 
6921 		ts.tv_sec = pg_timeout / NANOSEC;
6922 		ts.tv_nsec = pg_timeout % NANOSEC;
6923 
6924 		(void) nanosleep(&ts, NULL);
6925 
6926 		ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6927 		if (ret != SCF_SUCCESS) {
6928 			warn(gettext("Failed to get restarter property "
6929 			    "group for instance: %s\n"), inst->sc_name);
6930 			switch (ret) {
6931 			case SCF_ERROR_DELETED:
6932 				err = ENODEV;
6933 				break;
6934 			case SCF_ERROR_CONNECTION_BROKEN:
6935 				warn(gettext("Lost repository connection\n"));
6936 				err = ECONNABORTED;
6937 				break;
6938 			default:
6939 				bad_error("scf_service_get_instance", ret);
6940 			}
6941 
6942 			return (err);
6943 		}
6944 	}
6945 
6946 	/*
6947 	 * We don't have to free the property groups or other values that we got
6948 	 * because we stored them in global variables that are allocated and
6949 	 * freed by the routines that call into these functions. Unless of
6950 	 * course the rest of the code here that we are basing this on is
6951 	 * mistaken.
6952 	 */
6953 	return (0);
6954 }
6955 #endif
6956 
6957 /*
6958  * If the service is missing, create it, import its properties, and import the
6959  * instances.  Since the service is brand new, it should be empty, and if we
6960  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6961  *
6962  * If the service exists, we want to upgrade its properties and import the
6963  * instances.  Upgrade requires a last-import snapshot, though, which are
6964  * children of instances, so first we'll have to go through the instances
6965  * looking for a last-import snapshot.  If we don't find one then we'll just
6966  * override-import the service properties (but don't delete existing
6967  * properties: another service might have declared us as a dependent).  Before
6968  * we change anything, though, we want to take the previous snapshots.  We
6969  * also give lscf_instance_import() a leg up on taking last-import snapshots
6970  * by importing the manifest's service properties into a temporary service.
6971  *
6972  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6973  * sets lcbdata->sc_err to
6974  *   ECONNABORTED - repository connection broken
6975  *   ENOMEM - out of memory
6976  *   ENOSPC - svc.configd is out of resources
6977  *   EPERM - couldn't create temporary service (error printed)
6978  *	   - couldn't import into temp service (error printed)
6979  *	   - couldn't create service (error printed)
6980  *	   - couldn't import dependent (error printed)
6981  *	   - couldn't take snapshot (error printed)
6982  *	   - couldn't create instance (error printed)
6983  *	   - couldn't create, modify, or delete pg (error printed)
6984  *	   - couldn't create, modify, or delete dependent (error printed)
6985  *	   - couldn't import instance (error printed)
6986  *   EROFS - couldn't create temporary service (repository read-only)
6987  *	   - couldn't import into temporary service (repository read-only)
6988  *	   - couldn't create service (repository read-only)
6989  *	   - couldn't import dependent (repository read-only)
6990  *	   - couldn't create instance (repository read-only)
6991  *	   - couldn't create, modify, or delete pg or dependent
6992  *	   - couldn't import instance (repository read-only)
6993  *   EACCES - couldn't create temporary service (backend access denied)
6994  *	    - couldn't import into temporary service (backend access denied)
6995  *	    - couldn't create service (backend access denied)
6996  *	    - couldn't import dependent (backend access denied)
6997  *	    - couldn't create instance (backend access denied)
6998  *	    - couldn't create, modify, or delete pg or dependent
6999  *	    - couldn't import instance (backend access denied)
7000  *   EINVAL - service name is invalid (error printed)
7001  *	    - service name is too long (error printed)
7002  *	    - s has invalid pgroup (error printed)
7003  *	    - s has invalid dependent (error printed)
7004  *	    - instance name is invalid (error printed)
7005  *	    - instance entity_t is invalid (error printed)
7006  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7007  *	    - couldn't import dependent (dependency pg already exists) (printed)
7008  *	    - dependency collision in dependent service (error printed)
7009  *   EBUSY - temporary service deleted (error printed)
7010  *	   - property group added to temporary service (error printed)
7011  *	   - new property group changed or was deleted (error printed)
7012  *	   - service was added unexpectedly (error printed)
7013  *	   - service was deleted unexpectedly (error printed)
7014  *	   - property group added to new service (error printed)
7015  *	   - instance added unexpectedly (error printed)
7016  *	   - instance deleted unexpectedly (error printed)
7017  *	   - dependent service deleted unexpectedly (error printed)
7018  *	   - pg was added, changed, or deleted (error printed)
7019  *	   - dependent pg changed (error printed)
7020  *	   - temporary instance added, changed, or deleted (error printed)
7021  *   EBADF - a last-import snapshot is corrupt (error printed)
7022  *	   - the service is corrupt (error printed)
7023  *	   - a dependent is corrupt (error printed)
7024  *	   - an instance is corrupt (error printed)
7025  *	   - an instance has a corrupt last-import snapshot (error printed)
7026  *	   - dependent target has a corrupt snapshot (error printed)
7027  *   -1 - unknown libscf error (error printed)
7028  */
7029 static int
7030 lscf_service_import(void *v, void *pvt)
7031 {
7032 	entity_t *s = v;
7033 	scf_callback_t cbdata;
7034 	scf_callback_t *lcbdata = pvt;
7035 	scf_scope_t *scope = lcbdata->sc_parent;
7036 	entity_t *inst, linst;
7037 	int r;
7038 	int fresh = 0;
7039 	scf_snaplevel_t *running;
7040 	int have_ge = 0;
7041 	boolean_t retried = B_FALSE;
7042 
7043 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
7044 	    "was deleted unexpectedly.\n");
7045 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7046 	    "changed unexpectedly (property group added).\n");
7047 	const char * const s_deleted =
7048 	    gettext("%s was deleted unexpectedly.\n");
7049 	const char * const i_deleted =
7050 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7051 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7052 	    "is corrupt (missing service snaplevel).\n");
7053 	const char * const s_mfile_upd =
7054 	    gettext("Unable to update the manifest file connection "
7055 	    "for %s\n");
7056 
7057 	li_only = 0;
7058 	/* Validate the service name */
7059 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7060 		switch (scf_error()) {
7061 		case SCF_ERROR_CONNECTION_BROKEN:
7062 			return (stash_scferror(lcbdata));
7063 
7064 		case SCF_ERROR_INVALID_ARGUMENT:
7065 			warn(gettext("\"%s\" is an invalid service name.  "
7066 			    "Cannot import.\n"), s->sc_name);
7067 			return (stash_scferror(lcbdata));
7068 
7069 		case SCF_ERROR_NOT_FOUND:
7070 			break;
7071 
7072 		case SCF_ERROR_HANDLE_MISMATCH:
7073 		case SCF_ERROR_NOT_BOUND:
7074 		case SCF_ERROR_NOT_SET:
7075 		default:
7076 			bad_error("scf_scope_get_service", scf_error());
7077 		}
7078 	}
7079 
7080 	/* create temporary service */
7081 	/*
7082 	 * the size of the buffer was reduced to max_scf_name_len to prevent
7083 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
7084 	 * should be restored to its original value (max_scf_name_len +1)
7085 	 */
7086 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7087 	if (r < 0)
7088 		bad_error("snprintf", errno);
7089 	if (r > max_scf_name_len) {
7090 		warn(gettext(
7091 		    "Service name \"%s\" is too long.  Cannot import.\n"),
7092 		    s->sc_name);
7093 		lcbdata->sc_err = EINVAL;
7094 		return (UU_WALK_ERROR);
7095 	}
7096 
7097 retry:
7098 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7099 		switch (scf_error()) {
7100 		case SCF_ERROR_CONNECTION_BROKEN:
7101 		case SCF_ERROR_NO_RESOURCES:
7102 		case SCF_ERROR_BACKEND_READONLY:
7103 		case SCF_ERROR_BACKEND_ACCESS:
7104 			return (stash_scferror(lcbdata));
7105 
7106 		case SCF_ERROR_EXISTS:
7107 			if (!retried) {
7108 				lscf_delete(imp_tsname, 0);
7109 				retried = B_TRUE;
7110 				goto retry;
7111 			}
7112 			warn(gettext(
7113 			    "Temporary service \"%s\" must be deleted before "
7114 			    "this manifest can be imported.\n"), imp_tsname);
7115 			return (stash_scferror(lcbdata));
7116 
7117 		case SCF_ERROR_PERMISSION_DENIED:
7118 			warn(gettext("Could not create temporary service "
7119 			    "\"%s\" (permission denied).\n"), imp_tsname);
7120 			return (stash_scferror(lcbdata));
7121 
7122 		case SCF_ERROR_INVALID_ARGUMENT:
7123 		case SCF_ERROR_HANDLE_MISMATCH:
7124 		case SCF_ERROR_NOT_BOUND:
7125 		case SCF_ERROR_NOT_SET:
7126 		default:
7127 			bad_error("scf_scope_add_service", scf_error());
7128 		}
7129 	}
7130 
7131 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7132 	if (r < 0)
7133 		bad_error("snprintf", errno);
7134 
7135 	cbdata.sc_handle = lcbdata->sc_handle;
7136 	cbdata.sc_parent = imp_tsvc;
7137 	cbdata.sc_service = 1;
7138 	cbdata.sc_source_fmri = s->sc_fmri;
7139 	cbdata.sc_target_fmri = imp_str;
7140 	cbdata.sc_flags = 0;
7141 
7142 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7143 	    UU_DEFAULT) != 0) {
7144 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7145 			bad_error("uu_list_walk", uu_error());
7146 
7147 		lcbdata->sc_err = cbdata.sc_err;
7148 		switch (cbdata.sc_err) {
7149 		case ECONNABORTED:
7150 			goto connaborted;
7151 
7152 		case ECANCELED:
7153 			warn(ts_deleted, imp_tsname);
7154 			lcbdata->sc_err = EBUSY;
7155 			return (UU_WALK_ERROR);
7156 
7157 		case EEXIST:
7158 			warn(ts_pg_added, imp_tsname);
7159 			lcbdata->sc_err = EBUSY;
7160 			return (UU_WALK_ERROR);
7161 		}
7162 
7163 		r = UU_WALK_ERROR;
7164 		goto deltemp;
7165 	}
7166 
7167 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7168 	    UU_DEFAULT) != 0) {
7169 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7170 			bad_error("uu_list_walk", uu_error());
7171 
7172 		lcbdata->sc_err = cbdata.sc_err;
7173 		switch (cbdata.sc_err) {
7174 		case ECONNABORTED:
7175 			goto connaborted;
7176 
7177 		case ECANCELED:
7178 			warn(ts_deleted, imp_tsname);
7179 			lcbdata->sc_err = EBUSY;
7180 			return (UU_WALK_ERROR);
7181 
7182 		case EEXIST:
7183 			warn(ts_pg_added, imp_tsname);
7184 			lcbdata->sc_err = EBUSY;
7185 			return (UU_WALK_ERROR);
7186 		}
7187 
7188 		r = UU_WALK_ERROR;
7189 		goto deltemp;
7190 	}
7191 
7192 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7193 		switch (scf_error()) {
7194 		case SCF_ERROR_NOT_FOUND:
7195 			break;
7196 
7197 		case SCF_ERROR_CONNECTION_BROKEN:
7198 			goto connaborted;
7199 
7200 		case SCF_ERROR_INVALID_ARGUMENT:
7201 		case SCF_ERROR_HANDLE_MISMATCH:
7202 		case SCF_ERROR_NOT_BOUND:
7203 		case SCF_ERROR_NOT_SET:
7204 		default:
7205 			bad_error("scf_scope_get_service", scf_error());
7206 		}
7207 
7208 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7209 			switch (scf_error()) {
7210 			case SCF_ERROR_CONNECTION_BROKEN:
7211 				goto connaborted;
7212 
7213 			case SCF_ERROR_NO_RESOURCES:
7214 			case SCF_ERROR_BACKEND_READONLY:
7215 			case SCF_ERROR_BACKEND_ACCESS:
7216 				r = stash_scferror(lcbdata);
7217 				goto deltemp;
7218 
7219 			case SCF_ERROR_EXISTS:
7220 				warn(gettext("Scope \"%s\" changed unexpectedly"
7221 				    " (service \"%s\" added).\n"),
7222 				    SCF_SCOPE_LOCAL, s->sc_name);
7223 				lcbdata->sc_err = EBUSY;
7224 				goto deltemp;
7225 
7226 			case SCF_ERROR_PERMISSION_DENIED:
7227 				warn(gettext("Could not create service \"%s\" "
7228 				    "(permission denied).\n"), s->sc_name);
7229 				goto deltemp;
7230 
7231 			case SCF_ERROR_INVALID_ARGUMENT:
7232 			case SCF_ERROR_HANDLE_MISMATCH:
7233 			case SCF_ERROR_NOT_BOUND:
7234 			case SCF_ERROR_NOT_SET:
7235 			default:
7236 				bad_error("scf_scope_add_service", scf_error());
7237 			}
7238 		}
7239 
7240 		s->sc_import_state = IMPORT_PROP_BEGUN;
7241 
7242 		/* import service properties */
7243 		cbdata.sc_handle = lcbdata->sc_handle;
7244 		cbdata.sc_parent = imp_svc;
7245 		cbdata.sc_service = 1;
7246 		cbdata.sc_flags = lcbdata->sc_flags;
7247 		cbdata.sc_source_fmri = s->sc_fmri;
7248 		cbdata.sc_target_fmri = s->sc_fmri;
7249 
7250 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7251 		    &cbdata, UU_DEFAULT) != 0) {
7252 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7253 				bad_error("uu_list_walk", uu_error());
7254 
7255 			lcbdata->sc_err = cbdata.sc_err;
7256 			switch (cbdata.sc_err) {
7257 			case ECONNABORTED:
7258 				goto connaborted;
7259 
7260 			case ECANCELED:
7261 				warn(s_deleted, s->sc_fmri);
7262 				lcbdata->sc_err = EBUSY;
7263 				return (UU_WALK_ERROR);
7264 
7265 			case EEXIST:
7266 				warn(gettext("%s changed unexpectedly "
7267 				    "(property group added).\n"), s->sc_fmri);
7268 				lcbdata->sc_err = EBUSY;
7269 				return (UU_WALK_ERROR);
7270 
7271 			case EINVAL:
7272 				/* caught above */
7273 				bad_error("entity_pgroup_import",
7274 				    cbdata.sc_err);
7275 			}
7276 
7277 			r = UU_WALK_ERROR;
7278 			goto deltemp;
7279 		}
7280 
7281 		cbdata.sc_trans = NULL;
7282 		cbdata.sc_flags = 0;
7283 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7284 		    &cbdata, UU_DEFAULT) != 0) {
7285 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7286 				bad_error("uu_list_walk", uu_error());
7287 
7288 			lcbdata->sc_err = cbdata.sc_err;
7289 			if (cbdata.sc_err == ECONNABORTED)
7290 				goto connaborted;
7291 			r = UU_WALK_ERROR;
7292 			goto deltemp;
7293 		}
7294 
7295 		s->sc_import_state = IMPORT_PROP_DONE;
7296 
7297 		/*
7298 		 * This is a new service, so we can't take previous snapshots
7299 		 * or upgrade service properties.
7300 		 */
7301 		fresh = 1;
7302 		goto instances;
7303 	}
7304 
7305 	/* Clear sc_seen for the instances. */
7306 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7307 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7308 		bad_error("uu_list_walk", uu_error());
7309 
7310 	/*
7311 	 * Take previous snapshots for all instances.  Even for ones not
7312 	 * mentioned in the bundle, since we might change their service
7313 	 * properties.
7314 	 */
7315 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7316 		switch (scf_error()) {
7317 		case SCF_ERROR_CONNECTION_BROKEN:
7318 			goto connaborted;
7319 
7320 		case SCF_ERROR_DELETED:
7321 			warn(s_deleted, s->sc_fmri);
7322 			lcbdata->sc_err = EBUSY;
7323 			r = UU_WALK_ERROR;
7324 			goto deltemp;
7325 
7326 		case SCF_ERROR_HANDLE_MISMATCH:
7327 		case SCF_ERROR_NOT_BOUND:
7328 		case SCF_ERROR_NOT_SET:
7329 		default:
7330 			bad_error("scf_iter_service_instances", scf_error());
7331 		}
7332 	}
7333 
7334 	for (;;) {
7335 		r = scf_iter_next_instance(imp_iter, imp_inst);
7336 		if (r == 0)
7337 			break;
7338 		if (r != 1) {
7339 			switch (scf_error()) {
7340 			case SCF_ERROR_DELETED:
7341 				warn(s_deleted, s->sc_fmri);
7342 				lcbdata->sc_err = EBUSY;
7343 				r = UU_WALK_ERROR;
7344 				goto deltemp;
7345 
7346 			case SCF_ERROR_CONNECTION_BROKEN:
7347 				goto connaborted;
7348 
7349 			case SCF_ERROR_NOT_BOUND:
7350 			case SCF_ERROR_HANDLE_MISMATCH:
7351 			case SCF_ERROR_INVALID_ARGUMENT:
7352 			case SCF_ERROR_NOT_SET:
7353 			default:
7354 				bad_error("scf_iter_next_instance",
7355 				    scf_error());
7356 			}
7357 		}
7358 
7359 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7360 			switch (scf_error()) {
7361 			case SCF_ERROR_DELETED:
7362 				continue;
7363 
7364 			case SCF_ERROR_CONNECTION_BROKEN:
7365 				goto connaborted;
7366 
7367 			case SCF_ERROR_NOT_SET:
7368 			case SCF_ERROR_NOT_BOUND:
7369 			default:
7370 				bad_error("scf_instance_get_name", scf_error());
7371 			}
7372 		}
7373 
7374 		if (g_verbose)
7375 			warn(gettext(
7376 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7377 			    snap_previous, s->sc_name, imp_str);
7378 
7379 		r = take_snap(imp_inst, snap_previous, imp_snap);
7380 		switch (r) {
7381 		case 0:
7382 			break;
7383 
7384 		case ECANCELED:
7385 			continue;
7386 
7387 		case ECONNABORTED:
7388 			goto connaborted;
7389 
7390 		case EPERM:
7391 			warn(gettext("Could not take \"%s\" snapshot of "
7392 			    "svc:/%s:%s (permission denied).\n"),
7393 			    snap_previous, s->sc_name, imp_str);
7394 			lcbdata->sc_err = r;
7395 			return (UU_WALK_ERROR);
7396 
7397 		case ENOSPC:
7398 		case -1:
7399 			lcbdata->sc_err = r;
7400 			r = UU_WALK_ERROR;
7401 			goto deltemp;
7402 
7403 		default:
7404 			bad_error("take_snap", r);
7405 		}
7406 
7407 		linst.sc_name = imp_str;
7408 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7409 		    &linst, NULL, NULL);
7410 		if (inst != NULL) {
7411 			inst->sc_import_state = IMPORT_PREVIOUS;
7412 			inst->sc_seen = 1;
7413 		}
7414 	}
7415 
7416 	/*
7417 	 * Create the new instances and take previous snapshots of
7418 	 * them.  This is not necessary, but it maximizes data preservation.
7419 	 */
7420 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7421 	    inst != NULL;
7422 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7423 	    inst)) {
7424 		if (inst->sc_seen)
7425 			continue;
7426 
7427 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7428 		    imp_inst) != 0) {
7429 			switch (scf_error()) {
7430 			case SCF_ERROR_CONNECTION_BROKEN:
7431 				goto connaborted;
7432 
7433 			case SCF_ERROR_BACKEND_READONLY:
7434 			case SCF_ERROR_BACKEND_ACCESS:
7435 			case SCF_ERROR_NO_RESOURCES:
7436 				r = stash_scferror(lcbdata);
7437 				goto deltemp;
7438 
7439 			case SCF_ERROR_EXISTS:
7440 				warn(gettext("%s changed unexpectedly "
7441 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7442 				    inst->sc_name);
7443 				lcbdata->sc_err = EBUSY;
7444 				r = UU_WALK_ERROR;
7445 				goto deltemp;
7446 
7447 			case SCF_ERROR_INVALID_ARGUMENT:
7448 				warn(gettext("Service \"%s\" has instance with "
7449 				    "invalid name \"%s\".\n"), s->sc_name,
7450 				    inst->sc_name);
7451 				r = stash_scferror(lcbdata);
7452 				goto deltemp;
7453 
7454 			case SCF_ERROR_PERMISSION_DENIED:
7455 				warn(gettext("Could not create instance \"%s\" "
7456 				    "in %s (permission denied).\n"),
7457 				    inst->sc_name, s->sc_fmri);
7458 				r = stash_scferror(lcbdata);
7459 				goto deltemp;
7460 
7461 			case SCF_ERROR_HANDLE_MISMATCH:
7462 			case SCF_ERROR_NOT_BOUND:
7463 			case SCF_ERROR_NOT_SET:
7464 			default:
7465 				bad_error("scf_service_add_instance",
7466 				    scf_error());
7467 			}
7468 		}
7469 
7470 		if (g_verbose)
7471 			warn(gettext("Taking \"%s\" snapshot for "
7472 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7473 		r = take_snap(imp_inst, snap_previous, imp_snap);
7474 		switch (r) {
7475 		case 0:
7476 			break;
7477 
7478 		case ECANCELED:
7479 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7480 			lcbdata->sc_err = EBUSY;
7481 			r = UU_WALK_ERROR;
7482 			goto deltemp;
7483 
7484 		case ECONNABORTED:
7485 			goto connaborted;
7486 
7487 		case EPERM:
7488 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7489 			lcbdata->sc_err = r;
7490 			r = UU_WALK_ERROR;
7491 			goto deltemp;
7492 
7493 		case ENOSPC:
7494 		case -1:
7495 			r = UU_WALK_ERROR;
7496 			goto deltemp;
7497 
7498 		default:
7499 			bad_error("take_snap", r);
7500 		}
7501 	}
7502 
7503 	s->sc_import_state = IMPORT_PREVIOUS;
7504 
7505 	/*
7506 	 * Upgrade service properties, if we can find a last-import snapshot.
7507 	 * Any will do because we don't support different service properties
7508 	 * in different manifests, so all snaplevels of the service in all of
7509 	 * the last-import snapshots of the instances should be the same.
7510 	 */
7511 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7512 		switch (scf_error()) {
7513 		case SCF_ERROR_CONNECTION_BROKEN:
7514 			goto connaborted;
7515 
7516 		case SCF_ERROR_DELETED:
7517 			warn(s_deleted, s->sc_fmri);
7518 			lcbdata->sc_err = EBUSY;
7519 			r = UU_WALK_ERROR;
7520 			goto deltemp;
7521 
7522 		case SCF_ERROR_HANDLE_MISMATCH:
7523 		case SCF_ERROR_NOT_BOUND:
7524 		case SCF_ERROR_NOT_SET:
7525 		default:
7526 			bad_error("scf_iter_service_instances", scf_error());
7527 		}
7528 	}
7529 
7530 	for (;;) {
7531 		r = scf_iter_next_instance(imp_iter, imp_inst);
7532 		if (r == -1) {
7533 			switch (scf_error()) {
7534 			case SCF_ERROR_DELETED:
7535 				warn(s_deleted, s->sc_fmri);
7536 				lcbdata->sc_err = EBUSY;
7537 				r = UU_WALK_ERROR;
7538 				goto deltemp;
7539 
7540 			case SCF_ERROR_CONNECTION_BROKEN:
7541 				goto connaborted;
7542 
7543 			case SCF_ERROR_NOT_BOUND:
7544 			case SCF_ERROR_HANDLE_MISMATCH:
7545 			case SCF_ERROR_INVALID_ARGUMENT:
7546 			case SCF_ERROR_NOT_SET:
7547 			default:
7548 				bad_error("scf_iter_next_instance",
7549 				    scf_error());
7550 			}
7551 		}
7552 
7553 		if (r == 0) {
7554 			/*
7555 			 * Didn't find any last-import snapshots.  Override-
7556 			 * import the properties.  Unless one of the instances
7557 			 * has a general/enabled property, in which case we're
7558 			 * probably running a last-import-capable svccfg for
7559 			 * the first time, and we should only take the
7560 			 * last-import snapshot.
7561 			 */
7562 			if (have_ge) {
7563 				pgroup_t *mfpg;
7564 				scf_callback_t mfcbdata;
7565 
7566 				li_only = 1;
7567 				no_refresh = 1;
7568 				/*
7569 				 * Need to go ahead and import the manifestfiles
7570 				 * pg if it exists. If the last-import snapshot
7571 				 * upgrade code is ever removed this code can
7572 				 * be removed as well.
7573 				 */
7574 				mfpg = internal_pgroup_find(s,
7575 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7576 
7577 				if (mfpg) {
7578 					mfcbdata.sc_handle = g_hndl;
7579 					mfcbdata.sc_parent = imp_svc;
7580 					mfcbdata.sc_service = 1;
7581 					mfcbdata.sc_flags = SCI_FORCE;
7582 					mfcbdata.sc_source_fmri = s->sc_fmri;
7583 					mfcbdata.sc_target_fmri = s->sc_fmri;
7584 					if (entity_pgroup_import(mfpg,
7585 					    &mfcbdata) != UU_WALK_NEXT) {
7586 						warn(s_mfile_upd, s->sc_fmri);
7587 						r = UU_WALK_ERROR;
7588 						goto deltemp;
7589 					}
7590 				}
7591 				break;
7592 			}
7593 
7594 			s->sc_import_state = IMPORT_PROP_BEGUN;
7595 
7596 			cbdata.sc_handle = g_hndl;
7597 			cbdata.sc_parent = imp_svc;
7598 			cbdata.sc_service = 1;
7599 			cbdata.sc_flags = SCI_FORCE;
7600 			cbdata.sc_source_fmri = s->sc_fmri;
7601 			cbdata.sc_target_fmri = s->sc_fmri;
7602 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7603 			    &cbdata, UU_DEFAULT) != 0) {
7604 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7605 					bad_error("uu_list_walk", uu_error());
7606 				lcbdata->sc_err = cbdata.sc_err;
7607 				switch (cbdata.sc_err) {
7608 				case ECONNABORTED:
7609 					goto connaborted;
7610 
7611 				case ECANCELED:
7612 					warn(s_deleted, s->sc_fmri);
7613 					lcbdata->sc_err = EBUSY;
7614 					break;
7615 
7616 				case EINVAL:	/* caught above */
7617 				case EEXIST:
7618 					bad_error("entity_pgroup_import",
7619 					    cbdata.sc_err);
7620 				}
7621 
7622 				r = UU_WALK_ERROR;
7623 				goto deltemp;
7624 			}
7625 
7626 			cbdata.sc_trans = NULL;
7627 			cbdata.sc_flags = 0;
7628 			if (uu_list_walk(s->sc_dependents,
7629 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7630 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7631 					bad_error("uu_list_walk", uu_error());
7632 				lcbdata->sc_err = cbdata.sc_err;
7633 				if (cbdata.sc_err == ECONNABORTED)
7634 					goto connaborted;
7635 				r = UU_WALK_ERROR;
7636 				goto deltemp;
7637 			}
7638 			break;
7639 		}
7640 
7641 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7642 		    imp_snap) != 0) {
7643 			switch (scf_error()) {
7644 			case SCF_ERROR_DELETED:
7645 				continue;
7646 
7647 			case SCF_ERROR_NOT_FOUND:
7648 				break;
7649 
7650 			case SCF_ERROR_CONNECTION_BROKEN:
7651 				goto connaborted;
7652 
7653 			case SCF_ERROR_HANDLE_MISMATCH:
7654 			case SCF_ERROR_NOT_BOUND:
7655 			case SCF_ERROR_INVALID_ARGUMENT:
7656 			case SCF_ERROR_NOT_SET:
7657 			default:
7658 				bad_error("scf_instance_get_snapshot",
7659 				    scf_error());
7660 			}
7661 
7662 			if (have_ge)
7663 				continue;
7664 
7665 			/*
7666 			 * Check for a general/enabled property.  This is how
7667 			 * we tell whether to import if there turn out to be
7668 			 * no last-import snapshots.
7669 			 */
7670 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7671 			    imp_pg) == 0) {
7672 				if (scf_pg_get_property(imp_pg,
7673 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7674 					have_ge = 1;
7675 				} else {
7676 					switch (scf_error()) {
7677 					case SCF_ERROR_DELETED:
7678 					case SCF_ERROR_NOT_FOUND:
7679 						continue;
7680 
7681 					case SCF_ERROR_INVALID_ARGUMENT:
7682 					case SCF_ERROR_HANDLE_MISMATCH:
7683 					case SCF_ERROR_CONNECTION_BROKEN:
7684 					case SCF_ERROR_NOT_BOUND:
7685 					case SCF_ERROR_NOT_SET:
7686 					default:
7687 						bad_error("scf_pg_get_property",
7688 						    scf_error());
7689 					}
7690 				}
7691 			} else {
7692 				switch (scf_error()) {
7693 				case SCF_ERROR_DELETED:
7694 				case SCF_ERROR_NOT_FOUND:
7695 					continue;
7696 
7697 				case SCF_ERROR_CONNECTION_BROKEN:
7698 					goto connaborted;
7699 
7700 				case SCF_ERROR_NOT_BOUND:
7701 				case SCF_ERROR_NOT_SET:
7702 				case SCF_ERROR_INVALID_ARGUMENT:
7703 				case SCF_ERROR_HANDLE_MISMATCH:
7704 				default:
7705 					bad_error("scf_instance_get_pg",
7706 					    scf_error());
7707 				}
7708 			}
7709 			continue;
7710 		}
7711 
7712 		/* find service snaplevel */
7713 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7714 		switch (r) {
7715 		case 0:
7716 			break;
7717 
7718 		case ECONNABORTED:
7719 			goto connaborted;
7720 
7721 		case ECANCELED:
7722 			continue;
7723 
7724 		case ENOENT:
7725 			if (scf_instance_get_name(imp_inst, imp_str,
7726 			    imp_str_sz) < 0)
7727 				(void) strcpy(imp_str, "?");
7728 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7729 			lcbdata->sc_err = EBADF;
7730 			r = UU_WALK_ERROR;
7731 			goto deltemp;
7732 
7733 		default:
7734 			bad_error("get_snaplevel", r);
7735 		}
7736 
7737 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7738 		    imp_rsnap) != 0) {
7739 			switch (scf_error()) {
7740 			case SCF_ERROR_DELETED:
7741 				continue;
7742 
7743 			case SCF_ERROR_NOT_FOUND:
7744 				break;
7745 
7746 			case SCF_ERROR_CONNECTION_BROKEN:
7747 				goto connaborted;
7748 
7749 			case SCF_ERROR_INVALID_ARGUMENT:
7750 			case SCF_ERROR_HANDLE_MISMATCH:
7751 			case SCF_ERROR_NOT_BOUND:
7752 			case SCF_ERROR_NOT_SET:
7753 			default:
7754 				bad_error("scf_instance_get_snapshot",
7755 				    scf_error());
7756 			}
7757 			running = NULL;
7758 		} else {
7759 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7760 			switch (r) {
7761 			case 0:
7762 				running = imp_rsnpl;
7763 				break;
7764 
7765 			case ECONNABORTED:
7766 				goto connaborted;
7767 
7768 			case ECANCELED:
7769 				continue;
7770 
7771 			case ENOENT:
7772 				if (scf_instance_get_name(imp_inst, imp_str,
7773 				    imp_str_sz) < 0)
7774 					(void) strcpy(imp_str, "?");
7775 				warn(badsnap, snap_running, s->sc_name,
7776 				    imp_str);
7777 				lcbdata->sc_err = EBADF;
7778 				r = UU_WALK_ERROR;
7779 				goto deltemp;
7780 
7781 			default:
7782 				bad_error("get_snaplevel", r);
7783 			}
7784 		}
7785 
7786 		if (g_verbose) {
7787 			if (scf_instance_get_name(imp_inst, imp_str,
7788 			    imp_str_sz) < 0)
7789 				(void) strcpy(imp_str, "?");
7790 			warn(gettext("Upgrading properties of %s according to "
7791 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7792 		}
7793 
7794 		/* upgrade service properties */
7795 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7796 		if (r == 0)
7797 			break;
7798 
7799 		switch (r) {
7800 		case ECONNABORTED:
7801 			goto connaborted;
7802 
7803 		case ECANCELED:
7804 			warn(s_deleted, s->sc_fmri);
7805 			lcbdata->sc_err = EBUSY;
7806 			break;
7807 
7808 		case ENODEV:
7809 			if (scf_instance_get_name(imp_inst, imp_str,
7810 			    imp_str_sz) < 0)
7811 				(void) strcpy(imp_str, "?");
7812 			warn(i_deleted, s->sc_fmri, imp_str);
7813 			lcbdata->sc_err = EBUSY;
7814 			break;
7815 
7816 		default:
7817 			lcbdata->sc_err = r;
7818 		}
7819 
7820 		r = UU_WALK_ERROR;
7821 		goto deltemp;
7822 	}
7823 
7824 	s->sc_import_state = IMPORT_PROP_DONE;
7825 
7826 instances:
7827 	/* import instances */
7828 	cbdata.sc_handle = lcbdata->sc_handle;
7829 	cbdata.sc_parent = imp_svc;
7830 	cbdata.sc_service = 1;
7831 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7832 	cbdata.sc_general = NULL;
7833 
7834 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7835 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7836 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7837 			bad_error("uu_list_walk", uu_error());
7838 
7839 		lcbdata->sc_err = cbdata.sc_err;
7840 		if (cbdata.sc_err == ECONNABORTED)
7841 			goto connaborted;
7842 		r = UU_WALK_ERROR;
7843 		goto deltemp;
7844 	}
7845 
7846 	s->sc_import_state = IMPORT_COMPLETE;
7847 	r = UU_WALK_NEXT;
7848 
7849 deltemp:
7850 	/* delete temporary service */
7851 	if (scf_service_delete(imp_tsvc) != 0) {
7852 		switch (scf_error()) {
7853 		case SCF_ERROR_DELETED:
7854 			break;
7855 
7856 		case SCF_ERROR_CONNECTION_BROKEN:
7857 			goto connaborted;
7858 
7859 		case SCF_ERROR_EXISTS:
7860 			warn(gettext(
7861 			    "Could not delete svc:/%s (instances exist).\n"),
7862 			    imp_tsname);
7863 			break;
7864 
7865 		case SCF_ERROR_NOT_SET:
7866 		case SCF_ERROR_NOT_BOUND:
7867 		default:
7868 			bad_error("scf_service_delete", scf_error());
7869 		}
7870 	}
7871 
7872 	return (r);
7873 
7874 connaborted:
7875 	warn(gettext("Could not delete svc:/%s "
7876 	    "(repository connection broken).\n"), imp_tsname);
7877 	lcbdata->sc_err = ECONNABORTED;
7878 	return (UU_WALK_ERROR);
7879 }
7880 
7881 static const char *
7882 import_progress(int st)
7883 {
7884 	switch (st) {
7885 	case 0:
7886 		return (gettext("not reached."));
7887 
7888 	case IMPORT_PREVIOUS:
7889 		return (gettext("previous snapshot taken."));
7890 
7891 	case IMPORT_PROP_BEGUN:
7892 		return (gettext("some properties imported."));
7893 
7894 	case IMPORT_PROP_DONE:
7895 		return (gettext("properties imported."));
7896 
7897 	case IMPORT_COMPLETE:
7898 		return (gettext("imported."));
7899 
7900 	case IMPORT_REFRESHED:
7901 		return (gettext("refresh requested."));
7902 
7903 	default:
7904 #ifndef NDEBUG
7905 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7906 		    __FILE__, __LINE__, st);
7907 #endif
7908 		abort();
7909 		/* NOTREACHED */
7910 	}
7911 }
7912 
7913 /*
7914  * Returns
7915  *   0 - success
7916  *     - fmri wasn't found (error printed)
7917  *     - entity was deleted (error printed)
7918  *     - backend denied access (error printed)
7919  *   ENOMEM - out of memory (error printed)
7920  *   ECONNABORTED - repository connection broken (error printed)
7921  *   EPERM - permission denied (error printed)
7922  *   -1 - unknown libscf error (error printed)
7923  */
7924 static int
7925 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7926 {
7927 	scf_error_t serr;
7928 	void *ent;
7929 	int issvc;
7930 	int r;
7931 
7932 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7933 	const char *dpt_deleted = gettext("Could not refresh %s "
7934 	    "(dependent \"%s\" of %s) (deleted).\n");
7935 
7936 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7937 	switch (serr) {
7938 	case SCF_ERROR_NONE:
7939 		break;
7940 
7941 	case SCF_ERROR_NO_MEMORY:
7942 		if (name == NULL)
7943 			warn(gettext("Could not refresh %s (out of memory).\n"),
7944 			    fmri);
7945 		else
7946 			warn(gettext("Could not refresh %s "
7947 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7948 			    fmri, name, d_fmri);
7949 		return (ENOMEM);
7950 
7951 	case SCF_ERROR_NOT_FOUND:
7952 		if (name == NULL)
7953 			warn(deleted, fmri);
7954 		else
7955 			warn(dpt_deleted, fmri, name, d_fmri);
7956 		return (0);
7957 
7958 	case SCF_ERROR_INVALID_ARGUMENT:
7959 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7960 	default:
7961 		bad_error("fmri_to_entity", serr);
7962 	}
7963 
7964 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7965 	switch (r) {
7966 	case 0:
7967 		break;
7968 
7969 	case ECONNABORTED:
7970 		if (name != NULL)
7971 			warn(gettext("Could not refresh %s "
7972 			    "(dependent \"%s\" of %s) "
7973 			    "(repository connection broken).\n"), fmri, name,
7974 			    d_fmri);
7975 		return (r);
7976 
7977 	case ECANCELED:
7978 		if (name == NULL)
7979 			warn(deleted, fmri);
7980 		else
7981 			warn(dpt_deleted, fmri, name, d_fmri);
7982 		return (0);
7983 
7984 	case EACCES:
7985 		if (!g_verbose)
7986 			return (0);
7987 		if (name == NULL)
7988 			warn(gettext("Could not refresh %s "
7989 			    "(backend access denied).\n"), fmri);
7990 		else
7991 			warn(gettext("Could not refresh %s "
7992 			    "(dependent \"%s\" of %s) "
7993 			    "(backend access denied).\n"), fmri, name, d_fmri);
7994 		return (0);
7995 
7996 	case EPERM:
7997 		if (name == NULL)
7998 			warn(gettext("Could not refresh %s "
7999 			    "(permission denied).\n"), fmri);
8000 		else
8001 			warn(gettext("Could not refresh %s "
8002 			    "(dependent \"%s\" of %s) "
8003 			    "(permission denied).\n"), fmri, name, d_fmri);
8004 		return (r);
8005 
8006 	case ENOSPC:
8007 		if (name == NULL)
8008 			warn(gettext("Could not refresh %s "
8009 			    "(repository server out of resources).\n"),
8010 			    fmri);
8011 		else
8012 			warn(gettext("Could not refresh %s "
8013 			    "(dependent \"%s\" of %s) "
8014 			    "(repository server out of resources).\n"),
8015 			    fmri, name, d_fmri);
8016 		return (r);
8017 
8018 	case -1:
8019 		scfwarn();
8020 		return (r);
8021 
8022 	default:
8023 		bad_error("refresh_entity", r);
8024 	}
8025 
8026 	if (issvc)
8027 		scf_service_destroy(ent);
8028 	else
8029 		scf_instance_destroy(ent);
8030 
8031 	return (0);
8032 }
8033 
8034 static int
8035 alloc_imp_globals()
8036 {
8037 	int r;
8038 
8039 	const char * const emsg_nomem = gettext("Out of memory.\n");
8040 	const char * const emsg_nores =
8041 	    gettext("svc.configd is out of resources.\n");
8042 
8043 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8044 	    max_scf_name_len : max_scf_fmri_len) + 1;
8045 
8046 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8047 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
8048 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8049 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8050 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8051 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8052 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8053 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8054 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8055 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8056 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8057 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8058 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8059 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
8060 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8061 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8062 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8063 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8064 	    (imp_str = malloc(imp_str_sz)) == NULL ||
8065 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8066 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8067 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8068 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8069 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8070 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8071 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8072 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8073 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8074 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
8075 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8076 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
8077 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8078 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8079 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8080 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8081 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8082 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8083 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
8084 			warn(emsg_nores);
8085 		else
8086 			warn(emsg_nomem);
8087 
8088 		return (-1);
8089 	}
8090 
8091 	r = load_init();
8092 	switch (r) {
8093 	case 0:
8094 		break;
8095 
8096 	case ENOMEM:
8097 		warn(emsg_nomem);
8098 		return (-1);
8099 
8100 	default:
8101 		bad_error("load_init", r);
8102 	}
8103 
8104 	return (0);
8105 }
8106 
8107 static void
8108 free_imp_globals()
8109 {
8110 	pgroup_t *old_dpt;
8111 	void *cookie;
8112 
8113 	load_fini();
8114 
8115 	free(ud_ctarg);
8116 	free(ud_oldtarg);
8117 	free(ud_name);
8118 	ud_ctarg = ud_oldtarg = ud_name = NULL;
8119 
8120 	scf_transaction_destroy(ud_tx);
8121 	ud_tx = NULL;
8122 	scf_iter_destroy(ud_iter);
8123 	scf_iter_destroy(ud_iter2);
8124 	ud_iter = ud_iter2 = NULL;
8125 	scf_value_destroy(ud_val);
8126 	ud_val = NULL;
8127 	scf_property_destroy(ud_prop);
8128 	scf_property_destroy(ud_dpt_prop);
8129 	ud_prop = ud_dpt_prop = NULL;
8130 	scf_pg_destroy(ud_pg);
8131 	scf_pg_destroy(ud_cur_depts_pg);
8132 	scf_pg_destroy(ud_run_dpts_pg);
8133 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8134 	scf_snaplevel_destroy(ud_snpl);
8135 	ud_snpl = NULL;
8136 	scf_instance_destroy(ud_inst);
8137 	ud_inst = NULL;
8138 
8139 	free(imp_str);
8140 	free(imp_tsname);
8141 	free(imp_fe1);
8142 	free(imp_fe2);
8143 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8144 
8145 	cookie = NULL;
8146 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8147 	    NULL) {
8148 		free((char *)old_dpt->sc_pgroup_name);
8149 		free((char *)old_dpt->sc_pgroup_fmri);
8150 		internal_pgroup_free(old_dpt);
8151 	}
8152 	uu_list_destroy(imp_deleted_dpts);
8153 
8154 	scf_transaction_destroy(imp_tx);
8155 	imp_tx = NULL;
8156 	scf_iter_destroy(imp_iter);
8157 	scf_iter_destroy(imp_rpg_iter);
8158 	scf_iter_destroy(imp_up_iter);
8159 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8160 	scf_property_destroy(imp_prop);
8161 	imp_prop = NULL;
8162 	scf_pg_destroy(imp_pg);
8163 	scf_pg_destroy(imp_pg2);
8164 	imp_pg = imp_pg2 = NULL;
8165 	scf_snaplevel_destroy(imp_snpl);
8166 	scf_snaplevel_destroy(imp_rsnpl);
8167 	imp_snpl = imp_rsnpl = NULL;
8168 	scf_snapshot_destroy(imp_snap);
8169 	scf_snapshot_destroy(imp_lisnap);
8170 	scf_snapshot_destroy(imp_tlisnap);
8171 	scf_snapshot_destroy(imp_rsnap);
8172 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8173 	scf_instance_destroy(imp_inst);
8174 	scf_instance_destroy(imp_tinst);
8175 	imp_inst = imp_tinst = NULL;
8176 	scf_service_destroy(imp_svc);
8177 	scf_service_destroy(imp_tsvc);
8178 	imp_svc = imp_tsvc = NULL;
8179 	scf_scope_destroy(imp_scope);
8180 	imp_scope = NULL;
8181 
8182 	load_fini();
8183 }
8184 
8185 int
8186 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8187 {
8188 	scf_callback_t cbdata;
8189 	int result = 0;
8190 	entity_t *svc, *inst;
8191 	uu_list_t *insts;
8192 	int r;
8193 	pgroup_t *old_dpt;
8194 	int annotation_set = 0;
8195 
8196 	const char * const emsg_nomem = gettext("Out of memory.\n");
8197 	const char * const emsg_nores =
8198 	    gettext("svc.configd is out of resources.\n");
8199 
8200 	lscf_prep_hndl();
8201 
8202 	if (alloc_imp_globals())
8203 		goto out;
8204 
8205 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8206 		switch (scf_error()) {
8207 		case SCF_ERROR_CONNECTION_BROKEN:
8208 			warn(gettext("Repository connection broken.\n"));
8209 			repository_teardown();
8210 			result = -1;
8211 			goto out;
8212 
8213 		case SCF_ERROR_NOT_FOUND:
8214 		case SCF_ERROR_INVALID_ARGUMENT:
8215 		case SCF_ERROR_NOT_BOUND:
8216 		case SCF_ERROR_HANDLE_MISMATCH:
8217 		default:
8218 			bad_error("scf_handle_get_scope", scf_error());
8219 		}
8220 	}
8221 
8222 	/* Set up the auditing annotation. */
8223 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8224 		annotation_set = 1;
8225 	} else {
8226 		switch (scf_error()) {
8227 		case SCF_ERROR_CONNECTION_BROKEN:
8228 			warn(gettext("Repository connection broken.\n"));
8229 			repository_teardown();
8230 			result = -1;
8231 			goto out;
8232 
8233 		case SCF_ERROR_INVALID_ARGUMENT:
8234 		case SCF_ERROR_NOT_BOUND:
8235 		case SCF_ERROR_NO_RESOURCES:
8236 		case SCF_ERROR_INTERNAL:
8237 			bad_error("_scf_set_annotation", scf_error());
8238 			/* NOTREACHED */
8239 
8240 		default:
8241 			/*
8242 			 * Do not terminate import because of inability to
8243 			 * generate annotation audit event.
8244 			 */
8245 			warn(gettext("_scf_set_annotation() unexpectedly "
8246 			    "failed with return code of %d\n"), scf_error());
8247 			break;
8248 		}
8249 	}
8250 
8251 	/*
8252 	 * Clear the sc_import_state's of all services & instances so we can
8253 	 * report how far we got if we fail.
8254 	 */
8255 	for (svc = uu_list_first(bndl->sc_bundle_services);
8256 	    svc != NULL;
8257 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8258 		svc->sc_import_state = 0;
8259 
8260 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8261 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8262 		    UU_DEFAULT) != 0)
8263 			bad_error("uu_list_walk", uu_error());
8264 	}
8265 
8266 	cbdata.sc_handle = g_hndl;
8267 	cbdata.sc_parent = imp_scope;
8268 	cbdata.sc_flags = flags;
8269 	cbdata.sc_general = NULL;
8270 
8271 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8272 	    &cbdata, UU_DEFAULT) == 0) {
8273 		char *eptr;
8274 		/* Success.  Refresh everything. */
8275 
8276 		if (flags & SCI_NOREFRESH || no_refresh) {
8277 			no_refresh = 0;
8278 			result = 0;
8279 			goto out;
8280 		}
8281 
8282 		for (svc = uu_list_first(bndl->sc_bundle_services);
8283 		    svc != NULL;
8284 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8285 			pgroup_t *dpt;
8286 
8287 			insts = svc->sc_u.sc_service.sc_service_instances;
8288 
8289 			for (inst = uu_list_first(insts);
8290 			    inst != NULL;
8291 			    inst = uu_list_next(insts, inst)) {
8292 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8293 				switch (r) {
8294 				case 0:
8295 					break;
8296 
8297 				case ENOMEM:
8298 				case ECONNABORTED:
8299 				case EPERM:
8300 				case -1:
8301 					goto progress;
8302 
8303 				default:
8304 					bad_error("imp_refresh_fmri", r);
8305 				}
8306 
8307 				inst->sc_import_state = IMPORT_REFRESHED;
8308 
8309 				for (dpt = uu_list_first(inst->sc_dependents);
8310 				    dpt != NULL;
8311 				    dpt = uu_list_next(inst->sc_dependents,
8312 				    dpt))
8313 					if (imp_refresh_fmri(
8314 					    dpt->sc_pgroup_fmri,
8315 					    dpt->sc_pgroup_name,
8316 					    inst->sc_fmri) != 0)
8317 						goto progress;
8318 			}
8319 
8320 			for (dpt = uu_list_first(svc->sc_dependents);
8321 			    dpt != NULL;
8322 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8323 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8324 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8325 					goto progress;
8326 		}
8327 
8328 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8329 		    old_dpt != NULL;
8330 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8331 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8332 			    old_dpt->sc_pgroup_name,
8333 			    old_dpt->sc_parent->sc_fmri) != 0)
8334 				goto progress;
8335 
8336 		result = 0;
8337 
8338 		/*
8339 		 * This snippet of code assumes that we are running svccfg as we
8340 		 * normally do -- witih svc.startd running. Of course, that is
8341 		 * not actually the case all the time because we also use a
8342 		 * varient of svc.configd and svccfg which are only meant to
8343 		 * run during the build process. During this time we have no
8344 		 * svc.startd, so this check would hang the build process.
8345 		 *
8346 		 * However, we've also given other consolidations, a bit of a
8347 		 * means to tie themselves into a knot. They're not properly
8348 		 * using the native build equivalents, but they've been getting
8349 		 * away with it anyways. Therefore, if we've found that
8350 		 * SVCCFG_REPOSITORY is set indicating that a separate configd
8351 		 * should be spun up, then we have to assume it's not using a
8352 		 * startd and we should not do this check.
8353 		 */
8354 #ifndef NATIVE_BUILD
8355 		/*
8356 		 * Verify that the restarter group is preset
8357 		 */
8358 		eptr = getenv("SVCCFG_REPOSITORY");
8359 		for (svc = uu_list_first(bndl->sc_bundle_services);
8360 		    svc != NULL && eptr == NULL;
8361 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8362 
8363 			insts = svc->sc_u.sc_service.sc_service_instances;
8364 
8365 			for (inst = uu_list_first(insts);
8366 			    inst != NULL;
8367 			    inst = uu_list_next(insts, inst)) {
8368 				if (lscf_instance_verify(imp_scope, svc,
8369 				    inst) != 0)
8370 					goto progress;
8371 			}
8372 		}
8373 #endif
8374 		goto out;
8375 
8376 	}
8377 
8378 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8379 		bad_error("uu_list_walk", uu_error());
8380 
8381 printerr:
8382 	/* If the error hasn't been printed yet, do so here. */
8383 	switch (cbdata.sc_err) {
8384 	case ECONNABORTED:
8385 		warn(gettext("Repository connection broken.\n"));
8386 		break;
8387 
8388 	case ENOMEM:
8389 		warn(emsg_nomem);
8390 		break;
8391 
8392 	case ENOSPC:
8393 		warn(emsg_nores);
8394 		break;
8395 
8396 	case EROFS:
8397 		warn(gettext("Repository is read-only.\n"));
8398 		break;
8399 
8400 	case EACCES:
8401 		warn(gettext("Repository backend denied access.\n"));
8402 		break;
8403 
8404 	case EPERM:
8405 	case EINVAL:
8406 	case EEXIST:
8407 	case EBUSY:
8408 	case EBADF:
8409 	case -1:
8410 		break;
8411 
8412 	default:
8413 		bad_error("lscf_service_import", cbdata.sc_err);
8414 	}
8415 
8416 progress:
8417 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8418 
8419 	for (svc = uu_list_first(bndl->sc_bundle_services);
8420 	    svc != NULL;
8421 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8422 		insts = svc->sc_u.sc_service.sc_service_instances;
8423 
8424 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8425 		    import_progress(svc->sc_import_state));
8426 
8427 		for (inst = uu_list_first(insts);
8428 		    inst != NULL;
8429 		    inst = uu_list_next(insts, inst))
8430 			warn(gettext("    Instance \"%s\": %s\n"),
8431 			    inst->sc_name,
8432 			    import_progress(inst->sc_import_state));
8433 	}
8434 
8435 	if (cbdata.sc_err == ECONNABORTED)
8436 		repository_teardown();
8437 
8438 
8439 	result = -1;
8440 
8441 out:
8442 	if (annotation_set != 0) {
8443 		/* Turn off annotation.  It is no longer needed. */
8444 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8445 	}
8446 
8447 	free_imp_globals();
8448 
8449 	return (result);
8450 }
8451 
8452 /*
8453  * _lscf_import_err() summarize the error handling returned by
8454  * lscf_import_{instance | service}_pgs
8455  * Return values are:
8456  * IMPORT_NEXT
8457  * IMPORT_OUT
8458  * IMPORT_BAD
8459  */
8460 
8461 #define	IMPORT_BAD	-1
8462 #define	IMPORT_NEXT	0
8463 #define	IMPORT_OUT	1
8464 
8465 static int
8466 _lscf_import_err(int err, const char *fmri)
8467 {
8468 	switch (err) {
8469 	case 0:
8470 		if (g_verbose)
8471 			warn(gettext("%s updated.\n"), fmri);
8472 		return (IMPORT_NEXT);
8473 
8474 	case ECONNABORTED:
8475 		warn(gettext("Could not update %s "
8476 		    "(repository connection broken).\n"), fmri);
8477 		return (IMPORT_OUT);
8478 
8479 	case ENOMEM:
8480 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8481 		return (IMPORT_OUT);
8482 
8483 	case ENOSPC:
8484 		warn(gettext("Could not update %s "
8485 		    "(repository server out of resources).\n"), fmri);
8486 		return (IMPORT_OUT);
8487 
8488 	case ECANCELED:
8489 		warn(gettext(
8490 		    "Could not update %s (deleted).\n"), fmri);
8491 		return (IMPORT_NEXT);
8492 
8493 	case EPERM:
8494 	case EINVAL:
8495 	case EBUSY:
8496 		return (IMPORT_NEXT);
8497 
8498 	case EROFS:
8499 		warn(gettext("Could not update %s (repository read-only).\n"),
8500 		    fmri);
8501 		return (IMPORT_OUT);
8502 
8503 	case EACCES:
8504 		warn(gettext("Could not update %s "
8505 		    "(backend access denied).\n"), fmri);
8506 		return (IMPORT_NEXT);
8507 
8508 	case EEXIST:
8509 	default:
8510 		return (IMPORT_BAD);
8511 	}
8512 
8513 	/*NOTREACHED*/
8514 }
8515 
8516 /*
8517  * The global imp_svc and imp_inst should be set by the caller in the
8518  * check to make sure the service and instance exist that the apply is
8519  * working on.
8520  */
8521 static int
8522 lscf_dependent_apply(void *dpg, void *e)
8523 {
8524 	scf_callback_t cb;
8525 	pgroup_t *dpt_pgroup = dpg;
8526 	pgroup_t *deldpt;
8527 	entity_t *ent = e;
8528 	int tissvc;
8529 	void *sc_ent, *tent;
8530 	scf_error_t serr;
8531 	int r;
8532 
8533 	const char * const dependents = "dependents";
8534 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8535 
8536 	if (issvc)
8537 		sc_ent = imp_svc;
8538 	else
8539 		sc_ent = imp_inst;
8540 
8541 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8542 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8543 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8544 	    imp_prop) != 0) {
8545 		switch (scf_error()) {
8546 		case SCF_ERROR_NOT_FOUND:
8547 		case SCF_ERROR_DELETED:
8548 			break;
8549 
8550 		case SCF_ERROR_CONNECTION_BROKEN:
8551 		case SCF_ERROR_NOT_SET:
8552 		case SCF_ERROR_INVALID_ARGUMENT:
8553 		case SCF_ERROR_HANDLE_MISMATCH:
8554 		case SCF_ERROR_NOT_BOUND:
8555 		default:
8556 			bad_error("entity_get_pg", scf_error());
8557 		}
8558 	} else {
8559 		/*
8560 		 * Found the dependents/<wip dep> so check to
8561 		 * see if the service is different.  If so
8562 		 * store the service for later refresh, and
8563 		 * delete the wip dependency from the service
8564 		 */
8565 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8566 			switch (scf_error()) {
8567 				case SCF_ERROR_DELETED:
8568 					break;
8569 
8570 				case SCF_ERROR_CONNECTION_BROKEN:
8571 				case SCF_ERROR_NOT_SET:
8572 				case SCF_ERROR_INVALID_ARGUMENT:
8573 				case SCF_ERROR_HANDLE_MISMATCH:
8574 				case SCF_ERROR_NOT_BOUND:
8575 				default:
8576 					bad_error("scf_property_get_value",
8577 					    scf_error());
8578 			}
8579 		}
8580 
8581 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8582 		    max_scf_value_len + 1) < 0)
8583 			bad_error("scf_value_get_as_string", scf_error());
8584 
8585 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8586 		switch (r) {
8587 		case 1:
8588 			break;
8589 		case 0:
8590 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8591 			    &tissvc)) != SCF_ERROR_NONE) {
8592 				if (serr == SCF_ERROR_NOT_FOUND) {
8593 					break;
8594 				} else {
8595 					bad_error("fmri_to_entity", serr);
8596 				}
8597 			}
8598 
8599 			if (entity_get_pg(tent, tissvc,
8600 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8601 				serr = scf_error();
8602 				if (serr == SCF_ERROR_NOT_FOUND ||
8603 				    serr == SCF_ERROR_DELETED) {
8604 					break;
8605 				} else {
8606 					bad_error("entity_get_pg", scf_error());
8607 				}
8608 			}
8609 
8610 			if (scf_pg_delete(imp_pg) != 0) {
8611 				serr = scf_error();
8612 				if (serr == SCF_ERROR_NOT_FOUND ||
8613 				    serr == SCF_ERROR_DELETED) {
8614 					break;
8615 				} else {
8616 					bad_error("scf_pg_delete", scf_error());
8617 				}
8618 			}
8619 
8620 			deldpt = internal_pgroup_new();
8621 			if (deldpt == NULL)
8622 				return (ENOMEM);
8623 			deldpt->sc_pgroup_name =
8624 			    strdup(dpt_pgroup->sc_pgroup_name);
8625 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8626 			if (deldpt->sc_pgroup_name == NULL ||
8627 			    deldpt->sc_pgroup_fmri == NULL)
8628 				return (ENOMEM);
8629 			deldpt->sc_parent = (entity_t *)ent;
8630 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8631 			    deldpt) != 0)
8632 				uu_die(gettext("libuutil error: %s\n"),
8633 				    uu_strerror(uu_error()));
8634 
8635 			break;
8636 		default:
8637 			bad_error("fmri_equal", r);
8638 		}
8639 	}
8640 
8641 	cb.sc_handle = g_hndl;
8642 	cb.sc_parent = ent;
8643 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8644 	cb.sc_source_fmri = ent->sc_fmri;
8645 	cb.sc_target_fmri = ent->sc_fmri;
8646 	cb.sc_trans = NULL;
8647 	cb.sc_flags = SCI_FORCE;
8648 
8649 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8650 		return (UU_WALK_ERROR);
8651 
8652 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8653 	switch (r) {
8654 	case 0:
8655 		break;
8656 
8657 	case ENOMEM:
8658 	case ECONNABORTED:
8659 	case EPERM:
8660 	case -1:
8661 		warn(gettext("Unable to refresh \"%s\"\n"),
8662 		    dpt_pgroup->sc_pgroup_fmri);
8663 		return (UU_WALK_ERROR);
8664 
8665 	default:
8666 		bad_error("imp_refresh_fmri", r);
8667 	}
8668 
8669 	return (UU_WALK_NEXT);
8670 }
8671 
8672 /*
8673  * Returns
8674  *   0 - success
8675  *   -1 - lscf_import_instance_pgs() failed.
8676  */
8677 int
8678 lscf_bundle_apply(bundle_t *bndl, const char *file)
8679 {
8680 	pgroup_t *old_dpt;
8681 	entity_t *svc, *inst;
8682 	int annotation_set = 0;
8683 	int ret = 0;
8684 	int r = 0;
8685 
8686 	lscf_prep_hndl();
8687 
8688 	if ((ret = alloc_imp_globals()))
8689 		goto out;
8690 
8691 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8692 		scfdie();
8693 
8694 	/*
8695 	 * Set the strings to be used for the security audit annotation
8696 	 * event.
8697 	 */
8698 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8699 		annotation_set = 1;
8700 	} else {
8701 		switch (scf_error()) {
8702 		case SCF_ERROR_CONNECTION_BROKEN:
8703 			warn(gettext("Repository connection broken.\n"));
8704 			goto out;
8705 
8706 		case SCF_ERROR_INVALID_ARGUMENT:
8707 		case SCF_ERROR_NOT_BOUND:
8708 		case SCF_ERROR_NO_RESOURCES:
8709 		case SCF_ERROR_INTERNAL:
8710 			bad_error("_scf_set_annotation", scf_error());
8711 			/* NOTREACHED */
8712 
8713 		default:
8714 			/*
8715 			 * Do not abort apply operation because of
8716 			 * inability to create annotation audit event.
8717 			 */
8718 			warn(gettext("_scf_set_annotation() unexpectedly "
8719 			    "failed with return code of %d\n"), scf_error());
8720 			break;
8721 		}
8722 	}
8723 
8724 	for (svc = uu_list_first(bndl->sc_bundle_services);
8725 	    svc != NULL;
8726 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8727 		int refresh = 0;
8728 
8729 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8730 		    imp_svc) != 0) {
8731 			switch (scf_error()) {
8732 			case SCF_ERROR_NOT_FOUND:
8733 				if (g_verbose)
8734 					warn(gettext("Ignoring nonexistent "
8735 					    "service %s.\n"), svc->sc_name);
8736 				continue;
8737 
8738 			default:
8739 				scfdie();
8740 			}
8741 		}
8742 
8743 		/*
8744 		 * If there were missing types in the profile, then need to
8745 		 * attempt to find the types.
8746 		 */
8747 		if (svc->sc_miss_type) {
8748 			if (uu_list_numnodes(svc->sc_pgroups) &&
8749 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8750 			    svc, UU_DEFAULT) != 0) {
8751 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8752 					bad_error("uu_list_walk", uu_error());
8753 
8754 				ret = -1;
8755 				continue;
8756 			}
8757 
8758 			for (inst = uu_list_first(
8759 			    svc->sc_u.sc_service.sc_service_instances);
8760 			    inst != NULL;
8761 			    inst = uu_list_next(
8762 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8763 				/*
8764 				 * If the instance doesn't exist just
8765 				 * skip to the next instance and let the
8766 				 * import note the missing instance.
8767 				 */
8768 				if (scf_service_get_instance(imp_svc,
8769 				    inst->sc_name, imp_inst) != 0)
8770 					continue;
8771 
8772 				if (uu_list_walk(inst->sc_pgroups,
8773 				    find_current_pg_type, inst,
8774 				    UU_DEFAULT) != 0) {
8775 					if (uu_error() !=
8776 					    UU_ERROR_CALLBACK_FAILED)
8777 						bad_error("uu_list_walk",
8778 						    uu_error());
8779 
8780 					ret = -1;
8781 					inst->sc_miss_type = B_TRUE;
8782 				}
8783 			}
8784 		}
8785 
8786 		/*
8787 		 * if we have pgs in the profile, we need to refresh ALL
8788 		 * instances of the service
8789 		 */
8790 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8791 			refresh = 1;
8792 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8793 			    SCI_FORCE | SCI_KEEP);
8794 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8795 			case IMPORT_NEXT:
8796 				break;
8797 
8798 			case IMPORT_OUT:
8799 				goto out;
8800 
8801 			case IMPORT_BAD:
8802 			default:
8803 				bad_error("lscf_import_service_pgs", r);
8804 			}
8805 		}
8806 
8807 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8808 			uu_list_walk(svc->sc_dependents,
8809 			    lscf_dependent_apply, svc, UU_DEFAULT);
8810 		}
8811 
8812 		for (inst = uu_list_first(
8813 		    svc->sc_u.sc_service.sc_service_instances);
8814 		    inst != NULL;
8815 		    inst = uu_list_next(
8816 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8817 			/*
8818 			 * This instance still has missing types
8819 			 * so skip it.
8820 			 */
8821 			if (inst->sc_miss_type) {
8822 				if (g_verbose)
8823 					warn(gettext("Ignoring instance "
8824 					    "%s:%s with missing types\n"),
8825 					    inst->sc_parent->sc_name,
8826 					    inst->sc_name);
8827 
8828 				continue;
8829 			}
8830 
8831 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8832 			    imp_inst) != 0) {
8833 				switch (scf_error()) {
8834 				case SCF_ERROR_NOT_FOUND:
8835 					if (g_verbose)
8836 						warn(gettext("Ignoring "
8837 						    "nonexistant instance "
8838 						    "%s:%s.\n"),
8839 						    inst->sc_parent->sc_name,
8840 						    inst->sc_name);
8841 					continue;
8842 
8843 				default:
8844 					scfdie();
8845 				}
8846 			}
8847 
8848 			/*
8849 			 * If the instance does not have a general/enabled
8850 			 * property and no last-import snapshot then the
8851 			 * instance is not a fully installed instance and
8852 			 * should not have a profile applied to it.
8853 			 *
8854 			 * This could happen if a service/instance declares
8855 			 * a dependent on behalf of another service/instance.
8856 			 *
8857 			 */
8858 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8859 			    imp_snap) != 0) {
8860 				if (scf_instance_get_pg(imp_inst,
8861 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8862 				    scf_pg_get_property(imp_pg,
8863 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8864 					if (g_verbose)
8865 						warn(gettext("Ignoreing "
8866 						    "partial instance "
8867 						    "%s:%s.\n"),
8868 						    inst->sc_parent->sc_name,
8869 						    inst->sc_name);
8870 					continue;
8871 				}
8872 			}
8873 
8874 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8875 			    inst, SCI_FORCE | SCI_KEEP);
8876 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8877 			case IMPORT_NEXT:
8878 				break;
8879 
8880 			case IMPORT_OUT:
8881 				goto out;
8882 
8883 			case IMPORT_BAD:
8884 			default:
8885 				bad_error("lscf_import_instance_pgs", r);
8886 			}
8887 
8888 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8889 				uu_list_walk(inst->sc_dependents,
8890 				    lscf_dependent_apply, inst, UU_DEFAULT);
8891 			}
8892 
8893 			/* refresh only if there is no pgs in the service */
8894 			if (refresh == 0)
8895 				(void) refresh_entity(0, imp_inst,
8896 				    inst->sc_fmri, NULL, NULL, NULL);
8897 		}
8898 
8899 		if (refresh == 1) {
8900 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8901 
8902 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8903 			    imp_inst, imp_iter, name_buf);
8904 			free(name_buf);
8905 		}
8906 
8907 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8908 		    old_dpt != NULL;
8909 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8910 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8911 			    old_dpt->sc_pgroup_name,
8912 			    old_dpt->sc_parent->sc_fmri) != 0) {
8913 				warn(gettext("Unable to refresh \"%s\"\n"),
8914 				    old_dpt->sc_pgroup_fmri);
8915 			}
8916 		}
8917 	}
8918 
8919 out:
8920 	if (annotation_set) {
8921 		/* Remove security audit annotation strings. */
8922 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8923 	}
8924 
8925 	free_imp_globals();
8926 	return (ret);
8927 }
8928 
8929 
8930 /*
8931  * Export.  These functions create and output an XML tree of a service
8932  * description from the repository.  This is largely the inverse of
8933  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8934  *
8935  * - We must include any properties which are not represented specifically by
8936  *   a service manifest, e.g., properties created by an admin post-import.  To
8937  *   do so we'll iterate through all properties and deal with each
8938  *   apropriately.
8939  *
8940  * - Children of services and instances must must be in the order set by the
8941  *   DTD, but we iterate over the properties in undefined order.  The elements
8942  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8943  *   number of classes of them, however, we'll keep the classes separate and
8944  *   assemble them in order.
8945  */
8946 
8947 /*
8948  * Convenience function to handle xmlSetProp errors (and type casting).
8949  */
8950 static void
8951 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8952 {
8953 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8954 		uu_die(gettext("Could not set XML property.\n"));
8955 }
8956 
8957 /*
8958  * Convenience function to set an XML attribute to the single value of an
8959  * astring property.  If the value happens to be the default, don't set the
8960  * attribute.  "dval" should be the default value supplied by the DTD, or
8961  * NULL for no default.
8962  */
8963 static int
8964 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8965     const char *name, const char *dval)
8966 {
8967 	scf_value_t *val;
8968 	ssize_t len;
8969 	char *str;
8970 
8971 	val = scf_value_create(g_hndl);
8972 	if (val == NULL)
8973 		scfdie();
8974 
8975 	if (prop_get_val(prop, val) != 0) {
8976 		scf_value_destroy(val);
8977 		return (-1);
8978 	}
8979 
8980 	len = scf_value_get_as_string(val, NULL, 0);
8981 	if (len < 0)
8982 		scfdie();
8983 
8984 	str = safe_malloc(len + 1);
8985 
8986 	if (scf_value_get_as_string(val, str, len + 1) < 0)
8987 		scfdie();
8988 
8989 	scf_value_destroy(val);
8990 
8991 	if (dval == NULL || strcmp(str, dval) != 0)
8992 		safe_setprop(n, name, str);
8993 
8994 	free(str);
8995 
8996 	return (0);
8997 }
8998 
8999 /*
9000  * As above, but the attribute is always set.
9001  */
9002 static int
9003 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9004 {
9005 	return (set_attr_from_prop_default(prop, n, name, NULL));
9006 }
9007 
9008 /*
9009  * Dump the given document onto f, with "'s replaced by ''s.
9010  */
9011 static int
9012 write_service_bundle(xmlDocPtr doc, FILE *f)
9013 {
9014 	xmlChar *mem;
9015 	int sz, i;
9016 
9017 	mem = NULL;
9018 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9019 
9020 	if (mem == NULL) {
9021 		semerr(gettext("Could not dump XML tree.\n"));
9022 		return (-1);
9023 	}
9024 
9025 	/*
9026 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
9027 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9028 	 * &apos; code?!
9029 	 */
9030 	for (i = 0; i < sz; ++i) {
9031 		char c = (char)mem[i];
9032 
9033 		if (c == '"')
9034 			(void) fputc('\'', f);
9035 		else if (c == '\'')
9036 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9037 		else
9038 			(void) fputc(c, f);
9039 	}
9040 
9041 	return (0);
9042 }
9043 
9044 /*
9045  * Create the DOM elements in elts necessary to (generically) represent prop
9046  * (i.e., a property or propval element).  If the name of the property is
9047  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9048  */
9049 static void
9050 export_property(scf_property_t *prop, const char *name_arg,
9051     struct pg_elts *elts, int flags)
9052 {
9053 	const char *type;
9054 	scf_error_t err = 0;
9055 	xmlNodePtr pnode, lnode;
9056 	char *lnname;
9057 	int ret;
9058 
9059 	/* name */
9060 	if (name_arg != NULL) {
9061 		(void) strcpy(exp_str, name_arg);
9062 	} else {
9063 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9064 			scfdie();
9065 	}
9066 
9067 	/* type */
9068 	type = prop_to_typestr(prop);
9069 	if (type == NULL)
9070 		uu_die(gettext("Can't export property %s: unknown type.\n"),
9071 		    exp_str);
9072 
9073 	/* If we're exporting values, and there's just one, export it here. */
9074 	if (!(flags & SCE_ALL_VALUES))
9075 		goto empty;
9076 
9077 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9078 		xmlNodePtr n;
9079 
9080 		/* Single value, so use propval */
9081 		n = xmlNewNode(NULL, (xmlChar *)"propval");
9082 		if (n == NULL)
9083 			uu_die(emsg_create_xml);
9084 
9085 		safe_setprop(n, name_attr, exp_str);
9086 		safe_setprop(n, type_attr, type);
9087 
9088 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9089 			scfdie();
9090 		safe_setprop(n, value_attr, exp_str);
9091 
9092 		if (elts->propvals == NULL)
9093 			elts->propvals = n;
9094 		else
9095 			(void) xmlAddSibling(elts->propvals, n);
9096 
9097 		return;
9098 	}
9099 
9100 	err = scf_error();
9101 
9102 	if (err == SCF_ERROR_PERMISSION_DENIED) {
9103 		semerr(emsg_permission_denied);
9104 		return;
9105 	}
9106 
9107 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9108 	    err != SCF_ERROR_NOT_FOUND &&
9109 	    err != SCF_ERROR_PERMISSION_DENIED)
9110 		scfdie();
9111 
9112 empty:
9113 	/* Multiple (or no) values, so use property */
9114 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
9115 	if (pnode == NULL)
9116 		uu_die(emsg_create_xml);
9117 
9118 	safe_setprop(pnode, name_attr, exp_str);
9119 	safe_setprop(pnode, type_attr, type);
9120 
9121 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9122 		lnname = uu_msprintf("%s_list", type);
9123 		if (lnname == NULL)
9124 			uu_die(gettext("Could not create string"));
9125 
9126 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9127 		if (lnode == NULL)
9128 			uu_die(emsg_create_xml);
9129 
9130 		uu_free(lnname);
9131 
9132 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9133 			scfdie();
9134 
9135 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9136 		    1) {
9137 			xmlNodePtr vn;
9138 
9139 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9140 			    NULL);
9141 			if (vn == NULL)
9142 				uu_die(emsg_create_xml);
9143 
9144 			if (scf_value_get_as_string(exp_val, exp_str,
9145 			    exp_str_sz) < 0)
9146 				scfdie();
9147 			safe_setprop(vn, value_attr, exp_str);
9148 		}
9149 		if (ret != 0)
9150 			scfdie();
9151 	}
9152 
9153 	if (elts->properties == NULL)
9154 		elts->properties = pnode;
9155 	else
9156 		(void) xmlAddSibling(elts->properties, pnode);
9157 }
9158 
9159 /*
9160  * Add a property_group element for this property group to elts.
9161  */
9162 static void
9163 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9164 {
9165 	xmlNodePtr n;
9166 	struct pg_elts elts;
9167 	int ret;
9168 	boolean_t read_protected;
9169 
9170 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
9171 
9172 	/* name */
9173 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9174 		scfdie();
9175 	safe_setprop(n, name_attr, exp_str);
9176 
9177 	/* type */
9178 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9179 		scfdie();
9180 	safe_setprop(n, type_attr, exp_str);
9181 
9182 	/* properties */
9183 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9184 		scfdie();
9185 
9186 	(void) memset(&elts, 0, sizeof (elts));
9187 
9188 	/*
9189 	 * If this property group is not read protected, we always want to
9190 	 * output all the values.  Otherwise, we only output the values if the
9191 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9192 	 */
9193 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9194 		scfdie();
9195 
9196 	if (!read_protected)
9197 		flags |= SCE_ALL_VALUES;
9198 
9199 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9200 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9201 			scfdie();
9202 
9203 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9204 			xmlNodePtr m;
9205 
9206 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9207 			if (m == NULL)
9208 				uu_die(emsg_create_xml);
9209 
9210 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9211 				elts.stability = m;
9212 				continue;
9213 			}
9214 
9215 			xmlFreeNode(m);
9216 		}
9217 
9218 		export_property(exp_prop, NULL, &elts, flags);
9219 	}
9220 	if (ret == -1)
9221 		scfdie();
9222 
9223 	(void) xmlAddChild(n, elts.stability);
9224 	(void) xmlAddChildList(n, elts.propvals);
9225 	(void) xmlAddChildList(n, elts.properties);
9226 
9227 	if (eelts->property_groups == NULL)
9228 		eelts->property_groups = n;
9229 	else
9230 		(void) xmlAddSibling(eelts->property_groups, n);
9231 }
9232 
9233 /*
9234  * Create an XML node representing the dependency described by the given
9235  * property group and put it in eelts.  Unless the dependency is not valid, in
9236  * which case create a generic property_group element which represents it and
9237  * put it in eelts.
9238  */
9239 static void
9240 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9241 {
9242 	xmlNodePtr n;
9243 	int err = 0, ret;
9244 	struct pg_elts elts;
9245 
9246 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
9247 	if (n == NULL)
9248 		uu_die(emsg_create_xml);
9249 
9250 	/*
9251 	 * If the external flag is present, skip this dependency because it
9252 	 * should have been created by another manifest.
9253 	 */
9254 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9255 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9256 		    prop_get_val(exp_prop, exp_val) == 0) {
9257 			uint8_t b;
9258 
9259 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9260 				scfdie();
9261 
9262 			if (b)
9263 				return;
9264 		}
9265 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
9266 		scfdie();
9267 
9268 	/* Get the required attributes. */
9269 
9270 	/* name */
9271 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9272 		scfdie();
9273 	safe_setprop(n, name_attr, exp_str);
9274 
9275 	/* grouping */
9276 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9277 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9278 		err = 1;
9279 
9280 	/* restart_on */
9281 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9282 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9283 		err = 1;
9284 
9285 	/* type */
9286 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9287 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9288 		err = 1;
9289 
9290 	/*
9291 	 * entities: Not required, but if we create no children, it will be
9292 	 * created as empty on import, so fail if it's missing.
9293 	 */
9294 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9295 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9296 		scf_iter_t *eiter;
9297 		int ret2;
9298 
9299 		eiter = scf_iter_create(g_hndl);
9300 		if (eiter == NULL)
9301 			scfdie();
9302 
9303 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9304 			scfdie();
9305 
9306 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9307 			xmlNodePtr ch;
9308 
9309 			if (scf_value_get_astring(exp_val, exp_str,
9310 			    exp_str_sz) < 0)
9311 				scfdie();
9312 
9313 			/*
9314 			 * service_fmri's must be first, so we can add them
9315 			 * here.
9316 			 */
9317 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9318 			    NULL);
9319 			if (ch == NULL)
9320 				uu_die(emsg_create_xml);
9321 
9322 			safe_setprop(ch, value_attr, exp_str);
9323 		}
9324 		if (ret2 == -1)
9325 			scfdie();
9326 
9327 		scf_iter_destroy(eiter);
9328 	} else
9329 		err = 1;
9330 
9331 	if (err) {
9332 		xmlFreeNode(n);
9333 
9334 		export_pg(pg, eelts, SCE_ALL_VALUES);
9335 
9336 		return;
9337 	}
9338 
9339 	/* Iterate through the properties & handle each. */
9340 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9341 		scfdie();
9342 
9343 	(void) memset(&elts, 0, sizeof (elts));
9344 
9345 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9346 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9347 			scfdie();
9348 
9349 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9350 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9351 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9352 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9353 			continue;
9354 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9355 			xmlNodePtr m;
9356 
9357 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9358 			if (m == NULL)
9359 				uu_die(emsg_create_xml);
9360 
9361 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9362 				elts.stability = m;
9363 				continue;
9364 			}
9365 
9366 			xmlFreeNode(m);
9367 		}
9368 
9369 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9370 	}
9371 	if (ret == -1)
9372 		scfdie();
9373 
9374 	(void) xmlAddChild(n, elts.stability);
9375 	(void) xmlAddChildList(n, elts.propvals);
9376 	(void) xmlAddChildList(n, elts.properties);
9377 
9378 	if (eelts->dependencies == NULL)
9379 		eelts->dependencies = n;
9380 	else
9381 		(void) xmlAddSibling(eelts->dependencies, n);
9382 }
9383 
9384 static xmlNodePtr
9385 export_method_environment(scf_propertygroup_t *pg)
9386 {
9387 	xmlNodePtr env;
9388 	int ret;
9389 	int children = 0;
9390 
9391 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9392 		return (NULL);
9393 
9394 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9395 	if (env == NULL)
9396 		uu_die(emsg_create_xml);
9397 
9398 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9399 		scfdie();
9400 
9401 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9402 		scfdie();
9403 
9404 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9405 		xmlNodePtr ev;
9406 		char *cp;
9407 
9408 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9409 			scfdie();
9410 
9411 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9412 			warn(gettext("Invalid environment variable \"%s\".\n"),
9413 			    exp_str);
9414 			continue;
9415 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9416 			warn(gettext("Invalid environment variable \"%s\"; "
9417 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9418 			continue;
9419 		}
9420 
9421 		*cp = '\0';
9422 		cp++;
9423 
9424 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9425 		if (ev == NULL)
9426 			uu_die(emsg_create_xml);
9427 
9428 		safe_setprop(ev, name_attr, exp_str);
9429 		safe_setprop(ev, value_attr, cp);
9430 		children++;
9431 	}
9432 
9433 	if (ret != 0)
9434 		scfdie();
9435 
9436 	if (children == 0) {
9437 		xmlFreeNode(env);
9438 		return (NULL);
9439 	}
9440 
9441 	return (env);
9442 }
9443 
9444 /*
9445  * As above, but for a method property group.
9446  */
9447 static void
9448 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9449 {
9450 	xmlNodePtr n, env;
9451 	char *str;
9452 	int err = 0, nonenv, ret;
9453 	uint8_t use_profile;
9454 	struct pg_elts elts;
9455 	xmlNodePtr ctxt = NULL;
9456 
9457 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9458 
9459 	/* Get the required attributes. */
9460 
9461 	/* name */
9462 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9463 		scfdie();
9464 	safe_setprop(n, name_attr, exp_str);
9465 
9466 	/* type */
9467 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9468 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9469 		err = 1;
9470 
9471 	/* exec */
9472 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9473 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9474 		err = 1;
9475 
9476 	/* timeout */
9477 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9478 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9479 	    prop_get_val(exp_prop, exp_val) == 0) {
9480 		uint64_t c;
9481 
9482 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9483 			scfdie();
9484 
9485 		str = uu_msprintf("%llu", c);
9486 		if (str == NULL)
9487 			uu_die(gettext("Could not create string"));
9488 
9489 		safe_setprop(n, "timeout_seconds", str);
9490 		free(str);
9491 	} else
9492 		err = 1;
9493 
9494 	if (err) {
9495 		xmlFreeNode(n);
9496 
9497 		export_pg(pg, eelts, SCE_ALL_VALUES);
9498 
9499 		return;
9500 	}
9501 
9502 
9503 	/*
9504 	 * If we're going to have a method_context child, we need to know
9505 	 * before we iterate through the properties.  Since method_context's
9506 	 * are optional, we don't want to complain about any properties
9507 	 * missing if none of them are there.  Thus we can't use the
9508 	 * convenience functions.
9509 	 */
9510 	nonenv =
9511 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9512 	    SCF_SUCCESS ||
9513 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9514 	    SCF_SUCCESS ||
9515 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9516 	    SCF_SUCCESS ||
9517 	    scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9518 	    SCF_SUCCESS ||
9519 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9520 	    SCF_SUCCESS;
9521 
9522 	if (nonenv) {
9523 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9524 		if (ctxt == NULL)
9525 			uu_die(emsg_create_xml);
9526 
9527 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9528 		    0 &&
9529 		    set_attr_from_prop_default(exp_prop, ctxt,
9530 		    "working_directory", ":default") != 0)
9531 			err = 1;
9532 
9533 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9534 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9535 		    ":default") != 0)
9536 			err = 1;
9537 
9538 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9539 		    0 &&
9540 		    set_attr_from_prop_default(exp_prop, ctxt,
9541 		    "resource_pool", ":default") != 0)
9542 			err = 1;
9543 
9544 		if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9545 		    set_attr_from_prop_default(exp_prop, ctxt,
9546 		    "security_flags", ":default") != 0)
9547 			err = 1;
9548 
9549 		/*
9550 		 * We only want to complain about profile or credential
9551 		 * properties if we will use them.  To determine that we must
9552 		 * examine USE_PROFILE.
9553 		 */
9554 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9555 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9556 		    prop_get_val(exp_prop, exp_val) == 0) {
9557 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9558 			    SCF_SUCCESS) {
9559 				scfdie();
9560 			}
9561 
9562 			if (use_profile) {
9563 				xmlNodePtr prof;
9564 
9565 				prof = xmlNewChild(ctxt, NULL,
9566 				    (xmlChar *)"method_profile", NULL);
9567 				if (prof == NULL)
9568 					uu_die(emsg_create_xml);
9569 
9570 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9571 				    exp_prop) != 0 ||
9572 				    set_attr_from_prop(exp_prop, prof,
9573 				    name_attr) != 0)
9574 					err = 1;
9575 			} else {
9576 				xmlNodePtr cred;
9577 
9578 				cred = xmlNewChild(ctxt, NULL,
9579 				    (xmlChar *)"method_credential", NULL);
9580 				if (cred == NULL)
9581 					uu_die(emsg_create_xml);
9582 
9583 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9584 				    exp_prop) != 0 ||
9585 				    set_attr_from_prop(exp_prop, cred,
9586 				    "user") != 0) {
9587 					err = 1;
9588 				}
9589 
9590 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9591 				    exp_prop) == 0 &&
9592 				    set_attr_from_prop_default(exp_prop, cred,
9593 				    "group", ":default") != 0)
9594 					err = 1;
9595 
9596 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9597 				    exp_prop) == 0 &&
9598 				    set_attr_from_prop_default(exp_prop, cred,
9599 				    "supp_groups", ":default") != 0)
9600 					err = 1;
9601 
9602 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9603 				    exp_prop) == 0 &&
9604 				    set_attr_from_prop_default(exp_prop, cred,
9605 				    "privileges", ":default") != 0)
9606 					err = 1;
9607 
9608 				if (pg_get_prop(pg,
9609 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9610 				    exp_prop) == 0 &&
9611 				    set_attr_from_prop_default(exp_prop, cred,
9612 				    "limit_privileges", ":default") != 0)
9613 					err = 1;
9614 			}
9615 		}
9616 	}
9617 
9618 	if ((env = export_method_environment(pg)) != NULL) {
9619 		if (ctxt == NULL) {
9620 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9621 			if (ctxt == NULL)
9622 				uu_die(emsg_create_xml);
9623 		}
9624 		(void) xmlAddChild(ctxt, env);
9625 	}
9626 
9627 	if (env != NULL || (nonenv && err == 0))
9628 		(void) xmlAddChild(n, ctxt);
9629 	else
9630 		xmlFreeNode(ctxt);
9631 
9632 	nonenv = (err == 0);
9633 
9634 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9635 		scfdie();
9636 
9637 	(void) memset(&elts, 0, sizeof (elts));
9638 
9639 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9640 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9641 			scfdie();
9642 
9643 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9644 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9645 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9646 			continue;
9647 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9648 			xmlNodePtr m;
9649 
9650 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9651 			if (m == NULL)
9652 				uu_die(emsg_create_xml);
9653 
9654 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9655 				elts.stability = m;
9656 				continue;
9657 			}
9658 
9659 			xmlFreeNode(m);
9660 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9661 		    0 ||
9662 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9663 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9664 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9665 			if (nonenv)
9666 				continue;
9667 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9668 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9669 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9670 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9671 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9672 		    strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9673 			if (nonenv && !use_profile)
9674 				continue;
9675 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9676 			if (nonenv && use_profile)
9677 				continue;
9678 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9679 			if (env != NULL)
9680 				continue;
9681 		}
9682 
9683 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9684 	}
9685 	if (ret == -1)
9686 		scfdie();
9687 
9688 	(void) xmlAddChild(n, elts.stability);
9689 	(void) xmlAddChildList(n, elts.propvals);
9690 	(void) xmlAddChildList(n, elts.properties);
9691 
9692 	if (eelts->exec_methods == NULL)
9693 		eelts->exec_methods = n;
9694 	else
9695 		(void) xmlAddSibling(eelts->exec_methods, n);
9696 }
9697 
9698 static void
9699 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9700     struct entity_elts *eelts)
9701 {
9702 	xmlNodePtr pgnode;
9703 
9704 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9705 	if (pgnode == NULL)
9706 		uu_die(emsg_create_xml);
9707 
9708 	safe_setprop(pgnode, name_attr, name);
9709 	safe_setprop(pgnode, type_attr, type);
9710 
9711 	(void) xmlAddChildList(pgnode, elts->propvals);
9712 	(void) xmlAddChildList(pgnode, elts->properties);
9713 
9714 	if (eelts->property_groups == NULL)
9715 		eelts->property_groups = pgnode;
9716 	else
9717 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9718 }
9719 
9720 /*
9721  * Process the general property group for a service.  This is the one with the
9722  * goodies.
9723  */
9724 static void
9725 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9726 {
9727 	struct pg_elts elts;
9728 	int ret;
9729 
9730 	/*
9731 	 * In case there are properties which don't correspond to child
9732 	 * entities of the service entity, we'll set up a pg_elts structure to
9733 	 * put them in.
9734 	 */
9735 	(void) memset(&elts, 0, sizeof (elts));
9736 
9737 	/* Walk the properties, looking for special ones. */
9738 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9739 		scfdie();
9740 
9741 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9742 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9743 			scfdie();
9744 
9745 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9746 			/*
9747 			 * Unimplemented and obsolete, but we still process it
9748 			 * for compatibility purposes.
9749 			 */
9750 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9751 			    prop_get_val(exp_prop, exp_val) == 0) {
9752 				uint8_t b;
9753 
9754 				if (scf_value_get_boolean(exp_val, &b) !=
9755 				    SCF_SUCCESS)
9756 					scfdie();
9757 
9758 				if (b) {
9759 					selts->single_instance =
9760 					    xmlNewNode(NULL,
9761 					    (xmlChar *)"single_instance");
9762 					if (selts->single_instance == NULL)
9763 						uu_die(emsg_create_xml);
9764 				}
9765 
9766 				continue;
9767 			}
9768 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9769 			xmlNodePtr rnode, sfnode;
9770 
9771 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9772 			if (rnode == NULL)
9773 				uu_die(emsg_create_xml);
9774 
9775 			sfnode = xmlNewChild(rnode, NULL,
9776 			    (xmlChar *)"service_fmri", NULL);
9777 			if (sfnode == NULL)
9778 				uu_die(emsg_create_xml);
9779 
9780 			if (set_attr_from_prop(exp_prop, sfnode,
9781 			    value_attr) == 0) {
9782 				selts->restarter = rnode;
9783 				continue;
9784 			}
9785 
9786 			xmlFreeNode(rnode);
9787 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9788 		    0) {
9789 			xmlNodePtr s;
9790 
9791 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9792 			if (s == NULL)
9793 				uu_die(emsg_create_xml);
9794 
9795 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9796 				selts->stability = s;
9797 				continue;
9798 			}
9799 
9800 			xmlFreeNode(s);
9801 		}
9802 
9803 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9804 	}
9805 	if (ret == -1)
9806 		scfdie();
9807 
9808 	if (elts.propvals != NULL || elts.properties != NULL)
9809 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9810 		    selts);
9811 }
9812 
9813 static void
9814 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9815 {
9816 	xmlNodePtr n, prof, cred, env;
9817 	uint8_t use_profile;
9818 	int ret, err = 0;
9819 
9820 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9821 
9822 	env = export_method_environment(pg);
9823 
9824 	/* Need to know whether we'll use a profile or not. */
9825 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9826 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9827 	    prop_get_val(exp_prop, exp_val) == 0) {
9828 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9829 			scfdie();
9830 
9831 		if (use_profile)
9832 			prof =
9833 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9834 			    NULL);
9835 		else
9836 			cred =
9837 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9838 			    NULL);
9839 	}
9840 
9841 	if (env != NULL)
9842 		(void) xmlAddChild(n, env);
9843 
9844 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9845 		scfdie();
9846 
9847 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9848 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9849 			scfdie();
9850 
9851 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9852 			if (set_attr_from_prop(exp_prop, n,
9853 			    "working_directory") != 0)
9854 				err = 1;
9855 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9856 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9857 				err = 1;
9858 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9859 			if (set_attr_from_prop(exp_prop, n,
9860 			    "resource_pool") != 0)
9861 				err = 1;
9862 		} else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9863 			if (set_attr_from_prop(exp_prop, n,
9864 			    "security_flags") != 0)
9865 				err = 1;
9866 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9867 			/* EMPTY */
9868 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9869 			if (use_profile ||
9870 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9871 				err = 1;
9872 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9873 			if (use_profile ||
9874 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9875 				err = 1;
9876 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9877 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9878 			    "supp_groups") != 0)
9879 				err = 1;
9880 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9881 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9882 			    "privileges") != 0)
9883 				err = 1;
9884 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9885 		    0) {
9886 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9887 			    "limit_privileges") != 0)
9888 				err = 1;
9889 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9890 			if (!use_profile || set_attr_from_prop(exp_prop,
9891 			    prof, name_attr) != 0)
9892 				err = 1;
9893 		} else {
9894 			/* Can't have generic properties in method_context's */
9895 			err = 1;
9896 		}
9897 	}
9898 	if (ret == -1)
9899 		scfdie();
9900 
9901 	if (err && env == NULL) {
9902 		xmlFreeNode(n);
9903 		export_pg(pg, elts, SCE_ALL_VALUES);
9904 		return;
9905 	}
9906 
9907 	elts->method_context = n;
9908 }
9909 
9910 /*
9911  * Given a dependency property group in the tfmri entity (target fmri), return
9912  * a dependent element which represents it.
9913  */
9914 static xmlNodePtr
9915 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9916 {
9917 	uint8_t b;
9918 	xmlNodePtr n, sf;
9919 	int err = 0, ret;
9920 	struct pg_elts pgelts;
9921 
9922 	/*
9923 	 * If external isn't set to true then exporting the service will
9924 	 * export this as a normal dependency, so we should stop to avoid
9925 	 * duplication.
9926 	 */
9927 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9928 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9929 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9930 		if (g_verbose) {
9931 			warn(gettext("Dependent \"%s\" cannot be exported "
9932 			    "properly because the \"%s\" property of the "
9933 			    "\"%s\" dependency of %s is not set to true.\n"),
9934 			    name, scf_property_external, name, tfmri);
9935 		}
9936 
9937 		return (NULL);
9938 	}
9939 
9940 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9941 	if (n == NULL)
9942 		uu_die(emsg_create_xml);
9943 
9944 	safe_setprop(n, name_attr, name);
9945 
9946 	/* Get the required attributes */
9947 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9948 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9949 		err = 1;
9950 
9951 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9952 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9953 		err = 1;
9954 
9955 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9956 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9957 	    prop_get_val(exp_prop, exp_val) == 0) {
9958 		/* EMPTY */
9959 	} else
9960 		err = 1;
9961 
9962 	if (err) {
9963 		xmlFreeNode(n);
9964 		return (NULL);
9965 	}
9966 
9967 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9968 	if (sf == NULL)
9969 		uu_die(emsg_create_xml);
9970 
9971 	safe_setprop(sf, value_attr, tfmri);
9972 
9973 	/*
9974 	 * Now add elements for the other properties.
9975 	 */
9976 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9977 		scfdie();
9978 
9979 	(void) memset(&pgelts, 0, sizeof (pgelts));
9980 
9981 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9982 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9983 			scfdie();
9984 
9985 		if (strcmp(exp_str, scf_property_external) == 0 ||
9986 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9987 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9988 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9989 			continue;
9990 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9991 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9992 			    prop_get_val(exp_prop, exp_val) == 0) {
9993 				char type[sizeof ("service") + 1];
9994 
9995 				if (scf_value_get_astring(exp_val, type,
9996 				    sizeof (type)) < 0)
9997 					scfdie();
9998 
9999 				if (strcmp(type, "service") == 0)
10000 					continue;
10001 			}
10002 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
10003 			xmlNodePtr s;
10004 
10005 			s = xmlNewNode(NULL, (xmlChar *)"stability");
10006 			if (s == NULL)
10007 				uu_die(emsg_create_xml);
10008 
10009 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10010 				pgelts.stability = s;
10011 				continue;
10012 			}
10013 
10014 			xmlFreeNode(s);
10015 		}
10016 
10017 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10018 	}
10019 	if (ret == -1)
10020 		scfdie();
10021 
10022 	(void) xmlAddChild(n, pgelts.stability);
10023 	(void) xmlAddChildList(n, pgelts.propvals);
10024 	(void) xmlAddChildList(n, pgelts.properties);
10025 
10026 	return (n);
10027 }
10028 
10029 static void
10030 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10031 {
10032 	scf_propertygroup_t *opg;
10033 	scf_iter_t *iter;
10034 	char *type, *fmri;
10035 	int ret;
10036 	struct pg_elts pgelts;
10037 	xmlNodePtr n;
10038 	scf_error_t serr;
10039 
10040 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
10041 	    (iter = scf_iter_create(g_hndl)) == NULL)
10042 		scfdie();
10043 
10044 	/* Can't use exp_prop_iter due to export_dependent(). */
10045 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10046 		scfdie();
10047 
10048 	type = safe_malloc(max_scf_pg_type_len + 1);
10049 
10050 	/* Get an extra byte so we can tell if values are too long. */
10051 	fmri = safe_malloc(max_scf_fmri_len + 2);
10052 
10053 	(void) memset(&pgelts, 0, sizeof (pgelts));
10054 
10055 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10056 		void *entity;
10057 		int isservice;
10058 		scf_type_t ty;
10059 
10060 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10061 			scfdie();
10062 
10063 		if ((ty != SCF_TYPE_ASTRING &&
10064 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10065 		    prop_get_val(exp_prop, exp_val) != 0) {
10066 			export_property(exp_prop, NULL, &pgelts,
10067 			    SCE_ALL_VALUES);
10068 			continue;
10069 		}
10070 
10071 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10072 			scfdie();
10073 
10074 		if (scf_value_get_astring(exp_val, fmri,
10075 		    max_scf_fmri_len + 2) < 0)
10076 			scfdie();
10077 
10078 		/* Look for a dependency group in the target fmri. */
10079 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10080 		switch (serr) {
10081 		case SCF_ERROR_NONE:
10082 			break;
10083 
10084 		case SCF_ERROR_NO_MEMORY:
10085 			uu_die(gettext("Out of memory.\n"));
10086 			/* NOTREACHED */
10087 
10088 		case SCF_ERROR_INVALID_ARGUMENT:
10089 			if (g_verbose) {
10090 				if (scf_property_to_fmri(exp_prop, fmri,
10091 				    max_scf_fmri_len + 2) < 0)
10092 					scfdie();
10093 
10094 				warn(gettext("The value of %s is not a valid "
10095 				    "FMRI.\n"), fmri);
10096 			}
10097 
10098 			export_property(exp_prop, exp_str, &pgelts,
10099 			    SCE_ALL_VALUES);
10100 			continue;
10101 
10102 		case SCF_ERROR_CONSTRAINT_VIOLATED:
10103 			if (g_verbose) {
10104 				if (scf_property_to_fmri(exp_prop, fmri,
10105 				    max_scf_fmri_len + 2) < 0)
10106 					scfdie();
10107 
10108 				warn(gettext("The value of %s does not specify "
10109 				    "a service or an instance.\n"), fmri);
10110 			}
10111 
10112 			export_property(exp_prop, exp_str, &pgelts,
10113 			    SCE_ALL_VALUES);
10114 			continue;
10115 
10116 		case SCF_ERROR_NOT_FOUND:
10117 			if (g_verbose) {
10118 				if (scf_property_to_fmri(exp_prop, fmri,
10119 				    max_scf_fmri_len + 2) < 0)
10120 					scfdie();
10121 
10122 				warn(gettext("The entity specified by %s does "
10123 				    "not exist.\n"), fmri);
10124 			}
10125 
10126 			export_property(exp_prop, exp_str, &pgelts,
10127 			    SCE_ALL_VALUES);
10128 			continue;
10129 
10130 		default:
10131 #ifndef NDEBUG
10132 			(void) fprintf(stderr, "%s:%d: %s() failed with "
10133 			    "unexpected error %d.\n", __FILE__, __LINE__,
10134 			    "fmri_to_entity", serr);
10135 #endif
10136 			abort();
10137 		}
10138 
10139 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10140 			if (scf_error() != SCF_ERROR_NOT_FOUND)
10141 				scfdie();
10142 
10143 			warn(gettext("Entity %s is missing dependency property "
10144 			    "group %s.\n"), fmri, exp_str);
10145 
10146 			export_property(exp_prop, NULL, &pgelts,
10147 			    SCE_ALL_VALUES);
10148 			continue;
10149 		}
10150 
10151 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10152 			scfdie();
10153 
10154 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10155 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10156 				scfdie();
10157 
10158 			warn(gettext("Property group %s is not of "
10159 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10160 
10161 			export_property(exp_prop, NULL, &pgelts,
10162 			    SCE_ALL_VALUES);
10163 			continue;
10164 		}
10165 
10166 		n = export_dependent(opg, exp_str, fmri);
10167 		if (n == NULL) {
10168 			export_property(exp_prop, exp_str, &pgelts,
10169 			    SCE_ALL_VALUES);
10170 		} else {
10171 			if (eelts->dependents == NULL)
10172 				eelts->dependents = n;
10173 			else
10174 				(void) xmlAddSibling(eelts->dependents,
10175 				    n);
10176 		}
10177 	}
10178 	if (ret == -1)
10179 		scfdie();
10180 
10181 	free(fmri);
10182 	free(type);
10183 
10184 	scf_iter_destroy(iter);
10185 	scf_pg_destroy(opg);
10186 
10187 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10188 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10189 		    eelts);
10190 }
10191 
10192 static void
10193 make_node(xmlNodePtr *nodep, const char *name)
10194 {
10195 	if (*nodep == NULL) {
10196 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
10197 		if (*nodep == NULL)
10198 			uu_die(emsg_create_xml);
10199 	}
10200 }
10201 
10202 static xmlNodePtr
10203 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10204 {
10205 	int ret;
10206 	xmlNodePtr parent = NULL;
10207 	xmlNodePtr loctext = NULL;
10208 
10209 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10210 		scfdie();
10211 
10212 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10213 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10214 		    prop_get_val(exp_prop, exp_val) != 0)
10215 			continue;
10216 
10217 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10218 			scfdie();
10219 
10220 		make_node(&parent, parname);
10221 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10222 		    (xmlChar *)exp_str);
10223 		if (loctext == NULL)
10224 			uu_die(emsg_create_xml);
10225 
10226 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10227 			scfdie();
10228 
10229 		safe_setprop(loctext, "xml:lang", exp_str);
10230 	}
10231 
10232 	if (ret == -1)
10233 		scfdie();
10234 
10235 	return (parent);
10236 }
10237 
10238 static xmlNodePtr
10239 export_tm_manpage(scf_propertygroup_t *pg)
10240 {
10241 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10242 	if (manpage == NULL)
10243 		uu_die(emsg_create_xml);
10244 
10245 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10246 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10247 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10248 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10249 		xmlFreeNode(manpage);
10250 		return (NULL);
10251 	}
10252 
10253 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10254 		(void) set_attr_from_prop_default(exp_prop,
10255 		    manpage, "manpath", ":default");
10256 
10257 	return (manpage);
10258 }
10259 
10260 static xmlNodePtr
10261 export_tm_doc_link(scf_propertygroup_t *pg)
10262 {
10263 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10264 	if (doc_link == NULL)
10265 		uu_die(emsg_create_xml);
10266 
10267 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10268 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10269 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10270 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10271 		xmlFreeNode(doc_link);
10272 		return (NULL);
10273 	}
10274 	return (doc_link);
10275 }
10276 
10277 /*
10278  * Process template information for a service or instances.
10279  */
10280 static void
10281 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10282     struct template_elts *telts)
10283 {
10284 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10285 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10286 	xmlNodePtr child = NULL;
10287 
10288 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10289 		scfdie();
10290 
10291 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10292 		telts->common_name = export_tm_loctext(pg, "common_name");
10293 		if (telts->common_name == NULL)
10294 			export_pg(pg, elts, SCE_ALL_VALUES);
10295 		return;
10296 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10297 		telts->description = export_tm_loctext(pg, "description");
10298 		if (telts->description == NULL)
10299 			export_pg(pg, elts, SCE_ALL_VALUES);
10300 		return;
10301 	}
10302 
10303 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10304 		child = export_tm_manpage(pg);
10305 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10306 		child = export_tm_doc_link(pg);
10307 	}
10308 
10309 	if (child != NULL) {
10310 		make_node(&telts->documentation, "documentation");
10311 		(void) xmlAddChild(telts->documentation, child);
10312 	} else {
10313 		export_pg(pg, elts, SCE_ALL_VALUES);
10314 	}
10315 }
10316 
10317 /*
10318  * Process parameter and paramval elements
10319  */
10320 static void
10321 export_parameter(scf_property_t *prop, const char *name,
10322     struct params_elts *elts)
10323 {
10324 	xmlNodePtr param;
10325 	scf_error_t err = 0;
10326 	int ret;
10327 
10328 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10329 		if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10330 			uu_die(emsg_create_xml);
10331 
10332 		safe_setprop(param, name_attr, name);
10333 
10334 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10335 			scfdie();
10336 		safe_setprop(param, value_attr, exp_str);
10337 
10338 		if (elts->paramval == NULL)
10339 			elts->paramval = param;
10340 		else
10341 			(void) xmlAddSibling(elts->paramval, param);
10342 
10343 		return;
10344 	}
10345 
10346 	err = scf_error();
10347 
10348 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10349 	    err != SCF_ERROR_NOT_FOUND)
10350 		scfdie();
10351 
10352 	if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10353 		uu_die(emsg_create_xml);
10354 
10355 	safe_setprop(param, name_attr, name);
10356 
10357 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10358 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10359 			scfdie();
10360 
10361 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10362 		    1) {
10363 			xmlNodePtr vn;
10364 
10365 			if ((vn = xmlNewChild(param, NULL,
10366 			    (xmlChar *)"value_node", NULL)) == NULL)
10367 				uu_die(emsg_create_xml);
10368 
10369 			if (scf_value_get_as_string(exp_val, exp_str,
10370 			    exp_str_sz) < 0)
10371 				scfdie();
10372 
10373 			safe_setprop(vn, value_attr, exp_str);
10374 		}
10375 		if (ret != 0)
10376 			scfdie();
10377 	}
10378 
10379 	if (elts->parameter == NULL)
10380 		elts->parameter = param;
10381 	else
10382 		(void) xmlAddSibling(elts->parameter, param);
10383 }
10384 
10385 /*
10386  * Process notification parameters for a service or instance
10387  */
10388 static void
10389 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10390 {
10391 	xmlNodePtr n, event, *type;
10392 	struct params_elts *eelts;
10393 	int ret, err, i;
10394 	char *s;
10395 
10396 	n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10397 	event = xmlNewNode(NULL, (xmlChar *)"event");
10398 	if (n == NULL || event == NULL)
10399 		uu_die(emsg_create_xml);
10400 
10401 	/* event value */
10402 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10403 		scfdie();
10404 	/* trim SCF_NOTIFY_PG_POSTFIX appended to name on import */
10405 	if ((s = strchr(exp_str, ',')) != NULL)
10406 		*s = '\0';
10407 	safe_setprop(event, value_attr, exp_str);
10408 
10409 	(void) xmlAddChild(n, event);
10410 
10411 	if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10412 	    (eelts = calloc(URI_SCHEME_NUM,
10413 	    sizeof (struct params_elts))) == NULL)
10414 		uu_die(gettext("Out of memory.\n"));
10415 
10416 	err = 0;
10417 
10418 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10419 		scfdie();
10420 
10421 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10422 		char *t, *p;
10423 
10424 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10425 			scfdie();
10426 
10427 		if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10428 			/*
10429 			 * this is not a well formed notification parameters
10430 			 * element, we should export as regular pg
10431 			 */
10432 			err = 1;
10433 			break;
10434 		}
10435 
10436 		if ((i = check_uri_protocol(t)) < 0) {
10437 			err = 1;
10438 			break;
10439 		}
10440 
10441 		if (type[i] == NULL) {
10442 			if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10443 			    NULL)
10444 				uu_die(emsg_create_xml);
10445 
10446 			safe_setprop(type[i], name_attr, t);
10447 		}
10448 		if (strcmp(p, active_attr) == 0) {
10449 			if (set_attr_from_prop(exp_prop, type[i],
10450 			    active_attr) != 0) {
10451 				err = 1;
10452 				break;
10453 			}
10454 			continue;
10455 		}
10456 		/*
10457 		 * We export the parameter
10458 		 */
10459 		export_parameter(exp_prop, p, &eelts[i]);
10460 	}
10461 
10462 	if (ret == -1)
10463 		scfdie();
10464 
10465 	if (err == 1) {
10466 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10467 			xmlFree(type[i]);
10468 		free(type);
10469 
10470 		export_pg(pg, elts, SCE_ALL_VALUES);
10471 
10472 		return;
10473 	} else {
10474 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10475 			if (type[i] != NULL) {
10476 				(void) xmlAddChildList(type[i],
10477 				    eelts[i].paramval);
10478 				(void) xmlAddChildList(type[i],
10479 				    eelts[i].parameter);
10480 				(void) xmlAddSibling(event, type[i]);
10481 			}
10482 	}
10483 	free(type);
10484 
10485 	if (elts->notify_params == NULL)
10486 		elts->notify_params = n;
10487 	else
10488 		(void) xmlAddSibling(elts->notify_params, n);
10489 }
10490 
10491 /*
10492  * Process the general property group for an instance.
10493  */
10494 static void
10495 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10496     struct entity_elts *elts)
10497 {
10498 	uint8_t enabled;
10499 	struct pg_elts pgelts;
10500 	int ret;
10501 
10502 	/* enabled */
10503 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10504 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10505 	    prop_get_val(exp_prop, exp_val) == 0) {
10506 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10507 			scfdie();
10508 	} else {
10509 		enabled = 0;
10510 	}
10511 
10512 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10513 
10514 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10515 		scfdie();
10516 
10517 	(void) memset(&pgelts, 0, sizeof (pgelts));
10518 
10519 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10520 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10521 			scfdie();
10522 
10523 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10524 			continue;
10525 		} else if (strcmp(exp_str, SCF_PROPERTY_COMMENT) == 0) {
10526 			continue;
10527 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10528 			xmlNodePtr rnode, sfnode;
10529 
10530 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10531 			if (rnode == NULL)
10532 				uu_die(emsg_create_xml);
10533 
10534 			sfnode = xmlNewChild(rnode, NULL,
10535 			    (xmlChar *)"service_fmri", NULL);
10536 			if (sfnode == NULL)
10537 				uu_die(emsg_create_xml);
10538 
10539 			if (set_attr_from_prop(exp_prop, sfnode,
10540 			    value_attr) == 0) {
10541 				elts->restarter = rnode;
10542 				continue;
10543 			}
10544 
10545 			xmlFreeNode(rnode);
10546 		}
10547 
10548 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10549 	}
10550 	if (ret == -1)
10551 		scfdie();
10552 
10553 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10554 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10555 		    elts);
10556 }
10557 
10558 /*
10559  * Put an instance element for the given instance into selts.
10560  */
10561 static void
10562 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10563 {
10564 	xmlNodePtr n;
10565 	boolean_t isdefault;
10566 	struct entity_elts elts;
10567 	struct template_elts template_elts;
10568 	int ret;
10569 
10570 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10571 	if (n == NULL)
10572 		uu_die(emsg_create_xml);
10573 
10574 	/* name */
10575 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10576 		scfdie();
10577 	safe_setprop(n, name_attr, exp_str);
10578 	isdefault = strcmp(exp_str, "default") == 0;
10579 
10580 	/* check existance of general pg (since general/enabled is required) */
10581 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10582 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10583 			scfdie();
10584 
10585 		if (g_verbose) {
10586 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10587 				scfdie();
10588 
10589 			warn(gettext("Instance %s has no general property "
10590 			    "group; it will be marked disabled.\n"), exp_str);
10591 		}
10592 
10593 		safe_setprop(n, enabled_attr, false);
10594 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10595 	    strcmp(exp_str, scf_group_framework) != 0) {
10596 		if (g_verbose) {
10597 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10598 				scfdie();
10599 
10600 			warn(gettext("Property group %s is not of type "
10601 			    "framework; the instance will be marked "
10602 			    "disabled.\n"), exp_str);
10603 		}
10604 
10605 		safe_setprop(n, enabled_attr, false);
10606 	}
10607 
10608 	/* property groups */
10609 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10610 		scfdie();
10611 
10612 	(void) memset(&elts, 0, sizeof (elts));
10613 	(void) memset(&template_elts, 0, sizeof (template_elts));
10614 
10615 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10616 		uint32_t pgflags;
10617 
10618 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10619 			scfdie();
10620 
10621 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10622 			continue;
10623 
10624 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10625 			scfdie();
10626 
10627 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10628 			export_dependency(exp_pg, &elts);
10629 			continue;
10630 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10631 			export_method(exp_pg, &elts);
10632 			continue;
10633 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10634 			if (scf_pg_get_name(exp_pg, exp_str,
10635 			    max_scf_name_len + 1) < 0)
10636 				scfdie();
10637 
10638 			if (strcmp(exp_str, scf_pg_general) == 0) {
10639 				export_inst_general(exp_pg, n, &elts);
10640 				continue;
10641 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10642 			    0) {
10643 				export_method_context(exp_pg, &elts);
10644 				continue;
10645 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10646 				export_dependents(exp_pg, &elts);
10647 				continue;
10648 			}
10649 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10650 			export_template(exp_pg, &elts, &template_elts);
10651 			continue;
10652 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10653 			export_notify_params(exp_pg, &elts);
10654 			continue;
10655 		}
10656 
10657 		/* Ordinary pg. */
10658 		export_pg(exp_pg, &elts, flags);
10659 	}
10660 	if (ret == -1)
10661 		scfdie();
10662 
10663 	if (template_elts.common_name != NULL) {
10664 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10665 		(void) xmlAddChild(elts.template, template_elts.common_name);
10666 		(void) xmlAddChild(elts.template, template_elts.description);
10667 		(void) xmlAddChild(elts.template, template_elts.documentation);
10668 	} else {
10669 		xmlFreeNode(template_elts.description);
10670 		xmlFreeNode(template_elts.documentation);
10671 	}
10672 
10673 	if (isdefault && elts.restarter == NULL &&
10674 	    elts.dependencies == NULL && elts.method_context == NULL &&
10675 	    elts.exec_methods == NULL && elts.notify_params == NULL &&
10676 	    elts.property_groups == NULL && elts.template == NULL) {
10677 		xmlChar *eval;
10678 
10679 		/* This is a default instance */
10680 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10681 
10682 		xmlFreeNode(n);
10683 
10684 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10685 		if (n == NULL)
10686 			uu_die(emsg_create_xml);
10687 
10688 		safe_setprop(n, enabled_attr, (char *)eval);
10689 		xmlFree(eval);
10690 
10691 		selts->create_default_instance = n;
10692 	} else {
10693 		/* Assemble the children in order. */
10694 		(void) xmlAddChild(n, elts.restarter);
10695 		(void) xmlAddChildList(n, elts.dependencies);
10696 		(void) xmlAddChildList(n, elts.dependents);
10697 		(void) xmlAddChild(n, elts.method_context);
10698 		(void) xmlAddChildList(n, elts.exec_methods);
10699 		(void) xmlAddChildList(n, elts.notify_params);
10700 		(void) xmlAddChildList(n, elts.property_groups);
10701 		(void) xmlAddChild(n, elts.template);
10702 
10703 		if (selts->instances == NULL)
10704 			selts->instances = n;
10705 		else
10706 			(void) xmlAddSibling(selts->instances, n);
10707 	}
10708 }
10709 
10710 /*
10711  * Return a service element for the given service.
10712  */
10713 static xmlNodePtr
10714 export_service(scf_service_t *svc, int flags)
10715 {
10716 	xmlNodePtr snode;
10717 	struct entity_elts elts;
10718 	struct template_elts template_elts;
10719 	int ret;
10720 
10721 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10722 	if (snode == NULL)
10723 		uu_die(emsg_create_xml);
10724 
10725 	/* Get & set name attribute */
10726 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10727 		scfdie();
10728 	safe_setprop(snode, name_attr, exp_str);
10729 
10730 	safe_setprop(snode, type_attr, "service");
10731 	safe_setprop(snode, "version", "0");
10732 
10733 	/* Acquire child elements. */
10734 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10735 		scfdie();
10736 
10737 	(void) memset(&elts, 0, sizeof (elts));
10738 	(void) memset(&template_elts, 0, sizeof (template_elts));
10739 
10740 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10741 		uint32_t pgflags;
10742 
10743 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10744 			scfdie();
10745 
10746 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10747 			continue;
10748 
10749 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10750 			scfdie();
10751 
10752 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10753 			export_dependency(exp_pg, &elts);
10754 			continue;
10755 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10756 			export_method(exp_pg, &elts);
10757 			continue;
10758 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10759 			if (scf_pg_get_name(exp_pg, exp_str,
10760 			    max_scf_name_len + 1) < 0)
10761 				scfdie();
10762 
10763 			if (strcmp(exp_str, scf_pg_general) == 0) {
10764 				export_svc_general(exp_pg, &elts);
10765 				continue;
10766 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10767 			    0) {
10768 				export_method_context(exp_pg, &elts);
10769 				continue;
10770 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10771 				export_dependents(exp_pg, &elts);
10772 				continue;
10773 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10774 				continue;
10775 			}
10776 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10777 			export_template(exp_pg, &elts, &template_elts);
10778 			continue;
10779 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10780 			export_notify_params(exp_pg, &elts);
10781 			continue;
10782 		}
10783 
10784 		export_pg(exp_pg, &elts, flags);
10785 	}
10786 	if (ret == -1)
10787 		scfdie();
10788 
10789 	if (template_elts.common_name != NULL) {
10790 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10791 		(void) xmlAddChild(elts.template, template_elts.common_name);
10792 		(void) xmlAddChild(elts.template, template_elts.description);
10793 		(void) xmlAddChild(elts.template, template_elts.documentation);
10794 	} else {
10795 		xmlFreeNode(template_elts.description);
10796 		xmlFreeNode(template_elts.documentation);
10797 	}
10798 
10799 	/* Iterate instances */
10800 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10801 		scfdie();
10802 
10803 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10804 		export_instance(exp_inst, &elts, flags);
10805 	if (ret == -1)
10806 		scfdie();
10807 
10808 	/* Now add all of the accumulated elements in order. */
10809 	(void) xmlAddChild(snode, elts.create_default_instance);
10810 	(void) xmlAddChild(snode, elts.single_instance);
10811 	(void) xmlAddChild(snode, elts.restarter);
10812 	(void) xmlAddChildList(snode, elts.dependencies);
10813 	(void) xmlAddChildList(snode, elts.dependents);
10814 	(void) xmlAddChild(snode, elts.method_context);
10815 	(void) xmlAddChildList(snode, elts.exec_methods);
10816 	(void) xmlAddChildList(snode, elts.notify_params);
10817 	(void) xmlAddChildList(snode, elts.property_groups);
10818 	(void) xmlAddChildList(snode, elts.instances);
10819 	(void) xmlAddChild(snode, elts.stability);
10820 	(void) xmlAddChild(snode, elts.template);
10821 
10822 	return (snode);
10823 }
10824 
10825 static int
10826 export_callback(void *data, scf_walkinfo_t *wip)
10827 {
10828 	FILE *f;
10829 	xmlDocPtr doc;
10830 	xmlNodePtr sb;
10831 	int result;
10832 	struct export_args *argsp = (struct export_args *)data;
10833 
10834 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10835 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10836 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10837 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10838 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10839 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10840 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10841 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10842 		scfdie();
10843 
10844 	exp_str_sz = max_scf_len + 1;
10845 	exp_str = safe_malloc(exp_str_sz);
10846 
10847 	if (argsp->filename != NULL) {
10848 		errno = 0;
10849 		f = fopen(argsp->filename, "wb");
10850 		if (f == NULL) {
10851 			if (errno == 0)
10852 				uu_die(gettext("Could not open \"%s\": no free "
10853 				    "stdio streams.\n"), argsp->filename);
10854 			else
10855 				uu_die(gettext("Could not open \"%s\""),
10856 				    argsp->filename);
10857 		}
10858 	} else
10859 		f = stdout;
10860 
10861 	doc = xmlNewDoc((xmlChar *)"1.0");
10862 	if (doc == NULL)
10863 		uu_die(gettext("Could not create XML document.\n"));
10864 
10865 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10866 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10867 		uu_die(emsg_create_xml);
10868 
10869 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10870 	if (sb == NULL)
10871 		uu_die(emsg_create_xml);
10872 	safe_setprop(sb, type_attr, "manifest");
10873 	safe_setprop(sb, name_attr, "export");
10874 	(void) xmlAddSibling(doc->children, sb);
10875 
10876 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10877 
10878 	result = write_service_bundle(doc, f);
10879 
10880 	free(exp_str);
10881 	scf_iter_destroy(exp_val_iter);
10882 	scf_iter_destroy(exp_prop_iter);
10883 	scf_iter_destroy(exp_pg_iter);
10884 	scf_iter_destroy(exp_inst_iter);
10885 	scf_value_destroy(exp_val);
10886 	scf_property_destroy(exp_prop);
10887 	scf_pg_destroy(exp_pg);
10888 	scf_instance_destroy(exp_inst);
10889 
10890 	xmlFreeDoc(doc);
10891 
10892 	if (f != stdout)
10893 		(void) fclose(f);
10894 
10895 	return (result);
10896 }
10897 
10898 /*
10899  * Get the service named by fmri, build an XML tree which represents it, and
10900  * dump it into filename (or stdout if filename is NULL).
10901  */
10902 int
10903 lscf_service_export(char *fmri, const char *filename, int flags)
10904 {
10905 	struct export_args args;
10906 	char *fmridup;
10907 	const char *scope, *svc, *inst;
10908 	size_t cblen = 3 * max_scf_name_len;
10909 	char *canonbuf = alloca(cblen);
10910 	int ret, err;
10911 
10912 	lscf_prep_hndl();
10913 
10914 	bzero(&args, sizeof (args));
10915 	args.filename = filename;
10916 	args.flags = flags;
10917 
10918 	/*
10919 	 * If some poor user has passed an exact instance FMRI, of the sort
10920 	 * one might cut and paste from svcs(1) or an error message, warn
10921 	 * and chop off the instance instead of failing.
10922 	 */
10923 	fmridup = alloca(strlen(fmri) + 1);
10924 	(void) strcpy(fmridup, fmri);
10925 	if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10926 	    sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10927 	    scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10928 	    inst != NULL) {
10929 		(void) strlcpy(canonbuf, "svc:/", cblen);
10930 		if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10931 			(void) strlcat(canonbuf, "/", cblen);
10932 			(void) strlcat(canonbuf, scope, cblen);
10933 		}
10934 		(void) strlcat(canonbuf, svc, cblen);
10935 		fmri = canonbuf;
10936 
10937 		warn(gettext("Only services may be exported; ignoring "
10938 		    "instance portion of argument.\n"));
10939 	}
10940 
10941 	err = 0;
10942 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10943 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10944 	    &args, &err, semerr)) != 0) {
10945 		if (ret != -1)
10946 			semerr(gettext("Failed to walk instances: %s\n"),
10947 			    scf_strerror(ret));
10948 		return (-1);
10949 	}
10950 
10951 	/*
10952 	 * Error message has already been printed.
10953 	 */
10954 	if (err != 0)
10955 		return (-1);
10956 
10957 	return (0);
10958 }
10959 
10960 
10961 /*
10962  * Archive
10963  */
10964 
10965 static xmlNodePtr
10966 make_archive(int flags)
10967 {
10968 	xmlNodePtr sb;
10969 	scf_scope_t *scope;
10970 	scf_service_t *svc;
10971 	scf_iter_t *iter;
10972 	int r;
10973 
10974 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10975 	    (svc = scf_service_create(g_hndl)) == NULL ||
10976 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10977 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10978 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10979 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10980 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10981 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10982 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10983 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10984 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10985 		scfdie();
10986 
10987 	exp_str_sz = max_scf_len + 1;
10988 	exp_str = safe_malloc(exp_str_sz);
10989 
10990 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10991 	if (sb == NULL)
10992 		uu_die(emsg_create_xml);
10993 	safe_setprop(sb, type_attr, "archive");
10994 	safe_setprop(sb, name_attr, "none");
10995 
10996 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10997 		scfdie();
10998 	if (scf_iter_scope_services(iter, scope) != 0)
10999 		scfdie();
11000 
11001 	for (;;) {
11002 		r = scf_iter_next_service(iter, svc);
11003 		if (r == 0)
11004 			break;
11005 		if (r != 1)
11006 			scfdie();
11007 
11008 		if (scf_service_get_name(svc, exp_str,
11009 		    max_scf_name_len + 1) < 0)
11010 			scfdie();
11011 
11012 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11013 			continue;
11014 
11015 		(void) xmlAddChild(sb, export_service(svc, flags));
11016 	}
11017 
11018 	free(exp_str);
11019 
11020 	scf_iter_destroy(exp_val_iter);
11021 	scf_iter_destroy(exp_prop_iter);
11022 	scf_iter_destroy(exp_pg_iter);
11023 	scf_iter_destroy(exp_inst_iter);
11024 	scf_value_destroy(exp_val);
11025 	scf_property_destroy(exp_prop);
11026 	scf_pg_destroy(exp_pg);
11027 	scf_instance_destroy(exp_inst);
11028 	scf_iter_destroy(iter);
11029 	scf_service_destroy(svc);
11030 	scf_scope_destroy(scope);
11031 
11032 	return (sb);
11033 }
11034 
11035 int
11036 lscf_archive(const char *filename, int flags)
11037 {
11038 	FILE *f;
11039 	xmlDocPtr doc;
11040 	int result;
11041 
11042 	lscf_prep_hndl();
11043 
11044 	if (filename != NULL) {
11045 		errno = 0;
11046 		f = fopen(filename, "wb");
11047 		if (f == NULL) {
11048 			if (errno == 0)
11049 				uu_die(gettext("Could not open \"%s\": no free "
11050 				    "stdio streams.\n"), filename);
11051 			else
11052 				uu_die(gettext("Could not open \"%s\""),
11053 				    filename);
11054 		}
11055 	} else
11056 		f = stdout;
11057 
11058 	doc = xmlNewDoc((xmlChar *)"1.0");
11059 	if (doc == NULL)
11060 		uu_die(gettext("Could not create XML document.\n"));
11061 
11062 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11063 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11064 		uu_die(emsg_create_xml);
11065 
11066 	(void) xmlAddSibling(doc->children, make_archive(flags));
11067 
11068 	result = write_service_bundle(doc, f);
11069 
11070 	xmlFreeDoc(doc);
11071 
11072 	if (f != stdout)
11073 		(void) fclose(f);
11074 
11075 	return (result);
11076 }
11077 
11078 
11079 /*
11080  * "Extract" a profile.
11081  */
11082 int
11083 lscf_profile_extract(const char *filename)
11084 {
11085 	FILE *f;
11086 	xmlDocPtr doc;
11087 	xmlNodePtr sb, snode, inode;
11088 	scf_scope_t *scope;
11089 	scf_service_t *svc;
11090 	scf_instance_t *inst;
11091 	scf_propertygroup_t *pg;
11092 	scf_property_t *prop;
11093 	scf_value_t *val;
11094 	scf_iter_t *siter, *iiter;
11095 	int r, s;
11096 	char *namebuf;
11097 	uint8_t b;
11098 	int result;
11099 
11100 	lscf_prep_hndl();
11101 
11102 	if (filename != NULL) {
11103 		errno = 0;
11104 		f = fopen(filename, "wb");
11105 		if (f == NULL) {
11106 			if (errno == 0)
11107 				uu_die(gettext("Could not open \"%s\": no "
11108 				    "free stdio streams.\n"), filename);
11109 			else
11110 				uu_die(gettext("Could not open \"%s\""),
11111 				    filename);
11112 		}
11113 	} else
11114 		f = stdout;
11115 
11116 	doc = xmlNewDoc((xmlChar *)"1.0");
11117 	if (doc == NULL)
11118 		uu_die(gettext("Could not create XML document.\n"));
11119 
11120 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11121 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11122 		uu_die(emsg_create_xml);
11123 
11124 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11125 	if (sb == NULL)
11126 		uu_die(emsg_create_xml);
11127 	safe_setprop(sb, type_attr, "profile");
11128 	safe_setprop(sb, name_attr, "extract");
11129 	(void) xmlAddSibling(doc->children, sb);
11130 
11131 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
11132 	    (svc = scf_service_create(g_hndl)) == NULL ||
11133 	    (inst = scf_instance_create(g_hndl)) == NULL ||
11134 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11135 	    (prop = scf_property_create(g_hndl)) == NULL ||
11136 	    (val = scf_value_create(g_hndl)) == NULL ||
11137 	    (siter = scf_iter_create(g_hndl)) == NULL ||
11138 	    (iiter = scf_iter_create(g_hndl)) == NULL)
11139 		scfdie();
11140 
11141 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11142 		scfdie();
11143 
11144 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11145 		scfdie();
11146 
11147 	namebuf = safe_malloc(max_scf_name_len + 1);
11148 
11149 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
11150 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11151 			scfdie();
11152 
11153 		snode = xmlNewNode(NULL, (xmlChar *)"service");
11154 		if (snode == NULL)
11155 			uu_die(emsg_create_xml);
11156 
11157 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11158 		    0)
11159 			scfdie();
11160 
11161 		safe_setprop(snode, name_attr, namebuf);
11162 
11163 		safe_setprop(snode, type_attr, "service");
11164 		safe_setprop(snode, "version", "0");
11165 
11166 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11167 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11168 			    SCF_SUCCESS) {
11169 				if (scf_error() != SCF_ERROR_NOT_FOUND)
11170 					scfdie();
11171 
11172 				if (g_verbose) {
11173 					ssize_t len;
11174 					char *fmri;
11175 
11176 					len =
11177 					    scf_instance_to_fmri(inst, NULL, 0);
11178 					if (len < 0)
11179 						scfdie();
11180 
11181 					fmri = safe_malloc(len + 1);
11182 
11183 					if (scf_instance_to_fmri(inst, fmri,
11184 					    len + 1) < 0)
11185 						scfdie();
11186 
11187 					warn("Instance %s has no \"%s\" "
11188 					    "property group.\n", fmri,
11189 					    scf_pg_general);
11190 
11191 					free(fmri);
11192 				}
11193 
11194 				continue;
11195 			}
11196 
11197 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11198 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11199 			    prop_get_val(prop, val) != 0)
11200 				continue;
11201 
11202 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11203 			    NULL);
11204 			if (inode == NULL)
11205 				uu_die(emsg_create_xml);
11206 
11207 			if (scf_instance_get_name(inst, namebuf,
11208 			    max_scf_name_len + 1) < 0)
11209 				scfdie();
11210 
11211 			safe_setprop(inode, name_attr, namebuf);
11212 
11213 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11214 				scfdie();
11215 
11216 			safe_setprop(inode, enabled_attr, b ? true : false);
11217 		}
11218 		if (s < 0)
11219 			scfdie();
11220 
11221 		if (snode->children != NULL)
11222 			(void) xmlAddChild(sb, snode);
11223 		else
11224 			xmlFreeNode(snode);
11225 	}
11226 	if (r < 0)
11227 		scfdie();
11228 
11229 	free(namebuf);
11230 
11231 	result = write_service_bundle(doc, f);
11232 
11233 	xmlFreeDoc(doc);
11234 
11235 	if (f != stdout)
11236 		(void) fclose(f);
11237 
11238 	return (result);
11239 }
11240 
11241 
11242 /*
11243  * Entity manipulation commands
11244  */
11245 
11246 /*
11247  * Entity selection.  If no entity is selected, then the current scope is in
11248  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11249  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11250  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11251  * cur_inst will be non-NULL.
11252  */
11253 
11254 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11255 static int
11256 select_inst(const char *name)
11257 {
11258 	scf_instance_t *inst;
11259 	scf_error_t err;
11260 
11261 	assert(cur_svc != NULL);
11262 
11263 	inst = scf_instance_create(g_hndl);
11264 	if (inst == NULL)
11265 		scfdie();
11266 
11267 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11268 		cur_inst = inst;
11269 		return (0);
11270 	}
11271 
11272 	err = scf_error();
11273 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11274 		scfdie();
11275 
11276 	scf_instance_destroy(inst);
11277 	return (1);
11278 }
11279 
11280 /* Returns as above. */
11281 static int
11282 select_svc(const char *name)
11283 {
11284 	scf_service_t *svc;
11285 	scf_error_t err;
11286 
11287 	assert(cur_scope != NULL);
11288 
11289 	svc = scf_service_create(g_hndl);
11290 	if (svc == NULL)
11291 		scfdie();
11292 
11293 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11294 		cur_svc = svc;
11295 		return (0);
11296 	}
11297 
11298 	err = scf_error();
11299 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11300 		scfdie();
11301 
11302 	scf_service_destroy(svc);
11303 	return (1);
11304 }
11305 
11306 /* ARGSUSED */
11307 static int
11308 select_callback(void *unused, scf_walkinfo_t *wip)
11309 {
11310 	scf_instance_t *inst;
11311 	scf_service_t *svc;
11312 	scf_scope_t *scope;
11313 
11314 	if (wip->inst != NULL) {
11315 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11316 		    (svc = scf_service_create(g_hndl)) == NULL ||
11317 		    (inst = scf_instance_create(g_hndl)) == NULL)
11318 			scfdie();
11319 
11320 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11321 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11322 			scfdie();
11323 	} else {
11324 		assert(wip->svc != NULL);
11325 
11326 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11327 		    (svc = scf_service_create(g_hndl)) == NULL)
11328 			scfdie();
11329 
11330 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11331 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11332 			scfdie();
11333 
11334 		inst = NULL;
11335 	}
11336 
11337 	/* Clear out the current selection */
11338 	assert(cur_scope != NULL);
11339 	scf_scope_destroy(cur_scope);
11340 	scf_service_destroy(cur_svc);
11341 	scf_instance_destroy(cur_inst);
11342 
11343 	cur_scope = scope;
11344 	cur_svc = svc;
11345 	cur_inst = inst;
11346 
11347 	return (0);
11348 }
11349 
11350 static int
11351 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11352 {
11353 	char **fmri = fmri_p;
11354 
11355 	*fmri = strdup(wip->fmri);
11356 	if (*fmri == NULL)
11357 		uu_die(gettext("Out of memory.\n"));
11358 
11359 	return (0);
11360 }
11361 
11362 /*
11363  * validate [fmri]
11364  * Perform the validation of an FMRI instance.
11365  */
11366 void
11367 lscf_validate_fmri(const char *fmri)
11368 {
11369 	int ret = 0;
11370 	size_t inst_sz;
11371 	char *inst_fmri = NULL;
11372 	scf_tmpl_errors_t *errs = NULL;
11373 	char *snapbuf = NULL;
11374 
11375 	lscf_prep_hndl();
11376 
11377 	if (fmri == NULL) {
11378 		inst_sz = max_scf_fmri_len + 1;
11379 		inst_fmri = safe_malloc(inst_sz);
11380 
11381 		if (cur_snap != NULL) {
11382 			snapbuf = safe_malloc(max_scf_name_len + 1);
11383 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11384 			    max_scf_name_len + 1) < 0)
11385 				scfdie();
11386 		}
11387 		if (cur_inst == NULL) {
11388 			semerr(gettext("No instance selected\n"));
11389 			goto cleanup;
11390 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11391 		    inst_sz) >= inst_sz) {
11392 			/* sanity check. Should never get here */
11393 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11394 			    __FILE__, __LINE__);
11395 		}
11396 	} else {
11397 		scf_error_t scf_err;
11398 		int err = 0;
11399 
11400 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11401 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11402 			uu_warn("Failed to walk instances: %s\n",
11403 			    scf_strerror(scf_err));
11404 			goto cleanup;
11405 		}
11406 		if (err != 0) {
11407 			/* error message displayed by scf_walk_fmri */
11408 			goto cleanup;
11409 		}
11410 	}
11411 
11412 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11413 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11414 	if (ret == -1) {
11415 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11416 			warn(gettext("Template data for %s is invalid. "
11417 			    "Consider reverting to a previous snapshot or "
11418 			    "restoring original configuration.\n"), inst_fmri);
11419 		} else {
11420 			uu_warn("%s: %s\n",
11421 			    gettext("Error validating the instance"),
11422 			    scf_strerror(scf_error()));
11423 		}
11424 	} else if (ret == 1 && errs != NULL) {
11425 		scf_tmpl_error_t *err = NULL;
11426 		char *msg;
11427 		size_t len = 256;	/* initial error buffer size */
11428 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11429 		    SCF_TMPL_STRERROR_HUMAN : 0;
11430 
11431 		msg = safe_malloc(len);
11432 
11433 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11434 			int ret;
11435 
11436 			if ((ret = scf_tmpl_strerror(err, msg, len,
11437 			    flag)) >= len) {
11438 				len = ret + 1;
11439 				msg = realloc(msg, len);
11440 				if (msg == NULL)
11441 					uu_die(gettext(
11442 					    "Out of memory.\n"));
11443 				(void) scf_tmpl_strerror(err, msg, len,
11444 				    flag);
11445 			}
11446 			(void) fprintf(stderr, "%s\n", msg);
11447 		}
11448 		if (msg != NULL)
11449 			free(msg);
11450 	}
11451 	if (errs != NULL)
11452 		scf_tmpl_errors_destroy(errs);
11453 
11454 cleanup:
11455 	free(inst_fmri);
11456 	free(snapbuf);
11457 }
11458 
11459 static void
11460 lscf_validate_file(const char *filename)
11461 {
11462 	tmpl_errors_t *errs;
11463 
11464 	bundle_t *b = internal_bundle_new();
11465 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11466 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11467 			tmpl_errors_print(stderr, errs, "");
11468 			semerr(gettext("Validation failed.\n"));
11469 		}
11470 		tmpl_errors_destroy(errs);
11471 	}
11472 	(void) internal_bundle_free(b);
11473 }
11474 
11475 /*
11476  * validate [fmri|file]
11477  */
11478 void
11479 lscf_validate(const char *arg)
11480 {
11481 	const char *str;
11482 
11483 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11484 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11485 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11486 		lscf_validate_file(str);
11487 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11488 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11489 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11490 		lscf_validate_fmri(str);
11491 	} else if (access(arg, R_OK | F_OK) == 0) {
11492 		lscf_validate_file(arg);
11493 	} else {
11494 		lscf_validate_fmri(arg);
11495 	}
11496 }
11497 
11498 void
11499 lscf_select(const char *fmri)
11500 {
11501 	int ret, err;
11502 
11503 	lscf_prep_hndl();
11504 
11505 	if (cur_snap != NULL) {
11506 		struct snaplevel *elt;
11507 		char *buf;
11508 
11509 		/* Error unless name is that of the next level. */
11510 		elt = uu_list_next(cur_levels, cur_elt);
11511 		if (elt == NULL) {
11512 			semerr(gettext("No children.\n"));
11513 			return;
11514 		}
11515 
11516 		buf = safe_malloc(max_scf_name_len + 1);
11517 
11518 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11519 		    max_scf_name_len + 1) < 0)
11520 			scfdie();
11521 
11522 		if (strcmp(buf, fmri) != 0) {
11523 			semerr(gettext("No such child.\n"));
11524 			free(buf);
11525 			return;
11526 		}
11527 
11528 		free(buf);
11529 
11530 		cur_elt = elt;
11531 		cur_level = elt->sl;
11532 		return;
11533 	}
11534 
11535 	/*
11536 	 * Special case for 'svc:', which takes the user to the scope level.
11537 	 */
11538 	if (strcmp(fmri, "svc:") == 0) {
11539 		scf_instance_destroy(cur_inst);
11540 		scf_service_destroy(cur_svc);
11541 		cur_inst = NULL;
11542 		cur_svc = NULL;
11543 		return;
11544 	}
11545 
11546 	/*
11547 	 * Special case for ':properties'.  This appears as part of 'list' but
11548 	 * can't be selected.  Give a more helpful error message in this case.
11549 	 */
11550 	if (strcmp(fmri, ":properties") == 0) {
11551 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11552 		    "to list properties.\n"));
11553 		return;
11554 	}
11555 
11556 	/*
11557 	 * First try the argument as relative to the current selection.
11558 	 */
11559 	if (cur_inst != NULL) {
11560 		/* EMPTY */;
11561 	} else if (cur_svc != NULL) {
11562 		if (select_inst(fmri) != 1)
11563 			return;
11564 	} else {
11565 		if (select_svc(fmri) != 1)
11566 			return;
11567 	}
11568 
11569 	err = 0;
11570 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11571 	    select_callback, NULL, &err, semerr)) != 0) {
11572 		semerr(gettext("Failed to walk instances: %s\n"),
11573 		    scf_strerror(ret));
11574 	}
11575 }
11576 
11577 void
11578 lscf_unselect(void)
11579 {
11580 	lscf_prep_hndl();
11581 
11582 	if (cur_snap != NULL) {
11583 		struct snaplevel *elt;
11584 
11585 		elt = uu_list_prev(cur_levels, cur_elt);
11586 		if (elt == NULL) {
11587 			semerr(gettext("No parent levels.\n"));
11588 		} else {
11589 			cur_elt = elt;
11590 			cur_level = elt->sl;
11591 		}
11592 	} else if (cur_inst != NULL) {
11593 		scf_instance_destroy(cur_inst);
11594 		cur_inst = NULL;
11595 	} else if (cur_svc != NULL) {
11596 		scf_service_destroy(cur_svc);
11597 		cur_svc = NULL;
11598 	} else {
11599 		semerr(gettext("Cannot unselect at scope level.\n"));
11600 	}
11601 }
11602 
11603 /*
11604  * Return the FMRI of the current selection, for the prompt.
11605  */
11606 void
11607 lscf_get_selection_str(char *buf, size_t bufsz)
11608 {
11609 	char *cp;
11610 	ssize_t fmrilen, szret;
11611 	boolean_t deleted = B_FALSE;
11612 
11613 	if (g_hndl == NULL) {
11614 		(void) strlcpy(buf, "svc:", bufsz);
11615 		return;
11616 	}
11617 
11618 	if (cur_level != NULL) {
11619 		assert(cur_snap != NULL);
11620 
11621 		/* [ snapshot ] FMRI [: instance ] */
11622 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11623 		    + 2 + max_scf_name_len + 1 + 1);
11624 
11625 		buf[0] = '[';
11626 
11627 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11628 		    max_scf_name_len + 1);
11629 		if (szret < 0) {
11630 			if (scf_error() != SCF_ERROR_DELETED)
11631 				scfdie();
11632 
11633 			goto snap_deleted;
11634 		}
11635 
11636 		(void) strcat(buf, "]svc:/");
11637 
11638 		cp = strchr(buf, '\0');
11639 
11640 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11641 		    max_scf_name_len + 1);
11642 		if (szret < 0) {
11643 			if (scf_error() != SCF_ERROR_DELETED)
11644 				scfdie();
11645 
11646 			goto snap_deleted;
11647 		}
11648 
11649 		cp = strchr(cp, '\0');
11650 
11651 		if (snaplevel_is_instance(cur_level)) {
11652 			*cp++ = ':';
11653 
11654 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11655 			    max_scf_name_len + 1) < 0) {
11656 				if (scf_error() != SCF_ERROR_DELETED)
11657 					scfdie();
11658 
11659 				goto snap_deleted;
11660 			}
11661 		} else {
11662 			*cp++ = '[';
11663 			*cp++ = ':';
11664 
11665 			if (scf_instance_get_name(cur_inst, cp,
11666 			    max_scf_name_len + 1) < 0) {
11667 				if (scf_error() != SCF_ERROR_DELETED)
11668 					scfdie();
11669 
11670 				goto snap_deleted;
11671 			}
11672 
11673 			(void) strcat(buf, "]");
11674 		}
11675 
11676 		return;
11677 
11678 snap_deleted:
11679 		deleted = B_TRUE;
11680 		free(buf);
11681 		unselect_cursnap();
11682 	}
11683 
11684 	assert(cur_snap == NULL);
11685 
11686 	if (cur_inst != NULL) {
11687 		assert(cur_svc != NULL);
11688 		assert(cur_scope != NULL);
11689 
11690 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11691 		if (fmrilen >= 0) {
11692 			assert(fmrilen < bufsz);
11693 			if (deleted)
11694 				warn(emsg_deleted);
11695 			return;
11696 		}
11697 
11698 		if (scf_error() != SCF_ERROR_DELETED)
11699 			scfdie();
11700 
11701 		deleted = B_TRUE;
11702 
11703 		scf_instance_destroy(cur_inst);
11704 		cur_inst = NULL;
11705 	}
11706 
11707 	if (cur_svc != NULL) {
11708 		assert(cur_scope != NULL);
11709 
11710 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11711 		if (szret >= 0) {
11712 			assert(szret < bufsz);
11713 			if (deleted)
11714 				warn(emsg_deleted);
11715 			return;
11716 		}
11717 
11718 		if (scf_error() != SCF_ERROR_DELETED)
11719 			scfdie();
11720 
11721 		deleted = B_TRUE;
11722 		scf_service_destroy(cur_svc);
11723 		cur_svc = NULL;
11724 	}
11725 
11726 	assert(cur_scope != NULL);
11727 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11728 
11729 	if (fmrilen < 0)
11730 		scfdie();
11731 
11732 	assert(fmrilen < bufsz);
11733 	if (deleted)
11734 		warn(emsg_deleted);
11735 }
11736 
11737 /*
11738  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11739  * :statistics) are listed for the current selection.
11740  */
11741 void
11742 lscf_list(const char *pattern)
11743 {
11744 	scf_iter_t *iter;
11745 	char *buf;
11746 	int ret;
11747 
11748 	lscf_prep_hndl();
11749 
11750 	if (cur_level != NULL) {
11751 		struct snaplevel *elt;
11752 
11753 		(void) fputs(COLON_NAMESPACES, stdout);
11754 
11755 		elt = uu_list_next(cur_levels, cur_elt);
11756 		if (elt == NULL)
11757 			return;
11758 
11759 		/*
11760 		 * For now, we know that the next level is an instance.  But
11761 		 * if we ever have multiple scopes, this could be complicated.
11762 		 */
11763 		buf = safe_malloc(max_scf_name_len + 1);
11764 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11765 		    max_scf_name_len + 1) >= 0) {
11766 			(void) puts(buf);
11767 		} else {
11768 			if (scf_error() != SCF_ERROR_DELETED)
11769 				scfdie();
11770 		}
11771 
11772 		free(buf);
11773 
11774 		return;
11775 	}
11776 
11777 	if (cur_inst != NULL) {
11778 		(void) fputs(COLON_NAMESPACES, stdout);
11779 		return;
11780 	}
11781 
11782 	iter = scf_iter_create(g_hndl);
11783 	if (iter == NULL)
11784 		scfdie();
11785 
11786 	buf = safe_malloc(max_scf_name_len + 1);
11787 
11788 	if (cur_svc != NULL) {
11789 		/* List the instances in this service. */
11790 		scf_instance_t *inst;
11791 
11792 		inst = scf_instance_create(g_hndl);
11793 		if (inst == NULL)
11794 			scfdie();
11795 
11796 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11797 			safe_printf(COLON_NAMESPACES);
11798 
11799 			for (;;) {
11800 				ret = scf_iter_next_instance(iter, inst);
11801 				if (ret == 0)
11802 					break;
11803 				if (ret != 1) {
11804 					if (scf_error() != SCF_ERROR_DELETED)
11805 						scfdie();
11806 
11807 					break;
11808 				}
11809 
11810 				if (scf_instance_get_name(inst, buf,
11811 				    max_scf_name_len + 1) >= 0) {
11812 					if (pattern == NULL ||
11813 					    fnmatch(pattern, buf, 0) == 0)
11814 						(void) puts(buf);
11815 				} else {
11816 					if (scf_error() != SCF_ERROR_DELETED)
11817 						scfdie();
11818 				}
11819 			}
11820 		} else {
11821 			if (scf_error() != SCF_ERROR_DELETED)
11822 				scfdie();
11823 		}
11824 
11825 		scf_instance_destroy(inst);
11826 	} else {
11827 		/* List the services in this scope. */
11828 		scf_service_t *svc;
11829 
11830 		assert(cur_scope != NULL);
11831 
11832 		svc = scf_service_create(g_hndl);
11833 		if (svc == NULL)
11834 			scfdie();
11835 
11836 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11837 			scfdie();
11838 
11839 		for (;;) {
11840 			ret = scf_iter_next_service(iter, svc);
11841 			if (ret == 0)
11842 				break;
11843 			if (ret != 1)
11844 				scfdie();
11845 
11846 			if (scf_service_get_name(svc, buf,
11847 			    max_scf_name_len + 1) >= 0) {
11848 				if (pattern == NULL ||
11849 				    fnmatch(pattern, buf, 0) == 0)
11850 					safe_printf("%s\n", buf);
11851 			} else {
11852 				if (scf_error() != SCF_ERROR_DELETED)
11853 					scfdie();
11854 			}
11855 		}
11856 
11857 		scf_service_destroy(svc);
11858 	}
11859 
11860 	free(buf);
11861 	scf_iter_destroy(iter);
11862 }
11863 
11864 /*
11865  * Entity addition.  Creates an empty entity in the current selection.
11866  */
11867 void
11868 lscf_add(const char *name)
11869 {
11870 	lscf_prep_hndl();
11871 
11872 	if (cur_snap != NULL) {
11873 		semerr(emsg_cant_modify_snapshots);
11874 	} else if (cur_inst != NULL) {
11875 		semerr(gettext("Cannot add entities to an instance.\n"));
11876 	} else if (cur_svc != NULL) {
11877 
11878 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11879 		    SCF_SUCCESS) {
11880 			switch (scf_error()) {
11881 			case SCF_ERROR_INVALID_ARGUMENT:
11882 				semerr(gettext("Invalid name.\n"));
11883 				break;
11884 
11885 			case SCF_ERROR_EXISTS:
11886 				semerr(gettext("Instance already exists.\n"));
11887 				break;
11888 
11889 			case SCF_ERROR_PERMISSION_DENIED:
11890 				semerr(emsg_permission_denied);
11891 				break;
11892 
11893 			default:
11894 				scfdie();
11895 			}
11896 		}
11897 	} else {
11898 		assert(cur_scope != NULL);
11899 
11900 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11901 		    SCF_SUCCESS) {
11902 			switch (scf_error()) {
11903 			case SCF_ERROR_INVALID_ARGUMENT:
11904 				semerr(gettext("Invalid name.\n"));
11905 				break;
11906 
11907 			case SCF_ERROR_EXISTS:
11908 				semerr(gettext("Service already exists.\n"));
11909 				break;
11910 
11911 			case SCF_ERROR_PERMISSION_DENIED:
11912 				semerr(emsg_permission_denied);
11913 				break;
11914 
11915 			case SCF_ERROR_BACKEND_READONLY:
11916 				semerr(emsg_read_only);
11917 				break;
11918 
11919 			default:
11920 				scfdie();
11921 			}
11922 		}
11923 	}
11924 }
11925 
11926 /* return 1 if the entity has no persistent pgs, else return 0 */
11927 static int
11928 entity_has_no_pgs(void *ent, int isservice)
11929 {
11930 	scf_iter_t *iter = NULL;
11931 	scf_propertygroup_t *pg = NULL;
11932 	uint32_t flags;
11933 	int err;
11934 	int ret = 1;
11935 
11936 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11937 	    (pg = scf_pg_create(g_hndl)) == NULL)
11938 		scfdie();
11939 
11940 	if (isservice) {
11941 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11942 			scfdie();
11943 	} else {
11944 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11945 			scfdie();
11946 	}
11947 
11948 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11949 		if (scf_pg_get_flags(pg, &flags) != 0)
11950 			scfdie();
11951 
11952 		/* skip nonpersistent pgs */
11953 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11954 			continue;
11955 
11956 		ret = 0;
11957 		break;
11958 	}
11959 
11960 	if (err == -1)
11961 		scfdie();
11962 
11963 	scf_pg_destroy(pg);
11964 	scf_iter_destroy(iter);
11965 
11966 	return (ret);
11967 }
11968 
11969 /* return 1 if the service has no instances, else return 0 */
11970 static int
11971 svc_has_no_insts(scf_service_t *svc)
11972 {
11973 	scf_instance_t *inst;
11974 	scf_iter_t *iter;
11975 	int r;
11976 	int ret = 1;
11977 
11978 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11979 	    (iter = scf_iter_create(g_hndl)) == NULL)
11980 		scfdie();
11981 
11982 	if (scf_iter_service_instances(iter, svc) != 0)
11983 		scfdie();
11984 
11985 	r = scf_iter_next_instance(iter, inst);
11986 	if (r == 1) {
11987 		ret = 0;
11988 	} else if (r == 0) {
11989 		ret = 1;
11990 	} else if (r == -1) {
11991 		scfdie();
11992 	} else {
11993 		bad_error("scf_iter_next_instance", r);
11994 	}
11995 
11996 	scf_iter_destroy(iter);
11997 	scf_instance_destroy(inst);
11998 
11999 	return (ret);
12000 }
12001 
12002 /*
12003  * Entity deletion.
12004  */
12005 
12006 /*
12007  * Delete the property group <fmri>/:properties/<name>.  Returns
12008  * SCF_ERROR_NONE on success (or if the entity is not found),
12009  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
12010  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12011  * denied.
12012  */
12013 static scf_error_t
12014 delete_dependency_pg(const char *fmri, const char *name)
12015 {
12016 	void *entity = NULL;
12017 	int isservice;
12018 	scf_propertygroup_t *pg = NULL;
12019 	scf_error_t result;
12020 	char *pgty;
12021 	scf_service_t *svc = NULL;
12022 	scf_instance_t *inst = NULL;
12023 	scf_iter_t *iter = NULL;
12024 	char *name_buf = NULL;
12025 
12026 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12027 	switch (result) {
12028 	case SCF_ERROR_NONE:
12029 		break;
12030 
12031 	case SCF_ERROR_NO_MEMORY:
12032 		uu_die(gettext("Out of memory.\n"));
12033 		/* NOTREACHED */
12034 
12035 	case SCF_ERROR_INVALID_ARGUMENT:
12036 	case SCF_ERROR_CONSTRAINT_VIOLATED:
12037 		return (SCF_ERROR_INVALID_ARGUMENT);
12038 
12039 	case SCF_ERROR_NOT_FOUND:
12040 		result = SCF_ERROR_NONE;
12041 		goto out;
12042 
12043 	default:
12044 		bad_error("fmri_to_entity", result);
12045 	}
12046 
12047 	pg = scf_pg_create(g_hndl);
12048 	if (pg == NULL)
12049 		scfdie();
12050 
12051 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
12052 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12053 			scfdie();
12054 
12055 		result = SCF_ERROR_NONE;
12056 		goto out;
12057 	}
12058 
12059 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12060 
12061 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12062 		scfdie();
12063 
12064 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12065 		result = SCF_ERROR_TYPE_MISMATCH;
12066 		free(pgty);
12067 		goto out;
12068 	}
12069 
12070 	free(pgty);
12071 
12072 	if (scf_pg_delete(pg) != 0) {
12073 		result = scf_error();
12074 		if (result != SCF_ERROR_PERMISSION_DENIED)
12075 			scfdie();
12076 		goto out;
12077 	}
12078 
12079 	/*
12080 	 * We have to handle the case where we've just deleted the last
12081 	 * property group of a "dummy" entity (instance or service).
12082 	 * A "dummy" entity is an entity only present to hold an
12083 	 * external dependency.
12084 	 * So, in the case we deleted the last property group then we
12085 	 * can also delete the entity. If the entity is an instance then
12086 	 * we must verify if this was the last instance for the service
12087 	 * and if it is, we can also delete the service if it doesn't
12088 	 * have any property group either.
12089 	 */
12090 
12091 	result = SCF_ERROR_NONE;
12092 
12093 	if (isservice) {
12094 		svc = (scf_service_t *)entity;
12095 
12096 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
12097 		    (iter = scf_iter_create(g_hndl)) == NULL)
12098 			scfdie();
12099 
12100 		name_buf = safe_malloc(max_scf_name_len + 1);
12101 	} else {
12102 		inst = (scf_instance_t *)entity;
12103 	}
12104 
12105 	/*
12106 	 * If the entity is an instance and we've just deleted its last
12107 	 * property group then we should delete it.
12108 	 */
12109 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
12110 		/* find the service before deleting the inst. - needed later */
12111 		if ((svc = scf_service_create(g_hndl)) == NULL)
12112 			scfdie();
12113 
12114 		if (scf_instance_get_parent(inst, svc) != 0)
12115 			scfdie();
12116 
12117 		/* delete the instance */
12118 		if (scf_instance_delete(inst) != 0) {
12119 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12120 				scfdie();
12121 
12122 			result = SCF_ERROR_PERMISSION_DENIED;
12123 			goto out;
12124 		}
12125 		/* no need to refresh the instance */
12126 		inst = NULL;
12127 	}
12128 
12129 	/*
12130 	 * If the service has no more instances and pgs or we just deleted the
12131 	 * last instance and the service doesn't have anymore propery groups
12132 	 * then the service should be deleted.
12133 	 */
12134 	if (svc != NULL &&
12135 	    svc_has_no_insts(svc) &&
12136 	    entity_has_no_pgs((void *)svc, 1)) {
12137 		if (scf_service_delete(svc) == 0) {
12138 			if (isservice) {
12139 				/* no need to refresh the service */
12140 				svc = NULL;
12141 			}
12142 
12143 			goto out;
12144 		}
12145 
12146 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12147 			scfdie();
12148 
12149 		result = SCF_ERROR_PERMISSION_DENIED;
12150 	}
12151 
12152 	/* if the entity has not been deleted, refresh it */
12153 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12154 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
12155 		    name_buf);
12156 	}
12157 
12158 out:
12159 	if (isservice && (inst != NULL && iter != NULL)) {
12160 		free(name_buf);
12161 		scf_iter_destroy(iter);
12162 		scf_instance_destroy(inst);
12163 	}
12164 
12165 	if (!isservice && svc != NULL) {
12166 		scf_service_destroy(svc);
12167 	}
12168 
12169 	scf_pg_destroy(pg);
12170 	if (entity != NULL)
12171 		entity_destroy(entity, isservice);
12172 
12173 	return (result);
12174 }
12175 
12176 static int
12177 delete_dependents(scf_propertygroup_t *pg)
12178 {
12179 	char *pgty, *name, *fmri;
12180 	scf_property_t *prop;
12181 	scf_value_t *val;
12182 	scf_iter_t *iter;
12183 	int r;
12184 	scf_error_t err;
12185 
12186 	/* Verify that the pg has the correct type. */
12187 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12188 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12189 		scfdie();
12190 
12191 	if (strcmp(pgty, scf_group_framework) != 0) {
12192 		if (g_verbose) {
12193 			fmri = safe_malloc(max_scf_fmri_len + 1);
12194 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12195 				scfdie();
12196 
12197 			warn(gettext("Property group %s is not of expected "
12198 			    "type %s.\n"), fmri, scf_group_framework);
12199 
12200 			free(fmri);
12201 		}
12202 
12203 		free(pgty);
12204 		return (-1);
12205 	}
12206 
12207 	free(pgty);
12208 
12209 	/* map delete_dependency_pg onto the properties. */
12210 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12211 	    (val = scf_value_create(g_hndl)) == NULL ||
12212 	    (iter = scf_iter_create(g_hndl)) == NULL)
12213 		scfdie();
12214 
12215 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12216 		scfdie();
12217 
12218 	name = safe_malloc(max_scf_name_len + 1);
12219 	fmri = safe_malloc(max_scf_fmri_len + 2);
12220 
12221 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
12222 		scf_type_t ty;
12223 
12224 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12225 			scfdie();
12226 
12227 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12228 			scfdie();
12229 
12230 		if ((ty != SCF_TYPE_ASTRING &&
12231 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12232 		    prop_get_val(prop, val) != 0)
12233 			continue;
12234 
12235 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12236 			scfdie();
12237 
12238 		err = delete_dependency_pg(fmri, name);
12239 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12240 			if (scf_property_to_fmri(prop, fmri,
12241 			    max_scf_fmri_len + 2) < 0)
12242 				scfdie();
12243 
12244 			warn(gettext("Value of %s is not a valid FMRI.\n"),
12245 			    fmri);
12246 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12247 			warn(gettext("Property group \"%s\" of entity \"%s\" "
12248 			    "does not have dependency type.\n"), name, fmri);
12249 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12250 			warn(gettext("Could not delete property group \"%s\" "
12251 			    "of entity \"%s\" (permission denied).\n"), name,
12252 			    fmri);
12253 		}
12254 	}
12255 	if (r == -1)
12256 		scfdie();
12257 
12258 	scf_value_destroy(val);
12259 	scf_property_destroy(prop);
12260 
12261 	return (0);
12262 }
12263 
12264 /*
12265  * Returns 1 if the instance may be running, and 0 otherwise.
12266  */
12267 static int
12268 inst_is_running(scf_instance_t *inst)
12269 {
12270 	scf_propertygroup_t *pg;
12271 	scf_property_t *prop;
12272 	scf_value_t *val;
12273 	char buf[MAX_SCF_STATE_STRING_SZ];
12274 	int ret = 0;
12275 	ssize_t szret;
12276 
12277 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12278 	    (prop = scf_property_create(g_hndl)) == NULL ||
12279 	    (val = scf_value_create(g_hndl)) == NULL)
12280 		scfdie();
12281 
12282 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12283 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12284 			scfdie();
12285 		goto out;
12286 	}
12287 
12288 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12289 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12290 	    prop_get_val(prop, val) != 0)
12291 		goto out;
12292 
12293 	szret = scf_value_get_astring(val, buf, sizeof (buf));
12294 	assert(szret >= 0);
12295 
12296 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12297 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12298 
12299 out:
12300 	scf_value_destroy(val);
12301 	scf_property_destroy(prop);
12302 	scf_pg_destroy(pg);
12303 	return (ret);
12304 }
12305 
12306 static uint8_t
12307 pg_is_external_dependency(scf_propertygroup_t *pg)
12308 {
12309 	char *type;
12310 	scf_value_t *val;
12311 	scf_property_t *prop;
12312 	uint8_t b = B_FALSE;
12313 
12314 	type = safe_malloc(max_scf_pg_type_len + 1);
12315 
12316 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12317 		scfdie();
12318 
12319 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12320 	    (val = scf_value_create(g_hndl)) == NULL)
12321 		scfdie();
12322 
12323 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12324 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12325 			if (scf_property_get_value(prop, val) != 0)
12326 				scfdie();
12327 			if (scf_value_get_boolean(val, &b) != 0)
12328 				scfdie();
12329 		}
12330 	}
12331 
12332 	free(type);
12333 	(void) scf_value_destroy(val);
12334 	(void) scf_property_destroy(prop);
12335 
12336 	return (b);
12337 }
12338 
12339 #define	DELETE_FAILURE			-1
12340 #define	DELETE_SUCCESS_NOEXTDEPS	0
12341 #define	DELETE_SUCCESS_EXTDEPS		1
12342 
12343 /*
12344  * lscf_instance_delete() deletes an instance.  Before calling
12345  * scf_instance_delete(), though, we make sure the instance isn't
12346  * running and delete dependencies in other entities which the instance
12347  * declared as "dependents".  If there are dependencies which were
12348  * created for other entities, then instead of deleting the instance we
12349  * make it "empty" by deleting all other property groups and all
12350  * snapshots.
12351  *
12352  * lscf_instance_delete() verifies that there is no external dependency pgs
12353  * before suppressing the instance. If there is, then we must not remove them
12354  * now in case the instance is re-created otherwise the dependencies would be
12355  * lost. The external dependency pgs will be removed if the dependencies are
12356  * removed.
12357  *
12358  * Returns:
12359  *  DELETE_FAILURE		on failure
12360  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12361  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12362  */
12363 static int
12364 lscf_instance_delete(scf_instance_t *inst, int force)
12365 {
12366 	scf_propertygroup_t *pg;
12367 	scf_snapshot_t *snap;
12368 	scf_iter_t *iter;
12369 	int err;
12370 	int external = 0;
12371 
12372 	/* If we're not forcing and the instance is running, refuse. */
12373 	if (!force && inst_is_running(inst)) {
12374 		char *fmri;
12375 
12376 		fmri = safe_malloc(max_scf_fmri_len + 1);
12377 
12378 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12379 			scfdie();
12380 
12381 		semerr(gettext("Instance %s may be running.  "
12382 		    "Use delete -f if it is not.\n"), fmri);
12383 
12384 		free(fmri);
12385 		return (DELETE_FAILURE);
12386 	}
12387 
12388 	pg = scf_pg_create(g_hndl);
12389 	if (pg == NULL)
12390 		scfdie();
12391 
12392 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12393 		(void) delete_dependents(pg);
12394 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12395 		scfdie();
12396 
12397 	scf_pg_destroy(pg);
12398 
12399 	/*
12400 	 * If the instance has some external dependencies then we must
12401 	 * keep them in case the instance is reimported otherwise the
12402 	 * dependencies would be lost on reimport.
12403 	 */
12404 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12405 	    (pg = scf_pg_create(g_hndl)) == NULL)
12406 		scfdie();
12407 
12408 	if (scf_iter_instance_pgs(iter, inst) < 0)
12409 		scfdie();
12410 
12411 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12412 		if (pg_is_external_dependency(pg)) {
12413 			external = 1;
12414 			continue;
12415 		}
12416 
12417 		if (scf_pg_delete(pg) != 0) {
12418 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12419 				scfdie();
12420 			else {
12421 				semerr(emsg_permission_denied);
12422 
12423 				(void) scf_iter_destroy(iter);
12424 				(void) scf_pg_destroy(pg);
12425 				return (DELETE_FAILURE);
12426 			}
12427 		}
12428 	}
12429 
12430 	if (err == -1)
12431 		scfdie();
12432 
12433 	(void) scf_iter_destroy(iter);
12434 	(void) scf_pg_destroy(pg);
12435 
12436 	if (external) {
12437 		/*
12438 		 * All the pgs have been deleted for the instance except
12439 		 * the ones holding the external dependencies.
12440 		 * For the job to be complete, we must also delete the
12441 		 * snapshots associated with the instance.
12442 		 */
12443 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12444 		    NULL)
12445 			scfdie();
12446 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12447 			scfdie();
12448 
12449 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12450 			scfdie();
12451 
12452 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12453 			if (_scf_snapshot_delete(snap) != 0) {
12454 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12455 					scfdie();
12456 
12457 				semerr(emsg_permission_denied);
12458 
12459 				(void) scf_iter_destroy(iter);
12460 				(void) scf_snapshot_destroy(snap);
12461 				return (DELETE_FAILURE);
12462 			}
12463 		}
12464 
12465 		if (err == -1)
12466 			scfdie();
12467 
12468 		(void) scf_iter_destroy(iter);
12469 		(void) scf_snapshot_destroy(snap);
12470 		return (DELETE_SUCCESS_EXTDEPS);
12471 	}
12472 
12473 	if (scf_instance_delete(inst) != 0) {
12474 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12475 			scfdie();
12476 
12477 		semerr(emsg_permission_denied);
12478 
12479 		return (DELETE_FAILURE);
12480 	}
12481 
12482 	return (DELETE_SUCCESS_NOEXTDEPS);
12483 }
12484 
12485 /*
12486  * lscf_service_delete() deletes a service.  Before calling
12487  * scf_service_delete(), though, we call lscf_instance_delete() for
12488  * each of the instances and delete dependencies in other entities
12489  * which were created as "dependents" of this service.  If there are
12490  * dependencies which were created for other entities, then we delete
12491  * all other property groups in the service and leave it as "empty".
12492  *
12493  * lscf_service_delete() verifies that there is no external dependency
12494  * pgs at the instance & service level before suppressing the service.
12495  * If there is, then we must not remove them now in case the service
12496  * is re-imported otherwise the dependencies would be lost. The external
12497  * dependency pgs will be removed if the dependencies are removed.
12498  *
12499  * Returns:
12500  *   DELETE_FAILURE		on failure
12501  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12502  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12503  */
12504 static int
12505 lscf_service_delete(scf_service_t *svc, int force)
12506 {
12507 	int r;
12508 	scf_instance_t *inst;
12509 	scf_propertygroup_t *pg;
12510 	scf_iter_t *iter;
12511 	int ret;
12512 	int external = 0;
12513 
12514 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12515 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12516 	    (iter = scf_iter_create(g_hndl)) == NULL)
12517 		scfdie();
12518 
12519 	if (scf_iter_service_instances(iter, svc) != 0)
12520 		scfdie();
12521 
12522 	for (r = scf_iter_next_instance(iter, inst);
12523 	    r == 1;
12524 	    r = scf_iter_next_instance(iter, inst)) {
12525 
12526 		ret = lscf_instance_delete(inst, force);
12527 		if (ret == DELETE_FAILURE) {
12528 			scf_iter_destroy(iter);
12529 			scf_pg_destroy(pg);
12530 			scf_instance_destroy(inst);
12531 			return (DELETE_FAILURE);
12532 		}
12533 
12534 		/*
12535 		 * Record the fact that there is some external dependencies
12536 		 * at the instance level.
12537 		 */
12538 		if (ret == DELETE_SUCCESS_EXTDEPS)
12539 			external |= 1;
12540 	}
12541 
12542 	if (r != 0)
12543 		scfdie();
12544 
12545 	/* Delete dependency property groups in dependent services. */
12546 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12547 		(void) delete_dependents(pg);
12548 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12549 		scfdie();
12550 
12551 	scf_iter_destroy(iter);
12552 	scf_pg_destroy(pg);
12553 	scf_instance_destroy(inst);
12554 
12555 	/*
12556 	 * If the service has some external dependencies then we don't
12557 	 * want to remove them in case the service is re-imported.
12558 	 */
12559 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12560 	    (iter = scf_iter_create(g_hndl)) == NULL)
12561 		scfdie();
12562 
12563 	if (scf_iter_service_pgs(iter, svc) < 0)
12564 		scfdie();
12565 
12566 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12567 		if (pg_is_external_dependency(pg)) {
12568 			external |= 2;
12569 			continue;
12570 		}
12571 
12572 		if (scf_pg_delete(pg) != 0) {
12573 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12574 				scfdie();
12575 			else {
12576 				semerr(emsg_permission_denied);
12577 
12578 				(void) scf_iter_destroy(iter);
12579 				(void) scf_pg_destroy(pg);
12580 				return (DELETE_FAILURE);
12581 			}
12582 		}
12583 	}
12584 
12585 	if (r == -1)
12586 		scfdie();
12587 
12588 	(void) scf_iter_destroy(iter);
12589 	(void) scf_pg_destroy(pg);
12590 
12591 	if (external != 0)
12592 		return (DELETE_SUCCESS_EXTDEPS);
12593 
12594 	if (scf_service_delete(svc) == 0)
12595 		return (DELETE_SUCCESS_NOEXTDEPS);
12596 
12597 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12598 		scfdie();
12599 
12600 	semerr(emsg_permission_denied);
12601 	return (DELETE_FAILURE);
12602 }
12603 
12604 static int
12605 delete_callback(void *data, scf_walkinfo_t *wip)
12606 {
12607 	int force = (int)data;
12608 
12609 	if (wip->inst != NULL)
12610 		(void) lscf_instance_delete(wip->inst, force);
12611 	else
12612 		(void) lscf_service_delete(wip->svc, force);
12613 
12614 	return (0);
12615 }
12616 
12617 void
12618 lscf_delete(const char *fmri, int force)
12619 {
12620 	scf_service_t *svc;
12621 	scf_instance_t *inst;
12622 	int ret;
12623 
12624 	lscf_prep_hndl();
12625 
12626 	if (cur_snap != NULL) {
12627 		if (!snaplevel_is_instance(cur_level)) {
12628 			char *buf;
12629 
12630 			buf = safe_malloc(max_scf_name_len + 1);
12631 			if (scf_instance_get_name(cur_inst, buf,
12632 			    max_scf_name_len + 1) >= 0) {
12633 				if (strcmp(buf, fmri) == 0) {
12634 					semerr(emsg_cant_modify_snapshots);
12635 					free(buf);
12636 					return;
12637 				}
12638 			} else if (scf_error() != SCF_ERROR_DELETED) {
12639 				scfdie();
12640 			}
12641 			free(buf);
12642 		}
12643 	} else if (cur_inst != NULL) {
12644 		/* EMPTY */;
12645 	} else if (cur_svc != NULL) {
12646 		inst = scf_instance_create(g_hndl);
12647 		if (inst == NULL)
12648 			scfdie();
12649 
12650 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12651 		    SCF_SUCCESS) {
12652 			(void) lscf_instance_delete(inst, force);
12653 			scf_instance_destroy(inst);
12654 			return;
12655 		}
12656 
12657 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12658 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12659 			scfdie();
12660 
12661 		scf_instance_destroy(inst);
12662 	} else {
12663 		assert(cur_scope != NULL);
12664 
12665 		svc = scf_service_create(g_hndl);
12666 		if (svc == NULL)
12667 			scfdie();
12668 
12669 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12670 		    SCF_SUCCESS) {
12671 			(void) lscf_service_delete(svc, force);
12672 			scf_service_destroy(svc);
12673 			return;
12674 		}
12675 
12676 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12677 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12678 			scfdie();
12679 
12680 		scf_service_destroy(svc);
12681 	}
12682 
12683 	/*
12684 	 * Match FMRI to entity.
12685 	 */
12686 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12687 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12688 		semerr(gettext("Failed to walk instances: %s\n"),
12689 		    scf_strerror(ret));
12690 	}
12691 }
12692 
12693 
12694 
12695 /*
12696  * :properties commands.  These all end with "pg" or "prop" and generally
12697  * operate on the currently selected entity.
12698  */
12699 
12700 /*
12701  * Property listing.  List the property groups, properties, their types and
12702  * their values for the currently selected entity.
12703  */
12704 static void
12705 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12706 {
12707 	char *buf;
12708 	uint32_t flags;
12709 
12710 	buf = safe_malloc(max_scf_pg_type_len + 1);
12711 
12712 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12713 		scfdie();
12714 
12715 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12716 		scfdie();
12717 
12718 	safe_printf("%-*s  %s", namewidth, name, buf);
12719 
12720 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12721 		safe_printf("\tNONPERSISTENT");
12722 
12723 	safe_printf("\n");
12724 
12725 	free(buf);
12726 }
12727 
12728 static boolean_t
12729 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12730 {
12731 	if (scf_property_get_value(prop, val) == 0) {
12732 		return (B_FALSE);
12733 	} else {
12734 		switch (scf_error()) {
12735 		case SCF_ERROR_NOT_FOUND:
12736 			return (B_FALSE);
12737 		case SCF_ERROR_PERMISSION_DENIED:
12738 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12739 			return (B_TRUE);
12740 		default:
12741 			scfdie();
12742 			/*NOTREACHED*/
12743 		}
12744 	}
12745 }
12746 
12747 static void
12748 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12749 {
12750 	scf_iter_t *iter;
12751 	scf_value_t *val;
12752 	const char *type;
12753 	int multiple_strings = 0;
12754 	int ret;
12755 
12756 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12757 	    (val = scf_value_create(g_hndl)) == NULL)
12758 		scfdie();
12759 
12760 	type = prop_to_typestr(prop);
12761 	assert(type != NULL);
12762 
12763 	safe_printf("%-*s  %-7s ", len, name, type);
12764 
12765 	if (prop_has_multiple_values(prop, val) &&
12766 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12767 	    scf_value_type(val) == SCF_TYPE_USTRING))
12768 		multiple_strings = 1;
12769 
12770 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12771 		scfdie();
12772 
12773 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12774 		char *buf;
12775 		ssize_t vlen, szret;
12776 
12777 		vlen = scf_value_get_as_string(val, NULL, 0);
12778 		if (vlen < 0)
12779 			scfdie();
12780 
12781 		buf = safe_malloc(vlen + 1);
12782 
12783 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12784 		if (szret < 0)
12785 			scfdie();
12786 		assert(szret <= vlen);
12787 
12788 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12789 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12790 			safe_printf(" \"");
12791 			(void) quote_and_print(buf, stdout, 0);
12792 			(void) putchar('"');
12793 			if (ferror(stdout)) {
12794 				(void) putchar('\n');
12795 				uu_die(gettext("Error writing to stdout.\n"));
12796 			}
12797 		} else {
12798 			safe_printf(" %s", buf);
12799 		}
12800 
12801 		free(buf);
12802 	}
12803 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12804 		scfdie();
12805 
12806 	if (putchar('\n') != '\n')
12807 		uu_die(gettext("Could not output newline"));
12808 }
12809 
12810 /*
12811  * Outputs template property group info for the describe subcommand.
12812  * If 'templates' == 2, verbose output is printed in the format expected
12813  * for describe -v, which includes all templates fields.  If pg is
12814  * not NULL, we're describing the template data, not an existing property
12815  * group, and formatting should be appropriate for describe -t.
12816  */
12817 static void
12818 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12819 {
12820 	char *buf;
12821 	uint8_t required;
12822 	scf_property_t *stability_prop;
12823 	scf_value_t *stability_val;
12824 
12825 	if (templates == 0)
12826 		return;
12827 
12828 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12829 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12830 		scfdie();
12831 
12832 	if (templates == 2 && pg != NULL) {
12833 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12834 		    stability_prop) == 0) {
12835 			if (prop_check_type(stability_prop,
12836 			    SCF_TYPE_ASTRING) == 0 &&
12837 			    prop_get_val(stability_prop, stability_val) == 0) {
12838 				char *stability;
12839 
12840 				stability = safe_malloc(max_scf_value_len + 1);
12841 
12842 				if (scf_value_get_astring(stability_val,
12843 				    stability, max_scf_value_len + 1) == -1 &&
12844 				    scf_error() != SCF_ERROR_NOT_FOUND)
12845 					scfdie();
12846 
12847 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12848 				    gettext("stability"), stability);
12849 
12850 				free(stability);
12851 			}
12852 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12853 			scfdie();
12854 	}
12855 
12856 	scf_property_destroy(stability_prop);
12857 	scf_value_destroy(stability_val);
12858 
12859 	if (pgt == NULL)
12860 		return;
12861 
12862 	if (pg == NULL || templates == 2) {
12863 		/* print type info only if scf_tmpl_pg_name succeeds */
12864 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12865 			if (pg != NULL)
12866 				safe_printf("%s", TMPL_INDENT);
12867 			safe_printf("%s: ", gettext("name"));
12868 			safe_printf("%s\n", buf);
12869 			free(buf);
12870 		}
12871 
12872 		/* print type info only if scf_tmpl_pg_type succeeds */
12873 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12874 			if (pg != NULL)
12875 				safe_printf("%s", TMPL_INDENT);
12876 			safe_printf("%s: ", gettext("type"));
12877 			safe_printf("%s\n", buf);
12878 			free(buf);
12879 		}
12880 	}
12881 
12882 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12883 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12884 		    required ? "true" : "false");
12885 
12886 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12887 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12888 		    buf);
12889 		free(buf);
12890 	}
12891 
12892 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12893 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12894 		    buf);
12895 		free(buf);
12896 	}
12897 
12898 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12899 		if (templates == 2)
12900 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12901 			    gettext("description"), buf);
12902 		else
12903 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12904 		free(buf);
12905 	}
12906 
12907 }
12908 
12909 /*
12910  * With as_value set to true, indent as appropriate for the value level.
12911  * If false, indent to appropriate level for inclusion in constraint
12912  * or choice printout.
12913  */
12914 static void
12915 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12916     int as_value)
12917 {
12918 	char *buf;
12919 
12920 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12921 		if (as_value == 0)
12922 			safe_printf("%s", TMPL_CHOICE_INDENT);
12923 		else
12924 			safe_printf("%s", TMPL_INDENT);
12925 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12926 		free(buf);
12927 	}
12928 
12929 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12930 		if (as_value == 0)
12931 			safe_printf("%s", TMPL_CHOICE_INDENT);
12932 		else
12933 			safe_printf("%s", TMPL_INDENT);
12934 		safe_printf("%s: %s\n", gettext("value description"), buf);
12935 		free(buf);
12936 	}
12937 }
12938 
12939 static void
12940 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12941 {
12942 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12943 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12944 	safe_printf("%s\n", val_buf);
12945 
12946 	print_template_value_details(prt, val_buf, 1);
12947 }
12948 
12949 static void
12950 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12951 {
12952 	int i, printed = 0;
12953 	scf_values_t values;
12954 	scf_count_ranges_t c_ranges;
12955 	scf_int_ranges_t i_ranges;
12956 
12957 	printed = 0;
12958 	i = 0;
12959 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12960 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12961 		    gettext("value constraints"));
12962 		printed++;
12963 		for (i = 0; i < values.value_count; ++i) {
12964 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12965 			    gettext("value name"), values.values_as_strings[i]);
12966 			if (verbose == 1)
12967 				print_template_value_details(prt,
12968 				    values.values_as_strings[i], 0);
12969 		}
12970 
12971 		scf_values_destroy(&values);
12972 	}
12973 
12974 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12975 		if (printed++ == 0)
12976 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12977 			    gettext("value constraints"));
12978 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12979 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12980 			    gettext("range"), c_ranges.scr_min[i],
12981 			    c_ranges.scr_max[i]);
12982 		}
12983 		scf_count_ranges_destroy(&c_ranges);
12984 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12985 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12986 		if (printed++ == 0)
12987 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12988 			    gettext("value constraints"));
12989 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12990 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12991 			    gettext("range"), i_ranges.sir_min[i],
12992 			    i_ranges.sir_max[i]);
12993 		}
12994 		scf_int_ranges_destroy(&i_ranges);
12995 	}
12996 }
12997 
12998 static void
12999 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
13000 {
13001 	int i = 0, printed = 0;
13002 	scf_values_t values;
13003 	scf_count_ranges_t c_ranges;
13004 	scf_int_ranges_t i_ranges;
13005 
13006 	printed = 0;
13007 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
13008 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13009 		    gettext("value constraints"));
13010 		printed++;
13011 		for (i = 0; i < values.value_count; i++) {
13012 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13013 			    gettext("value name"), values.values_as_strings[i]);
13014 			if (verbose == 1)
13015 				print_template_value_details(prt,
13016 				    values.values_as_strings[i], 0);
13017 		}
13018 
13019 		scf_values_destroy(&values);
13020 	}
13021 
13022 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13023 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13024 			if (printed++ == 0)
13025 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13026 				    gettext("value choices"));
13027 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13028 			    gettext("range"), c_ranges.scr_min[i],
13029 			    c_ranges.scr_max[i]);
13030 		}
13031 		scf_count_ranges_destroy(&c_ranges);
13032 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13033 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13034 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
13035 			if (printed++ == 0)
13036 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13037 				    gettext("value choices"));
13038 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
13039 			    gettext("range"), i_ranges.sir_min[i],
13040 			    i_ranges.sir_max[i]);
13041 		}
13042 		scf_int_ranges_destroy(&i_ranges);
13043 	}
13044 }
13045 
13046 static void
13047 list_values_by_template(scf_prop_tmpl_t *prt)
13048 {
13049 	print_template_constraints(prt, 1);
13050 	print_template_choices(prt, 1);
13051 }
13052 
13053 static void
13054 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13055 {
13056 	char *val_buf;
13057 	scf_iter_t *iter;
13058 	scf_value_t *val;
13059 	int ret;
13060 
13061 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13062 	    (val = scf_value_create(g_hndl)) == NULL)
13063 		scfdie();
13064 
13065 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13066 		scfdie();
13067 
13068 	val_buf = safe_malloc(max_scf_value_len + 1);
13069 
13070 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13071 		if (scf_value_get_as_string(val, val_buf,
13072 		    max_scf_value_len + 1) < 0)
13073 			scfdie();
13074 
13075 		print_template_value(prt, val_buf);
13076 	}
13077 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13078 		scfdie();
13079 	free(val_buf);
13080 
13081 	print_template_constraints(prt, 0);
13082 	print_template_choices(prt, 0);
13083 
13084 }
13085 
13086 /*
13087  * Outputs property info for the describe subcommand
13088  * Verbose output if templates == 2, -v option of svccfg describe
13089  * Displays template data if prop is not NULL, -t option of svccfg describe
13090  */
13091 static void
13092 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13093 {
13094 	char *buf;
13095 	uint8_t u_buf;
13096 	int i;
13097 	uint64_t min, max;
13098 	scf_values_t values;
13099 
13100 	if (prt == NULL || templates == 0)
13101 		return;
13102 
13103 	if (prop == NULL) {
13104 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13105 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
13106 			safe_printf("%s\n", buf);
13107 			free(buf);
13108 		} else
13109 			safe_printf("(%s)\n", gettext("any"));
13110 	}
13111 
13112 	if (prop == NULL || templates == 2) {
13113 		if (prop != NULL)
13114 			safe_printf("%s", TMPL_INDENT);
13115 		else
13116 			safe_printf("%s", TMPL_VALUE_INDENT);
13117 		safe_printf("%s: ", gettext("type"));
13118 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13119 			safe_printf("%s\n", buf);
13120 			free(buf);
13121 		} else
13122 			safe_printf("(%s)\n", gettext("any"));
13123 	}
13124 
13125 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13126 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13127 		    u_buf ? "true" : "false");
13128 
13129 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13130 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13131 		    buf);
13132 		free(buf);
13133 	}
13134 
13135 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13136 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13137 		    buf);
13138 		free(buf);
13139 	}
13140 
13141 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13142 		safe_printf("%s%s\n", TMPL_INDENT, buf);
13143 		free(buf);
13144 	}
13145 
13146 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13147 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13148 		    scf_tmpl_visibility_to_string(u_buf));
13149 
13150 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13151 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13152 		    gettext("minimum number of values"), min);
13153 		if (max == ULLONG_MAX) {
13154 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13155 			    gettext("maximum number of values"),
13156 			    gettext("unlimited"));
13157 		} else {
13158 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13159 			    gettext("maximum number of values"), max);
13160 		}
13161 	}
13162 
13163 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13164 		for (i = 0; i < values.value_count; i++) {
13165 			if (i == 0) {
13166 				safe_printf("%s%s:", TMPL_INDENT,
13167 				    gettext("internal separators"));
13168 			}
13169 			safe_printf(" \"%s\"", values.values_as_strings[i]);
13170 		}
13171 		safe_printf("\n");
13172 	}
13173 
13174 	if (templates != 2)
13175 		return;
13176 
13177 	if (prop != NULL)
13178 		list_values_tmpl(prt, prop);
13179 	else
13180 		list_values_by_template(prt);
13181 }
13182 
13183 static char *
13184 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13185 {
13186 	char *rv;
13187 
13188 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
13189 	if (rv == NULL) {
13190 		switch (scf_error()) {
13191 		case SCF_ERROR_NOT_FOUND:
13192 			break;
13193 		default:
13194 			scfdie();
13195 		}
13196 	}
13197 	return (rv);
13198 }
13199 
13200 static void
13201 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13202 {
13203 	size_t doc_len;
13204 	size_t man_len;
13205 	char *pg_name;
13206 	char *text = NULL;
13207 	int rv;
13208 
13209 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13210 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13211 	pg_name = safe_malloc(max_scf_name_len + 1);
13212 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13213 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13214 			scfdie();
13215 		}
13216 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13217 			/* Display doc_link and and uri */
13218 			safe_printf("%s%s:\n", TMPL_INDENT,
13219 			    gettext("doc_link"));
13220 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13221 			if (text != NULL) {
13222 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13223 				    TMPL_INDENT, gettext("name"), text);
13224 				uu_free(text);
13225 			}
13226 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
13227 			if (text != NULL) {
13228 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13229 				    gettext("uri"), text);
13230 				uu_free(text);
13231 			}
13232 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13233 		    man_len) == 0) {
13234 			/* Display manpage title, section and path */
13235 			safe_printf("%s%s:\n", TMPL_INDENT,
13236 			    gettext("manpage"));
13237 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13238 			if (text != NULL) {
13239 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13240 				    TMPL_INDENT, gettext("title"), text);
13241 				uu_free(text);
13242 			}
13243 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13244 			if (text != NULL) {
13245 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13246 				    TMPL_INDENT, gettext("section"), text);
13247 				uu_free(text);
13248 			}
13249 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13250 			if (text != NULL) {
13251 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13252 				    TMPL_INDENT, gettext("manpath"), text);
13253 				uu_free(text);
13254 			}
13255 		}
13256 	}
13257 	if (rv == -1)
13258 		scfdie();
13259 
13260 done:
13261 	free(pg_name);
13262 }
13263 
13264 static void
13265 list_entity_tmpl(int templates)
13266 {
13267 	char *common_name = NULL;
13268 	char *description = NULL;
13269 	char *locale = NULL;
13270 	scf_iter_t *iter;
13271 	scf_propertygroup_t *pg;
13272 	scf_property_t *prop;
13273 	int r;
13274 	scf_value_t *val;
13275 
13276 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13277 	    (prop = scf_property_create(g_hndl)) == NULL ||
13278 	    (val = scf_value_create(g_hndl)) == NULL ||
13279 	    (iter = scf_iter_create(g_hndl)) == NULL)
13280 		scfdie();
13281 
13282 	locale = setlocale(LC_MESSAGES, NULL);
13283 
13284 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13285 		common_name = safe_malloc(max_scf_value_len + 1);
13286 
13287 		/* Try both the current locale and the "C" locale. */
13288 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
13289 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
13290 		    scf_pg_get_property(pg, "C", prop) == 0)) {
13291 			if (prop_get_val(prop, val) == 0 &&
13292 			    scf_value_get_ustring(val, common_name,
13293 			    max_scf_value_len + 1) != -1) {
13294 				safe_printf("%s%s: %s\n", TMPL_INDENT,
13295 				    gettext("common name"), common_name);
13296 			}
13297 		}
13298 	}
13299 
13300 	/*
13301 	 * Do description, manpages, and doc links if templates == 2.
13302 	 */
13303 	if (templates == 2) {
13304 		/* Get the description. */
13305 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13306 			description = safe_malloc(max_scf_value_len + 1);
13307 
13308 			/* Try both the current locale and the "C" locale. */
13309 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
13310 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
13311 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13312 				if (prop_get_val(prop, val) == 0 &&
13313 				    scf_value_get_ustring(val, description,
13314 				    max_scf_value_len + 1) != -1) {
13315 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13316 					    gettext("description"),
13317 					    description);
13318 				}
13319 			}
13320 		}
13321 
13322 		/* Process doc_link & manpage elements. */
13323 		if (cur_level != NULL) {
13324 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13325 			    SCF_GROUP_TEMPLATE);
13326 		} else if (cur_inst != NULL) {
13327 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13328 			    SCF_GROUP_TEMPLATE);
13329 		} else {
13330 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13331 			    SCF_GROUP_TEMPLATE);
13332 		}
13333 		if (r == 0) {
13334 			display_documentation(iter, pg);
13335 		}
13336 	}
13337 
13338 	free(common_name);
13339 	free(description);
13340 	scf_pg_destroy(pg);
13341 	scf_property_destroy(prop);
13342 	scf_value_destroy(val);
13343 	scf_iter_destroy(iter);
13344 }
13345 
13346 static void
13347 listtmpl(const char *pattern, int templates)
13348 {
13349 	scf_pg_tmpl_t *pgt;
13350 	scf_prop_tmpl_t *prt;
13351 	char *snapbuf = NULL;
13352 	char *fmribuf;
13353 	char *pg_name = NULL, *prop_name = NULL;
13354 	ssize_t prop_name_size;
13355 	char *qual_prop_name;
13356 	char *search_name;
13357 	int listed = 0;
13358 
13359 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13360 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13361 		scfdie();
13362 
13363 	fmribuf = safe_malloc(max_scf_name_len + 1);
13364 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13365 
13366 	if (cur_snap != NULL) {
13367 		snapbuf = safe_malloc(max_scf_name_len + 1);
13368 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13369 		    max_scf_name_len + 1) < 0)
13370 			scfdie();
13371 	}
13372 
13373 	if (cur_inst != NULL) {
13374 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13375 		    max_scf_name_len + 1) < 0)
13376 			scfdie();
13377 	} else if (cur_svc != NULL) {
13378 		if (scf_service_to_fmri(cur_svc, fmribuf,
13379 		    max_scf_name_len + 1) < 0)
13380 			scfdie();
13381 	} else
13382 		abort();
13383 
13384 	/* If pattern is specified, we want to list only those items. */
13385 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13386 		listed = 0;
13387 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13388 		    fnmatch(pattern, pg_name, 0) == 0)) {
13389 			list_pg_tmpl(pgt, NULL, templates);
13390 			listed++;
13391 		}
13392 
13393 		scf_tmpl_prop_reset(prt);
13394 
13395 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13396 			search_name = NULL;
13397 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13398 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13399 				if (snprintf(qual_prop_name,
13400 				    max_scf_name_len + 1, "%s/%s",
13401 				    pg_name, prop_name) >=
13402 				    max_scf_name_len + 1) {
13403 					prop_name_size = -1;
13404 				} else {
13405 					search_name = qual_prop_name;
13406 				}
13407 			}
13408 			if (listed > 0 || pattern == NULL ||
13409 			    (prop_name_size > 0 &&
13410 			    fnmatch(pattern, search_name,
13411 			    FNM_PATHNAME) == 0))
13412 				list_prop_tmpl(prt, NULL, templates);
13413 			if (prop_name != NULL) {
13414 				free(prop_name);
13415 				prop_name = NULL;
13416 			}
13417 		}
13418 		if (pg_name != NULL) {
13419 			free(pg_name);
13420 			pg_name = NULL;
13421 		}
13422 	}
13423 
13424 	scf_tmpl_prop_destroy(prt);
13425 	scf_tmpl_pg_destroy(pgt);
13426 	free(snapbuf);
13427 	free(fmribuf);
13428 	free(qual_prop_name);
13429 }
13430 
13431 static void
13432 listprop(const char *pattern, int only_pgs, int templates)
13433 {
13434 	scf_propertygroup_t *pg;
13435 	scf_property_t *prop;
13436 	scf_iter_t *iter, *piter;
13437 	char *pgnbuf, *prnbuf, *ppnbuf;
13438 	scf_pg_tmpl_t *pgt, *pgtp;
13439 	scf_prop_tmpl_t *prt;
13440 
13441 	void **objects;
13442 	char **names;
13443 	void **tmpls;
13444 	int allocd, i;
13445 
13446 	int ret;
13447 	ssize_t pgnlen, prnlen, szret;
13448 	size_t max_len = 0;
13449 
13450 	if (cur_svc == NULL && cur_inst == NULL) {
13451 		semerr(emsg_entity_not_selected);
13452 		return;
13453 	}
13454 
13455 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13456 	    (prop = scf_property_create(g_hndl)) == NULL ||
13457 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13458 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13459 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13460 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13461 		scfdie();
13462 
13463 	prnbuf = safe_malloc(max_scf_name_len + 1);
13464 
13465 	if (cur_level != NULL)
13466 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13467 	else if (cur_inst != NULL)
13468 		ret = scf_iter_instance_pgs(iter, cur_inst);
13469 	else
13470 		ret = scf_iter_service_pgs(iter, cur_svc);
13471 	if (ret != 0) {
13472 		return;
13473 	}
13474 
13475 	/*
13476 	 * We want to only list items which match pattern, and we want the
13477 	 * second column to line up, so during the first pass we'll save
13478 	 * matching items, their names, and their templates in objects,
13479 	 * names, and tmpls, computing the maximum name length as we go,
13480 	 * and then we'll print them out.
13481 	 *
13482 	 * Note: We always keep an extra slot available so the array can be
13483 	 * NULL-terminated.
13484 	 */
13485 	i = 0;
13486 	allocd = 1;
13487 	objects = safe_malloc(sizeof (*objects));
13488 	names = safe_malloc(sizeof (*names));
13489 	tmpls = safe_malloc(sizeof (*tmpls));
13490 
13491 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13492 		int new_pg = 0;
13493 		int print_props = 0;
13494 		pgtp = NULL;
13495 
13496 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13497 		if (pgnlen < 0)
13498 			scfdie();
13499 
13500 		pgnbuf = safe_malloc(pgnlen + 1);
13501 
13502 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13503 		if (szret < 0)
13504 			scfdie();
13505 		assert(szret <= pgnlen);
13506 
13507 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13508 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13509 				scfdie();
13510 			pgtp = NULL;
13511 		} else {
13512 			pgtp = pgt;
13513 		}
13514 
13515 		if (pattern == NULL ||
13516 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13517 			if (i+1 >= allocd) {
13518 				allocd *= 2;
13519 				objects = realloc(objects,
13520 				    sizeof (*objects) * allocd);
13521 				names =
13522 				    realloc(names, sizeof (*names) * allocd);
13523 				tmpls = realloc(tmpls,
13524 				    sizeof (*tmpls) * allocd);
13525 				if (objects == NULL || names == NULL ||
13526 				    tmpls == NULL)
13527 					uu_die(gettext("Out of memory"));
13528 			}
13529 			objects[i] = pg;
13530 			names[i] = pgnbuf;
13531 
13532 			if (pgtp == NULL)
13533 				tmpls[i] = NULL;
13534 			else
13535 				tmpls[i] = pgt;
13536 
13537 			++i;
13538 
13539 			if (pgnlen > max_len)
13540 				max_len = pgnlen;
13541 
13542 			new_pg = 1;
13543 			print_props = 1;
13544 		}
13545 
13546 		if (only_pgs) {
13547 			if (new_pg) {
13548 				pg = scf_pg_create(g_hndl);
13549 				if (pg == NULL)
13550 					scfdie();
13551 				pgt = scf_tmpl_pg_create(g_hndl);
13552 				if (pgt == NULL)
13553 					scfdie();
13554 			} else
13555 				free(pgnbuf);
13556 
13557 			continue;
13558 		}
13559 
13560 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13561 			scfdie();
13562 
13563 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13564 			prnlen = scf_property_get_name(prop, prnbuf,
13565 			    max_scf_name_len + 1);
13566 			if (prnlen < 0)
13567 				scfdie();
13568 
13569 			/* Will prepend the property group name and a slash. */
13570 			prnlen += pgnlen + 1;
13571 
13572 			ppnbuf = safe_malloc(prnlen + 1);
13573 
13574 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13575 			    prnbuf) < 0)
13576 				uu_die("snprintf");
13577 
13578 			if (pattern == NULL || print_props == 1 ||
13579 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13580 				if (i+1 >= allocd) {
13581 					allocd *= 2;
13582 					objects = realloc(objects,
13583 					    sizeof (*objects) * allocd);
13584 					names = realloc(names,
13585 					    sizeof (*names) * allocd);
13586 					tmpls = realloc(tmpls,
13587 					    sizeof (*tmpls) * allocd);
13588 					if (objects == NULL || names == NULL ||
13589 					    tmpls == NULL)
13590 						uu_die(gettext(
13591 						    "Out of memory"));
13592 				}
13593 
13594 				objects[i] = prop;
13595 				names[i] = ppnbuf;
13596 
13597 				if (pgtp != NULL) {
13598 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13599 					    prt, 0) < 0) {
13600 						if (scf_error() !=
13601 						    SCF_ERROR_NOT_FOUND)
13602 							scfdie();
13603 						tmpls[i] = NULL;
13604 					} else {
13605 						tmpls[i] = prt;
13606 					}
13607 				} else {
13608 					tmpls[i] = NULL;
13609 				}
13610 
13611 				++i;
13612 
13613 				if (prnlen > max_len)
13614 					max_len = prnlen;
13615 
13616 				prop = scf_property_create(g_hndl);
13617 				prt = scf_tmpl_prop_create(g_hndl);
13618 			} else {
13619 				free(ppnbuf);
13620 			}
13621 		}
13622 
13623 		if (new_pg) {
13624 			pg = scf_pg_create(g_hndl);
13625 			if (pg == NULL)
13626 				scfdie();
13627 			pgt = scf_tmpl_pg_create(g_hndl);
13628 			if (pgt == NULL)
13629 				scfdie();
13630 		} else
13631 			free(pgnbuf);
13632 	}
13633 	if (ret != 0)
13634 		scfdie();
13635 
13636 	objects[i] = NULL;
13637 
13638 	scf_pg_destroy(pg);
13639 	scf_tmpl_pg_destroy(pgt);
13640 	scf_property_destroy(prop);
13641 	scf_tmpl_prop_destroy(prt);
13642 
13643 	for (i = 0; objects[i] != NULL; ++i) {
13644 		if (strchr(names[i], '/') == NULL) {
13645 			/* property group */
13646 			pg = (scf_propertygroup_t *)objects[i];
13647 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13648 			list_pg_info(pg, names[i], max_len);
13649 			list_pg_tmpl(pgt, pg, templates);
13650 			free(names[i]);
13651 			scf_pg_destroy(pg);
13652 			if (pgt != NULL)
13653 				scf_tmpl_pg_destroy(pgt);
13654 		} else {
13655 			/* property */
13656 			prop = (scf_property_t *)objects[i];
13657 			prt = (scf_prop_tmpl_t *)tmpls[i];
13658 			list_prop_info(prop, names[i], max_len);
13659 			list_prop_tmpl(prt, prop, templates);
13660 			free(names[i]);
13661 			scf_property_destroy(prop);
13662 			if (prt != NULL)
13663 				scf_tmpl_prop_destroy(prt);
13664 		}
13665 	}
13666 
13667 	free(names);
13668 	free(objects);
13669 	free(tmpls);
13670 }
13671 
13672 void
13673 lscf_listpg(const char *pattern)
13674 {
13675 	lscf_prep_hndl();
13676 
13677 	listprop(pattern, 1, 0);
13678 }
13679 
13680 /*
13681  * Property group and property creation, setting, and deletion.  setprop (and
13682  * its alias, addprop) can either create a property group of a given type, or
13683  * it can create or set a property to a given type and list of values.
13684  */
13685 void
13686 lscf_addpg(const char *name, const char *type, const char *flags)
13687 {
13688 	scf_propertygroup_t *pg;
13689 	int ret;
13690 	uint32_t flgs = 0;
13691 	const char *cp;
13692 
13693 
13694 	lscf_prep_hndl();
13695 
13696 	if (cur_snap != NULL) {
13697 		semerr(emsg_cant_modify_snapshots);
13698 		return;
13699 	}
13700 
13701 	if (cur_inst == NULL && cur_svc == NULL) {
13702 		semerr(emsg_entity_not_selected);
13703 		return;
13704 	}
13705 
13706 	if (flags != NULL) {
13707 		for (cp = flags; *cp != '\0'; ++cp) {
13708 			switch (*cp) {
13709 			case 'P':
13710 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13711 				break;
13712 
13713 			case 'p':
13714 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13715 				break;
13716 
13717 			default:
13718 				semerr(gettext("Invalid property group flag "
13719 				    "%c."), *cp);
13720 				return;
13721 			}
13722 		}
13723 	}
13724 
13725 	pg = scf_pg_create(g_hndl);
13726 	if (pg == NULL)
13727 		scfdie();
13728 
13729 	if (cur_inst != NULL)
13730 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13731 	else
13732 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13733 
13734 	if (ret != SCF_SUCCESS) {
13735 		switch (scf_error()) {
13736 		case SCF_ERROR_INVALID_ARGUMENT:
13737 			semerr(gettext("Name, type, or flags are invalid.\n"));
13738 			break;
13739 
13740 		case SCF_ERROR_EXISTS:
13741 			semerr(gettext("Property group already exists.\n"));
13742 			break;
13743 
13744 		case SCF_ERROR_PERMISSION_DENIED:
13745 			semerr(emsg_permission_denied);
13746 			break;
13747 
13748 		case SCF_ERROR_BACKEND_ACCESS:
13749 			semerr(gettext("Backend refused access.\n"));
13750 			break;
13751 
13752 		default:
13753 			scfdie();
13754 		}
13755 	}
13756 
13757 	scf_pg_destroy(pg);
13758 
13759 	private_refresh();
13760 }
13761 
13762 void
13763 lscf_delpg(char *name)
13764 {
13765 	lscf_prep_hndl();
13766 
13767 	if (cur_snap != NULL) {
13768 		semerr(emsg_cant_modify_snapshots);
13769 		return;
13770 	}
13771 
13772 	if (cur_inst == NULL && cur_svc == NULL) {
13773 		semerr(emsg_entity_not_selected);
13774 		return;
13775 	}
13776 
13777 	if (strchr(name, '/') != NULL) {
13778 		semerr(emsg_invalid_pg_name, name);
13779 		return;
13780 	}
13781 
13782 	lscf_delprop(name);
13783 }
13784 
13785 /*
13786  * scf_delhash() is used to remove the property group related to the
13787  * hash entry for a specific manifest in the repository. pgname will be
13788  * constructed from the location of the manifest file. If deathrow isn't 0,
13789  * manifest file doesn't need to exist (manifest string will be used as
13790  * an absolute path).
13791  */
13792 void
13793 lscf_delhash(char *manifest, int deathrow)
13794 {
13795 	char *pgname;
13796 
13797 	if (cur_snap != NULL ||
13798 	    cur_inst != NULL || cur_svc != NULL) {
13799 		warn(gettext("error, an entity is selected\n"));
13800 		return;
13801 	}
13802 
13803 	/* select smf/manifest */
13804 	lscf_select(HASH_SVC);
13805 	/*
13806 	 * Translate the manifest file name to property name. In the deathrow
13807 	 * case, the manifest file does not need to exist.
13808 	 */
13809 	pgname = mhash_filename_to_propname(manifest,
13810 	    deathrow ? B_TRUE : B_FALSE);
13811 	if (pgname == NULL) {
13812 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13813 		return;
13814 	}
13815 	/* delete the hash property name */
13816 	lscf_delpg(pgname);
13817 }
13818 
13819 void
13820 lscf_listprop(const char *pattern)
13821 {
13822 	lscf_prep_hndl();
13823 
13824 	listprop(pattern, 0, 0);
13825 }
13826 
13827 int
13828 lscf_setprop(const char *pgname, const char *type, const char *value,
13829     const uu_list_t *values)
13830 {
13831 	scf_type_t ty, current_ty;
13832 	scf_service_t *svc;
13833 	scf_propertygroup_t *pg, *parent_pg;
13834 	scf_property_t *prop, *parent_prop;
13835 	scf_pg_tmpl_t *pgt;
13836 	scf_prop_tmpl_t *prt;
13837 	int ret, result = 0;
13838 	scf_transaction_t *tx;
13839 	scf_transaction_entry_t *e;
13840 	scf_value_t *v;
13841 	uu_list_walk_t *walk;
13842 	string_list_t *sp;
13843 	char *propname;
13844 	int req_quotes = 0;
13845 
13846 	lscf_prep_hndl();
13847 
13848 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13849 	    (svc = scf_service_create(g_hndl)) == NULL ||
13850 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13851 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13852 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13853 	    (prop = scf_property_create(g_hndl)) == NULL ||
13854 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13855 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13856 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13857 		scfdie();
13858 
13859 	if (cur_snap != NULL) {
13860 		semerr(emsg_cant_modify_snapshots);
13861 		goto fail;
13862 	}
13863 
13864 	if (cur_inst == NULL && cur_svc == NULL) {
13865 		semerr(emsg_entity_not_selected);
13866 		goto fail;
13867 	}
13868 
13869 	propname = strchr(pgname, '/');
13870 	if (propname == NULL) {
13871 		semerr(gettext("Property names must contain a `/'.\n"));
13872 		goto fail;
13873 	}
13874 
13875 	*propname = '\0';
13876 	++propname;
13877 
13878 	if (type != NULL) {
13879 		ty = string_to_type(type);
13880 		if (ty == SCF_TYPE_INVALID) {
13881 			semerr(gettext("Unknown type \"%s\".\n"), type);
13882 			goto fail;
13883 		}
13884 	}
13885 
13886 	if (cur_inst != NULL)
13887 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13888 	else
13889 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13890 	if (ret != SCF_SUCCESS) {
13891 		switch (scf_error()) {
13892 		case SCF_ERROR_NOT_FOUND:
13893 			semerr(emsg_no_such_pg, pgname);
13894 			goto fail;
13895 
13896 		case SCF_ERROR_INVALID_ARGUMENT:
13897 			semerr(emsg_invalid_pg_name, pgname);
13898 			goto fail;
13899 
13900 		default:
13901 			scfdie();
13902 			break;
13903 		}
13904 	}
13905 
13906 	do {
13907 		if (scf_pg_update(pg) == -1)
13908 			scfdie();
13909 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13910 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13911 				scfdie();
13912 
13913 			semerr(emsg_permission_denied);
13914 			goto fail;
13915 		}
13916 
13917 		ret = scf_pg_get_property(pg, propname, prop);
13918 		if (ret == SCF_SUCCESS) {
13919 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13920 				scfdie();
13921 
13922 			if (type == NULL)
13923 				ty = current_ty;
13924 			if (scf_transaction_property_change_type(tx, e,
13925 			    propname, ty) == -1)
13926 				scfdie();
13927 
13928 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13929 			/* Infer the type, if possible. */
13930 			if (type == NULL) {
13931 				/*
13932 				 * First check if we're an instance and the
13933 				 * property is set on the service.
13934 				 */
13935 				if (cur_inst != NULL &&
13936 				    scf_instance_get_parent(cur_inst,
13937 				    svc) == 0 &&
13938 				    scf_service_get_pg(cur_svc, pgname,
13939 				    parent_pg) == 0 &&
13940 				    scf_pg_get_property(parent_pg, propname,
13941 				    parent_prop) == 0 &&
13942 				    scf_property_type(parent_prop,
13943 				    &current_ty) == 0) {
13944 					ty = current_ty;
13945 
13946 				/* Then check for a type set in a template. */
13947 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13948 				    0) == 0 &&
13949 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13950 				    0) == 0 &&
13951 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13952 					ty = current_ty;
13953 
13954 				/* If type can't be inferred, fail. */
13955 				} else {
13956 					semerr(gettext("Type required for new "
13957 					    "properties.\n"));
13958 					goto fail;
13959 				}
13960 			}
13961 			if (scf_transaction_property_new(tx, e, propname,
13962 			    ty) == -1)
13963 				scfdie();
13964 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13965 			semerr(emsg_invalid_prop_name, propname);
13966 			goto fail;
13967 		} else {
13968 			scfdie();
13969 		}
13970 
13971 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13972 			req_quotes = 1;
13973 
13974 		if (value != NULL) {
13975 			v = string_to_value(value, ty, 0);
13976 
13977 			if (v == NULL)
13978 				goto fail;
13979 
13980 			ret = scf_entry_add_value(e, v);
13981 			assert(ret == SCF_SUCCESS);
13982 		} else {
13983 			assert(values != NULL);
13984 
13985 			walk = uu_list_walk_start((uu_list_t *)values,
13986 			    UU_DEFAULT);
13987 			if (walk == NULL)
13988 				uu_die(gettext("Could not walk list"));
13989 
13990 			for (sp = uu_list_walk_next(walk); sp != NULL;
13991 			    sp = uu_list_walk_next(walk)) {
13992 				v = string_to_value(sp->str, ty, req_quotes);
13993 
13994 				if (v == NULL) {
13995 					scf_entry_destroy_children(e);
13996 					goto fail;
13997 				}
13998 
13999 				ret = scf_entry_add_value(e, v);
14000 				assert(ret == SCF_SUCCESS);
14001 			}
14002 			uu_list_walk_end(walk);
14003 		}
14004 		result = scf_transaction_commit(tx);
14005 
14006 		scf_transaction_reset(tx);
14007 		scf_entry_destroy_children(e);
14008 	} while (result == 0);
14009 
14010 	if (result < 0) {
14011 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14012 			scfdie();
14013 
14014 		semerr(emsg_permission_denied);
14015 		goto fail;
14016 	}
14017 
14018 	ret = 0;
14019 
14020 	private_refresh();
14021 
14022 	goto cleanup;
14023 
14024 fail:
14025 	ret = -1;
14026 
14027 cleanup:
14028 	scf_transaction_destroy(tx);
14029 	scf_entry_destroy(e);
14030 	scf_service_destroy(svc);
14031 	scf_pg_destroy(parent_pg);
14032 	scf_pg_destroy(pg);
14033 	scf_property_destroy(parent_prop);
14034 	scf_property_destroy(prop);
14035 	scf_tmpl_pg_destroy(pgt);
14036 	scf_tmpl_prop_destroy(prt);
14037 
14038 	return (ret);
14039 }
14040 
14041 void
14042 lscf_delprop(char *pgn)
14043 {
14044 	char *slash, *pn;
14045 	scf_propertygroup_t *pg;
14046 	scf_transaction_t *tx;
14047 	scf_transaction_entry_t *e;
14048 	int ret;
14049 
14050 
14051 	lscf_prep_hndl();
14052 
14053 	if (cur_snap != NULL) {
14054 		semerr(emsg_cant_modify_snapshots);
14055 		return;
14056 	}
14057 
14058 	if (cur_inst == NULL && cur_svc == NULL) {
14059 		semerr(emsg_entity_not_selected);
14060 		return;
14061 	}
14062 
14063 	pg = scf_pg_create(g_hndl);
14064 	if (pg == NULL)
14065 		scfdie();
14066 
14067 	slash = strchr(pgn, '/');
14068 	if (slash == NULL) {
14069 		pn = NULL;
14070 	} else {
14071 		*slash = '\0';
14072 		pn = slash + 1;
14073 	}
14074 
14075 	if (cur_inst != NULL)
14076 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
14077 	else
14078 		ret = scf_service_get_pg(cur_svc, pgn, pg);
14079 	if (ret != SCF_SUCCESS) {
14080 		switch (scf_error()) {
14081 		case SCF_ERROR_NOT_FOUND:
14082 			semerr(emsg_no_such_pg, pgn);
14083 			break;
14084 
14085 		case SCF_ERROR_INVALID_ARGUMENT:
14086 			semerr(emsg_invalid_pg_name, pgn);
14087 			break;
14088 
14089 		default:
14090 			scfdie();
14091 		}
14092 
14093 		scf_pg_destroy(pg);
14094 
14095 		return;
14096 	}
14097 
14098 	if (pn == NULL) {
14099 		/* Try to delete the property group. */
14100 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
14101 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14102 				scfdie();
14103 
14104 			semerr(emsg_permission_denied);
14105 		} else {
14106 			private_refresh();
14107 		}
14108 
14109 		scf_pg_destroy(pg);
14110 		return;
14111 	}
14112 
14113 	e = scf_entry_create(g_hndl);
14114 	tx = scf_transaction_create(g_hndl);
14115 
14116 	do {
14117 		if (scf_pg_update(pg) == -1)
14118 			scfdie();
14119 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14120 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14121 				scfdie();
14122 
14123 			semerr(emsg_permission_denied);
14124 			break;
14125 		}
14126 
14127 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14128 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
14129 				semerr(gettext("No such property %s/%s.\n"),
14130 				    pgn, pn);
14131 				break;
14132 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14133 				semerr(emsg_invalid_prop_name, pn);
14134 				break;
14135 			} else {
14136 				scfdie();
14137 			}
14138 		}
14139 
14140 		ret = scf_transaction_commit(tx);
14141 
14142 		if (ret == 0)
14143 			scf_transaction_reset(tx);
14144 	} while (ret == 0);
14145 
14146 	if (ret < 0) {
14147 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14148 			scfdie();
14149 
14150 		semerr(emsg_permission_denied);
14151 	} else {
14152 		private_refresh();
14153 	}
14154 
14155 	scf_transaction_destroy(tx);
14156 	scf_entry_destroy(e);
14157 	scf_pg_destroy(pg);
14158 }
14159 
14160 /*
14161  * Property editing.
14162  */
14163 
14164 static int
14165 write_edit_script(FILE *strm)
14166 {
14167 	char *fmribuf;
14168 	ssize_t fmrilen;
14169 
14170 	scf_propertygroup_t *pg;
14171 	scf_property_t *prop;
14172 	scf_value_t *val;
14173 	scf_type_t ty;
14174 	int ret, result = 0;
14175 	scf_iter_t *iter, *piter, *viter;
14176 	char *buf, *tybuf, *pname;
14177 	const char *emsg_write_error;
14178 
14179 
14180 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14181 
14182 
14183 	/* select fmri */
14184 	if (cur_inst != NULL) {
14185 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14186 		if (fmrilen < 0)
14187 			scfdie();
14188 		fmribuf = safe_malloc(fmrilen + 1);
14189 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14190 			scfdie();
14191 	} else {
14192 		assert(cur_svc != NULL);
14193 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14194 		if (fmrilen < 0)
14195 			scfdie();
14196 		fmribuf = safe_malloc(fmrilen + 1);
14197 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14198 			scfdie();
14199 	}
14200 
14201 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14202 		warn(emsg_write_error, strerror(errno));
14203 		free(fmribuf);
14204 		return (-1);
14205 	}
14206 
14207 	free(fmribuf);
14208 
14209 
14210 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
14211 	    (prop = scf_property_create(g_hndl)) == NULL ||
14212 	    (val = scf_value_create(g_hndl)) == NULL ||
14213 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14214 	    (piter = scf_iter_create(g_hndl)) == NULL ||
14215 	    (viter = scf_iter_create(g_hndl)) == NULL)
14216 		scfdie();
14217 
14218 	buf = safe_malloc(max_scf_name_len + 1);
14219 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
14220 	pname = safe_malloc(max_scf_name_len + 1);
14221 
14222 	if (cur_inst != NULL)
14223 		ret = scf_iter_instance_pgs(iter, cur_inst);
14224 	else
14225 		ret = scf_iter_service_pgs(iter, cur_svc);
14226 	if (ret != SCF_SUCCESS)
14227 		scfdie();
14228 
14229 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14230 		int ret2;
14231 
14232 		/*
14233 		 * # delprop pg
14234 		 * # addpg pg type
14235 		 */
14236 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14237 			scfdie();
14238 
14239 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14240 			scfdie();
14241 
14242 		if (fprintf(strm, "# Property group \"%s\"\n"
14243 		    "# delprop %s\n"
14244 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14245 			warn(emsg_write_error, strerror(errno));
14246 			result = -1;
14247 			goto out;
14248 		}
14249 
14250 		/* # setprop pg/prop = (values) */
14251 
14252 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14253 			scfdie();
14254 
14255 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14256 			int first = 1;
14257 			int ret3;
14258 			int multiple;
14259 			int is_str;
14260 			scf_type_t bty;
14261 
14262 			if (scf_property_get_name(prop, pname,
14263 			    max_scf_name_len + 1) < 0)
14264 				scfdie();
14265 
14266 			if (scf_property_type(prop, &ty) != 0)
14267 				scfdie();
14268 
14269 			multiple = prop_has_multiple_values(prop, val);
14270 
14271 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14272 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
14273 			    < 0) {
14274 				warn(emsg_write_error, strerror(errno));
14275 				result = -1;
14276 				goto out;
14277 			}
14278 
14279 			(void) scf_type_base_type(ty, &bty);
14280 			is_str = (bty == SCF_TYPE_ASTRING);
14281 
14282 			if (scf_iter_property_values(viter, prop) !=
14283 			    SCF_SUCCESS)
14284 				scfdie();
14285 
14286 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14287 				char *buf;
14288 				ssize_t buflen;
14289 
14290 				buflen = scf_value_get_as_string(val, NULL, 0);
14291 				if (buflen < 0)
14292 					scfdie();
14293 
14294 				buf = safe_malloc(buflen + 1);
14295 
14296 				if (scf_value_get_as_string(val, buf,
14297 				    buflen + 1) < 0)
14298 					scfdie();
14299 
14300 				if (first)
14301 					first = 0;
14302 				else {
14303 					if (putc(' ', strm) != ' ') {
14304 						warn(emsg_write_error,
14305 						    strerror(errno));
14306 						result = -1;
14307 						goto out;
14308 					}
14309 				}
14310 
14311 				if ((is_str && multiple) ||
14312 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14313 					(void) putc('"', strm);
14314 					(void) quote_and_print(buf, strm, 1);
14315 					(void) putc('"', strm);
14316 
14317 					if (ferror(strm)) {
14318 						warn(emsg_write_error,
14319 						    strerror(errno));
14320 						result = -1;
14321 						goto out;
14322 					}
14323 				} else {
14324 					if (fprintf(strm, "%s", buf) < 0) {
14325 						warn(emsg_write_error,
14326 						    strerror(errno));
14327 						result = -1;
14328 						goto out;
14329 					}
14330 				}
14331 
14332 				free(buf);
14333 			}
14334 			if (ret3 < 0 &&
14335 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14336 				scfdie();
14337 
14338 			/* Write closing paren if mult-value property */
14339 			if ((multiple && putc(')', strm) == EOF) ||
14340 
14341 			    /* Write final newline */
14342 			    fputc('\n', strm) == EOF) {
14343 				warn(emsg_write_error, strerror(errno));
14344 				result = -1;
14345 				goto out;
14346 			}
14347 		}
14348 		if (ret2 < 0)
14349 			scfdie();
14350 
14351 		if (fputc('\n', strm) == EOF) {
14352 			warn(emsg_write_error, strerror(errno));
14353 			result = -1;
14354 			goto out;
14355 		}
14356 	}
14357 	if (ret < 0)
14358 		scfdie();
14359 
14360 out:
14361 	free(pname);
14362 	free(tybuf);
14363 	free(buf);
14364 	scf_iter_destroy(viter);
14365 	scf_iter_destroy(piter);
14366 	scf_iter_destroy(iter);
14367 	scf_value_destroy(val);
14368 	scf_property_destroy(prop);
14369 	scf_pg_destroy(pg);
14370 
14371 	if (result == 0) {
14372 		if (fflush(strm) != 0) {
14373 			warn(emsg_write_error, strerror(errno));
14374 			return (-1);
14375 		}
14376 	}
14377 
14378 	return (result);
14379 }
14380 
14381 int
14382 lscf_editprop()
14383 {
14384 	char *buf, *editor;
14385 	size_t bufsz;
14386 	int tmpfd;
14387 	char tempname[] = TEMP_FILE_PATTERN;
14388 
14389 	lscf_prep_hndl();
14390 
14391 	if (cur_snap != NULL) {
14392 		semerr(emsg_cant_modify_snapshots);
14393 		return (-1);
14394 	}
14395 
14396 	if (cur_svc == NULL && cur_inst == NULL) {
14397 		semerr(emsg_entity_not_selected);
14398 		return (-1);
14399 	}
14400 
14401 	tmpfd = mkstemp(tempname);
14402 	if (tmpfd == -1) {
14403 		semerr(gettext("Could not create temporary file.\n"));
14404 		return (-1);
14405 	}
14406 
14407 	(void) strcpy(tempfilename, tempname);
14408 
14409 	tempfile = fdopen(tmpfd, "r+");
14410 	if (tempfile == NULL) {
14411 		warn(gettext("Could not create temporary file.\n"));
14412 		if (close(tmpfd) == -1)
14413 			warn(gettext("Could not close temporary file: %s.\n"),
14414 			    strerror(errno));
14415 
14416 		remove_tempfile();
14417 
14418 		return (-1);
14419 	}
14420 
14421 	if (write_edit_script(tempfile) == -1) {
14422 		remove_tempfile();
14423 		return (-1);
14424 	}
14425 
14426 	editor = getenv("EDITOR");
14427 	if (editor == NULL)
14428 		editor = "vi";
14429 
14430 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14431 	buf = safe_malloc(bufsz);
14432 
14433 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14434 		uu_die(gettext("Error creating editor command"));
14435 
14436 	if (system(buf) == -1) {
14437 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14438 		    strerror(errno));
14439 		free(buf);
14440 		remove_tempfile();
14441 		return (-1);
14442 	}
14443 
14444 	free(buf);
14445 
14446 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14447 
14448 	remove_tempfile();
14449 
14450 	return (0);
14451 }
14452 
14453 static void
14454 add_string(uu_list_t *strlist, const char *str)
14455 {
14456 	string_list_t *elem;
14457 	elem = safe_malloc(sizeof (*elem));
14458 	uu_list_node_init(elem, &elem->node, string_pool);
14459 	elem->str = safe_strdup(str);
14460 	if (uu_list_append(strlist, elem) != 0)
14461 		uu_die(gettext("libuutil error: %s\n"),
14462 		    uu_strerror(uu_error()));
14463 }
14464 
14465 static int
14466 remove_string(uu_list_t *strlist, const char *str)
14467 {
14468 	uu_list_walk_t	*elems;
14469 	string_list_t	*sp;
14470 
14471 	/*
14472 	 * Find the element that needs to be removed.
14473 	 */
14474 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14475 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14476 		if (strcmp(sp->str, str) == 0)
14477 			break;
14478 	}
14479 	uu_list_walk_end(elems);
14480 
14481 	/*
14482 	 * Returning 1 here as the value was not found, this
14483 	 * might not be an error.  Leave it to the caller to
14484 	 * decide.
14485 	 */
14486 	if (sp == NULL) {
14487 		return (1);
14488 	}
14489 
14490 	uu_list_remove(strlist, sp);
14491 
14492 	free(sp->str);
14493 	free(sp);
14494 
14495 	return (0);
14496 }
14497 
14498 /*
14499  * Get all property values that don't match the given glob pattern,
14500  * if a pattern is specified.
14501  */
14502 static void
14503 get_prop_values(scf_property_t *prop, uu_list_t *values,
14504     const char *pattern)
14505 {
14506 	scf_iter_t *iter;
14507 	scf_value_t *val;
14508 	int ret;
14509 
14510 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14511 	    (val = scf_value_create(g_hndl)) == NULL)
14512 		scfdie();
14513 
14514 	if (scf_iter_property_values(iter, prop) != 0)
14515 		scfdie();
14516 
14517 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14518 		char *buf;
14519 		ssize_t vlen, szret;
14520 
14521 		vlen = scf_value_get_as_string(val, NULL, 0);
14522 		if (vlen < 0)
14523 			scfdie();
14524 
14525 		buf = safe_malloc(vlen + 1);
14526 
14527 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14528 		if (szret < 0)
14529 			scfdie();
14530 		assert(szret <= vlen);
14531 
14532 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14533 			add_string(values, buf);
14534 
14535 		free(buf);
14536 	}
14537 
14538 	if (ret == -1)
14539 		scfdie();
14540 
14541 	scf_value_destroy(val);
14542 	scf_iter_destroy(iter);
14543 }
14544 
14545 static int
14546 lscf_setpropvalue(const char *pgname, const char *type,
14547     const char *arg, int isadd, int isnotfoundok)
14548 {
14549 	scf_type_t ty;
14550 	scf_propertygroup_t *pg;
14551 	scf_property_t *prop;
14552 	int ret, result = 0;
14553 	scf_transaction_t *tx;
14554 	scf_transaction_entry_t *e;
14555 	scf_value_t *v;
14556 	string_list_t *sp;
14557 	char *propname;
14558 	uu_list_t *values;
14559 	uu_list_walk_t *walk;
14560 	void *cookie = NULL;
14561 	char *pattern = NULL;
14562 
14563 	lscf_prep_hndl();
14564 
14565 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14566 		uu_die(gettext("Could not create property list: %s\n"),
14567 		    uu_strerror(uu_error()));
14568 
14569 	if (!isadd)
14570 		pattern = safe_strdup(arg);
14571 
14572 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14573 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14574 	    (prop = scf_property_create(g_hndl)) == NULL ||
14575 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14576 		scfdie();
14577 
14578 	if (cur_snap != NULL) {
14579 		semerr(emsg_cant_modify_snapshots);
14580 		goto fail;
14581 	}
14582 
14583 	if (cur_inst == NULL && cur_svc == NULL) {
14584 		semerr(emsg_entity_not_selected);
14585 		goto fail;
14586 	}
14587 
14588 	propname = strchr(pgname, '/');
14589 	if (propname == NULL) {
14590 		semerr(gettext("Property names must contain a `/'.\n"));
14591 		goto fail;
14592 	}
14593 
14594 	*propname = '\0';
14595 	++propname;
14596 
14597 	if (type != NULL) {
14598 		ty = string_to_type(type);
14599 		if (ty == SCF_TYPE_INVALID) {
14600 			semerr(gettext("Unknown type \"%s\".\n"), type);
14601 			goto fail;
14602 		}
14603 	}
14604 
14605 	if (cur_inst != NULL)
14606 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14607 	else
14608 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14609 	if (ret != 0) {
14610 		switch (scf_error()) {
14611 		case SCF_ERROR_NOT_FOUND:
14612 			if (isnotfoundok) {
14613 				result = 0;
14614 			} else {
14615 				semerr(emsg_no_such_pg, pgname);
14616 				result = -1;
14617 			}
14618 			goto out;
14619 
14620 		case SCF_ERROR_INVALID_ARGUMENT:
14621 			semerr(emsg_invalid_pg_name, pgname);
14622 			goto fail;
14623 
14624 		default:
14625 			scfdie();
14626 		}
14627 	}
14628 
14629 	do {
14630 		if (scf_pg_update(pg) == -1)
14631 			scfdie();
14632 		if (scf_transaction_start(tx, pg) != 0) {
14633 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14634 				scfdie();
14635 
14636 			semerr(emsg_permission_denied);
14637 			goto fail;
14638 		}
14639 
14640 		ret = scf_pg_get_property(pg, propname, prop);
14641 		if (ret == 0) {
14642 			scf_type_t ptype;
14643 			char *pat = pattern;
14644 
14645 			if (scf_property_type(prop, &ptype) != 0)
14646 				scfdie();
14647 
14648 			if (isadd) {
14649 				if (type != NULL && ptype != ty) {
14650 					semerr(gettext("Property \"%s\" is not "
14651 					    "of type \"%s\".\n"), propname,
14652 					    type);
14653 					goto fail;
14654 				}
14655 
14656 				pat = NULL;
14657 			} else {
14658 				size_t len = strlen(pat);
14659 				if (len > 0 && pat[len - 1] == '\"')
14660 					pat[len - 1] = '\0';
14661 				if (len > 0 && pat[0] == '\"')
14662 					pat++;
14663 			}
14664 
14665 			ty = ptype;
14666 
14667 			get_prop_values(prop, values, pat);
14668 
14669 			if (isadd)
14670 				add_string(values, arg);
14671 
14672 			if (scf_transaction_property_change(tx, e,
14673 			    propname, ty) == -1)
14674 				scfdie();
14675 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14676 			if (isadd) {
14677 				if (type == NULL) {
14678 					semerr(gettext("Type required "
14679 					    "for new properties.\n"));
14680 					goto fail;
14681 				}
14682 
14683 				add_string(values, arg);
14684 
14685 				if (scf_transaction_property_new(tx, e,
14686 				    propname, ty) == -1)
14687 					scfdie();
14688 			} else if (isnotfoundok) {
14689 				result = 0;
14690 				goto out;
14691 			} else {
14692 				semerr(gettext("No such property %s/%s.\n"),
14693 				    pgname, propname);
14694 				result = -1;
14695 				goto out;
14696 			}
14697 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14698 			semerr(emsg_invalid_prop_name, propname);
14699 			goto fail;
14700 		} else {
14701 			scfdie();
14702 		}
14703 
14704 		walk = uu_list_walk_start(values, UU_DEFAULT);
14705 		if (walk == NULL)
14706 			uu_die(gettext("Could not walk property list.\n"));
14707 
14708 		for (sp = uu_list_walk_next(walk); sp != NULL;
14709 		    sp = uu_list_walk_next(walk)) {
14710 			v = string_to_value(sp->str, ty, 0);
14711 
14712 			if (v == NULL) {
14713 				scf_entry_destroy_children(e);
14714 				goto fail;
14715 			}
14716 			ret = scf_entry_add_value(e, v);
14717 			assert(ret == 0);
14718 		}
14719 		uu_list_walk_end(walk);
14720 
14721 		result = scf_transaction_commit(tx);
14722 
14723 		scf_transaction_reset(tx);
14724 		scf_entry_destroy_children(e);
14725 	} while (result == 0);
14726 
14727 	if (result < 0) {
14728 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14729 			scfdie();
14730 
14731 		semerr(emsg_permission_denied);
14732 		goto fail;
14733 	}
14734 
14735 	result = 0;
14736 
14737 	private_refresh();
14738 
14739 out:
14740 	scf_transaction_destroy(tx);
14741 	scf_entry_destroy(e);
14742 	scf_pg_destroy(pg);
14743 	scf_property_destroy(prop);
14744 	free(pattern);
14745 
14746 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14747 		free(sp->str);
14748 		free(sp);
14749 	}
14750 
14751 	uu_list_destroy(values);
14752 
14753 	return (result);
14754 
14755 fail:
14756 	result = -1;
14757 	goto out;
14758 }
14759 
14760 int
14761 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14762 {
14763 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14764 }
14765 
14766 int
14767 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14768 {
14769 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14770 }
14771 
14772 /*
14773  * Look for a standard start method, first in the instance (if any),
14774  * then the service.
14775  */
14776 static const char *
14777 start_method_name(int *in_instance)
14778 {
14779 	scf_propertygroup_t *pg;
14780 	char **p;
14781 	int ret;
14782 	scf_instance_t *inst = cur_inst;
14783 
14784 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14785 		scfdie();
14786 
14787 again:
14788 	for (p = start_method_names; *p != NULL; p++) {
14789 		if (inst != NULL)
14790 			ret = scf_instance_get_pg(inst, *p, pg);
14791 		else
14792 			ret = scf_service_get_pg(cur_svc, *p, pg);
14793 
14794 		if (ret == 0) {
14795 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14796 			char *buf = safe_malloc(bufsz);
14797 
14798 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14799 				free(buf);
14800 				continue;
14801 			}
14802 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14803 				free(buf);
14804 				continue;
14805 			}
14806 
14807 			free(buf);
14808 			*in_instance = (inst != NULL);
14809 			scf_pg_destroy(pg);
14810 			return (*p);
14811 		}
14812 
14813 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14814 			continue;
14815 
14816 		scfdie();
14817 	}
14818 
14819 	if (inst != NULL) {
14820 		inst = NULL;
14821 		goto again;
14822 	}
14823 
14824 	scf_pg_destroy(pg);
14825 	return (NULL);
14826 }
14827 
14828 static int
14829 addpg(const char *name, const char *type)
14830 {
14831 	scf_propertygroup_t *pg;
14832 	int ret;
14833 
14834 	pg = scf_pg_create(g_hndl);
14835 	if (pg == NULL)
14836 		scfdie();
14837 
14838 	if (cur_inst != NULL)
14839 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14840 	else
14841 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14842 
14843 	if (ret != 0) {
14844 		switch (scf_error()) {
14845 		case SCF_ERROR_EXISTS:
14846 			ret = 0;
14847 			break;
14848 
14849 		case SCF_ERROR_PERMISSION_DENIED:
14850 			semerr(emsg_permission_denied);
14851 			break;
14852 
14853 		default:
14854 			scfdie();
14855 		}
14856 	}
14857 
14858 	scf_pg_destroy(pg);
14859 	return (ret);
14860 }
14861 
14862 int
14863 lscf_setenv(uu_list_t *args, int isunset)
14864 {
14865 	int ret = 0;
14866 	size_t i;
14867 	int argc;
14868 	char **argv = NULL;
14869 	string_list_t *slp;
14870 	char *pattern;
14871 	char *prop;
14872 	int do_service = 0;
14873 	int do_instance = 0;
14874 	const char *method = NULL;
14875 	const char *name = NULL;
14876 	const char *value = NULL;
14877 	scf_instance_t *saved_cur_inst = cur_inst;
14878 
14879 	lscf_prep_hndl();
14880 
14881 	argc = uu_list_numnodes(args);
14882 	if (argc < 1)
14883 		goto usage;
14884 
14885 	argv = calloc(argc + 1, sizeof (char *));
14886 	if (argv == NULL)
14887 		uu_die(gettext("Out of memory.\n"));
14888 
14889 	for (slp = uu_list_first(args), i = 0;
14890 	    slp != NULL;
14891 	    slp = uu_list_next(args, slp), ++i)
14892 		argv[i] = slp->str;
14893 
14894 	argv[i] = NULL;
14895 
14896 	opterr = 0;
14897 	optind = 0;
14898 	for (;;) {
14899 		ret = getopt(argc, argv, "sim:");
14900 		if (ret == -1)
14901 			break;
14902 
14903 		switch (ret) {
14904 		case 's':
14905 			do_service = 1;
14906 			cur_inst = NULL;
14907 			break;
14908 
14909 		case 'i':
14910 			do_instance = 1;
14911 			break;
14912 
14913 		case 'm':
14914 			method = optarg;
14915 			break;
14916 
14917 		case '?':
14918 			goto usage;
14919 
14920 		default:
14921 			bad_error("getopt", ret);
14922 		}
14923 	}
14924 
14925 	argc -= optind;
14926 	if ((do_service && do_instance) ||
14927 	    (isunset && argc != 1) ||
14928 	    (!isunset && argc != 2))
14929 		goto usage;
14930 
14931 	name = argv[optind];
14932 	if (!isunset)
14933 		value = argv[optind + 1];
14934 
14935 	if (cur_snap != NULL) {
14936 		semerr(emsg_cant_modify_snapshots);
14937 		ret = -1;
14938 		goto out;
14939 	}
14940 
14941 	if (cur_inst == NULL && cur_svc == NULL) {
14942 		semerr(emsg_entity_not_selected);
14943 		ret = -1;
14944 		goto out;
14945 	}
14946 
14947 	if (do_instance && cur_inst == NULL) {
14948 		semerr(gettext("No instance is selected.\n"));
14949 		ret = -1;
14950 		goto out;
14951 	}
14952 
14953 	if (do_service && cur_svc == NULL) {
14954 		semerr(gettext("No service is selected.\n"));
14955 		ret = -1;
14956 		goto out;
14957 	}
14958 
14959 	if (method == NULL) {
14960 		if (do_instance || do_service) {
14961 			method = "method_context";
14962 			if (!isunset) {
14963 				ret = addpg("method_context",
14964 				    SCF_GROUP_FRAMEWORK);
14965 				if (ret != 0)
14966 					goto out;
14967 			}
14968 		} else {
14969 			int in_instance;
14970 			method = start_method_name(&in_instance);
14971 			if (method == NULL) {
14972 				semerr(gettext(
14973 				    "Couldn't find start method; please "
14974 				    "specify a method with '-m'.\n"));
14975 				ret = -1;
14976 				goto out;
14977 			}
14978 			if (!in_instance)
14979 				cur_inst = NULL;
14980 		}
14981 	} else {
14982 		scf_propertygroup_t *pg;
14983 		size_t bufsz;
14984 		char *buf;
14985 		int ret;
14986 
14987 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14988 			scfdie();
14989 
14990 		if (cur_inst != NULL)
14991 			ret = scf_instance_get_pg(cur_inst, method, pg);
14992 		else
14993 			ret = scf_service_get_pg(cur_svc, method, pg);
14994 
14995 		if (ret != 0) {
14996 			scf_pg_destroy(pg);
14997 			switch (scf_error()) {
14998 			case SCF_ERROR_NOT_FOUND:
14999 				semerr(gettext("Couldn't find the method "
15000 				    "\"%s\".\n"), method);
15001 				goto out;
15002 
15003 			case SCF_ERROR_INVALID_ARGUMENT:
15004 				semerr(gettext("Invalid method name \"%s\".\n"),
15005 				    method);
15006 				goto out;
15007 
15008 			default:
15009 				scfdie();
15010 			}
15011 		}
15012 
15013 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
15014 		buf = safe_malloc(bufsz);
15015 
15016 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15017 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
15018 			semerr(gettext("Property group \"%s\" is not of type "
15019 			    "\"method\".\n"), method);
15020 			ret = -1;
15021 			free(buf);
15022 			scf_pg_destroy(pg);
15023 			goto out;
15024 		}
15025 
15026 		free(buf);
15027 		scf_pg_destroy(pg);
15028 	}
15029 
15030 	prop = uu_msprintf("%s/environment", method);
15031 	pattern = uu_msprintf("%s=*", name);
15032 
15033 	if (prop == NULL || pattern == NULL)
15034 		uu_die(gettext("Out of memory.\n"));
15035 
15036 	ret = lscf_delpropvalue(prop, pattern, !isunset);
15037 
15038 	if (ret == 0 && !isunset) {
15039 		uu_free(pattern);
15040 		uu_free(prop);
15041 		prop = uu_msprintf("%s/environment", method);
15042 		pattern = uu_msprintf("%s=%s", name, value);
15043 		if (prop == NULL || pattern == NULL)
15044 			uu_die(gettext("Out of memory.\n"));
15045 		ret = lscf_addpropvalue(prop, "astring:", pattern);
15046 	}
15047 	uu_free(pattern);
15048 	uu_free(prop);
15049 
15050 out:
15051 	cur_inst = saved_cur_inst;
15052 
15053 	free(argv);
15054 	return (ret);
15055 usage:
15056 	ret = -2;
15057 	goto out;
15058 }
15059 
15060 /*
15061  * Snapshot commands
15062  */
15063 
15064 void
15065 lscf_listsnap()
15066 {
15067 	scf_snapshot_t *snap;
15068 	scf_iter_t *iter;
15069 	char *nb;
15070 	int r;
15071 
15072 	lscf_prep_hndl();
15073 
15074 	if (cur_inst == NULL) {
15075 		semerr(gettext("Instance not selected.\n"));
15076 		return;
15077 	}
15078 
15079 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15080 	    (iter = scf_iter_create(g_hndl)) == NULL)
15081 		scfdie();
15082 
15083 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15084 		scfdie();
15085 
15086 	nb = safe_malloc(max_scf_name_len + 1);
15087 
15088 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15089 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15090 			scfdie();
15091 
15092 		(void) puts(nb);
15093 	}
15094 	if (r < 0)
15095 		scfdie();
15096 
15097 	free(nb);
15098 	scf_iter_destroy(iter);
15099 	scf_snapshot_destroy(snap);
15100 }
15101 
15102 void
15103 lscf_selectsnap(const char *name)
15104 {
15105 	scf_snapshot_t *snap;
15106 	scf_snaplevel_t *level;
15107 
15108 	lscf_prep_hndl();
15109 
15110 	if (cur_inst == NULL) {
15111 		semerr(gettext("Instance not selected.\n"));
15112 		return;
15113 	}
15114 
15115 	if (cur_snap != NULL) {
15116 		if (name != NULL) {
15117 			char *cur_snap_name;
15118 			boolean_t nochange;
15119 
15120 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
15121 
15122 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15123 			    max_scf_name_len + 1) < 0)
15124 				scfdie();
15125 
15126 			nochange = strcmp(name, cur_snap_name) == 0;
15127 
15128 			free(cur_snap_name);
15129 
15130 			if (nochange)
15131 				return;
15132 		}
15133 
15134 		unselect_cursnap();
15135 	}
15136 
15137 	if (name == NULL)
15138 		return;
15139 
15140 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15141 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
15142 		scfdie();
15143 
15144 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15145 	    SCF_SUCCESS) {
15146 		switch (scf_error()) {
15147 		case SCF_ERROR_INVALID_ARGUMENT:
15148 			semerr(gettext("Invalid name \"%s\".\n"), name);
15149 			break;
15150 
15151 		case SCF_ERROR_NOT_FOUND:
15152 			semerr(gettext("No such snapshot \"%s\".\n"), name);
15153 			break;
15154 
15155 		default:
15156 			scfdie();
15157 		}
15158 
15159 		scf_snaplevel_destroy(level);
15160 		scf_snapshot_destroy(snap);
15161 		return;
15162 	}
15163 
15164 	/* Load the snaplevels into our list. */
15165 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15166 	if (cur_levels == NULL)
15167 		uu_die(gettext("Could not create list: %s\n"),
15168 		    uu_strerror(uu_error()));
15169 
15170 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15171 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15172 			scfdie();
15173 
15174 		semerr(gettext("Snapshot has no snaplevels.\n"));
15175 
15176 		scf_snaplevel_destroy(level);
15177 		scf_snapshot_destroy(snap);
15178 		return;
15179 	}
15180 
15181 	cur_snap = snap;
15182 
15183 	for (;;) {
15184 		cur_elt = safe_malloc(sizeof (*cur_elt));
15185 		uu_list_node_init(cur_elt, &cur_elt->list_node,
15186 		    snaplevel_pool);
15187 		cur_elt->sl = level;
15188 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15189 			uu_die(gettext("libuutil error: %s\n"),
15190 			    uu_strerror(uu_error()));
15191 
15192 		level = scf_snaplevel_create(g_hndl);
15193 		if (level == NULL)
15194 			scfdie();
15195 
15196 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15197 		    level) != SCF_SUCCESS) {
15198 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15199 				scfdie();
15200 
15201 			scf_snaplevel_destroy(level);
15202 			break;
15203 		}
15204 	}
15205 
15206 	cur_elt = uu_list_last(cur_levels);
15207 	cur_level = cur_elt->sl;
15208 }
15209 
15210 /*
15211  * Copies the properties & values in src to dst.  Assumes src won't change.
15212  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15213  * and 0 on success.
15214  *
15215  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15216  * property, if it is copied and has type boolean.  (See comment in
15217  * lscf_revert()).
15218  */
15219 static int
15220 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15221     uint8_t enabled)
15222 {
15223 	scf_transaction_t *tx;
15224 	scf_iter_t *iter, *viter;
15225 	scf_property_t *prop;
15226 	scf_value_t *v;
15227 	char *nbuf;
15228 	int r;
15229 
15230 	tx = scf_transaction_create(g_hndl);
15231 	if (tx == NULL)
15232 		scfdie();
15233 
15234 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15235 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15236 			scfdie();
15237 
15238 		scf_transaction_destroy(tx);
15239 
15240 		return (-1);
15241 	}
15242 
15243 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
15244 	    (prop = scf_property_create(g_hndl)) == NULL ||
15245 	    (viter = scf_iter_create(g_hndl)) == NULL)
15246 		scfdie();
15247 
15248 	nbuf = safe_malloc(max_scf_name_len + 1);
15249 
15250 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15251 		scfdie();
15252 
15253 	for (;;) {
15254 		scf_transaction_entry_t *e;
15255 		scf_type_t ty;
15256 
15257 		r = scf_iter_next_property(iter, prop);
15258 		if (r == -1)
15259 			scfdie();
15260 		if (r == 0)
15261 			break;
15262 
15263 		e = scf_entry_create(g_hndl);
15264 		if (e == NULL)
15265 			scfdie();
15266 
15267 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15268 			scfdie();
15269 
15270 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15271 			scfdie();
15272 
15273 		if (scf_transaction_property_new(tx, e, nbuf,
15274 		    ty) != SCF_SUCCESS)
15275 			scfdie();
15276 
15277 		if ((enabled == 0 || enabled == 1) &&
15278 		    strcmp(nbuf, scf_property_enabled) == 0 &&
15279 		    ty == SCF_TYPE_BOOLEAN) {
15280 			v = scf_value_create(g_hndl);
15281 			if (v == NULL)
15282 				scfdie();
15283 
15284 			scf_value_set_boolean(v, enabled);
15285 
15286 			if (scf_entry_add_value(e, v) != 0)
15287 				scfdie();
15288 		} else {
15289 			if (scf_iter_property_values(viter, prop) != 0)
15290 				scfdie();
15291 
15292 			for (;;) {
15293 				v = scf_value_create(g_hndl);
15294 				if (v == NULL)
15295 					scfdie();
15296 
15297 				r = scf_iter_next_value(viter, v);
15298 				if (r == -1)
15299 					scfdie();
15300 				if (r == 0) {
15301 					scf_value_destroy(v);
15302 					break;
15303 				}
15304 
15305 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15306 					scfdie();
15307 			}
15308 		}
15309 	}
15310 
15311 	free(nbuf);
15312 	scf_iter_destroy(viter);
15313 	scf_property_destroy(prop);
15314 	scf_iter_destroy(iter);
15315 
15316 	r = scf_transaction_commit(tx);
15317 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15318 		scfdie();
15319 
15320 	scf_transaction_destroy_children(tx);
15321 	scf_transaction_destroy(tx);
15322 
15323 	switch (r) {
15324 	case 1:		return (0);
15325 	case 0:		return (-2);
15326 	case -1:	return (-1);
15327 
15328 	default:
15329 		abort();
15330 	}
15331 
15332 	/* NOTREACHED */
15333 }
15334 
15335 void
15336 lscf_revert(const char *snapname)
15337 {
15338 	scf_snapshot_t *snap, *prev;
15339 	scf_snaplevel_t *level, *nlevel;
15340 	scf_iter_t *iter;
15341 	scf_propertygroup_t *pg, *npg;
15342 	scf_property_t *prop;
15343 	scf_value_t *val;
15344 	char *nbuf, *tbuf;
15345 	uint8_t enabled;
15346 
15347 	lscf_prep_hndl();
15348 
15349 	if (cur_inst == NULL) {
15350 		semerr(gettext("Instance not selected.\n"));
15351 		return;
15352 	}
15353 
15354 	if (snapname != NULL) {
15355 		snap = scf_snapshot_create(g_hndl);
15356 		if (snap == NULL)
15357 			scfdie();
15358 
15359 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15360 		    SCF_SUCCESS) {
15361 			switch (scf_error()) {
15362 			case SCF_ERROR_INVALID_ARGUMENT:
15363 				semerr(gettext("Invalid snapshot name "
15364 				    "\"%s\".\n"), snapname);
15365 				break;
15366 
15367 			case SCF_ERROR_NOT_FOUND:
15368 				semerr(gettext("No such snapshot.\n"));
15369 				break;
15370 
15371 			default:
15372 				scfdie();
15373 			}
15374 
15375 			scf_snapshot_destroy(snap);
15376 			return;
15377 		}
15378 	} else {
15379 		if (cur_snap != NULL) {
15380 			snap = cur_snap;
15381 		} else {
15382 			semerr(gettext("No snapshot selected.\n"));
15383 			return;
15384 		}
15385 	}
15386 
15387 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15388 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15389 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15390 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15391 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15392 	    (prop = scf_property_create(g_hndl)) == NULL ||
15393 	    (val = scf_value_create(g_hndl)) == NULL)
15394 		scfdie();
15395 
15396 	nbuf = safe_malloc(max_scf_name_len + 1);
15397 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15398 
15399 	/* Take the "previous" snapshot before we blow away the properties. */
15400 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15401 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15402 			scfdie();
15403 	} else {
15404 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15405 			scfdie();
15406 
15407 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15408 			scfdie();
15409 	}
15410 
15411 	/* Save general/enabled, since we're probably going to replace it. */
15412 	enabled = 2;
15413 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15414 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15415 	    scf_property_get_value(prop, val) == 0)
15416 		(void) scf_value_get_boolean(val, &enabled);
15417 
15418 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15419 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15420 			scfdie();
15421 
15422 		goto out;
15423 	}
15424 
15425 	for (;;) {
15426 		boolean_t isinst;
15427 		uint32_t flags;
15428 		int r;
15429 
15430 		/* Clear the properties from the corresponding entity. */
15431 		isinst = snaplevel_is_instance(level);
15432 
15433 		if (!isinst)
15434 			r = scf_iter_service_pgs(iter, cur_svc);
15435 		else
15436 			r = scf_iter_instance_pgs(iter, cur_inst);
15437 		if (r != SCF_SUCCESS)
15438 			scfdie();
15439 
15440 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15441 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15442 				scfdie();
15443 
15444 			/* Skip nonpersistent pgs. */
15445 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15446 				continue;
15447 
15448 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15449 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15450 					scfdie();
15451 
15452 				semerr(emsg_permission_denied);
15453 				goto out;
15454 			}
15455 		}
15456 		if (r == -1)
15457 			scfdie();
15458 
15459 		/* Copy the properties to the corresponding entity. */
15460 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15461 			scfdie();
15462 
15463 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15464 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15465 				scfdie();
15466 
15467 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15468 			    0)
15469 				scfdie();
15470 
15471 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15472 				scfdie();
15473 
15474 			if (!isinst)
15475 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15476 				    flags, npg);
15477 			else
15478 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15479 				    flags, npg);
15480 			if (r != SCF_SUCCESS) {
15481 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15482 					scfdie();
15483 
15484 				semerr(emsg_permission_denied);
15485 				goto out;
15486 			}
15487 
15488 			if ((enabled == 0 || enabled == 1) &&
15489 			    strcmp(nbuf, scf_pg_general) == 0)
15490 				r = pg_copy(pg, npg, enabled);
15491 			else
15492 				r = pg_copy(pg, npg, 2);
15493 
15494 			switch (r) {
15495 			case 0:
15496 				break;
15497 
15498 			case -1:
15499 				semerr(emsg_permission_denied);
15500 				goto out;
15501 
15502 			case -2:
15503 				semerr(gettext(
15504 				    "Interrupted by another change.\n"));
15505 				goto out;
15506 
15507 			default:
15508 				abort();
15509 			}
15510 		}
15511 		if (r == -1)
15512 			scfdie();
15513 
15514 		/* Get next level. */
15515 		nlevel = scf_snaplevel_create(g_hndl);
15516 		if (nlevel == NULL)
15517 			scfdie();
15518 
15519 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15520 		    SCF_SUCCESS) {
15521 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15522 				scfdie();
15523 
15524 			scf_snaplevel_destroy(nlevel);
15525 			break;
15526 		}
15527 
15528 		scf_snaplevel_destroy(level);
15529 		level = nlevel;
15530 	}
15531 
15532 	if (snapname == NULL) {
15533 		lscf_selectsnap(NULL);
15534 		snap = NULL;		/* cur_snap has been destroyed */
15535 	}
15536 
15537 out:
15538 	free(tbuf);
15539 	free(nbuf);
15540 	scf_value_destroy(val);
15541 	scf_property_destroy(prop);
15542 	scf_pg_destroy(npg);
15543 	scf_pg_destroy(pg);
15544 	scf_iter_destroy(iter);
15545 	scf_snaplevel_destroy(level);
15546 	scf_snapshot_destroy(prev);
15547 	if (snap != cur_snap)
15548 		scf_snapshot_destroy(snap);
15549 }
15550 
15551 void
15552 lscf_refresh(void)
15553 {
15554 	ssize_t fmrilen;
15555 	size_t bufsz;
15556 	char *fmribuf;
15557 	int r;
15558 
15559 	lscf_prep_hndl();
15560 
15561 	if (cur_inst == NULL) {
15562 		semerr(gettext("Instance not selected.\n"));
15563 		return;
15564 	}
15565 
15566 	bufsz = max_scf_fmri_len + 1;
15567 	fmribuf = safe_malloc(bufsz);
15568 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15569 	if (fmrilen < 0) {
15570 		free(fmribuf);
15571 		if (scf_error() != SCF_ERROR_DELETED)
15572 			scfdie();
15573 		scf_instance_destroy(cur_inst);
15574 		cur_inst = NULL;
15575 		warn(emsg_deleted);
15576 		return;
15577 	}
15578 	assert(fmrilen < bufsz);
15579 
15580 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15581 	switch (r) {
15582 	case 0:
15583 		break;
15584 
15585 	case ECONNABORTED:
15586 		warn(gettext("Could not refresh %s "
15587 		    "(repository connection broken).\n"), fmribuf);
15588 		break;
15589 
15590 	case ECANCELED:
15591 		warn(emsg_deleted);
15592 		break;
15593 
15594 	case EPERM:
15595 		warn(gettext("Could not refresh %s "
15596 		    "(permission denied).\n"), fmribuf);
15597 		break;
15598 
15599 	case ENOSPC:
15600 		warn(gettext("Could not refresh %s "
15601 		    "(repository server out of resources).\n"),
15602 		    fmribuf);
15603 		break;
15604 
15605 	case EACCES:
15606 	default:
15607 		bad_error("refresh_entity", scf_error());
15608 	}
15609 
15610 	free(fmribuf);
15611 }
15612 
15613 /*
15614  * describe [-v] [-t] [pg/prop]
15615  */
15616 int
15617 lscf_describe(uu_list_t *args, int hasargs)
15618 {
15619 	int ret = 0;
15620 	size_t i;
15621 	int argc;
15622 	char **argv = NULL;
15623 	string_list_t *slp;
15624 	int do_verbose = 0;
15625 	int do_templates = 0;
15626 	char *pattern = NULL;
15627 
15628 	lscf_prep_hndl();
15629 
15630 	if (hasargs != 0)  {
15631 		argc = uu_list_numnodes(args);
15632 		if (argc < 1)
15633 			goto usage;
15634 
15635 		argv = calloc(argc + 1, sizeof (char *));
15636 		if (argv == NULL)
15637 			uu_die(gettext("Out of memory.\n"));
15638 
15639 		for (slp = uu_list_first(args), i = 0;
15640 		    slp != NULL;
15641 		    slp = uu_list_next(args, slp), ++i)
15642 			argv[i] = slp->str;
15643 
15644 		argv[i] = NULL;
15645 
15646 		/*
15647 		 * We start optind = 0 because our list of arguments
15648 		 * starts at argv[0]
15649 		 */
15650 		optind = 0;
15651 		opterr = 0;
15652 		for (;;) {
15653 			ret = getopt(argc, argv, "vt");
15654 			if (ret == -1)
15655 				break;
15656 
15657 			switch (ret) {
15658 			case 'v':
15659 				do_verbose = 1;
15660 				break;
15661 
15662 			case 't':
15663 				do_templates = 1;
15664 				break;
15665 
15666 			case '?':
15667 				goto usage;
15668 
15669 			default:
15670 				bad_error("getopt", ret);
15671 			}
15672 		}
15673 
15674 		pattern = argv[optind];
15675 	}
15676 
15677 	if (cur_inst == NULL && cur_svc == NULL) {
15678 		semerr(emsg_entity_not_selected);
15679 		ret = -1;
15680 		goto out;
15681 	}
15682 
15683 	/*
15684 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15685 	 * output if their last parameter is set to 2.  Less information is
15686 	 * produced if the parameter is set to 1.
15687 	 */
15688 	if (pattern == NULL) {
15689 		if (do_verbose == 1)
15690 			list_entity_tmpl(2);
15691 		else
15692 			list_entity_tmpl(1);
15693 	}
15694 
15695 	if (do_templates == 0) {
15696 		if (do_verbose == 1)
15697 			listprop(pattern, 0, 2);
15698 		else
15699 			listprop(pattern, 0, 1);
15700 	} else {
15701 		if (do_verbose == 1)
15702 			listtmpl(pattern, 2);
15703 		else
15704 			listtmpl(pattern, 1);
15705 	}
15706 
15707 	ret = 0;
15708 out:
15709 	if (argv != NULL)
15710 		free(argv);
15711 	return (ret);
15712 usage:
15713 	ret = -2;
15714 	goto out;
15715 }
15716 
15717 #define	PARAM_ACTIVE	((const char *) "active")
15718 #define	PARAM_INACTIVE	((const char *) "inactive")
15719 #define	PARAM_SMTP_TO	((const char *) "to")
15720 
15721 /*
15722  * tokenize()
15723  * Breaks down the string according to the tokens passed.
15724  * Caller is responsible for freeing array of pointers returned.
15725  * Returns NULL on failure
15726  */
15727 char **
15728 tokenize(char *str, const char *sep)
15729 {
15730 	char *token, *lasts;
15731 	char **buf;
15732 	int n = 0;	/* number of elements */
15733 	int size = 8;	/* size of the array (initial) */
15734 
15735 	buf = safe_malloc(size * sizeof (char *));
15736 
15737 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15738 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15739 		if (n + 1 >= size) {
15740 			size *= 2;
15741 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15742 			    NULL) {
15743 				uu_die(gettext("Out of memory"));
15744 			}
15745 		}
15746 		buf[n] = token;
15747 	}
15748 	/* NULL terminate the pointer array */
15749 	buf[n] = NULL;
15750 
15751 	return (buf);
15752 }
15753 
15754 int32_t
15755 check_tokens(char **p)
15756 {
15757 	int32_t smf = 0;
15758 	int32_t fma = 0;
15759 
15760 	while (*p) {
15761 		int32_t t = string_to_tset(*p);
15762 
15763 		if (t == 0) {
15764 			if (is_fma_token(*p) == 0)
15765 				return (INVALID_TOKENS);
15766 			fma = 1; /* this token is an fma event */
15767 		} else {
15768 			smf |= t;
15769 		}
15770 
15771 		if (smf != 0 && fma == 1)
15772 			return (MIXED_TOKENS);
15773 		++p;
15774 	}
15775 
15776 	if (smf > 0)
15777 		return (smf);
15778 	else if (fma == 1)
15779 		return (FMA_TOKENS);
15780 
15781 	return (INVALID_TOKENS);
15782 }
15783 
15784 static int
15785 get_selection_str(char *fmri, size_t sz)
15786 {
15787 	if (g_hndl == NULL) {
15788 		semerr(emsg_entity_not_selected);
15789 		return (-1);
15790 	} else if (cur_level != NULL) {
15791 		semerr(emsg_invalid_for_snapshot);
15792 		return (-1);
15793 	} else {
15794 		lscf_get_selection_str(fmri, sz);
15795 	}
15796 
15797 	return (0);
15798 }
15799 
15800 void
15801 lscf_delnotify(const char *set, int global)
15802 {
15803 	char *str = strdup(set);
15804 	char **pgs;
15805 	char **p;
15806 	int32_t tset;
15807 	char *fmri = NULL;
15808 
15809 	if (str == NULL)
15810 		uu_die(gettext("Out of memory.\n"));
15811 
15812 	pgs = tokenize(str, ",");
15813 
15814 	if ((tset = check_tokens(pgs)) > 0) {
15815 		size_t sz = max_scf_fmri_len + 1;
15816 
15817 		fmri = safe_malloc(sz);
15818 		if (global) {
15819 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15820 		} else if (get_selection_str(fmri, sz) != 0) {
15821 			goto out;
15822 		}
15823 
15824 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15825 		    tset) != SCF_SUCCESS) {
15826 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15827 			    scf_strerror(scf_error()));
15828 		}
15829 	} else if (tset == FMA_TOKENS) {
15830 		if (global) {
15831 			semerr(gettext("Can't use option '-g' with FMA event "
15832 			    "definitions\n"));
15833 			goto out;
15834 		}
15835 
15836 		for (p = pgs; *p; ++p) {
15837 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15838 			    SCF_SUCCESS) {
15839 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15840 				    scf_strerror(scf_error()));
15841 				goto out;
15842 			}
15843 		}
15844 	} else if (tset == MIXED_TOKENS) {
15845 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15846 		goto out;
15847 	} else {
15848 		uu_die(gettext("Invalid input.\n"));
15849 	}
15850 
15851 out:
15852 	free(fmri);
15853 	free(pgs);
15854 	free(str);
15855 }
15856 
15857 void
15858 lscf_listnotify(const char *set, int global)
15859 {
15860 	char *str = safe_strdup(set);
15861 	char **pgs;
15862 	char **p;
15863 	int32_t tset;
15864 	nvlist_t *nvl;
15865 	char *fmri = NULL;
15866 
15867 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15868 		uu_die(gettext("Out of memory.\n"));
15869 
15870 	pgs = tokenize(str, ",");
15871 
15872 	if ((tset = check_tokens(pgs)) > 0) {
15873 		size_t sz = max_scf_fmri_len + 1;
15874 
15875 		fmri = safe_malloc(sz);
15876 		if (global) {
15877 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15878 		} else if (get_selection_str(fmri, sz) != 0) {
15879 			goto out;
15880 		}
15881 
15882 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15883 		    SCF_SUCCESS) {
15884 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15885 			    scf_error() != SCF_ERROR_DELETED)
15886 				uu_warn(gettext(
15887 				    "Failed listnotify: %s\n"),
15888 				    scf_strerror(scf_error()));
15889 			goto out;
15890 		}
15891 
15892 		listnotify_print(nvl, NULL);
15893 	} else if (tset == FMA_TOKENS) {
15894 		if (global) {
15895 			semerr(gettext("Can't use option '-g' with FMA event "
15896 			    "definitions\n"));
15897 			goto out;
15898 		}
15899 
15900 		for (p = pgs; *p; ++p) {
15901 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15902 			    SCF_SUCCESS) {
15903 				/*
15904 				 * if the preferences have just been deleted
15905 				 * or does not exist, just skip.
15906 				 */
15907 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15908 				    scf_error() == SCF_ERROR_DELETED)
15909 					continue;
15910 				uu_warn(gettext(
15911 				    "Failed listnotify: %s\n"),
15912 				    scf_strerror(scf_error()));
15913 				goto out;
15914 			}
15915 			listnotify_print(nvl, re_tag(*p));
15916 		}
15917 	} else if (tset == MIXED_TOKENS) {
15918 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15919 		goto out;
15920 	} else {
15921 		semerr(gettext("Invalid input.\n"));
15922 	}
15923 
15924 out:
15925 	nvlist_free(nvl);
15926 	free(fmri);
15927 	free(pgs);
15928 	free(str);
15929 }
15930 
15931 static char *
15932 strip_quotes_and_blanks(char *s)
15933 {
15934 	char *start = s;
15935 	char *end = strrchr(s, '\"');
15936 
15937 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15938 		start = s + 1;
15939 		while (isblank(*start))
15940 			start++;
15941 		while (isblank(*(end - 1)) && end > start) {
15942 			end--;
15943 		}
15944 		*end = '\0';
15945 	}
15946 
15947 	return (start);
15948 }
15949 
15950 static int
15951 set_active(nvlist_t *mech, const char *hier_part)
15952 {
15953 	boolean_t b;
15954 
15955 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15956 		b = B_TRUE;
15957 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15958 		b = B_FALSE;
15959 	} else {
15960 		return (-1);
15961 	}
15962 
15963 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15964 		uu_die(gettext("Out of memory.\n"));
15965 
15966 	return (0);
15967 }
15968 
15969 static int
15970 add_snmp_params(nvlist_t *mech, char *hier_part)
15971 {
15972 	return (set_active(mech, hier_part));
15973 }
15974 
15975 static int
15976 add_syslog_params(nvlist_t *mech, char *hier_part)
15977 {
15978 	return (set_active(mech, hier_part));
15979 }
15980 
15981 /*
15982  * add_mailto_paramas()
15983  * parse the hier_part of mailto URI
15984  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15985  * or mailto:{[active]|inactive}
15986  */
15987 static int
15988 add_mailto_params(nvlist_t *mech, char *hier_part)
15989 {
15990 	const char *tok = "?&";
15991 	char *p;
15992 	char *lasts;
15993 	char *param;
15994 	char *val;
15995 
15996 	/*
15997 	 * If the notification parametes are in the form of
15998 	 *
15999 	 *   malito:{[active]|inactive}
16000 	 *
16001 	 * we set the property accordingly and return.
16002 	 * Otherwise, we make the notification type active and
16003 	 * process the hier_part.
16004 	 */
16005 	if (set_active(mech, hier_part) == 0)
16006 		return (0);
16007 	else if (set_active(mech, PARAM_ACTIVE) != 0)
16008 		return (-1);
16009 
16010 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16011 		/*
16012 		 * sanity check: we only get here if hier_part = "", but
16013 		 * that's handled by set_active
16014 		 */
16015 		uu_die("strtok_r");
16016 	}
16017 
16018 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16019 		uu_die(gettext("Out of memory.\n"));
16020 
16021 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16022 		if ((param = strtok_r(p, "=", &val)) != NULL)
16023 			if (nvlist_add_string(mech, param, val) != 0)
16024 				uu_die(gettext("Out of memory.\n"));
16025 
16026 	return (0);
16027 }
16028 
16029 static int
16030 uri_split(char *uri, char **scheme, char **hier_part)
16031 {
16032 	int r = -1;
16033 
16034 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16035 	    *hier_part == NULL) {
16036 		semerr(gettext("'%s' is not an URI\n"), uri);
16037 		return (r);
16038 	}
16039 
16040 	if ((r = check_uri_scheme(*scheme)) < 0) {
16041 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16042 		return (r);
16043 	}
16044 
16045 	return (r);
16046 }
16047 
16048 static int
16049 process_uri(nvlist_t *params, char *uri)
16050 {
16051 	char *scheme;
16052 	char *hier_part;
16053 	nvlist_t *mech;
16054 	int index;
16055 	int r;
16056 
16057 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16058 		return (-1);
16059 
16060 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16061 		uu_die(gettext("Out of memory.\n"));
16062 
16063 	switch (index) {
16064 	case 0:
16065 		/* error messages displayed by called function */
16066 		r = add_mailto_params(mech, hier_part);
16067 		break;
16068 
16069 	case 1:
16070 		if ((r = add_snmp_params(mech, hier_part)) != 0)
16071 			semerr(gettext("Not valid parameters: '%s'\n"),
16072 			    hier_part);
16073 		break;
16074 
16075 	case 2:
16076 		if ((r = add_syslog_params(mech, hier_part)) != 0)
16077 			semerr(gettext("Not valid parameters: '%s'\n"),
16078 			    hier_part);
16079 		break;
16080 
16081 	default:
16082 		r = -1;
16083 	}
16084 
16085 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16086 	    mech) != 0)
16087 		uu_die(gettext("Out of memory.\n"));
16088 
16089 	nvlist_free(mech);
16090 	return (r);
16091 }
16092 
16093 static int
16094 set_params(nvlist_t *params, char **p)
16095 {
16096 	char *uri;
16097 
16098 	if (p == NULL)
16099 		/* sanity check */
16100 		uu_die("set_params");
16101 
16102 	while (*p) {
16103 		uri = strip_quotes_and_blanks(*p);
16104 		if (process_uri(params, uri) != 0)
16105 			return (-1);
16106 
16107 		++p;
16108 	}
16109 
16110 	return (0);
16111 }
16112 
16113 static int
16114 setnotify(const char *e, char **p, int global)
16115 {
16116 	char *str = safe_strdup(e);
16117 	char **events;
16118 	int32_t tset;
16119 	int r = -1;
16120 	nvlist_t *nvl, *params;
16121 	char *fmri = NULL;
16122 
16123 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16124 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16125 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16126 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
16127 		uu_die(gettext("Out of memory.\n"));
16128 
16129 	events = tokenize(str, ",");
16130 
16131 	if ((tset = check_tokens(events)) > 0) {
16132 		/* SMF state transitions parameters */
16133 		size_t sz = max_scf_fmri_len + 1;
16134 
16135 		fmri = safe_malloc(sz);
16136 		if (global) {
16137 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16138 		} else if (get_selection_str(fmri, sz) != 0) {
16139 			goto out;
16140 		}
16141 
16142 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16143 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16144 			uu_die(gettext("Out of memory.\n"));
16145 
16146 		if ((r = set_params(params, p)) == 0) {
16147 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16148 			    params) != 0)
16149 				uu_die(gettext("Out of memory.\n"));
16150 
16151 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16152 			    nvl) != SCF_SUCCESS) {
16153 				r = -1;
16154 				uu_warn(gettext(
16155 				    "Failed smf_notify_set_params(3SCF): %s\n"),
16156 				    scf_strerror(scf_error()));
16157 			}
16158 		}
16159 	} else if (tset == FMA_TOKENS) {
16160 		/* FMA event parameters */
16161 		if (global) {
16162 			semerr(gettext("Can't use option '-g' with FMA event "
16163 			    "definitions\n"));
16164 			goto out;
16165 		}
16166 
16167 		if ((r = set_params(params, p)) != 0)
16168 			goto out;
16169 
16170 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16171 			uu_die(gettext("Out of memory.\n"));
16172 
16173 		while (*events) {
16174 			if (smf_notify_set_params(de_tag(*events), nvl) !=
16175 			    SCF_SUCCESS)
16176 				uu_warn(gettext(
16177 				    "Failed smf_notify_set_params(3SCF) for "
16178 				    "event %s: %s\n"), *events,
16179 				    scf_strerror(scf_error()));
16180 			events++;
16181 		}
16182 	} else if (tset == MIXED_TOKENS) {
16183 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16184 	} else {
16185 		/* Sanity check */
16186 		uu_die(gettext("Invalid input.\n"));
16187 	}
16188 
16189 out:
16190 	nvlist_free(nvl);
16191 	nvlist_free(params);
16192 	free(fmri);
16193 	free(str);
16194 
16195 	return (r);
16196 }
16197 
16198 int
16199 lscf_setnotify(uu_list_t *args)
16200 {
16201 	int argc;
16202 	char **argv = NULL;
16203 	string_list_t *slp;
16204 	int global;
16205 	char *events;
16206 	char **p;
16207 	int i;
16208 	int ret;
16209 
16210 	if ((argc = uu_list_numnodes(args)) < 2)
16211 		goto usage;
16212 
16213 	argv = calloc(argc + 1, sizeof (char *));
16214 	if (argv == NULL)
16215 		uu_die(gettext("Out of memory.\n"));
16216 
16217 	for (slp = uu_list_first(args), i = 0;
16218 	    slp != NULL;
16219 	    slp = uu_list_next(args, slp), ++i)
16220 		argv[i] = slp->str;
16221 
16222 	argv[i] = NULL;
16223 
16224 	if (strcmp(argv[0], "-g") == 0) {
16225 		global = 1;
16226 		events = argv[1];
16227 		p = argv + 2;
16228 	} else {
16229 		global = 0;
16230 		events = argv[0];
16231 		p = argv + 1;
16232 	}
16233 
16234 	ret = setnotify(events, p, global);
16235 
16236 out:
16237 	free(argv);
16238 	return (ret);
16239 
16240 usage:
16241 	ret = -2;
16242 	goto out;
16243 }
16244 
16245 /*
16246  * Creates a list of instance name strings associated with a service. If
16247  * wohandcrafted flag is set, get only instances that have a last-import
16248  * snapshot, instances that were imported via svccfg.
16249  */
16250 static uu_list_t *
16251 create_instance_list(scf_service_t *svc, int wohandcrafted)
16252 {
16253 	scf_snapshot_t  *snap = NULL;
16254 	scf_instance_t  *inst;
16255 	scf_iter_t	*inst_iter;
16256 	uu_list_t	*instances;
16257 	char		*instname;
16258 	int		r;
16259 
16260 	inst_iter = scf_iter_create(g_hndl);
16261 	inst = scf_instance_create(g_hndl);
16262 	if (inst_iter == NULL || inst == NULL) {
16263 		uu_warn(gettext("Could not create instance or iterator\n"));
16264 		scfdie();
16265 	}
16266 
16267 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16268 		return (instances);
16269 
16270 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
16271 		switch (scf_error()) {
16272 		case SCF_ERROR_CONNECTION_BROKEN:
16273 		case SCF_ERROR_DELETED:
16274 			uu_list_destroy(instances);
16275 			instances = NULL;
16276 			goto out;
16277 
16278 		case SCF_ERROR_HANDLE_MISMATCH:
16279 		case SCF_ERROR_NOT_BOUND:
16280 		case SCF_ERROR_NOT_SET:
16281 		default:
16282 			bad_error("scf_iter_service_instances", scf_error());
16283 		}
16284 	}
16285 
16286 	instname = safe_malloc(max_scf_name_len + 1);
16287 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16288 		if (r == -1) {
16289 			(void) uu_warn(gettext("Unable to iterate through "
16290 			    "instances to create instance list : %s\n"),
16291 			    scf_strerror(scf_error()));
16292 
16293 			uu_list_destroy(instances);
16294 			instances = NULL;
16295 			goto out;
16296 		}
16297 
16298 		/*
16299 		 * If the instance does not have a last-import snapshot
16300 		 * then do not add it to the list as it is a hand-crafted
16301 		 * instance that should not be managed.
16302 		 */
16303 		if (wohandcrafted) {
16304 			if (snap == NULL &&
16305 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
16306 				uu_warn(gettext("Unable to create snapshot "
16307 				    "entity\n"));
16308 				scfdie();
16309 			}
16310 
16311 			if (scf_instance_get_snapshot(inst,
16312 			    snap_lastimport, snap) != 0) {
16313 				switch (scf_error()) {
16314 				case SCF_ERROR_NOT_FOUND :
16315 				case SCF_ERROR_DELETED:
16316 					continue;
16317 
16318 				case SCF_ERROR_CONNECTION_BROKEN:
16319 					uu_list_destroy(instances);
16320 					instances = NULL;
16321 					goto out;
16322 
16323 				case SCF_ERROR_HANDLE_MISMATCH:
16324 				case SCF_ERROR_NOT_BOUND:
16325 				case SCF_ERROR_NOT_SET:
16326 				default:
16327 					bad_error("scf_iter_service_instances",
16328 					    scf_error());
16329 				}
16330 			}
16331 		}
16332 
16333 		if (scf_instance_get_name(inst, instname,
16334 		    max_scf_name_len + 1) < 0) {
16335 			switch (scf_error()) {
16336 			case SCF_ERROR_NOT_FOUND :
16337 				continue;
16338 
16339 			case SCF_ERROR_CONNECTION_BROKEN:
16340 			case SCF_ERROR_DELETED:
16341 				uu_list_destroy(instances);
16342 				instances = NULL;
16343 				goto out;
16344 
16345 			case SCF_ERROR_HANDLE_MISMATCH:
16346 			case SCF_ERROR_NOT_BOUND:
16347 			case SCF_ERROR_NOT_SET:
16348 			default:
16349 				bad_error("scf_iter_service_instances",
16350 				    scf_error());
16351 			}
16352 		}
16353 
16354 		add_string(instances, instname);
16355 	}
16356 
16357 out:
16358 	if (snap)
16359 		scf_snapshot_destroy(snap);
16360 
16361 	scf_instance_destroy(inst);
16362 	scf_iter_destroy(inst_iter);
16363 	free(instname);
16364 	return (instances);
16365 }
16366 
16367 /*
16368  * disable an instance but wait for the instance to
16369  * move out of the running state.
16370  *
16371  * Returns 0 : if the instance did not disable
16372  * Returns non-zero : if the instance disabled.
16373  *
16374  */
16375 static int
16376 disable_instance(scf_instance_t *instance)
16377 {
16378 	char	*fmribuf;
16379 	int	enabled = 10000;
16380 
16381 	if (inst_is_running(instance)) {
16382 		fmribuf = safe_malloc(max_scf_name_len + 1);
16383 		if (scf_instance_to_fmri(instance, fmribuf,
16384 		    max_scf_name_len + 1) < 0) {
16385 			free(fmribuf);
16386 			return (0);
16387 		}
16388 
16389 		/*
16390 		 * If the instance cannot be disabled then return
16391 		 * failure to disable and let the caller decide
16392 		 * if that is of importance.
16393 		 */
16394 		if (smf_disable_instance(fmribuf, 0) != 0) {
16395 			free(fmribuf);
16396 			return (0);
16397 		}
16398 
16399 		while (enabled) {
16400 			if (!inst_is_running(instance))
16401 				break;
16402 
16403 			(void) poll(NULL, 0, 5);
16404 			enabled = enabled - 5;
16405 		}
16406 
16407 		free(fmribuf);
16408 	}
16409 
16410 	return (enabled);
16411 }
16412 
16413 /*
16414  * Function to compare two service_manifest structures.
16415  */
16416 /* ARGSUSED2 */
16417 static int
16418 service_manifest_compare(const void *left, const void *right, void *unused)
16419 {
16420 	service_manifest_t *l = (service_manifest_t *)left;
16421 	service_manifest_t *r = (service_manifest_t *)right;
16422 	int rc;
16423 
16424 	rc = strcmp(l->servicename, r->servicename);
16425 
16426 	return (rc);
16427 }
16428 
16429 /*
16430  * Look for the provided service in the service to manifest
16431  * tree.  If the service exists, and a manifest was provided
16432  * then add the manifest to that service.  If the service
16433  * does not exist, then add the service and manifest to the
16434  * list.
16435  *
16436  * If the manifest is NULL, return the element if found.  If
16437  * the service is not found return NULL.
16438  */
16439 service_manifest_t *
16440 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16441 {
16442 	service_manifest_t	elem;
16443 	service_manifest_t	*fnelem;
16444 	uu_avl_index_t		marker;
16445 
16446 	elem.servicename = svnbuf;
16447 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16448 
16449 	if (mfst) {
16450 		if (fnelem) {
16451 			add_string(fnelem->mfstlist, strdup(mfst));
16452 		} else {
16453 			fnelem = safe_malloc(sizeof (*fnelem));
16454 			fnelem->servicename = safe_strdup(svnbuf);
16455 			if ((fnelem->mfstlist =
16456 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16457 				uu_die(gettext("Could not create property "
16458 				    "list: %s\n"), uu_strerror(uu_error()));
16459 
16460 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16461 
16462 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16463 		}
16464 	}
16465 
16466 	return (fnelem);
16467 }
16468 
16469 /*
16470  * Create the service to manifest avl tree.
16471  *
16472  * Walk each of the manifests currently installed in the supported
16473  * directories, /lib/svc/manifest and /var/svc/manifest.  For
16474  * each of the manifests, inventory the services and add them to
16475  * the tree.
16476  *
16477  * Code that calls this function should make sure fileystem/minimal is online,
16478  * /var is available, since this function walks the /var/svc/manifest directory.
16479  */
16480 static void
16481 create_manifest_tree(void)
16482 {
16483 	manifest_info_t **entry;
16484 	manifest_info_t **manifests;
16485 	uu_list_walk_t	*svcs;
16486 	bundle_t	*b;
16487 	entity_t	*mfsvc;
16488 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16489 	int		c, status;
16490 
16491 	if (service_manifest_pool)
16492 		return;
16493 
16494 	/*
16495 	 * Create the list pool for the service manifest list
16496 	 */
16497 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16498 	    sizeof (service_manifest_t),
16499 	    offsetof(service_manifest_t, svcmfst_node),
16500 	    service_manifest_compare, UU_DEFAULT);
16501 	if (service_manifest_pool == NULL)
16502 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16503 		    uu_strerror(uu_error()));
16504 
16505 	/*
16506 	 * Create the list
16507 	 */
16508 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16509 	    UU_DEFAULT);
16510 	if (service_manifest_tree == NULL)
16511 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16512 		    uu_strerror(uu_error()));
16513 
16514 	/*
16515 	 * Walk the manifests adding the service(s) from each manifest.
16516 	 *
16517 	 * If a service already exists add the manifest to the manifest
16518 	 * list for that service.  This covers the case of a service that
16519 	 * is supported by multiple manifest files.
16520 	 */
16521 	for (c = 0; dirs[c]; c++) {
16522 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16523 		if (status < 0) {
16524 			uu_warn(gettext("file tree walk of %s encountered "
16525 			    "error %s\n"), dirs[c], strerror(errno));
16526 
16527 			uu_avl_destroy(service_manifest_tree);
16528 			service_manifest_tree = NULL;
16529 			return;
16530 		}
16531 
16532 		/*
16533 		 * If a manifest that was in the list is not found
16534 		 * then skip and go to the next manifest file.
16535 		 */
16536 		if (manifests != NULL) {
16537 			for (entry = manifests; *entry != NULL; entry++) {
16538 				b = internal_bundle_new();
16539 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16540 				    SVCCFG_OP_IMPORT) != 0) {
16541 					internal_bundle_free(b);
16542 					continue;
16543 				}
16544 
16545 				svcs = uu_list_walk_start(b->sc_bundle_services,
16546 				    0);
16547 				if (svcs == NULL) {
16548 					internal_bundle_free(b);
16549 					continue;
16550 				}
16551 
16552 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16553 				    NULL) {
16554 					/* Add manifest to service */
16555 					(void) find_add_svc_mfst(mfsvc->sc_name,
16556 					    (*entry)->mi_path);
16557 				}
16558 
16559 				uu_list_walk_end(svcs);
16560 				internal_bundle_free(b);
16561 			}
16562 
16563 			free_manifest_array(manifests);
16564 		}
16565 	}
16566 }
16567 
16568 /*
16569  * Check the manifest history file to see
16570  * if the service was ever installed from
16571  * one of the supported directories.
16572  *
16573  * Return Values :
16574  *	-1 - if there's error reading manifest history file
16575  *	 1 - if the service is not found
16576  *	 0 - if the service is found
16577  */
16578 static int
16579 check_mfst_history(const char *svcname)
16580 {
16581 	struct stat	st;
16582 	caddr_t		mfsthist_start;
16583 	char		*svnbuf;
16584 	int		fd;
16585 	int		r = 1;
16586 
16587 	fd = open(MFSTHISTFILE, O_RDONLY);
16588 	if (fd == -1) {
16589 		uu_warn(gettext("Unable to open the history file\n"));
16590 		return (-1);
16591 	}
16592 
16593 	if (fstat(fd, &st) == -1) {
16594 		uu_warn(gettext("Unable to stat the history file\n"));
16595 		return (-1);
16596 	}
16597 
16598 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16599 	    MAP_PRIVATE, fd, 0);
16600 
16601 	(void) close(fd);
16602 	if (mfsthist_start == MAP_FAILED ||
16603 	    *(mfsthist_start + st.st_size) != '\0') {
16604 		(void) munmap(mfsthist_start, st.st_size);
16605 		return (-1);
16606 	}
16607 
16608 	/*
16609 	 * The manifest history file is a space delimited list
16610 	 * of service and instance to manifest linkage.  Adding
16611 	 * a space to the end of the service name so to get only
16612 	 * the service that is being searched for.
16613 	 */
16614 	svnbuf = uu_msprintf("%s ", svcname);
16615 	if (svnbuf == NULL)
16616 		uu_die(gettext("Out of memory"));
16617 
16618 	if (strstr(mfsthist_start, svnbuf) != NULL)
16619 		r = 0;
16620 
16621 	(void) munmap(mfsthist_start, st.st_size);
16622 	uu_free(svnbuf);
16623 	return (r);
16624 }
16625 
16626 /*
16627  * Take down each of the instances in the service
16628  * and remove them, then delete the service.
16629  */
16630 static void
16631 teardown_service(scf_service_t *svc, const char *svnbuf)
16632 {
16633 	scf_instance_t	*instance;
16634 	scf_iter_t	*iter;
16635 	int		r;
16636 
16637 	safe_printf(gettext("Delete service %s as there are no "
16638 	    "supporting manifests\n"), svnbuf);
16639 
16640 	instance = scf_instance_create(g_hndl);
16641 	iter = scf_iter_create(g_hndl);
16642 	if (iter == NULL || instance == NULL) {
16643 		uu_warn(gettext("Unable to create supporting entities to "
16644 		    "teardown the service\n"));
16645 		uu_warn(gettext("scf error is : %s\n"),
16646 		    scf_strerror(scf_error()));
16647 		scfdie();
16648 	}
16649 
16650 	if (scf_iter_service_instances(iter, svc) != 0) {
16651 		switch (scf_error()) {
16652 		case SCF_ERROR_CONNECTION_BROKEN:
16653 		case SCF_ERROR_DELETED:
16654 			goto out;
16655 
16656 		case SCF_ERROR_HANDLE_MISMATCH:
16657 		case SCF_ERROR_NOT_BOUND:
16658 		case SCF_ERROR_NOT_SET:
16659 		default:
16660 			bad_error("scf_iter_service_instances",
16661 			    scf_error());
16662 		}
16663 	}
16664 
16665 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16666 		if (r == -1) {
16667 			uu_warn(gettext("Error - %s\n"),
16668 			    scf_strerror(scf_error()));
16669 			goto out;
16670 		}
16671 
16672 		(void) disable_instance(instance);
16673 	}
16674 
16675 	/*
16676 	 * Delete the service... forcing the deletion in case
16677 	 * any of the instances did not disable.
16678 	 */
16679 	(void) lscf_service_delete(svc, 1);
16680 out:
16681 	scf_instance_destroy(instance);
16682 	scf_iter_destroy(iter);
16683 }
16684 
16685 /*
16686  * Get the list of instances supported by the manifest
16687  * file.
16688  *
16689  * Return 0 if there are no instances.
16690  *
16691  * Return -1 if there are errors attempting to collect instances.
16692  *
16693  * Return the count of instances found if there are no errors.
16694  *
16695  */
16696 static int
16697 check_instance_support(char *mfstfile, const char *svcname,
16698     uu_list_t *instances)
16699 {
16700 	uu_list_walk_t	*svcs, *insts;
16701 	uu_list_t	*ilist;
16702 	bundle_t	*b;
16703 	entity_t	*mfsvc, *mfinst;
16704 	const char	*svcn;
16705 	int		rminstcnt = 0;
16706 
16707 
16708 	b = internal_bundle_new();
16709 
16710 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16711 		/*
16712 		 * Unable to process the manifest file for
16713 		 * instance support, so just return as
16714 		 * don't want to remove instances that could
16715 		 * not be accounted for that might exist here.
16716 		 */
16717 		internal_bundle_free(b);
16718 		return (0);
16719 	}
16720 
16721 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16722 	if (svcs == NULL) {
16723 		internal_bundle_free(b);
16724 		return (0);
16725 	}
16726 
16727 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16728 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16729 
16730 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16731 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16732 			break;
16733 	}
16734 	uu_list_walk_end(svcs);
16735 
16736 	if (mfsvc == NULL) {
16737 		internal_bundle_free(b);
16738 		return (-1);
16739 	}
16740 
16741 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16742 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16743 		internal_bundle_free(b);
16744 		return (0);
16745 	}
16746 
16747 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16748 		/*
16749 		 * Remove the instance from the instances list.
16750 		 * The unaccounted for instances will be removed
16751 		 * from the service once all manifests are
16752 		 * processed.
16753 		 */
16754 		(void) remove_string(instances,
16755 		    mfinst->sc_name);
16756 		rminstcnt++;
16757 	}
16758 
16759 	uu_list_walk_end(insts);
16760 	internal_bundle_free(b);
16761 
16762 	return (rminstcnt);
16763 }
16764 
16765 /*
16766  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16767  * 'false' to indicate there's no manifest file(s) found for the service.
16768  */
16769 static void
16770 svc_add_no_support(scf_service_t *svc)
16771 {
16772 	char	*pname;
16773 
16774 	/* Add no support */
16775 	cur_svc = svc;
16776 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16777 		return;
16778 
16779 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16780 	if (pname == NULL)
16781 		uu_die(gettext("Out of memory.\n"));
16782 
16783 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16784 
16785 	uu_free(pname);
16786 	cur_svc = NULL;
16787 }
16788 
16789 /*
16790  * This function handles all upgrade scenarios for a service that doesn't have
16791  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16792  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16793  * manifest(s) mapping. Manifests under supported directories are inventoried
16794  * and a property is added for each file that delivers configuration to the
16795  * service.  A service that has no corresponding manifest files (deleted) are
16796  * removed from repository.
16797  *
16798  * Unsupported services:
16799  *
16800  * A service is considered unsupported if there is no corresponding manifest
16801  * in the supported directories for that service and the service isn't in the
16802  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16803  * services and instances that were delivered by Solaris before the introduction
16804  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16805  * the path to the manifest file that defined the service or instance.
16806  *
16807  * Another type of unsupported services is 'handcrafted' services,
16808  * programmatically created services or services created by dependent entries
16809  * in other manifests. A handcrafted service is identified by its lack of any
16810  * instance containing last-import snapshot which is created during svccfg
16811  * import.
16812  *
16813  * This function sets a flag for unsupported services by setting services'
16814  * SCF_PG_MANIFESTFILES/support property to false.
16815  */
16816 static void
16817 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16818 {
16819 	service_manifest_t	*elem;
16820 	uu_list_walk_t		*mfwalk;
16821 	string_list_t		*mfile;
16822 	uu_list_t		*instances;
16823 	const char		*sname;
16824 	char			*pname;
16825 	int			r;
16826 
16827 	/*
16828 	 * Since there's no guarantee manifests under /var are available during
16829 	 * early import, don't perform any upgrade during early import.
16830 	 */
16831 	if (IGNORE_VAR)
16832 		return;
16833 
16834 	if (service_manifest_tree == NULL) {
16835 		create_manifest_tree();
16836 	}
16837 
16838 	/*
16839 	 * Find service's supporting manifest(s) after
16840 	 * stripping off the svc:/ prefix that is part
16841 	 * of the fmri that is not used in the service
16842 	 * manifest bundle list.
16843 	 */
16844 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16845 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16846 	elem = find_add_svc_mfst(sname, NULL);
16847 	if (elem == NULL) {
16848 
16849 		/*
16850 		 * A handcrafted service, one that has no instance containing
16851 		 * last-import snapshot, should get unsupported flag.
16852 		 */
16853 		instances = create_instance_list(svc, 1);
16854 		if (instances == NULL) {
16855 			uu_warn(gettext("Unable to create instance list %s\n"),
16856 			    svcname);
16857 			return;
16858 		}
16859 
16860 		if (uu_list_numnodes(instances) == 0) {
16861 			svc_add_no_support(svc);
16862 			return;
16863 		}
16864 
16865 		/*
16866 		 * If the service is in the history file, and its supporting
16867 		 * manifests are not found, we can safely delete the service
16868 		 * because its manifests are removed from the system.
16869 		 *
16870 		 * Services not found in the history file are not delivered by
16871 		 * Solaris and/or delivered outside supported directories, set
16872 		 * unsupported flag for these services.
16873 		 */
16874 		r = check_mfst_history(svcname);
16875 		if (r == -1)
16876 			return;
16877 
16878 		if (r) {
16879 			/* Set unsupported flag for service  */
16880 			svc_add_no_support(svc);
16881 		} else {
16882 			/* Delete the service */
16883 			teardown_service(svc, svcname);
16884 		}
16885 
16886 		return;
16887 	}
16888 
16889 	/*
16890 	 * Walk through the list of manifests and add them
16891 	 * to the service.
16892 	 *
16893 	 * Create a manifestfiles pg and add the property.
16894 	 */
16895 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16896 	if (mfwalk == NULL)
16897 		return;
16898 
16899 	cur_svc = svc;
16900 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16901 	if (r != 0) {
16902 		cur_svc = NULL;
16903 		return;
16904 	}
16905 
16906 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16907 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16908 		    mhash_filename_to_propname(mfile->str, 0));
16909 		if (pname == NULL)
16910 			uu_die(gettext("Out of memory.\n"));
16911 
16912 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16913 		uu_free(pname);
16914 	}
16915 	uu_list_walk_end(mfwalk);
16916 
16917 	cur_svc = NULL;
16918 }
16919 
16920 /*
16921  * Take a service and process the manifest file entires to see if
16922  * there is continued support for the service and instances.  If
16923  * not cleanup as appropriate.
16924  *
16925  * If a service does not have a manifest files entry flag it for
16926  * upgrade and return.
16927  *
16928  * For each manifestfiles property check if the manifest file is
16929  * under the supported /lib/svc/manifest or /var/svc/manifest path
16930  * and if not then return immediately as this service is not supported
16931  * by the cleanup mechanism and should be ignored.
16932  *
16933  * For each manifest file that is supported, check to see if the
16934  * file exists.  If not then remove the manifest file property
16935  * from the service and the smf/manifest hash table.  If the manifest
16936  * file exists then verify that it supports the instances that are
16937  * part of the service.
16938  *
16939  * Once all manifest files have been accounted for remove any instances
16940  * that are no longer supported in the service.
16941  *
16942  * Return values :
16943  * 0 - Successfully processed the service
16944  * non-zero - failed to process the service
16945  *
16946  * On most errors, will just return to wait and get the next service,
16947  * unless in case of unable to create the needed structures which is
16948  * most likely a fatal error that is not going to be recoverable.
16949  */
16950 int
16951 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16952 {
16953 	struct mpg_mfile	*mpntov = NULL;
16954 	struct mpg_mfile	**mpvarry = NULL;
16955 	scf_service_t		*svc;
16956 	scf_propertygroup_t	*mpg;
16957 	scf_property_t		*mp;
16958 	scf_value_t		*mv;
16959 	scf_iter_t		*mi;
16960 	scf_instance_t		*instance;
16961 	uu_list_walk_t		*insts;
16962 	uu_list_t		*instances = NULL;
16963 	boolean_t		activity = (boolean_t)act;
16964 	char			*mpnbuf = NULL;
16965 	char			*mpvbuf = NULL;
16966 	char			*pgpropbuf;
16967 	int			mfstcnt, rminstct, instct, mfstmax;
16968 	int			index;
16969 	int			r = 0;
16970 
16971 	assert(g_hndl != NULL);
16972 	assert(wip->svc != NULL);
16973 	assert(wip->fmri != NULL);
16974 
16975 	svc = wip->svc;
16976 
16977 	mpg = scf_pg_create(g_hndl);
16978 	mp = scf_property_create(g_hndl);
16979 	mi = scf_iter_create(g_hndl);
16980 	mv = scf_value_create(g_hndl);
16981 	instance = scf_instance_create(g_hndl);
16982 
16983 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16984 	    instance == NULL) {
16985 		uu_warn(gettext("Unable to create the supporting entities\n"));
16986 		uu_warn(gettext("scf error is : %s\n"),
16987 		    scf_strerror(scf_error()));
16988 		scfdie();
16989 	}
16990 
16991 	/*
16992 	 * Get the manifestfiles property group to be parsed for
16993 	 * files existence.
16994 	 */
16995 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16996 		switch (scf_error()) {
16997 		case SCF_ERROR_NOT_FOUND:
16998 			upgrade_svc_mfst_connection(svc, wip->fmri);
16999 			break;
17000 		case SCF_ERROR_DELETED:
17001 		case SCF_ERROR_CONNECTION_BROKEN:
17002 			goto out;
17003 
17004 		case SCF_ERROR_HANDLE_MISMATCH:
17005 		case SCF_ERROR_NOT_BOUND:
17006 		case SCF_ERROR_NOT_SET:
17007 		default:
17008 			bad_error("scf_iter_pg_properties",
17009 			    scf_error());
17010 		}
17011 
17012 		goto out;
17013 	}
17014 
17015 	/*
17016 	 * Iterate through each of the manifestfiles properties
17017 	 * to determine what manifestfiles are available.
17018 	 *
17019 	 * If a manifest file is supported then increment the
17020 	 * count and therefore the service is safe.
17021 	 */
17022 	if (scf_iter_pg_properties(mi, mpg) != 0) {
17023 		switch (scf_error()) {
17024 		case SCF_ERROR_DELETED:
17025 		case SCF_ERROR_CONNECTION_BROKEN:
17026 			goto out;
17027 
17028 		case SCF_ERROR_HANDLE_MISMATCH:
17029 		case SCF_ERROR_NOT_BOUND:
17030 		case SCF_ERROR_NOT_SET:
17031 		default:
17032 			bad_error("scf_iter_pg_properties",
17033 			    scf_error());
17034 		}
17035 	}
17036 
17037 	mfstcnt = 0;
17038 	mfstmax = MFSTFILE_MAX;
17039 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17040 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
17041 		if (r == -1)
17042 			bad_error(gettext("Unable to iterate through "
17043 			    "manifestfiles properties : %s"),
17044 			    scf_error());
17045 
17046 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
17047 		mpnbuf = safe_malloc(max_scf_name_len + 1);
17048 		mpvbuf = safe_malloc(max_scf_value_len + 1);
17049 		mpntov->mpg = mpnbuf;
17050 		mpntov->mfile = mpvbuf;
17051 		mpntov->access = 1;
17052 		if (scf_property_get_name(mp, mpnbuf,
17053 		    max_scf_name_len + 1) < 0) {
17054 			uu_warn(gettext("Unable to get manifest file "
17055 			    "property : %s\n"),
17056 			    scf_strerror(scf_error()));
17057 
17058 			switch (scf_error()) {
17059 			case SCF_ERROR_DELETED:
17060 			case SCF_ERROR_CONNECTION_BROKEN:
17061 				r = scferror2errno(scf_error());
17062 				goto out_free;
17063 
17064 			case SCF_ERROR_HANDLE_MISMATCH:
17065 			case SCF_ERROR_NOT_BOUND:
17066 			case SCF_ERROR_NOT_SET:
17067 			default:
17068 				bad_error("scf_iter_pg_properties",
17069 				    scf_error());
17070 			}
17071 		}
17072 
17073 		/*
17074 		 * The support property is a boolean value that indicates
17075 		 * if the service is supported for manifest file deletion.
17076 		 * Currently at this time there is no code that sets this
17077 		 * value to true.  So while we could just let this be caught
17078 		 * by the support check below, in the future this by be set
17079 		 * to true and require processing.  So for that, go ahead
17080 		 * and check here, and just return if false.  Otherwise,
17081 		 * fall through expecting that other support checks will
17082 		 * handle the entries.
17083 		 */
17084 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17085 			uint8_t	support;
17086 
17087 			if (scf_property_get_value(mp, mv) != 0 ||
17088 			    scf_value_get_boolean(mv, &support) != 0) {
17089 				uu_warn(gettext("Unable to get the manifest "
17090 				    "support value: %s\n"),
17091 				    scf_strerror(scf_error()));
17092 
17093 				switch (scf_error()) {
17094 				case SCF_ERROR_DELETED:
17095 				case SCF_ERROR_CONNECTION_BROKEN:
17096 					r = scferror2errno(scf_error());
17097 					goto out_free;
17098 
17099 				case SCF_ERROR_HANDLE_MISMATCH:
17100 				case SCF_ERROR_NOT_BOUND:
17101 				case SCF_ERROR_NOT_SET:
17102 				default:
17103 					bad_error("scf_iter_pg_properties",
17104 					    scf_error());
17105 				}
17106 			}
17107 
17108 			if (support == B_FALSE)
17109 				goto out_free;
17110 		}
17111 
17112 		/*
17113 		 * Anything with a manifest outside of the supported
17114 		 * directories, immediately bail out because that makes
17115 		 * this service non-supported.  We don't even want
17116 		 * to do instance processing in this case because the
17117 		 * instances could be part of the non-supported manifest.
17118 		 */
17119 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17120 			/*
17121 			 * Manifest is not in /lib/svc, so we need to
17122 			 * consider the /var/svc case.
17123 			 */
17124 			if (strncmp(mpnbuf, VARSVC_PR,
17125 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17126 				/*
17127 				 * Either the manifest is not in /var/svc or
17128 				 * /var is not yet mounted.  We ignore the
17129 				 * manifest either because it is not in a
17130 				 * standard location or because we cannot
17131 				 * currently access the manifest.
17132 				 */
17133 				goto out_free;
17134 			}
17135 		}
17136 
17137 		/*
17138 		 * Get the value to of the manifest file for this entry
17139 		 * for access verification and instance support
17140 		 * verification if it still exists.
17141 		 *
17142 		 * During Early Manifest Import if the manifest is in
17143 		 * /var/svc then it may not yet be available for checking
17144 		 * so we must determine if /var/svc is available.  If not
17145 		 * then defer until Late Manifest Import to cleanup.
17146 		 */
17147 		if (scf_property_get_value(mp, mv) != 0) {
17148 			uu_warn(gettext("Unable to get the manifest file "
17149 			    "value: %s\n"),
17150 			    scf_strerror(scf_error()));
17151 
17152 			switch (scf_error()) {
17153 			case SCF_ERROR_DELETED:
17154 			case SCF_ERROR_CONNECTION_BROKEN:
17155 				r = scferror2errno(scf_error());
17156 				goto out_free;
17157 
17158 			case SCF_ERROR_HANDLE_MISMATCH:
17159 			case SCF_ERROR_NOT_BOUND:
17160 			case SCF_ERROR_NOT_SET:
17161 			default:
17162 				bad_error("scf_property_get_value",
17163 				    scf_error());
17164 			}
17165 		}
17166 
17167 		if (scf_value_get_astring(mv, mpvbuf,
17168 		    max_scf_value_len + 1) < 0) {
17169 			uu_warn(gettext("Unable to get the manifest "
17170 			    "file : %s\n"),
17171 			    scf_strerror(scf_error()));
17172 
17173 			switch (scf_error()) {
17174 			case SCF_ERROR_DELETED:
17175 			case SCF_ERROR_CONNECTION_BROKEN:
17176 				r = scferror2errno(scf_error());
17177 				goto out_free;
17178 
17179 			case SCF_ERROR_HANDLE_MISMATCH:
17180 			case SCF_ERROR_NOT_BOUND:
17181 			case SCF_ERROR_NOT_SET:
17182 			default:
17183 				bad_error("scf_value_get_astring",
17184 				    scf_error());
17185 			}
17186 		}
17187 
17188 		mpvarry[mfstcnt] = mpntov;
17189 		mfstcnt++;
17190 
17191 		/*
17192 		 * Check for the need to reallocate array
17193 		 */
17194 		if (mfstcnt >= (mfstmax - 1)) {
17195 			struct mpg_mfile **newmpvarry;
17196 
17197 			mfstmax = mfstmax * 2;
17198 			newmpvarry = realloc(mpvarry,
17199 			    sizeof (struct mpg_mfile *) * mfstmax);
17200 
17201 			if (newmpvarry == NULL)
17202 				goto out_free;
17203 
17204 			mpvarry = newmpvarry;
17205 		}
17206 
17207 		mpvarry[mfstcnt] = NULL;
17208 	}
17209 
17210 	for (index = 0; mpvarry[index]; index++) {
17211 		mpntov = mpvarry[index];
17212 
17213 		/*
17214 		 * Check to see if the manifestfile is accessable, if so hand
17215 		 * this service and manifestfile off to be processed for
17216 		 * instance support.
17217 		 */
17218 		mpnbuf = mpntov->mpg;
17219 		mpvbuf = mpntov->mfile;
17220 		if (access(mpvbuf, F_OK) != 0) {
17221 			mpntov->access = 0;
17222 			activity++;
17223 			mfstcnt--;
17224 			/* Remove the entry from the service */
17225 			cur_svc = svc;
17226 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17227 			    mpnbuf);
17228 			if (pgpropbuf == NULL)
17229 				uu_die(gettext("Out of memory.\n"));
17230 
17231 			lscf_delprop(pgpropbuf);
17232 			cur_svc = NULL;
17233 
17234 			uu_free(pgpropbuf);
17235 		}
17236 	}
17237 
17238 	/*
17239 	 * If mfstcnt is 0, none of the manifests that supported the service
17240 	 * existed so remove the service.
17241 	 */
17242 	if (mfstcnt == 0) {
17243 		teardown_service(svc, wip->fmri);
17244 
17245 		goto out_free;
17246 	}
17247 
17248 	if (activity) {
17249 		int	nosvcsupport = 0;
17250 
17251 		/*
17252 		 * If the list of service instances is NULL then
17253 		 * create the list.
17254 		 */
17255 		instances = create_instance_list(svc, 1);
17256 		if (instances == NULL) {
17257 			uu_warn(gettext("Unable to create instance list %s\n"),
17258 			    wip->fmri);
17259 			goto out_free;
17260 		}
17261 
17262 		rminstct = uu_list_numnodes(instances);
17263 		instct = rminstct;
17264 
17265 		for (index = 0; mpvarry[index]; index++) {
17266 			mpntov = mpvarry[index];
17267 			if (mpntov->access == 0)
17268 				continue;
17269 
17270 			mpnbuf = mpntov->mpg;
17271 			mpvbuf = mpntov->mfile;
17272 			r = check_instance_support(mpvbuf, wip->fmri,
17273 			    instances);
17274 			if (r == -1) {
17275 				nosvcsupport++;
17276 			} else {
17277 				rminstct -= r;
17278 			}
17279 		}
17280 
17281 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17282 			teardown_service(svc, wip->fmri);
17283 
17284 			goto out_free;
17285 		}
17286 	}
17287 
17288 	/*
17289 	 * If there are instances left on the instance list, then
17290 	 * we must remove them.
17291 	 */
17292 	if (instances != NULL && uu_list_numnodes(instances)) {
17293 		string_list_t *sp;
17294 
17295 		insts = uu_list_walk_start(instances, 0);
17296 		while ((sp = uu_list_walk_next(insts)) != NULL) {
17297 			/*
17298 			 * Remove the instance from the instances list.
17299 			 */
17300 			safe_printf(gettext("Delete instance %s from "
17301 			    "service %s\n"), sp->str, wip->fmri);
17302 			if (scf_service_get_instance(svc, sp->str,
17303 			    instance) != SCF_SUCCESS) {
17304 				(void) uu_warn("scf_error - %s\n",
17305 				    scf_strerror(scf_error()));
17306 
17307 				continue;
17308 			}
17309 
17310 			(void) disable_instance(instance);
17311 
17312 			(void) lscf_instance_delete(instance, 1);
17313 		}
17314 		scf_instance_destroy(instance);
17315 		uu_list_walk_end(insts);
17316 	}
17317 
17318 out_free:
17319 	if (mpvarry) {
17320 		struct mpg_mfile *fmpntov;
17321 
17322 		for (index = 0; mpvarry[index]; index++) {
17323 			fmpntov  = mpvarry[index];
17324 			if (fmpntov->mpg == mpnbuf)
17325 				mpnbuf = NULL;
17326 			free(fmpntov->mpg);
17327 
17328 			if (fmpntov->mfile == mpvbuf)
17329 				mpvbuf = NULL;
17330 			free(fmpntov->mfile);
17331 
17332 			if (fmpntov == mpntov)
17333 				mpntov = NULL;
17334 			free(fmpntov);
17335 		}
17336 		if (mpnbuf)
17337 			free(mpnbuf);
17338 		if (mpvbuf)
17339 			free(mpvbuf);
17340 		if (mpntov)
17341 			free(mpntov);
17342 
17343 		free(mpvarry);
17344 	}
17345 out:
17346 	scf_pg_destroy(mpg);
17347 	scf_property_destroy(mp);
17348 	scf_iter_destroy(mi);
17349 	scf_value_destroy(mv);
17350 
17351 	return (0);
17352 }
17353 
17354 /*
17355  * Take the service and search for the manifestfiles property
17356  * in each of the property groups.  If the manifest file
17357  * associated with the property does not exist then remove
17358  * the property group.
17359  */
17360 int
17361 lscf_hash_cleanup()
17362 {
17363 	scf_service_t		*svc;
17364 	scf_scope_t		*scope;
17365 	scf_propertygroup_t	*pg;
17366 	scf_property_t		*prop;
17367 	scf_value_t		*val;
17368 	scf_iter_t		*iter;
17369 	char			*pgname = NULL;
17370 	char			*mfile = NULL;
17371 	int			r;
17372 
17373 	svc = scf_service_create(g_hndl);
17374 	scope = scf_scope_create(g_hndl);
17375 	pg = scf_pg_create(g_hndl);
17376 	prop = scf_property_create(g_hndl);
17377 	val = scf_value_create(g_hndl);
17378 	iter = scf_iter_create(g_hndl);
17379 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17380 	    svc == NULL || scope == NULL) {
17381 		uu_warn(gettext("Unable to create a property group, or "
17382 		    "property\n"));
17383 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17384 		    "pg is not NULL");
17385 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17386 		    "prop is not NULL");
17387 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17388 		    "val is not NULL");
17389 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17390 		    "iter is not NULL");
17391 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17392 		    "svc is not NULL");
17393 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17394 		    "scope is not NULL");
17395 		uu_warn(gettext("scf error is : %s\n"),
17396 		    scf_strerror(scf_error()));
17397 		scfdie();
17398 	}
17399 
17400 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17401 		switch (scf_error()) {
17402 		case SCF_ERROR_CONNECTION_BROKEN:
17403 		case SCF_ERROR_NOT_FOUND:
17404 			goto out;
17405 
17406 		case SCF_ERROR_HANDLE_MISMATCH:
17407 		case SCF_ERROR_NOT_BOUND:
17408 		case SCF_ERROR_INVALID_ARGUMENT:
17409 		default:
17410 			bad_error("scf_handle_get_scope", scf_error());
17411 		}
17412 	}
17413 
17414 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17415 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17416 		    HASH_SVC);
17417 		goto out;
17418 	}
17419 
17420 	pgname = safe_malloc(max_scf_name_len + 1);
17421 	mfile = safe_malloc(max_scf_value_len + 1);
17422 
17423 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17424 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17425 		    scf_strerror(scf_error()));
17426 		goto out;
17427 	}
17428 
17429 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17430 		if (r == -1)
17431 			goto out;
17432 
17433 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17434 			switch (scf_error()) {
17435 			case SCF_ERROR_DELETED:
17436 				return (ENODEV);
17437 
17438 			case SCF_ERROR_CONNECTION_BROKEN:
17439 				return (ECONNABORTED);
17440 
17441 			case SCF_ERROR_NOT_SET:
17442 			case SCF_ERROR_NOT_BOUND:
17443 			default:
17444 				bad_error("scf_pg_get_name", scf_error());
17445 			}
17446 		}
17447 		if (IGNORE_VAR) {
17448 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17449 				continue;
17450 		}
17451 
17452 		/*
17453 		 * If unable to get the property continue as this is an
17454 		 * entry that has no location to check against.
17455 		 */
17456 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17457 			continue;
17458 		}
17459 
17460 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17461 			uu_warn(gettext("Unable to get value from %s\n"),
17462 			    pgname);
17463 
17464 			switch (scf_error()) {
17465 			case SCF_ERROR_DELETED:
17466 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17467 			case SCF_ERROR_NOT_FOUND:
17468 			case SCF_ERROR_NOT_SET:
17469 				continue;
17470 
17471 			case SCF_ERROR_CONNECTION_BROKEN:
17472 				r = scferror2errno(scf_error());
17473 				goto out;
17474 
17475 			case SCF_ERROR_HANDLE_MISMATCH:
17476 			case SCF_ERROR_NOT_BOUND:
17477 			default:
17478 				bad_error("scf_property_get_value",
17479 				    scf_error());
17480 			}
17481 		}
17482 
17483 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17484 		    == -1) {
17485 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17486 			    pgname, scf_strerror(scf_error()));
17487 
17488 			switch (scf_error()) {
17489 			case SCF_ERROR_NOT_SET:
17490 			case SCF_ERROR_TYPE_MISMATCH:
17491 				continue;
17492 
17493 			default:
17494 				bad_error("scf_value_get_astring", scf_error());
17495 			}
17496 		}
17497 
17498 		if (access(mfile, F_OK) == 0)
17499 			continue;
17500 
17501 		(void) scf_pg_delete(pg);
17502 	}
17503 
17504 out:
17505 	scf_scope_destroy(scope);
17506 	scf_service_destroy(svc);
17507 	scf_pg_destroy(pg);
17508 	scf_property_destroy(prop);
17509 	scf_value_destroy(val);
17510 	scf_iter_destroy(iter);
17511 	free(pgname);
17512 	free(mfile);
17513 
17514 	return (0);
17515 }
17516 
17517 #ifndef NATIVE_BUILD
17518 /* ARGSUSED */
17519 CPL_MATCH_FN(complete_select)
17520 {
17521 	const char *arg0, *arg1, *arg1end;
17522 	int word_start, err = 0, r;
17523 	size_t len;
17524 	char *buf;
17525 
17526 	lscf_prep_hndl();
17527 
17528 	arg0 = line + strspn(line, " \t");
17529 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17530 
17531 	arg1 = arg0 + sizeof ("select") - 1;
17532 	arg1 += strspn(arg1, " \t");
17533 	word_start = arg1 - line;
17534 
17535 	arg1end = arg1 + strcspn(arg1, " \t");
17536 	if (arg1end < line + word_end)
17537 		return (0);
17538 
17539 	len = line + word_end - arg1;
17540 
17541 	buf = safe_malloc(max_scf_name_len + 1);
17542 
17543 	if (cur_snap != NULL) {
17544 		return (0);
17545 	} else if (cur_inst != NULL) {
17546 		return (0);
17547 	} else if (cur_svc != NULL) {
17548 		scf_instance_t *inst;
17549 		scf_iter_t *iter;
17550 
17551 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17552 		    (iter = scf_iter_create(g_hndl)) == NULL)
17553 			scfdie();
17554 
17555 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17556 			scfdie();
17557 
17558 		for (;;) {
17559 			r = scf_iter_next_instance(iter, inst);
17560 			if (r == 0)
17561 				break;
17562 			if (r != 1)
17563 				scfdie();
17564 
17565 			if (scf_instance_get_name(inst, buf,
17566 			    max_scf_name_len + 1) < 0)
17567 				scfdie();
17568 
17569 			if (strncmp(buf, arg1, len) == 0) {
17570 				err = cpl_add_completion(cpl, line, word_start,
17571 				    word_end, buf + len, "", " ");
17572 				if (err != 0)
17573 					break;
17574 			}
17575 		}
17576 
17577 		scf_iter_destroy(iter);
17578 		scf_instance_destroy(inst);
17579 
17580 		return (err);
17581 	} else {
17582 		scf_service_t *svc;
17583 		scf_iter_t *iter;
17584 
17585 		assert(cur_scope != NULL);
17586 
17587 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17588 		    (iter = scf_iter_create(g_hndl)) == NULL)
17589 			scfdie();
17590 
17591 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17592 			scfdie();
17593 
17594 		for (;;) {
17595 			r = scf_iter_next_service(iter, svc);
17596 			if (r == 0)
17597 				break;
17598 			if (r != 1)
17599 				scfdie();
17600 
17601 			if (scf_service_get_name(svc, buf,
17602 			    max_scf_name_len + 1) < 0)
17603 				scfdie();
17604 
17605 			if (strncmp(buf, arg1, len) == 0) {
17606 				err = cpl_add_completion(cpl, line, word_start,
17607 				    word_end, buf + len, "", " ");
17608 				if (err != 0)
17609 					break;
17610 			}
17611 		}
17612 
17613 		scf_iter_destroy(iter);
17614 		scf_service_destroy(svc);
17615 
17616 		return (err);
17617 	}
17618 }
17619 
17620 /* ARGSUSED */
17621 CPL_MATCH_FN(complete_command)
17622 {
17623 	uint32_t scope = 0;
17624 
17625 	if (cur_snap != NULL)
17626 		scope = CS_SNAP;
17627 	else if (cur_inst != NULL)
17628 		scope = CS_INST;
17629 	else if (cur_svc != NULL)
17630 		scope = CS_SVC;
17631 	else
17632 		scope = CS_SCOPE;
17633 
17634 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17635 }
17636 #endif	/* NATIVE_BUILD */
17637