xref: /illumos-gate/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision 2d8dae53e7585d2412a48eceb751cbfaea048241)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2015 Joyent, Inc.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  * Copyright 2017 RackTop Systems.
27  */
28 
29 
30 #include <alloca.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <door.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <fnmatch.h>
37 #include <inttypes.h>
38 #include <libintl.h>
39 #include <libnvpair.h>
40 #include <libscf.h>
41 #include <libscf_priv.h>
42 #include <libtecla.h>
43 #include <libuutil.h>
44 #include <limits.h>
45 #include <locale.h>
46 #include <stdarg.h>
47 #include <string.h>
48 #include <strings.h>
49 #include <time.h>
50 #include <unistd.h>
51 #include <wait.h>
52 #include <poll.h>
53 
54 #include <libxml/tree.h>
55 
56 #include <sys/param.h>
57 
58 #include <sys/stat.h>
59 #include <sys/mman.h>
60 
61 #include "svccfg.h"
62 #include "notify_params.h"
63 #include "manifest_hash.h"
64 #include "manifest_find.h"
65 
66 /* The colon namespaces in each entity (each followed by a newline). */
67 #define	COLON_NAMESPACES	":properties\n"
68 
69 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
70 
71 /* These are characters which the lexer requires to be in double-quotes. */
72 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
73 
74 #define	HASH_SIZE		16
75 #define	HASH_PG_TYPE		"framework"
76 #define	HASH_PG_FLAGS		0
77 #define	HASH_PROP		"md5sum"
78 
79 /*
80  * Indentation used in the output of the describe subcommand.
81  */
82 #define	TMPL_VALUE_INDENT	"  "
83 #define	TMPL_INDENT		"    "
84 #define	TMPL_INDENT_2X		"        "
85 #define	TMPL_CHOICE_INDENT	"      "
86 
87 /*
88  * Directory locations for manifests
89  */
90 #define	VARSVC_DIR		"/var/svc/manifest"
91 #define	LIBSVC_DIR		"/lib/svc/manifest"
92 #define	VARSVC_PR		"var_svc_manifest"
93 #define	LIBSVC_PR		"lib_svc_manifest"
94 #define	MFSTFILEPR		"manifestfile"
95 
96 #define	SUPPORTPROP		"support"
97 
98 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
99 
100 #define	MFSTFILE_MAX		16
101 
102 /*
103  * These are the classes of elements which may appear as children of service
104  * or instance elements in XML manifests.
105  */
106 struct entity_elts {
107 	xmlNodePtr	create_default_instance;
108 	xmlNodePtr	single_instance;
109 	xmlNodePtr	restarter;
110 	xmlNodePtr	dependencies;
111 	xmlNodePtr	dependents;
112 	xmlNodePtr	method_context;
113 	xmlNodePtr	exec_methods;
114 	xmlNodePtr	notify_params;
115 	xmlNodePtr	property_groups;
116 	xmlNodePtr	instances;
117 	xmlNodePtr	stability;
118 	xmlNodePtr	template;
119 };
120 
121 /*
122  * Likewise for property_group elements.
123  */
124 struct pg_elts {
125 	xmlNodePtr	stability;
126 	xmlNodePtr	propvals;
127 	xmlNodePtr	properties;
128 };
129 
130 /*
131  * Likewise for template elements.
132  */
133 struct template_elts {
134 	xmlNodePtr	common_name;
135 	xmlNodePtr	description;
136 	xmlNodePtr	documentation;
137 };
138 
139 /*
140  * Likewise for type (for notification parameters) elements.
141  */
142 struct params_elts {
143 	xmlNodePtr	paramval;
144 	xmlNodePtr	parameter;
145 };
146 
147 /*
148  * This structure is for snaplevel lists.  They are convenient because libscf
149  * only allows traversing snaplevels in one direction.
150  */
151 struct snaplevel {
152 	uu_list_node_t	list_node;
153 	scf_snaplevel_t	*sl;
154 };
155 
156 /*
157  * This is used for communication between lscf_service_export and
158  * export_callback.
159  */
160 struct export_args {
161 	const char	*filename;
162 	int 		flags;
163 };
164 
165 /*
166  * The service_manifest structure is used by the upgrade process
167  * to create a list of service to manifest linkages from the manifests
168  * in a set of given directories.
169  */
170 typedef struct service_manifest {
171 	const char 	*servicename;
172 	uu_list_t	*mfstlist;
173 	size_t	mfstlist_sz;
174 
175 	uu_avl_node_t	svcmfst_node;
176 } service_manifest_t;
177 
178 /*
179  * Structure to track the manifest file property group
180  * and the manifest file associated with that property
181  * group.  Also, a flag to keep the access once it has
182  * been checked.
183  */
184 struct mpg_mfile {
185 	char	*mpg;
186 	char	*mfile;
187 	int	access;
188 };
189 
190 const char * const scf_pg_general = SCF_PG_GENERAL;
191 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
192 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
193 const char * const scf_property_external = "external";
194 
195 const char * const snap_initial = "initial";
196 const char * const snap_lastimport = "last-import";
197 const char * const snap_previous = "previous";
198 const char * const snap_running = "running";
199 
200 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
201 
202 ssize_t max_scf_fmri_len;
203 ssize_t max_scf_name_len;
204 ssize_t max_scf_pg_type_len;
205 ssize_t max_scf_value_len;
206 static size_t max_scf_len;
207 
208 static scf_scope_t *cur_scope;
209 static scf_service_t *cur_svc = NULL;
210 static scf_instance_t *cur_inst = NULL;
211 static scf_snapshot_t *cur_snap = NULL;
212 static scf_snaplevel_t *cur_level = NULL;
213 
214 static uu_list_pool_t *snaplevel_pool;
215 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
216 static uu_list_t *cur_levels;
217 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
218 
219 static FILE *tempfile = NULL;
220 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
221 
222 static const char *emsg_entity_not_selected;
223 static const char *emsg_permission_denied;
224 static const char *emsg_create_xml;
225 static const char *emsg_cant_modify_snapshots;
226 static const char *emsg_invalid_for_snapshot;
227 static const char *emsg_read_only;
228 static const char *emsg_deleted;
229 static const char *emsg_invalid_pg_name;
230 static const char *emsg_invalid_prop_name;
231 static const char *emsg_no_such_pg;
232 static const char *emsg_fmri_invalid_pg_name;
233 static const char *emsg_fmri_invalid_pg_name_type;
234 static const char *emsg_pg_added;
235 static const char *emsg_pg_changed;
236 static const char *emsg_pg_deleted;
237 static const char *emsg_pg_mod_perm;
238 static const char *emsg_pg_add_perm;
239 static const char *emsg_pg_del_perm;
240 static const char *emsg_snap_perm;
241 static const char *emsg_dpt_dangling;
242 static const char *emsg_dpt_no_dep;
243 
244 static int li_only = 0;
245 static int no_refresh = 0;
246 
247 /* how long in ns we should wait between checks for a pg */
248 static uint64_t pg_timeout = 100 * (NANOSEC / MILLISEC);
249 
250 /* import globals, to minimize allocations */
251 static scf_scope_t *imp_scope = NULL;
252 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
253 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
254 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
255 static scf_snapshot_t *imp_rsnap = NULL;
256 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
257 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
258 static scf_property_t *imp_prop = NULL;
259 static scf_iter_t *imp_iter = NULL;
260 static scf_iter_t *imp_rpg_iter = NULL;
261 static scf_iter_t *imp_up_iter = NULL;
262 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
263 static char *imp_str = NULL;
264 static size_t imp_str_sz;
265 static char *imp_tsname = NULL;
266 static char *imp_fe1 = NULL;		/* for fmri_equal() */
267 static char *imp_fe2 = NULL;
268 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
269 
270 /* upgrade_dependents() globals */
271 static scf_instance_t *ud_inst = NULL;
272 static scf_snaplevel_t *ud_snpl = NULL;
273 static scf_propertygroup_t *ud_pg = NULL;
274 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
275 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
276 static int ud_run_dpts_pg_set = 0;
277 static scf_property_t *ud_prop = NULL;
278 static scf_property_t *ud_dpt_prop = NULL;
279 static scf_value_t *ud_val = NULL;
280 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
281 static scf_transaction_t *ud_tx = NULL;
282 static char *ud_ctarg = NULL;
283 static char *ud_oldtarg = NULL;
284 static char *ud_name = NULL;
285 
286 /* export globals */
287 static scf_instance_t *exp_inst;
288 static scf_propertygroup_t *exp_pg;
289 static scf_property_t *exp_prop;
290 static scf_value_t *exp_val;
291 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
292 static char *exp_str;
293 static size_t exp_str_sz;
294 
295 /* cleanup globals */
296 static uu_avl_pool_t *service_manifest_pool = NULL;
297 static uu_avl_t *service_manifest_tree = NULL;
298 
299 static void scfdie_lineno(int lineno) __NORETURN;
300 
301 static char *start_method_names[] = {
302 	"start",
303 	"inetd_start",
304 	NULL
305 };
306 
307 static struct uri_scheme {
308 	const char *scheme;
309 	const char *protocol;
310 } uri_scheme[] = {
311 	{ "mailto", "smtp" },
312 	{ "snmp", "snmp" },
313 	{ "syslog", "syslog" },
314 	{ NULL, NULL }
315 };
316 #define	URI_SCHEME_NUM ((sizeof (uri_scheme) / \
317     sizeof (struct uri_scheme)) - 1)
318 
319 static int
320 check_uri_scheme(const char *scheme)
321 {
322 	int i;
323 
324 	for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
325 		if (strcmp(scheme, uri_scheme[i].scheme) == 0)
326 			return (i);
327 	}
328 
329 	return (-1);
330 }
331 
332 static int
333 check_uri_protocol(const char *p)
334 {
335 	int i;
336 
337 	for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
338 		if (strcmp(p, uri_scheme[i].protocol) == 0)
339 			return (i);
340 	}
341 
342 	return (-1);
343 }
344 
345 /*
346  * For unexpected libscf errors.
347  */
348 #ifdef NDEBUG
349 
350 static void scfdie(void) __NORETURN;
351 
352 static void
353 scfdie(void)
354 {
355 	scf_error_t err = scf_error();
356 
357 	if (err == SCF_ERROR_CONNECTION_BROKEN)
358 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
359 
360 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
361 	    scf_strerror(err));
362 }
363 
364 #else
365 
366 #define	scfdie()	scfdie_lineno(__LINE__)
367 
368 static void
369 scfdie_lineno(int lineno)
370 {
371 	scf_error_t err = scf_error();
372 
373 	if (err == SCF_ERROR_CONNECTION_BROKEN)
374 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
375 
376 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
377 	    ": %s.\n"), lineno, scf_strerror(err));
378 }
379 
380 #endif
381 
382 static void
383 scfwarn(void)
384 {
385 	warn(gettext("Unexpected libscf error: %s.\n"),
386 	    scf_strerror(scf_error()));
387 }
388 
389 /*
390  * Clear a field of a structure.
391  */
392 static int
393 clear_int(void *a, void *b)
394 {
395 	/* LINTED */
396 	*(int *)((char *)a + (size_t)b) = 0;
397 
398 	return (UU_WALK_NEXT);
399 }
400 
401 static int
402 scferror2errno(scf_error_t err)
403 {
404 	switch (err) {
405 	case SCF_ERROR_BACKEND_ACCESS:
406 		return (EACCES);
407 
408 	case SCF_ERROR_BACKEND_READONLY:
409 		return (EROFS);
410 
411 	case SCF_ERROR_CONNECTION_BROKEN:
412 		return (ECONNABORTED);
413 
414 	case SCF_ERROR_CONSTRAINT_VIOLATED:
415 	case SCF_ERROR_INVALID_ARGUMENT:
416 		return (EINVAL);
417 
418 	case SCF_ERROR_DELETED:
419 		return (ECANCELED);
420 
421 	case SCF_ERROR_EXISTS:
422 		return (EEXIST);
423 
424 	case SCF_ERROR_NO_MEMORY:
425 		return (ENOMEM);
426 
427 	case SCF_ERROR_NO_RESOURCES:
428 		return (ENOSPC);
429 
430 	case SCF_ERROR_NOT_FOUND:
431 		return (ENOENT);
432 
433 	case SCF_ERROR_PERMISSION_DENIED:
434 		return (EPERM);
435 
436 	default:
437 #ifndef NDEBUG
438 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
439 		    __FILE__, __LINE__, err);
440 #else
441 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
442 #endif
443 		abort();
444 		/* NOTREACHED */
445 	}
446 }
447 
448 static int
449 entity_get_pg(void *ent, int issvc, const char *name,
450     scf_propertygroup_t *pg)
451 {
452 	if (issvc)
453 		return (scf_service_get_pg(ent, name, pg));
454 	else
455 		return (scf_instance_get_pg(ent, name, pg));
456 }
457 
458 static void
459 entity_destroy(void *ent, int issvc)
460 {
461 	if (issvc)
462 		scf_service_destroy(ent);
463 	else
464 		scf_instance_destroy(ent);
465 }
466 
467 static int
468 get_pg(const char *pg_name, scf_propertygroup_t *pg)
469 {
470 	int ret;
471 
472 	if (cur_level != NULL)
473 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
474 	else if (cur_inst != NULL)
475 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
476 	else
477 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
478 
479 	return (ret);
480 }
481 
482 /*
483  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
484  * snaplevel.  Otherwise find the instance snaplevel.
485  *
486  * Returns
487  *   0 - success
488  *   ECONNABORTED - repository connection broken
489  *   ECANCELED - instance containing snap was deleted
490  *   ENOENT - snap has no snaplevels
491  *	    - requested snaplevel not found
492  */
493 static int
494 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
495 {
496 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
497 		switch (scf_error()) {
498 		case SCF_ERROR_CONNECTION_BROKEN:
499 		case SCF_ERROR_DELETED:
500 		case SCF_ERROR_NOT_FOUND:
501 			return (scferror2errno(scf_error()));
502 
503 		case SCF_ERROR_HANDLE_MISMATCH:
504 		case SCF_ERROR_NOT_BOUND:
505 		case SCF_ERROR_NOT_SET:
506 		default:
507 			bad_error("scf_snapshot_get_base_snaplevel",
508 			    scf_error());
509 		}
510 	}
511 
512 	for (;;) {
513 		ssize_t ssz;
514 
515 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
516 		if (ssz >= 0) {
517 			if (!get_svc)
518 				return (0);
519 		} else {
520 			switch (scf_error()) {
521 			case SCF_ERROR_CONSTRAINT_VIOLATED:
522 				if (get_svc)
523 					return (0);
524 				break;
525 
526 			case SCF_ERROR_DELETED:
527 			case SCF_ERROR_CONNECTION_BROKEN:
528 				return (scferror2errno(scf_error()));
529 
530 			case SCF_ERROR_NOT_SET:
531 			case SCF_ERROR_NOT_BOUND:
532 			default:
533 				bad_error("scf_snaplevel_get_instance_name",
534 				    scf_error());
535 			}
536 		}
537 
538 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
539 			switch (scf_error()) {
540 			case SCF_ERROR_NOT_FOUND:
541 			case SCF_ERROR_CONNECTION_BROKEN:
542 			case SCF_ERROR_DELETED:
543 				return (scferror2errno(scf_error()));
544 
545 			case SCF_ERROR_HANDLE_MISMATCH:
546 			case SCF_ERROR_NOT_BOUND:
547 			case SCF_ERROR_NOT_SET:
548 			case SCF_ERROR_INVALID_ARGUMENT:
549 			default:
550 				bad_error("scf_snaplevel_get_next_snaplevel",
551 				    scf_error());
552 			}
553 		}
554 	}
555 }
556 
557 /*
558  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
559  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
560  * the property group named name in it.  If it doesn't have a running
561  * snapshot, set pg to the instance's current property group named name.
562  *
563  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
564  * its instances.  If one has a running snapshot with a service snaplevel, set
565  * pg to the property group named name in it.  If no such snaplevel could be
566  * found, set pg to the service's current property group named name.
567  *
568  * iter, inst, snap, and snpl are required scratch objects.
569  *
570  * Returns
571  *   0 - success
572  *   ECONNABORTED - repository connection broken
573  *   ECANCELED - ent was deleted
574  *   ENOENT - no such property group
575  *   EINVAL - name is an invalid property group name
576  *   EBADF - found running snapshot is missing a snaplevel
577  */
578 static int
579 entity_get_running_pg(void *ent, int issvc, const char *name,
580     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
581     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
582 {
583 	int r;
584 
585 	if (issvc) {
586 		/* Search for an instance with a running snapshot. */
587 		if (scf_iter_service_instances(iter, ent) != 0) {
588 			switch (scf_error()) {
589 			case SCF_ERROR_DELETED:
590 			case SCF_ERROR_CONNECTION_BROKEN:
591 				return (scferror2errno(scf_error()));
592 
593 			case SCF_ERROR_NOT_SET:
594 			case SCF_ERROR_NOT_BOUND:
595 			case SCF_ERROR_HANDLE_MISMATCH:
596 			default:
597 				bad_error("scf_iter_service_instances",
598 				    scf_error());
599 			}
600 		}
601 
602 		for (;;) {
603 			r = scf_iter_next_instance(iter, inst);
604 			if (r == 0) {
605 				if (scf_service_get_pg(ent, name, pg) == 0)
606 					return (0);
607 
608 				switch (scf_error()) {
609 				case SCF_ERROR_DELETED:
610 				case SCF_ERROR_NOT_FOUND:
611 				case SCF_ERROR_INVALID_ARGUMENT:
612 				case SCF_ERROR_CONNECTION_BROKEN:
613 					return (scferror2errno(scf_error()));
614 
615 				case SCF_ERROR_NOT_BOUND:
616 				case SCF_ERROR_HANDLE_MISMATCH:
617 				case SCF_ERROR_NOT_SET:
618 				default:
619 					bad_error("scf_service_get_pg",
620 					    scf_error());
621 				}
622 			}
623 			if (r != 1) {
624 				switch (scf_error()) {
625 				case SCF_ERROR_DELETED:
626 				case SCF_ERROR_CONNECTION_BROKEN:
627 					return (scferror2errno(scf_error()));
628 
629 				case SCF_ERROR_INVALID_ARGUMENT:
630 				case SCF_ERROR_NOT_SET:
631 				case SCF_ERROR_NOT_BOUND:
632 				case SCF_ERROR_HANDLE_MISMATCH:
633 				default:
634 					bad_error("scf_iter_next_instance",
635 					    scf_error());
636 				}
637 			}
638 
639 			if (scf_instance_get_snapshot(inst, snap_running,
640 			    snap) == 0)
641 				break;
642 
643 			switch (scf_error()) {
644 			case SCF_ERROR_NOT_FOUND:
645 			case SCF_ERROR_DELETED:
646 				continue;
647 
648 			case SCF_ERROR_CONNECTION_BROKEN:
649 				return (ECONNABORTED);
650 
651 			case SCF_ERROR_HANDLE_MISMATCH:
652 			case SCF_ERROR_INVALID_ARGUMENT:
653 			case SCF_ERROR_NOT_SET:
654 			case SCF_ERROR_NOT_BOUND:
655 			default:
656 				bad_error("scf_instance_get_snapshot",
657 				    scf_error());
658 			}
659 		}
660 	} else {
661 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
662 			switch (scf_error()) {
663 			case SCF_ERROR_NOT_FOUND:
664 				break;
665 
666 			case SCF_ERROR_DELETED:
667 			case SCF_ERROR_CONNECTION_BROKEN:
668 				return (scferror2errno(scf_error()));
669 
670 			case SCF_ERROR_NOT_BOUND:
671 			case SCF_ERROR_HANDLE_MISMATCH:
672 			case SCF_ERROR_INVALID_ARGUMENT:
673 			case SCF_ERROR_NOT_SET:
674 			default:
675 				bad_error("scf_instance_get_snapshot",
676 				    scf_error());
677 			}
678 
679 			if (scf_instance_get_pg(ent, name, pg) == 0)
680 				return (0);
681 
682 			switch (scf_error()) {
683 			case SCF_ERROR_DELETED:
684 			case SCF_ERROR_NOT_FOUND:
685 			case SCF_ERROR_INVALID_ARGUMENT:
686 			case SCF_ERROR_CONNECTION_BROKEN:
687 				return (scferror2errno(scf_error()));
688 
689 			case SCF_ERROR_NOT_BOUND:
690 			case SCF_ERROR_HANDLE_MISMATCH:
691 			case SCF_ERROR_NOT_SET:
692 			default:
693 				bad_error("scf_instance_get_pg", scf_error());
694 			}
695 		}
696 	}
697 
698 	r = get_snaplevel(snap, issvc, snpl);
699 	switch (r) {
700 	case 0:
701 		break;
702 
703 	case ECONNABORTED:
704 	case ECANCELED:
705 		return (r);
706 
707 	case ENOENT:
708 		return (EBADF);
709 
710 	default:
711 		bad_error("get_snaplevel", r);
712 	}
713 
714 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
715 		return (0);
716 
717 	switch (scf_error()) {
718 	case SCF_ERROR_DELETED:
719 	case SCF_ERROR_INVALID_ARGUMENT:
720 	case SCF_ERROR_CONNECTION_BROKEN:
721 	case SCF_ERROR_NOT_FOUND:
722 		return (scferror2errno(scf_error()));
723 
724 	case SCF_ERROR_NOT_BOUND:
725 	case SCF_ERROR_HANDLE_MISMATCH:
726 	case SCF_ERROR_NOT_SET:
727 	default:
728 		bad_error("scf_snaplevel_get_pg", scf_error());
729 		/* NOTREACHED */
730 	}
731 }
732 
733 /*
734  * To be registered with atexit().
735  */
736 static void
737 remove_tempfile(void)
738 {
739 	int ret;
740 
741 	if (tempfile != NULL) {
742 		if (fclose(tempfile) == EOF)
743 			(void) warn(gettext("Could not close temporary file"));
744 		tempfile = NULL;
745 	}
746 
747 	if (tempfilename[0] != '\0') {
748 		do {
749 			ret = remove(tempfilename);
750 		} while (ret == -1 && errno == EINTR);
751 		if (ret == -1)
752 			warn(gettext("Could not remove temporary file"));
753 		tempfilename[0] = '\0';
754 	}
755 }
756 
757 /*
758  * Launch private svc.configd(1M) for manipulating alternate repositories.
759  */
760 static void
761 start_private_repository(engine_state_t *est)
762 {
763 	int fd, stat;
764 	struct door_info info;
765 	pid_t pid;
766 
767 	/*
768 	 * 1.  Create a temporary file for the door.
769 	 */
770 	if (est->sc_repo_doorname != NULL)
771 		free((void *)est->sc_repo_doorname);
772 
773 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
774 	if (est->sc_repo_doorname == NULL)
775 		uu_die(gettext("Could not acquire temporary filename"));
776 
777 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
778 	if (fd < 0)
779 		uu_die(gettext("Could not create temporary file for "
780 		    "repository server"));
781 
782 	(void) close(fd);
783 
784 	/*
785 	 * 2.  Launch a configd with that door, using the specified
786 	 * repository.
787 	 */
788 	if ((est->sc_repo_pid = fork()) == 0) {
789 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
790 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
791 		    NULL);
792 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
793 	} else if (est->sc_repo_pid == -1)
794 		uu_die(gettext("Attempt to fork failed"));
795 
796 	do {
797 		pid = waitpid(est->sc_repo_pid, &stat, 0);
798 	} while (pid == -1 && errno == EINTR);
799 
800 	if (pid == -1)
801 		uu_die(gettext("Could not waitpid() for repository server"));
802 
803 	if (!WIFEXITED(stat)) {
804 		uu_die(gettext("Repository server failed (status %d).\n"),
805 		    stat);
806 	} else if (WEXITSTATUS(stat) != 0) {
807 		uu_die(gettext("Repository server failed (exit %d).\n"),
808 		    WEXITSTATUS(stat));
809 	}
810 
811 	/*
812 	 * See if it was successful by checking if the door is a door.
813 	 */
814 
815 	fd = open(est->sc_repo_doorname, O_RDWR);
816 	if (fd < 0)
817 		uu_die(gettext("Could not open door \"%s\""),
818 		    est->sc_repo_doorname);
819 
820 	if (door_info(fd, &info) < 0)
821 		uu_die(gettext("Unexpected door_info() error"));
822 
823 	if (close(fd) == -1)
824 		warn(gettext("Could not close repository door"),
825 		    strerror(errno));
826 
827 	est->sc_repo_pid = info.di_target;
828 }
829 
830 void
831 lscf_cleanup(void)
832 {
833 	/*
834 	 * In the case where we've launched a private svc.configd(1M)
835 	 * instance, we must terminate our child and remove the temporary
836 	 * rendezvous point.
837 	 */
838 	if (est->sc_repo_pid > 0) {
839 		(void) kill(est->sc_repo_pid, SIGTERM);
840 		(void) waitpid(est->sc_repo_pid, NULL, 0);
841 		(void) unlink(est->sc_repo_doorname);
842 
843 		est->sc_repo_pid = 0;
844 	}
845 }
846 
847 void
848 unselect_cursnap(void)
849 {
850 	void *cookie;
851 
852 	cur_level = NULL;
853 
854 	cookie = NULL;
855 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
856 		scf_snaplevel_destroy(cur_elt->sl);
857 		free(cur_elt);
858 	}
859 
860 	scf_snapshot_destroy(cur_snap);
861 	cur_snap = NULL;
862 }
863 
864 void
865 lscf_prep_hndl(void)
866 {
867 	if (g_hndl != NULL)
868 		return;
869 
870 	g_hndl = scf_handle_create(SCF_VERSION);
871 	if (g_hndl == NULL)
872 		scfdie();
873 
874 	if (est->sc_repo_filename != NULL)
875 		start_private_repository(est);
876 
877 	if (est->sc_repo_doorname != NULL) {
878 		scf_value_t *repo_value;
879 		int ret;
880 
881 		repo_value = scf_value_create(g_hndl);
882 		if (repo_value == NULL)
883 			scfdie();
884 
885 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
886 		assert(ret == SCF_SUCCESS);
887 
888 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
889 		    SCF_SUCCESS)
890 			scfdie();
891 
892 		scf_value_destroy(repo_value);
893 	}
894 
895 	if (scf_handle_bind(g_hndl) != 0)
896 		uu_die(gettext("Could not connect to repository server: %s.\n"),
897 		    scf_strerror(scf_error()));
898 
899 	cur_scope = scf_scope_create(g_hndl);
900 	if (cur_scope == NULL)
901 		scfdie();
902 
903 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
904 		scfdie();
905 }
906 
907 static void
908 repository_teardown(void)
909 {
910 	if (g_hndl != NULL) {
911 		if (cur_snap != NULL)
912 			unselect_cursnap();
913 		scf_instance_destroy(cur_inst);
914 		scf_service_destroy(cur_svc);
915 		scf_scope_destroy(cur_scope);
916 		scf_handle_destroy(g_hndl);
917 		cur_inst = NULL;
918 		cur_svc = NULL;
919 		cur_scope = NULL;
920 		g_hndl = NULL;
921 		lscf_cleanup();
922 	}
923 }
924 
925 void
926 lscf_set_repository(const char *repfile, int force)
927 {
928 	repository_teardown();
929 
930 	if (est->sc_repo_filename != NULL) {
931 		free((void *)est->sc_repo_filename);
932 		est->sc_repo_filename = NULL;
933 	}
934 
935 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
936 		/*
937 		 * Repository file does not exist
938 		 * or has no read permission.
939 		 */
940 		warn(gettext("Cannot access \"%s\": %s\n"),
941 		    repfile, strerror(errno));
942 	} else {
943 		est->sc_repo_filename = safe_strdup(repfile);
944 	}
945 
946 	lscf_prep_hndl();
947 }
948 
949 void
950 lscf_init()
951 {
952 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
953 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
954 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
955 	    0 ||
956 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
957 		scfdie();
958 
959 	max_scf_len = max_scf_fmri_len;
960 	if (max_scf_name_len > max_scf_len)
961 		max_scf_len = max_scf_name_len;
962 	if (max_scf_pg_type_len > max_scf_len)
963 		max_scf_len = max_scf_pg_type_len;
964 	/*
965 	 * When a value of type opaque is represented as a string, the
966 	 * string contains 2 characters for every byte of data.  That is
967 	 * because the string contains the hex representation of the opaque
968 	 * value.
969 	 */
970 	if (2 * max_scf_value_len > max_scf_len)
971 		max_scf_len = 2 * max_scf_value_len;
972 
973 	if (atexit(remove_tempfile) != 0)
974 		uu_die(gettext("Could not register atexit() function"));
975 
976 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
977 	emsg_permission_denied = gettext("Permission denied.\n");
978 	emsg_create_xml = gettext("Could not create XML node.\n");
979 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
980 	emsg_invalid_for_snapshot =
981 	    gettext("Invalid operation on a snapshot.\n");
982 	emsg_read_only = gettext("Backend read-only.\n");
983 	emsg_deleted = gettext("Current selection has been deleted.\n");
984 	emsg_invalid_pg_name =
985 	    gettext("Invalid property group name \"%s\".\n");
986 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
987 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
988 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
989 	    "with invalid name \"%s\".\n");
990 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
991 	    "group with invalid name \"%s\" or type \"%s\".\n");
992 	emsg_pg_added = gettext("%s changed unexpectedly "
993 	    "(property group \"%s\" added).\n");
994 	emsg_pg_changed = gettext("%s changed unexpectedly "
995 	    "(property group \"%s\" changed).\n");
996 	emsg_pg_deleted = gettext("%s changed unexpectedly "
997 	    "(property group \"%s\" or an ancestor was deleted).\n");
998 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
999 	    "in %s (permission denied).\n");
1000 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
1001 	    "in %s (permission denied).\n");
1002 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
1003 	    "in %s (permission denied).\n");
1004 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
1005 	    "(permission denied).\n");
1006 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1007 	    "new dependent \"%s\" because it already exists).  Warning: The "
1008 	    "current dependent's target (%s) does not exist.\n");
1009 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1010 	    "dependent \"%s\" because it already exists).  Warning: The "
1011 	    "current dependent's target (%s) does not have a dependency named "
1012 	    "\"%s\" as expected.\n");
1013 
1014 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1015 	    offsetof(string_list_t, node), NULL, 0);
1016 	snaplevel_pool = uu_list_pool_create("snaplevels",
1017 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1018 	    NULL, 0);
1019 }
1020 
1021 
1022 static const char *
1023 prop_to_typestr(const scf_property_t *prop)
1024 {
1025 	scf_type_t ty;
1026 
1027 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1028 		scfdie();
1029 
1030 	return (scf_type_to_string(ty));
1031 }
1032 
1033 static scf_type_t
1034 string_to_type(const char *type)
1035 {
1036 	size_t len = strlen(type);
1037 	char *buf;
1038 
1039 	if (len == 0 || type[len - 1] != ':')
1040 		return (SCF_TYPE_INVALID);
1041 
1042 	buf = (char *)alloca(len + 1);
1043 	(void) strlcpy(buf, type, len + 1);
1044 	buf[len - 1] = 0;
1045 
1046 	return (scf_string_to_type(buf));
1047 }
1048 
1049 static scf_value_t *
1050 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1051 {
1052 	scf_value_t *v;
1053 	char *dup, *nstr;
1054 	size_t len;
1055 
1056 	v = scf_value_create(g_hndl);
1057 	if (v == NULL)
1058 		scfdie();
1059 
1060 	len = strlen(str);
1061 	if (require_quotes &&
1062 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1063 		semerr(gettext("Multiple string values or string values "
1064 		    "with spaces must be quoted with '\"'.\n"));
1065 		scf_value_destroy(v);
1066 		return (NULL);
1067 	}
1068 
1069 	nstr = dup = safe_strdup(str);
1070 	if (dup[0] == '\"') {
1071 		/*
1072 		 * Strip out the first and the last quote.
1073 		 */
1074 		dup[len - 1] = '\0';
1075 		nstr = dup + 1;
1076 	}
1077 
1078 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1079 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1080 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1081 		    scf_type_to_string(ty), nstr);
1082 		scf_value_destroy(v);
1083 		v = NULL;
1084 	}
1085 	free(dup);
1086 	return (v);
1087 }
1088 
1089 /*
1090  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1091  * Optionally append a comment prefix ('#') to newlines ('\n').
1092  */
1093 static int
1094 quote_and_print(const char *str, FILE *strm, int commentnl)
1095 {
1096 	const char *cp;
1097 
1098 	for (cp = str; *cp != '\0'; ++cp) {
1099 		if (*cp == '"' || *cp == '\\')
1100 			(void) putc('\\', strm);
1101 
1102 		(void) putc(*cp, strm);
1103 
1104 		if (commentnl && *cp == '\n') {
1105 			(void) putc('#', strm);
1106 		}
1107 	}
1108 
1109 	return (ferror(strm));
1110 }
1111 
1112 /*
1113  * These wrappers around lowlevel functions provide consistent error checking
1114  * and warnings.
1115  */
1116 static int
1117 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1118 {
1119 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1120 		return (0);
1121 
1122 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1123 		scfdie();
1124 
1125 	if (g_verbose) {
1126 		ssize_t len;
1127 		char *fmri;
1128 
1129 		len = scf_pg_to_fmri(pg, NULL, 0);
1130 		if (len < 0)
1131 			scfdie();
1132 
1133 		fmri = safe_malloc(len + 1);
1134 
1135 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1136 			scfdie();
1137 
1138 		warn(gettext("Expected property %s of property group %s is "
1139 		    "missing.\n"), propname, fmri);
1140 
1141 		free(fmri);
1142 	}
1143 
1144 	return (-1);
1145 }
1146 
1147 static int
1148 prop_check_type(scf_property_t *prop, scf_type_t ty)
1149 {
1150 	scf_type_t pty;
1151 
1152 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1153 		scfdie();
1154 
1155 	if (ty == pty)
1156 		return (0);
1157 
1158 	if (g_verbose) {
1159 		ssize_t len;
1160 		char *fmri;
1161 		const char *tystr;
1162 
1163 		len = scf_property_to_fmri(prop, NULL, 0);
1164 		if (len < 0)
1165 			scfdie();
1166 
1167 		fmri = safe_malloc(len + 1);
1168 
1169 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1170 			scfdie();
1171 
1172 		tystr = scf_type_to_string(ty);
1173 		if (tystr == NULL)
1174 			tystr = "?";
1175 
1176 		warn(gettext("Property %s is not of expected type %s.\n"),
1177 		    fmri, tystr);
1178 
1179 		free(fmri);
1180 	}
1181 
1182 	return (-1);
1183 }
1184 
1185 static int
1186 prop_get_val(scf_property_t *prop, scf_value_t *val)
1187 {
1188 	scf_error_t err;
1189 
1190 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1191 		return (0);
1192 
1193 	err = scf_error();
1194 
1195 	if (err != SCF_ERROR_NOT_FOUND &&
1196 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1197 	    err != SCF_ERROR_PERMISSION_DENIED)
1198 		scfdie();
1199 
1200 	if (g_verbose) {
1201 		ssize_t len;
1202 		char *fmri, *emsg;
1203 
1204 		len = scf_property_to_fmri(prop, NULL, 0);
1205 		if (len < 0)
1206 			scfdie();
1207 
1208 		fmri = safe_malloc(len + 1);
1209 
1210 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1211 			scfdie();
1212 
1213 		if (err == SCF_ERROR_NOT_FOUND)
1214 			emsg = gettext("Property %s has no values; expected "
1215 			    "one.\n");
1216 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1217 			emsg = gettext("Property %s has multiple values; "
1218 			    "expected one.\n");
1219 		else
1220 			emsg = gettext("No permission to read property %s.\n");
1221 
1222 		warn(emsg, fmri);
1223 
1224 		free(fmri);
1225 	}
1226 
1227 	return (-1);
1228 }
1229 
1230 
1231 static boolean_t
1232 snaplevel_is_instance(const scf_snaplevel_t *level)
1233 {
1234 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1235 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1236 			scfdie();
1237 		return (0);
1238 	} else {
1239 		return (1);
1240 	}
1241 }
1242 
1243 /*
1244  * Decode FMRI into a service or instance, and put the result in *ep.  If
1245  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1246  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1247  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1248  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1249  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1250  * whether *ep is a service.
1251  */
1252 static scf_error_t
1253 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1254 {
1255 	char *fmri_copy;
1256 	const char *sstr, *istr, *pgstr;
1257 	scf_service_t *svc;
1258 	scf_instance_t *inst;
1259 
1260 	fmri_copy = strdup(fmri);
1261 	if (fmri_copy == NULL)
1262 		return (SCF_ERROR_NO_MEMORY);
1263 
1264 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1265 	    SCF_SUCCESS) {
1266 		free(fmri_copy);
1267 		return (SCF_ERROR_INVALID_ARGUMENT);
1268 	}
1269 
1270 	free(fmri_copy);
1271 
1272 	if (sstr == NULL || pgstr != NULL)
1273 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1274 
1275 	if (istr == NULL) {
1276 		svc = scf_service_create(h);
1277 		if (svc == NULL)
1278 			return (SCF_ERROR_NO_MEMORY);
1279 
1280 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1281 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1282 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1283 				scfdie();
1284 
1285 			return (SCF_ERROR_NOT_FOUND);
1286 		}
1287 
1288 		*ep = svc;
1289 		*isservice = 1;
1290 	} else {
1291 		inst = scf_instance_create(h);
1292 		if (inst == NULL)
1293 			return (SCF_ERROR_NO_MEMORY);
1294 
1295 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1296 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1297 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1298 				scfdie();
1299 
1300 			return (SCF_ERROR_NOT_FOUND);
1301 		}
1302 
1303 		*ep = inst;
1304 		*isservice = 0;
1305 	}
1306 
1307 	return (SCF_ERROR_NONE);
1308 }
1309 
1310 /*
1311  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1312  * *ep, and set or clear *isservicep if it is a service or an instance.
1313  * Returns
1314  *   SCF_ERROR_NONE - success
1315  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1316  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1317  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1318  *   SCF_ERROR_NOT_FOUND - no such scope
1319  *   SCF_ERROR_PERMISSION_DENIED
1320  *   SCF_ERROR_BACKEND_READONLY
1321  *   SCF_ERROR_BACKEND_ACCESS
1322  */
1323 static scf_error_t
1324 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1325 {
1326 	char *fmri_copy;
1327 	const char *scstr, *sstr, *istr, *pgstr;
1328 	scf_scope_t *scope = NULL;
1329 	scf_service_t *svc = NULL;
1330 	scf_instance_t *inst = NULL;
1331 	scf_error_t scfe;
1332 
1333 	fmri_copy = safe_strdup(fmri);
1334 
1335 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1336 	    0) {
1337 		free(fmri_copy);
1338 		return (SCF_ERROR_INVALID_ARGUMENT);
1339 	}
1340 
1341 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1342 		free(fmri_copy);
1343 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1344 	}
1345 
1346 	*ep = NULL;
1347 
1348 	if ((scope = scf_scope_create(h)) == NULL ||
1349 	    (svc = scf_service_create(h)) == NULL ||
1350 	    (inst = scf_instance_create(h)) == NULL) {
1351 		scfe = SCF_ERROR_NO_MEMORY;
1352 		goto out;
1353 	}
1354 
1355 get_scope:
1356 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1357 		switch (scf_error()) {
1358 		case SCF_ERROR_CONNECTION_BROKEN:
1359 			scfdie();
1360 			/* NOTREACHED */
1361 
1362 		case SCF_ERROR_NOT_FOUND:
1363 			scfe = SCF_ERROR_NOT_FOUND;
1364 			goto out;
1365 
1366 		case SCF_ERROR_HANDLE_MISMATCH:
1367 		case SCF_ERROR_NOT_BOUND:
1368 		case SCF_ERROR_INVALID_ARGUMENT:
1369 		default:
1370 			bad_error("scf_handle_get_scope", scf_error());
1371 		}
1372 	}
1373 
1374 get_svc:
1375 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1376 		switch (scf_error()) {
1377 		case SCF_ERROR_CONNECTION_BROKEN:
1378 			scfdie();
1379 			/* NOTREACHED */
1380 
1381 		case SCF_ERROR_DELETED:
1382 			goto get_scope;
1383 
1384 		case SCF_ERROR_NOT_FOUND:
1385 			break;
1386 
1387 		case SCF_ERROR_HANDLE_MISMATCH:
1388 		case SCF_ERROR_INVALID_ARGUMENT:
1389 		case SCF_ERROR_NOT_BOUND:
1390 		case SCF_ERROR_NOT_SET:
1391 		default:
1392 			bad_error("scf_scope_get_service", scf_error());
1393 		}
1394 
1395 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1396 			switch (scf_error()) {
1397 			case SCF_ERROR_CONNECTION_BROKEN:
1398 				scfdie();
1399 				/* NOTREACHED */
1400 
1401 			case SCF_ERROR_DELETED:
1402 				goto get_scope;
1403 
1404 			case SCF_ERROR_PERMISSION_DENIED:
1405 			case SCF_ERROR_BACKEND_READONLY:
1406 			case SCF_ERROR_BACKEND_ACCESS:
1407 				scfe = scf_error();
1408 				goto out;
1409 
1410 			case SCF_ERROR_HANDLE_MISMATCH:
1411 			case SCF_ERROR_INVALID_ARGUMENT:
1412 			case SCF_ERROR_NOT_BOUND:
1413 			case SCF_ERROR_NOT_SET:
1414 			default:
1415 				bad_error("scf_scope_get_service", scf_error());
1416 			}
1417 		}
1418 	}
1419 
1420 	if (istr == NULL) {
1421 		scfe = SCF_ERROR_NONE;
1422 		*ep = svc;
1423 		*isservicep = 1;
1424 		goto out;
1425 	}
1426 
1427 get_inst:
1428 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1429 		switch (scf_error()) {
1430 		case SCF_ERROR_CONNECTION_BROKEN:
1431 			scfdie();
1432 			/* NOTREACHED */
1433 
1434 		case SCF_ERROR_DELETED:
1435 			goto get_svc;
1436 
1437 		case SCF_ERROR_NOT_FOUND:
1438 			break;
1439 
1440 		case SCF_ERROR_HANDLE_MISMATCH:
1441 		case SCF_ERROR_INVALID_ARGUMENT:
1442 		case SCF_ERROR_NOT_BOUND:
1443 		case SCF_ERROR_NOT_SET:
1444 		default:
1445 			bad_error("scf_service_get_instance", scf_error());
1446 		}
1447 
1448 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1449 			switch (scf_error()) {
1450 			case SCF_ERROR_CONNECTION_BROKEN:
1451 				scfdie();
1452 				/* NOTREACHED */
1453 
1454 			case SCF_ERROR_DELETED:
1455 				goto get_svc;
1456 
1457 			case SCF_ERROR_PERMISSION_DENIED:
1458 			case SCF_ERROR_BACKEND_READONLY:
1459 			case SCF_ERROR_BACKEND_ACCESS:
1460 				scfe = scf_error();
1461 				goto out;
1462 
1463 			case SCF_ERROR_HANDLE_MISMATCH:
1464 			case SCF_ERROR_INVALID_ARGUMENT:
1465 			case SCF_ERROR_NOT_BOUND:
1466 			case SCF_ERROR_NOT_SET:
1467 			default:
1468 				bad_error("scf_service_add_instance",
1469 				    scf_error());
1470 			}
1471 		}
1472 	}
1473 
1474 	scfe = SCF_ERROR_NONE;
1475 	*ep = inst;
1476 	*isservicep = 0;
1477 
1478 out:
1479 	if (*ep != inst)
1480 		scf_instance_destroy(inst);
1481 	if (*ep != svc)
1482 		scf_service_destroy(svc);
1483 	scf_scope_destroy(scope);
1484 	free(fmri_copy);
1485 	return (scfe);
1486 }
1487 
1488 /*
1489  * Create or update a snapshot of inst.  snap is a required scratch object.
1490  *
1491  * Returns
1492  *   0 - success
1493  *   ECONNABORTED - repository connection broken
1494  *   EPERM - permission denied
1495  *   ENOSPC - configd is out of resources
1496  *   ECANCELED - inst was deleted
1497  *   -1 - unknown libscf error (message printed)
1498  */
1499 static int
1500 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1501 {
1502 again:
1503 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1504 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1505 			switch (scf_error()) {
1506 			case SCF_ERROR_CONNECTION_BROKEN:
1507 			case SCF_ERROR_PERMISSION_DENIED:
1508 			case SCF_ERROR_NO_RESOURCES:
1509 				return (scferror2errno(scf_error()));
1510 
1511 			case SCF_ERROR_NOT_SET:
1512 			case SCF_ERROR_INVALID_ARGUMENT:
1513 			default:
1514 				bad_error("_scf_snapshot_take_attach",
1515 				    scf_error());
1516 			}
1517 		}
1518 	} else {
1519 		switch (scf_error()) {
1520 		case SCF_ERROR_NOT_FOUND:
1521 			break;
1522 
1523 		case SCF_ERROR_DELETED:
1524 		case SCF_ERROR_CONNECTION_BROKEN:
1525 			return (scferror2errno(scf_error()));
1526 
1527 		case SCF_ERROR_HANDLE_MISMATCH:
1528 		case SCF_ERROR_NOT_BOUND:
1529 		case SCF_ERROR_INVALID_ARGUMENT:
1530 		case SCF_ERROR_NOT_SET:
1531 		default:
1532 			bad_error("scf_instance_get_snapshot", scf_error());
1533 		}
1534 
1535 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1536 			switch (scf_error()) {
1537 			case SCF_ERROR_EXISTS:
1538 				goto again;
1539 
1540 			case SCF_ERROR_CONNECTION_BROKEN:
1541 			case SCF_ERROR_NO_RESOURCES:
1542 			case SCF_ERROR_PERMISSION_DENIED:
1543 				return (scferror2errno(scf_error()));
1544 
1545 			default:
1546 				scfwarn();
1547 				return (-1);
1548 
1549 			case SCF_ERROR_NOT_SET:
1550 			case SCF_ERROR_INTERNAL:
1551 			case SCF_ERROR_INVALID_ARGUMENT:
1552 			case SCF_ERROR_HANDLE_MISMATCH:
1553 				bad_error("_scf_snapshot_take_new",
1554 				    scf_error());
1555 			}
1556 		}
1557 	}
1558 
1559 	return (0);
1560 }
1561 
1562 static int
1563 refresh_running_snapshot(void *entity)
1564 {
1565 	scf_snapshot_t *snap;
1566 	int r;
1567 
1568 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1569 		scfdie();
1570 	r = take_snap(entity, snap_running, snap);
1571 	scf_snapshot_destroy(snap);
1572 
1573 	return (r);
1574 }
1575 
1576 /*
1577  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1578  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1579  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1580  * for scratch space.  Returns
1581  *   0 - success
1582  *   ECONNABORTED - repository connection broken
1583  *   ECANCELED - entity was deleted
1584  *   EACCES - backend denied access
1585  *   EPERM - permission denied
1586  *   ENOSPC - repository server out of resources
1587  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1588  */
1589 static int
1590 refresh_entity(int isservice, void *entity, const char *fmri,
1591     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1592 {
1593 	scf_error_t scfe;
1594 	int r;
1595 
1596 	if (!isservice) {
1597 		/*
1598 		 * Let restarter handles refreshing and making new running
1599 		 * snapshot only if operating on a live repository and not
1600 		 * running in early import.
1601 		 */
1602 		if (est->sc_repo_filename == NULL &&
1603 		    est->sc_repo_doorname == NULL &&
1604 		    est->sc_in_emi == 0) {
1605 			if (_smf_refresh_instance_i(entity) == 0) {
1606 				if (g_verbose)
1607 					warn(gettext("Refreshed %s.\n"), fmri);
1608 				return (0);
1609 			}
1610 
1611 			switch (scf_error()) {
1612 			case SCF_ERROR_BACKEND_ACCESS:
1613 				return (EACCES);
1614 
1615 			case SCF_ERROR_PERMISSION_DENIED:
1616 				return (EPERM);
1617 
1618 			default:
1619 				return (-1);
1620 			}
1621 		} else {
1622 			r = refresh_running_snapshot(entity);
1623 			switch (r) {
1624 			case 0:
1625 				break;
1626 
1627 			case ECONNABORTED:
1628 			case ECANCELED:
1629 			case EPERM:
1630 			case ENOSPC:
1631 				break;
1632 
1633 			default:
1634 				bad_error("refresh_running_snapshot",
1635 				    scf_error());
1636 			}
1637 
1638 			return (r);
1639 		}
1640 	}
1641 
1642 	if (scf_iter_service_instances(iter, entity) != 0) {
1643 		switch (scf_error()) {
1644 		case SCF_ERROR_CONNECTION_BROKEN:
1645 			return (ECONNABORTED);
1646 
1647 		case SCF_ERROR_DELETED:
1648 			return (ECANCELED);
1649 
1650 		case SCF_ERROR_HANDLE_MISMATCH:
1651 		case SCF_ERROR_NOT_BOUND:
1652 		case SCF_ERROR_NOT_SET:
1653 		default:
1654 			bad_error("scf_iter_service_instances", scf_error());
1655 		}
1656 	}
1657 
1658 	for (;;) {
1659 		r = scf_iter_next_instance(iter, inst);
1660 		if (r == 0)
1661 			break;
1662 		if (r != 1) {
1663 			switch (scf_error()) {
1664 			case SCF_ERROR_CONNECTION_BROKEN:
1665 				return (ECONNABORTED);
1666 
1667 			case SCF_ERROR_DELETED:
1668 				return (ECANCELED);
1669 
1670 			case SCF_ERROR_HANDLE_MISMATCH:
1671 			case SCF_ERROR_NOT_BOUND:
1672 			case SCF_ERROR_NOT_SET:
1673 			case SCF_ERROR_INVALID_ARGUMENT:
1674 			default:
1675 				bad_error("scf_iter_next_instance",
1676 				    scf_error());
1677 			}
1678 		}
1679 
1680 		/*
1681 		 * Similarly, just take a new running snapshot if operating on
1682 		 * a non-live repository or running during early import.
1683 		 */
1684 		if (est->sc_repo_filename != NULL ||
1685 		    est->sc_repo_doorname != NULL ||
1686 		    est->sc_in_emi == 1) {
1687 			r = refresh_running_snapshot(inst);
1688 			switch (r) {
1689 			case 0:
1690 				continue;
1691 
1692 			case ECONNABORTED:
1693 			case ECANCELED:
1694 			case EPERM:
1695 			case ENOSPC:
1696 				break;
1697 			default:
1698 				bad_error("refresh_running_snapshot",
1699 				    scf_error());
1700 			}
1701 
1702 			return (r);
1703 
1704 		}
1705 
1706 		if (_smf_refresh_instance_i(inst) == 0) {
1707 			if (g_verbose) {
1708 				if (scf_instance_get_name(inst, name_buf,
1709 				    max_scf_name_len + 1) < 0)
1710 					(void) strcpy(name_buf, "?");
1711 
1712 				warn(gettext("Refreshed %s:%s.\n"),
1713 				    fmri, name_buf);
1714 			}
1715 		} else {
1716 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1717 			    g_verbose) {
1718 				scfe = scf_error();
1719 
1720 				if (scf_instance_to_fmri(inst, name_buf,
1721 				    max_scf_name_len + 1) < 0)
1722 					(void) strcpy(name_buf, "?");
1723 
1724 				warn(gettext(
1725 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1726 				    name_buf, scf_strerror(scfe));
1727 			}
1728 		}
1729 	}
1730 
1731 	return (0);
1732 }
1733 
1734 static void
1735 private_refresh(void)
1736 {
1737 	scf_instance_t *pinst = NULL;
1738 	scf_iter_t *piter = NULL;
1739 	ssize_t fmrilen;
1740 	size_t bufsz;
1741 	char *fmribuf;
1742 	void *ent;
1743 	int issvc;
1744 	int r;
1745 
1746 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1747 		return;
1748 
1749 	assert(cur_svc != NULL);
1750 
1751 	bufsz = max_scf_fmri_len + 1;
1752 	fmribuf = safe_malloc(bufsz);
1753 	if (cur_inst) {
1754 		issvc = 0;
1755 		ent = cur_inst;
1756 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1757 	} else {
1758 		issvc = 1;
1759 		ent = cur_svc;
1760 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1761 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1762 			scfdie();
1763 
1764 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1765 			scfdie();
1766 	}
1767 	if (fmrilen < 0) {
1768 		free(fmribuf);
1769 		if (scf_error() != SCF_ERROR_DELETED)
1770 			scfdie();
1771 
1772 		warn(emsg_deleted);
1773 		return;
1774 	}
1775 	assert(fmrilen < bufsz);
1776 
1777 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1778 	switch (r) {
1779 	case 0:
1780 		break;
1781 
1782 	case ECONNABORTED:
1783 		warn(gettext("Could not refresh %s "
1784 		    "(repository connection broken).\n"), fmribuf);
1785 		break;
1786 
1787 	case ECANCELED:
1788 		warn(emsg_deleted);
1789 		break;
1790 
1791 	case EPERM:
1792 		warn(gettext("Could not refresh %s "
1793 		    "(permission denied).\n"), fmribuf);
1794 		break;
1795 
1796 	case ENOSPC:
1797 		warn(gettext("Could not refresh %s "
1798 		    "(repository server out of resources).\n"),
1799 		    fmribuf);
1800 		break;
1801 
1802 	case EACCES:
1803 	default:
1804 		bad_error("refresh_entity", scf_error());
1805 	}
1806 
1807 	if (issvc) {
1808 		scf_instance_destroy(pinst);
1809 		scf_iter_destroy(piter);
1810 	}
1811 
1812 	free(fmribuf);
1813 }
1814 
1815 
1816 static int
1817 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1818 {
1819 	cbp->sc_err = scferror2errno(err);
1820 	return (UU_WALK_ERROR);
1821 }
1822 
1823 static int
1824 stash_scferror(scf_callback_t *cbp)
1825 {
1826 	return (stash_scferror_err(cbp, scf_error()));
1827 }
1828 
1829 static int select_inst(const char *);
1830 static int select_svc(const char *);
1831 
1832 /*
1833  * Take a property that does not have a type and check to see if a type
1834  * exists or can be gleened from the current data.  Set the type.
1835  *
1836  * Check the current level (instance) and then check the higher level
1837  * (service).  This could be the case for adding a new property to
1838  * the instance that's going to "override" a service level property.
1839  *
1840  * For a property :
1841  * 1. Take the type from an existing property
1842  * 2. Take the type from a template entry
1843  *
1844  * If the type can not be found, then leave the type as is, and let the import
1845  * report the problem of the missing type.
1846  */
1847 static int
1848 find_current_prop_type(void *p, void *g)
1849 {
1850 	property_t *prop = p;
1851 	scf_callback_t *lcb = g;
1852 	pgroup_t *pg = NULL;
1853 
1854 	const char *fmri = NULL;
1855 	char *lfmri = NULL;
1856 	char *cur_selection = NULL;
1857 
1858 	scf_propertygroup_t *sc_pg = NULL;
1859 	scf_property_t *sc_prop = NULL;
1860 	scf_pg_tmpl_t *t_pg = NULL;
1861 	scf_prop_tmpl_t *t_prop = NULL;
1862 	scf_type_t prop_type;
1863 
1864 	value_t *vp;
1865 	int issvc = lcb->sc_service;
1866 	int r = UU_WALK_ERROR;
1867 
1868 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1869 		return (UU_WALK_NEXT);
1870 
1871 	t_prop = scf_tmpl_prop_create(g_hndl);
1872 	sc_prop = scf_property_create(g_hndl);
1873 	if (sc_prop == NULL || t_prop == NULL) {
1874 		warn(gettext("Unable to create the property to attempt and "
1875 		    "find a missing type.\n"));
1876 
1877 		scf_property_destroy(sc_prop);
1878 		scf_tmpl_prop_destroy(t_prop);
1879 
1880 		return (UU_WALK_ERROR);
1881 	}
1882 
1883 	if (lcb->sc_flags == 1) {
1884 		pg = lcb->sc_parent;
1885 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1886 		fmri = pg->sc_parent->sc_fmri;
1887 retry_pg:
1888 		if (cur_svc && cur_selection == NULL) {
1889 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1890 			lscf_get_selection_str(cur_selection,
1891 			    max_scf_fmri_len + 1);
1892 
1893 			if (strcmp(cur_selection, fmri) != 0) {
1894 				lscf_select(fmri);
1895 			} else {
1896 				free(cur_selection);
1897 				cur_selection = NULL;
1898 			}
1899 		} else {
1900 			lscf_select(fmri);
1901 		}
1902 
1903 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1904 			warn(gettext("Unable to create property group to "
1905 			    "find a missing property type.\n"));
1906 
1907 			goto out;
1908 		}
1909 
1910 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1911 			/*
1912 			 * If this is the sc_pg from the parent
1913 			 * let the caller clean up the sc_pg,
1914 			 * and just throw it away in this case.
1915 			 */
1916 			if (sc_pg != lcb->sc_parent)
1917 				scf_pg_destroy(sc_pg);
1918 
1919 			sc_pg = NULL;
1920 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1921 				warn(gettext("Unable to create template "
1922 				    "property group to find a property "
1923 				    "type.\n"));
1924 
1925 				goto out;
1926 			}
1927 
1928 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1929 			    pg->sc_pgroup_name, NULL, t_pg,
1930 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1931 				/*
1932 				 * if instance get service and jump back
1933 				 */
1934 				scf_tmpl_pg_destroy(t_pg);
1935 				t_pg = NULL;
1936 				if (issvc == 0) {
1937 					entity_t *e = pg->sc_parent->sc_parent;
1938 
1939 					fmri = e->sc_fmri;
1940 					issvc = 1;
1941 					goto retry_pg;
1942 				} else {
1943 					goto out;
1944 				}
1945 			}
1946 		}
1947 	} else {
1948 		sc_pg = lcb->sc_parent;
1949 	}
1950 
1951 	/*
1952 	 * Attempt to get the type from an existing property.  If the property
1953 	 * cannot be found then attempt to get the type from a template entry
1954 	 * for the property.
1955 	 *
1956 	 * Finally, if at the instance level look at the service level.
1957 	 */
1958 	if (sc_pg != NULL &&
1959 	    pg_get_prop(sc_pg, prop->sc_property_name,
1960 	    sc_prop) == SCF_SUCCESS &&
1961 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1962 		prop->sc_value_type = prop_type;
1963 
1964 		/*
1965 		 * Found a type, update the value types and validate
1966 		 * the actual value against this type.
1967 		 */
1968 		for (vp = uu_list_first(prop->sc_property_values);
1969 		    vp != NULL;
1970 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1971 			vp->sc_type = prop->sc_value_type;
1972 			lxml_store_value(vp, 0, NULL);
1973 		}
1974 
1975 		r = UU_WALK_NEXT;
1976 		goto out;
1977 	}
1978 
1979 	/*
1980 	 * If we get here with t_pg set to NULL then we had to have
1981 	 * gotten an sc_pg but that sc_pg did not have the property
1982 	 * we are looking for.   So if the t_pg is not null look up
1983 	 * the template entry for the property.
1984 	 *
1985 	 * If the t_pg is null then need to attempt to get a matching
1986 	 * template entry for the sc_pg, and see if there is a property
1987 	 * entry for that template entry.
1988 	 */
1989 do_tmpl :
1990 	if (t_pg != NULL &&
1991 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1992 	    t_prop, 0) == SCF_SUCCESS) {
1993 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1994 			prop->sc_value_type = prop_type;
1995 
1996 			/*
1997 			 * Found a type, update the value types and validate
1998 			 * the actual value against this type.
1999 			 */
2000 			for (vp = uu_list_first(prop->sc_property_values);
2001 			    vp != NULL;
2002 			    vp = uu_list_next(prop->sc_property_values, vp)) {
2003 				vp->sc_type = prop->sc_value_type;
2004 				lxml_store_value(vp, 0, NULL);
2005 			}
2006 
2007 			r = UU_WALK_NEXT;
2008 			goto out;
2009 		}
2010 	} else {
2011 		if (t_pg == NULL && sc_pg) {
2012 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2013 				warn(gettext("Unable to create template "
2014 				    "property group to find a property "
2015 				    "type.\n"));
2016 
2017 				goto out;
2018 			}
2019 
2020 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2021 				scf_tmpl_pg_destroy(t_pg);
2022 				t_pg = NULL;
2023 			} else {
2024 				goto do_tmpl;
2025 			}
2026 		}
2027 	}
2028 
2029 	if (issvc == 0) {
2030 		scf_instance_t *i;
2031 		scf_service_t *s;
2032 
2033 		issvc = 1;
2034 		if (lcb->sc_flags == 1) {
2035 			entity_t *e = pg->sc_parent->sc_parent;
2036 
2037 			fmri = e->sc_fmri;
2038 			goto retry_pg;
2039 		}
2040 
2041 		/*
2042 		 * because lcb->sc_flags was not set then this means
2043 		 * the pg was not used and can be used here.
2044 		 */
2045 		if ((pg = internal_pgroup_new()) == NULL) {
2046 			warn(gettext("Could not create internal property group "
2047 			    "to find a missing type."));
2048 
2049 			goto out;
2050 		}
2051 
2052 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2053 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2054 		    max_scf_name_len + 1) < 0)
2055 				goto out;
2056 
2057 		i = scf_instance_create(g_hndl);
2058 		s = scf_service_create(g_hndl);
2059 		if (i == NULL || s == NULL ||
2060 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2061 			warn(gettext("Could not get a service for the instance "
2062 			    "to find a missing type."));
2063 
2064 			goto out;
2065 		}
2066 
2067 		/*
2068 		 * Check to see truly at the instance level.
2069 		 */
2070 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2071 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2072 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2073 			goto out;
2074 		else
2075 			fmri = (const char *)lfmri;
2076 
2077 		goto retry_pg;
2078 	}
2079 
2080 out :
2081 	if (sc_pg != lcb->sc_parent) {
2082 		scf_pg_destroy(sc_pg);
2083 	}
2084 
2085 	/*
2086 	 * If this is true then the pg was allocated
2087 	 * here, and the name was set so need to free
2088 	 * the name and the pg.
2089 	 */
2090 	if (pg != NULL && pg != lcb->sc_parent) {
2091 		free((char *)pg->sc_pgroup_name);
2092 		internal_pgroup_free(pg);
2093 	}
2094 
2095 	if (cur_selection) {
2096 		lscf_select(cur_selection);
2097 		free(cur_selection);
2098 	}
2099 
2100 	scf_tmpl_pg_destroy(t_pg);
2101 	scf_tmpl_prop_destroy(t_prop);
2102 	scf_property_destroy(sc_prop);
2103 
2104 	if (r != UU_WALK_NEXT)
2105 		warn(gettext("Could not find property type for \"%s\" "
2106 		    "from \"%s\"\n"), prop->sc_property_name,
2107 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2108 
2109 	free(lfmri);
2110 
2111 	return (r);
2112 }
2113 
2114 /*
2115  * Take a property group that does not have a type and check to see if a type
2116  * exists or can be gleened from the current data.  Set the type.
2117  *
2118  * Check the current level (instance) and then check the higher level
2119  * (service).  This could be the case for adding a new property to
2120  * the instance that's going to "override" a service level property.
2121  *
2122  * For a property group
2123  * 1. Take the type from an existing property group
2124  * 2. Take the type from a template entry
2125  *
2126  * If the type can not be found, then leave the type as is, and let the import
2127  * report the problem of the missing type.
2128  */
2129 static int
2130 find_current_pg_type(void *p, void *sori)
2131 {
2132 	entity_t *si = sori;
2133 	pgroup_t *pg = p;
2134 
2135 	const char *ofmri, *fmri;
2136 	char *cur_selection = NULL;
2137 	char *pg_type = NULL;
2138 
2139 	scf_propertygroup_t *sc_pg = NULL;
2140 	scf_pg_tmpl_t *t_pg = NULL;
2141 
2142 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2143 	int r = UU_WALK_ERROR;
2144 
2145 	ofmri = fmri = si->sc_fmri;
2146 	if (pg->sc_pgroup_type != NULL) {
2147 		r = UU_WALK_NEXT;
2148 
2149 		goto out;
2150 	}
2151 
2152 	sc_pg = scf_pg_create(g_hndl);
2153 	if (sc_pg == NULL) {
2154 		warn(gettext("Unable to create property group to attempt "
2155 		    "and find a missing type.\n"));
2156 
2157 		return (UU_WALK_ERROR);
2158 	}
2159 
2160 	/*
2161 	 * Using get_pg() requires that the cur_svc/cur_inst be
2162 	 * via lscf_select.  Need to preserve the current selection
2163 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2164 	 */
2165 	if (cur_svc) {
2166 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2167 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2168 	}
2169 
2170 	/*
2171 	 * If the property group exists get the type, and set
2172 	 * the pgroup_t type of that type.
2173 	 *
2174 	 * If not the check for a template pg_pattern entry
2175 	 * and take the type from that.
2176 	 */
2177 retry_svc:
2178 	lscf_select(fmri);
2179 
2180 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2181 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2182 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2183 		    max_scf_pg_type_len + 1) != -1) {
2184 			pg->sc_pgroup_type = pg_type;
2185 
2186 			r = UU_WALK_NEXT;
2187 			goto out;
2188 		} else {
2189 			free(pg_type);
2190 		}
2191 	} else {
2192 		if ((t_pg == NULL) &&
2193 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2194 			goto out;
2195 
2196 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2197 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2198 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2199 			pg->sc_pgroup_type = pg_type;
2200 
2201 			r = UU_WALK_NEXT;
2202 			goto out;
2203 		}
2204 	}
2205 
2206 	/*
2207 	 * If type is not found at the instance level then attempt to
2208 	 * find the type at the service level.
2209 	 */
2210 	if (!issvc) {
2211 		si = si->sc_parent;
2212 		fmri = si->sc_fmri;
2213 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2214 		goto retry_svc;
2215 	}
2216 
2217 out :
2218 	if (cur_selection) {
2219 		lscf_select(cur_selection);
2220 		free(cur_selection);
2221 	}
2222 
2223 	/*
2224 	 * Now walk the properties of the property group to make sure that
2225 	 * all properties have the correct type and values are valid for
2226 	 * those types.
2227 	 */
2228 	if (r == UU_WALK_NEXT) {
2229 		scf_callback_t cb;
2230 
2231 		cb.sc_service = issvc;
2232 		cb.sc_source_fmri = ofmri;
2233 		if (sc_pg != NULL) {
2234 			cb.sc_parent = sc_pg;
2235 			cb.sc_flags = 0;
2236 		} else {
2237 			cb.sc_parent = pg;
2238 			cb.sc_flags = 1;
2239 		}
2240 
2241 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2242 		    &cb, UU_DEFAULT) != 0) {
2243 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2244 				bad_error("uu_list_walk", uu_error());
2245 
2246 			r = UU_WALK_ERROR;
2247 		}
2248 	} else {
2249 		warn(gettext("Could not find property group type for "
2250 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2251 	}
2252 
2253 	scf_tmpl_pg_destroy(t_pg);
2254 	scf_pg_destroy(sc_pg);
2255 
2256 	return (r);
2257 }
2258 
2259 /*
2260  * Import.  These functions import a bundle into the repository.
2261  */
2262 
2263 /*
2264  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2265  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2266  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2267  * lcbdata->sc_err to
2268  *   ENOMEM - out of memory
2269  *   ECONNABORTED - repository connection broken
2270  *   ECANCELED - sc_trans's property group was deleted
2271  *   EINVAL - p's name is invalid (error printed)
2272  *	    - p has an invalid value (error printed)
2273  */
2274 static int
2275 lscf_property_import(void *v, void *pvt)
2276 {
2277 	property_t *p = v;
2278 	scf_callback_t *lcbdata = pvt;
2279 	value_t *vp;
2280 	scf_transaction_t *trans = lcbdata->sc_trans;
2281 	scf_transaction_entry_t *entr;
2282 	scf_value_t *val;
2283 	scf_type_t tp;
2284 
2285 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2286 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2287 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2288 		lcbdata->sc_enable = p;
2289 		return (UU_WALK_NEXT);
2290 	}
2291 
2292 	entr = scf_entry_create(lcbdata->sc_handle);
2293 	if (entr == NULL) {
2294 		switch (scf_error()) {
2295 		case SCF_ERROR_NO_MEMORY:
2296 			return (stash_scferror(lcbdata));
2297 
2298 		case SCF_ERROR_INVALID_ARGUMENT:
2299 		default:
2300 			bad_error("scf_entry_create", scf_error());
2301 		}
2302 	}
2303 
2304 	tp = p->sc_value_type;
2305 
2306 	if (scf_transaction_property_new(trans, entr,
2307 	    p->sc_property_name, tp) != 0) {
2308 		switch (scf_error()) {
2309 		case SCF_ERROR_INVALID_ARGUMENT:
2310 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2311 			scf_entry_destroy(entr);
2312 			return (stash_scferror(lcbdata));
2313 
2314 		case SCF_ERROR_EXISTS:
2315 			break;
2316 
2317 		case SCF_ERROR_DELETED:
2318 		case SCF_ERROR_CONNECTION_BROKEN:
2319 			scf_entry_destroy(entr);
2320 			return (stash_scferror(lcbdata));
2321 
2322 		case SCF_ERROR_NOT_BOUND:
2323 		case SCF_ERROR_HANDLE_MISMATCH:
2324 		case SCF_ERROR_NOT_SET:
2325 		default:
2326 			bad_error("scf_transaction_property_new", scf_error());
2327 		}
2328 
2329 		if (scf_transaction_property_change_type(trans, entr,
2330 		    p->sc_property_name, tp) != 0) {
2331 			switch (scf_error()) {
2332 			case SCF_ERROR_DELETED:
2333 			case SCF_ERROR_CONNECTION_BROKEN:
2334 				scf_entry_destroy(entr);
2335 				return (stash_scferror(lcbdata));
2336 
2337 			case SCF_ERROR_INVALID_ARGUMENT:
2338 				semerr(emsg_invalid_prop_name,
2339 				    p->sc_property_name);
2340 				scf_entry_destroy(entr);
2341 				return (stash_scferror(lcbdata));
2342 
2343 			case SCF_ERROR_NOT_FOUND:
2344 			case SCF_ERROR_NOT_SET:
2345 			case SCF_ERROR_HANDLE_MISMATCH:
2346 			case SCF_ERROR_NOT_BOUND:
2347 			default:
2348 				bad_error(
2349 				    "scf_transaction_property_change_type",
2350 				    scf_error());
2351 			}
2352 		}
2353 	}
2354 
2355 	for (vp = uu_list_first(p->sc_property_values);
2356 	    vp != NULL;
2357 	    vp = uu_list_next(p->sc_property_values, vp)) {
2358 		val = scf_value_create(g_hndl);
2359 		if (val == NULL) {
2360 			switch (scf_error()) {
2361 			case SCF_ERROR_NO_MEMORY:
2362 				return (stash_scferror(lcbdata));
2363 
2364 			case SCF_ERROR_INVALID_ARGUMENT:
2365 			default:
2366 				bad_error("scf_value_create", scf_error());
2367 			}
2368 		}
2369 
2370 		switch (tp) {
2371 		case SCF_TYPE_BOOLEAN:
2372 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2373 			break;
2374 		case SCF_TYPE_COUNT:
2375 			scf_value_set_count(val, vp->sc_u.sc_count);
2376 			break;
2377 		case SCF_TYPE_INTEGER:
2378 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2379 			break;
2380 		default:
2381 			assert(vp->sc_u.sc_string != NULL);
2382 			if (scf_value_set_from_string(val, tp,
2383 			    vp->sc_u.sc_string) != 0) {
2384 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2385 					bad_error("scf_value_set_from_string",
2386 					    scf_error());
2387 
2388 				warn(gettext("Value \"%s\" is not a valid "
2389 				    "%s.\n"), vp->sc_u.sc_string,
2390 				    scf_type_to_string(tp));
2391 				scf_value_destroy(val);
2392 				return (stash_scferror(lcbdata));
2393 			}
2394 			break;
2395 		}
2396 
2397 		if (scf_entry_add_value(entr, val) != 0)
2398 			bad_error("scf_entry_add_value", scf_error());
2399 	}
2400 
2401 	return (UU_WALK_NEXT);
2402 }
2403 
2404 /*
2405  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2406  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2407  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2408  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2409  * lcbdata->sc_err to
2410  *   ECONNABORTED - repository connection broken
2411  *   ENOMEM - out of memory
2412  *   ENOSPC - svc.configd is out of resources
2413  *   ECANCELED - sc_parent was deleted
2414  *   EPERM - could not create property group (permission denied) (error printed)
2415  *	   - could not modify property group (permission denied) (error printed)
2416  *	   - could not delete property group (permission denied) (error	printed)
2417  *   EROFS - could not create property group (repository is read-only)
2418  *	   - could not delete property group (repository is read-only)
2419  *   EACCES - could not create property group (backend access denied)
2420  *	    - could not delete property group (backend access denied)
2421  *   EEXIST - could not create property group (already exists)
2422  *   EINVAL - invalid property group name (error printed)
2423  *	    - invalid property name (error printed)
2424  *	    - invalid value (error printed)
2425  *   EBUSY - new property group deleted (error printed)
2426  *	   - new property group changed (error printed)
2427  *	   - property group added (error printed)
2428  *	   - property group deleted (error printed)
2429  */
2430 static int
2431 entity_pgroup_import(void *v, void *pvt)
2432 {
2433 	pgroup_t *p = v;
2434 	scf_callback_t cbdata;
2435 	scf_callback_t *lcbdata = pvt;
2436 	void *ent = lcbdata->sc_parent;
2437 	int issvc = lcbdata->sc_service;
2438 	int r;
2439 
2440 	const char * const pg_changed = gettext("%s changed unexpectedly "
2441 	    "(new property group \"%s\" changed).\n");
2442 
2443 	/* Never import deleted property groups. */
2444 	if (p->sc_pgroup_delete) {
2445 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2446 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2447 			goto delete_pg;
2448 		}
2449 		return (UU_WALK_NEXT);
2450 	}
2451 
2452 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2453 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2454 		lcbdata->sc_general = p;
2455 		return (UU_WALK_NEXT);
2456 	}
2457 
2458 add_pg:
2459 	if (issvc)
2460 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2461 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2462 	else
2463 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2464 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2465 	if (r != 0) {
2466 		switch (scf_error()) {
2467 		case SCF_ERROR_DELETED:
2468 		case SCF_ERROR_CONNECTION_BROKEN:
2469 		case SCF_ERROR_BACKEND_READONLY:
2470 		case SCF_ERROR_BACKEND_ACCESS:
2471 		case SCF_ERROR_NO_RESOURCES:
2472 			return (stash_scferror(lcbdata));
2473 
2474 		case SCF_ERROR_EXISTS:
2475 			if (lcbdata->sc_flags & SCI_FORCE)
2476 				break;
2477 			return (stash_scferror(lcbdata));
2478 
2479 		case SCF_ERROR_INVALID_ARGUMENT:
2480 			warn(emsg_fmri_invalid_pg_name_type,
2481 			    lcbdata->sc_source_fmri,
2482 			    p->sc_pgroup_name, p->sc_pgroup_type);
2483 			return (stash_scferror(lcbdata));
2484 
2485 		case SCF_ERROR_PERMISSION_DENIED:
2486 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2487 			    lcbdata->sc_target_fmri);
2488 			return (stash_scferror(lcbdata));
2489 
2490 		case SCF_ERROR_NOT_BOUND:
2491 		case SCF_ERROR_HANDLE_MISMATCH:
2492 		case SCF_ERROR_NOT_SET:
2493 		default:
2494 			bad_error("scf_service_add_pg", scf_error());
2495 		}
2496 
2497 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2498 			switch (scf_error()) {
2499 			case SCF_ERROR_CONNECTION_BROKEN:
2500 			case SCF_ERROR_DELETED:
2501 				return (stash_scferror(lcbdata));
2502 
2503 			case SCF_ERROR_INVALID_ARGUMENT:
2504 				warn(emsg_fmri_invalid_pg_name,
2505 				    lcbdata->sc_source_fmri,
2506 				    p->sc_pgroup_name);
2507 				return (stash_scferror(lcbdata));
2508 
2509 			case SCF_ERROR_NOT_FOUND:
2510 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2511 				    p->sc_pgroup_name);
2512 				lcbdata->sc_err = EBUSY;
2513 				return (UU_WALK_ERROR);
2514 
2515 			case SCF_ERROR_NOT_BOUND:
2516 			case SCF_ERROR_HANDLE_MISMATCH:
2517 			case SCF_ERROR_NOT_SET:
2518 			default:
2519 				bad_error("entity_get_pg", scf_error());
2520 			}
2521 		}
2522 
2523 		if (lcbdata->sc_flags & SCI_KEEP)
2524 			goto props;
2525 
2526 delete_pg:
2527 		if (scf_pg_delete(imp_pg) != 0) {
2528 			switch (scf_error()) {
2529 			case SCF_ERROR_DELETED:
2530 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2531 				    p->sc_pgroup_name);
2532 				lcbdata->sc_err = EBUSY;
2533 				return (UU_WALK_ERROR);
2534 
2535 			case SCF_ERROR_PERMISSION_DENIED:
2536 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2537 				    lcbdata->sc_target_fmri);
2538 				return (stash_scferror(lcbdata));
2539 
2540 			case SCF_ERROR_BACKEND_READONLY:
2541 			case SCF_ERROR_BACKEND_ACCESS:
2542 			case SCF_ERROR_CONNECTION_BROKEN:
2543 				return (stash_scferror(lcbdata));
2544 
2545 			case SCF_ERROR_NOT_SET:
2546 			default:
2547 				bad_error("scf_pg_delete", scf_error());
2548 			}
2549 		}
2550 
2551 		if (p->sc_pgroup_delete)
2552 			return (UU_WALK_NEXT);
2553 
2554 		goto add_pg;
2555 	}
2556 
2557 props:
2558 
2559 	/*
2560 	 * Add properties to property group, if any.
2561 	 */
2562 	cbdata.sc_handle = lcbdata->sc_handle;
2563 	cbdata.sc_parent = imp_pg;
2564 	cbdata.sc_flags = lcbdata->sc_flags;
2565 	cbdata.sc_trans = imp_tx;
2566 	cbdata.sc_enable = NULL;
2567 
2568 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2569 		switch (scf_error()) {
2570 		case SCF_ERROR_BACKEND_ACCESS:
2571 		case SCF_ERROR_BACKEND_READONLY:
2572 		case SCF_ERROR_CONNECTION_BROKEN:
2573 			return (stash_scferror(lcbdata));
2574 
2575 		case SCF_ERROR_DELETED:
2576 			warn(pg_changed, lcbdata->sc_target_fmri,
2577 			    p->sc_pgroup_name);
2578 			lcbdata->sc_err = EBUSY;
2579 			return (UU_WALK_ERROR);
2580 
2581 		case SCF_ERROR_PERMISSION_DENIED:
2582 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2583 			    lcbdata->sc_target_fmri);
2584 			return (stash_scferror(lcbdata));
2585 
2586 		case SCF_ERROR_NOT_BOUND:
2587 		case SCF_ERROR_NOT_SET:
2588 		case SCF_ERROR_IN_USE:
2589 		case SCF_ERROR_HANDLE_MISMATCH:
2590 		default:
2591 			bad_error("scf_transaction_start", scf_error());
2592 		}
2593 	}
2594 
2595 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2596 	    UU_DEFAULT) != 0) {
2597 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2598 			bad_error("uu_list_walk", uu_error());
2599 		scf_transaction_reset(imp_tx);
2600 
2601 		lcbdata->sc_err = cbdata.sc_err;
2602 		if (cbdata.sc_err == ECANCELED) {
2603 			warn(pg_changed, lcbdata->sc_target_fmri,
2604 			    p->sc_pgroup_name);
2605 			lcbdata->sc_err = EBUSY;
2606 		}
2607 		return (UU_WALK_ERROR);
2608 	}
2609 
2610 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2611 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2612 
2613 		/*
2614 		 * take the snapshot running snapshot then
2615 		 * import the stored general/enable property
2616 		 */
2617 		r = take_snap(ent, snap_running, imp_rsnap);
2618 		switch (r) {
2619 		case 0:
2620 			break;
2621 
2622 		case ECONNABORTED:
2623 			warn(gettext("Could not take %s snapshot on import "
2624 			    "(repository connection broken).\n"),
2625 			    snap_running);
2626 			lcbdata->sc_err = r;
2627 			return (UU_WALK_ERROR);
2628 		case ECANCELED:
2629 			warn(emsg_deleted);
2630 			lcbdata->sc_err = r;
2631 			return (UU_WALK_ERROR);
2632 
2633 		case EPERM:
2634 			warn(gettext("Could not take %s snapshot "
2635 			    "(permission denied).\n"), snap_running);
2636 			lcbdata->sc_err = r;
2637 			return (UU_WALK_ERROR);
2638 
2639 		case ENOSPC:
2640 			warn(gettext("Could not take %s snapshot"
2641 			    "(repository server out of resources).\n"),
2642 			    snap_running);
2643 			lcbdata->sc_err = r;
2644 			return (UU_WALK_ERROR);
2645 
2646 		default:
2647 			bad_error("take_snap", r);
2648 		}
2649 
2650 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2651 		if (r != UU_WALK_NEXT) {
2652 			if (r != UU_WALK_ERROR)
2653 				bad_error("lscf_property_import", r);
2654 			return (EINVAL);
2655 		}
2656 	}
2657 
2658 	r = scf_transaction_commit(imp_tx);
2659 	switch (r) {
2660 	case 1:
2661 		r = UU_WALK_NEXT;
2662 		break;
2663 
2664 	case 0:
2665 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2666 		lcbdata->sc_err = EBUSY;
2667 		r = UU_WALK_ERROR;
2668 		break;
2669 
2670 	case -1:
2671 		switch (scf_error()) {
2672 		case SCF_ERROR_BACKEND_READONLY:
2673 		case SCF_ERROR_BACKEND_ACCESS:
2674 		case SCF_ERROR_CONNECTION_BROKEN:
2675 		case SCF_ERROR_NO_RESOURCES:
2676 			r = stash_scferror(lcbdata);
2677 			break;
2678 
2679 		case SCF_ERROR_DELETED:
2680 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2681 			    p->sc_pgroup_name);
2682 			lcbdata->sc_err = EBUSY;
2683 			r = UU_WALK_ERROR;
2684 			break;
2685 
2686 		case SCF_ERROR_PERMISSION_DENIED:
2687 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2688 			    lcbdata->sc_target_fmri);
2689 			r = stash_scferror(lcbdata);
2690 			break;
2691 
2692 		case SCF_ERROR_NOT_SET:
2693 		case SCF_ERROR_INVALID_ARGUMENT:
2694 		case SCF_ERROR_NOT_BOUND:
2695 		default:
2696 			bad_error("scf_transaction_commit", scf_error());
2697 		}
2698 		break;
2699 
2700 	default:
2701 		bad_error("scf_transaction_commit", r);
2702 	}
2703 
2704 	scf_transaction_destroy_children(imp_tx);
2705 
2706 	return (r);
2707 }
2708 
2709 /*
2710  * Returns
2711  *   0 - success
2712  *   ECONNABORTED - repository connection broken
2713  *   ENOMEM - out of memory
2714  *   ENOSPC - svc.configd is out of resources
2715  *   ECANCELED - inst was deleted
2716  *   EPERM - could not create property group (permission denied) (error printed)
2717  *	   - could not modify property group (permission denied) (error printed)
2718  *   EROFS - could not create property group (repository is read-only)
2719  *   EACCES - could not create property group (backend access denied)
2720  *   EEXIST - could not create property group (already exists)
2721  *   EINVAL - invalid property group name (error printed)
2722  *	    - invalid property name (error printed)
2723  *	    - invalid value (error printed)
2724  *   EBUSY - new property group changed (error printed)
2725  */
2726 static int
2727 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2728     const entity_t *isvc, int flags)
2729 {
2730 	scf_callback_t cbdata;
2731 
2732 	cbdata.sc_handle = scf_service_handle(svc);
2733 	cbdata.sc_parent = svc;
2734 	cbdata.sc_service = 1;
2735 	cbdata.sc_general = 0;
2736 	cbdata.sc_enable = 0;
2737 	cbdata.sc_flags = flags;
2738 	cbdata.sc_source_fmri = isvc->sc_fmri;
2739 	cbdata.sc_target_fmri = target_fmri;
2740 
2741 	/*
2742 	 * If the op is set, then add the flag to the callback
2743 	 * flags for later use.
2744 	 */
2745 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2746 		switch (isvc->sc_op) {
2747 		case SVCCFG_OP_IMPORT :
2748 			cbdata.sc_flags |= SCI_OP_IMPORT;
2749 			break;
2750 		case SVCCFG_OP_APPLY :
2751 			cbdata.sc_flags |= SCI_OP_APPLY;
2752 			break;
2753 		case SVCCFG_OP_RESTORE :
2754 			cbdata.sc_flags |= SCI_OP_RESTORE;
2755 			break;
2756 		default :
2757 			uu_die(gettext("lscf_import_service_pgs : "
2758 			    "Unknown op stored in the service entity\n"));
2759 
2760 		}
2761 	}
2762 
2763 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2764 	    UU_DEFAULT) != 0) {
2765 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2766 			bad_error("uu_list_walk", uu_error());
2767 
2768 		return (cbdata.sc_err);
2769 	}
2770 
2771 	return (0);
2772 }
2773 
2774 /*
2775  * Returns
2776  *   0 - success
2777  *   ECONNABORTED - repository connection broken
2778  *   ENOMEM - out of memory
2779  *   ENOSPC - svc.configd is out of resources
2780  *   ECANCELED - inst was deleted
2781  *   EPERM - could not create property group (permission denied) (error printed)
2782  *	   - could not modify property group (permission denied) (error printed)
2783  *   EROFS - could not create property group (repository is read-only)
2784  *   EACCES - could not create property group (backend access denied)
2785  *   EEXIST - could not create property group (already exists)
2786  *   EINVAL - invalid property group name (error printed)
2787  *	    - invalid property name (error printed)
2788  *	    - invalid value (error printed)
2789  *   EBUSY - new property group changed (error printed)
2790  */
2791 static int
2792 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2793     const entity_t *iinst, int flags)
2794 {
2795 	scf_callback_t cbdata;
2796 
2797 	cbdata.sc_handle = scf_instance_handle(inst);
2798 	cbdata.sc_parent = inst;
2799 	cbdata.sc_service = 0;
2800 	cbdata.sc_general = NULL;
2801 	cbdata.sc_enable = NULL;
2802 	cbdata.sc_flags = flags;
2803 	cbdata.sc_source_fmri = iinst->sc_fmri;
2804 	cbdata.sc_target_fmri = target_fmri;
2805 
2806 	/*
2807 	 * If the op is set, then add the flag to the callback
2808 	 * flags for later use.
2809 	 */
2810 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2811 		switch (iinst->sc_op) {
2812 		case SVCCFG_OP_IMPORT :
2813 			cbdata.sc_flags |= SCI_OP_IMPORT;
2814 			break;
2815 		case SVCCFG_OP_APPLY :
2816 			cbdata.sc_flags |= SCI_OP_APPLY;
2817 			break;
2818 		case SVCCFG_OP_RESTORE :
2819 			cbdata.sc_flags |= SCI_OP_RESTORE;
2820 			break;
2821 		default :
2822 			uu_die(gettext("lscf_import_instance_pgs : "
2823 			    "Unknown op stored in the instance entity\n"));
2824 		}
2825 	}
2826 
2827 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2828 	    UU_DEFAULT) != 0) {
2829 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2830 			bad_error("uu_list_walk", uu_error());
2831 
2832 		return (cbdata.sc_err);
2833 	}
2834 
2835 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2836 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2837 		/*
2838 		 * If importing with the SCI_NOENABLED flag then
2839 		 * skip the delay, but if not then add the delay
2840 		 * of the enable property.
2841 		 */
2842 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2843 			cbdata.sc_flags |= SCI_DELAYENABLE;
2844 		}
2845 
2846 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2847 		    != UU_WALK_NEXT)
2848 			return (cbdata.sc_err);
2849 	}
2850 
2851 	return (0);
2852 }
2853 
2854 /*
2855  * Report the reasons why we can't upgrade pg2 to pg1.
2856  */
2857 static void
2858 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2859     int new)
2860 {
2861 	property_t *p1, *p2;
2862 
2863 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2864 
2865 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2866 		return;
2867 
2868 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2869 	    p1 != NULL;
2870 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2871 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2872 		if (p2 != NULL) {
2873 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2874 			    new);
2875 			continue;
2876 		}
2877 
2878 		if (new)
2879 			warn(gettext("Conflict upgrading %s (new property "
2880 			    "group \"%s\" is missing property \"%s\").\n"),
2881 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2882 		else
2883 			warn(gettext("Conflict upgrading %s (property "
2884 			    "\"%s/%s\" is missing).\n"), fmri,
2885 			    pg1->sc_pgroup_name, p1->sc_property_name);
2886 	}
2887 
2888 	/*
2889 	 * Since pg1 should be from the manifest, any properties in pg2 which
2890 	 * aren't in pg1 shouldn't be reported as conflicts.
2891 	 */
2892 }
2893 
2894 /*
2895  * Add transaction entries to tx which will upgrade cur's pg according to old
2896  * & new.
2897  *
2898  * Returns
2899  *   0 - success
2900  *   EINVAL - new has a property with an invalid name or value (message emitted)
2901  *   ENOMEM - out of memory
2902  */
2903 static int
2904 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2905     pgroup_t *cur, int speak, const char *fmri)
2906 {
2907 	property_t *p, *new_p, *cur_p;
2908 	scf_transaction_entry_t *e;
2909 	int r;
2910 	int is_general;
2911 	int is_protected;
2912 
2913 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2914 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2915 		bad_error("uu_list_walk", uu_error());
2916 
2917 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2918 
2919 	for (p = uu_list_first(old->sc_pgroup_props);
2920 	    p != NULL;
2921 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2922 		/* p is a property in the old property group. */
2923 
2924 		/* Protect live properties. */
2925 		is_protected = 0;
2926 		if (is_general) {
2927 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2928 			    0 ||
2929 			    strcmp(p->sc_property_name,
2930 			    SCF_PROPERTY_RESTARTER) == 0)
2931 				is_protected = 1;
2932 		}
2933 
2934 		/* Look for the same property in the new properties. */
2935 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2936 		if (new_p != NULL) {
2937 			new_p->sc_seen = 1;
2938 
2939 			/*
2940 			 * If the new property is the same as the old, don't do
2941 			 * anything (leave any user customizations).
2942 			 */
2943 			if (prop_equal(p, new_p, NULL, NULL, 0))
2944 				continue;
2945 
2946 			if (new_p->sc_property_override)
2947 				goto upgrade;
2948 		}
2949 
2950 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2951 		if (cur_p == NULL) {
2952 			/*
2953 			 * p has been deleted from the repository.  If we were
2954 			 * going to delete it anyway, do nothing.  Otherwise
2955 			 * report a conflict.
2956 			 */
2957 			if (new_p == NULL)
2958 				continue;
2959 
2960 			if (is_protected)
2961 				continue;
2962 
2963 			warn(gettext("Conflict upgrading %s "
2964 			    "(property \"%s/%s\" is missing).\n"), fmri,
2965 			    old->sc_pgroup_name, p->sc_property_name);
2966 			continue;
2967 		}
2968 
2969 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2970 			/*
2971 			 * Conflict.  Don't warn if the property is already the
2972 			 * way we want it, though.
2973 			 */
2974 			if (is_protected)
2975 				continue;
2976 
2977 			if (new_p == NULL)
2978 				(void) prop_equal(p, cur_p, fmri,
2979 				    old->sc_pgroup_name, 0);
2980 			else
2981 				(void) prop_equal(cur_p, new_p, fmri,
2982 				    old->sc_pgroup_name, 0);
2983 			continue;
2984 		}
2985 
2986 		if (is_protected) {
2987 			if (speak)
2988 				warn(gettext("%s: Refusing to upgrade "
2989 				    "\"%s/%s\" (live property).\n"), fmri,
2990 				    old->sc_pgroup_name, p->sc_property_name);
2991 			continue;
2992 		}
2993 
2994 upgrade:
2995 		/* p hasn't been customized in the repository.  Upgrade it. */
2996 		if (new_p == NULL) {
2997 			/* p was deleted.  Delete from cur if unchanged. */
2998 			if (speak)
2999 				warn(gettext(
3000 				    "%s: Deleting property \"%s/%s\".\n"),
3001 				    fmri, old->sc_pgroup_name,
3002 				    p->sc_property_name);
3003 
3004 			e = scf_entry_create(g_hndl);
3005 			if (e == NULL)
3006 				return (ENOMEM);
3007 
3008 			if (scf_transaction_property_delete(tx, e,
3009 			    p->sc_property_name) != 0) {
3010 				switch (scf_error()) {
3011 				case SCF_ERROR_DELETED:
3012 					scf_entry_destroy(e);
3013 					return (ECANCELED);
3014 
3015 				case SCF_ERROR_CONNECTION_BROKEN:
3016 					scf_entry_destroy(e);
3017 					return (ECONNABORTED);
3018 
3019 				case SCF_ERROR_NOT_FOUND:
3020 					/*
3021 					 * This can happen if cur is from the
3022 					 * running snapshot (and it differs
3023 					 * from the live properties).
3024 					 */
3025 					scf_entry_destroy(e);
3026 					break;
3027 
3028 				case SCF_ERROR_HANDLE_MISMATCH:
3029 				case SCF_ERROR_NOT_BOUND:
3030 				case SCF_ERROR_NOT_SET:
3031 				case SCF_ERROR_INVALID_ARGUMENT:
3032 				default:
3033 					bad_error(
3034 					    "scf_transaction_property_delete",
3035 					    scf_error());
3036 				}
3037 			}
3038 		} else {
3039 			scf_callback_t ctx;
3040 
3041 			if (speak)
3042 				warn(gettext(
3043 				    "%s: Upgrading property \"%s/%s\".\n"),
3044 				    fmri, old->sc_pgroup_name,
3045 				    p->sc_property_name);
3046 
3047 			ctx.sc_handle = g_hndl;
3048 			ctx.sc_trans = tx;
3049 			ctx.sc_flags = 0;
3050 
3051 			r = lscf_property_import(new_p, &ctx);
3052 			if (r != UU_WALK_NEXT) {
3053 				if (r != UU_WALK_ERROR)
3054 					bad_error("lscf_property_import", r);
3055 				return (EINVAL);
3056 			}
3057 		}
3058 	}
3059 
3060 	/* Go over the properties which were added. */
3061 	for (new_p = uu_list_first(new->sc_pgroup_props);
3062 	    new_p != NULL;
3063 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3064 		if (new_p->sc_seen)
3065 			continue;
3066 
3067 		/* This is a new property. */
3068 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3069 		if (cur_p == NULL) {
3070 			scf_callback_t ctx;
3071 
3072 			ctx.sc_handle = g_hndl;
3073 			ctx.sc_trans = tx;
3074 			ctx.sc_flags = 0;
3075 
3076 			r = lscf_property_import(new_p, &ctx);
3077 			if (r != UU_WALK_NEXT) {
3078 				if (r != UU_WALK_ERROR)
3079 					bad_error("lscf_property_import", r);
3080 				return (EINVAL);
3081 			}
3082 			continue;
3083 		}
3084 
3085 		/*
3086 		 * Report a conflict if the new property differs from the
3087 		 * current one.  Unless it's general/enabled, since that's
3088 		 * never in the last-import snapshot.
3089 		 */
3090 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3091 		    0 &&
3092 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3093 			continue;
3094 
3095 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3096 	}
3097 
3098 	return (0);
3099 }
3100 
3101 /*
3102  * Upgrade pg according to old & new.
3103  *
3104  * Returns
3105  *   0 - success
3106  *   ECONNABORTED - repository connection broken
3107  *   ENOMEM - out of memory
3108  *   ENOSPC - svc.configd is out of resources
3109  *   ECANCELED - pg was deleted
3110  *   EPERM - couldn't modify pg (permission denied)
3111  *   EROFS - couldn't modify pg (backend read-only)
3112  *   EACCES - couldn't modify pg (backend access denied)
3113  *   EINVAL - new has a property with invalid name or value (error printed)
3114  *   EBUSY - pg changed unexpectedly
3115  */
3116 static int
3117 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3118     pgroup_t *new, int speak, const char *fmri)
3119 {
3120 	int r;
3121 
3122 	if (scf_transaction_start(imp_tx, pg) != 0) {
3123 		switch (scf_error()) {
3124 		case SCF_ERROR_CONNECTION_BROKEN:
3125 		case SCF_ERROR_DELETED:
3126 		case SCF_ERROR_PERMISSION_DENIED:
3127 		case SCF_ERROR_BACKEND_READONLY:
3128 		case SCF_ERROR_BACKEND_ACCESS:
3129 			return (scferror2errno(scf_error()));
3130 
3131 		case SCF_ERROR_HANDLE_MISMATCH:
3132 		case SCF_ERROR_IN_USE:
3133 		case SCF_ERROR_NOT_BOUND:
3134 		case SCF_ERROR_NOT_SET:
3135 		default:
3136 			bad_error("scf_transaction_start", scf_error());
3137 		}
3138 	}
3139 
3140 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3141 	switch (r) {
3142 	case 0:
3143 		break;
3144 
3145 	case EINVAL:
3146 	case ENOMEM:
3147 		scf_transaction_destroy_children(imp_tx);
3148 		return (r);
3149 
3150 	default:
3151 		bad_error("add_upgrade_entries", r);
3152 	}
3153 
3154 	r = scf_transaction_commit(imp_tx);
3155 
3156 	scf_transaction_destroy_children(imp_tx);
3157 
3158 	switch (r) {
3159 	case 1:
3160 		break;
3161 
3162 	case 0:
3163 		return (EBUSY);
3164 
3165 	case -1:
3166 		switch (scf_error()) {
3167 		case SCF_ERROR_CONNECTION_BROKEN:
3168 		case SCF_ERROR_NO_RESOURCES:
3169 		case SCF_ERROR_PERMISSION_DENIED:
3170 		case SCF_ERROR_BACKEND_READONLY:
3171 		case SCF_ERROR_BACKEND_ACCESS:
3172 		case SCF_ERROR_DELETED:
3173 			return (scferror2errno(scf_error()));
3174 
3175 		case SCF_ERROR_NOT_BOUND:
3176 		case SCF_ERROR_INVALID_ARGUMENT:
3177 		case SCF_ERROR_NOT_SET:
3178 		default:
3179 			bad_error("scf_transaction_commit", scf_error());
3180 		}
3181 
3182 	default:
3183 		bad_error("scf_transaction_commit", r);
3184 	}
3185 
3186 	return (0);
3187 }
3188 
3189 /*
3190  * Compares two entity FMRIs.  Returns
3191  *
3192  *   1 - equal
3193  *   0 - not equal
3194  *   -1 - f1 is invalid or not an entity
3195  *   -2 - f2 is invalid or not an entity
3196  */
3197 static int
3198 fmri_equal(const char *f1, const char *f2)
3199 {
3200 	int r;
3201 	const char *s1, *i1, *pg1;
3202 	const char *s2, *i2, *pg2;
3203 
3204 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3205 		return (-1);
3206 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3207 		return (-1);
3208 
3209 	if (s1 == NULL || pg1 != NULL)
3210 		return (-1);
3211 
3212 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3213 		return (-2);
3214 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3215 		return (-2);
3216 
3217 	if (s2 == NULL || pg2 != NULL)
3218 		return (-2);
3219 
3220 	r = strcmp(s1, s2);
3221 	if (r != 0)
3222 		return (0);
3223 
3224 	if (i1 == NULL && i2 == NULL)
3225 		return (1);
3226 
3227 	if (i1 == NULL || i2 == NULL)
3228 		return (0);
3229 
3230 	return (strcmp(i1, i2) == 0);
3231 }
3232 
3233 /*
3234  * Import a dependent by creating a dependency property group in the dependent
3235  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3236  * dependents pg, and add an entry to create a new property for this
3237  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3238  *
3239  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3240  * lcbdata->sc_err to
3241  *   ECONNABORTED - repository connection broken
3242  *   ENOMEM - out of memory
3243  *   ENOSPC - configd is out of resources
3244  *   EINVAL - target is invalid (error printed)
3245  *	    - target is not an entity (error printed)
3246  *	    - dependent has invalid name (error printed)
3247  *	    - invalid property name (error printed)
3248  *	    - invalid value (error printed)
3249  *	    - scope of target does not exist (error printed)
3250  *   EPERM - couldn't create target (permission denied) (error printed)
3251  *	   - couldn't create dependency pg (permission denied) (error printed)
3252  *	   - couldn't modify dependency pg (permission denied) (error printed)
3253  *   EROFS - couldn't create target (repository read-only)
3254  *	   - couldn't create dependency pg (repository read-only)
3255  *   EACCES - couldn't create target (backend access denied)
3256  *	    - couldn't create dependency pg (backend access denied)
3257  *   ECANCELED - sc_trans's pg was deleted
3258  *   EALREADY - property for dependent already exists in sc_trans's pg
3259  *   EEXIST - dependency pg already exists in target (error printed)
3260  *   EBUSY - target deleted (error printed)
3261  *         - property group changed during import (error printed)
3262  */
3263 static int
3264 lscf_dependent_import(void *a1, void *pvt)
3265 {
3266 	pgroup_t *pgrp = a1;
3267 	scf_callback_t *lcbdata = pvt;
3268 
3269 	int isservice;
3270 	int ret;
3271 	scf_transaction_entry_t *e;
3272 	scf_value_t *val;
3273 	scf_callback_t dependent_cbdata;
3274 	scf_error_t scfe;
3275 
3276 	/*
3277 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3278 	 * it's invalid, we fail before modifying the repository.
3279 	 */
3280 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3281 	    &dependent_cbdata.sc_parent, &isservice);
3282 	switch (scfe) {
3283 	case SCF_ERROR_NONE:
3284 		break;
3285 
3286 	case SCF_ERROR_NO_MEMORY:
3287 		return (stash_scferror_err(lcbdata, scfe));
3288 
3289 	case SCF_ERROR_INVALID_ARGUMENT:
3290 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3291 		    "invalid.\n"), pgrp->sc_pgroup_name);
3292 		return (stash_scferror_err(lcbdata, scfe));
3293 
3294 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3295 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3296 		    "specifies neither a service nor an instance.\n"),
3297 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3298 		return (stash_scferror_err(lcbdata, scfe));
3299 
3300 	case SCF_ERROR_NOT_FOUND:
3301 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3302 		    &dependent_cbdata.sc_parent, &isservice);
3303 		switch (scfe) {
3304 		case SCF_ERROR_NONE:
3305 			break;
3306 
3307 		case SCF_ERROR_NO_MEMORY:
3308 		case SCF_ERROR_BACKEND_READONLY:
3309 		case SCF_ERROR_BACKEND_ACCESS:
3310 			return (stash_scferror_err(lcbdata, scfe));
3311 
3312 		case SCF_ERROR_NOT_FOUND:
3313 			semerr(gettext("The scope in FMRI \"%s\" for the "
3314 			    "\"%s\" dependent does not exist.\n"),
3315 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3316 			lcbdata->sc_err = EINVAL;
3317 			return (UU_WALK_ERROR);
3318 
3319 		case SCF_ERROR_PERMISSION_DENIED:
3320 			warn(gettext(
3321 			    "Could not create %s (permission denied).\n"),
3322 			    pgrp->sc_pgroup_fmri);
3323 			return (stash_scferror_err(lcbdata, scfe));
3324 
3325 		case SCF_ERROR_INVALID_ARGUMENT:
3326 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3327 		default:
3328 			bad_error("create_entity", scfe);
3329 		}
3330 		break;
3331 
3332 	default:
3333 		bad_error("fmri_to_entity", scfe);
3334 	}
3335 
3336 	if (lcbdata->sc_trans != NULL) {
3337 		e = scf_entry_create(lcbdata->sc_handle);
3338 		if (e == NULL) {
3339 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3340 				bad_error("scf_entry_create", scf_error());
3341 
3342 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3343 			return (stash_scferror(lcbdata));
3344 		}
3345 
3346 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3347 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3348 			switch (scf_error()) {
3349 			case SCF_ERROR_INVALID_ARGUMENT:
3350 				warn(gettext("Dependent of %s has invalid name "
3351 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3352 				    pgrp->sc_pgroup_name);
3353 				/* FALLTHROUGH */
3354 
3355 			case SCF_ERROR_DELETED:
3356 			case SCF_ERROR_CONNECTION_BROKEN:
3357 				scf_entry_destroy(e);
3358 				entity_destroy(dependent_cbdata.sc_parent,
3359 				    isservice);
3360 				return (stash_scferror(lcbdata));
3361 
3362 			case SCF_ERROR_EXISTS:
3363 				scf_entry_destroy(e);
3364 				entity_destroy(dependent_cbdata.sc_parent,
3365 				    isservice);
3366 				lcbdata->sc_err = EALREADY;
3367 				return (UU_WALK_ERROR);
3368 
3369 			case SCF_ERROR_NOT_BOUND:
3370 			case SCF_ERROR_HANDLE_MISMATCH:
3371 			case SCF_ERROR_NOT_SET:
3372 			default:
3373 				bad_error("scf_transaction_property_new",
3374 				    scf_error());
3375 			}
3376 		}
3377 
3378 		val = scf_value_create(lcbdata->sc_handle);
3379 		if (val == NULL) {
3380 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3381 				bad_error("scf_value_create", scf_error());
3382 
3383 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3384 			return (stash_scferror(lcbdata));
3385 		}
3386 
3387 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3388 		    pgrp->sc_pgroup_fmri) != 0)
3389 			/* invalid should have been caught above */
3390 			bad_error("scf_value_set_from_string", scf_error());
3391 
3392 		if (scf_entry_add_value(e, val) != 0)
3393 			bad_error("scf_entry_add_value", scf_error());
3394 	}
3395 
3396 	/* Add the property group to the target entity. */
3397 
3398 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3399 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3400 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3401 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3402 
3403 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3404 
3405 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3406 
3407 	if (ret == UU_WALK_NEXT)
3408 		return (ret);
3409 
3410 	if (ret != UU_WALK_ERROR)
3411 		bad_error("entity_pgroup_import", ret);
3412 
3413 	switch (dependent_cbdata.sc_err) {
3414 	case ECANCELED:
3415 		warn(gettext("%s deleted unexpectedly.\n"),
3416 		    pgrp->sc_pgroup_fmri);
3417 		lcbdata->sc_err = EBUSY;
3418 		break;
3419 
3420 	case EEXIST:
3421 		warn(gettext("Could not create \"%s\" dependency in %s "
3422 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3423 		    pgrp->sc_pgroup_fmri);
3424 		/* FALLTHROUGH */
3425 
3426 	default:
3427 		lcbdata->sc_err = dependent_cbdata.sc_err;
3428 	}
3429 
3430 	return (UU_WALK_ERROR);
3431 }
3432 
3433 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3434     const scf_snaplevel_t *, scf_transaction_t *);
3435 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3436     const pgroup_t *);
3437 
3438 /*
3439  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3440  * the current dependent targets from running (the snaplevel of a running
3441  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3442  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3443  * dependent targets and dependency properties from li_dpts_pg (the
3444  * "dependents" property group in snpl) and snpl (the snaplevel which
3445  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3446  * snpl doesn't have a "dependents" property group, and any dependents in ient
3447  * are new.
3448  *
3449  * Returns
3450  *   0 - success
3451  *   ECONNABORTED - repository connection broken
3452  *   ENOMEM - out of memory
3453  *   ENOSPC - configd is out of resources
3454  *   ECANCELED - ent was deleted
3455  *   ENODEV - the entity containing li_dpts_pg was deleted
3456  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3457  *	   - couldn't upgrade dependent (permission denied) (error printed)
3458  *	   - couldn't create dependent (permission denied) (error printed)
3459  *   EROFS - could not modify dependents pg (repository read-only)
3460  *	   - couldn't upgrade dependent (repository read-only)
3461  *	   - couldn't create dependent (repository read-only)
3462  *   EACCES - could not modify dependents pg (backend access denied)
3463  *	    - could not upgrade dependent (backend access denied)
3464  *	    - could not create dependent (backend access denied)
3465  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3466  *	   - dependent target deleted (error printed)
3467  *	   - dependent pg changed (error printed)
3468  *   EINVAL - new dependent is invalid (error printed)
3469  *   EBADF - snpl is corrupt (error printed)
3470  *	   - snpl has corrupt pg (error printed)
3471  *	   - dependency pg in target is corrupt (error printed)
3472  *	   - target has corrupt snapshot (error printed)
3473  *   EEXIST - dependency pg already existed in target service (error printed)
3474  */
3475 static int
3476 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3477     const scf_snaplevel_t *snpl, const entity_t *ient,
3478     const scf_snaplevel_t *running, void *ent)
3479 {
3480 	pgroup_t *new_dpt_pgroup;
3481 	scf_callback_t cbdata;
3482 	int r, unseen, tx_started = 0;
3483 	int have_cur_depts;
3484 
3485 	const char * const dependents = "dependents";
3486 
3487 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3488 
3489 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3490 		/* Nothing to do. */
3491 		return (0);
3492 
3493 	/* Fetch the current version of the "dependents" property group. */
3494 	have_cur_depts = 1;
3495 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3496 		switch (scf_error()) {
3497 		case SCF_ERROR_NOT_FOUND:
3498 			break;
3499 
3500 		case SCF_ERROR_DELETED:
3501 		case SCF_ERROR_CONNECTION_BROKEN:
3502 			return (scferror2errno(scf_error()));
3503 
3504 		case SCF_ERROR_NOT_SET:
3505 		case SCF_ERROR_INVALID_ARGUMENT:
3506 		case SCF_ERROR_HANDLE_MISMATCH:
3507 		case SCF_ERROR_NOT_BOUND:
3508 		default:
3509 			bad_error("entity_get_pg", scf_error());
3510 		}
3511 
3512 		have_cur_depts = 0;
3513 	}
3514 
3515 	/* Fetch the running version of the "dependents" property group. */
3516 	ud_run_dpts_pg_set = 0;
3517 	if (running != NULL)
3518 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3519 	else
3520 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3521 	if (r == 0) {
3522 		ud_run_dpts_pg_set = 1;
3523 	} else {
3524 		switch (scf_error()) {
3525 		case SCF_ERROR_NOT_FOUND:
3526 			break;
3527 
3528 		case SCF_ERROR_DELETED:
3529 		case SCF_ERROR_CONNECTION_BROKEN:
3530 			return (scferror2errno(scf_error()));
3531 
3532 		case SCF_ERROR_NOT_SET:
3533 		case SCF_ERROR_INVALID_ARGUMENT:
3534 		case SCF_ERROR_HANDLE_MISMATCH:
3535 		case SCF_ERROR_NOT_BOUND:
3536 		default:
3537 			bad_error(running ? "scf_snaplevel_get_pg" :
3538 			    "entity_get_pg", scf_error());
3539 		}
3540 	}
3541 
3542 	/*
3543 	 * Clear the seen fields of the dependents, so we can tell which ones
3544 	 * are new.
3545 	 */
3546 	if (uu_list_walk(ient->sc_dependents, clear_int,
3547 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3548 		bad_error("uu_list_walk", uu_error());
3549 
3550 	if (li_dpts_pg != NULL) {
3551 		/*
3552 		 * Each property in li_dpts_pg represents a dependent tag in
3553 		 * the old manifest.  For each, call upgrade_dependent(),
3554 		 * which will change ud_cur_depts_pg or dependencies in other
3555 		 * services as appropriate.  Note (a) that changes to
3556 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3557 		 * made en masse, and (b) it's ok if the entity doesn't have
3558 		 * a current version of the "dependents" property group,
3559 		 * because we'll just consider all dependents as customized
3560 		 * (by being deleted).
3561 		 */
3562 
3563 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3564 			switch (scf_error()) {
3565 			case SCF_ERROR_DELETED:
3566 				return (ENODEV);
3567 
3568 			case SCF_ERROR_CONNECTION_BROKEN:
3569 				return (ECONNABORTED);
3570 
3571 			case SCF_ERROR_HANDLE_MISMATCH:
3572 			case SCF_ERROR_NOT_BOUND:
3573 			case SCF_ERROR_NOT_SET:
3574 			default:
3575 				bad_error("scf_iter_pg_properties",
3576 				    scf_error());
3577 			}
3578 		}
3579 
3580 		if (have_cur_depts &&
3581 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3582 			switch (scf_error()) {
3583 			case SCF_ERROR_BACKEND_ACCESS:
3584 			case SCF_ERROR_BACKEND_READONLY:
3585 			case SCF_ERROR_CONNECTION_BROKEN:
3586 				return (scferror2errno(scf_error()));
3587 
3588 			case SCF_ERROR_DELETED:
3589 				warn(emsg_pg_deleted, ient->sc_fmri,
3590 				    dependents);
3591 				return (EBUSY);
3592 
3593 			case SCF_ERROR_PERMISSION_DENIED:
3594 				warn(emsg_pg_mod_perm, dependents,
3595 				    ient->sc_fmri);
3596 				return (scferror2errno(scf_error()));
3597 
3598 			case SCF_ERROR_HANDLE_MISMATCH:
3599 			case SCF_ERROR_IN_USE:
3600 			case SCF_ERROR_NOT_BOUND:
3601 			case SCF_ERROR_NOT_SET:
3602 			default:
3603 				bad_error("scf_transaction_start", scf_error());
3604 			}
3605 		}
3606 		tx_started = have_cur_depts;
3607 
3608 		for (;;) {
3609 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3610 			if (r == 0)
3611 				break;
3612 			if (r == 1) {
3613 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3614 				    tx_started ? ud_tx : NULL);
3615 				switch (r) {
3616 				case 0:
3617 					continue;
3618 
3619 				case ECONNABORTED:
3620 				case ENOMEM:
3621 				case ENOSPC:
3622 				case EBADF:
3623 				case EBUSY:
3624 				case EINVAL:
3625 				case EPERM:
3626 				case EROFS:
3627 				case EACCES:
3628 				case EEXIST:
3629 					break;
3630 
3631 				case ECANCELED:
3632 					r = ENODEV;
3633 					break;
3634 
3635 				default:
3636 					bad_error("upgrade_dependent", r);
3637 				}
3638 
3639 				if (tx_started)
3640 					scf_transaction_destroy_children(ud_tx);
3641 				return (r);
3642 			}
3643 			if (r != -1)
3644 				bad_error("scf_iter_next_property", r);
3645 
3646 			switch (scf_error()) {
3647 			case SCF_ERROR_DELETED:
3648 				r = ENODEV;
3649 				break;
3650 
3651 			case SCF_ERROR_CONNECTION_BROKEN:
3652 				r = ECONNABORTED;
3653 				break;
3654 
3655 			case SCF_ERROR_NOT_SET:
3656 			case SCF_ERROR_INVALID_ARGUMENT:
3657 			case SCF_ERROR_NOT_BOUND:
3658 			case SCF_ERROR_HANDLE_MISMATCH:
3659 			default:
3660 				bad_error("scf_iter_next_property",
3661 				    scf_error());
3662 			}
3663 
3664 			if (tx_started)
3665 				scf_transaction_destroy_children(ud_tx);
3666 			return (r);
3667 		}
3668 	}
3669 
3670 	/* import unseen dependents */
3671 	unseen = 0;
3672 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3673 	    new_dpt_pgroup != NULL;
3674 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3675 	    new_dpt_pgroup)) {
3676 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3677 			unseen = 1;
3678 			break;
3679 		}
3680 	}
3681 
3682 	/* If there are none, exit early. */
3683 	if (unseen == 0)
3684 		goto commit;
3685 
3686 	/* Set up for lscf_dependent_import() */
3687 	cbdata.sc_handle = g_hndl;
3688 	cbdata.sc_parent = ent;
3689 	cbdata.sc_service = issvc;
3690 	cbdata.sc_flags = 0;
3691 
3692 	if (!have_cur_depts) {
3693 		/*
3694 		 * We have new dependents to import, so we need a "dependents"
3695 		 * property group.
3696 		 */
3697 		if (issvc)
3698 			r = scf_service_add_pg(ent, dependents,
3699 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3700 		else
3701 			r = scf_instance_add_pg(ent, dependents,
3702 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3703 		if (r != 0) {
3704 			switch (scf_error()) {
3705 			case SCF_ERROR_DELETED:
3706 			case SCF_ERROR_CONNECTION_BROKEN:
3707 			case SCF_ERROR_BACKEND_READONLY:
3708 			case SCF_ERROR_BACKEND_ACCESS:
3709 			case SCF_ERROR_NO_RESOURCES:
3710 				return (scferror2errno(scf_error()));
3711 
3712 			case SCF_ERROR_EXISTS:
3713 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3714 				return (EBUSY);
3715 
3716 			case SCF_ERROR_PERMISSION_DENIED:
3717 				warn(emsg_pg_add_perm, dependents,
3718 				    ient->sc_fmri);
3719 				return (scferror2errno(scf_error()));
3720 
3721 			case SCF_ERROR_NOT_BOUND:
3722 			case SCF_ERROR_HANDLE_MISMATCH:
3723 			case SCF_ERROR_INVALID_ARGUMENT:
3724 			case SCF_ERROR_NOT_SET:
3725 			default:
3726 				bad_error("scf_service_add_pg", scf_error());
3727 			}
3728 		}
3729 	}
3730 
3731 	cbdata.sc_trans = ud_tx;
3732 
3733 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3734 		switch (scf_error()) {
3735 		case SCF_ERROR_CONNECTION_BROKEN:
3736 		case SCF_ERROR_BACKEND_ACCESS:
3737 		case SCF_ERROR_BACKEND_READONLY:
3738 			return (scferror2errno(scf_error()));
3739 
3740 		case SCF_ERROR_DELETED:
3741 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3742 			return (EBUSY);
3743 
3744 		case SCF_ERROR_PERMISSION_DENIED:
3745 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3746 			return (scferror2errno(scf_error()));
3747 
3748 		case SCF_ERROR_HANDLE_MISMATCH:
3749 		case SCF_ERROR_IN_USE:
3750 		case SCF_ERROR_NOT_BOUND:
3751 		case SCF_ERROR_NOT_SET:
3752 		default:
3753 			bad_error("scf_transaction_start", scf_error());
3754 		}
3755 	}
3756 	tx_started = 1;
3757 
3758 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3759 	    new_dpt_pgroup != NULL;
3760 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3761 	    new_dpt_pgroup)) {
3762 		if (new_dpt_pgroup->sc_pgroup_seen)
3763 			continue;
3764 
3765 		if (ud_run_dpts_pg_set) {
3766 			/*
3767 			 * If the dependent is already there, then we have
3768 			 * a conflict.
3769 			 */
3770 			if (scf_pg_get_property(ud_run_dpts_pg,
3771 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3772 				r = handle_dependent_conflict(ient, ud_prop,
3773 				    new_dpt_pgroup);
3774 				switch (r) {
3775 				case 0:
3776 					continue;
3777 
3778 				case ECONNABORTED:
3779 				case ENOMEM:
3780 				case EBUSY:
3781 				case EBADF:
3782 				case EINVAL:
3783 					scf_transaction_destroy_children(ud_tx);
3784 					return (r);
3785 
3786 				default:
3787 					bad_error("handle_dependent_conflict",
3788 					    r);
3789 				}
3790 			} else {
3791 				switch (scf_error()) {
3792 				case SCF_ERROR_NOT_FOUND:
3793 					break;
3794 
3795 				case SCF_ERROR_INVALID_ARGUMENT:
3796 					warn(emsg_fmri_invalid_pg_name,
3797 					    ient->sc_fmri,
3798 					    new_dpt_pgroup->sc_pgroup_name);
3799 					scf_transaction_destroy_children(ud_tx);
3800 					return (EINVAL);
3801 
3802 				case SCF_ERROR_DELETED:
3803 					warn(emsg_pg_deleted, ient->sc_fmri,
3804 					    new_dpt_pgroup->sc_pgroup_name);
3805 					scf_transaction_destroy_children(ud_tx);
3806 					return (EBUSY);
3807 
3808 				case SCF_ERROR_CONNECTION_BROKEN:
3809 					scf_transaction_destroy_children(ud_tx);
3810 					return (ECONNABORTED);
3811 
3812 				case SCF_ERROR_NOT_BOUND:
3813 				case SCF_ERROR_HANDLE_MISMATCH:
3814 				case SCF_ERROR_NOT_SET:
3815 				default:
3816 					bad_error("scf_pg_get_property",
3817 					    scf_error());
3818 				}
3819 			}
3820 		}
3821 
3822 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3823 		if (r != UU_WALK_NEXT) {
3824 			if (r != UU_WALK_ERROR)
3825 				bad_error("lscf_dependent_import", r);
3826 
3827 			if (cbdata.sc_err == EALREADY) {
3828 				/* Collisions were handled preemptively. */
3829 				bad_error("lscf_dependent_import",
3830 				    cbdata.sc_err);
3831 			}
3832 
3833 			scf_transaction_destroy_children(ud_tx);
3834 			return (cbdata.sc_err);
3835 		}
3836 	}
3837 
3838 commit:
3839 	if (!tx_started)
3840 		return (0);
3841 
3842 	r = scf_transaction_commit(ud_tx);
3843 
3844 	scf_transaction_destroy_children(ud_tx);
3845 
3846 	switch (r) {
3847 	case 1:
3848 		return (0);
3849 
3850 	case 0:
3851 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3852 		return (EBUSY);
3853 
3854 	case -1:
3855 		break;
3856 
3857 	default:
3858 		bad_error("scf_transaction_commit", r);
3859 	}
3860 
3861 	switch (scf_error()) {
3862 	case SCF_ERROR_CONNECTION_BROKEN:
3863 	case SCF_ERROR_BACKEND_READONLY:
3864 	case SCF_ERROR_BACKEND_ACCESS:
3865 	case SCF_ERROR_NO_RESOURCES:
3866 		return (scferror2errno(scf_error()));
3867 
3868 	case SCF_ERROR_DELETED:
3869 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3870 		return (EBUSY);
3871 
3872 	case SCF_ERROR_PERMISSION_DENIED:
3873 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3874 		return (scferror2errno(scf_error()));
3875 
3876 	case SCF_ERROR_NOT_BOUND:
3877 	case SCF_ERROR_INVALID_ARGUMENT:
3878 	case SCF_ERROR_NOT_SET:
3879 	default:
3880 		bad_error("scf_transaction_destroy", scf_error());
3881 		/* NOTREACHED */
3882 	}
3883 }
3884 
3885 /*
3886  * Used to add the manifests to the list of currently supported manifests.
3887  * We can modify the existing manifest list removing entries if the files
3888  * don't exist.
3889  *
3890  * Get the old list and the new file name
3891  * If the new file name is in the list return
3892  * If not then add the file to the list.
3893  * As we process the list check to see if the files in the old list exist
3894  * 	if not then remove the file from the list.
3895  * Commit the list of manifest file names.
3896  *
3897  */
3898 static int
3899 upgrade_manifestfiles(pgroup_t *pg, entity_t *ient,
3900     const scf_snaplevel_t *running, void *ent)
3901 {
3902 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3903 	scf_property_t *ud_prop = NULL;
3904 	scf_iter_t *ud_prop_iter;
3905 	scf_value_t *fname_value;
3906 	scf_callback_t cbdata;
3907 	pgroup_t *mfst_pgroup;
3908 	property_t *mfst_prop;
3909 	property_t *old_prop;
3910 	char *pname;
3911 	char *fval;
3912 	char *old_pname;
3913 	char *old_fval;
3914 	int no_upgrade_pg;
3915 	int mfst_seen;
3916 	int r;
3917 
3918 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3919 
3920 	/*
3921 	 * This should always be the service base on the code
3922 	 * path, and the fact that the manifests pg is a service
3923 	 * level property group only.
3924 	 */
3925 	ud_mfsts_pg = scf_pg_create(g_hndl);
3926 	ud_prop = scf_property_create(g_hndl);
3927 	ud_prop_iter = scf_iter_create(g_hndl);
3928 	fname_value = scf_value_create(g_hndl);
3929 
3930 	/* Fetch the "manifests" property group */
3931 	no_upgrade_pg = 0;
3932 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3933 	    ud_mfsts_pg);
3934 	if (r != 0) {
3935 		switch (scf_error()) {
3936 		case SCF_ERROR_NOT_FOUND:
3937 			no_upgrade_pg = 1;
3938 			break;
3939 
3940 		case SCF_ERROR_DELETED:
3941 		case SCF_ERROR_CONNECTION_BROKEN:
3942 			return (scferror2errno(scf_error()));
3943 
3944 		case SCF_ERROR_NOT_SET:
3945 		case SCF_ERROR_INVALID_ARGUMENT:
3946 		case SCF_ERROR_HANDLE_MISMATCH:
3947 		case SCF_ERROR_NOT_BOUND:
3948 		default:
3949 			bad_error(running ? "scf_snaplevel_get_pg" :
3950 			    "entity_get_pg", scf_error());
3951 		}
3952 	}
3953 
3954 	if (no_upgrade_pg) {
3955 		cbdata.sc_handle = g_hndl;
3956 		cbdata.sc_parent = ent;
3957 		cbdata.sc_service = issvc;
3958 		cbdata.sc_flags = SCI_FORCE;
3959 		cbdata.sc_source_fmri = ient->sc_fmri;
3960 		cbdata.sc_target_fmri = ient->sc_fmri;
3961 
3962 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3963 			return (cbdata.sc_err);
3964 
3965 		return (0);
3966 	}
3967 
3968 	/* Fetch the new manifests property group */
3969 	mfst_pgroup = internal_pgroup_find_or_create(ient,
3970 	    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
3971 	assert(mfst_pgroup != NULL);
3972 
3973 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3974 	    SCF_SUCCESS)
3975 		return (-1);
3976 
3977 	if ((pname = malloc(MAXPATHLEN)) == NULL)
3978 		return (ENOMEM);
3979 	if ((fval = malloc(MAXPATHLEN)) == NULL) {
3980 		free(pname);
3981 		return (ENOMEM);
3982 	}
3983 
3984 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3985 		mfst_seen = 0;
3986 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3987 			continue;
3988 
3989 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3990 		    mfst_prop != NULL;
3991 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3992 		    mfst_prop)) {
3993 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3994 				mfst_seen = 1;
3995 			}
3996 		}
3997 
3998 		/*
3999 		 * If the manifest is not seen then add it to the new mfst
4000 		 * property list to get proccessed into the repo.
4001 		 */
4002 		if (mfst_seen == 0) {
4003 			/*
4004 			 * If we cannot get the value then there is no
4005 			 * reason to attempt to attach the value to
4006 			 * the property group
4007 			 */
4008 			if (prop_get_val(ud_prop, fname_value) == 0 &&
4009 			    scf_value_get_astring(fname_value, fval,
4010 			    MAXPATHLEN) != -1)  {
4011 				old_pname = safe_strdup(pname);
4012 				old_fval = safe_strdup(fval);
4013 				old_prop = internal_property_create(old_pname,
4014 				    SCF_TYPE_ASTRING, 1, old_fval);
4015 
4016 				/*
4017 				 * Already checked to see if the property exists
4018 				 * in the group, and it does not.
4019 				 */
4020 				(void) internal_attach_property(mfst_pgroup,
4021 				    old_prop);
4022 			}
4023 		}
4024 	}
4025 	free(pname);
4026 	free(fval);
4027 
4028 	cbdata.sc_handle = g_hndl;
4029 	cbdata.sc_parent = ent;
4030 	cbdata.sc_service = issvc;
4031 	cbdata.sc_flags = SCI_FORCE;
4032 	cbdata.sc_source_fmri = ient->sc_fmri;
4033 	cbdata.sc_target_fmri = ient->sc_fmri;
4034 
4035 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4036 		return (cbdata.sc_err);
4037 
4038 	return (r);
4039 }
4040 
4041 /*
4042  * prop is taken to be a property in the "dependents" property group of snpl,
4043  * which is taken to be the snaplevel of a last-import snapshot corresponding
4044  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4045  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4046  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4047  * of the entity ient represents (possibly in the running snapshot).  If it
4048  * needs to be changed, an entry will be added to tx, if not NULL.
4049  *
4050  * Returns
4051  *   0 - success
4052  *   ECONNABORTED - repository connection broken
4053  *   ENOMEM - out of memory
4054  *   ENOSPC - configd was out of resources
4055  *   ECANCELED - snpl's entity was deleted
4056  *   EINVAL - dependent target is invalid (error printed)
4057  *	    - dependent is invalid (error printed)
4058  *   EBADF - snpl is corrupt (error printed)
4059  *	   - snpl has corrupt pg (error printed)
4060  *	   - dependency pg in target is corrupt (error printed)
4061  *	   - running snapshot in dependent is missing snaplevel (error printed)
4062  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4063  *	   - couldn't create dependent (permission denied) (error printed)
4064  *	   - couldn't modify dependent pg (permission denied) (error printed)
4065  *   EROFS - couldn't delete dependency pg (repository read-only)
4066  *	   - couldn't create dependent (repository read-only)
4067  *   EACCES - couldn't delete dependency pg (backend access denied)
4068  *	    - couldn't create dependent (backend access denied)
4069  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4070  *	   - tx's pg was deleted (error printed)
4071  *	   - dependent pg was changed or deleted (error printed)
4072  *   EEXIST - dependency pg already exists in new target (error printed)
4073  */
4074 static int
4075 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4076     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4077 {
4078 	pgroup_t pgrp;
4079 	scf_type_t ty;
4080 	pgroup_t *new_dpt_pgroup;
4081 	pgroup_t *old_dpt_pgroup = NULL;
4082 	pgroup_t *current_pg;
4083 	pgroup_t *dpt;
4084 	scf_callback_t cbdata;
4085 	int tissvc;
4086 	void *target_ent;
4087 	scf_error_t serr;
4088 	int r;
4089 	scf_transaction_entry_t *ent;
4090 
4091 	const char * const cf_inval = gettext("Conflict upgrading %s "
4092 	    "(dependent \"%s\" has invalid dependents property).\n");
4093 	const char * const cf_missing = gettext("Conflict upgrading %s "
4094 	    "(dependent \"%s\" is missing).\n");
4095 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4096 	    "(dependent \"%s\" has new dependency property group).\n");
4097 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4098 	    "(dependent \"%s\" has new target).\n");
4099 	const char * const li_corrupt =
4100 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4101 	const char * const upgrading =
4102 	    gettext("%s: Upgrading dependent \"%s\".\n");
4103 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4104 	    "corrupt (missing snaplevel).\n");
4105 
4106 	if (scf_property_type(prop, &ty) != 0) {
4107 		switch (scf_error()) {
4108 		case SCF_ERROR_DELETED:
4109 		case SCF_ERROR_CONNECTION_BROKEN:
4110 			return (scferror2errno(scf_error()));
4111 
4112 		case SCF_ERROR_NOT_BOUND:
4113 		case SCF_ERROR_NOT_SET:
4114 		default:
4115 			bad_error("scf_property_type", scf_error());
4116 		}
4117 	}
4118 
4119 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4120 		warn(li_corrupt, ient->sc_fmri);
4121 		return (EBADF);
4122 	}
4123 
4124 	/*
4125 	 * prop represents a dependent in the old manifest.  It is named after
4126 	 * the dependent.
4127 	 */
4128 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4129 		switch (scf_error()) {
4130 		case SCF_ERROR_DELETED:
4131 		case SCF_ERROR_CONNECTION_BROKEN:
4132 			return (scferror2errno(scf_error()));
4133 
4134 		case SCF_ERROR_NOT_BOUND:
4135 		case SCF_ERROR_NOT_SET:
4136 		default:
4137 			bad_error("scf_property_get_name", scf_error());
4138 		}
4139 	}
4140 
4141 	/* See if it's in the new manifest. */
4142 	pgrp.sc_pgroup_name = ud_name;
4143 	new_dpt_pgroup =
4144 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4145 
4146 	/* If it's not, delete it... if it hasn't been customized. */
4147 	if (new_dpt_pgroup == NULL) {
4148 		if (!ud_run_dpts_pg_set)
4149 			return (0);
4150 
4151 		if (scf_property_get_value(prop, ud_val) != 0) {
4152 			switch (scf_error()) {
4153 			case SCF_ERROR_NOT_FOUND:
4154 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4155 				warn(li_corrupt, ient->sc_fmri);
4156 				return (EBADF);
4157 
4158 			case SCF_ERROR_DELETED:
4159 			case SCF_ERROR_CONNECTION_BROKEN:
4160 				return (scferror2errno(scf_error()));
4161 
4162 			case SCF_ERROR_HANDLE_MISMATCH:
4163 			case SCF_ERROR_NOT_BOUND:
4164 			case SCF_ERROR_NOT_SET:
4165 			case SCF_ERROR_PERMISSION_DENIED:
4166 			default:
4167 				bad_error("scf_property_get_value",
4168 				    scf_error());
4169 			}
4170 		}
4171 
4172 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4173 		    max_scf_value_len + 1) < 0)
4174 			bad_error("scf_value_get_as_string", scf_error());
4175 
4176 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4177 		    0) {
4178 			switch (scf_error()) {
4179 			case SCF_ERROR_NOT_FOUND:
4180 				return (0);
4181 
4182 			case SCF_ERROR_CONNECTION_BROKEN:
4183 				return (scferror2errno(scf_error()));
4184 
4185 			case SCF_ERROR_DELETED:
4186 				warn(emsg_pg_deleted, ient->sc_fmri,
4187 				    "dependents");
4188 				return (EBUSY);
4189 
4190 			case SCF_ERROR_INVALID_ARGUMENT:
4191 			case SCF_ERROR_NOT_BOUND:
4192 			case SCF_ERROR_HANDLE_MISMATCH:
4193 			case SCF_ERROR_NOT_SET:
4194 			default:
4195 				bad_error("scf_pg_get_property", scf_error());
4196 			}
4197 		}
4198 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4199 			switch (scf_error()) {
4200 			case SCF_ERROR_NOT_FOUND:
4201 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4202 				warn(cf_inval, ient->sc_fmri, ud_name);
4203 				return (0);
4204 
4205 			case SCF_ERROR_DELETED:
4206 			case SCF_ERROR_CONNECTION_BROKEN:
4207 				return (scferror2errno(scf_error()));
4208 
4209 			case SCF_ERROR_HANDLE_MISMATCH:
4210 			case SCF_ERROR_NOT_BOUND:
4211 			case SCF_ERROR_NOT_SET:
4212 			case SCF_ERROR_PERMISSION_DENIED:
4213 			default:
4214 				bad_error("scf_property_get_value",
4215 				    scf_error());
4216 			}
4217 		}
4218 
4219 		ty = scf_value_type(ud_val);
4220 		assert(ty != SCF_TYPE_INVALID);
4221 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4222 			warn(cf_inval, ient->sc_fmri, ud_name);
4223 			return (0);
4224 		}
4225 
4226 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4227 		    max_scf_value_len + 1) < 0)
4228 			bad_error("scf_value_get_as_string", scf_error());
4229 
4230 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4231 		switch (r) {
4232 		case 1:
4233 			break;
4234 
4235 		case 0:
4236 		case -1:	/* warn? */
4237 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4238 			return (0);
4239 
4240 		case -2:
4241 			warn(li_corrupt, ient->sc_fmri);
4242 			return (EBADF);
4243 
4244 		default:
4245 			bad_error("fmri_equal", r);
4246 		}
4247 
4248 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4249 			switch (scf_error()) {
4250 			case SCF_ERROR_NOT_FOUND:
4251 				warn(li_corrupt, ient->sc_fmri);
4252 				return (EBADF);
4253 
4254 			case SCF_ERROR_DELETED:
4255 			case SCF_ERROR_CONNECTION_BROKEN:
4256 				return (scferror2errno(scf_error()));
4257 
4258 			case SCF_ERROR_NOT_BOUND:
4259 			case SCF_ERROR_HANDLE_MISMATCH:
4260 			case SCF_ERROR_INVALID_ARGUMENT:
4261 			case SCF_ERROR_NOT_SET:
4262 			default:
4263 				bad_error("scf_snaplevel_get_pg", scf_error());
4264 			}
4265 		}
4266 
4267 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4268 		    snap_lastimport);
4269 		switch (r) {
4270 		case 0:
4271 			break;
4272 
4273 		case ECANCELED:
4274 		case ECONNABORTED:
4275 		case ENOMEM:
4276 		case EBADF:
4277 			return (r);
4278 
4279 		case EACCES:
4280 		default:
4281 			bad_error("load_pg", r);
4282 		}
4283 
4284 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4285 		switch (serr) {
4286 		case SCF_ERROR_NONE:
4287 			break;
4288 
4289 		case SCF_ERROR_NO_MEMORY:
4290 			internal_pgroup_free(old_dpt_pgroup);
4291 			return (ENOMEM);
4292 
4293 		case SCF_ERROR_NOT_FOUND:
4294 			internal_pgroup_free(old_dpt_pgroup);
4295 			goto delprop;
4296 
4297 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4298 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4299 		default:
4300 			bad_error("fmri_to_entity", serr);
4301 		}
4302 
4303 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4304 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4305 		switch (r) {
4306 		case 0:
4307 			break;
4308 
4309 		case ECONNABORTED:
4310 			internal_pgroup_free(old_dpt_pgroup);
4311 			return (r);
4312 
4313 		case ECANCELED:
4314 		case ENOENT:
4315 			internal_pgroup_free(old_dpt_pgroup);
4316 			goto delprop;
4317 
4318 		case EBADF:
4319 			warn(r_no_lvl, ud_ctarg);
4320 			internal_pgroup_free(old_dpt_pgroup);
4321 			return (r);
4322 
4323 		case EINVAL:
4324 		default:
4325 			bad_error("entity_get_running_pg", r);
4326 		}
4327 
4328 		/* load it */
4329 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4330 		switch (r) {
4331 		case 0:
4332 			break;
4333 
4334 		case ECANCELED:
4335 			internal_pgroup_free(old_dpt_pgroup);
4336 			goto delprop;
4337 
4338 		case ECONNABORTED:
4339 		case ENOMEM:
4340 		case EBADF:
4341 			internal_pgroup_free(old_dpt_pgroup);
4342 			return (r);
4343 
4344 		case EACCES:
4345 		default:
4346 			bad_error("load_pg", r);
4347 		}
4348 
4349 		/* compare property groups */
4350 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4351 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4352 			internal_pgroup_free(old_dpt_pgroup);
4353 			internal_pgroup_free(current_pg);
4354 			return (0);
4355 		}
4356 
4357 		internal_pgroup_free(old_dpt_pgroup);
4358 		internal_pgroup_free(current_pg);
4359 
4360 		if (g_verbose)
4361 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4362 			    ient->sc_fmri, ud_name);
4363 
4364 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4365 			switch (scf_error()) {
4366 			case SCF_ERROR_NOT_FOUND:
4367 			case SCF_ERROR_DELETED:
4368 				internal_pgroup_free(old_dpt_pgroup);
4369 				goto delprop;
4370 
4371 			case SCF_ERROR_CONNECTION_BROKEN:
4372 				internal_pgroup_free(old_dpt_pgroup);
4373 				return (ECONNABORTED);
4374 
4375 			case SCF_ERROR_NOT_SET:
4376 			case SCF_ERROR_INVALID_ARGUMENT:
4377 			case SCF_ERROR_HANDLE_MISMATCH:
4378 			case SCF_ERROR_NOT_BOUND:
4379 			default:
4380 				bad_error("entity_get_pg", scf_error());
4381 			}
4382 		}
4383 
4384 		if (scf_pg_delete(ud_pg) != 0) {
4385 			switch (scf_error()) {
4386 			case SCF_ERROR_DELETED:
4387 				break;
4388 
4389 			case SCF_ERROR_CONNECTION_BROKEN:
4390 			case SCF_ERROR_BACKEND_READONLY:
4391 			case SCF_ERROR_BACKEND_ACCESS:
4392 				return (scferror2errno(scf_error()));
4393 
4394 			case SCF_ERROR_PERMISSION_DENIED:
4395 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4396 				return (scferror2errno(scf_error()));
4397 
4398 			case SCF_ERROR_NOT_SET:
4399 			default:
4400 				bad_error("scf_pg_delete", scf_error());
4401 			}
4402 		}
4403 
4404 		/*
4405 		 * This service was changed, so it must be refreshed.  But
4406 		 * since it's not mentioned in the new manifest, we have to
4407 		 * record its FMRI here for use later.  We record the name
4408 		 * & the entity (via sc_parent) in case we need to print error
4409 		 * messages during the refresh.
4410 		 */
4411 		dpt = internal_pgroup_new();
4412 		if (dpt == NULL)
4413 			return (ENOMEM);
4414 		dpt->sc_pgroup_name = strdup(ud_name);
4415 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4416 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4417 			return (ENOMEM);
4418 		dpt->sc_parent = (entity_t *)ient;
4419 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4420 			uu_die(gettext("libuutil error: %s\n"),
4421 			    uu_strerror(uu_error()));
4422 
4423 delprop:
4424 		if (tx == NULL)
4425 			return (0);
4426 
4427 		ent = scf_entry_create(g_hndl);
4428 		if (ent == NULL)
4429 			return (ENOMEM);
4430 
4431 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4432 			scf_entry_destroy(ent);
4433 			switch (scf_error()) {
4434 			case SCF_ERROR_DELETED:
4435 				warn(emsg_pg_deleted, ient->sc_fmri,
4436 				    "dependents");
4437 				return (EBUSY);
4438 
4439 			case SCF_ERROR_CONNECTION_BROKEN:
4440 				return (scferror2errno(scf_error()));
4441 
4442 			case SCF_ERROR_NOT_FOUND:
4443 				break;
4444 
4445 			case SCF_ERROR_HANDLE_MISMATCH:
4446 			case SCF_ERROR_NOT_BOUND:
4447 			case SCF_ERROR_INVALID_ARGUMENT:
4448 			case SCF_ERROR_NOT_SET:
4449 			default:
4450 				bad_error("scf_transaction_property_delete",
4451 				    scf_error());
4452 			}
4453 		}
4454 
4455 		return (0);
4456 	}
4457 
4458 	new_dpt_pgroup->sc_pgroup_seen = 1;
4459 
4460 	/*
4461 	 * Decide whether the dependent has changed in the manifest.
4462 	 */
4463 	/* Compare the target. */
4464 	if (scf_property_get_value(prop, ud_val) != 0) {
4465 		switch (scf_error()) {
4466 		case SCF_ERROR_NOT_FOUND:
4467 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4468 			warn(li_corrupt, ient->sc_fmri);
4469 			return (EBADF);
4470 
4471 		case SCF_ERROR_DELETED:
4472 		case SCF_ERROR_CONNECTION_BROKEN:
4473 			return (scferror2errno(scf_error()));
4474 
4475 		case SCF_ERROR_HANDLE_MISMATCH:
4476 		case SCF_ERROR_NOT_BOUND:
4477 		case SCF_ERROR_NOT_SET:
4478 		case SCF_ERROR_PERMISSION_DENIED:
4479 		default:
4480 			bad_error("scf_property_get_value", scf_error());
4481 		}
4482 	}
4483 
4484 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4485 	    0)
4486 		bad_error("scf_value_get_as_string", scf_error());
4487 
4488 	/*
4489 	 * If the fmri's are not equal then the old fmri will need to
4490 	 * be refreshed to ensure that the changes are properly updated
4491 	 * in that service.
4492 	 */
4493 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4494 	switch (r) {
4495 	case 0:
4496 		dpt = internal_pgroup_new();
4497 		if (dpt == NULL)
4498 			return (ENOMEM);
4499 		dpt->sc_pgroup_name = strdup(ud_name);
4500 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4501 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4502 			return (ENOMEM);
4503 		dpt->sc_parent = (entity_t *)ient;
4504 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4505 			uu_die(gettext("libuutil error: %s\n"),
4506 			    uu_strerror(uu_error()));
4507 		break;
4508 
4509 	case 1:
4510 		/* Compare the dependency pgs. */
4511 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4512 			switch (scf_error()) {
4513 			case SCF_ERROR_NOT_FOUND:
4514 				warn(li_corrupt, ient->sc_fmri);
4515 				return (EBADF);
4516 
4517 			case SCF_ERROR_DELETED:
4518 			case SCF_ERROR_CONNECTION_BROKEN:
4519 				return (scferror2errno(scf_error()));
4520 
4521 			case SCF_ERROR_NOT_BOUND:
4522 			case SCF_ERROR_HANDLE_MISMATCH:
4523 			case SCF_ERROR_INVALID_ARGUMENT:
4524 			case SCF_ERROR_NOT_SET:
4525 			default:
4526 				bad_error("scf_snaplevel_get_pg", scf_error());
4527 			}
4528 		}
4529 
4530 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4531 		    snap_lastimport);
4532 		switch (r) {
4533 		case 0:
4534 			break;
4535 
4536 		case ECANCELED:
4537 		case ECONNABORTED:
4538 		case ENOMEM:
4539 		case EBADF:
4540 			return (r);
4541 
4542 		case EACCES:
4543 		default:
4544 			bad_error("load_pg", r);
4545 		}
4546 
4547 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4548 			/* no change, leave customizations */
4549 			internal_pgroup_free(old_dpt_pgroup);
4550 			return (0);
4551 		}
4552 		break;
4553 
4554 	case -1:
4555 		warn(li_corrupt, ient->sc_fmri);
4556 		return (EBADF);
4557 
4558 	case -2:
4559 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4560 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4561 		return (EINVAL);
4562 
4563 	default:
4564 		bad_error("fmri_equal", r);
4565 	}
4566 
4567 	/*
4568 	 * The dependent has changed in the manifest.  Upgrade the current
4569 	 * properties if they haven't been customized.
4570 	 */
4571 
4572 	/*
4573 	 * If new_dpt_pgroup->sc_override, then act as though the property
4574 	 * group hasn't been customized.
4575 	 */
4576 	if (new_dpt_pgroup->sc_pgroup_override) {
4577 		(void) strcpy(ud_ctarg, ud_oldtarg);
4578 		goto nocust;
4579 	}
4580 
4581 	if (!ud_run_dpts_pg_set) {
4582 		warn(cf_missing, ient->sc_fmri, ud_name);
4583 		r = 0;
4584 		goto out;
4585 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4586 		switch (scf_error()) {
4587 		case SCF_ERROR_NOT_FOUND:
4588 			warn(cf_missing, ient->sc_fmri, ud_name);
4589 			r = 0;
4590 			goto out;
4591 
4592 		case SCF_ERROR_CONNECTION_BROKEN:
4593 			r = scferror2errno(scf_error());
4594 			goto out;
4595 
4596 		case SCF_ERROR_DELETED:
4597 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4598 			r = EBUSY;
4599 			goto out;
4600 
4601 		case SCF_ERROR_INVALID_ARGUMENT:
4602 		case SCF_ERROR_NOT_BOUND:
4603 		case SCF_ERROR_HANDLE_MISMATCH:
4604 		case SCF_ERROR_NOT_SET:
4605 		default:
4606 			bad_error("scf_pg_get_property", scf_error());
4607 		}
4608 	}
4609 
4610 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4611 		switch (scf_error()) {
4612 		case SCF_ERROR_NOT_FOUND:
4613 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4614 			warn(cf_inval, ient->sc_fmri, ud_name);
4615 			r = 0;
4616 			goto out;
4617 
4618 		case SCF_ERROR_DELETED:
4619 		case SCF_ERROR_CONNECTION_BROKEN:
4620 			r = scferror2errno(scf_error());
4621 			goto out;
4622 
4623 		case SCF_ERROR_HANDLE_MISMATCH:
4624 		case SCF_ERROR_NOT_BOUND:
4625 		case SCF_ERROR_NOT_SET:
4626 		case SCF_ERROR_PERMISSION_DENIED:
4627 		default:
4628 			bad_error("scf_property_get_value", scf_error());
4629 		}
4630 	}
4631 
4632 	ty = scf_value_type(ud_val);
4633 	assert(ty != SCF_TYPE_INVALID);
4634 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4635 		warn(cf_inval, ient->sc_fmri, ud_name);
4636 		r = 0;
4637 		goto out;
4638 	}
4639 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4640 	    0)
4641 		bad_error("scf_value_get_as_string", scf_error());
4642 
4643 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4644 	if (r == -1) {
4645 		warn(cf_inval, ient->sc_fmri, ud_name);
4646 		r = 0;
4647 		goto out;
4648 	} else if (r == -2) {
4649 		warn(li_corrupt, ient->sc_fmri);
4650 		r = EBADF;
4651 		goto out;
4652 	} else if (r == 0) {
4653 		/*
4654 		 * Target has been changed.  Only abort now if it's been
4655 		 * changed to something other than what's in the manifest.
4656 		 */
4657 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4658 		if (r == -1) {
4659 			warn(cf_inval, ient->sc_fmri, ud_name);
4660 			r = 0;
4661 			goto out;
4662 		} else if (r == 0) {
4663 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4664 			r = 0;
4665 			goto out;
4666 		} else if (r != 1) {
4667 			/* invalid sc_pgroup_fmri caught above */
4668 			bad_error("fmri_equal", r);
4669 		}
4670 
4671 		/*
4672 		 * Fetch the current dependency pg.  If it's what the manifest
4673 		 * says, then no problem.
4674 		 */
4675 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4676 		switch (serr) {
4677 		case SCF_ERROR_NONE:
4678 			break;
4679 
4680 		case SCF_ERROR_NOT_FOUND:
4681 			warn(cf_missing, ient->sc_fmri, ud_name);
4682 			r = 0;
4683 			goto out;
4684 
4685 		case SCF_ERROR_NO_MEMORY:
4686 			r = ENOMEM;
4687 			goto out;
4688 
4689 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4690 		case SCF_ERROR_INVALID_ARGUMENT:
4691 		default:
4692 			bad_error("fmri_to_entity", serr);
4693 		}
4694 
4695 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4696 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4697 		switch (r) {
4698 		case 0:
4699 			break;
4700 
4701 		case ECONNABORTED:
4702 			goto out;
4703 
4704 		case ECANCELED:
4705 		case ENOENT:
4706 			warn(cf_missing, ient->sc_fmri, ud_name);
4707 			r = 0;
4708 			goto out;
4709 
4710 		case EBADF:
4711 			warn(r_no_lvl, ud_ctarg);
4712 			goto out;
4713 
4714 		case EINVAL:
4715 		default:
4716 			bad_error("entity_get_running_pg", r);
4717 		}
4718 
4719 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4720 		switch (r) {
4721 		case 0:
4722 			break;
4723 
4724 		case ECANCELED:
4725 			warn(cf_missing, ient->sc_fmri, ud_name);
4726 			r = 0;
4727 			goto out;
4728 
4729 		case ECONNABORTED:
4730 		case ENOMEM:
4731 		case EBADF:
4732 			goto out;
4733 
4734 		case EACCES:
4735 		default:
4736 			bad_error("load_pg", r);
4737 		}
4738 
4739 		if (!pg_equal(current_pg, new_dpt_pgroup))
4740 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4741 		internal_pgroup_free(current_pg);
4742 		r = 0;
4743 		goto out;
4744 	} else if (r != 1) {
4745 		bad_error("fmri_equal", r);
4746 	}
4747 
4748 nocust:
4749 	/*
4750 	 * Target has not been customized.  Check the dependency property
4751 	 * group.
4752 	 */
4753 
4754 	if (old_dpt_pgroup == NULL) {
4755 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4756 		    ud_pg) != 0) {
4757 			switch (scf_error()) {
4758 			case SCF_ERROR_NOT_FOUND:
4759 				warn(li_corrupt, ient->sc_fmri);
4760 				return (EBADF);
4761 
4762 			case SCF_ERROR_DELETED:
4763 			case SCF_ERROR_CONNECTION_BROKEN:
4764 				return (scferror2errno(scf_error()));
4765 
4766 			case SCF_ERROR_NOT_BOUND:
4767 			case SCF_ERROR_HANDLE_MISMATCH:
4768 			case SCF_ERROR_INVALID_ARGUMENT:
4769 			case SCF_ERROR_NOT_SET:
4770 			default:
4771 				bad_error("scf_snaplevel_get_pg", scf_error());
4772 			}
4773 		}
4774 
4775 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4776 		    snap_lastimport);
4777 		switch (r) {
4778 		case 0:
4779 			break;
4780 
4781 		case ECANCELED:
4782 		case ECONNABORTED:
4783 		case ENOMEM:
4784 		case EBADF:
4785 			return (r);
4786 
4787 		case EACCES:
4788 		default:
4789 			bad_error("load_pg", r);
4790 		}
4791 	}
4792 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4793 	switch (serr) {
4794 	case SCF_ERROR_NONE:
4795 		break;
4796 
4797 	case SCF_ERROR_NOT_FOUND:
4798 		warn(cf_missing, ient->sc_fmri, ud_name);
4799 		r = 0;
4800 		goto out;
4801 
4802 	case SCF_ERROR_NO_MEMORY:
4803 		r = ENOMEM;
4804 		goto out;
4805 
4806 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4807 	case SCF_ERROR_INVALID_ARGUMENT:
4808 	default:
4809 		bad_error("fmri_to_entity", serr);
4810 	}
4811 
4812 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4813 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4814 	switch (r) {
4815 	case 0:
4816 		break;
4817 
4818 	case ECONNABORTED:
4819 		goto out;
4820 
4821 	case ECANCELED:
4822 	case ENOENT:
4823 		warn(cf_missing, ient->sc_fmri, ud_name);
4824 		r = 0;
4825 		goto out;
4826 
4827 	case EBADF:
4828 		warn(r_no_lvl, ud_ctarg);
4829 		goto out;
4830 
4831 	case EINVAL:
4832 	default:
4833 		bad_error("entity_get_running_pg", r);
4834 	}
4835 
4836 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4837 	switch (r) {
4838 	case 0:
4839 		break;
4840 
4841 	case ECANCELED:
4842 		warn(cf_missing, ient->sc_fmri, ud_name);
4843 		goto out;
4844 
4845 	case ECONNABORTED:
4846 	case ENOMEM:
4847 	case EBADF:
4848 		goto out;
4849 
4850 	case EACCES:
4851 	default:
4852 		bad_error("load_pg", r);
4853 	}
4854 
4855 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4856 		if (!pg_equal(current_pg, new_dpt_pgroup))
4857 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4858 		internal_pgroup_free(current_pg);
4859 		r = 0;
4860 		goto out;
4861 	}
4862 
4863 	/* Uncustomized.  Upgrade. */
4864 
4865 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4866 	switch (r) {
4867 	case 1:
4868 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4869 			/* Already upgraded. */
4870 			internal_pgroup_free(current_pg);
4871 			r = 0;
4872 			goto out;
4873 		}
4874 
4875 		internal_pgroup_free(current_pg);
4876 
4877 		/* upgrade current_pg */
4878 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4879 			switch (scf_error()) {
4880 			case SCF_ERROR_CONNECTION_BROKEN:
4881 				r = scferror2errno(scf_error());
4882 				goto out;
4883 
4884 			case SCF_ERROR_DELETED:
4885 				warn(cf_missing, ient->sc_fmri, ud_name);
4886 				r = 0;
4887 				goto out;
4888 
4889 			case SCF_ERROR_NOT_FOUND:
4890 				break;
4891 
4892 			case SCF_ERROR_INVALID_ARGUMENT:
4893 			case SCF_ERROR_NOT_BOUND:
4894 			case SCF_ERROR_NOT_SET:
4895 			case SCF_ERROR_HANDLE_MISMATCH:
4896 			default:
4897 				bad_error("entity_get_pg", scf_error());
4898 			}
4899 
4900 			if (tissvc)
4901 				r = scf_service_add_pg(target_ent, ud_name,
4902 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4903 			else
4904 				r = scf_instance_add_pg(target_ent, ud_name,
4905 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4906 			if (r != 0) {
4907 				switch (scf_error()) {
4908 				case SCF_ERROR_CONNECTION_BROKEN:
4909 				case SCF_ERROR_NO_RESOURCES:
4910 				case SCF_ERROR_BACKEND_READONLY:
4911 				case SCF_ERROR_BACKEND_ACCESS:
4912 					r = scferror2errno(scf_error());
4913 					goto out;
4914 
4915 				case SCF_ERROR_DELETED:
4916 					warn(cf_missing, ient->sc_fmri,
4917 					    ud_name);
4918 					r = 0;
4919 					goto out;
4920 
4921 				case SCF_ERROR_PERMISSION_DENIED:
4922 					warn(emsg_pg_deleted, ud_ctarg,
4923 					    ud_name);
4924 					r = EPERM;
4925 					goto out;
4926 
4927 				case SCF_ERROR_EXISTS:
4928 					warn(emsg_pg_added, ud_ctarg, ud_name);
4929 					r = EBUSY;
4930 					goto out;
4931 
4932 				case SCF_ERROR_NOT_BOUND:
4933 				case SCF_ERROR_HANDLE_MISMATCH:
4934 				case SCF_ERROR_INVALID_ARGUMENT:
4935 				case SCF_ERROR_NOT_SET:
4936 				default:
4937 					bad_error("entity_add_pg", scf_error());
4938 				}
4939 			}
4940 		}
4941 
4942 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4943 		switch (r) {
4944 		case 0:
4945 			break;
4946 
4947 		case ECANCELED:
4948 			warn(cf_missing, ient->sc_fmri, ud_name);
4949 			goto out;
4950 
4951 		case ECONNABORTED:
4952 		case ENOMEM:
4953 		case EBADF:
4954 			goto out;
4955 
4956 		case EACCES:
4957 		default:
4958 			bad_error("load_pg", r);
4959 		}
4960 
4961 		if (g_verbose)
4962 			warn(upgrading, ient->sc_fmri, ud_name);
4963 
4964 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4965 		    new_dpt_pgroup, 0, ient->sc_fmri);
4966 		switch (r) {
4967 		case 0:
4968 			break;
4969 
4970 		case ECANCELED:
4971 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4972 			r = EBUSY;
4973 			goto out;
4974 
4975 		case EPERM:
4976 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4977 			goto out;
4978 
4979 		case EBUSY:
4980 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4981 			goto out;
4982 
4983 		case ECONNABORTED:
4984 		case ENOMEM:
4985 		case ENOSPC:
4986 		case EROFS:
4987 		case EACCES:
4988 		case EINVAL:
4989 			goto out;
4990 
4991 		default:
4992 			bad_error("upgrade_pg", r);
4993 		}
4994 		break;
4995 
4996 	case 0: {
4997 		scf_transaction_entry_t *ent;
4998 		scf_value_t *val;
4999 
5000 		internal_pgroup_free(current_pg);
5001 
5002 		/* delete old pg */
5003 		if (g_verbose)
5004 			warn(upgrading, ient->sc_fmri, ud_name);
5005 
5006 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5007 			switch (scf_error()) {
5008 			case SCF_ERROR_CONNECTION_BROKEN:
5009 				r = scferror2errno(scf_error());
5010 				goto out;
5011 
5012 			case SCF_ERROR_DELETED:
5013 				warn(cf_missing, ient->sc_fmri, ud_name);
5014 				r = 0;
5015 				goto out;
5016 
5017 			case SCF_ERROR_NOT_FOUND:
5018 				break;
5019 
5020 			case SCF_ERROR_INVALID_ARGUMENT:
5021 			case SCF_ERROR_NOT_BOUND:
5022 			case SCF_ERROR_NOT_SET:
5023 			case SCF_ERROR_HANDLE_MISMATCH:
5024 			default:
5025 				bad_error("entity_get_pg", scf_error());
5026 			}
5027 		} else if (scf_pg_delete(ud_pg) != 0) {
5028 			switch (scf_error()) {
5029 			case SCF_ERROR_DELETED:
5030 				break;
5031 
5032 			case SCF_ERROR_CONNECTION_BROKEN:
5033 			case SCF_ERROR_BACKEND_READONLY:
5034 			case SCF_ERROR_BACKEND_ACCESS:
5035 				r = scferror2errno(scf_error());
5036 				goto out;
5037 
5038 			case SCF_ERROR_PERMISSION_DENIED:
5039 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5040 				r = scferror2errno(scf_error());
5041 				goto out;
5042 
5043 			case SCF_ERROR_NOT_SET:
5044 			default:
5045 				bad_error("scf_pg_delete", scf_error());
5046 			}
5047 		}
5048 
5049 		/* import new one */
5050 		cbdata.sc_handle = g_hndl;
5051 		cbdata.sc_trans = NULL;		/* handled below */
5052 		cbdata.sc_flags = 0;
5053 
5054 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5055 		if (r != UU_WALK_NEXT) {
5056 			if (r != UU_WALK_ERROR)
5057 				bad_error("lscf_dependent_import", r);
5058 
5059 			r = cbdata.sc_err;
5060 			goto out;
5061 		}
5062 
5063 		if (tx == NULL)
5064 			break;
5065 
5066 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5067 		    (val = scf_value_create(g_hndl)) == NULL) {
5068 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5069 				return (ENOMEM);
5070 
5071 			bad_error("scf_entry_create", scf_error());
5072 		}
5073 
5074 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5075 		    SCF_TYPE_FMRI) != 0) {
5076 			switch (scf_error()) {
5077 			case SCF_ERROR_CONNECTION_BROKEN:
5078 				r = scferror2errno(scf_error());
5079 				goto out;
5080 
5081 			case SCF_ERROR_DELETED:
5082 				warn(emsg_pg_deleted, ient->sc_fmri,
5083 				    "dependents");
5084 				r = EBUSY;
5085 				goto out;
5086 
5087 			case SCF_ERROR_NOT_FOUND:
5088 				break;
5089 
5090 			case SCF_ERROR_NOT_BOUND:
5091 			case SCF_ERROR_HANDLE_MISMATCH:
5092 			case SCF_ERROR_INVALID_ARGUMENT:
5093 			case SCF_ERROR_NOT_SET:
5094 			default:
5095 				bad_error("scf_transaction_property_"
5096 				    "change_type", scf_error());
5097 			}
5098 
5099 			if (scf_transaction_property_new(tx, ent, ud_name,
5100 			    SCF_TYPE_FMRI) != 0) {
5101 				switch (scf_error()) {
5102 				case SCF_ERROR_CONNECTION_BROKEN:
5103 					r = scferror2errno(scf_error());
5104 					goto out;
5105 
5106 				case SCF_ERROR_DELETED:
5107 					warn(emsg_pg_deleted, ient->sc_fmri,
5108 					    "dependents");
5109 					r = EBUSY;
5110 					goto out;
5111 
5112 				case SCF_ERROR_EXISTS:
5113 					warn(emsg_pg_changed, ient->sc_fmri,
5114 					    "dependents");
5115 					r = EBUSY;
5116 					goto out;
5117 
5118 				case SCF_ERROR_INVALID_ARGUMENT:
5119 				case SCF_ERROR_HANDLE_MISMATCH:
5120 				case SCF_ERROR_NOT_BOUND:
5121 				case SCF_ERROR_NOT_SET:
5122 				default:
5123 					bad_error("scf_transaction_property_"
5124 					    "new", scf_error());
5125 				}
5126 			}
5127 		}
5128 
5129 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5130 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5131 			/* invalid sc_pgroup_fmri caught above */
5132 			bad_error("scf_value_set_from_string",
5133 			    scf_error());
5134 
5135 		if (scf_entry_add_value(ent, val) != 0)
5136 			bad_error("scf_entry_add_value", scf_error());
5137 		break;
5138 	}
5139 
5140 	case -2:
5141 		warn(li_corrupt, ient->sc_fmri);
5142 		internal_pgroup_free(current_pg);
5143 		r = EBADF;
5144 		goto out;
5145 
5146 	case -1:
5147 	default:
5148 		/* invalid sc_pgroup_fmri caught above */
5149 		bad_error("fmri_equal", r);
5150 	}
5151 
5152 	r = 0;
5153 
5154 out:
5155 	if (old_dpt_pgroup != NULL)
5156 		internal_pgroup_free(old_dpt_pgroup);
5157 
5158 	return (r);
5159 }
5160 
5161 /*
5162  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5163  * would import it, except it seems to exist in the service anyway.  Compare
5164  * the existent dependent with the one we would import, and report any
5165  * differences (if there are none, be silent).  prop is the property which
5166  * represents the existent dependent (in the dependents property group) in the
5167  * entity corresponding to ient.
5168  *
5169  * Returns
5170  *   0 - success (Sort of.  At least, we can continue importing.)
5171  *   ECONNABORTED - repository connection broken
5172  *   EBUSY - ancestor of prop was deleted (error printed)
5173  *   ENOMEM - out of memory
5174  *   EBADF - corrupt property group (error printed)
5175  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5176  */
5177 static int
5178 handle_dependent_conflict(const entity_t * const ient,
5179     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5180 {
5181 	int r;
5182 	scf_type_t ty;
5183 	scf_error_t scfe;
5184 	void *tptr;
5185 	int tissvc;
5186 	pgroup_t *pgroup;
5187 
5188 	if (scf_property_get_value(prop, ud_val) != 0) {
5189 		switch (scf_error()) {
5190 		case SCF_ERROR_CONNECTION_BROKEN:
5191 			return (scferror2errno(scf_error()));
5192 
5193 		case SCF_ERROR_DELETED:
5194 			warn(emsg_pg_deleted, ient->sc_fmri,
5195 			    new_dpt_pgroup->sc_pgroup_name);
5196 			return (EBUSY);
5197 
5198 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5199 		case SCF_ERROR_NOT_FOUND:
5200 			warn(gettext("Conflict upgrading %s (not importing "
5201 			    "dependent \"%s\" because it already exists.)  "
5202 			    "Warning: The \"%s/%2$s\" property has more or "
5203 			    "fewer than one value)).\n"), ient->sc_fmri,
5204 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5205 			return (0);
5206 
5207 		case SCF_ERROR_HANDLE_MISMATCH:
5208 		case SCF_ERROR_NOT_BOUND:
5209 		case SCF_ERROR_NOT_SET:
5210 		case SCF_ERROR_PERMISSION_DENIED:
5211 		default:
5212 			bad_error("scf_property_get_value",
5213 			    scf_error());
5214 		}
5215 	}
5216 
5217 	ty = scf_value_type(ud_val);
5218 	assert(ty != SCF_TYPE_INVALID);
5219 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5220 		warn(gettext("Conflict upgrading %s (not importing dependent "
5221 		    "\"%s\" because it already exists).  Warning: The "
5222 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5223 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5224 		    scf_type_to_string(ty), "dependents");
5225 		return (0);
5226 	}
5227 
5228 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5229 	    0)
5230 		bad_error("scf_value_get_as_string", scf_error());
5231 
5232 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5233 	switch (r) {
5234 	case 0:
5235 		warn(gettext("Conflict upgrading %s (not importing dependent "
5236 		    "\"%s\" (target \"%s\") because it already exists with "
5237 		    "target \"%s\").\n"), ient->sc_fmri,
5238 		    new_dpt_pgroup->sc_pgroup_name,
5239 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5240 		return (0);
5241 
5242 	case 1:
5243 		break;
5244 
5245 	case -1:
5246 		warn(gettext("Conflict upgrading %s (not importing dependent "
5247 		    "\"%s\" because it already exists).  Warning: The current "
5248 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5249 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5250 		return (0);
5251 
5252 	case -2:
5253 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5254 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5255 		    new_dpt_pgroup->sc_pgroup_fmri);
5256 		return (EINVAL);
5257 
5258 	default:
5259 		bad_error("fmri_equal", r);
5260 	}
5261 
5262 	/* compare dependency pgs in target */
5263 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5264 	switch (scfe) {
5265 	case SCF_ERROR_NONE:
5266 		break;
5267 
5268 	case SCF_ERROR_NO_MEMORY:
5269 		return (ENOMEM);
5270 
5271 	case SCF_ERROR_NOT_FOUND:
5272 		warn(emsg_dpt_dangling, ient->sc_fmri,
5273 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5274 		return (0);
5275 
5276 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5277 	case SCF_ERROR_INVALID_ARGUMENT:
5278 	default:
5279 		bad_error("fmri_to_entity", scfe);
5280 	}
5281 
5282 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5283 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5284 	switch (r) {
5285 	case 0:
5286 		break;
5287 
5288 	case ECONNABORTED:
5289 		return (r);
5290 
5291 	case ECANCELED:
5292 		warn(emsg_dpt_dangling, ient->sc_fmri,
5293 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5294 		return (0);
5295 
5296 	case EBADF:
5297 		if (tissvc)
5298 			warn(gettext("%s has an instance with a \"%s\" "
5299 			    "snapshot which is missing a snaplevel.\n"),
5300 			    ud_ctarg, "running");
5301 		else
5302 			warn(gettext("%s has a \"%s\" snapshot which is "
5303 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5304 		/* FALLTHROUGH */
5305 
5306 	case ENOENT:
5307 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5308 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5309 		    new_dpt_pgroup->sc_pgroup_name);
5310 		return (0);
5311 
5312 	case EINVAL:
5313 	default:
5314 		bad_error("entity_get_running_pg", r);
5315 	}
5316 
5317 	pgroup = internal_pgroup_new();
5318 	if (pgroup == NULL)
5319 		return (ENOMEM);
5320 
5321 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5322 	switch (r) {
5323 	case 0:
5324 		break;
5325 
5326 	case ECONNABORTED:
5327 	case EBADF:
5328 	case ENOMEM:
5329 		internal_pgroup_free(pgroup);
5330 		return (r);
5331 
5332 	case ECANCELED:
5333 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5334 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5335 		    new_dpt_pgroup->sc_pgroup_name);
5336 		internal_pgroup_free(pgroup);
5337 		return (0);
5338 
5339 	case EACCES:
5340 	default:
5341 		bad_error("load_pg", r);
5342 	}
5343 
5344 	/* report differences */
5345 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5346 	internal_pgroup_free(pgroup);
5347 	return (0);
5348 }
5349 
5350 /*
5351  * lipg is a property group in the last-import snapshot of ent, which is an
5352  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5353  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5354  * in ents's property groups, compare and upgrade ent appropriately.
5355  *
5356  * Returns
5357  *   0 - success
5358  *   ECONNABORTED - repository connection broken
5359  *   ENOMEM - out of memory
5360  *   ENOSPC - configd is out of resources
5361  *   EINVAL - ient has invalid dependent (error printed)
5362  *	    - ient has invalid pgroup_t (error printed)
5363  *   ECANCELED - ent has been deleted
5364  *   ENODEV - entity containing lipg has been deleted
5365  *	    - entity containing running has been deleted
5366  *   EPERM - could not delete pg (permission denied) (error printed)
5367  *	   - couldn't upgrade dependents (permission denied) (error printed)
5368  *	   - couldn't import pg (permission denied) (error printed)
5369  *	   - couldn't upgrade pg (permission denied) (error printed)
5370  *   EROFS - could not delete pg (repository read-only)
5371  *	   - couldn't upgrade dependents (repository read-only)
5372  *	   - couldn't import pg (repository read-only)
5373  *	   - couldn't upgrade pg (repository read-only)
5374  *   EACCES - could not delete pg (backend access denied)
5375  *	    - couldn't upgrade dependents (backend access denied)
5376  *	    - couldn't import pg (backend access denied)
5377  *	    - couldn't upgrade pg (backend access denied)
5378  *	    - couldn't read property (backend access denied)
5379  *   EBUSY - property group was added (error printed)
5380  *	   - property group was deleted (error printed)
5381  *	   - property group changed (error printed)
5382  *	   - "dependents" pg was added, changed, or deleted (error printed)
5383  *	   - dependent target deleted (error printed)
5384  *	   - dependent pg changed (error printed)
5385  *   EBADF - imp_snpl is corrupt (error printed)
5386  *	   - ent has bad pg (error printed)
5387  *   EEXIST - dependent collision in target service (error printed)
5388  */
5389 static int
5390 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5391     const scf_snaplevel_t *running)
5392 {
5393 	int r;
5394 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5395 	scf_callback_t cbdata;
5396 
5397 	const char * const cf_pg_missing =
5398 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5399 	const char * const deleting =
5400 	    gettext("%s: Deleting property group \"%s\".\n");
5401 
5402 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5403 
5404 	/* Skip dependent property groups. */
5405 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5406 		switch (scf_error()) {
5407 		case SCF_ERROR_DELETED:
5408 			return (ENODEV);
5409 
5410 		case SCF_ERROR_CONNECTION_BROKEN:
5411 			return (ECONNABORTED);
5412 
5413 		case SCF_ERROR_NOT_SET:
5414 		case SCF_ERROR_NOT_BOUND:
5415 		default:
5416 			bad_error("scf_pg_get_type", scf_error());
5417 		}
5418 	}
5419 
5420 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5421 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5422 			return (0);
5423 
5424 		switch (scf_error()) {
5425 		case SCF_ERROR_NOT_FOUND:
5426 			break;
5427 
5428 		case SCF_ERROR_CONNECTION_BROKEN:
5429 			return (ECONNABORTED);
5430 
5431 		case SCF_ERROR_DELETED:
5432 			return (ENODEV);
5433 
5434 		case SCF_ERROR_INVALID_ARGUMENT:
5435 		case SCF_ERROR_NOT_BOUND:
5436 		case SCF_ERROR_HANDLE_MISMATCH:
5437 		case SCF_ERROR_NOT_SET:
5438 		default:
5439 			bad_error("scf_pg_get_property", scf_error());
5440 		}
5441 	}
5442 
5443 	/* lookup pg in new properties */
5444 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5445 		switch (scf_error()) {
5446 		case SCF_ERROR_DELETED:
5447 			return (ENODEV);
5448 
5449 		case SCF_ERROR_CONNECTION_BROKEN:
5450 			return (ECONNABORTED);
5451 
5452 		case SCF_ERROR_NOT_SET:
5453 		case SCF_ERROR_NOT_BOUND:
5454 		default:
5455 			bad_error("scf_pg_get_name", scf_error());
5456 		}
5457 	}
5458 
5459 	pgrp.sc_pgroup_name = imp_str;
5460 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5461 
5462 	if (mpg != NULL)
5463 		mpg->sc_pgroup_seen = 1;
5464 
5465 	/* Special handling for dependents */
5466 	if (strcmp(imp_str, "dependents") == 0)
5467 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5468 
5469 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5470 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5471 
5472 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5473 		/* property group was deleted from manifest */
5474 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5475 			switch (scf_error()) {
5476 			case SCF_ERROR_NOT_FOUND:
5477 				return (0);
5478 
5479 			case SCF_ERROR_DELETED:
5480 			case SCF_ERROR_CONNECTION_BROKEN:
5481 				return (scferror2errno(scf_error()));
5482 
5483 			case SCF_ERROR_INVALID_ARGUMENT:
5484 			case SCF_ERROR_HANDLE_MISMATCH:
5485 			case SCF_ERROR_NOT_BOUND:
5486 			case SCF_ERROR_NOT_SET:
5487 			default:
5488 				bad_error("entity_get_pg", scf_error());
5489 			}
5490 		}
5491 
5492 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5493 			if (g_verbose)
5494 				warn(deleting, ient->sc_fmri, imp_str);
5495 			if (scf_pg_delete(imp_pg2) == 0)
5496 				return (0);
5497 
5498 			switch (scf_error()) {
5499 			case SCF_ERROR_DELETED:
5500 				return (0);
5501 
5502 			case SCF_ERROR_CONNECTION_BROKEN:
5503 			case SCF_ERROR_BACKEND_READONLY:
5504 			case SCF_ERROR_BACKEND_ACCESS:
5505 				return (scferror2errno(scf_error()));
5506 
5507 			case SCF_ERROR_PERMISSION_DENIED:
5508 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5509 				return (scferror2errno(scf_error()));
5510 
5511 			case SCF_ERROR_NOT_SET:
5512 			default:
5513 				bad_error("scf_pg_delete", scf_error());
5514 			}
5515 		}
5516 
5517 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5518 		switch (r) {
5519 		case 0:
5520 			break;
5521 
5522 		case ECANCELED:
5523 			return (ENODEV);
5524 
5525 		case ECONNABORTED:
5526 		case ENOMEM:
5527 		case EBADF:
5528 		case EACCES:
5529 			return (r);
5530 
5531 		default:
5532 			bad_error("load_pg", r);
5533 		}
5534 
5535 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5536 		switch (r) {
5537 		case 0:
5538 			break;
5539 
5540 		case ECANCELED:
5541 		case ECONNABORTED:
5542 		case ENOMEM:
5543 		case EBADF:
5544 		case EACCES:
5545 			internal_pgroup_free(lipg_i);
5546 			return (r);
5547 
5548 		default:
5549 			bad_error("load_pg", r);
5550 		}
5551 
5552 		if (pg_equal(lipg_i, curpg_i)) {
5553 			if (g_verbose)
5554 				warn(deleting, ient->sc_fmri, imp_str);
5555 			if (scf_pg_delete(imp_pg2) != 0) {
5556 				switch (scf_error()) {
5557 				case SCF_ERROR_DELETED:
5558 					break;
5559 
5560 				case SCF_ERROR_CONNECTION_BROKEN:
5561 					internal_pgroup_free(lipg_i);
5562 					internal_pgroup_free(curpg_i);
5563 					return (ECONNABORTED);
5564 
5565 				case SCF_ERROR_NOT_SET:
5566 				case SCF_ERROR_NOT_BOUND:
5567 				default:
5568 					bad_error("scf_pg_delete", scf_error());
5569 				}
5570 			}
5571 		} else {
5572 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5573 		}
5574 
5575 		internal_pgroup_free(lipg_i);
5576 		internal_pgroup_free(curpg_i);
5577 
5578 		return (0);
5579 	}
5580 
5581 	/*
5582 	 * Only dependent pgs can have override set, and we skipped those
5583 	 * above.
5584 	 */
5585 	assert(!mpg->sc_pgroup_override);
5586 
5587 	/* compare */
5588 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5589 	switch (r) {
5590 	case 0:
5591 		break;
5592 
5593 	case ECANCELED:
5594 		return (ENODEV);
5595 
5596 	case ECONNABORTED:
5597 	case EBADF:
5598 	case ENOMEM:
5599 	case EACCES:
5600 		return (r);
5601 
5602 	default:
5603 		bad_error("load_pg", r);
5604 	}
5605 
5606 	if (pg_equal(mpg, lipg_i)) {
5607 		/* The manifest pg has not changed.  Move on. */
5608 		r = 0;
5609 		goto out;
5610 	}
5611 
5612 	/* upgrade current properties according to lipg & mpg */
5613 	if (running != NULL)
5614 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5615 	else
5616 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5617 	if (r != 0) {
5618 		switch (scf_error()) {
5619 		case SCF_ERROR_CONNECTION_BROKEN:
5620 			r = scferror2errno(scf_error());
5621 			goto out;
5622 
5623 		case SCF_ERROR_DELETED:
5624 			if (running != NULL)
5625 				r = ENODEV;
5626 			else
5627 				r = ECANCELED;
5628 			goto out;
5629 
5630 		case SCF_ERROR_NOT_FOUND:
5631 			break;
5632 
5633 		case SCF_ERROR_INVALID_ARGUMENT:
5634 		case SCF_ERROR_HANDLE_MISMATCH:
5635 		case SCF_ERROR_NOT_BOUND:
5636 		case SCF_ERROR_NOT_SET:
5637 		default:
5638 			bad_error("entity_get_pg", scf_error());
5639 		}
5640 
5641 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5642 
5643 		r = 0;
5644 		goto out;
5645 	}
5646 
5647 	r = load_pg_attrs(imp_pg2, &curpg_i);
5648 	switch (r) {
5649 	case 0:
5650 		break;
5651 
5652 	case ECANCELED:
5653 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5654 		r = 0;
5655 		goto out;
5656 
5657 	case ECONNABORTED:
5658 	case ENOMEM:
5659 		goto out;
5660 
5661 	default:
5662 		bad_error("load_pg_attrs", r);
5663 	}
5664 
5665 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5666 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5667 		internal_pgroup_free(curpg_i);
5668 		r = 0;
5669 		goto out;
5670 	}
5671 
5672 	internal_pgroup_free(curpg_i);
5673 
5674 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5675 	switch (r) {
5676 	case 0:
5677 		break;
5678 
5679 	case ECANCELED:
5680 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5681 		r = 0;
5682 		goto out;
5683 
5684 	case ECONNABORTED:
5685 	case EBADF:
5686 	case ENOMEM:
5687 	case EACCES:
5688 		goto out;
5689 
5690 	default:
5691 		bad_error("load_pg", r);
5692 	}
5693 
5694 	if (pg_equal(lipg_i, curpg_i) &&
5695 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5696 		int do_delete = 1;
5697 
5698 		if (g_verbose)
5699 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5700 			    ient->sc_fmri, mpg->sc_pgroup_name);
5701 
5702 		internal_pgroup_free(curpg_i);
5703 
5704 		if (running != NULL &&
5705 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5706 			switch (scf_error()) {
5707 			case SCF_ERROR_DELETED:
5708 				r = ECANCELED;
5709 				goto out;
5710 
5711 			case SCF_ERROR_NOT_FOUND:
5712 				do_delete = 0;
5713 				break;
5714 
5715 			case SCF_ERROR_CONNECTION_BROKEN:
5716 				r = scferror2errno(scf_error());
5717 				goto out;
5718 
5719 			case SCF_ERROR_HANDLE_MISMATCH:
5720 			case SCF_ERROR_INVALID_ARGUMENT:
5721 			case SCF_ERROR_NOT_SET:
5722 			case SCF_ERROR_NOT_BOUND:
5723 			default:
5724 				bad_error("entity_get_pg", scf_error());
5725 			}
5726 		}
5727 
5728 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5729 			switch (scf_error()) {
5730 			case SCF_ERROR_DELETED:
5731 				break;
5732 
5733 			case SCF_ERROR_CONNECTION_BROKEN:
5734 			case SCF_ERROR_BACKEND_READONLY:
5735 			case SCF_ERROR_BACKEND_ACCESS:
5736 				r = scferror2errno(scf_error());
5737 				goto out;
5738 
5739 			case SCF_ERROR_PERMISSION_DENIED:
5740 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5741 				    ient->sc_fmri);
5742 				r = scferror2errno(scf_error());
5743 				goto out;
5744 
5745 			case SCF_ERROR_NOT_SET:
5746 			case SCF_ERROR_NOT_BOUND:
5747 			default:
5748 				bad_error("scf_pg_delete", scf_error());
5749 			}
5750 		}
5751 
5752 		cbdata.sc_handle = g_hndl;
5753 		cbdata.sc_parent = ent;
5754 		cbdata.sc_service = issvc;
5755 		cbdata.sc_flags = 0;
5756 		cbdata.sc_source_fmri = ient->sc_fmri;
5757 		cbdata.sc_target_fmri = ient->sc_fmri;
5758 
5759 		r = entity_pgroup_import(mpg, &cbdata);
5760 		switch (r) {
5761 		case UU_WALK_NEXT:
5762 			r = 0;
5763 			goto out;
5764 
5765 		case UU_WALK_ERROR:
5766 			if (cbdata.sc_err == EEXIST) {
5767 				warn(emsg_pg_added, ient->sc_fmri,
5768 				    mpg->sc_pgroup_name);
5769 				r = EBUSY;
5770 			} else {
5771 				r = cbdata.sc_err;
5772 			}
5773 			goto out;
5774 
5775 		default:
5776 			bad_error("entity_pgroup_import", r);
5777 		}
5778 	}
5779 
5780 	if (running != NULL &&
5781 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5782 		switch (scf_error()) {
5783 		case SCF_ERROR_CONNECTION_BROKEN:
5784 		case SCF_ERROR_DELETED:
5785 			r = scferror2errno(scf_error());
5786 			goto out;
5787 
5788 		case SCF_ERROR_NOT_FOUND:
5789 			break;
5790 
5791 		case SCF_ERROR_HANDLE_MISMATCH:
5792 		case SCF_ERROR_INVALID_ARGUMENT:
5793 		case SCF_ERROR_NOT_SET:
5794 		case SCF_ERROR_NOT_BOUND:
5795 		default:
5796 			bad_error("entity_get_pg", scf_error());
5797 		}
5798 
5799 		cbdata.sc_handle = g_hndl;
5800 		cbdata.sc_parent = ent;
5801 		cbdata.sc_service = issvc;
5802 		cbdata.sc_flags = SCI_FORCE;
5803 		cbdata.sc_source_fmri = ient->sc_fmri;
5804 		cbdata.sc_target_fmri = ient->sc_fmri;
5805 
5806 		r = entity_pgroup_import(mpg, &cbdata);
5807 		switch (r) {
5808 		case UU_WALK_NEXT:
5809 			r = 0;
5810 			goto out;
5811 
5812 		case UU_WALK_ERROR:
5813 			if (cbdata.sc_err == EEXIST) {
5814 				warn(emsg_pg_added, ient->sc_fmri,
5815 				    mpg->sc_pgroup_name);
5816 				r = EBUSY;
5817 			} else {
5818 				r = cbdata.sc_err;
5819 			}
5820 			goto out;
5821 
5822 		default:
5823 			bad_error("entity_pgroup_import", r);
5824 		}
5825 	}
5826 
5827 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5828 	internal_pgroup_free(curpg_i);
5829 	switch (r) {
5830 	case 0:
5831 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5832 		break;
5833 
5834 	case ECANCELED:
5835 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5836 		r = EBUSY;
5837 		break;
5838 
5839 	case EPERM:
5840 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5841 		break;
5842 
5843 	case EBUSY:
5844 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5845 		break;
5846 
5847 	case ECONNABORTED:
5848 	case ENOMEM:
5849 	case ENOSPC:
5850 	case EROFS:
5851 	case EACCES:
5852 	case EINVAL:
5853 		break;
5854 
5855 	default:
5856 		bad_error("upgrade_pg", r);
5857 	}
5858 
5859 out:
5860 	internal_pgroup_free(lipg_i);
5861 	return (r);
5862 }
5863 
5864 /*
5865  * Upgrade the properties of ent according to snpl & ient.
5866  *
5867  * Returns
5868  *   0 - success
5869  *   ECONNABORTED - repository connection broken
5870  *   ENOMEM - out of memory
5871  *   ENOSPC - configd is out of resources
5872  *   ECANCELED - ent was deleted
5873  *   ENODEV - entity containing snpl was deleted
5874  *	    - entity containing running was deleted
5875  *   EBADF - imp_snpl is corrupt (error printed)
5876  *	   - ent has corrupt pg (error printed)
5877  *	   - dependent has corrupt pg (error printed)
5878  *	   - dependent target has a corrupt snapshot (error printed)
5879  *   EBUSY - pg was added, changed, or deleted (error printed)
5880  *	   - dependent target was deleted (error printed)
5881  *	   - dependent pg changed (error printed)
5882  *   EINVAL - invalid property group name (error printed)
5883  *	    - invalid property name (error printed)
5884  *	    - invalid value (error printed)
5885  *	    - ient has invalid pgroup or dependent (error printed)
5886  *   EPERM - could not create property group (permission denied) (error printed)
5887  *	   - could not modify property group (permission denied) (error printed)
5888  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5889  *   EROFS - could not create property group (repository read-only)
5890  *	   - couldn't delete, upgrade, or import pg or dependent
5891  *   EACCES - could not create property group (backend access denied)
5892  *	    - couldn't delete, upgrade, or import pg or dependent
5893  *   EEXIST - dependent collision in target service (error printed)
5894  */
5895 static int
5896 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5897     entity_t *ient)
5898 {
5899 	pgroup_t *pg, *rpg;
5900 	int r;
5901 	uu_list_t *pgs = ient->sc_pgroups;
5902 
5903 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5904 
5905 	/* clear sc_sceen for pgs */
5906 	if (uu_list_walk(pgs, clear_int,
5907 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5908 		bad_error("uu_list_walk", uu_error());
5909 
5910 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5911 		switch (scf_error()) {
5912 		case SCF_ERROR_DELETED:
5913 			return (ENODEV);
5914 
5915 		case SCF_ERROR_CONNECTION_BROKEN:
5916 			return (ECONNABORTED);
5917 
5918 		case SCF_ERROR_NOT_SET:
5919 		case SCF_ERROR_NOT_BOUND:
5920 		case SCF_ERROR_HANDLE_MISMATCH:
5921 		default:
5922 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5923 		}
5924 	}
5925 
5926 	for (;;) {
5927 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5928 		if (r == 0)
5929 			break;
5930 		if (r == 1) {
5931 			r = process_old_pg(imp_pg, ient, ent, running);
5932 			switch (r) {
5933 			case 0:
5934 				break;
5935 
5936 			case ECONNABORTED:
5937 			case ENOMEM:
5938 			case ENOSPC:
5939 			case ECANCELED:
5940 			case ENODEV:
5941 			case EPERM:
5942 			case EROFS:
5943 			case EACCES:
5944 			case EBADF:
5945 			case EBUSY:
5946 			case EINVAL:
5947 			case EEXIST:
5948 				return (r);
5949 
5950 			default:
5951 				bad_error("process_old_pg", r);
5952 			}
5953 			continue;
5954 		}
5955 		if (r != -1)
5956 			bad_error("scf_iter_next_pg", r);
5957 
5958 		switch (scf_error()) {
5959 		case SCF_ERROR_DELETED:
5960 			return (ENODEV);
5961 
5962 		case SCF_ERROR_CONNECTION_BROKEN:
5963 			return (ECONNABORTED);
5964 
5965 		case SCF_ERROR_HANDLE_MISMATCH:
5966 		case SCF_ERROR_NOT_BOUND:
5967 		case SCF_ERROR_NOT_SET:
5968 		case SCF_ERROR_INVALID_ARGUMENT:
5969 		default:
5970 			bad_error("scf_iter_next_pg", scf_error());
5971 		}
5972 	}
5973 
5974 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5975 		if (pg->sc_pgroup_seen)
5976 			continue;
5977 
5978 		/* pg is new */
5979 
5980 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5981 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5982 			    ent);
5983 			switch (r) {
5984 			case 0:
5985 				break;
5986 
5987 			case ECONNABORTED:
5988 			case ENOMEM:
5989 			case ENOSPC:
5990 			case ECANCELED:
5991 			case ENODEV:
5992 			case EBADF:
5993 			case EBUSY:
5994 			case EINVAL:
5995 			case EPERM:
5996 			case EROFS:
5997 			case EACCES:
5998 			case EEXIST:
5999 				return (r);
6000 
6001 			default:
6002 				bad_error("upgrade_dependents", r);
6003 			}
6004 			continue;
6005 		}
6006 
6007 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6008 			r = upgrade_manifestfiles(pg, ient, running, ent);
6009 			switch (r) {
6010 			case 0:
6011 				break;
6012 
6013 			case ECONNABORTED:
6014 			case ENOMEM:
6015 			case ENOSPC:
6016 			case ECANCELED:
6017 			case ENODEV:
6018 			case EBADF:
6019 			case EBUSY:
6020 			case EINVAL:
6021 			case EPERM:
6022 			case EROFS:
6023 			case EACCES:
6024 			case EEXIST:
6025 				return (r);
6026 
6027 			default:
6028 				bad_error("upgrade_manifestfiles", r);
6029 			}
6030 			continue;
6031 		}
6032 
6033 		if (running != NULL) {
6034 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6035 			    imp_pg);
6036 		} else {
6037 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6038 			    imp_pg);
6039 		}
6040 		if (r != 0) {
6041 			scf_callback_t cbdata;
6042 
6043 			switch (scf_error()) {
6044 			case SCF_ERROR_NOT_FOUND:
6045 				break;
6046 
6047 			case SCF_ERROR_CONNECTION_BROKEN:
6048 				return (scferror2errno(scf_error()));
6049 
6050 			case SCF_ERROR_DELETED:
6051 				if (running != NULL)
6052 					return (ENODEV);
6053 				else
6054 					return (scferror2errno(scf_error()));
6055 
6056 			case SCF_ERROR_INVALID_ARGUMENT:
6057 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6058 				    pg->sc_pgroup_name);
6059 				return (EINVAL);
6060 
6061 			case SCF_ERROR_NOT_SET:
6062 			case SCF_ERROR_HANDLE_MISMATCH:
6063 			case SCF_ERROR_NOT_BOUND:
6064 			default:
6065 				bad_error("entity_get_pg", scf_error());
6066 			}
6067 
6068 			/* User doesn't have pg, so import it. */
6069 
6070 			cbdata.sc_handle = g_hndl;
6071 			cbdata.sc_parent = ent;
6072 			cbdata.sc_service = issvc;
6073 			cbdata.sc_flags = SCI_FORCE;
6074 			cbdata.sc_source_fmri = ient->sc_fmri;
6075 			cbdata.sc_target_fmri = ient->sc_fmri;
6076 
6077 			r = entity_pgroup_import(pg, &cbdata);
6078 			switch (r) {
6079 			case UU_WALK_NEXT:
6080 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6081 				continue;
6082 
6083 			case UU_WALK_ERROR:
6084 				if (cbdata.sc_err == EEXIST) {
6085 					warn(emsg_pg_added, ient->sc_fmri,
6086 					    pg->sc_pgroup_name);
6087 					return (EBUSY);
6088 				}
6089 				return (cbdata.sc_err);
6090 
6091 			default:
6092 				bad_error("entity_pgroup_import", r);
6093 			}
6094 		}
6095 
6096 		/* report differences between pg & current */
6097 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6098 		switch (r) {
6099 		case 0:
6100 			break;
6101 
6102 		case ECANCELED:
6103 			warn(emsg_pg_deleted, ient->sc_fmri,
6104 			    pg->sc_pgroup_name);
6105 			return (EBUSY);
6106 
6107 		case ECONNABORTED:
6108 		case EBADF:
6109 		case ENOMEM:
6110 		case EACCES:
6111 			return (r);
6112 
6113 		default:
6114 			bad_error("load_pg", r);
6115 		}
6116 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6117 		internal_pgroup_free(rpg);
6118 		rpg = NULL;
6119 	}
6120 
6121 	return (0);
6122 }
6123 
6124 /*
6125  * Import an instance.  If it doesn't exist, create it.  If it has
6126  * a last-import snapshot, upgrade its properties.  Finish by updating its
6127  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6128  * could have been created for a dependent tag in another manifest.  Import the
6129  * new properties.  If there's a conflict, don't override, like now?
6130  *
6131  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6132  * lcbdata->sc_err to
6133  *   ECONNABORTED - repository connection broken
6134  *   ENOMEM - out of memory
6135  *   ENOSPC - svc.configd is out of resources
6136  *   EEXIST - dependency collision in dependent service (error printed)
6137  *   EPERM - couldn't create temporary instance (permission denied)
6138  *	   - couldn't import into temporary instance (permission denied)
6139  *	   - couldn't take snapshot (permission denied)
6140  *	   - couldn't upgrade properties (permission denied)
6141  *	   - couldn't import properties (permission denied)
6142  *	   - couldn't import dependents (permission denied)
6143  *   EROFS - couldn't create temporary instance (repository read-only)
6144  *	   - couldn't import into temporary instance (repository read-only)
6145  *	   - couldn't upgrade properties (repository read-only)
6146  *	   - couldn't import properties (repository read-only)
6147  *	   - couldn't import dependents (repository read-only)
6148  *   EACCES - couldn't create temporary instance (backend access denied)
6149  *	    - couldn't import into temporary instance (backend access denied)
6150  *	    - couldn't upgrade properties (backend access denied)
6151  *	    - couldn't import properties (backend access denied)
6152  *	    - couldn't import dependents (backend access denied)
6153  *   EINVAL - invalid instance name (error printed)
6154  *	    - invalid pgroup_t's (error printed)
6155  *	    - invalid dependents (error printed)
6156  *   EBUSY - temporary service deleted (error printed)
6157  *	   - temporary instance deleted (error printed)
6158  *	   - temporary instance changed (error printed)
6159  *	   - temporary instance already exists (error printed)
6160  *	   - instance deleted (error printed)
6161  *   EBADF - instance has corrupt last-import snapshot (error printed)
6162  *	   - instance is corrupt (error printed)
6163  *	   - dependent has corrupt pg (error printed)
6164  *	   - dependent target has a corrupt snapshot (error printed)
6165  *   -1 - unknown libscf error (error printed)
6166  */
6167 static int
6168 lscf_instance_import(void *v, void *pvt)
6169 {
6170 	entity_t *inst = v;
6171 	scf_callback_t ctx;
6172 	scf_callback_t *lcbdata = pvt;
6173 	scf_service_t *rsvc = lcbdata->sc_parent;
6174 	int r;
6175 	scf_snaplevel_t *running;
6176 	int flags = lcbdata->sc_flags;
6177 
6178 	const char * const emsg_tdel =
6179 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6180 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6181 	    "changed unexpectedly.\n");
6182 	const char * const emsg_del = gettext("%s changed unexpectedly "
6183 	    "(instance \"%s\" was deleted.)\n");
6184 	const char * const emsg_badsnap = gettext(
6185 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6186 
6187 	/*
6188 	 * prepare last-import snapshot:
6189 	 * create temporary instance (service was precreated)
6190 	 * populate with properties from bundle
6191 	 * take snapshot
6192 	 */
6193 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6194 		switch (scf_error()) {
6195 		case SCF_ERROR_CONNECTION_BROKEN:
6196 		case SCF_ERROR_NO_RESOURCES:
6197 		case SCF_ERROR_BACKEND_READONLY:
6198 		case SCF_ERROR_BACKEND_ACCESS:
6199 			return (stash_scferror(lcbdata));
6200 
6201 		case SCF_ERROR_EXISTS:
6202 			warn(gettext("Temporary service svc:/%s "
6203 			    "changed unexpectedly (instance \"%s\" added).\n"),
6204 			    imp_tsname, inst->sc_name);
6205 			lcbdata->sc_err = EBUSY;
6206 			return (UU_WALK_ERROR);
6207 
6208 		case SCF_ERROR_DELETED:
6209 			warn(gettext("Temporary service svc:/%s "
6210 			    "was deleted unexpectedly.\n"), imp_tsname);
6211 			lcbdata->sc_err = EBUSY;
6212 			return (UU_WALK_ERROR);
6213 
6214 		case SCF_ERROR_INVALID_ARGUMENT:
6215 			warn(gettext("Invalid instance name \"%s\".\n"),
6216 			    inst->sc_name);
6217 			return (stash_scferror(lcbdata));
6218 
6219 		case SCF_ERROR_PERMISSION_DENIED:
6220 			warn(gettext("Could not create temporary instance "
6221 			    "\"%s\" in svc:/%s (permission denied).\n"),
6222 			    inst->sc_name, imp_tsname);
6223 			return (stash_scferror(lcbdata));
6224 
6225 		case SCF_ERROR_HANDLE_MISMATCH:
6226 		case SCF_ERROR_NOT_BOUND:
6227 		case SCF_ERROR_NOT_SET:
6228 		default:
6229 			bad_error("scf_service_add_instance", scf_error());
6230 		}
6231 	}
6232 
6233 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6234 	    inst->sc_name);
6235 	if (r < 0)
6236 		bad_error("snprintf", errno);
6237 
6238 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6239 	    lcbdata->sc_flags | SCI_NOENABLED);
6240 	switch (r) {
6241 	case 0:
6242 		break;
6243 
6244 	case ECANCELED:
6245 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6246 		lcbdata->sc_err = EBUSY;
6247 		r = UU_WALK_ERROR;
6248 		goto deltemp;
6249 
6250 	case EEXIST:
6251 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6252 		lcbdata->sc_err = EBUSY;
6253 		r = UU_WALK_ERROR;
6254 		goto deltemp;
6255 
6256 	case ECONNABORTED:
6257 		goto connaborted;
6258 
6259 	case ENOMEM:
6260 	case ENOSPC:
6261 	case EPERM:
6262 	case EROFS:
6263 	case EACCES:
6264 	case EINVAL:
6265 	case EBUSY:
6266 		lcbdata->sc_err = r;
6267 		r = UU_WALK_ERROR;
6268 		goto deltemp;
6269 
6270 	default:
6271 		bad_error("lscf_import_instance_pgs", r);
6272 	}
6273 
6274 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6275 	    inst->sc_name);
6276 	if (r < 0)
6277 		bad_error("snprintf", errno);
6278 
6279 	ctx.sc_handle = lcbdata->sc_handle;
6280 	ctx.sc_parent = imp_tinst;
6281 	ctx.sc_service = 0;
6282 	ctx.sc_source_fmri = inst->sc_fmri;
6283 	ctx.sc_target_fmri = imp_str;
6284 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6285 	    UU_DEFAULT) != 0) {
6286 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6287 			bad_error("uu_list_walk", uu_error());
6288 
6289 		switch (ctx.sc_err) {
6290 		case ECONNABORTED:
6291 			goto connaborted;
6292 
6293 		case ECANCELED:
6294 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6295 			lcbdata->sc_err = EBUSY;
6296 			break;
6297 
6298 		case EEXIST:
6299 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6300 			lcbdata->sc_err = EBUSY;
6301 			break;
6302 
6303 		default:
6304 			lcbdata->sc_err = ctx.sc_err;
6305 		}
6306 		r = UU_WALK_ERROR;
6307 		goto deltemp;
6308 	}
6309 
6310 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6311 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6312 		switch (scf_error()) {
6313 		case SCF_ERROR_CONNECTION_BROKEN:
6314 			goto connaborted;
6315 
6316 		case SCF_ERROR_NO_RESOURCES:
6317 			r = stash_scferror(lcbdata);
6318 			goto deltemp;
6319 
6320 		case SCF_ERROR_EXISTS:
6321 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6322 			lcbdata->sc_err = EBUSY;
6323 			r = UU_WALK_ERROR;
6324 			goto deltemp;
6325 
6326 		case SCF_ERROR_PERMISSION_DENIED:
6327 			warn(gettext("Could not take \"%s\" snapshot of %s "
6328 			    "(permission denied).\n"), snap_lastimport,
6329 			    imp_str);
6330 			r = stash_scferror(lcbdata);
6331 			goto deltemp;
6332 
6333 		default:
6334 			scfwarn();
6335 			lcbdata->sc_err = -1;
6336 			r = UU_WALK_ERROR;
6337 			goto deltemp;
6338 
6339 		case SCF_ERROR_HANDLE_MISMATCH:
6340 		case SCF_ERROR_INVALID_ARGUMENT:
6341 		case SCF_ERROR_NOT_SET:
6342 			bad_error("_scf_snapshot_take_new_named", scf_error());
6343 		}
6344 	}
6345 
6346 	if (lcbdata->sc_flags & SCI_FRESH)
6347 		goto fresh;
6348 
6349 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6350 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6351 		    imp_lisnap) != 0) {
6352 			switch (scf_error()) {
6353 			case SCF_ERROR_DELETED:
6354 				warn(emsg_del, inst->sc_parent->sc_fmri,
6355 				    inst->sc_name);
6356 				lcbdata->sc_err = EBUSY;
6357 				r = UU_WALK_ERROR;
6358 				goto deltemp;
6359 
6360 			case SCF_ERROR_NOT_FOUND:
6361 				flags |= SCI_FORCE;
6362 				goto nosnap;
6363 
6364 			case SCF_ERROR_CONNECTION_BROKEN:
6365 				goto connaborted;
6366 
6367 			case SCF_ERROR_INVALID_ARGUMENT:
6368 			case SCF_ERROR_HANDLE_MISMATCH:
6369 			case SCF_ERROR_NOT_BOUND:
6370 			case SCF_ERROR_NOT_SET:
6371 			default:
6372 				bad_error("scf_instance_get_snapshot",
6373 				    scf_error());
6374 			}
6375 		}
6376 
6377 		/* upgrade */
6378 
6379 		/*
6380 		 * compare new properties with last-import properties
6381 		 * upgrade current properties
6382 		 */
6383 		/* clear sc_sceen for pgs */
6384 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6385 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6386 		    0)
6387 			bad_error("uu_list_walk", uu_error());
6388 
6389 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6390 		switch (r) {
6391 		case 0:
6392 			break;
6393 
6394 		case ECONNABORTED:
6395 			goto connaborted;
6396 
6397 		case ECANCELED:
6398 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6399 			lcbdata->sc_err = EBUSY;
6400 			r = UU_WALK_ERROR;
6401 			goto deltemp;
6402 
6403 		case ENOENT:
6404 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6405 			lcbdata->sc_err = EBADF;
6406 			r = UU_WALK_ERROR;
6407 			goto deltemp;
6408 
6409 		default:
6410 			bad_error("get_snaplevel", r);
6411 		}
6412 
6413 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6414 		    imp_rsnap) != 0) {
6415 			switch (scf_error()) {
6416 			case SCF_ERROR_DELETED:
6417 				warn(emsg_del, inst->sc_parent->sc_fmri,
6418 				    inst->sc_name);
6419 				lcbdata->sc_err = EBUSY;
6420 				r = UU_WALK_ERROR;
6421 				goto deltemp;
6422 
6423 			case SCF_ERROR_NOT_FOUND:
6424 				break;
6425 
6426 			case SCF_ERROR_CONNECTION_BROKEN:
6427 				goto connaborted;
6428 
6429 			case SCF_ERROR_INVALID_ARGUMENT:
6430 			case SCF_ERROR_HANDLE_MISMATCH:
6431 			case SCF_ERROR_NOT_BOUND:
6432 			case SCF_ERROR_NOT_SET:
6433 			default:
6434 				bad_error("scf_instance_get_snapshot",
6435 				    scf_error());
6436 			}
6437 
6438 			running = NULL;
6439 		} else {
6440 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6441 			switch (r) {
6442 			case 0:
6443 				running = imp_rsnpl;
6444 				break;
6445 
6446 			case ECONNABORTED:
6447 				goto connaborted;
6448 
6449 			case ECANCELED:
6450 				warn(emsg_del, inst->sc_parent->sc_fmri,
6451 				    inst->sc_name);
6452 				lcbdata->sc_err = EBUSY;
6453 				r = UU_WALK_ERROR;
6454 				goto deltemp;
6455 
6456 			case ENOENT:
6457 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6458 				lcbdata->sc_err = EBADF;
6459 				r = UU_WALK_ERROR;
6460 				goto deltemp;
6461 
6462 			default:
6463 				bad_error("get_snaplevel", r);
6464 			}
6465 		}
6466 
6467 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6468 		switch (r) {
6469 		case 0:
6470 			break;
6471 
6472 		case ECANCELED:
6473 		case ENODEV:
6474 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6475 			lcbdata->sc_err = EBUSY;
6476 			r = UU_WALK_ERROR;
6477 			goto deltemp;
6478 
6479 		case ECONNABORTED:
6480 			goto connaborted;
6481 
6482 		case ENOMEM:
6483 		case ENOSPC:
6484 		case EBADF:
6485 		case EBUSY:
6486 		case EINVAL:
6487 		case EPERM:
6488 		case EROFS:
6489 		case EACCES:
6490 		case EEXIST:
6491 			lcbdata->sc_err = r;
6492 			r = UU_WALK_ERROR;
6493 			goto deltemp;
6494 
6495 		default:
6496 			bad_error("upgrade_props", r);
6497 		}
6498 
6499 		inst->sc_import_state = IMPORT_PROP_DONE;
6500 	} else {
6501 		switch (scf_error()) {
6502 		case SCF_ERROR_CONNECTION_BROKEN:
6503 			goto connaborted;
6504 
6505 		case SCF_ERROR_NOT_FOUND:
6506 			break;
6507 
6508 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6509 		case SCF_ERROR_HANDLE_MISMATCH:
6510 		case SCF_ERROR_NOT_BOUND:
6511 		case SCF_ERROR_NOT_SET:
6512 		default:
6513 			bad_error("scf_service_get_instance", scf_error());
6514 		}
6515 
6516 fresh:
6517 		/* create instance */
6518 		if (scf_service_add_instance(rsvc, inst->sc_name,
6519 		    imp_inst) != 0) {
6520 			switch (scf_error()) {
6521 			case SCF_ERROR_CONNECTION_BROKEN:
6522 				goto connaborted;
6523 
6524 			case SCF_ERROR_NO_RESOURCES:
6525 			case SCF_ERROR_BACKEND_READONLY:
6526 			case SCF_ERROR_BACKEND_ACCESS:
6527 				r = stash_scferror(lcbdata);
6528 				goto deltemp;
6529 
6530 			case SCF_ERROR_EXISTS:
6531 				warn(gettext("%s changed unexpectedly "
6532 				    "(instance \"%s\" added).\n"),
6533 				    inst->sc_parent->sc_fmri, inst->sc_name);
6534 				lcbdata->sc_err = EBUSY;
6535 				r = UU_WALK_ERROR;
6536 				goto deltemp;
6537 
6538 			case SCF_ERROR_PERMISSION_DENIED:
6539 				warn(gettext("Could not create \"%s\" instance "
6540 				    "in %s (permission denied).\n"),
6541 				    inst->sc_name, inst->sc_parent->sc_fmri);
6542 				r = stash_scferror(lcbdata);
6543 				goto deltemp;
6544 
6545 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6546 			case SCF_ERROR_HANDLE_MISMATCH:
6547 			case SCF_ERROR_NOT_BOUND:
6548 			case SCF_ERROR_NOT_SET:
6549 			default:
6550 				bad_error("scf_service_add_instance",
6551 				    scf_error());
6552 			}
6553 		}
6554 
6555 nosnap:
6556 		/*
6557 		 * Create a last-import snapshot to serve as an attachment
6558 		 * point for the real one from the temporary instance.  Since
6559 		 * the contents is irrelevant, take it now, while the instance
6560 		 * is empty, to minimize svc.configd's work.
6561 		 */
6562 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6563 		    imp_lisnap) != 0) {
6564 			switch (scf_error()) {
6565 			case SCF_ERROR_CONNECTION_BROKEN:
6566 				goto connaborted;
6567 
6568 			case SCF_ERROR_NO_RESOURCES:
6569 				r = stash_scferror(lcbdata);
6570 				goto deltemp;
6571 
6572 			case SCF_ERROR_EXISTS:
6573 				warn(gettext("%s changed unexpectedly "
6574 				    "(snapshot \"%s\" added).\n"),
6575 				    inst->sc_fmri, snap_lastimport);
6576 				lcbdata->sc_err = EBUSY;
6577 				r = UU_WALK_ERROR;
6578 				goto deltemp;
6579 
6580 			case SCF_ERROR_PERMISSION_DENIED:
6581 				warn(gettext("Could not take \"%s\" snapshot "
6582 				    "of %s (permission denied).\n"),
6583 				    snap_lastimport, inst->sc_fmri);
6584 				r = stash_scferror(lcbdata);
6585 				goto deltemp;
6586 
6587 			default:
6588 				scfwarn();
6589 				lcbdata->sc_err = -1;
6590 				r = UU_WALK_ERROR;
6591 				goto deltemp;
6592 
6593 			case SCF_ERROR_NOT_SET:
6594 			case SCF_ERROR_INTERNAL:
6595 			case SCF_ERROR_INVALID_ARGUMENT:
6596 			case SCF_ERROR_HANDLE_MISMATCH:
6597 				bad_error("_scf_snapshot_take_new",
6598 				    scf_error());
6599 			}
6600 		}
6601 
6602 		if (li_only)
6603 			goto lionly;
6604 
6605 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6606 
6607 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6608 		    flags);
6609 		switch (r) {
6610 		case 0:
6611 			break;
6612 
6613 		case ECONNABORTED:
6614 			goto connaborted;
6615 
6616 		case ECANCELED:
6617 			warn(gettext("%s changed unexpectedly "
6618 			    "(instance \"%s\" deleted).\n"),
6619 			    inst->sc_parent->sc_fmri, inst->sc_name);
6620 			lcbdata->sc_err = EBUSY;
6621 			r = UU_WALK_ERROR;
6622 			goto deltemp;
6623 
6624 		case EEXIST:
6625 			warn(gettext("%s changed unexpectedly "
6626 			    "(property group added).\n"), inst->sc_fmri);
6627 			lcbdata->sc_err = EBUSY;
6628 			r = UU_WALK_ERROR;
6629 			goto deltemp;
6630 
6631 		default:
6632 			lcbdata->sc_err = r;
6633 			r = UU_WALK_ERROR;
6634 			goto deltemp;
6635 
6636 		case EINVAL:	/* caught above */
6637 			bad_error("lscf_import_instance_pgs", r);
6638 		}
6639 
6640 		ctx.sc_parent = imp_inst;
6641 		ctx.sc_service = 0;
6642 		ctx.sc_trans = NULL;
6643 		ctx.sc_flags = 0;
6644 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6645 		    &ctx, UU_DEFAULT) != 0) {
6646 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6647 				bad_error("uu_list_walk", uu_error());
6648 
6649 			if (ctx.sc_err == ECONNABORTED)
6650 				goto connaborted;
6651 			lcbdata->sc_err = ctx.sc_err;
6652 			r = UU_WALK_ERROR;
6653 			goto deltemp;
6654 		}
6655 
6656 		inst->sc_import_state = IMPORT_PROP_DONE;
6657 
6658 		if (g_verbose)
6659 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6660 			    snap_initial, inst->sc_fmri);
6661 		r = take_snap(imp_inst, snap_initial, imp_snap);
6662 		switch (r) {
6663 		case 0:
6664 			break;
6665 
6666 		case ECONNABORTED:
6667 			goto connaborted;
6668 
6669 		case ENOSPC:
6670 		case -1:
6671 			lcbdata->sc_err = r;
6672 			r = UU_WALK_ERROR;
6673 			goto deltemp;
6674 
6675 		case ECANCELED:
6676 			warn(gettext("%s changed unexpectedly "
6677 			    "(instance %s deleted).\n"),
6678 			    inst->sc_parent->sc_fmri, inst->sc_name);
6679 			lcbdata->sc_err = r;
6680 			r = UU_WALK_ERROR;
6681 			goto deltemp;
6682 
6683 		case EPERM:
6684 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6685 			lcbdata->sc_err = r;
6686 			r = UU_WALK_ERROR;
6687 			goto deltemp;
6688 
6689 		default:
6690 			bad_error("take_snap", r);
6691 		}
6692 	}
6693 
6694 lionly:
6695 	if (lcbdata->sc_flags & SCI_NOSNAP)
6696 		goto deltemp;
6697 
6698 	/* transfer snapshot from temporary instance */
6699 	if (g_verbose)
6700 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6701 		    snap_lastimport, inst->sc_fmri);
6702 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6703 		switch (scf_error()) {
6704 		case SCF_ERROR_CONNECTION_BROKEN:
6705 			goto connaborted;
6706 
6707 		case SCF_ERROR_NO_RESOURCES:
6708 			r = stash_scferror(lcbdata);
6709 			goto deltemp;
6710 
6711 		case SCF_ERROR_PERMISSION_DENIED:
6712 			warn(gettext("Could not take \"%s\" snapshot for %s "
6713 			    "(permission denied).\n"), snap_lastimport,
6714 			    inst->sc_fmri);
6715 			r = stash_scferror(lcbdata);
6716 			goto deltemp;
6717 
6718 		case SCF_ERROR_NOT_SET:
6719 		case SCF_ERROR_HANDLE_MISMATCH:
6720 		default:
6721 			bad_error("_scf_snapshot_attach", scf_error());
6722 		}
6723 	}
6724 
6725 	inst->sc_import_state = IMPORT_COMPLETE;
6726 
6727 	r = UU_WALK_NEXT;
6728 
6729 deltemp:
6730 	/* delete temporary instance */
6731 	if (scf_instance_delete(imp_tinst) != 0) {
6732 		switch (scf_error()) {
6733 		case SCF_ERROR_DELETED:
6734 			break;
6735 
6736 		case SCF_ERROR_CONNECTION_BROKEN:
6737 			goto connaborted;
6738 
6739 		case SCF_ERROR_NOT_SET:
6740 		case SCF_ERROR_NOT_BOUND:
6741 		default:
6742 			bad_error("scf_instance_delete", scf_error());
6743 		}
6744 	}
6745 
6746 	return (r);
6747 
6748 connaborted:
6749 	warn(gettext("Could not delete svc:/%s:%s "
6750 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6751 	lcbdata->sc_err = ECONNABORTED;
6752 	return (UU_WALK_ERROR);
6753 }
6754 
6755 /*
6756  * When an instance is imported we end up telling configd about it. Once we tell
6757  * configd about these changes, startd eventually notices. If this is a new
6758  * instance, the manifest may not specify the SCF_PG_RESTARTER (restarter)
6759  * property group. However, many of the other tools expect that this property
6760  * group exists and has certain values.
6761  *
6762  * These values are added asynchronously by startd. We should not return from
6763  * this routine until we can verify that the property group we need is there.
6764  *
6765  * Before we go ahead and verify this, we have to ask ourselves an important
6766  * question: Is the early manifest service currently running?  Because if it is
6767  * running and it has invoked us, then the service will never get a restarter
6768  * property because svc.startd is blocked on EMI finishing before it lets itself
6769  * fully connect to svc.configd. Of course, this means that this race condition
6770  * is in fact impossible to 100% eliminate.
6771  *
6772  * svc.startd makes sure that EMI only runs once and has succeeded by checking
6773  * the state of the EMI instance. If it is online it bails out and makes sure
6774  * that it doesn't run again. In this case, we're going to do something similar,
6775  * only if the state is online, then we're going to actually verify. EMI always
6776  * has to be present, but it can be explicitly disabled to reduce the amount of
6777  * damage it can cause. If EMI has been disabled then we no longer have to worry
6778  * about the implicit race condition and can go ahead and check things. If EMI
6779  * is in some state that isn't online or disabled and isn't runinng, then we
6780  * assume that things are rather bad and we're not going to get in your way,
6781  * even if the rest of SMF does.
6782  *
6783  * Returns 0 on success or returns an errno.
6784  */
6785 #ifndef NATIVE_BUILD
6786 static int
6787 lscf_instance_verify(scf_scope_t *scope, entity_t *svc, entity_t *inst)
6788 {
6789 	int ret, err;
6790 	struct timespec ts;
6791 	char *emi_state;
6792 
6793 	/*
6794 	 * smf_get_state does not distinguish between its different failure
6795 	 * modes: memory allocation failures, SMF internal failures, and a lack
6796 	 * of EMI entirely because it's been removed. In these cases, we're
6797 	 * going to be conservative and opt to say that if we don't know, better
6798 	 * to not block import or falsely warn to the user.
6799 	 */
6800 	if ((emi_state = smf_get_state(SCF_INSTANCE_EMI)) == NULL) {
6801 		return (0);
6802 	}
6803 
6804 	/*
6805 	 * As per the block comment for this function check the state of EMI
6806 	 */
6807 	if (strcmp(emi_state, SCF_STATE_STRING_ONLINE) != 0 &&
6808 	    strcmp(emi_state, SCF_STATE_STRING_DISABLED) != 0) {
6809 		warn(gettext("Not validating instance %s:%s because EMI's "
6810 		    "state is %s\n"), svc->sc_name, inst->sc_name, emi_state);
6811 		free(emi_state);
6812 		return (0);
6813 	}
6814 
6815 	free(emi_state);
6816 
6817 	/*
6818 	 * First we have to get the property.
6819 	 */
6820 	if ((ret = scf_scope_get_service(scope, svc->sc_name, imp_svc)) != 0) {
6821 		ret = scf_error();
6822 		warn(gettext("Failed to look up service: %s\n"), svc->sc_name);
6823 		return (ret);
6824 	}
6825 
6826 	/*
6827 	 * We should always be able to get the instance. It should already
6828 	 * exist because we just created it or got it. There probably is a
6829 	 * slim chance that someone may have come in and deleted it though from
6830 	 * under us.
6831 	 */
6832 	if ((ret = scf_service_get_instance(imp_svc, inst->sc_name, imp_inst))
6833 	    != 0) {
6834 		ret = scf_error();
6835 		warn(gettext("Failed to verify instance: %s\n"), inst->sc_name);
6836 		switch (ret) {
6837 		case SCF_ERROR_DELETED:
6838 			err = ENODEV;
6839 			break;
6840 		case SCF_ERROR_CONNECTION_BROKEN:
6841 			warn(gettext("Lost repository connection\n"));
6842 			err = ECONNABORTED;
6843 			break;
6844 		case SCF_ERROR_NOT_FOUND:
6845 			warn(gettext("Instance \"%s\" disappeared out from "
6846 			    "under us.\n"), inst->sc_name);
6847 			err = ENOENT;
6848 			break;
6849 		default:
6850 			bad_error("scf_service_get_instance", ret);
6851 		}
6852 
6853 		return (err);
6854 	}
6855 
6856 	/*
6857 	 * An astute observer may want to use _scf_wait_pg which would notify us
6858 	 * of a property group change, unfortunately that does not work if the
6859 	 * property group in question does not exist. So instead we have to
6860 	 * manually poll and ask smf the best way to get to it.
6861 	 */
6862 	while ((ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg))
6863 	    != SCF_SUCCESS) {
6864 		ret = scf_error();
6865 		if (ret != SCF_ERROR_NOT_FOUND) {
6866 			warn(gettext("Failed to get restarter property "
6867 			    "group for instance: %s\n"), inst->sc_name);
6868 			switch (ret) {
6869 			case SCF_ERROR_DELETED:
6870 				err = ENODEV;
6871 				break;
6872 			case SCF_ERROR_CONNECTION_BROKEN:
6873 				warn(gettext("Lost repository connection\n"));
6874 				err = ECONNABORTED;
6875 				break;
6876 			default:
6877 				bad_error("scf_service_get_instance", ret);
6878 			}
6879 
6880 			return (err);
6881 		}
6882 
6883 		ts.tv_sec = pg_timeout / NANOSEC;
6884 		ts.tv_nsec = pg_timeout % NANOSEC;
6885 
6886 		(void) nanosleep(&ts, NULL);
6887 	}
6888 
6889 	/*
6890 	 * svcadm also expects that the SCF_PROPERTY_STATE property is present.
6891 	 * So in addition to the property group being present, we need to wait
6892 	 * for the property to be there in some form.
6893 	 *
6894 	 * Note that a property group is a frozen snapshot in time. To properly
6895 	 * get beyond this, you have to refresh the property group each time.
6896 	 */
6897 	while ((ret = scf_pg_get_property(imp_pg, SCF_PROPERTY_STATE,
6898 	    imp_prop)) != 0) {
6899 
6900 		ret = scf_error();
6901 		if (ret != SCF_ERROR_NOT_FOUND) {
6902 			warn(gettext("Failed to get property %s from the "
6903 			    "restarter property group of instance %s\n"),
6904 			    SCF_PROPERTY_STATE, inst->sc_name);
6905 			switch (ret) {
6906 			case SCF_ERROR_CONNECTION_BROKEN:
6907 				warn(gettext("Lost repository connection\n"));
6908 				err = ECONNABORTED;
6909 				break;
6910 			case SCF_ERROR_DELETED:
6911 				err = ENODEV;
6912 				break;
6913 			default:
6914 				bad_error("scf_pg_get_property", ret);
6915 			}
6916 
6917 			return (err);
6918 		}
6919 
6920 		ts.tv_sec = pg_timeout / NANOSEC;
6921 		ts.tv_nsec = pg_timeout % NANOSEC;
6922 
6923 		(void) nanosleep(&ts, NULL);
6924 
6925 		ret = scf_instance_get_pg(imp_inst, SCF_PG_RESTARTER, imp_pg);
6926 		if (ret != SCF_SUCCESS) {
6927 			warn(gettext("Failed to get restarter property "
6928 			    "group for instance: %s\n"), inst->sc_name);
6929 			switch (ret) {
6930 			case SCF_ERROR_DELETED:
6931 				err = ENODEV;
6932 				break;
6933 			case SCF_ERROR_CONNECTION_BROKEN:
6934 				warn(gettext("Lost repository connection\n"));
6935 				err = ECONNABORTED;
6936 				break;
6937 			default:
6938 				bad_error("scf_service_get_instance", ret);
6939 			}
6940 
6941 			return (err);
6942 		}
6943 	}
6944 
6945 	/*
6946 	 * We don't have to free the property groups or other values that we got
6947 	 * because we stored them in global variables that are allocated and
6948 	 * freed by the routines that call into these functions. Unless of
6949 	 * course the rest of the code here that we are basing this on is
6950 	 * mistaken.
6951 	 */
6952 	return (0);
6953 }
6954 #endif
6955 
6956 /*
6957  * If the service is missing, create it, import its properties, and import the
6958  * instances.  Since the service is brand new, it should be empty, and if we
6959  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6960  *
6961  * If the service exists, we want to upgrade its properties and import the
6962  * instances.  Upgrade requires a last-import snapshot, though, which are
6963  * children of instances, so first we'll have to go through the instances
6964  * looking for a last-import snapshot.  If we don't find one then we'll just
6965  * override-import the service properties (but don't delete existing
6966  * properties: another service might have declared us as a dependent).  Before
6967  * we change anything, though, we want to take the previous snapshots.  We
6968  * also give lscf_instance_import() a leg up on taking last-import snapshots
6969  * by importing the manifest's service properties into a temporary service.
6970  *
6971  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6972  * sets lcbdata->sc_err to
6973  *   ECONNABORTED - repository connection broken
6974  *   ENOMEM - out of memory
6975  *   ENOSPC - svc.configd is out of resources
6976  *   EPERM - couldn't create temporary service (error printed)
6977  *	   - couldn't import into temp service (error printed)
6978  *	   - couldn't create service (error printed)
6979  *	   - couldn't import dependent (error printed)
6980  *	   - couldn't take snapshot (error printed)
6981  *	   - couldn't create instance (error printed)
6982  *	   - couldn't create, modify, or delete pg (error printed)
6983  *	   - couldn't create, modify, or delete dependent (error printed)
6984  *	   - couldn't import instance (error printed)
6985  *   EROFS - couldn't create temporary service (repository read-only)
6986  *	   - couldn't import into temporary service (repository read-only)
6987  *	   - couldn't create service (repository read-only)
6988  *	   - couldn't import dependent (repository read-only)
6989  *	   - couldn't create instance (repository read-only)
6990  *	   - couldn't create, modify, or delete pg or dependent
6991  *	   - couldn't import instance (repository read-only)
6992  *   EACCES - couldn't create temporary service (backend access denied)
6993  *	    - couldn't import into temporary service (backend access denied)
6994  *	    - couldn't create service (backend access denied)
6995  *	    - couldn't import dependent (backend access denied)
6996  *	    - couldn't create instance (backend access denied)
6997  *	    - couldn't create, modify, or delete pg or dependent
6998  *	    - couldn't import instance (backend access denied)
6999  *   EINVAL - service name is invalid (error printed)
7000  *	    - service name is too long (error printed)
7001  *	    - s has invalid pgroup (error printed)
7002  *	    - s has invalid dependent (error printed)
7003  *	    - instance name is invalid (error printed)
7004  *	    - instance entity_t is invalid (error printed)
7005  *   EEXIST - couldn't create temporary service (already exists) (error printed)
7006  *	    - couldn't import dependent (dependency pg already exists) (printed)
7007  *	    - dependency collision in dependent service (error printed)
7008  *   EBUSY - temporary service deleted (error printed)
7009  *	   - property group added to temporary service (error printed)
7010  *	   - new property group changed or was deleted (error printed)
7011  *	   - service was added unexpectedly (error printed)
7012  *	   - service was deleted unexpectedly (error printed)
7013  *	   - property group added to new service (error printed)
7014  *	   - instance added unexpectedly (error printed)
7015  *	   - instance deleted unexpectedly (error printed)
7016  *	   - dependent service deleted unexpectedly (error printed)
7017  *	   - pg was added, changed, or deleted (error printed)
7018  *	   - dependent pg changed (error printed)
7019  *	   - temporary instance added, changed, or deleted (error printed)
7020  *   EBADF - a last-import snapshot is corrupt (error printed)
7021  *	   - the service is corrupt (error printed)
7022  *	   - a dependent is corrupt (error printed)
7023  *	   - an instance is corrupt (error printed)
7024  *	   - an instance has a corrupt last-import snapshot (error printed)
7025  *	   - dependent target has a corrupt snapshot (error printed)
7026  *   -1 - unknown libscf error (error printed)
7027  */
7028 static int
7029 lscf_service_import(void *v, void *pvt)
7030 {
7031 	entity_t *s = v;
7032 	scf_callback_t cbdata;
7033 	scf_callback_t *lcbdata = pvt;
7034 	scf_scope_t *scope = lcbdata->sc_parent;
7035 	entity_t *inst, linst;
7036 	int r;
7037 	int fresh = 0;
7038 	scf_snaplevel_t *running;
7039 	int have_ge = 0;
7040 	boolean_t retried = B_FALSE;
7041 
7042 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
7043 	    "was deleted unexpectedly.\n");
7044 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
7045 	    "changed unexpectedly (property group added).\n");
7046 	const char * const s_deleted =
7047 	    gettext("%s was deleted unexpectedly.\n");
7048 	const char * const i_deleted =
7049 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
7050 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
7051 	    "is corrupt (missing service snaplevel).\n");
7052 	const char * const s_mfile_upd =
7053 	    gettext("Unable to update the manifest file connection "
7054 	    "for %s\n");
7055 
7056 	li_only = 0;
7057 	/* Validate the service name */
7058 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7059 		switch (scf_error()) {
7060 		case SCF_ERROR_CONNECTION_BROKEN:
7061 			return (stash_scferror(lcbdata));
7062 
7063 		case SCF_ERROR_INVALID_ARGUMENT:
7064 			warn(gettext("\"%s\" is an invalid service name.  "
7065 			    "Cannot import.\n"), s->sc_name);
7066 			return (stash_scferror(lcbdata));
7067 
7068 		case SCF_ERROR_NOT_FOUND:
7069 			break;
7070 
7071 		case SCF_ERROR_HANDLE_MISMATCH:
7072 		case SCF_ERROR_NOT_BOUND:
7073 		case SCF_ERROR_NOT_SET:
7074 		default:
7075 			bad_error("scf_scope_get_service", scf_error());
7076 		}
7077 	}
7078 
7079 	/* create temporary service */
7080 	/*
7081 	 * the size of the buffer was reduced to max_scf_name_len to prevent
7082 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
7083 	 * should be restored to its original value (max_scf_name_len +1)
7084 	 */
7085 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
7086 	if (r < 0)
7087 		bad_error("snprintf", errno);
7088 	if (r > max_scf_name_len) {
7089 		warn(gettext(
7090 		    "Service name \"%s\" is too long.  Cannot import.\n"),
7091 		    s->sc_name);
7092 		lcbdata->sc_err = EINVAL;
7093 		return (UU_WALK_ERROR);
7094 	}
7095 
7096 retry:
7097 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
7098 		switch (scf_error()) {
7099 		case SCF_ERROR_CONNECTION_BROKEN:
7100 		case SCF_ERROR_NO_RESOURCES:
7101 		case SCF_ERROR_BACKEND_READONLY:
7102 		case SCF_ERROR_BACKEND_ACCESS:
7103 			return (stash_scferror(lcbdata));
7104 
7105 		case SCF_ERROR_EXISTS:
7106 			if (!retried) {
7107 				lscf_delete(imp_tsname, 0);
7108 				retried = B_TRUE;
7109 				goto retry;
7110 			}
7111 			warn(gettext(
7112 			    "Temporary service \"%s\" must be deleted before "
7113 			    "this manifest can be imported.\n"), imp_tsname);
7114 			return (stash_scferror(lcbdata));
7115 
7116 		case SCF_ERROR_PERMISSION_DENIED:
7117 			warn(gettext("Could not create temporary service "
7118 			    "\"%s\" (permission denied).\n"), imp_tsname);
7119 			return (stash_scferror(lcbdata));
7120 
7121 		case SCF_ERROR_INVALID_ARGUMENT:
7122 		case SCF_ERROR_HANDLE_MISMATCH:
7123 		case SCF_ERROR_NOT_BOUND:
7124 		case SCF_ERROR_NOT_SET:
7125 		default:
7126 			bad_error("scf_scope_add_service", scf_error());
7127 		}
7128 	}
7129 
7130 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
7131 	if (r < 0)
7132 		bad_error("snprintf", errno);
7133 
7134 	cbdata.sc_handle = lcbdata->sc_handle;
7135 	cbdata.sc_parent = imp_tsvc;
7136 	cbdata.sc_service = 1;
7137 	cbdata.sc_source_fmri = s->sc_fmri;
7138 	cbdata.sc_target_fmri = imp_str;
7139 	cbdata.sc_flags = 0;
7140 
7141 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
7142 	    UU_DEFAULT) != 0) {
7143 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7144 			bad_error("uu_list_walk", uu_error());
7145 
7146 		lcbdata->sc_err = cbdata.sc_err;
7147 		switch (cbdata.sc_err) {
7148 		case ECONNABORTED:
7149 			goto connaborted;
7150 
7151 		case ECANCELED:
7152 			warn(ts_deleted, imp_tsname);
7153 			lcbdata->sc_err = EBUSY;
7154 			return (UU_WALK_ERROR);
7155 
7156 		case EEXIST:
7157 			warn(ts_pg_added, imp_tsname);
7158 			lcbdata->sc_err = EBUSY;
7159 			return (UU_WALK_ERROR);
7160 		}
7161 
7162 		r = UU_WALK_ERROR;
7163 		goto deltemp;
7164 	}
7165 
7166 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
7167 	    UU_DEFAULT) != 0) {
7168 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7169 			bad_error("uu_list_walk", uu_error());
7170 
7171 		lcbdata->sc_err = cbdata.sc_err;
7172 		switch (cbdata.sc_err) {
7173 		case ECONNABORTED:
7174 			goto connaborted;
7175 
7176 		case ECANCELED:
7177 			warn(ts_deleted, imp_tsname);
7178 			lcbdata->sc_err = EBUSY;
7179 			return (UU_WALK_ERROR);
7180 
7181 		case EEXIST:
7182 			warn(ts_pg_added, imp_tsname);
7183 			lcbdata->sc_err = EBUSY;
7184 			return (UU_WALK_ERROR);
7185 		}
7186 
7187 		r = UU_WALK_ERROR;
7188 		goto deltemp;
7189 	}
7190 
7191 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
7192 		switch (scf_error()) {
7193 		case SCF_ERROR_NOT_FOUND:
7194 			break;
7195 
7196 		case SCF_ERROR_CONNECTION_BROKEN:
7197 			goto connaborted;
7198 
7199 		case SCF_ERROR_INVALID_ARGUMENT:
7200 		case SCF_ERROR_HANDLE_MISMATCH:
7201 		case SCF_ERROR_NOT_BOUND:
7202 		case SCF_ERROR_NOT_SET:
7203 		default:
7204 			bad_error("scf_scope_get_service", scf_error());
7205 		}
7206 
7207 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
7208 			switch (scf_error()) {
7209 			case SCF_ERROR_CONNECTION_BROKEN:
7210 				goto connaborted;
7211 
7212 			case SCF_ERROR_NO_RESOURCES:
7213 			case SCF_ERROR_BACKEND_READONLY:
7214 			case SCF_ERROR_BACKEND_ACCESS:
7215 				r = stash_scferror(lcbdata);
7216 				goto deltemp;
7217 
7218 			case SCF_ERROR_EXISTS:
7219 				warn(gettext("Scope \"%s\" changed unexpectedly"
7220 				    " (service \"%s\" added).\n"),
7221 				    SCF_SCOPE_LOCAL, s->sc_name);
7222 				lcbdata->sc_err = EBUSY;
7223 				goto deltemp;
7224 
7225 			case SCF_ERROR_PERMISSION_DENIED:
7226 				warn(gettext("Could not create service \"%s\" "
7227 				    "(permission denied).\n"), s->sc_name);
7228 				goto deltemp;
7229 
7230 			case SCF_ERROR_INVALID_ARGUMENT:
7231 			case SCF_ERROR_HANDLE_MISMATCH:
7232 			case SCF_ERROR_NOT_BOUND:
7233 			case SCF_ERROR_NOT_SET:
7234 			default:
7235 				bad_error("scf_scope_add_service", scf_error());
7236 			}
7237 		}
7238 
7239 		s->sc_import_state = IMPORT_PROP_BEGUN;
7240 
7241 		/* import service properties */
7242 		cbdata.sc_handle = lcbdata->sc_handle;
7243 		cbdata.sc_parent = imp_svc;
7244 		cbdata.sc_service = 1;
7245 		cbdata.sc_flags = lcbdata->sc_flags;
7246 		cbdata.sc_source_fmri = s->sc_fmri;
7247 		cbdata.sc_target_fmri = s->sc_fmri;
7248 
7249 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7250 		    &cbdata, UU_DEFAULT) != 0) {
7251 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7252 				bad_error("uu_list_walk", uu_error());
7253 
7254 			lcbdata->sc_err = cbdata.sc_err;
7255 			switch (cbdata.sc_err) {
7256 			case ECONNABORTED:
7257 				goto connaborted;
7258 
7259 			case ECANCELED:
7260 				warn(s_deleted, s->sc_fmri);
7261 				lcbdata->sc_err = EBUSY;
7262 				return (UU_WALK_ERROR);
7263 
7264 			case EEXIST:
7265 				warn(gettext("%s changed unexpectedly "
7266 				    "(property group added).\n"), s->sc_fmri);
7267 				lcbdata->sc_err = EBUSY;
7268 				return (UU_WALK_ERROR);
7269 
7270 			case EINVAL:
7271 				/* caught above */
7272 				bad_error("entity_pgroup_import",
7273 				    cbdata.sc_err);
7274 			}
7275 
7276 			r = UU_WALK_ERROR;
7277 			goto deltemp;
7278 		}
7279 
7280 		cbdata.sc_trans = NULL;
7281 		cbdata.sc_flags = 0;
7282 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7283 		    &cbdata, UU_DEFAULT) != 0) {
7284 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7285 				bad_error("uu_list_walk", uu_error());
7286 
7287 			lcbdata->sc_err = cbdata.sc_err;
7288 			if (cbdata.sc_err == ECONNABORTED)
7289 				goto connaborted;
7290 			r = UU_WALK_ERROR;
7291 			goto deltemp;
7292 		}
7293 
7294 		s->sc_import_state = IMPORT_PROP_DONE;
7295 
7296 		/*
7297 		 * This is a new service, so we can't take previous snapshots
7298 		 * or upgrade service properties.
7299 		 */
7300 		fresh = 1;
7301 		goto instances;
7302 	}
7303 
7304 	/* Clear sc_seen for the instances. */
7305 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7306 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7307 		bad_error("uu_list_walk", uu_error());
7308 
7309 	/*
7310 	 * Take previous snapshots for all instances.  Even for ones not
7311 	 * mentioned in the bundle, since we might change their service
7312 	 * properties.
7313 	 */
7314 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7315 		switch (scf_error()) {
7316 		case SCF_ERROR_CONNECTION_BROKEN:
7317 			goto connaborted;
7318 
7319 		case SCF_ERROR_DELETED:
7320 			warn(s_deleted, s->sc_fmri);
7321 			lcbdata->sc_err = EBUSY;
7322 			r = UU_WALK_ERROR;
7323 			goto deltemp;
7324 
7325 		case SCF_ERROR_HANDLE_MISMATCH:
7326 		case SCF_ERROR_NOT_BOUND:
7327 		case SCF_ERROR_NOT_SET:
7328 		default:
7329 			bad_error("scf_iter_service_instances", scf_error());
7330 		}
7331 	}
7332 
7333 	for (;;) {
7334 		r = scf_iter_next_instance(imp_iter, imp_inst);
7335 		if (r == 0)
7336 			break;
7337 		if (r != 1) {
7338 			switch (scf_error()) {
7339 			case SCF_ERROR_DELETED:
7340 				warn(s_deleted, s->sc_fmri);
7341 				lcbdata->sc_err = EBUSY;
7342 				r = UU_WALK_ERROR;
7343 				goto deltemp;
7344 
7345 			case SCF_ERROR_CONNECTION_BROKEN:
7346 				goto connaborted;
7347 
7348 			case SCF_ERROR_NOT_BOUND:
7349 			case SCF_ERROR_HANDLE_MISMATCH:
7350 			case SCF_ERROR_INVALID_ARGUMENT:
7351 			case SCF_ERROR_NOT_SET:
7352 			default:
7353 				bad_error("scf_iter_next_instance",
7354 				    scf_error());
7355 			}
7356 		}
7357 
7358 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7359 			switch (scf_error()) {
7360 			case SCF_ERROR_DELETED:
7361 				continue;
7362 
7363 			case SCF_ERROR_CONNECTION_BROKEN:
7364 				goto connaborted;
7365 
7366 			case SCF_ERROR_NOT_SET:
7367 			case SCF_ERROR_NOT_BOUND:
7368 			default:
7369 				bad_error("scf_instance_get_name", scf_error());
7370 			}
7371 		}
7372 
7373 		if (g_verbose)
7374 			warn(gettext(
7375 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7376 			    snap_previous, s->sc_name, imp_str);
7377 
7378 		r = take_snap(imp_inst, snap_previous, imp_snap);
7379 		switch (r) {
7380 		case 0:
7381 			break;
7382 
7383 		case ECANCELED:
7384 			continue;
7385 
7386 		case ECONNABORTED:
7387 			goto connaborted;
7388 
7389 		case EPERM:
7390 			warn(gettext("Could not take \"%s\" snapshot of "
7391 			    "svc:/%s:%s (permission denied).\n"),
7392 			    snap_previous, s->sc_name, imp_str);
7393 			lcbdata->sc_err = r;
7394 			return (UU_WALK_ERROR);
7395 
7396 		case ENOSPC:
7397 		case -1:
7398 			lcbdata->sc_err = r;
7399 			r = UU_WALK_ERROR;
7400 			goto deltemp;
7401 
7402 		default:
7403 			bad_error("take_snap", r);
7404 		}
7405 
7406 		linst.sc_name = imp_str;
7407 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7408 		    &linst, NULL, NULL);
7409 		if (inst != NULL) {
7410 			inst->sc_import_state = IMPORT_PREVIOUS;
7411 			inst->sc_seen = 1;
7412 		}
7413 	}
7414 
7415 	/*
7416 	 * Create the new instances and take previous snapshots of
7417 	 * them.  This is not necessary, but it maximizes data preservation.
7418 	 */
7419 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7420 	    inst != NULL;
7421 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7422 	    inst)) {
7423 		if (inst->sc_seen)
7424 			continue;
7425 
7426 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7427 		    imp_inst) != 0) {
7428 			switch (scf_error()) {
7429 			case SCF_ERROR_CONNECTION_BROKEN:
7430 				goto connaborted;
7431 
7432 			case SCF_ERROR_BACKEND_READONLY:
7433 			case SCF_ERROR_BACKEND_ACCESS:
7434 			case SCF_ERROR_NO_RESOURCES:
7435 				r = stash_scferror(lcbdata);
7436 				goto deltemp;
7437 
7438 			case SCF_ERROR_EXISTS:
7439 				warn(gettext("%s changed unexpectedly "
7440 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7441 				    inst->sc_name);
7442 				lcbdata->sc_err = EBUSY;
7443 				r = UU_WALK_ERROR;
7444 				goto deltemp;
7445 
7446 			case SCF_ERROR_INVALID_ARGUMENT:
7447 				warn(gettext("Service \"%s\" has instance with "
7448 				    "invalid name \"%s\".\n"), s->sc_name,
7449 				    inst->sc_name);
7450 				r = stash_scferror(lcbdata);
7451 				goto deltemp;
7452 
7453 			case SCF_ERROR_PERMISSION_DENIED:
7454 				warn(gettext("Could not create instance \"%s\" "
7455 				    "in %s (permission denied).\n"),
7456 				    inst->sc_name, s->sc_fmri);
7457 				r = stash_scferror(lcbdata);
7458 				goto deltemp;
7459 
7460 			case SCF_ERROR_HANDLE_MISMATCH:
7461 			case SCF_ERROR_NOT_BOUND:
7462 			case SCF_ERROR_NOT_SET:
7463 			default:
7464 				bad_error("scf_service_add_instance",
7465 				    scf_error());
7466 			}
7467 		}
7468 
7469 		if (g_verbose)
7470 			warn(gettext("Taking \"%s\" snapshot for "
7471 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7472 		r = take_snap(imp_inst, snap_previous, imp_snap);
7473 		switch (r) {
7474 		case 0:
7475 			break;
7476 
7477 		case ECANCELED:
7478 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7479 			lcbdata->sc_err = EBUSY;
7480 			r = UU_WALK_ERROR;
7481 			goto deltemp;
7482 
7483 		case ECONNABORTED:
7484 			goto connaborted;
7485 
7486 		case EPERM:
7487 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7488 			lcbdata->sc_err = r;
7489 			r = UU_WALK_ERROR;
7490 			goto deltemp;
7491 
7492 		case ENOSPC:
7493 		case -1:
7494 			r = UU_WALK_ERROR;
7495 			goto deltemp;
7496 
7497 		default:
7498 			bad_error("take_snap", r);
7499 		}
7500 	}
7501 
7502 	s->sc_import_state = IMPORT_PREVIOUS;
7503 
7504 	/*
7505 	 * Upgrade service properties, if we can find a last-import snapshot.
7506 	 * Any will do because we don't support different service properties
7507 	 * in different manifests, so all snaplevels of the service in all of
7508 	 * the last-import snapshots of the instances should be the same.
7509 	 */
7510 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7511 		switch (scf_error()) {
7512 		case SCF_ERROR_CONNECTION_BROKEN:
7513 			goto connaborted;
7514 
7515 		case SCF_ERROR_DELETED:
7516 			warn(s_deleted, s->sc_fmri);
7517 			lcbdata->sc_err = EBUSY;
7518 			r = UU_WALK_ERROR;
7519 			goto deltemp;
7520 
7521 		case SCF_ERROR_HANDLE_MISMATCH:
7522 		case SCF_ERROR_NOT_BOUND:
7523 		case SCF_ERROR_NOT_SET:
7524 		default:
7525 			bad_error("scf_iter_service_instances", scf_error());
7526 		}
7527 	}
7528 
7529 	for (;;) {
7530 		r = scf_iter_next_instance(imp_iter, imp_inst);
7531 		if (r == -1) {
7532 			switch (scf_error()) {
7533 			case SCF_ERROR_DELETED:
7534 				warn(s_deleted, s->sc_fmri);
7535 				lcbdata->sc_err = EBUSY;
7536 				r = UU_WALK_ERROR;
7537 				goto deltemp;
7538 
7539 			case SCF_ERROR_CONNECTION_BROKEN:
7540 				goto connaborted;
7541 
7542 			case SCF_ERROR_NOT_BOUND:
7543 			case SCF_ERROR_HANDLE_MISMATCH:
7544 			case SCF_ERROR_INVALID_ARGUMENT:
7545 			case SCF_ERROR_NOT_SET:
7546 			default:
7547 				bad_error("scf_iter_next_instance",
7548 				    scf_error());
7549 			}
7550 		}
7551 
7552 		if (r == 0) {
7553 			/*
7554 			 * Didn't find any last-import snapshots.  Override-
7555 			 * import the properties.  Unless one of the instances
7556 			 * has a general/enabled property, in which case we're
7557 			 * probably running a last-import-capable svccfg for
7558 			 * the first time, and we should only take the
7559 			 * last-import snapshot.
7560 			 */
7561 			if (have_ge) {
7562 				pgroup_t *mfpg;
7563 				scf_callback_t mfcbdata;
7564 
7565 				li_only = 1;
7566 				no_refresh = 1;
7567 				/*
7568 				 * Need to go ahead and import the manifestfiles
7569 				 * pg if it exists. If the last-import snapshot
7570 				 * upgrade code is ever removed this code can
7571 				 * be removed as well.
7572 				 */
7573 				mfpg = internal_pgroup_find(s,
7574 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7575 
7576 				if (mfpg) {
7577 					mfcbdata.sc_handle = g_hndl;
7578 					mfcbdata.sc_parent = imp_svc;
7579 					mfcbdata.sc_service = 1;
7580 					mfcbdata.sc_flags = SCI_FORCE;
7581 					mfcbdata.sc_source_fmri = s->sc_fmri;
7582 					mfcbdata.sc_target_fmri = s->sc_fmri;
7583 					if (entity_pgroup_import(mfpg,
7584 					    &mfcbdata) != UU_WALK_NEXT) {
7585 						warn(s_mfile_upd, s->sc_fmri);
7586 						r = UU_WALK_ERROR;
7587 						goto deltemp;
7588 					}
7589 				}
7590 				break;
7591 			}
7592 
7593 			s->sc_import_state = IMPORT_PROP_BEGUN;
7594 
7595 			cbdata.sc_handle = g_hndl;
7596 			cbdata.sc_parent = imp_svc;
7597 			cbdata.sc_service = 1;
7598 			cbdata.sc_flags = SCI_FORCE;
7599 			cbdata.sc_source_fmri = s->sc_fmri;
7600 			cbdata.sc_target_fmri = s->sc_fmri;
7601 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7602 			    &cbdata, UU_DEFAULT) != 0) {
7603 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7604 					bad_error("uu_list_walk", uu_error());
7605 				lcbdata->sc_err = cbdata.sc_err;
7606 				switch (cbdata.sc_err) {
7607 				case ECONNABORTED:
7608 					goto connaborted;
7609 
7610 				case ECANCELED:
7611 					warn(s_deleted, s->sc_fmri);
7612 					lcbdata->sc_err = EBUSY;
7613 					break;
7614 
7615 				case EINVAL:	/* caught above */
7616 				case EEXIST:
7617 					bad_error("entity_pgroup_import",
7618 					    cbdata.sc_err);
7619 				}
7620 
7621 				r = UU_WALK_ERROR;
7622 				goto deltemp;
7623 			}
7624 
7625 			cbdata.sc_trans = NULL;
7626 			cbdata.sc_flags = 0;
7627 			if (uu_list_walk(s->sc_dependents,
7628 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7629 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7630 					bad_error("uu_list_walk", uu_error());
7631 				lcbdata->sc_err = cbdata.sc_err;
7632 				if (cbdata.sc_err == ECONNABORTED)
7633 					goto connaborted;
7634 				r = UU_WALK_ERROR;
7635 				goto deltemp;
7636 			}
7637 			break;
7638 		}
7639 
7640 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7641 		    imp_snap) != 0) {
7642 			switch (scf_error()) {
7643 			case SCF_ERROR_DELETED:
7644 				continue;
7645 
7646 			case SCF_ERROR_NOT_FOUND:
7647 				break;
7648 
7649 			case SCF_ERROR_CONNECTION_BROKEN:
7650 				goto connaborted;
7651 
7652 			case SCF_ERROR_HANDLE_MISMATCH:
7653 			case SCF_ERROR_NOT_BOUND:
7654 			case SCF_ERROR_INVALID_ARGUMENT:
7655 			case SCF_ERROR_NOT_SET:
7656 			default:
7657 				bad_error("scf_instance_get_snapshot",
7658 				    scf_error());
7659 			}
7660 
7661 			if (have_ge)
7662 				continue;
7663 
7664 			/*
7665 			 * Check for a general/enabled property.  This is how
7666 			 * we tell whether to import if there turn out to be
7667 			 * no last-import snapshots.
7668 			 */
7669 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7670 			    imp_pg) == 0) {
7671 				if (scf_pg_get_property(imp_pg,
7672 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7673 					have_ge = 1;
7674 				} else {
7675 					switch (scf_error()) {
7676 					case SCF_ERROR_DELETED:
7677 					case SCF_ERROR_NOT_FOUND:
7678 						continue;
7679 
7680 					case SCF_ERROR_INVALID_ARGUMENT:
7681 					case SCF_ERROR_HANDLE_MISMATCH:
7682 					case SCF_ERROR_CONNECTION_BROKEN:
7683 					case SCF_ERROR_NOT_BOUND:
7684 					case SCF_ERROR_NOT_SET:
7685 					default:
7686 						bad_error("scf_pg_get_property",
7687 						    scf_error());
7688 					}
7689 				}
7690 			} else {
7691 				switch (scf_error()) {
7692 				case SCF_ERROR_DELETED:
7693 				case SCF_ERROR_NOT_FOUND:
7694 					continue;
7695 
7696 				case SCF_ERROR_CONNECTION_BROKEN:
7697 					goto connaborted;
7698 
7699 				case SCF_ERROR_NOT_BOUND:
7700 				case SCF_ERROR_NOT_SET:
7701 				case SCF_ERROR_INVALID_ARGUMENT:
7702 				case SCF_ERROR_HANDLE_MISMATCH:
7703 				default:
7704 					bad_error("scf_instance_get_pg",
7705 					    scf_error());
7706 				}
7707 			}
7708 			continue;
7709 		}
7710 
7711 		/* find service snaplevel */
7712 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7713 		switch (r) {
7714 		case 0:
7715 			break;
7716 
7717 		case ECONNABORTED:
7718 			goto connaborted;
7719 
7720 		case ECANCELED:
7721 			continue;
7722 
7723 		case ENOENT:
7724 			if (scf_instance_get_name(imp_inst, imp_str,
7725 			    imp_str_sz) < 0)
7726 				(void) strcpy(imp_str, "?");
7727 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7728 			lcbdata->sc_err = EBADF;
7729 			r = UU_WALK_ERROR;
7730 			goto deltemp;
7731 
7732 		default:
7733 			bad_error("get_snaplevel", r);
7734 		}
7735 
7736 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7737 		    imp_rsnap) != 0) {
7738 			switch (scf_error()) {
7739 			case SCF_ERROR_DELETED:
7740 				continue;
7741 
7742 			case SCF_ERROR_NOT_FOUND:
7743 				break;
7744 
7745 			case SCF_ERROR_CONNECTION_BROKEN:
7746 				goto connaborted;
7747 
7748 			case SCF_ERROR_INVALID_ARGUMENT:
7749 			case SCF_ERROR_HANDLE_MISMATCH:
7750 			case SCF_ERROR_NOT_BOUND:
7751 			case SCF_ERROR_NOT_SET:
7752 			default:
7753 				bad_error("scf_instance_get_snapshot",
7754 				    scf_error());
7755 			}
7756 			running = NULL;
7757 		} else {
7758 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7759 			switch (r) {
7760 			case 0:
7761 				running = imp_rsnpl;
7762 				break;
7763 
7764 			case ECONNABORTED:
7765 				goto connaborted;
7766 
7767 			case ECANCELED:
7768 				continue;
7769 
7770 			case ENOENT:
7771 				if (scf_instance_get_name(imp_inst, imp_str,
7772 				    imp_str_sz) < 0)
7773 					(void) strcpy(imp_str, "?");
7774 				warn(badsnap, snap_running, s->sc_name,
7775 				    imp_str);
7776 				lcbdata->sc_err = EBADF;
7777 				r = UU_WALK_ERROR;
7778 				goto deltemp;
7779 
7780 			default:
7781 				bad_error("get_snaplevel", r);
7782 			}
7783 		}
7784 
7785 		if (g_verbose) {
7786 			if (scf_instance_get_name(imp_inst, imp_str,
7787 			    imp_str_sz) < 0)
7788 				(void) strcpy(imp_str, "?");
7789 			warn(gettext("Upgrading properties of %s according to "
7790 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7791 		}
7792 
7793 		/* upgrade service properties */
7794 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7795 		if (r == 0)
7796 			break;
7797 
7798 		switch (r) {
7799 		case ECONNABORTED:
7800 			goto connaborted;
7801 
7802 		case ECANCELED:
7803 			warn(s_deleted, s->sc_fmri);
7804 			lcbdata->sc_err = EBUSY;
7805 			break;
7806 
7807 		case ENODEV:
7808 			if (scf_instance_get_name(imp_inst, imp_str,
7809 			    imp_str_sz) < 0)
7810 				(void) strcpy(imp_str, "?");
7811 			warn(i_deleted, s->sc_fmri, imp_str);
7812 			lcbdata->sc_err = EBUSY;
7813 			break;
7814 
7815 		default:
7816 			lcbdata->sc_err = r;
7817 		}
7818 
7819 		r = UU_WALK_ERROR;
7820 		goto deltemp;
7821 	}
7822 
7823 	s->sc_import_state = IMPORT_PROP_DONE;
7824 
7825 instances:
7826 	/* import instances */
7827 	cbdata.sc_handle = lcbdata->sc_handle;
7828 	cbdata.sc_parent = imp_svc;
7829 	cbdata.sc_service = 1;
7830 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7831 	cbdata.sc_general = NULL;
7832 
7833 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7834 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7835 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7836 			bad_error("uu_list_walk", uu_error());
7837 
7838 		lcbdata->sc_err = cbdata.sc_err;
7839 		if (cbdata.sc_err == ECONNABORTED)
7840 			goto connaborted;
7841 		r = UU_WALK_ERROR;
7842 		goto deltemp;
7843 	}
7844 
7845 	s->sc_import_state = IMPORT_COMPLETE;
7846 	r = UU_WALK_NEXT;
7847 
7848 deltemp:
7849 	/* delete temporary service */
7850 	if (scf_service_delete(imp_tsvc) != 0) {
7851 		switch (scf_error()) {
7852 		case SCF_ERROR_DELETED:
7853 			break;
7854 
7855 		case SCF_ERROR_CONNECTION_BROKEN:
7856 			goto connaborted;
7857 
7858 		case SCF_ERROR_EXISTS:
7859 			warn(gettext(
7860 			    "Could not delete svc:/%s (instances exist).\n"),
7861 			    imp_tsname);
7862 			break;
7863 
7864 		case SCF_ERROR_NOT_SET:
7865 		case SCF_ERROR_NOT_BOUND:
7866 		default:
7867 			bad_error("scf_service_delete", scf_error());
7868 		}
7869 	}
7870 
7871 	return (r);
7872 
7873 connaborted:
7874 	warn(gettext("Could not delete svc:/%s "
7875 	    "(repository connection broken).\n"), imp_tsname);
7876 	lcbdata->sc_err = ECONNABORTED;
7877 	return (UU_WALK_ERROR);
7878 }
7879 
7880 static const char *
7881 import_progress(int st)
7882 {
7883 	switch (st) {
7884 	case 0:
7885 		return (gettext("not reached."));
7886 
7887 	case IMPORT_PREVIOUS:
7888 		return (gettext("previous snapshot taken."));
7889 
7890 	case IMPORT_PROP_BEGUN:
7891 		return (gettext("some properties imported."));
7892 
7893 	case IMPORT_PROP_DONE:
7894 		return (gettext("properties imported."));
7895 
7896 	case IMPORT_COMPLETE:
7897 		return (gettext("imported."));
7898 
7899 	case IMPORT_REFRESHED:
7900 		return (gettext("refresh requested."));
7901 
7902 	default:
7903 #ifndef NDEBUG
7904 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7905 		    __FILE__, __LINE__, st);
7906 #endif
7907 		abort();
7908 		/* NOTREACHED */
7909 	}
7910 }
7911 
7912 /*
7913  * Returns
7914  *   0 - success
7915  *     - fmri wasn't found (error printed)
7916  *     - entity was deleted (error printed)
7917  *     - backend denied access (error printed)
7918  *   ENOMEM - out of memory (error printed)
7919  *   ECONNABORTED - repository connection broken (error printed)
7920  *   EPERM - permission denied (error printed)
7921  *   -1 - unknown libscf error (error printed)
7922  */
7923 static int
7924 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7925 {
7926 	scf_error_t serr;
7927 	void *ent;
7928 	int issvc;
7929 	int r;
7930 
7931 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7932 	const char *dpt_deleted = gettext("Could not refresh %s "
7933 	    "(dependent \"%s\" of %s) (deleted).\n");
7934 
7935 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7936 	switch (serr) {
7937 	case SCF_ERROR_NONE:
7938 		break;
7939 
7940 	case SCF_ERROR_NO_MEMORY:
7941 		if (name == NULL)
7942 			warn(gettext("Could not refresh %s (out of memory).\n"),
7943 			    fmri);
7944 		else
7945 			warn(gettext("Could not refresh %s "
7946 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7947 			    fmri, name, d_fmri);
7948 		return (ENOMEM);
7949 
7950 	case SCF_ERROR_NOT_FOUND:
7951 		if (name == NULL)
7952 			warn(deleted, fmri);
7953 		else
7954 			warn(dpt_deleted, fmri, name, d_fmri);
7955 		return (0);
7956 
7957 	case SCF_ERROR_INVALID_ARGUMENT:
7958 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7959 	default:
7960 		bad_error("fmri_to_entity", serr);
7961 	}
7962 
7963 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7964 	switch (r) {
7965 	case 0:
7966 		break;
7967 
7968 	case ECONNABORTED:
7969 		if (name != NULL)
7970 			warn(gettext("Could not refresh %s "
7971 			    "(dependent \"%s\" of %s) "
7972 			    "(repository connection broken).\n"), fmri, name,
7973 			    d_fmri);
7974 		return (r);
7975 
7976 	case ECANCELED:
7977 		if (name == NULL)
7978 			warn(deleted, fmri);
7979 		else
7980 			warn(dpt_deleted, fmri, name, d_fmri);
7981 		return (0);
7982 
7983 	case EACCES:
7984 		if (!g_verbose)
7985 			return (0);
7986 		if (name == NULL)
7987 			warn(gettext("Could not refresh %s "
7988 			    "(backend access denied).\n"), fmri);
7989 		else
7990 			warn(gettext("Could not refresh %s "
7991 			    "(dependent \"%s\" of %s) "
7992 			    "(backend access denied).\n"), fmri, name, d_fmri);
7993 		return (0);
7994 
7995 	case EPERM:
7996 		if (name == NULL)
7997 			warn(gettext("Could not refresh %s "
7998 			    "(permission denied).\n"), fmri);
7999 		else
8000 			warn(gettext("Could not refresh %s "
8001 			    "(dependent \"%s\" of %s) "
8002 			    "(permission denied).\n"), fmri, name, d_fmri);
8003 		return (r);
8004 
8005 	case ENOSPC:
8006 		if (name == NULL)
8007 			warn(gettext("Could not refresh %s "
8008 			    "(repository server out of resources).\n"),
8009 			    fmri);
8010 		else
8011 			warn(gettext("Could not refresh %s "
8012 			    "(dependent \"%s\" of %s) "
8013 			    "(repository server out of resources).\n"),
8014 			    fmri, name, d_fmri);
8015 		return (r);
8016 
8017 	case -1:
8018 		scfwarn();
8019 		return (r);
8020 
8021 	default:
8022 		bad_error("refresh_entity", r);
8023 	}
8024 
8025 	if (issvc)
8026 		scf_service_destroy(ent);
8027 	else
8028 		scf_instance_destroy(ent);
8029 
8030 	return (0);
8031 }
8032 
8033 static int
8034 alloc_imp_globals()
8035 {
8036 	int r;
8037 
8038 	const char * const emsg_nomem = gettext("Out of memory.\n");
8039 	const char * const emsg_nores =
8040 	    gettext("svc.configd is out of resources.\n");
8041 
8042 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
8043 	    max_scf_name_len : max_scf_fmri_len) + 1;
8044 
8045 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
8046 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
8047 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
8048 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
8049 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
8050 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
8051 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
8052 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
8053 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
8054 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8055 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
8056 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
8057 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
8058 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
8059 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
8060 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
8061 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
8062 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
8063 	    (imp_str = malloc(imp_str_sz)) == NULL ||
8064 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
8065 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
8066 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
8067 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
8068 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
8069 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
8070 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
8071 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
8072 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
8073 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
8074 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
8075 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
8076 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
8077 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
8078 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
8079 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
8080 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
8081 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
8082 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
8083 			warn(emsg_nores);
8084 		else
8085 			warn(emsg_nomem);
8086 
8087 		return (-1);
8088 	}
8089 
8090 	r = load_init();
8091 	switch (r) {
8092 	case 0:
8093 		break;
8094 
8095 	case ENOMEM:
8096 		warn(emsg_nomem);
8097 		return (-1);
8098 
8099 	default:
8100 		bad_error("load_init", r);
8101 	}
8102 
8103 	return (0);
8104 }
8105 
8106 static void
8107 free_imp_globals()
8108 {
8109 	pgroup_t *old_dpt;
8110 	void *cookie;
8111 
8112 	load_fini();
8113 
8114 	free(ud_ctarg);
8115 	free(ud_oldtarg);
8116 	free(ud_name);
8117 	ud_ctarg = ud_oldtarg = ud_name = NULL;
8118 
8119 	scf_transaction_destroy(ud_tx);
8120 	ud_tx = NULL;
8121 	scf_iter_destroy(ud_iter);
8122 	scf_iter_destroy(ud_iter2);
8123 	ud_iter = ud_iter2 = NULL;
8124 	scf_value_destroy(ud_val);
8125 	ud_val = NULL;
8126 	scf_property_destroy(ud_prop);
8127 	scf_property_destroy(ud_dpt_prop);
8128 	ud_prop = ud_dpt_prop = NULL;
8129 	scf_pg_destroy(ud_pg);
8130 	scf_pg_destroy(ud_cur_depts_pg);
8131 	scf_pg_destroy(ud_run_dpts_pg);
8132 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
8133 	scf_snaplevel_destroy(ud_snpl);
8134 	ud_snpl = NULL;
8135 	scf_instance_destroy(ud_inst);
8136 	ud_inst = NULL;
8137 
8138 	free(imp_str);
8139 	free(imp_tsname);
8140 	free(imp_fe1);
8141 	free(imp_fe2);
8142 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
8143 
8144 	cookie = NULL;
8145 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
8146 	    NULL) {
8147 		free((char *)old_dpt->sc_pgroup_name);
8148 		free((char *)old_dpt->sc_pgroup_fmri);
8149 		internal_pgroup_free(old_dpt);
8150 	}
8151 	uu_list_destroy(imp_deleted_dpts);
8152 
8153 	scf_transaction_destroy(imp_tx);
8154 	imp_tx = NULL;
8155 	scf_iter_destroy(imp_iter);
8156 	scf_iter_destroy(imp_rpg_iter);
8157 	scf_iter_destroy(imp_up_iter);
8158 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
8159 	scf_property_destroy(imp_prop);
8160 	imp_prop = NULL;
8161 	scf_pg_destroy(imp_pg);
8162 	scf_pg_destroy(imp_pg2);
8163 	imp_pg = imp_pg2 = NULL;
8164 	scf_snaplevel_destroy(imp_snpl);
8165 	scf_snaplevel_destroy(imp_rsnpl);
8166 	imp_snpl = imp_rsnpl = NULL;
8167 	scf_snapshot_destroy(imp_snap);
8168 	scf_snapshot_destroy(imp_lisnap);
8169 	scf_snapshot_destroy(imp_tlisnap);
8170 	scf_snapshot_destroy(imp_rsnap);
8171 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
8172 	scf_instance_destroy(imp_inst);
8173 	scf_instance_destroy(imp_tinst);
8174 	imp_inst = imp_tinst = NULL;
8175 	scf_service_destroy(imp_svc);
8176 	scf_service_destroy(imp_tsvc);
8177 	imp_svc = imp_tsvc = NULL;
8178 	scf_scope_destroy(imp_scope);
8179 	imp_scope = NULL;
8180 
8181 	load_fini();
8182 }
8183 
8184 int
8185 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
8186 {
8187 	scf_callback_t cbdata;
8188 	int result = 0;
8189 	entity_t *svc, *inst;
8190 	uu_list_t *insts;
8191 	int r;
8192 	pgroup_t *old_dpt;
8193 	int annotation_set = 0;
8194 
8195 	const char * const emsg_nomem = gettext("Out of memory.\n");
8196 	const char * const emsg_nores =
8197 	    gettext("svc.configd is out of resources.\n");
8198 
8199 	lscf_prep_hndl();
8200 
8201 	if (alloc_imp_globals())
8202 		goto out;
8203 
8204 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
8205 		switch (scf_error()) {
8206 		case SCF_ERROR_CONNECTION_BROKEN:
8207 			warn(gettext("Repository connection broken.\n"));
8208 			repository_teardown();
8209 			result = -1;
8210 			goto out;
8211 
8212 		case SCF_ERROR_NOT_FOUND:
8213 		case SCF_ERROR_INVALID_ARGUMENT:
8214 		case SCF_ERROR_NOT_BOUND:
8215 		case SCF_ERROR_HANDLE_MISMATCH:
8216 		default:
8217 			bad_error("scf_handle_get_scope", scf_error());
8218 		}
8219 	}
8220 
8221 	/* Set up the auditing annotation. */
8222 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8223 		annotation_set = 1;
8224 	} else {
8225 		switch (scf_error()) {
8226 		case SCF_ERROR_CONNECTION_BROKEN:
8227 			warn(gettext("Repository connection broken.\n"));
8228 			repository_teardown();
8229 			result = -1;
8230 			goto out;
8231 
8232 		case SCF_ERROR_INVALID_ARGUMENT:
8233 		case SCF_ERROR_NOT_BOUND:
8234 		case SCF_ERROR_NO_RESOURCES:
8235 		case SCF_ERROR_INTERNAL:
8236 			bad_error("_scf_set_annotation", scf_error());
8237 			/* NOTREACHED */
8238 
8239 		default:
8240 			/*
8241 			 * Do not terminate import because of inability to
8242 			 * generate annotation audit event.
8243 			 */
8244 			warn(gettext("_scf_set_annotation() unexpectedly "
8245 			    "failed with return code of %d\n"), scf_error());
8246 			break;
8247 		}
8248 	}
8249 
8250 	/*
8251 	 * Clear the sc_import_state's of all services & instances so we can
8252 	 * report how far we got if we fail.
8253 	 */
8254 	for (svc = uu_list_first(bndl->sc_bundle_services);
8255 	    svc != NULL;
8256 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8257 		svc->sc_import_state = 0;
8258 
8259 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8260 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8261 		    UU_DEFAULT) != 0)
8262 			bad_error("uu_list_walk", uu_error());
8263 	}
8264 
8265 	cbdata.sc_handle = g_hndl;
8266 	cbdata.sc_parent = imp_scope;
8267 	cbdata.sc_flags = flags;
8268 	cbdata.sc_general = NULL;
8269 
8270 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8271 	    &cbdata, UU_DEFAULT) == 0) {
8272 		char *eptr;
8273 		/* Success.  Refresh everything. */
8274 
8275 		if (flags & SCI_NOREFRESH || no_refresh) {
8276 			no_refresh = 0;
8277 			result = 0;
8278 			goto out;
8279 		}
8280 
8281 		for (svc = uu_list_first(bndl->sc_bundle_services);
8282 		    svc != NULL;
8283 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8284 			pgroup_t *dpt;
8285 
8286 			insts = svc->sc_u.sc_service.sc_service_instances;
8287 
8288 			for (inst = uu_list_first(insts);
8289 			    inst != NULL;
8290 			    inst = uu_list_next(insts, inst)) {
8291 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8292 				switch (r) {
8293 				case 0:
8294 					break;
8295 
8296 				case ENOMEM:
8297 				case ECONNABORTED:
8298 				case EPERM:
8299 				case -1:
8300 					goto progress;
8301 
8302 				default:
8303 					bad_error("imp_refresh_fmri", r);
8304 				}
8305 
8306 				inst->sc_import_state = IMPORT_REFRESHED;
8307 
8308 				for (dpt = uu_list_first(inst->sc_dependents);
8309 				    dpt != NULL;
8310 				    dpt = uu_list_next(inst->sc_dependents,
8311 				    dpt))
8312 					if (imp_refresh_fmri(
8313 					    dpt->sc_pgroup_fmri,
8314 					    dpt->sc_pgroup_name,
8315 					    inst->sc_fmri) != 0)
8316 						goto progress;
8317 			}
8318 
8319 			for (dpt = uu_list_first(svc->sc_dependents);
8320 			    dpt != NULL;
8321 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8322 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8323 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8324 					goto progress;
8325 		}
8326 
8327 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8328 		    old_dpt != NULL;
8329 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8330 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8331 			    old_dpt->sc_pgroup_name,
8332 			    old_dpt->sc_parent->sc_fmri) != 0)
8333 				goto progress;
8334 
8335 		result = 0;
8336 
8337 		/*
8338 		 * This snippet of code assumes that we are running svccfg as we
8339 		 * normally do -- witih svc.startd running. Of course, that is
8340 		 * not actually the case all the time because we also use a
8341 		 * varient of svc.configd and svccfg which are only meant to
8342 		 * run during the build process. During this time we have no
8343 		 * svc.startd, so this check would hang the build process.
8344 		 *
8345 		 * However, we've also given other consolidations, a bit of a
8346 		 * means to tie themselves into a knot. They're not properly
8347 		 * using the native build equivalents, but they've been getting
8348 		 * away with it anyways. Therefore, if we've found that
8349 		 * SVCCFG_REPOSITORY is set indicating that a separate configd
8350 		 * should be spun up, then we have to assume it's not using a
8351 		 * startd and we should not do this check.
8352 		 */
8353 #ifndef NATIVE_BUILD
8354 		/*
8355 		 * Verify that the restarter group is preset
8356 		 */
8357 		eptr = getenv("SVCCFG_REPOSITORY");
8358 		for (svc = uu_list_first(bndl->sc_bundle_services);
8359 		    svc != NULL && eptr == NULL;
8360 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8361 
8362 			insts = svc->sc_u.sc_service.sc_service_instances;
8363 
8364 			for (inst = uu_list_first(insts);
8365 			    inst != NULL;
8366 			    inst = uu_list_next(insts, inst)) {
8367 				if (lscf_instance_verify(imp_scope, svc,
8368 				    inst) != 0)
8369 					goto progress;
8370 			}
8371 		}
8372 #endif
8373 		goto out;
8374 
8375 	}
8376 
8377 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8378 		bad_error("uu_list_walk", uu_error());
8379 
8380 printerr:
8381 	/* If the error hasn't been printed yet, do so here. */
8382 	switch (cbdata.sc_err) {
8383 	case ECONNABORTED:
8384 		warn(gettext("Repository connection broken.\n"));
8385 		break;
8386 
8387 	case ENOMEM:
8388 		warn(emsg_nomem);
8389 		break;
8390 
8391 	case ENOSPC:
8392 		warn(emsg_nores);
8393 		break;
8394 
8395 	case EROFS:
8396 		warn(gettext("Repository is read-only.\n"));
8397 		break;
8398 
8399 	case EACCES:
8400 		warn(gettext("Repository backend denied access.\n"));
8401 		break;
8402 
8403 	case EPERM:
8404 	case EINVAL:
8405 	case EEXIST:
8406 	case EBUSY:
8407 	case EBADF:
8408 	case -1:
8409 		break;
8410 
8411 	default:
8412 		bad_error("lscf_service_import", cbdata.sc_err);
8413 	}
8414 
8415 progress:
8416 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8417 
8418 	for (svc = uu_list_first(bndl->sc_bundle_services);
8419 	    svc != NULL;
8420 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8421 		insts = svc->sc_u.sc_service.sc_service_instances;
8422 
8423 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8424 		    import_progress(svc->sc_import_state));
8425 
8426 		for (inst = uu_list_first(insts);
8427 		    inst != NULL;
8428 		    inst = uu_list_next(insts, inst))
8429 			warn(gettext("    Instance \"%s\": %s\n"),
8430 			    inst->sc_name,
8431 			    import_progress(inst->sc_import_state));
8432 	}
8433 
8434 	if (cbdata.sc_err == ECONNABORTED)
8435 		repository_teardown();
8436 
8437 
8438 	result = -1;
8439 
8440 out:
8441 	if (annotation_set != 0) {
8442 		/* Turn off annotation.  It is no longer needed. */
8443 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8444 	}
8445 
8446 	free_imp_globals();
8447 
8448 	return (result);
8449 }
8450 
8451 /*
8452  * _lscf_import_err() summarize the error handling returned by
8453  * lscf_import_{instance | service}_pgs
8454  * Return values are:
8455  * IMPORT_NEXT
8456  * IMPORT_OUT
8457  * IMPORT_BAD
8458  */
8459 
8460 #define	IMPORT_BAD	-1
8461 #define	IMPORT_NEXT	0
8462 #define	IMPORT_OUT	1
8463 
8464 static int
8465 _lscf_import_err(int err, const char *fmri)
8466 {
8467 	switch (err) {
8468 	case 0:
8469 		if (g_verbose)
8470 			warn(gettext("%s updated.\n"), fmri);
8471 		return (IMPORT_NEXT);
8472 
8473 	case ECONNABORTED:
8474 		warn(gettext("Could not update %s "
8475 		    "(repository connection broken).\n"), fmri);
8476 		return (IMPORT_OUT);
8477 
8478 	case ENOMEM:
8479 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8480 		return (IMPORT_OUT);
8481 
8482 	case ENOSPC:
8483 		warn(gettext("Could not update %s "
8484 		    "(repository server out of resources).\n"), fmri);
8485 		return (IMPORT_OUT);
8486 
8487 	case ECANCELED:
8488 		warn(gettext(
8489 		    "Could not update %s (deleted).\n"), fmri);
8490 		return (IMPORT_NEXT);
8491 
8492 	case EPERM:
8493 	case EINVAL:
8494 	case EBUSY:
8495 		return (IMPORT_NEXT);
8496 
8497 	case EROFS:
8498 		warn(gettext("Could not update %s (repository read-only).\n"),
8499 		    fmri);
8500 		return (IMPORT_OUT);
8501 
8502 	case EACCES:
8503 		warn(gettext("Could not update %s "
8504 		    "(backend access denied).\n"), fmri);
8505 		return (IMPORT_NEXT);
8506 
8507 	case EEXIST:
8508 	default:
8509 		return (IMPORT_BAD);
8510 	}
8511 
8512 	/*NOTREACHED*/
8513 }
8514 
8515 /*
8516  * The global imp_svc and imp_inst should be set by the caller in the
8517  * check to make sure the service and instance exist that the apply is
8518  * working on.
8519  */
8520 static int
8521 lscf_dependent_apply(void *dpg, void *e)
8522 {
8523 	scf_callback_t cb;
8524 	pgroup_t *dpt_pgroup = dpg;
8525 	pgroup_t *deldpt;
8526 	entity_t *ent = e;
8527 	int tissvc;
8528 	void *sc_ent, *tent;
8529 	scf_error_t serr;
8530 	int r;
8531 
8532 	const char * const dependents = "dependents";
8533 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8534 
8535 	if (issvc)
8536 		sc_ent = imp_svc;
8537 	else
8538 		sc_ent = imp_inst;
8539 
8540 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8541 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8542 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8543 	    imp_prop) != 0) {
8544 		switch (scf_error()) {
8545 		case SCF_ERROR_NOT_FOUND:
8546 		case SCF_ERROR_DELETED:
8547 			break;
8548 
8549 		case SCF_ERROR_CONNECTION_BROKEN:
8550 		case SCF_ERROR_NOT_SET:
8551 		case SCF_ERROR_INVALID_ARGUMENT:
8552 		case SCF_ERROR_HANDLE_MISMATCH:
8553 		case SCF_ERROR_NOT_BOUND:
8554 		default:
8555 			bad_error("entity_get_pg", scf_error());
8556 		}
8557 	} else {
8558 		/*
8559 		 * Found the dependents/<wip dep> so check to
8560 		 * see if the service is different.  If so
8561 		 * store the service for later refresh, and
8562 		 * delete the wip dependency from the service
8563 		 */
8564 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8565 			switch (scf_error()) {
8566 				case SCF_ERROR_DELETED:
8567 					break;
8568 
8569 				case SCF_ERROR_CONNECTION_BROKEN:
8570 				case SCF_ERROR_NOT_SET:
8571 				case SCF_ERROR_INVALID_ARGUMENT:
8572 				case SCF_ERROR_HANDLE_MISMATCH:
8573 				case SCF_ERROR_NOT_BOUND:
8574 				default:
8575 					bad_error("scf_property_get_value",
8576 					    scf_error());
8577 			}
8578 		}
8579 
8580 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8581 		    max_scf_value_len + 1) < 0)
8582 			bad_error("scf_value_get_as_string", scf_error());
8583 
8584 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8585 		switch (r) {
8586 		case 1:
8587 			break;
8588 		case 0:
8589 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8590 			    &tissvc)) != SCF_ERROR_NONE) {
8591 				if (serr == SCF_ERROR_NOT_FOUND) {
8592 					break;
8593 				} else {
8594 					bad_error("fmri_to_entity", serr);
8595 				}
8596 			}
8597 
8598 			if (entity_get_pg(tent, tissvc,
8599 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8600 				serr = scf_error();
8601 				if (serr == SCF_ERROR_NOT_FOUND ||
8602 				    serr == SCF_ERROR_DELETED) {
8603 					break;
8604 				} else {
8605 					bad_error("entity_get_pg", scf_error());
8606 				}
8607 			}
8608 
8609 			if (scf_pg_delete(imp_pg) != 0) {
8610 				serr = scf_error();
8611 				if (serr == SCF_ERROR_NOT_FOUND ||
8612 				    serr == SCF_ERROR_DELETED) {
8613 					break;
8614 				} else {
8615 					bad_error("scf_pg_delete", scf_error());
8616 				}
8617 			}
8618 
8619 			deldpt = internal_pgroup_new();
8620 			if (deldpt == NULL)
8621 				return (ENOMEM);
8622 			deldpt->sc_pgroup_name =
8623 			    strdup(dpt_pgroup->sc_pgroup_name);
8624 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8625 			if (deldpt->sc_pgroup_name == NULL ||
8626 			    deldpt->sc_pgroup_fmri == NULL)
8627 				return (ENOMEM);
8628 			deldpt->sc_parent = (entity_t *)ent;
8629 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8630 			    deldpt) != 0)
8631 				uu_die(gettext("libuutil error: %s\n"),
8632 				    uu_strerror(uu_error()));
8633 
8634 			break;
8635 		default:
8636 			bad_error("fmri_equal", r);
8637 		}
8638 	}
8639 
8640 	cb.sc_handle = g_hndl;
8641 	cb.sc_parent = ent;
8642 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8643 	cb.sc_source_fmri = ent->sc_fmri;
8644 	cb.sc_target_fmri = ent->sc_fmri;
8645 	cb.sc_trans = NULL;
8646 	cb.sc_flags = SCI_FORCE;
8647 
8648 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8649 		return (UU_WALK_ERROR);
8650 
8651 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8652 	switch (r) {
8653 	case 0:
8654 		break;
8655 
8656 	case ENOMEM:
8657 	case ECONNABORTED:
8658 	case EPERM:
8659 	case -1:
8660 		warn(gettext("Unable to refresh \"%s\"\n"),
8661 		    dpt_pgroup->sc_pgroup_fmri);
8662 		return (UU_WALK_ERROR);
8663 
8664 	default:
8665 		bad_error("imp_refresh_fmri", r);
8666 	}
8667 
8668 	return (UU_WALK_NEXT);
8669 }
8670 
8671 /*
8672  * Returns
8673  *   0 - success
8674  *   -1 - lscf_import_instance_pgs() failed.
8675  */
8676 int
8677 lscf_bundle_apply(bundle_t *bndl, const char *file)
8678 {
8679 	pgroup_t *old_dpt;
8680 	entity_t *svc, *inst;
8681 	int annotation_set = 0;
8682 	int ret = 0;
8683 	int r = 0;
8684 
8685 	lscf_prep_hndl();
8686 
8687 	if ((ret = alloc_imp_globals()))
8688 		goto out;
8689 
8690 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8691 		scfdie();
8692 
8693 	/*
8694 	 * Set the strings to be used for the security audit annotation
8695 	 * event.
8696 	 */
8697 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8698 		annotation_set = 1;
8699 	} else {
8700 		switch (scf_error()) {
8701 		case SCF_ERROR_CONNECTION_BROKEN:
8702 			warn(gettext("Repository connection broken.\n"));
8703 			goto out;
8704 
8705 		case SCF_ERROR_INVALID_ARGUMENT:
8706 		case SCF_ERROR_NOT_BOUND:
8707 		case SCF_ERROR_NO_RESOURCES:
8708 		case SCF_ERROR_INTERNAL:
8709 			bad_error("_scf_set_annotation", scf_error());
8710 			/* NOTREACHED */
8711 
8712 		default:
8713 			/*
8714 			 * Do not abort apply operation because of
8715 			 * inability to create annotation audit event.
8716 			 */
8717 			warn(gettext("_scf_set_annotation() unexpectedly "
8718 			    "failed with return code of %d\n"), scf_error());
8719 			break;
8720 		}
8721 	}
8722 
8723 	for (svc = uu_list_first(bndl->sc_bundle_services);
8724 	    svc != NULL;
8725 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8726 		int refresh = 0;
8727 
8728 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8729 		    imp_svc) != 0) {
8730 			switch (scf_error()) {
8731 			case SCF_ERROR_NOT_FOUND:
8732 				if (g_verbose)
8733 					warn(gettext("Ignoring nonexistent "
8734 					    "service %s.\n"), svc->sc_name);
8735 				continue;
8736 
8737 			default:
8738 				scfdie();
8739 			}
8740 		}
8741 
8742 		/*
8743 		 * If there were missing types in the profile, then need to
8744 		 * attempt to find the types.
8745 		 */
8746 		if (svc->sc_miss_type) {
8747 			if (uu_list_numnodes(svc->sc_pgroups) &&
8748 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8749 			    svc, UU_DEFAULT) != 0) {
8750 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8751 					bad_error("uu_list_walk", uu_error());
8752 
8753 				ret = -1;
8754 				continue;
8755 			}
8756 
8757 			for (inst = uu_list_first(
8758 			    svc->sc_u.sc_service.sc_service_instances);
8759 			    inst != NULL;
8760 			    inst = uu_list_next(
8761 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8762 				/*
8763 				 * If the instance doesn't exist just
8764 				 * skip to the next instance and let the
8765 				 * import note the missing instance.
8766 				 */
8767 				if (scf_service_get_instance(imp_svc,
8768 				    inst->sc_name, imp_inst) != 0)
8769 					continue;
8770 
8771 				if (uu_list_walk(inst->sc_pgroups,
8772 				    find_current_pg_type, inst,
8773 				    UU_DEFAULT) != 0) {
8774 					if (uu_error() !=
8775 					    UU_ERROR_CALLBACK_FAILED)
8776 						bad_error("uu_list_walk",
8777 						    uu_error());
8778 
8779 					ret = -1;
8780 					inst->sc_miss_type = B_TRUE;
8781 				}
8782 			}
8783 		}
8784 
8785 		/*
8786 		 * if we have pgs in the profile, we need to refresh ALL
8787 		 * instances of the service
8788 		 */
8789 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8790 			refresh = 1;
8791 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8792 			    SCI_FORCE | SCI_KEEP);
8793 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8794 			case IMPORT_NEXT:
8795 				break;
8796 
8797 			case IMPORT_OUT:
8798 				goto out;
8799 
8800 			case IMPORT_BAD:
8801 			default:
8802 				bad_error("lscf_import_service_pgs", r);
8803 			}
8804 		}
8805 
8806 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8807 			uu_list_walk(svc->sc_dependents,
8808 			    lscf_dependent_apply, svc, UU_DEFAULT);
8809 		}
8810 
8811 		for (inst = uu_list_first(
8812 		    svc->sc_u.sc_service.sc_service_instances);
8813 		    inst != NULL;
8814 		    inst = uu_list_next(
8815 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8816 			/*
8817 			 * This instance still has missing types
8818 			 * so skip it.
8819 			 */
8820 			if (inst->sc_miss_type) {
8821 				if (g_verbose)
8822 					warn(gettext("Ignoring instance "
8823 					    "%s:%s with missing types\n"),
8824 					    inst->sc_parent->sc_name,
8825 					    inst->sc_name);
8826 
8827 				continue;
8828 			}
8829 
8830 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8831 			    imp_inst) != 0) {
8832 				switch (scf_error()) {
8833 				case SCF_ERROR_NOT_FOUND:
8834 					if (g_verbose)
8835 						warn(gettext("Ignoring "
8836 						    "nonexistant instance "
8837 						    "%s:%s.\n"),
8838 						    inst->sc_parent->sc_name,
8839 						    inst->sc_name);
8840 					continue;
8841 
8842 				default:
8843 					scfdie();
8844 				}
8845 			}
8846 
8847 			/*
8848 			 * If the instance does not have a general/enabled
8849 			 * property and no last-import snapshot then the
8850 			 * instance is not a fully installed instance and
8851 			 * should not have a profile applied to it.
8852 			 *
8853 			 * This could happen if a service/instance declares
8854 			 * a dependent on behalf of another service/instance.
8855 			 *
8856 			 */
8857 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8858 			    imp_snap) != 0) {
8859 				if (scf_instance_get_pg(imp_inst,
8860 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8861 				    scf_pg_get_property(imp_pg,
8862 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8863 					if (g_verbose)
8864 						warn(gettext("Ignoreing "
8865 						    "partial instance "
8866 						    "%s:%s.\n"),
8867 						    inst->sc_parent->sc_name,
8868 						    inst->sc_name);
8869 					continue;
8870 				}
8871 			}
8872 
8873 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8874 			    inst, SCI_FORCE | SCI_KEEP);
8875 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8876 			case IMPORT_NEXT:
8877 				break;
8878 
8879 			case IMPORT_OUT:
8880 				goto out;
8881 
8882 			case IMPORT_BAD:
8883 			default:
8884 				bad_error("lscf_import_instance_pgs", r);
8885 			}
8886 
8887 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8888 				uu_list_walk(inst->sc_dependents,
8889 				    lscf_dependent_apply, inst, UU_DEFAULT);
8890 			}
8891 
8892 			/* refresh only if there is no pgs in the service */
8893 			if (refresh == 0)
8894 				(void) refresh_entity(0, imp_inst,
8895 				    inst->sc_fmri, NULL, NULL, NULL);
8896 		}
8897 
8898 		if (refresh == 1) {
8899 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8900 
8901 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8902 			    imp_inst, imp_iter, name_buf);
8903 			free(name_buf);
8904 		}
8905 
8906 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8907 		    old_dpt != NULL;
8908 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8909 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8910 			    old_dpt->sc_pgroup_name,
8911 			    old_dpt->sc_parent->sc_fmri) != 0) {
8912 				warn(gettext("Unable to refresh \"%s\"\n"),
8913 				    old_dpt->sc_pgroup_fmri);
8914 			}
8915 		}
8916 	}
8917 
8918 out:
8919 	if (annotation_set) {
8920 		/* Remove security audit annotation strings. */
8921 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8922 	}
8923 
8924 	free_imp_globals();
8925 	return (ret);
8926 }
8927 
8928 
8929 /*
8930  * Export.  These functions create and output an XML tree of a service
8931  * description from the repository.  This is largely the inverse of
8932  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8933  *
8934  * - We must include any properties which are not represented specifically by
8935  *   a service manifest, e.g., properties created by an admin post-import.  To
8936  *   do so we'll iterate through all properties and deal with each
8937  *   apropriately.
8938  *
8939  * - Children of services and instances must must be in the order set by the
8940  *   DTD, but we iterate over the properties in undefined order.  The elements
8941  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8942  *   number of classes of them, however, we'll keep the classes separate and
8943  *   assemble them in order.
8944  */
8945 
8946 /*
8947  * Convenience function to handle xmlSetProp errors (and type casting).
8948  */
8949 static void
8950 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8951 {
8952 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8953 		uu_die(gettext("Could not set XML property.\n"));
8954 }
8955 
8956 /*
8957  * Convenience function to set an XML attribute to the single value of an
8958  * astring property.  If the value happens to be the default, don't set the
8959  * attribute.  "dval" should be the default value supplied by the DTD, or
8960  * NULL for no default.
8961  */
8962 static int
8963 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8964     const char *name, const char *dval)
8965 {
8966 	scf_value_t *val;
8967 	ssize_t len;
8968 	char *str;
8969 
8970 	val = scf_value_create(g_hndl);
8971 	if (val == NULL)
8972 		scfdie();
8973 
8974 	if (prop_get_val(prop, val) != 0) {
8975 		scf_value_destroy(val);
8976 		return (-1);
8977 	}
8978 
8979 	len = scf_value_get_as_string(val, NULL, 0);
8980 	if (len < 0)
8981 		scfdie();
8982 
8983 	str = safe_malloc(len + 1);
8984 
8985 	if (scf_value_get_as_string(val, str, len + 1) < 0)
8986 		scfdie();
8987 
8988 	scf_value_destroy(val);
8989 
8990 	if (dval == NULL || strcmp(str, dval) != 0)
8991 		safe_setprop(n, name, str);
8992 
8993 	free(str);
8994 
8995 	return (0);
8996 }
8997 
8998 /*
8999  * As above, but the attribute is always set.
9000  */
9001 static int
9002 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
9003 {
9004 	return (set_attr_from_prop_default(prop, n, name, NULL));
9005 }
9006 
9007 /*
9008  * Dump the given document onto f, with "'s replaced by ''s.
9009  */
9010 static int
9011 write_service_bundle(xmlDocPtr doc, FILE *f)
9012 {
9013 	xmlChar *mem;
9014 	int sz, i;
9015 
9016 	mem = NULL;
9017 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
9018 
9019 	if (mem == NULL) {
9020 		semerr(gettext("Could not dump XML tree.\n"));
9021 		return (-1);
9022 	}
9023 
9024 	/*
9025 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
9026 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
9027 	 * &apos; code?!
9028 	 */
9029 	for (i = 0; i < sz; ++i) {
9030 		char c = (char)mem[i];
9031 
9032 		if (c == '"')
9033 			(void) fputc('\'', f);
9034 		else if (c == '\'')
9035 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
9036 		else
9037 			(void) fputc(c, f);
9038 	}
9039 
9040 	return (0);
9041 }
9042 
9043 /*
9044  * Create the DOM elements in elts necessary to (generically) represent prop
9045  * (i.e., a property or propval element).  If the name of the property is
9046  * known, it should be passed as name_arg.  Otherwise, pass NULL.
9047  */
9048 static void
9049 export_property(scf_property_t *prop, const char *name_arg,
9050     struct pg_elts *elts, int flags)
9051 {
9052 	const char *type;
9053 	scf_error_t err = 0;
9054 	xmlNodePtr pnode, lnode;
9055 	char *lnname;
9056 	int ret;
9057 
9058 	/* name */
9059 	if (name_arg != NULL) {
9060 		(void) strcpy(exp_str, name_arg);
9061 	} else {
9062 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
9063 			scfdie();
9064 	}
9065 
9066 	/* type */
9067 	type = prop_to_typestr(prop);
9068 	if (type == NULL)
9069 		uu_die(gettext("Can't export property %s: unknown type.\n"),
9070 		    exp_str);
9071 
9072 	/* If we're exporting values, and there's just one, export it here. */
9073 	if (!(flags & SCE_ALL_VALUES))
9074 		goto empty;
9075 
9076 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
9077 		xmlNodePtr n;
9078 
9079 		/* Single value, so use propval */
9080 		n = xmlNewNode(NULL, (xmlChar *)"propval");
9081 		if (n == NULL)
9082 			uu_die(emsg_create_xml);
9083 
9084 		safe_setprop(n, name_attr, exp_str);
9085 		safe_setprop(n, type_attr, type);
9086 
9087 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9088 			scfdie();
9089 		safe_setprop(n, value_attr, exp_str);
9090 
9091 		if (elts->propvals == NULL)
9092 			elts->propvals = n;
9093 		else
9094 			(void) xmlAddSibling(elts->propvals, n);
9095 
9096 		return;
9097 	}
9098 
9099 	err = scf_error();
9100 
9101 	if (err == SCF_ERROR_PERMISSION_DENIED) {
9102 		semerr(emsg_permission_denied);
9103 		return;
9104 	}
9105 
9106 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
9107 	    err != SCF_ERROR_NOT_FOUND &&
9108 	    err != SCF_ERROR_PERMISSION_DENIED)
9109 		scfdie();
9110 
9111 empty:
9112 	/* Multiple (or no) values, so use property */
9113 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
9114 	if (pnode == NULL)
9115 		uu_die(emsg_create_xml);
9116 
9117 	safe_setprop(pnode, name_attr, exp_str);
9118 	safe_setprop(pnode, type_attr, type);
9119 
9120 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
9121 		lnname = uu_msprintf("%s_list", type);
9122 		if (lnname == NULL)
9123 			uu_die(gettext("Could not create string"));
9124 
9125 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
9126 		if (lnode == NULL)
9127 			uu_die(emsg_create_xml);
9128 
9129 		uu_free(lnname);
9130 
9131 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
9132 			scfdie();
9133 
9134 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
9135 		    1) {
9136 			xmlNodePtr vn;
9137 
9138 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
9139 			    NULL);
9140 			if (vn == NULL)
9141 				uu_die(emsg_create_xml);
9142 
9143 			if (scf_value_get_as_string(exp_val, exp_str,
9144 			    exp_str_sz) < 0)
9145 				scfdie();
9146 			safe_setprop(vn, value_attr, exp_str);
9147 		}
9148 		if (ret != 0)
9149 			scfdie();
9150 	}
9151 
9152 	if (elts->properties == NULL)
9153 		elts->properties = pnode;
9154 	else
9155 		(void) xmlAddSibling(elts->properties, pnode);
9156 }
9157 
9158 /*
9159  * Add a property_group element for this property group to elts.
9160  */
9161 static void
9162 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
9163 {
9164 	xmlNodePtr n;
9165 	struct pg_elts elts;
9166 	int ret;
9167 	boolean_t read_protected;
9168 
9169 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
9170 
9171 	/* name */
9172 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9173 		scfdie();
9174 	safe_setprop(n, name_attr, exp_str);
9175 
9176 	/* type */
9177 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
9178 		scfdie();
9179 	safe_setprop(n, type_attr, exp_str);
9180 
9181 	/* properties */
9182 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9183 		scfdie();
9184 
9185 	(void) memset(&elts, 0, sizeof (elts));
9186 
9187 	/*
9188 	 * If this property group is not read protected, we always want to
9189 	 * output all the values.  Otherwise, we only output the values if the
9190 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
9191 	 */
9192 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
9193 		scfdie();
9194 
9195 	if (!read_protected)
9196 		flags |= SCE_ALL_VALUES;
9197 
9198 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9199 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9200 			scfdie();
9201 
9202 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9203 			xmlNodePtr m;
9204 
9205 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9206 			if (m == NULL)
9207 				uu_die(emsg_create_xml);
9208 
9209 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9210 				elts.stability = m;
9211 				continue;
9212 			}
9213 
9214 			xmlFreeNode(m);
9215 		}
9216 
9217 		export_property(exp_prop, NULL, &elts, flags);
9218 	}
9219 	if (ret == -1)
9220 		scfdie();
9221 
9222 	(void) xmlAddChild(n, elts.stability);
9223 	(void) xmlAddChildList(n, elts.propvals);
9224 	(void) xmlAddChildList(n, elts.properties);
9225 
9226 	if (eelts->property_groups == NULL)
9227 		eelts->property_groups = n;
9228 	else
9229 		(void) xmlAddSibling(eelts->property_groups, n);
9230 }
9231 
9232 /*
9233  * Create an XML node representing the dependency described by the given
9234  * property group and put it in eelts.  Unless the dependency is not valid, in
9235  * which case create a generic property_group element which represents it and
9236  * put it in eelts.
9237  */
9238 static void
9239 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
9240 {
9241 	xmlNodePtr n;
9242 	int err = 0, ret;
9243 	struct pg_elts elts;
9244 
9245 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
9246 	if (n == NULL)
9247 		uu_die(emsg_create_xml);
9248 
9249 	/*
9250 	 * If the external flag is present, skip this dependency because it
9251 	 * should have been created by another manifest.
9252 	 */
9253 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9254 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9255 		    prop_get_val(exp_prop, exp_val) == 0) {
9256 			uint8_t b;
9257 
9258 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9259 				scfdie();
9260 
9261 			if (b)
9262 				return;
9263 		}
9264 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
9265 		scfdie();
9266 
9267 	/* Get the required attributes. */
9268 
9269 	/* name */
9270 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9271 		scfdie();
9272 	safe_setprop(n, name_attr, exp_str);
9273 
9274 	/* grouping */
9275 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9276 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9277 		err = 1;
9278 
9279 	/* restart_on */
9280 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9281 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9282 		err = 1;
9283 
9284 	/* type */
9285 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9286 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9287 		err = 1;
9288 
9289 	/*
9290 	 * entities: Not required, but if we create no children, it will be
9291 	 * created as empty on import, so fail if it's missing.
9292 	 */
9293 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9294 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9295 		scf_iter_t *eiter;
9296 		int ret2;
9297 
9298 		eiter = scf_iter_create(g_hndl);
9299 		if (eiter == NULL)
9300 			scfdie();
9301 
9302 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9303 			scfdie();
9304 
9305 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9306 			xmlNodePtr ch;
9307 
9308 			if (scf_value_get_astring(exp_val, exp_str,
9309 			    exp_str_sz) < 0)
9310 				scfdie();
9311 
9312 			/*
9313 			 * service_fmri's must be first, so we can add them
9314 			 * here.
9315 			 */
9316 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9317 			    NULL);
9318 			if (ch == NULL)
9319 				uu_die(emsg_create_xml);
9320 
9321 			safe_setprop(ch, value_attr, exp_str);
9322 		}
9323 		if (ret2 == -1)
9324 			scfdie();
9325 
9326 		scf_iter_destroy(eiter);
9327 	} else
9328 		err = 1;
9329 
9330 	if (err) {
9331 		xmlFreeNode(n);
9332 
9333 		export_pg(pg, eelts, SCE_ALL_VALUES);
9334 
9335 		return;
9336 	}
9337 
9338 	/* Iterate through the properties & handle each. */
9339 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9340 		scfdie();
9341 
9342 	(void) memset(&elts, 0, sizeof (elts));
9343 
9344 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9345 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9346 			scfdie();
9347 
9348 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9349 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9350 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9351 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9352 			continue;
9353 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9354 			xmlNodePtr m;
9355 
9356 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9357 			if (m == NULL)
9358 				uu_die(emsg_create_xml);
9359 
9360 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9361 				elts.stability = m;
9362 				continue;
9363 			}
9364 
9365 			xmlFreeNode(m);
9366 		}
9367 
9368 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9369 	}
9370 	if (ret == -1)
9371 		scfdie();
9372 
9373 	(void) xmlAddChild(n, elts.stability);
9374 	(void) xmlAddChildList(n, elts.propvals);
9375 	(void) xmlAddChildList(n, elts.properties);
9376 
9377 	if (eelts->dependencies == NULL)
9378 		eelts->dependencies = n;
9379 	else
9380 		(void) xmlAddSibling(eelts->dependencies, n);
9381 }
9382 
9383 static xmlNodePtr
9384 export_method_environment(scf_propertygroup_t *pg)
9385 {
9386 	xmlNodePtr env;
9387 	int ret;
9388 	int children = 0;
9389 
9390 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9391 		return (NULL);
9392 
9393 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9394 	if (env == NULL)
9395 		uu_die(emsg_create_xml);
9396 
9397 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9398 		scfdie();
9399 
9400 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9401 		scfdie();
9402 
9403 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9404 		xmlNodePtr ev;
9405 		char *cp;
9406 
9407 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9408 			scfdie();
9409 
9410 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9411 			warn(gettext("Invalid environment variable \"%s\".\n"),
9412 			    exp_str);
9413 			continue;
9414 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9415 			warn(gettext("Invalid environment variable \"%s\"; "
9416 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9417 			continue;
9418 		}
9419 
9420 		*cp = '\0';
9421 		cp++;
9422 
9423 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9424 		if (ev == NULL)
9425 			uu_die(emsg_create_xml);
9426 
9427 		safe_setprop(ev, name_attr, exp_str);
9428 		safe_setprop(ev, value_attr, cp);
9429 		children++;
9430 	}
9431 
9432 	if (ret != 0)
9433 		scfdie();
9434 
9435 	if (children == 0) {
9436 		xmlFreeNode(env);
9437 		return (NULL);
9438 	}
9439 
9440 	return (env);
9441 }
9442 
9443 /*
9444  * As above, but for a method property group.
9445  */
9446 static void
9447 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9448 {
9449 	xmlNodePtr n, env;
9450 	char *str;
9451 	int err = 0, nonenv, ret;
9452 	uint8_t use_profile;
9453 	struct pg_elts elts;
9454 	xmlNodePtr ctxt = NULL;
9455 
9456 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9457 
9458 	/* Get the required attributes. */
9459 
9460 	/* name */
9461 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9462 		scfdie();
9463 	safe_setprop(n, name_attr, exp_str);
9464 
9465 	/* type */
9466 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9467 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9468 		err = 1;
9469 
9470 	/* exec */
9471 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9472 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9473 		err = 1;
9474 
9475 	/* timeout */
9476 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9477 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9478 	    prop_get_val(exp_prop, exp_val) == 0) {
9479 		uint64_t c;
9480 
9481 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9482 			scfdie();
9483 
9484 		str = uu_msprintf("%llu", c);
9485 		if (str == NULL)
9486 			uu_die(gettext("Could not create string"));
9487 
9488 		safe_setprop(n, "timeout_seconds", str);
9489 		free(str);
9490 	} else
9491 		err = 1;
9492 
9493 	if (err) {
9494 		xmlFreeNode(n);
9495 
9496 		export_pg(pg, eelts, SCE_ALL_VALUES);
9497 
9498 		return;
9499 	}
9500 
9501 
9502 	/*
9503 	 * If we're going to have a method_context child, we need to know
9504 	 * before we iterate through the properties.  Since method_context's
9505 	 * are optional, we don't want to complain about any properties
9506 	 * missing if none of them are there.  Thus we can't use the
9507 	 * convenience functions.
9508 	 */
9509 	nonenv =
9510 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9511 	    SCF_SUCCESS ||
9512 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9513 	    SCF_SUCCESS ||
9514 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9515 	    SCF_SUCCESS ||
9516 	    scf_pg_get_property(pg, SCF_PROPERTY_SECFLAGS, NULL) ==
9517 	    SCF_SUCCESS ||
9518 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9519 	    SCF_SUCCESS;
9520 
9521 	if (nonenv) {
9522 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9523 		if (ctxt == NULL)
9524 			uu_die(emsg_create_xml);
9525 
9526 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9527 		    0 &&
9528 		    set_attr_from_prop_default(exp_prop, ctxt,
9529 		    "working_directory", ":default") != 0)
9530 			err = 1;
9531 
9532 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9533 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9534 		    ":default") != 0)
9535 			err = 1;
9536 
9537 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9538 		    0 &&
9539 		    set_attr_from_prop_default(exp_prop, ctxt,
9540 		    "resource_pool", ":default") != 0)
9541 			err = 1;
9542 
9543 		if (pg_get_prop(pg, SCF_PROPERTY_SECFLAGS, exp_prop) == 0 &&
9544 		    set_attr_from_prop_default(exp_prop, ctxt,
9545 		    "security_flags", ":default") != 0)
9546 			err = 1;
9547 
9548 		/*
9549 		 * We only want to complain about profile or credential
9550 		 * properties if we will use them.  To determine that we must
9551 		 * examine USE_PROFILE.
9552 		 */
9553 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9554 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9555 		    prop_get_val(exp_prop, exp_val) == 0) {
9556 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9557 			    SCF_SUCCESS) {
9558 				scfdie();
9559 			}
9560 
9561 			if (use_profile) {
9562 				xmlNodePtr prof;
9563 
9564 				prof = xmlNewChild(ctxt, NULL,
9565 				    (xmlChar *)"method_profile", NULL);
9566 				if (prof == NULL)
9567 					uu_die(emsg_create_xml);
9568 
9569 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9570 				    exp_prop) != 0 ||
9571 				    set_attr_from_prop(exp_prop, prof,
9572 				    name_attr) != 0)
9573 					err = 1;
9574 			} else {
9575 				xmlNodePtr cred;
9576 
9577 				cred = xmlNewChild(ctxt, NULL,
9578 				    (xmlChar *)"method_credential", NULL);
9579 				if (cred == NULL)
9580 					uu_die(emsg_create_xml);
9581 
9582 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9583 				    exp_prop) != 0 ||
9584 				    set_attr_from_prop(exp_prop, cred,
9585 				    "user") != 0) {
9586 					err = 1;
9587 				}
9588 
9589 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9590 				    exp_prop) == 0 &&
9591 				    set_attr_from_prop_default(exp_prop, cred,
9592 				    "group", ":default") != 0)
9593 					err = 1;
9594 
9595 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9596 				    exp_prop) == 0 &&
9597 				    set_attr_from_prop_default(exp_prop, cred,
9598 				    "supp_groups", ":default") != 0)
9599 					err = 1;
9600 
9601 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9602 				    exp_prop) == 0 &&
9603 				    set_attr_from_prop_default(exp_prop, cred,
9604 				    "privileges", ":default") != 0)
9605 					err = 1;
9606 
9607 				if (pg_get_prop(pg,
9608 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9609 				    exp_prop) == 0 &&
9610 				    set_attr_from_prop_default(exp_prop, cred,
9611 				    "limit_privileges", ":default") != 0)
9612 					err = 1;
9613 			}
9614 		}
9615 	}
9616 
9617 	if ((env = export_method_environment(pg)) != NULL) {
9618 		if (ctxt == NULL) {
9619 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9620 			if (ctxt == NULL)
9621 				uu_die(emsg_create_xml);
9622 		}
9623 		(void) xmlAddChild(ctxt, env);
9624 	}
9625 
9626 	if (env != NULL || (nonenv && err == 0))
9627 		(void) xmlAddChild(n, ctxt);
9628 	else
9629 		xmlFreeNode(ctxt);
9630 
9631 	nonenv = (err == 0);
9632 
9633 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9634 		scfdie();
9635 
9636 	(void) memset(&elts, 0, sizeof (elts));
9637 
9638 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9639 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9640 			scfdie();
9641 
9642 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9643 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9644 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9645 			continue;
9646 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9647 			xmlNodePtr m;
9648 
9649 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9650 			if (m == NULL)
9651 				uu_die(emsg_create_xml);
9652 
9653 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9654 				elts.stability = m;
9655 				continue;
9656 			}
9657 
9658 			xmlFreeNode(m);
9659 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9660 		    0 ||
9661 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9662 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9663 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9664 			if (nonenv)
9665 				continue;
9666 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9667 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9668 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9669 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9670 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0 ||
9671 		    strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9672 			if (nonenv && !use_profile)
9673 				continue;
9674 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9675 			if (nonenv && use_profile)
9676 				continue;
9677 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9678 			if (env != NULL)
9679 				continue;
9680 		}
9681 
9682 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9683 	}
9684 	if (ret == -1)
9685 		scfdie();
9686 
9687 	(void) xmlAddChild(n, elts.stability);
9688 	(void) xmlAddChildList(n, elts.propvals);
9689 	(void) xmlAddChildList(n, elts.properties);
9690 
9691 	if (eelts->exec_methods == NULL)
9692 		eelts->exec_methods = n;
9693 	else
9694 		(void) xmlAddSibling(eelts->exec_methods, n);
9695 }
9696 
9697 static void
9698 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9699     struct entity_elts *eelts)
9700 {
9701 	xmlNodePtr pgnode;
9702 
9703 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9704 	if (pgnode == NULL)
9705 		uu_die(emsg_create_xml);
9706 
9707 	safe_setprop(pgnode, name_attr, name);
9708 	safe_setprop(pgnode, type_attr, type);
9709 
9710 	(void) xmlAddChildList(pgnode, elts->propvals);
9711 	(void) xmlAddChildList(pgnode, elts->properties);
9712 
9713 	if (eelts->property_groups == NULL)
9714 		eelts->property_groups = pgnode;
9715 	else
9716 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9717 }
9718 
9719 /*
9720  * Process the general property group for a service.  This is the one with the
9721  * goodies.
9722  */
9723 static void
9724 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9725 {
9726 	struct pg_elts elts;
9727 	int ret;
9728 
9729 	/*
9730 	 * In case there are properties which don't correspond to child
9731 	 * entities of the service entity, we'll set up a pg_elts structure to
9732 	 * put them in.
9733 	 */
9734 	(void) memset(&elts, 0, sizeof (elts));
9735 
9736 	/* Walk the properties, looking for special ones. */
9737 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9738 		scfdie();
9739 
9740 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9741 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9742 			scfdie();
9743 
9744 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9745 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9746 			    prop_get_val(exp_prop, exp_val) == 0) {
9747 				uint8_t b;
9748 
9749 				if (scf_value_get_boolean(exp_val, &b) !=
9750 				    SCF_SUCCESS)
9751 					scfdie();
9752 
9753 				if (b) {
9754 					selts->single_instance =
9755 					    xmlNewNode(NULL,
9756 					    (xmlChar *)"single_instance");
9757 					if (selts->single_instance == NULL)
9758 						uu_die(emsg_create_xml);
9759 				}
9760 
9761 				continue;
9762 			}
9763 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9764 			xmlNodePtr rnode, sfnode;
9765 
9766 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9767 			if (rnode == NULL)
9768 				uu_die(emsg_create_xml);
9769 
9770 			sfnode = xmlNewChild(rnode, NULL,
9771 			    (xmlChar *)"service_fmri", NULL);
9772 			if (sfnode == NULL)
9773 				uu_die(emsg_create_xml);
9774 
9775 			if (set_attr_from_prop(exp_prop, sfnode,
9776 			    value_attr) == 0) {
9777 				selts->restarter = rnode;
9778 				continue;
9779 			}
9780 
9781 			xmlFreeNode(rnode);
9782 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9783 		    0) {
9784 			xmlNodePtr s;
9785 
9786 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9787 			if (s == NULL)
9788 				uu_die(emsg_create_xml);
9789 
9790 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9791 				selts->stability = s;
9792 				continue;
9793 			}
9794 
9795 			xmlFreeNode(s);
9796 		}
9797 
9798 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9799 	}
9800 	if (ret == -1)
9801 		scfdie();
9802 
9803 	if (elts.propvals != NULL || elts.properties != NULL)
9804 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9805 		    selts);
9806 }
9807 
9808 static void
9809 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9810 {
9811 	xmlNodePtr n, prof, cred, env;
9812 	uint8_t use_profile;
9813 	int ret, err = 0;
9814 
9815 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9816 
9817 	env = export_method_environment(pg);
9818 
9819 	/* Need to know whether we'll use a profile or not. */
9820 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9821 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9822 	    prop_get_val(exp_prop, exp_val) == 0) {
9823 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9824 			scfdie();
9825 
9826 		if (use_profile)
9827 			prof =
9828 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9829 			    NULL);
9830 		else
9831 			cred =
9832 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9833 			    NULL);
9834 	}
9835 
9836 	if (env != NULL)
9837 		(void) xmlAddChild(n, env);
9838 
9839 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9840 		scfdie();
9841 
9842 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9843 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9844 			scfdie();
9845 
9846 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9847 			if (set_attr_from_prop(exp_prop, n,
9848 			    "working_directory") != 0)
9849 				err = 1;
9850 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9851 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9852 				err = 1;
9853 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9854 			if (set_attr_from_prop(exp_prop, n,
9855 			    "resource_pool") != 0)
9856 				err = 1;
9857 		} else if (strcmp(exp_str, SCF_PROPERTY_SECFLAGS) == 0) {
9858 			if (set_attr_from_prop(exp_prop, n,
9859 			    "security_flags") != 0)
9860 				err = 1;
9861 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9862 			/* EMPTY */
9863 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9864 			if (use_profile ||
9865 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9866 				err = 1;
9867 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9868 			if (use_profile ||
9869 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9870 				err = 1;
9871 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9872 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9873 			    "supp_groups") != 0)
9874 				err = 1;
9875 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9876 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9877 			    "privileges") != 0)
9878 				err = 1;
9879 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9880 		    0) {
9881 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9882 			    "limit_privileges") != 0)
9883 				err = 1;
9884 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9885 			if (!use_profile || set_attr_from_prop(exp_prop,
9886 			    prof, name_attr) != 0)
9887 				err = 1;
9888 		} else {
9889 			/* Can't have generic properties in method_context's */
9890 			err = 1;
9891 		}
9892 	}
9893 	if (ret == -1)
9894 		scfdie();
9895 
9896 	if (err && env == NULL) {
9897 		xmlFreeNode(n);
9898 		export_pg(pg, elts, SCE_ALL_VALUES);
9899 		return;
9900 	}
9901 
9902 	elts->method_context = n;
9903 }
9904 
9905 /*
9906  * Given a dependency property group in the tfmri entity (target fmri), return
9907  * a dependent element which represents it.
9908  */
9909 static xmlNodePtr
9910 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9911 {
9912 	uint8_t b;
9913 	xmlNodePtr n, sf;
9914 	int err = 0, ret;
9915 	struct pg_elts pgelts;
9916 
9917 	/*
9918 	 * If external isn't set to true then exporting the service will
9919 	 * export this as a normal dependency, so we should stop to avoid
9920 	 * duplication.
9921 	 */
9922 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9923 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9924 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9925 		if (g_verbose) {
9926 			warn(gettext("Dependent \"%s\" cannot be exported "
9927 			    "properly because the \"%s\" property of the "
9928 			    "\"%s\" dependency of %s is not set to true.\n"),
9929 			    name, scf_property_external, name, tfmri);
9930 		}
9931 
9932 		return (NULL);
9933 	}
9934 
9935 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9936 	if (n == NULL)
9937 		uu_die(emsg_create_xml);
9938 
9939 	safe_setprop(n, name_attr, name);
9940 
9941 	/* Get the required attributes */
9942 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9943 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9944 		err = 1;
9945 
9946 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9947 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9948 		err = 1;
9949 
9950 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9951 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9952 	    prop_get_val(exp_prop, exp_val) == 0) {
9953 		/* EMPTY */
9954 	} else
9955 		err = 1;
9956 
9957 	if (err) {
9958 		xmlFreeNode(n);
9959 		return (NULL);
9960 	}
9961 
9962 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9963 	if (sf == NULL)
9964 		uu_die(emsg_create_xml);
9965 
9966 	safe_setprop(sf, value_attr, tfmri);
9967 
9968 	/*
9969 	 * Now add elements for the other properties.
9970 	 */
9971 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9972 		scfdie();
9973 
9974 	(void) memset(&pgelts, 0, sizeof (pgelts));
9975 
9976 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9977 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9978 			scfdie();
9979 
9980 		if (strcmp(exp_str, scf_property_external) == 0 ||
9981 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9982 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9983 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9984 			continue;
9985 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9986 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9987 			    prop_get_val(exp_prop, exp_val) == 0) {
9988 				char type[sizeof ("service") + 1];
9989 
9990 				if (scf_value_get_astring(exp_val, type,
9991 				    sizeof (type)) < 0)
9992 					scfdie();
9993 
9994 				if (strcmp(type, "service") == 0)
9995 					continue;
9996 			}
9997 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9998 			xmlNodePtr s;
9999 
10000 			s = xmlNewNode(NULL, (xmlChar *)"stability");
10001 			if (s == NULL)
10002 				uu_die(emsg_create_xml);
10003 
10004 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
10005 				pgelts.stability = s;
10006 				continue;
10007 			}
10008 
10009 			xmlFreeNode(s);
10010 		}
10011 
10012 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10013 	}
10014 	if (ret == -1)
10015 		scfdie();
10016 
10017 	(void) xmlAddChild(n, pgelts.stability);
10018 	(void) xmlAddChildList(n, pgelts.propvals);
10019 	(void) xmlAddChildList(n, pgelts.properties);
10020 
10021 	return (n);
10022 }
10023 
10024 static void
10025 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
10026 {
10027 	scf_propertygroup_t *opg;
10028 	scf_iter_t *iter;
10029 	char *type, *fmri;
10030 	int ret;
10031 	struct pg_elts pgelts;
10032 	xmlNodePtr n;
10033 	scf_error_t serr;
10034 
10035 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
10036 	    (iter = scf_iter_create(g_hndl)) == NULL)
10037 		scfdie();
10038 
10039 	/* Can't use exp_prop_iter due to export_dependent(). */
10040 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10041 		scfdie();
10042 
10043 	type = safe_malloc(max_scf_pg_type_len + 1);
10044 
10045 	/* Get an extra byte so we can tell if values are too long. */
10046 	fmri = safe_malloc(max_scf_fmri_len + 2);
10047 
10048 	(void) memset(&pgelts, 0, sizeof (pgelts));
10049 
10050 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
10051 		void *entity;
10052 		int isservice;
10053 		scf_type_t ty;
10054 
10055 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
10056 			scfdie();
10057 
10058 		if ((ty != SCF_TYPE_ASTRING &&
10059 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
10060 		    prop_get_val(exp_prop, exp_val) != 0) {
10061 			export_property(exp_prop, NULL, &pgelts,
10062 			    SCE_ALL_VALUES);
10063 			continue;
10064 		}
10065 
10066 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10067 			scfdie();
10068 
10069 		if (scf_value_get_astring(exp_val, fmri,
10070 		    max_scf_fmri_len + 2) < 0)
10071 			scfdie();
10072 
10073 		/* Look for a dependency group in the target fmri. */
10074 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10075 		switch (serr) {
10076 		case SCF_ERROR_NONE:
10077 			break;
10078 
10079 		case SCF_ERROR_NO_MEMORY:
10080 			uu_die(gettext("Out of memory.\n"));
10081 			/* NOTREACHED */
10082 
10083 		case SCF_ERROR_INVALID_ARGUMENT:
10084 			if (g_verbose) {
10085 				if (scf_property_to_fmri(exp_prop, fmri,
10086 				    max_scf_fmri_len + 2) < 0)
10087 					scfdie();
10088 
10089 				warn(gettext("The value of %s is not a valid "
10090 				    "FMRI.\n"), fmri);
10091 			}
10092 
10093 			export_property(exp_prop, exp_str, &pgelts,
10094 			    SCE_ALL_VALUES);
10095 			continue;
10096 
10097 		case SCF_ERROR_CONSTRAINT_VIOLATED:
10098 			if (g_verbose) {
10099 				if (scf_property_to_fmri(exp_prop, fmri,
10100 				    max_scf_fmri_len + 2) < 0)
10101 					scfdie();
10102 
10103 				warn(gettext("The value of %s does not specify "
10104 				    "a service or an instance.\n"), fmri);
10105 			}
10106 
10107 			export_property(exp_prop, exp_str, &pgelts,
10108 			    SCE_ALL_VALUES);
10109 			continue;
10110 
10111 		case SCF_ERROR_NOT_FOUND:
10112 			if (g_verbose) {
10113 				if (scf_property_to_fmri(exp_prop, fmri,
10114 				    max_scf_fmri_len + 2) < 0)
10115 					scfdie();
10116 
10117 				warn(gettext("The entity specified by %s does "
10118 				    "not exist.\n"), fmri);
10119 			}
10120 
10121 			export_property(exp_prop, exp_str, &pgelts,
10122 			    SCE_ALL_VALUES);
10123 			continue;
10124 
10125 		default:
10126 #ifndef NDEBUG
10127 			(void) fprintf(stderr, "%s:%d: %s() failed with "
10128 			    "unexpected error %d.\n", __FILE__, __LINE__,
10129 			    "fmri_to_entity", serr);
10130 #endif
10131 			abort();
10132 		}
10133 
10134 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
10135 			if (scf_error() != SCF_ERROR_NOT_FOUND)
10136 				scfdie();
10137 
10138 			warn(gettext("Entity %s is missing dependency property "
10139 			    "group %s.\n"), fmri, exp_str);
10140 
10141 			export_property(exp_prop, NULL, &pgelts,
10142 			    SCE_ALL_VALUES);
10143 			continue;
10144 		}
10145 
10146 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
10147 			scfdie();
10148 
10149 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
10150 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
10151 				scfdie();
10152 
10153 			warn(gettext("Property group %s is not of "
10154 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
10155 
10156 			export_property(exp_prop, NULL, &pgelts,
10157 			    SCE_ALL_VALUES);
10158 			continue;
10159 		}
10160 
10161 		n = export_dependent(opg, exp_str, fmri);
10162 		if (n == NULL) {
10163 			export_property(exp_prop, exp_str, &pgelts,
10164 			    SCE_ALL_VALUES);
10165 		} else {
10166 			if (eelts->dependents == NULL)
10167 				eelts->dependents = n;
10168 			else
10169 				(void) xmlAddSibling(eelts->dependents,
10170 				    n);
10171 		}
10172 	}
10173 	if (ret == -1)
10174 		scfdie();
10175 
10176 	free(fmri);
10177 	free(type);
10178 
10179 	scf_iter_destroy(iter);
10180 	scf_pg_destroy(opg);
10181 
10182 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10183 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
10184 		    eelts);
10185 }
10186 
10187 static void
10188 make_node(xmlNodePtr *nodep, const char *name)
10189 {
10190 	if (*nodep == NULL) {
10191 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
10192 		if (*nodep == NULL)
10193 			uu_die(emsg_create_xml);
10194 	}
10195 }
10196 
10197 static xmlNodePtr
10198 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
10199 {
10200 	int ret;
10201 	xmlNodePtr parent = NULL;
10202 	xmlNodePtr loctext = NULL;
10203 
10204 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10205 		scfdie();
10206 
10207 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10208 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
10209 		    prop_get_val(exp_prop, exp_val) != 0)
10210 			continue;
10211 
10212 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
10213 			scfdie();
10214 
10215 		make_node(&parent, parname);
10216 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
10217 		    (xmlChar *)exp_str);
10218 		if (loctext == NULL)
10219 			uu_die(emsg_create_xml);
10220 
10221 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10222 			scfdie();
10223 
10224 		safe_setprop(loctext, "xml:lang", exp_str);
10225 	}
10226 
10227 	if (ret == -1)
10228 		scfdie();
10229 
10230 	return (parent);
10231 }
10232 
10233 static xmlNodePtr
10234 export_tm_manpage(scf_propertygroup_t *pg)
10235 {
10236 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
10237 	if (manpage == NULL)
10238 		uu_die(emsg_create_xml);
10239 
10240 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
10241 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
10242 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
10243 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
10244 		xmlFreeNode(manpage);
10245 		return (NULL);
10246 	}
10247 
10248 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
10249 		(void) set_attr_from_prop_default(exp_prop,
10250 		    manpage, "manpath", ":default");
10251 
10252 	return (manpage);
10253 }
10254 
10255 static xmlNodePtr
10256 export_tm_doc_link(scf_propertygroup_t *pg)
10257 {
10258 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
10259 	if (doc_link == NULL)
10260 		uu_die(emsg_create_xml);
10261 
10262 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10263 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10264 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10265 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10266 		xmlFreeNode(doc_link);
10267 		return (NULL);
10268 	}
10269 	return (doc_link);
10270 }
10271 
10272 /*
10273  * Process template information for a service or instances.
10274  */
10275 static void
10276 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10277     struct template_elts *telts)
10278 {
10279 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10280 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10281 	xmlNodePtr child = NULL;
10282 
10283 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10284 		scfdie();
10285 
10286 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10287 		telts->common_name = export_tm_loctext(pg, "common_name");
10288 		if (telts->common_name == NULL)
10289 			export_pg(pg, elts, SCE_ALL_VALUES);
10290 		return;
10291 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10292 		telts->description = export_tm_loctext(pg, "description");
10293 		if (telts->description == NULL)
10294 			export_pg(pg, elts, SCE_ALL_VALUES);
10295 		return;
10296 	}
10297 
10298 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10299 		child = export_tm_manpage(pg);
10300 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10301 		child = export_tm_doc_link(pg);
10302 	}
10303 
10304 	if (child != NULL) {
10305 		make_node(&telts->documentation, "documentation");
10306 		(void) xmlAddChild(telts->documentation, child);
10307 	} else {
10308 		export_pg(pg, elts, SCE_ALL_VALUES);
10309 	}
10310 }
10311 
10312 /*
10313  * Process parameter and paramval elements
10314  */
10315 static void
10316 export_parameter(scf_property_t *prop, const char *name,
10317     struct params_elts *elts)
10318 {
10319 	xmlNodePtr param;
10320 	scf_error_t err = 0;
10321 	int ret;
10322 
10323 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10324 		if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10325 			uu_die(emsg_create_xml);
10326 
10327 		safe_setprop(param, name_attr, name);
10328 
10329 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10330 			scfdie();
10331 		safe_setprop(param, value_attr, exp_str);
10332 
10333 		if (elts->paramval == NULL)
10334 			elts->paramval = param;
10335 		else
10336 			(void) xmlAddSibling(elts->paramval, param);
10337 
10338 		return;
10339 	}
10340 
10341 	err = scf_error();
10342 
10343 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10344 	    err != SCF_ERROR_NOT_FOUND)
10345 		scfdie();
10346 
10347 	if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10348 		uu_die(emsg_create_xml);
10349 
10350 	safe_setprop(param, name_attr, name);
10351 
10352 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10353 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10354 			scfdie();
10355 
10356 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10357 		    1) {
10358 			xmlNodePtr vn;
10359 
10360 			if ((vn = xmlNewChild(param, NULL,
10361 			    (xmlChar *)"value_node", NULL)) == NULL)
10362 				uu_die(emsg_create_xml);
10363 
10364 			if (scf_value_get_as_string(exp_val, exp_str,
10365 			    exp_str_sz) < 0)
10366 				scfdie();
10367 
10368 			safe_setprop(vn, value_attr, exp_str);
10369 		}
10370 		if (ret != 0)
10371 			scfdie();
10372 	}
10373 
10374 	if (elts->parameter == NULL)
10375 		elts->parameter = param;
10376 	else
10377 		(void) xmlAddSibling(elts->parameter, param);
10378 }
10379 
10380 /*
10381  * Process notification parameters for a service or instance
10382  */
10383 static void
10384 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10385 {
10386 	xmlNodePtr n, event, *type;
10387 	struct params_elts *eelts;
10388 	int ret, err, i;
10389 
10390 	n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10391 	event = xmlNewNode(NULL, (xmlChar *)"event");
10392 	if (n == NULL || event == NULL)
10393 		uu_die(emsg_create_xml);
10394 
10395 	/* event value */
10396 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10397 		scfdie();
10398 	safe_setprop(event, value_attr, exp_str);
10399 
10400 	(void) xmlAddChild(n, event);
10401 
10402 	if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10403 	    (eelts = calloc(URI_SCHEME_NUM,
10404 	    sizeof (struct params_elts))) == NULL)
10405 		uu_die(gettext("Out of memory.\n"));
10406 
10407 	err = 0;
10408 
10409 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10410 		scfdie();
10411 
10412 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10413 		char *t, *p;
10414 
10415 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10416 			scfdie();
10417 
10418 		if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10419 			/*
10420 			 * this is not a well formed notification parameters
10421 			 * element, we should export as regular pg
10422 			 */
10423 			err = 1;
10424 			break;
10425 		}
10426 
10427 		if ((i = check_uri_protocol(t)) < 0) {
10428 			err = 1;
10429 			break;
10430 		}
10431 
10432 		if (type[i] == NULL) {
10433 			if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10434 			    NULL)
10435 				uu_die(emsg_create_xml);
10436 
10437 			safe_setprop(type[i], name_attr, t);
10438 		}
10439 		if (strcmp(p, active_attr) == 0) {
10440 			if (set_attr_from_prop(exp_prop, type[i],
10441 			    active_attr) != 0) {
10442 				err = 1;
10443 				break;
10444 			}
10445 			continue;
10446 		}
10447 		/*
10448 		 * We export the parameter
10449 		 */
10450 		export_parameter(exp_prop, p, &eelts[i]);
10451 	}
10452 
10453 	if (ret == -1)
10454 		scfdie();
10455 
10456 	if (err == 1) {
10457 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10458 			xmlFree(type[i]);
10459 		free(type);
10460 
10461 		export_pg(pg, elts, SCE_ALL_VALUES);
10462 
10463 		return;
10464 	} else {
10465 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10466 			if (type[i] != NULL) {
10467 				(void) xmlAddChildList(type[i],
10468 				    eelts[i].paramval);
10469 				(void) xmlAddChildList(type[i],
10470 				    eelts[i].parameter);
10471 				(void) xmlAddSibling(event, type[i]);
10472 			}
10473 	}
10474 	free(type);
10475 
10476 	if (elts->notify_params == NULL)
10477 		elts->notify_params = n;
10478 	else
10479 		(void) xmlAddSibling(elts->notify_params, n);
10480 }
10481 
10482 /*
10483  * Process the general property group for an instance.
10484  */
10485 static void
10486 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10487     struct entity_elts *elts)
10488 {
10489 	uint8_t enabled;
10490 	struct pg_elts pgelts;
10491 	int ret;
10492 
10493 	/* enabled */
10494 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10495 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10496 	    prop_get_val(exp_prop, exp_val) == 0) {
10497 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10498 			scfdie();
10499 	} else {
10500 		enabled = 0;
10501 	}
10502 
10503 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10504 
10505 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10506 		scfdie();
10507 
10508 	(void) memset(&pgelts, 0, sizeof (pgelts));
10509 
10510 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10511 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10512 			scfdie();
10513 
10514 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10515 			continue;
10516 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10517 			xmlNodePtr rnode, sfnode;
10518 
10519 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10520 			if (rnode == NULL)
10521 				uu_die(emsg_create_xml);
10522 
10523 			sfnode = xmlNewChild(rnode, NULL,
10524 			    (xmlChar *)"service_fmri", NULL);
10525 			if (sfnode == NULL)
10526 				uu_die(emsg_create_xml);
10527 
10528 			if (set_attr_from_prop(exp_prop, sfnode,
10529 			    value_attr) == 0) {
10530 				elts->restarter = rnode;
10531 				continue;
10532 			}
10533 
10534 			xmlFreeNode(rnode);
10535 		}
10536 
10537 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10538 	}
10539 	if (ret == -1)
10540 		scfdie();
10541 
10542 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10543 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10544 		    elts);
10545 }
10546 
10547 /*
10548  * Put an instance element for the given instance into selts.
10549  */
10550 static void
10551 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10552 {
10553 	xmlNodePtr n;
10554 	boolean_t isdefault;
10555 	struct entity_elts elts;
10556 	struct template_elts template_elts;
10557 	int ret;
10558 
10559 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10560 	if (n == NULL)
10561 		uu_die(emsg_create_xml);
10562 
10563 	/* name */
10564 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10565 		scfdie();
10566 	safe_setprop(n, name_attr, exp_str);
10567 	isdefault = strcmp(exp_str, "default") == 0;
10568 
10569 	/* check existance of general pg (since general/enabled is required) */
10570 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10571 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10572 			scfdie();
10573 
10574 		if (g_verbose) {
10575 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10576 				scfdie();
10577 
10578 			warn(gettext("Instance %s has no general property "
10579 			    "group; it will be marked disabled.\n"), exp_str);
10580 		}
10581 
10582 		safe_setprop(n, enabled_attr, false);
10583 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10584 	    strcmp(exp_str, scf_group_framework) != 0) {
10585 		if (g_verbose) {
10586 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10587 				scfdie();
10588 
10589 			warn(gettext("Property group %s is not of type "
10590 			    "framework; the instance will be marked "
10591 			    "disabled.\n"), exp_str);
10592 		}
10593 
10594 		safe_setprop(n, enabled_attr, false);
10595 	}
10596 
10597 	/* property groups */
10598 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10599 		scfdie();
10600 
10601 	(void) memset(&elts, 0, sizeof (elts));
10602 	(void) memset(&template_elts, 0, sizeof (template_elts));
10603 
10604 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10605 		uint32_t pgflags;
10606 
10607 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10608 			scfdie();
10609 
10610 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10611 			continue;
10612 
10613 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10614 			scfdie();
10615 
10616 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10617 			export_dependency(exp_pg, &elts);
10618 			continue;
10619 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10620 			export_method(exp_pg, &elts);
10621 			continue;
10622 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10623 			if (scf_pg_get_name(exp_pg, exp_str,
10624 			    max_scf_name_len + 1) < 0)
10625 				scfdie();
10626 
10627 			if (strcmp(exp_str, scf_pg_general) == 0) {
10628 				export_inst_general(exp_pg, n, &elts);
10629 				continue;
10630 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10631 			    0) {
10632 				export_method_context(exp_pg, &elts);
10633 				continue;
10634 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10635 				export_dependents(exp_pg, &elts);
10636 				continue;
10637 			}
10638 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10639 			export_template(exp_pg, &elts, &template_elts);
10640 			continue;
10641 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10642 			export_notify_params(exp_pg, &elts);
10643 			continue;
10644 		}
10645 
10646 		/* Ordinary pg. */
10647 		export_pg(exp_pg, &elts, flags);
10648 	}
10649 	if (ret == -1)
10650 		scfdie();
10651 
10652 	if (template_elts.common_name != NULL) {
10653 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10654 		(void) xmlAddChild(elts.template, template_elts.common_name);
10655 		(void) xmlAddChild(elts.template, template_elts.description);
10656 		(void) xmlAddChild(elts.template, template_elts.documentation);
10657 	} else {
10658 		xmlFreeNode(template_elts.description);
10659 		xmlFreeNode(template_elts.documentation);
10660 	}
10661 
10662 	if (isdefault && elts.restarter == NULL &&
10663 	    elts.dependencies == NULL && elts.method_context == NULL &&
10664 	    elts.exec_methods == NULL && elts.notify_params == NULL &&
10665 	    elts.property_groups == NULL && elts.template == NULL) {
10666 		xmlChar *eval;
10667 
10668 		/* This is a default instance */
10669 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10670 
10671 		xmlFreeNode(n);
10672 
10673 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10674 		if (n == NULL)
10675 			uu_die(emsg_create_xml);
10676 
10677 		safe_setprop(n, enabled_attr, (char *)eval);
10678 		xmlFree(eval);
10679 
10680 		selts->create_default_instance = n;
10681 	} else {
10682 		/* Assemble the children in order. */
10683 		(void) xmlAddChild(n, elts.restarter);
10684 		(void) xmlAddChildList(n, elts.dependencies);
10685 		(void) xmlAddChildList(n, elts.dependents);
10686 		(void) xmlAddChild(n, elts.method_context);
10687 		(void) xmlAddChildList(n, elts.exec_methods);
10688 		(void) xmlAddChildList(n, elts.notify_params);
10689 		(void) xmlAddChildList(n, elts.property_groups);
10690 		(void) xmlAddChild(n, elts.template);
10691 
10692 		if (selts->instances == NULL)
10693 			selts->instances = n;
10694 		else
10695 			(void) xmlAddSibling(selts->instances, n);
10696 	}
10697 }
10698 
10699 /*
10700  * Return a service element for the given service.
10701  */
10702 static xmlNodePtr
10703 export_service(scf_service_t *svc, int flags)
10704 {
10705 	xmlNodePtr snode;
10706 	struct entity_elts elts;
10707 	struct template_elts template_elts;
10708 	int ret;
10709 
10710 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10711 	if (snode == NULL)
10712 		uu_die(emsg_create_xml);
10713 
10714 	/* Get & set name attribute */
10715 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10716 		scfdie();
10717 	safe_setprop(snode, name_attr, exp_str);
10718 
10719 	safe_setprop(snode, type_attr, "service");
10720 	safe_setprop(snode, "version", "0");
10721 
10722 	/* Acquire child elements. */
10723 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10724 		scfdie();
10725 
10726 	(void) memset(&elts, 0, sizeof (elts));
10727 	(void) memset(&template_elts, 0, sizeof (template_elts));
10728 
10729 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10730 		uint32_t pgflags;
10731 
10732 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10733 			scfdie();
10734 
10735 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10736 			continue;
10737 
10738 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10739 			scfdie();
10740 
10741 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10742 			export_dependency(exp_pg, &elts);
10743 			continue;
10744 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10745 			export_method(exp_pg, &elts);
10746 			continue;
10747 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10748 			if (scf_pg_get_name(exp_pg, exp_str,
10749 			    max_scf_name_len + 1) < 0)
10750 				scfdie();
10751 
10752 			if (strcmp(exp_str, scf_pg_general) == 0) {
10753 				export_svc_general(exp_pg, &elts);
10754 				continue;
10755 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10756 			    0) {
10757 				export_method_context(exp_pg, &elts);
10758 				continue;
10759 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10760 				export_dependents(exp_pg, &elts);
10761 				continue;
10762 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10763 				continue;
10764 			}
10765 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10766 			export_template(exp_pg, &elts, &template_elts);
10767 			continue;
10768 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10769 			export_notify_params(exp_pg, &elts);
10770 			continue;
10771 		}
10772 
10773 		export_pg(exp_pg, &elts, flags);
10774 	}
10775 	if (ret == -1)
10776 		scfdie();
10777 
10778 	if (template_elts.common_name != NULL) {
10779 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10780 		(void) xmlAddChild(elts.template, template_elts.common_name);
10781 		(void) xmlAddChild(elts.template, template_elts.description);
10782 		(void) xmlAddChild(elts.template, template_elts.documentation);
10783 	} else {
10784 		xmlFreeNode(template_elts.description);
10785 		xmlFreeNode(template_elts.documentation);
10786 	}
10787 
10788 	/* Iterate instances */
10789 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10790 		scfdie();
10791 
10792 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10793 		export_instance(exp_inst, &elts, flags);
10794 	if (ret == -1)
10795 		scfdie();
10796 
10797 	/* Now add all of the accumulated elements in order. */
10798 	(void) xmlAddChild(snode, elts.create_default_instance);
10799 	(void) xmlAddChild(snode, elts.single_instance);
10800 	(void) xmlAddChild(snode, elts.restarter);
10801 	(void) xmlAddChildList(snode, elts.dependencies);
10802 	(void) xmlAddChildList(snode, elts.dependents);
10803 	(void) xmlAddChild(snode, elts.method_context);
10804 	(void) xmlAddChildList(snode, elts.exec_methods);
10805 	(void) xmlAddChildList(snode, elts.notify_params);
10806 	(void) xmlAddChildList(snode, elts.property_groups);
10807 	(void) xmlAddChildList(snode, elts.instances);
10808 	(void) xmlAddChild(snode, elts.stability);
10809 	(void) xmlAddChild(snode, elts.template);
10810 
10811 	return (snode);
10812 }
10813 
10814 static int
10815 export_callback(void *data, scf_walkinfo_t *wip)
10816 {
10817 	FILE *f;
10818 	xmlDocPtr doc;
10819 	xmlNodePtr sb;
10820 	int result;
10821 	struct export_args *argsp = (struct export_args *)data;
10822 
10823 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10824 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10825 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10826 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10827 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10828 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10829 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10830 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10831 		scfdie();
10832 
10833 	exp_str_sz = max_scf_len + 1;
10834 	exp_str = safe_malloc(exp_str_sz);
10835 
10836 	if (argsp->filename != NULL) {
10837 		errno = 0;
10838 		f = fopen(argsp->filename, "wb");
10839 		if (f == NULL) {
10840 			if (errno == 0)
10841 				uu_die(gettext("Could not open \"%s\": no free "
10842 				    "stdio streams.\n"), argsp->filename);
10843 			else
10844 				uu_die(gettext("Could not open \"%s\""),
10845 				    argsp->filename);
10846 		}
10847 	} else
10848 		f = stdout;
10849 
10850 	doc = xmlNewDoc((xmlChar *)"1.0");
10851 	if (doc == NULL)
10852 		uu_die(gettext("Could not create XML document.\n"));
10853 
10854 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10855 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10856 		uu_die(emsg_create_xml);
10857 
10858 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10859 	if (sb == NULL)
10860 		uu_die(emsg_create_xml);
10861 	safe_setprop(sb, type_attr, "manifest");
10862 	safe_setprop(sb, name_attr, "export");
10863 	(void) xmlAddSibling(doc->children, sb);
10864 
10865 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10866 
10867 	result = write_service_bundle(doc, f);
10868 
10869 	free(exp_str);
10870 	scf_iter_destroy(exp_val_iter);
10871 	scf_iter_destroy(exp_prop_iter);
10872 	scf_iter_destroy(exp_pg_iter);
10873 	scf_iter_destroy(exp_inst_iter);
10874 	scf_value_destroy(exp_val);
10875 	scf_property_destroy(exp_prop);
10876 	scf_pg_destroy(exp_pg);
10877 	scf_instance_destroy(exp_inst);
10878 
10879 	xmlFreeDoc(doc);
10880 
10881 	if (f != stdout)
10882 		(void) fclose(f);
10883 
10884 	return (result);
10885 }
10886 
10887 /*
10888  * Get the service named by fmri, build an XML tree which represents it, and
10889  * dump it into filename (or stdout if filename is NULL).
10890  */
10891 int
10892 lscf_service_export(char *fmri, const char *filename, int flags)
10893 {
10894 	struct export_args args;
10895 	char *fmridup;
10896 	const char *scope, *svc, *inst;
10897 	size_t cblen = 3 * max_scf_name_len;
10898 	char *canonbuf = alloca(cblen);
10899 	int ret, err;
10900 
10901 	lscf_prep_hndl();
10902 
10903 	bzero(&args, sizeof (args));
10904 	args.filename = filename;
10905 	args.flags = flags;
10906 
10907 	/*
10908 	 * If some poor user has passed an exact instance FMRI, of the sort
10909 	 * one might cut and paste from svcs(1) or an error message, warn
10910 	 * and chop off the instance instead of failing.
10911 	 */
10912 	fmridup = alloca(strlen(fmri) + 1);
10913 	(void) strcpy(fmridup, fmri);
10914 	if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10915 	    sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10916 	    scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10917 	    inst != NULL) {
10918 		(void) strlcpy(canonbuf, "svc:/", cblen);
10919 		if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10920 			(void) strlcat(canonbuf, "/", cblen);
10921 			(void) strlcat(canonbuf, scope, cblen);
10922 		}
10923 		(void) strlcat(canonbuf, svc, cblen);
10924 		fmri = canonbuf;
10925 
10926 		warn(gettext("Only services may be exported; ignoring "
10927 		    "instance portion of argument.\n"));
10928 	}
10929 
10930 	err = 0;
10931 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10932 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10933 	    &args, &err, semerr)) != 0) {
10934 		if (ret != -1)
10935 			semerr(gettext("Failed to walk instances: %s\n"),
10936 			    scf_strerror(ret));
10937 		return (-1);
10938 	}
10939 
10940 	/*
10941 	 * Error message has already been printed.
10942 	 */
10943 	if (err != 0)
10944 		return (-1);
10945 
10946 	return (0);
10947 }
10948 
10949 
10950 /*
10951  * Archive
10952  */
10953 
10954 static xmlNodePtr
10955 make_archive(int flags)
10956 {
10957 	xmlNodePtr sb;
10958 	scf_scope_t *scope;
10959 	scf_service_t *svc;
10960 	scf_iter_t *iter;
10961 	int r;
10962 
10963 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10964 	    (svc = scf_service_create(g_hndl)) == NULL ||
10965 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10966 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10967 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10968 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10969 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10970 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10971 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10972 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10973 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10974 		scfdie();
10975 
10976 	exp_str_sz = max_scf_len + 1;
10977 	exp_str = safe_malloc(exp_str_sz);
10978 
10979 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10980 	if (sb == NULL)
10981 		uu_die(emsg_create_xml);
10982 	safe_setprop(sb, type_attr, "archive");
10983 	safe_setprop(sb, name_attr, "none");
10984 
10985 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10986 		scfdie();
10987 	if (scf_iter_scope_services(iter, scope) != 0)
10988 		scfdie();
10989 
10990 	for (;;) {
10991 		r = scf_iter_next_service(iter, svc);
10992 		if (r == 0)
10993 			break;
10994 		if (r != 1)
10995 			scfdie();
10996 
10997 		if (scf_service_get_name(svc, exp_str,
10998 		    max_scf_name_len + 1) < 0)
10999 			scfdie();
11000 
11001 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
11002 			continue;
11003 
11004 		(void) xmlAddChild(sb, export_service(svc, flags));
11005 	}
11006 
11007 	free(exp_str);
11008 
11009 	scf_iter_destroy(exp_val_iter);
11010 	scf_iter_destroy(exp_prop_iter);
11011 	scf_iter_destroy(exp_pg_iter);
11012 	scf_iter_destroy(exp_inst_iter);
11013 	scf_value_destroy(exp_val);
11014 	scf_property_destroy(exp_prop);
11015 	scf_pg_destroy(exp_pg);
11016 	scf_instance_destroy(exp_inst);
11017 	scf_iter_destroy(iter);
11018 	scf_service_destroy(svc);
11019 	scf_scope_destroy(scope);
11020 
11021 	return (sb);
11022 }
11023 
11024 int
11025 lscf_archive(const char *filename, int flags)
11026 {
11027 	FILE *f;
11028 	xmlDocPtr doc;
11029 	int result;
11030 
11031 	lscf_prep_hndl();
11032 
11033 	if (filename != NULL) {
11034 		errno = 0;
11035 		f = fopen(filename, "wb");
11036 		if (f == NULL) {
11037 			if (errno == 0)
11038 				uu_die(gettext("Could not open \"%s\": no free "
11039 				    "stdio streams.\n"), filename);
11040 			else
11041 				uu_die(gettext("Could not open \"%s\""),
11042 				    filename);
11043 		}
11044 	} else
11045 		f = stdout;
11046 
11047 	doc = xmlNewDoc((xmlChar *)"1.0");
11048 	if (doc == NULL)
11049 		uu_die(gettext("Could not create XML document.\n"));
11050 
11051 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11052 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11053 		uu_die(emsg_create_xml);
11054 
11055 	(void) xmlAddSibling(doc->children, make_archive(flags));
11056 
11057 	result = write_service_bundle(doc, f);
11058 
11059 	xmlFreeDoc(doc);
11060 
11061 	if (f != stdout)
11062 		(void) fclose(f);
11063 
11064 	return (result);
11065 }
11066 
11067 
11068 /*
11069  * "Extract" a profile.
11070  */
11071 int
11072 lscf_profile_extract(const char *filename)
11073 {
11074 	FILE *f;
11075 	xmlDocPtr doc;
11076 	xmlNodePtr sb, snode, inode;
11077 	scf_scope_t *scope;
11078 	scf_service_t *svc;
11079 	scf_instance_t *inst;
11080 	scf_propertygroup_t *pg;
11081 	scf_property_t *prop;
11082 	scf_value_t *val;
11083 	scf_iter_t *siter, *iiter;
11084 	int r, s;
11085 	char *namebuf;
11086 	uint8_t b;
11087 	int result;
11088 
11089 	lscf_prep_hndl();
11090 
11091 	if (filename != NULL) {
11092 		errno = 0;
11093 		f = fopen(filename, "wb");
11094 		if (f == NULL) {
11095 			if (errno == 0)
11096 				uu_die(gettext("Could not open \"%s\": no "
11097 				    "free stdio streams.\n"), filename);
11098 			else
11099 				uu_die(gettext("Could not open \"%s\""),
11100 				    filename);
11101 		}
11102 	} else
11103 		f = stdout;
11104 
11105 	doc = xmlNewDoc((xmlChar *)"1.0");
11106 	if (doc == NULL)
11107 		uu_die(gettext("Could not create XML document.\n"));
11108 
11109 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
11110 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
11111 		uu_die(emsg_create_xml);
11112 
11113 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
11114 	if (sb == NULL)
11115 		uu_die(emsg_create_xml);
11116 	safe_setprop(sb, type_attr, "profile");
11117 	safe_setprop(sb, name_attr, "extract");
11118 	(void) xmlAddSibling(doc->children, sb);
11119 
11120 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
11121 	    (svc = scf_service_create(g_hndl)) == NULL ||
11122 	    (inst = scf_instance_create(g_hndl)) == NULL ||
11123 	    (pg = scf_pg_create(g_hndl)) == NULL ||
11124 	    (prop = scf_property_create(g_hndl)) == NULL ||
11125 	    (val = scf_value_create(g_hndl)) == NULL ||
11126 	    (siter = scf_iter_create(g_hndl)) == NULL ||
11127 	    (iiter = scf_iter_create(g_hndl)) == NULL)
11128 		scfdie();
11129 
11130 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
11131 		scfdie();
11132 
11133 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
11134 		scfdie();
11135 
11136 	namebuf = safe_malloc(max_scf_name_len + 1);
11137 
11138 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
11139 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
11140 			scfdie();
11141 
11142 		snode = xmlNewNode(NULL, (xmlChar *)"service");
11143 		if (snode == NULL)
11144 			uu_die(emsg_create_xml);
11145 
11146 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
11147 		    0)
11148 			scfdie();
11149 
11150 		safe_setprop(snode, name_attr, namebuf);
11151 
11152 		safe_setprop(snode, type_attr, "service");
11153 		safe_setprop(snode, "version", "0");
11154 
11155 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
11156 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
11157 			    SCF_SUCCESS) {
11158 				if (scf_error() != SCF_ERROR_NOT_FOUND)
11159 					scfdie();
11160 
11161 				if (g_verbose) {
11162 					ssize_t len;
11163 					char *fmri;
11164 
11165 					len =
11166 					    scf_instance_to_fmri(inst, NULL, 0);
11167 					if (len < 0)
11168 						scfdie();
11169 
11170 					fmri = safe_malloc(len + 1);
11171 
11172 					if (scf_instance_to_fmri(inst, fmri,
11173 					    len + 1) < 0)
11174 						scfdie();
11175 
11176 					warn("Instance %s has no \"%s\" "
11177 					    "property group.\n", fmri,
11178 					    scf_pg_general);
11179 
11180 					free(fmri);
11181 				}
11182 
11183 				continue;
11184 			}
11185 
11186 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
11187 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
11188 			    prop_get_val(prop, val) != 0)
11189 				continue;
11190 
11191 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
11192 			    NULL);
11193 			if (inode == NULL)
11194 				uu_die(emsg_create_xml);
11195 
11196 			if (scf_instance_get_name(inst, namebuf,
11197 			    max_scf_name_len + 1) < 0)
11198 				scfdie();
11199 
11200 			safe_setprop(inode, name_attr, namebuf);
11201 
11202 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
11203 				scfdie();
11204 
11205 			safe_setprop(inode, enabled_attr, b ? true : false);
11206 		}
11207 		if (s < 0)
11208 			scfdie();
11209 
11210 		if (snode->children != NULL)
11211 			(void) xmlAddChild(sb, snode);
11212 		else
11213 			xmlFreeNode(snode);
11214 	}
11215 	if (r < 0)
11216 		scfdie();
11217 
11218 	free(namebuf);
11219 
11220 	result = write_service_bundle(doc, f);
11221 
11222 	xmlFreeDoc(doc);
11223 
11224 	if (f != stdout)
11225 		(void) fclose(f);
11226 
11227 	return (result);
11228 }
11229 
11230 
11231 /*
11232  * Entity manipulation commands
11233  */
11234 
11235 /*
11236  * Entity selection.  If no entity is selected, then the current scope is in
11237  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
11238  * only cur_inst is NULL, and when an instance is selected, none are NULL.
11239  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
11240  * cur_inst will be non-NULL.
11241  */
11242 
11243 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
11244 static int
11245 select_inst(const char *name)
11246 {
11247 	scf_instance_t *inst;
11248 	scf_error_t err;
11249 
11250 	assert(cur_svc != NULL);
11251 
11252 	inst = scf_instance_create(g_hndl);
11253 	if (inst == NULL)
11254 		scfdie();
11255 
11256 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
11257 		cur_inst = inst;
11258 		return (0);
11259 	}
11260 
11261 	err = scf_error();
11262 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11263 		scfdie();
11264 
11265 	scf_instance_destroy(inst);
11266 	return (1);
11267 }
11268 
11269 /* Returns as above. */
11270 static int
11271 select_svc(const char *name)
11272 {
11273 	scf_service_t *svc;
11274 	scf_error_t err;
11275 
11276 	assert(cur_scope != NULL);
11277 
11278 	svc = scf_service_create(g_hndl);
11279 	if (svc == NULL)
11280 		scfdie();
11281 
11282 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11283 		cur_svc = svc;
11284 		return (0);
11285 	}
11286 
11287 	err = scf_error();
11288 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11289 		scfdie();
11290 
11291 	scf_service_destroy(svc);
11292 	return (1);
11293 }
11294 
11295 /* ARGSUSED */
11296 static int
11297 select_callback(void *unused, scf_walkinfo_t *wip)
11298 {
11299 	scf_instance_t *inst;
11300 	scf_service_t *svc;
11301 	scf_scope_t *scope;
11302 
11303 	if (wip->inst != NULL) {
11304 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11305 		    (svc = scf_service_create(g_hndl)) == NULL ||
11306 		    (inst = scf_instance_create(g_hndl)) == NULL)
11307 			scfdie();
11308 
11309 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11310 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11311 			scfdie();
11312 	} else {
11313 		assert(wip->svc != NULL);
11314 
11315 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11316 		    (svc = scf_service_create(g_hndl)) == NULL)
11317 			scfdie();
11318 
11319 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11320 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11321 			scfdie();
11322 
11323 		inst = NULL;
11324 	}
11325 
11326 	/* Clear out the current selection */
11327 	assert(cur_scope != NULL);
11328 	scf_scope_destroy(cur_scope);
11329 	scf_service_destroy(cur_svc);
11330 	scf_instance_destroy(cur_inst);
11331 
11332 	cur_scope = scope;
11333 	cur_svc = svc;
11334 	cur_inst = inst;
11335 
11336 	return (0);
11337 }
11338 
11339 static int
11340 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11341 {
11342 	char **fmri = fmri_p;
11343 
11344 	*fmri = strdup(wip->fmri);
11345 	if (*fmri == NULL)
11346 		uu_die(gettext("Out of memory.\n"));
11347 
11348 	return (0);
11349 }
11350 
11351 /*
11352  * validate [fmri]
11353  * Perform the validation of an FMRI instance.
11354  */
11355 void
11356 lscf_validate_fmri(const char *fmri)
11357 {
11358 	int ret = 0;
11359 	size_t inst_sz;
11360 	char *inst_fmri = NULL;
11361 	scf_tmpl_errors_t *errs = NULL;
11362 	char *snapbuf = NULL;
11363 
11364 	lscf_prep_hndl();
11365 
11366 	if (fmri == NULL) {
11367 		inst_sz = max_scf_fmri_len + 1;
11368 		inst_fmri = safe_malloc(inst_sz);
11369 
11370 		if (cur_snap != NULL) {
11371 			snapbuf = safe_malloc(max_scf_name_len + 1);
11372 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11373 			    max_scf_name_len + 1) < 0)
11374 				scfdie();
11375 		}
11376 		if (cur_inst == NULL) {
11377 			semerr(gettext("No instance selected\n"));
11378 			goto cleanup;
11379 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11380 		    inst_sz) >= inst_sz) {
11381 			/* sanity check. Should never get here */
11382 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11383 			    __FILE__, __LINE__);
11384 		}
11385 	} else {
11386 		scf_error_t scf_err;
11387 		int err = 0;
11388 
11389 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11390 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11391 			uu_warn("Failed to walk instances: %s\n",
11392 			    scf_strerror(scf_err));
11393 			goto cleanup;
11394 		}
11395 		if (err != 0) {
11396 			/* error message displayed by scf_walk_fmri */
11397 			goto cleanup;
11398 		}
11399 	}
11400 
11401 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11402 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11403 	if (ret == -1) {
11404 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11405 			warn(gettext("Template data for %s is invalid. "
11406 			    "Consider reverting to a previous snapshot or "
11407 			    "restoring original configuration.\n"), inst_fmri);
11408 		} else {
11409 			uu_warn("%s: %s\n",
11410 			    gettext("Error validating the instance"),
11411 			    scf_strerror(scf_error()));
11412 		}
11413 	} else if (ret == 1 && errs != NULL) {
11414 		scf_tmpl_error_t *err = NULL;
11415 		char *msg;
11416 		size_t len = 256;	/* initial error buffer size */
11417 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11418 		    SCF_TMPL_STRERROR_HUMAN : 0;
11419 
11420 		msg = safe_malloc(len);
11421 
11422 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11423 			int ret;
11424 
11425 			if ((ret = scf_tmpl_strerror(err, msg, len,
11426 			    flag)) >= len) {
11427 				len = ret + 1;
11428 				msg = realloc(msg, len);
11429 				if (msg == NULL)
11430 					uu_die(gettext(
11431 					    "Out of memory.\n"));
11432 				(void) scf_tmpl_strerror(err, msg, len,
11433 				    flag);
11434 			}
11435 			(void) fprintf(stderr, "%s\n", msg);
11436 		}
11437 		if (msg != NULL)
11438 			free(msg);
11439 	}
11440 	if (errs != NULL)
11441 		scf_tmpl_errors_destroy(errs);
11442 
11443 cleanup:
11444 	free(inst_fmri);
11445 	free(snapbuf);
11446 }
11447 
11448 static void
11449 lscf_validate_file(const char *filename)
11450 {
11451 	tmpl_errors_t *errs;
11452 
11453 	bundle_t *b = internal_bundle_new();
11454 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11455 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11456 			tmpl_errors_print(stderr, errs, "");
11457 			semerr(gettext("Validation failed.\n"));
11458 		}
11459 		tmpl_errors_destroy(errs);
11460 	}
11461 	(void) internal_bundle_free(b);
11462 }
11463 
11464 /*
11465  * validate [fmri|file]
11466  */
11467 void
11468 lscf_validate(const char *arg)
11469 {
11470 	const char *str;
11471 
11472 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11473 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11474 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11475 		lscf_validate_file(str);
11476 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11477 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11478 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11479 		lscf_validate_fmri(str);
11480 	} else if (access(arg, R_OK | F_OK) == 0) {
11481 		lscf_validate_file(arg);
11482 	} else {
11483 		lscf_validate_fmri(arg);
11484 	}
11485 }
11486 
11487 void
11488 lscf_select(const char *fmri)
11489 {
11490 	int ret, err;
11491 
11492 	lscf_prep_hndl();
11493 
11494 	if (cur_snap != NULL) {
11495 		struct snaplevel *elt;
11496 		char *buf;
11497 
11498 		/* Error unless name is that of the next level. */
11499 		elt = uu_list_next(cur_levels, cur_elt);
11500 		if (elt == NULL) {
11501 			semerr(gettext("No children.\n"));
11502 			return;
11503 		}
11504 
11505 		buf = safe_malloc(max_scf_name_len + 1);
11506 
11507 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11508 		    max_scf_name_len + 1) < 0)
11509 			scfdie();
11510 
11511 		if (strcmp(buf, fmri) != 0) {
11512 			semerr(gettext("No such child.\n"));
11513 			free(buf);
11514 			return;
11515 		}
11516 
11517 		free(buf);
11518 
11519 		cur_elt = elt;
11520 		cur_level = elt->sl;
11521 		return;
11522 	}
11523 
11524 	/*
11525 	 * Special case for 'svc:', which takes the user to the scope level.
11526 	 */
11527 	if (strcmp(fmri, "svc:") == 0) {
11528 		scf_instance_destroy(cur_inst);
11529 		scf_service_destroy(cur_svc);
11530 		cur_inst = NULL;
11531 		cur_svc = NULL;
11532 		return;
11533 	}
11534 
11535 	/*
11536 	 * Special case for ':properties'.  This appears as part of 'list' but
11537 	 * can't be selected.  Give a more helpful error message in this case.
11538 	 */
11539 	if (strcmp(fmri, ":properties") == 0) {
11540 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11541 		    "to list properties.\n"));
11542 		return;
11543 	}
11544 
11545 	/*
11546 	 * First try the argument as relative to the current selection.
11547 	 */
11548 	if (cur_inst != NULL) {
11549 		/* EMPTY */;
11550 	} else if (cur_svc != NULL) {
11551 		if (select_inst(fmri) != 1)
11552 			return;
11553 	} else {
11554 		if (select_svc(fmri) != 1)
11555 			return;
11556 	}
11557 
11558 	err = 0;
11559 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11560 	    select_callback, NULL, &err, semerr)) != 0) {
11561 		semerr(gettext("Failed to walk instances: %s\n"),
11562 		    scf_strerror(ret));
11563 	}
11564 }
11565 
11566 void
11567 lscf_unselect(void)
11568 {
11569 	lscf_prep_hndl();
11570 
11571 	if (cur_snap != NULL) {
11572 		struct snaplevel *elt;
11573 
11574 		elt = uu_list_prev(cur_levels, cur_elt);
11575 		if (elt == NULL) {
11576 			semerr(gettext("No parent levels.\n"));
11577 		} else {
11578 			cur_elt = elt;
11579 			cur_level = elt->sl;
11580 		}
11581 	} else if (cur_inst != NULL) {
11582 		scf_instance_destroy(cur_inst);
11583 		cur_inst = NULL;
11584 	} else if (cur_svc != NULL) {
11585 		scf_service_destroy(cur_svc);
11586 		cur_svc = NULL;
11587 	} else {
11588 		semerr(gettext("Cannot unselect at scope level.\n"));
11589 	}
11590 }
11591 
11592 /*
11593  * Return the FMRI of the current selection, for the prompt.
11594  */
11595 void
11596 lscf_get_selection_str(char *buf, size_t bufsz)
11597 {
11598 	char *cp;
11599 	ssize_t fmrilen, szret;
11600 	boolean_t deleted = B_FALSE;
11601 
11602 	if (g_hndl == NULL) {
11603 		(void) strlcpy(buf, "svc:", bufsz);
11604 		return;
11605 	}
11606 
11607 	if (cur_level != NULL) {
11608 		assert(cur_snap != NULL);
11609 
11610 		/* [ snapshot ] FMRI [: instance ] */
11611 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11612 		    + 2 + max_scf_name_len + 1 + 1);
11613 
11614 		buf[0] = '[';
11615 
11616 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11617 		    max_scf_name_len + 1);
11618 		if (szret < 0) {
11619 			if (scf_error() != SCF_ERROR_DELETED)
11620 				scfdie();
11621 
11622 			goto snap_deleted;
11623 		}
11624 
11625 		(void) strcat(buf, "]svc:/");
11626 
11627 		cp = strchr(buf, '\0');
11628 
11629 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11630 		    max_scf_name_len + 1);
11631 		if (szret < 0) {
11632 			if (scf_error() != SCF_ERROR_DELETED)
11633 				scfdie();
11634 
11635 			goto snap_deleted;
11636 		}
11637 
11638 		cp = strchr(cp, '\0');
11639 
11640 		if (snaplevel_is_instance(cur_level)) {
11641 			*cp++ = ':';
11642 
11643 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11644 			    max_scf_name_len + 1) < 0) {
11645 				if (scf_error() != SCF_ERROR_DELETED)
11646 					scfdie();
11647 
11648 				goto snap_deleted;
11649 			}
11650 		} else {
11651 			*cp++ = '[';
11652 			*cp++ = ':';
11653 
11654 			if (scf_instance_get_name(cur_inst, cp,
11655 			    max_scf_name_len + 1) < 0) {
11656 				if (scf_error() != SCF_ERROR_DELETED)
11657 					scfdie();
11658 
11659 				goto snap_deleted;
11660 			}
11661 
11662 			(void) strcat(buf, "]");
11663 		}
11664 
11665 		return;
11666 
11667 snap_deleted:
11668 		deleted = B_TRUE;
11669 		free(buf);
11670 		unselect_cursnap();
11671 	}
11672 
11673 	assert(cur_snap == NULL);
11674 
11675 	if (cur_inst != NULL) {
11676 		assert(cur_svc != NULL);
11677 		assert(cur_scope != NULL);
11678 
11679 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11680 		if (fmrilen >= 0) {
11681 			assert(fmrilen < bufsz);
11682 			if (deleted)
11683 				warn(emsg_deleted);
11684 			return;
11685 		}
11686 
11687 		if (scf_error() != SCF_ERROR_DELETED)
11688 			scfdie();
11689 
11690 		deleted = B_TRUE;
11691 
11692 		scf_instance_destroy(cur_inst);
11693 		cur_inst = NULL;
11694 	}
11695 
11696 	if (cur_svc != NULL) {
11697 		assert(cur_scope != NULL);
11698 
11699 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11700 		if (szret >= 0) {
11701 			assert(szret < bufsz);
11702 			if (deleted)
11703 				warn(emsg_deleted);
11704 			return;
11705 		}
11706 
11707 		if (scf_error() != SCF_ERROR_DELETED)
11708 			scfdie();
11709 
11710 		deleted = B_TRUE;
11711 		scf_service_destroy(cur_svc);
11712 		cur_svc = NULL;
11713 	}
11714 
11715 	assert(cur_scope != NULL);
11716 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11717 
11718 	if (fmrilen < 0)
11719 		scfdie();
11720 
11721 	assert(fmrilen < bufsz);
11722 	if (deleted)
11723 		warn(emsg_deleted);
11724 }
11725 
11726 /*
11727  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11728  * :statistics) are listed for the current selection.
11729  */
11730 void
11731 lscf_list(const char *pattern)
11732 {
11733 	scf_iter_t *iter;
11734 	char *buf;
11735 	int ret;
11736 
11737 	lscf_prep_hndl();
11738 
11739 	if (cur_level != NULL) {
11740 		struct snaplevel *elt;
11741 
11742 		(void) fputs(COLON_NAMESPACES, stdout);
11743 
11744 		elt = uu_list_next(cur_levels, cur_elt);
11745 		if (elt == NULL)
11746 			return;
11747 
11748 		/*
11749 		 * For now, we know that the next level is an instance.  But
11750 		 * if we ever have multiple scopes, this could be complicated.
11751 		 */
11752 		buf = safe_malloc(max_scf_name_len + 1);
11753 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11754 		    max_scf_name_len + 1) >= 0) {
11755 			(void) puts(buf);
11756 		} else {
11757 			if (scf_error() != SCF_ERROR_DELETED)
11758 				scfdie();
11759 		}
11760 
11761 		free(buf);
11762 
11763 		return;
11764 	}
11765 
11766 	if (cur_inst != NULL) {
11767 		(void) fputs(COLON_NAMESPACES, stdout);
11768 		return;
11769 	}
11770 
11771 	iter = scf_iter_create(g_hndl);
11772 	if (iter == NULL)
11773 		scfdie();
11774 
11775 	buf = safe_malloc(max_scf_name_len + 1);
11776 
11777 	if (cur_svc != NULL) {
11778 		/* List the instances in this service. */
11779 		scf_instance_t *inst;
11780 
11781 		inst = scf_instance_create(g_hndl);
11782 		if (inst == NULL)
11783 			scfdie();
11784 
11785 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11786 			safe_printf(COLON_NAMESPACES);
11787 
11788 			for (;;) {
11789 				ret = scf_iter_next_instance(iter, inst);
11790 				if (ret == 0)
11791 					break;
11792 				if (ret != 1) {
11793 					if (scf_error() != SCF_ERROR_DELETED)
11794 						scfdie();
11795 
11796 					break;
11797 				}
11798 
11799 				if (scf_instance_get_name(inst, buf,
11800 				    max_scf_name_len + 1) >= 0) {
11801 					if (pattern == NULL ||
11802 					    fnmatch(pattern, buf, 0) == 0)
11803 						(void) puts(buf);
11804 				} else {
11805 					if (scf_error() != SCF_ERROR_DELETED)
11806 						scfdie();
11807 				}
11808 			}
11809 		} else {
11810 			if (scf_error() != SCF_ERROR_DELETED)
11811 				scfdie();
11812 		}
11813 
11814 		scf_instance_destroy(inst);
11815 	} else {
11816 		/* List the services in this scope. */
11817 		scf_service_t *svc;
11818 
11819 		assert(cur_scope != NULL);
11820 
11821 		svc = scf_service_create(g_hndl);
11822 		if (svc == NULL)
11823 			scfdie();
11824 
11825 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11826 			scfdie();
11827 
11828 		for (;;) {
11829 			ret = scf_iter_next_service(iter, svc);
11830 			if (ret == 0)
11831 				break;
11832 			if (ret != 1)
11833 				scfdie();
11834 
11835 			if (scf_service_get_name(svc, buf,
11836 			    max_scf_name_len + 1) >= 0) {
11837 				if (pattern == NULL ||
11838 				    fnmatch(pattern, buf, 0) == 0)
11839 					safe_printf("%s\n", buf);
11840 			} else {
11841 				if (scf_error() != SCF_ERROR_DELETED)
11842 					scfdie();
11843 			}
11844 		}
11845 
11846 		scf_service_destroy(svc);
11847 	}
11848 
11849 	free(buf);
11850 	scf_iter_destroy(iter);
11851 }
11852 
11853 /*
11854  * Entity addition.  Creates an empty entity in the current selection.
11855  */
11856 void
11857 lscf_add(const char *name)
11858 {
11859 	lscf_prep_hndl();
11860 
11861 	if (cur_snap != NULL) {
11862 		semerr(emsg_cant_modify_snapshots);
11863 	} else if (cur_inst != NULL) {
11864 		semerr(gettext("Cannot add entities to an instance.\n"));
11865 	} else if (cur_svc != NULL) {
11866 
11867 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11868 		    SCF_SUCCESS) {
11869 			switch (scf_error()) {
11870 			case SCF_ERROR_INVALID_ARGUMENT:
11871 				semerr(gettext("Invalid name.\n"));
11872 				break;
11873 
11874 			case SCF_ERROR_EXISTS:
11875 				semerr(gettext("Instance already exists.\n"));
11876 				break;
11877 
11878 			case SCF_ERROR_PERMISSION_DENIED:
11879 				semerr(emsg_permission_denied);
11880 				break;
11881 
11882 			default:
11883 				scfdie();
11884 			}
11885 		}
11886 	} else {
11887 		assert(cur_scope != NULL);
11888 
11889 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11890 		    SCF_SUCCESS) {
11891 			switch (scf_error()) {
11892 			case SCF_ERROR_INVALID_ARGUMENT:
11893 				semerr(gettext("Invalid name.\n"));
11894 				break;
11895 
11896 			case SCF_ERROR_EXISTS:
11897 				semerr(gettext("Service already exists.\n"));
11898 				break;
11899 
11900 			case SCF_ERROR_PERMISSION_DENIED:
11901 				semerr(emsg_permission_denied);
11902 				break;
11903 
11904 			case SCF_ERROR_BACKEND_READONLY:
11905 				semerr(emsg_read_only);
11906 				break;
11907 
11908 			default:
11909 				scfdie();
11910 			}
11911 		}
11912 	}
11913 }
11914 
11915 /* return 1 if the entity has no persistent pgs, else return 0 */
11916 static int
11917 entity_has_no_pgs(void *ent, int isservice)
11918 {
11919 	scf_iter_t *iter = NULL;
11920 	scf_propertygroup_t *pg = NULL;
11921 	uint32_t flags;
11922 	int err;
11923 	int ret = 1;
11924 
11925 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11926 	    (pg = scf_pg_create(g_hndl)) == NULL)
11927 		scfdie();
11928 
11929 	if (isservice) {
11930 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11931 			scfdie();
11932 	} else {
11933 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11934 			scfdie();
11935 	}
11936 
11937 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11938 		if (scf_pg_get_flags(pg, &flags) != 0)
11939 			scfdie();
11940 
11941 		/* skip nonpersistent pgs */
11942 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11943 			continue;
11944 
11945 		ret = 0;
11946 		break;
11947 	}
11948 
11949 	if (err == -1)
11950 		scfdie();
11951 
11952 	scf_pg_destroy(pg);
11953 	scf_iter_destroy(iter);
11954 
11955 	return (ret);
11956 }
11957 
11958 /* return 1 if the service has no instances, else return 0 */
11959 static int
11960 svc_has_no_insts(scf_service_t *svc)
11961 {
11962 	scf_instance_t *inst;
11963 	scf_iter_t *iter;
11964 	int r;
11965 	int ret = 1;
11966 
11967 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11968 	    (iter = scf_iter_create(g_hndl)) == NULL)
11969 		scfdie();
11970 
11971 	if (scf_iter_service_instances(iter, svc) != 0)
11972 		scfdie();
11973 
11974 	r = scf_iter_next_instance(iter, inst);
11975 	if (r == 1) {
11976 		ret = 0;
11977 	} else if (r == 0) {
11978 		ret = 1;
11979 	} else if (r == -1) {
11980 		scfdie();
11981 	} else {
11982 		bad_error("scf_iter_next_instance", r);
11983 	}
11984 
11985 	scf_iter_destroy(iter);
11986 	scf_instance_destroy(inst);
11987 
11988 	return (ret);
11989 }
11990 
11991 /*
11992  * Entity deletion.
11993  */
11994 
11995 /*
11996  * Delete the property group <fmri>/:properties/<name>.  Returns
11997  * SCF_ERROR_NONE on success (or if the entity is not found),
11998  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11999  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
12000  * denied.
12001  */
12002 static scf_error_t
12003 delete_dependency_pg(const char *fmri, const char *name)
12004 {
12005 	void *entity = NULL;
12006 	int isservice;
12007 	scf_propertygroup_t *pg = NULL;
12008 	scf_error_t result;
12009 	char *pgty;
12010 	scf_service_t *svc = NULL;
12011 	scf_instance_t *inst = NULL;
12012 	scf_iter_t *iter = NULL;
12013 	char *name_buf = NULL;
12014 
12015 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
12016 	switch (result) {
12017 	case SCF_ERROR_NONE:
12018 		break;
12019 
12020 	case SCF_ERROR_NO_MEMORY:
12021 		uu_die(gettext("Out of memory.\n"));
12022 		/* NOTREACHED */
12023 
12024 	case SCF_ERROR_INVALID_ARGUMENT:
12025 	case SCF_ERROR_CONSTRAINT_VIOLATED:
12026 		return (SCF_ERROR_INVALID_ARGUMENT);
12027 
12028 	case SCF_ERROR_NOT_FOUND:
12029 		result = SCF_ERROR_NONE;
12030 		goto out;
12031 
12032 	default:
12033 		bad_error("fmri_to_entity", result);
12034 	}
12035 
12036 	pg = scf_pg_create(g_hndl);
12037 	if (pg == NULL)
12038 		scfdie();
12039 
12040 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
12041 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12042 			scfdie();
12043 
12044 		result = SCF_ERROR_NONE;
12045 		goto out;
12046 	}
12047 
12048 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12049 
12050 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12051 		scfdie();
12052 
12053 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
12054 		result = SCF_ERROR_TYPE_MISMATCH;
12055 		free(pgty);
12056 		goto out;
12057 	}
12058 
12059 	free(pgty);
12060 
12061 	if (scf_pg_delete(pg) != 0) {
12062 		result = scf_error();
12063 		if (result != SCF_ERROR_PERMISSION_DENIED)
12064 			scfdie();
12065 		goto out;
12066 	}
12067 
12068 	/*
12069 	 * We have to handle the case where we've just deleted the last
12070 	 * property group of a "dummy" entity (instance or service).
12071 	 * A "dummy" entity is an entity only present to hold an
12072 	 * external dependency.
12073 	 * So, in the case we deleted the last property group then we
12074 	 * can also delete the entity. If the entity is an instance then
12075 	 * we must verify if this was the last instance for the service
12076 	 * and if it is, we can also delete the service if it doesn't
12077 	 * have any property group either.
12078 	 */
12079 
12080 	result = SCF_ERROR_NONE;
12081 
12082 	if (isservice) {
12083 		svc = (scf_service_t *)entity;
12084 
12085 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
12086 		    (iter = scf_iter_create(g_hndl)) == NULL)
12087 			scfdie();
12088 
12089 		name_buf = safe_malloc(max_scf_name_len + 1);
12090 	} else {
12091 		inst = (scf_instance_t *)entity;
12092 	}
12093 
12094 	/*
12095 	 * If the entity is an instance and we've just deleted its last
12096 	 * property group then we should delete it.
12097 	 */
12098 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
12099 		/* find the service before deleting the inst. - needed later */
12100 		if ((svc = scf_service_create(g_hndl)) == NULL)
12101 			scfdie();
12102 
12103 		if (scf_instance_get_parent(inst, svc) != 0)
12104 			scfdie();
12105 
12106 		/* delete the instance */
12107 		if (scf_instance_delete(inst) != 0) {
12108 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12109 				scfdie();
12110 
12111 			result = SCF_ERROR_PERMISSION_DENIED;
12112 			goto out;
12113 		}
12114 		/* no need to refresh the instance */
12115 		inst = NULL;
12116 	}
12117 
12118 	/*
12119 	 * If the service has no more instances and pgs or we just deleted the
12120 	 * last instance and the service doesn't have anymore propery groups
12121 	 * then the service should be deleted.
12122 	 */
12123 	if (svc != NULL &&
12124 	    svc_has_no_insts(svc) &&
12125 	    entity_has_no_pgs((void *)svc, 1)) {
12126 		if (scf_service_delete(svc) == 0) {
12127 			if (isservice) {
12128 				/* no need to refresh the service */
12129 				svc = NULL;
12130 			}
12131 
12132 			goto out;
12133 		}
12134 
12135 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12136 			scfdie();
12137 
12138 		result = SCF_ERROR_PERMISSION_DENIED;
12139 	}
12140 
12141 	/* if the entity has not been deleted, refresh it */
12142 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
12143 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
12144 		    name_buf);
12145 	}
12146 
12147 out:
12148 	if (isservice && (inst != NULL && iter != NULL)) {
12149 		free(name_buf);
12150 		scf_iter_destroy(iter);
12151 		scf_instance_destroy(inst);
12152 	}
12153 
12154 	if (!isservice && svc != NULL) {
12155 		scf_service_destroy(svc);
12156 	}
12157 
12158 	scf_pg_destroy(pg);
12159 	if (entity != NULL)
12160 		entity_destroy(entity, isservice);
12161 
12162 	return (result);
12163 }
12164 
12165 static int
12166 delete_dependents(scf_propertygroup_t *pg)
12167 {
12168 	char *pgty, *name, *fmri;
12169 	scf_property_t *prop;
12170 	scf_value_t *val;
12171 	scf_iter_t *iter;
12172 	int r;
12173 	scf_error_t err;
12174 
12175 	/* Verify that the pg has the correct type. */
12176 	pgty = safe_malloc(max_scf_pg_type_len + 1);
12177 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
12178 		scfdie();
12179 
12180 	if (strcmp(pgty, scf_group_framework) != 0) {
12181 		if (g_verbose) {
12182 			fmri = safe_malloc(max_scf_fmri_len + 1);
12183 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
12184 				scfdie();
12185 
12186 			warn(gettext("Property group %s is not of expected "
12187 			    "type %s.\n"), fmri, scf_group_framework);
12188 
12189 			free(fmri);
12190 		}
12191 
12192 		free(pgty);
12193 		return (-1);
12194 	}
12195 
12196 	free(pgty);
12197 
12198 	/* map delete_dependency_pg onto the properties. */
12199 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12200 	    (val = scf_value_create(g_hndl)) == NULL ||
12201 	    (iter = scf_iter_create(g_hndl)) == NULL)
12202 		scfdie();
12203 
12204 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
12205 		scfdie();
12206 
12207 	name = safe_malloc(max_scf_name_len + 1);
12208 	fmri = safe_malloc(max_scf_fmri_len + 2);
12209 
12210 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
12211 		scf_type_t ty;
12212 
12213 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
12214 			scfdie();
12215 
12216 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
12217 			scfdie();
12218 
12219 		if ((ty != SCF_TYPE_ASTRING &&
12220 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
12221 		    prop_get_val(prop, val) != 0)
12222 			continue;
12223 
12224 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
12225 			scfdie();
12226 
12227 		err = delete_dependency_pg(fmri, name);
12228 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
12229 			if (scf_property_to_fmri(prop, fmri,
12230 			    max_scf_fmri_len + 2) < 0)
12231 				scfdie();
12232 
12233 			warn(gettext("Value of %s is not a valid FMRI.\n"),
12234 			    fmri);
12235 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
12236 			warn(gettext("Property group \"%s\" of entity \"%s\" "
12237 			    "does not have dependency type.\n"), name, fmri);
12238 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
12239 			warn(gettext("Could not delete property group \"%s\" "
12240 			    "of entity \"%s\" (permission denied).\n"), name,
12241 			    fmri);
12242 		}
12243 	}
12244 	if (r == -1)
12245 		scfdie();
12246 
12247 	scf_value_destroy(val);
12248 	scf_property_destroy(prop);
12249 
12250 	return (0);
12251 }
12252 
12253 /*
12254  * Returns 1 if the instance may be running, and 0 otherwise.
12255  */
12256 static int
12257 inst_is_running(scf_instance_t *inst)
12258 {
12259 	scf_propertygroup_t *pg;
12260 	scf_property_t *prop;
12261 	scf_value_t *val;
12262 	char buf[MAX_SCF_STATE_STRING_SZ];
12263 	int ret = 0;
12264 	ssize_t szret;
12265 
12266 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12267 	    (prop = scf_property_create(g_hndl)) == NULL ||
12268 	    (val = scf_value_create(g_hndl)) == NULL)
12269 		scfdie();
12270 
12271 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12272 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12273 			scfdie();
12274 		goto out;
12275 	}
12276 
12277 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12278 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12279 	    prop_get_val(prop, val) != 0)
12280 		goto out;
12281 
12282 	szret = scf_value_get_astring(val, buf, sizeof (buf));
12283 	assert(szret >= 0);
12284 
12285 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12286 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12287 
12288 out:
12289 	scf_value_destroy(val);
12290 	scf_property_destroy(prop);
12291 	scf_pg_destroy(pg);
12292 	return (ret);
12293 }
12294 
12295 static uint8_t
12296 pg_is_external_dependency(scf_propertygroup_t *pg)
12297 {
12298 	char *type;
12299 	scf_value_t *val;
12300 	scf_property_t *prop;
12301 	uint8_t b = B_FALSE;
12302 
12303 	type = safe_malloc(max_scf_pg_type_len + 1);
12304 
12305 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12306 		scfdie();
12307 
12308 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12309 	    (val = scf_value_create(g_hndl)) == NULL)
12310 		scfdie();
12311 
12312 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12313 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12314 			if (scf_property_get_value(prop, val) != 0)
12315 				scfdie();
12316 			if (scf_value_get_boolean(val, &b) != 0)
12317 				scfdie();
12318 		}
12319 	}
12320 
12321 	free(type);
12322 	(void) scf_value_destroy(val);
12323 	(void) scf_property_destroy(prop);
12324 
12325 	return (b);
12326 }
12327 
12328 #define	DELETE_FAILURE			-1
12329 #define	DELETE_SUCCESS_NOEXTDEPS	0
12330 #define	DELETE_SUCCESS_EXTDEPS		1
12331 
12332 /*
12333  * lscf_instance_delete() deletes an instance.  Before calling
12334  * scf_instance_delete(), though, we make sure the instance isn't
12335  * running and delete dependencies in other entities which the instance
12336  * declared as "dependents".  If there are dependencies which were
12337  * created for other entities, then instead of deleting the instance we
12338  * make it "empty" by deleting all other property groups and all
12339  * snapshots.
12340  *
12341  * lscf_instance_delete() verifies that there is no external dependency pgs
12342  * before suppressing the instance. If there is, then we must not remove them
12343  * now in case the instance is re-created otherwise the dependencies would be
12344  * lost. The external dependency pgs will be removed if the dependencies are
12345  * removed.
12346  *
12347  * Returns:
12348  *  DELETE_FAILURE		on failure
12349  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12350  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12351  */
12352 static int
12353 lscf_instance_delete(scf_instance_t *inst, int force)
12354 {
12355 	scf_propertygroup_t *pg;
12356 	scf_snapshot_t *snap;
12357 	scf_iter_t *iter;
12358 	int err;
12359 	int external = 0;
12360 
12361 	/* If we're not forcing and the instance is running, refuse. */
12362 	if (!force && inst_is_running(inst)) {
12363 		char *fmri;
12364 
12365 		fmri = safe_malloc(max_scf_fmri_len + 1);
12366 
12367 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12368 			scfdie();
12369 
12370 		semerr(gettext("Instance %s may be running.  "
12371 		    "Use delete -f if it is not.\n"), fmri);
12372 
12373 		free(fmri);
12374 		return (DELETE_FAILURE);
12375 	}
12376 
12377 	pg = scf_pg_create(g_hndl);
12378 	if (pg == NULL)
12379 		scfdie();
12380 
12381 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12382 		(void) delete_dependents(pg);
12383 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12384 		scfdie();
12385 
12386 	scf_pg_destroy(pg);
12387 
12388 	/*
12389 	 * If the instance has some external dependencies then we must
12390 	 * keep them in case the instance is reimported otherwise the
12391 	 * dependencies would be lost on reimport.
12392 	 */
12393 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12394 	    (pg = scf_pg_create(g_hndl)) == NULL)
12395 		scfdie();
12396 
12397 	if (scf_iter_instance_pgs(iter, inst) < 0)
12398 		scfdie();
12399 
12400 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12401 		if (pg_is_external_dependency(pg)) {
12402 			external = 1;
12403 			continue;
12404 		}
12405 
12406 		if (scf_pg_delete(pg) != 0) {
12407 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12408 				scfdie();
12409 			else {
12410 				semerr(emsg_permission_denied);
12411 
12412 				(void) scf_iter_destroy(iter);
12413 				(void) scf_pg_destroy(pg);
12414 				return (DELETE_FAILURE);
12415 			}
12416 		}
12417 	}
12418 
12419 	if (err == -1)
12420 		scfdie();
12421 
12422 	(void) scf_iter_destroy(iter);
12423 	(void) scf_pg_destroy(pg);
12424 
12425 	if (external) {
12426 		/*
12427 		 * All the pgs have been deleted for the instance except
12428 		 * the ones holding the external dependencies.
12429 		 * For the job to be complete, we must also delete the
12430 		 * snapshots associated with the instance.
12431 		 */
12432 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12433 		    NULL)
12434 			scfdie();
12435 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12436 			scfdie();
12437 
12438 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12439 			scfdie();
12440 
12441 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12442 			if (_scf_snapshot_delete(snap) != 0) {
12443 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12444 					scfdie();
12445 
12446 				semerr(emsg_permission_denied);
12447 
12448 				(void) scf_iter_destroy(iter);
12449 				(void) scf_snapshot_destroy(snap);
12450 				return (DELETE_FAILURE);
12451 			}
12452 		}
12453 
12454 		if (err == -1)
12455 			scfdie();
12456 
12457 		(void) scf_iter_destroy(iter);
12458 		(void) scf_snapshot_destroy(snap);
12459 		return (DELETE_SUCCESS_EXTDEPS);
12460 	}
12461 
12462 	if (scf_instance_delete(inst) != 0) {
12463 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12464 			scfdie();
12465 
12466 		semerr(emsg_permission_denied);
12467 
12468 		return (DELETE_FAILURE);
12469 	}
12470 
12471 	return (DELETE_SUCCESS_NOEXTDEPS);
12472 }
12473 
12474 /*
12475  * lscf_service_delete() deletes a service.  Before calling
12476  * scf_service_delete(), though, we call lscf_instance_delete() for
12477  * each of the instances and delete dependencies in other entities
12478  * which were created as "dependents" of this service.  If there are
12479  * dependencies which were created for other entities, then we delete
12480  * all other property groups in the service and leave it as "empty".
12481  *
12482  * lscf_service_delete() verifies that there is no external dependency
12483  * pgs at the instance & service level before suppressing the service.
12484  * If there is, then we must not remove them now in case the service
12485  * is re-imported otherwise the dependencies would be lost. The external
12486  * dependency pgs will be removed if the dependencies are removed.
12487  *
12488  * Returns:
12489  *   DELETE_FAILURE		on failure
12490  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12491  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12492  */
12493 static int
12494 lscf_service_delete(scf_service_t *svc, int force)
12495 {
12496 	int r;
12497 	scf_instance_t *inst;
12498 	scf_propertygroup_t *pg;
12499 	scf_iter_t *iter;
12500 	int ret;
12501 	int external = 0;
12502 
12503 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12504 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12505 	    (iter = scf_iter_create(g_hndl)) == NULL)
12506 		scfdie();
12507 
12508 	if (scf_iter_service_instances(iter, svc) != 0)
12509 		scfdie();
12510 
12511 	for (r = scf_iter_next_instance(iter, inst);
12512 	    r == 1;
12513 	    r = scf_iter_next_instance(iter, inst)) {
12514 
12515 		ret = lscf_instance_delete(inst, force);
12516 		if (ret == DELETE_FAILURE) {
12517 			scf_iter_destroy(iter);
12518 			scf_pg_destroy(pg);
12519 			scf_instance_destroy(inst);
12520 			return (DELETE_FAILURE);
12521 		}
12522 
12523 		/*
12524 		 * Record the fact that there is some external dependencies
12525 		 * at the instance level.
12526 		 */
12527 		if (ret == DELETE_SUCCESS_EXTDEPS)
12528 			external |= 1;
12529 	}
12530 
12531 	if (r != 0)
12532 		scfdie();
12533 
12534 	/* Delete dependency property groups in dependent services. */
12535 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12536 		(void) delete_dependents(pg);
12537 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12538 		scfdie();
12539 
12540 	scf_iter_destroy(iter);
12541 	scf_pg_destroy(pg);
12542 	scf_instance_destroy(inst);
12543 
12544 	/*
12545 	 * If the service has some external dependencies then we don't
12546 	 * want to remove them in case the service is re-imported.
12547 	 */
12548 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12549 	    (iter = scf_iter_create(g_hndl)) == NULL)
12550 		scfdie();
12551 
12552 	if (scf_iter_service_pgs(iter, svc) < 0)
12553 		scfdie();
12554 
12555 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12556 		if (pg_is_external_dependency(pg)) {
12557 			external |= 2;
12558 			continue;
12559 		}
12560 
12561 		if (scf_pg_delete(pg) != 0) {
12562 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12563 				scfdie();
12564 			else {
12565 				semerr(emsg_permission_denied);
12566 
12567 				(void) scf_iter_destroy(iter);
12568 				(void) scf_pg_destroy(pg);
12569 				return (DELETE_FAILURE);
12570 			}
12571 		}
12572 	}
12573 
12574 	if (r == -1)
12575 		scfdie();
12576 
12577 	(void) scf_iter_destroy(iter);
12578 	(void) scf_pg_destroy(pg);
12579 
12580 	if (external != 0)
12581 		return (DELETE_SUCCESS_EXTDEPS);
12582 
12583 	if (scf_service_delete(svc) == 0)
12584 		return (DELETE_SUCCESS_NOEXTDEPS);
12585 
12586 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12587 		scfdie();
12588 
12589 	semerr(emsg_permission_denied);
12590 	return (DELETE_FAILURE);
12591 }
12592 
12593 static int
12594 delete_callback(void *data, scf_walkinfo_t *wip)
12595 {
12596 	int force = (int)data;
12597 
12598 	if (wip->inst != NULL)
12599 		(void) lscf_instance_delete(wip->inst, force);
12600 	else
12601 		(void) lscf_service_delete(wip->svc, force);
12602 
12603 	return (0);
12604 }
12605 
12606 void
12607 lscf_delete(const char *fmri, int force)
12608 {
12609 	scf_service_t *svc;
12610 	scf_instance_t *inst;
12611 	int ret;
12612 
12613 	lscf_prep_hndl();
12614 
12615 	if (cur_snap != NULL) {
12616 		if (!snaplevel_is_instance(cur_level)) {
12617 			char *buf;
12618 
12619 			buf = safe_malloc(max_scf_name_len + 1);
12620 			if (scf_instance_get_name(cur_inst, buf,
12621 			    max_scf_name_len + 1) >= 0) {
12622 				if (strcmp(buf, fmri) == 0) {
12623 					semerr(emsg_cant_modify_snapshots);
12624 					free(buf);
12625 					return;
12626 				}
12627 			} else if (scf_error() != SCF_ERROR_DELETED) {
12628 				scfdie();
12629 			}
12630 			free(buf);
12631 		}
12632 	} else if (cur_inst != NULL) {
12633 		/* EMPTY */;
12634 	} else if (cur_svc != NULL) {
12635 		inst = scf_instance_create(g_hndl);
12636 		if (inst == NULL)
12637 			scfdie();
12638 
12639 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12640 		    SCF_SUCCESS) {
12641 			(void) lscf_instance_delete(inst, force);
12642 			scf_instance_destroy(inst);
12643 			return;
12644 		}
12645 
12646 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12647 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12648 			scfdie();
12649 
12650 		scf_instance_destroy(inst);
12651 	} else {
12652 		assert(cur_scope != NULL);
12653 
12654 		svc = scf_service_create(g_hndl);
12655 		if (svc == NULL)
12656 			scfdie();
12657 
12658 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12659 		    SCF_SUCCESS) {
12660 			(void) lscf_service_delete(svc, force);
12661 			scf_service_destroy(svc);
12662 			return;
12663 		}
12664 
12665 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12666 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12667 			scfdie();
12668 
12669 		scf_service_destroy(svc);
12670 	}
12671 
12672 	/*
12673 	 * Match FMRI to entity.
12674 	 */
12675 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12676 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12677 		semerr(gettext("Failed to walk instances: %s\n"),
12678 		    scf_strerror(ret));
12679 	}
12680 }
12681 
12682 
12683 
12684 /*
12685  * :properties commands.  These all end with "pg" or "prop" and generally
12686  * operate on the currently selected entity.
12687  */
12688 
12689 /*
12690  * Property listing.  List the property groups, properties, their types and
12691  * their values for the currently selected entity.
12692  */
12693 static void
12694 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12695 {
12696 	char *buf;
12697 	uint32_t flags;
12698 
12699 	buf = safe_malloc(max_scf_pg_type_len + 1);
12700 
12701 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12702 		scfdie();
12703 
12704 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12705 		scfdie();
12706 
12707 	safe_printf("%-*s  %s", namewidth, name, buf);
12708 
12709 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12710 		safe_printf("\tNONPERSISTENT");
12711 
12712 	safe_printf("\n");
12713 
12714 	free(buf);
12715 }
12716 
12717 static boolean_t
12718 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12719 {
12720 	if (scf_property_get_value(prop, val) == 0) {
12721 		return (B_FALSE);
12722 	} else {
12723 		switch (scf_error()) {
12724 		case SCF_ERROR_NOT_FOUND:
12725 			return (B_FALSE);
12726 		case SCF_ERROR_PERMISSION_DENIED:
12727 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12728 			return (B_TRUE);
12729 		default:
12730 			scfdie();
12731 			/*NOTREACHED*/
12732 		}
12733 	}
12734 }
12735 
12736 static void
12737 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12738 {
12739 	scf_iter_t *iter;
12740 	scf_value_t *val;
12741 	const char *type;
12742 	int multiple_strings = 0;
12743 	int ret;
12744 
12745 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12746 	    (val = scf_value_create(g_hndl)) == NULL)
12747 		scfdie();
12748 
12749 	type = prop_to_typestr(prop);
12750 	assert(type != NULL);
12751 
12752 	safe_printf("%-*s  %-7s ", len, name, type);
12753 
12754 	if (prop_has_multiple_values(prop, val) &&
12755 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12756 	    scf_value_type(val) == SCF_TYPE_USTRING))
12757 		multiple_strings = 1;
12758 
12759 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12760 		scfdie();
12761 
12762 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12763 		char *buf;
12764 		ssize_t vlen, szret;
12765 
12766 		vlen = scf_value_get_as_string(val, NULL, 0);
12767 		if (vlen < 0)
12768 			scfdie();
12769 
12770 		buf = safe_malloc(vlen + 1);
12771 
12772 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12773 		if (szret < 0)
12774 			scfdie();
12775 		assert(szret <= vlen);
12776 
12777 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12778 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12779 			safe_printf(" \"");
12780 			(void) quote_and_print(buf, stdout, 0);
12781 			(void) putchar('"');
12782 			if (ferror(stdout)) {
12783 				(void) putchar('\n');
12784 				uu_die(gettext("Error writing to stdout.\n"));
12785 			}
12786 		} else {
12787 			safe_printf(" %s", buf);
12788 		}
12789 
12790 		free(buf);
12791 	}
12792 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12793 		scfdie();
12794 
12795 	if (putchar('\n') != '\n')
12796 		uu_die(gettext("Could not output newline"));
12797 }
12798 
12799 /*
12800  * Outputs template property group info for the describe subcommand.
12801  * If 'templates' == 2, verbose output is printed in the format expected
12802  * for describe -v, which includes all templates fields.  If pg is
12803  * not NULL, we're describing the template data, not an existing property
12804  * group, and formatting should be appropriate for describe -t.
12805  */
12806 static void
12807 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12808 {
12809 	char *buf;
12810 	uint8_t required;
12811 	scf_property_t *stability_prop;
12812 	scf_value_t *stability_val;
12813 
12814 	if (templates == 0)
12815 		return;
12816 
12817 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12818 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12819 		scfdie();
12820 
12821 	if (templates == 2 && pg != NULL) {
12822 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12823 		    stability_prop) == 0) {
12824 			if (prop_check_type(stability_prop,
12825 			    SCF_TYPE_ASTRING) == 0 &&
12826 			    prop_get_val(stability_prop, stability_val) == 0) {
12827 				char *stability;
12828 
12829 				stability = safe_malloc(max_scf_value_len + 1);
12830 
12831 				if (scf_value_get_astring(stability_val,
12832 				    stability, max_scf_value_len + 1) == -1 &&
12833 				    scf_error() != SCF_ERROR_NOT_FOUND)
12834 					scfdie();
12835 
12836 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12837 				    gettext("stability"), stability);
12838 
12839 				free(stability);
12840 			}
12841 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12842 			scfdie();
12843 	}
12844 
12845 	scf_property_destroy(stability_prop);
12846 	scf_value_destroy(stability_val);
12847 
12848 	if (pgt == NULL)
12849 		return;
12850 
12851 	if (pg == NULL || templates == 2) {
12852 		/* print type info only if scf_tmpl_pg_name succeeds */
12853 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12854 			if (pg != NULL)
12855 				safe_printf("%s", TMPL_INDENT);
12856 			safe_printf("%s: ", gettext("name"));
12857 			safe_printf("%s\n", buf);
12858 			free(buf);
12859 		}
12860 
12861 		/* print type info only if scf_tmpl_pg_type succeeds */
12862 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12863 			if (pg != NULL)
12864 				safe_printf("%s", TMPL_INDENT);
12865 			safe_printf("%s: ", gettext("type"));
12866 			safe_printf("%s\n", buf);
12867 			free(buf);
12868 		}
12869 	}
12870 
12871 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12872 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12873 		    required ? "true" : "false");
12874 
12875 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12876 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12877 		    buf);
12878 		free(buf);
12879 	}
12880 
12881 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12882 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12883 		    buf);
12884 		free(buf);
12885 	}
12886 
12887 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12888 		if (templates == 2)
12889 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12890 			    gettext("description"), buf);
12891 		else
12892 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12893 		free(buf);
12894 	}
12895 
12896 }
12897 
12898 /*
12899  * With as_value set to true, indent as appropriate for the value level.
12900  * If false, indent to appropriate level for inclusion in constraint
12901  * or choice printout.
12902  */
12903 static void
12904 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12905     int as_value)
12906 {
12907 	char *buf;
12908 
12909 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12910 		if (as_value == 0)
12911 			safe_printf("%s", TMPL_CHOICE_INDENT);
12912 		else
12913 			safe_printf("%s", TMPL_INDENT);
12914 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12915 		free(buf);
12916 	}
12917 
12918 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12919 		if (as_value == 0)
12920 			safe_printf("%s", TMPL_CHOICE_INDENT);
12921 		else
12922 			safe_printf("%s", TMPL_INDENT);
12923 		safe_printf("%s: %s\n", gettext("value description"), buf);
12924 		free(buf);
12925 	}
12926 }
12927 
12928 static void
12929 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12930 {
12931 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12932 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12933 	safe_printf("%s\n", val_buf);
12934 
12935 	print_template_value_details(prt, val_buf, 1);
12936 }
12937 
12938 static void
12939 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12940 {
12941 	int i, printed = 0;
12942 	scf_values_t values;
12943 	scf_count_ranges_t c_ranges;
12944 	scf_int_ranges_t i_ranges;
12945 
12946 	printed = 0;
12947 	i = 0;
12948 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12949 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12950 		    gettext("value constraints"));
12951 		printed++;
12952 		for (i = 0; i < values.value_count; ++i) {
12953 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12954 			    gettext("value name"), values.values_as_strings[i]);
12955 			if (verbose == 1)
12956 				print_template_value_details(prt,
12957 				    values.values_as_strings[i], 0);
12958 		}
12959 
12960 		scf_values_destroy(&values);
12961 	}
12962 
12963 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12964 		if (printed++ == 0)
12965 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12966 			    gettext("value constraints"));
12967 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12968 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12969 			    gettext("range"), c_ranges.scr_min[i],
12970 			    c_ranges.scr_max[i]);
12971 		}
12972 		scf_count_ranges_destroy(&c_ranges);
12973 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12974 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12975 		if (printed++ == 0)
12976 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12977 			    gettext("value constraints"));
12978 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12979 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12980 			    gettext("range"), i_ranges.sir_min[i],
12981 			    i_ranges.sir_max[i]);
12982 		}
12983 		scf_int_ranges_destroy(&i_ranges);
12984 	}
12985 }
12986 
12987 static void
12988 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12989 {
12990 	int i = 0, printed = 0;
12991 	scf_values_t values;
12992 	scf_count_ranges_t c_ranges;
12993 	scf_int_ranges_t i_ranges;
12994 
12995 	printed = 0;
12996 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12997 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12998 		    gettext("value constraints"));
12999 		printed++;
13000 		for (i = 0; i < values.value_count; i++) {
13001 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13002 			    gettext("value name"), values.values_as_strings[i]);
13003 			if (verbose == 1)
13004 				print_template_value_details(prt,
13005 				    values.values_as_strings[i], 0);
13006 		}
13007 
13008 		scf_values_destroy(&values);
13009 	}
13010 
13011 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
13012 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
13013 			if (printed++ == 0)
13014 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
13015 				    gettext("value choices"));
13016 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
13017 			    gettext("range"), c_ranges.scr_min[i],
13018 			    c_ranges.scr_max[i]);
13019 		}
13020 		scf_count_ranges_destroy(&c_ranges);
13021 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
13022 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
13023 		for (i = 0; i < i_ranges.sir_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: %lld to %lld\n", TMPL_INDENT,
13028 			    gettext("range"), i_ranges.sir_min[i],
13029 			    i_ranges.sir_max[i]);
13030 		}
13031 		scf_int_ranges_destroy(&i_ranges);
13032 	}
13033 }
13034 
13035 static void
13036 list_values_by_template(scf_prop_tmpl_t *prt)
13037 {
13038 	print_template_constraints(prt, 1);
13039 	print_template_choices(prt, 1);
13040 }
13041 
13042 static void
13043 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
13044 {
13045 	char *val_buf;
13046 	scf_iter_t *iter;
13047 	scf_value_t *val;
13048 	int ret;
13049 
13050 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13051 	    (val = scf_value_create(g_hndl)) == NULL)
13052 		scfdie();
13053 
13054 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
13055 		scfdie();
13056 
13057 	val_buf = safe_malloc(max_scf_value_len + 1);
13058 
13059 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
13060 		if (scf_value_get_as_string(val, val_buf,
13061 		    max_scf_value_len + 1) < 0)
13062 			scfdie();
13063 
13064 		print_template_value(prt, val_buf);
13065 	}
13066 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13067 		scfdie();
13068 	free(val_buf);
13069 
13070 	print_template_constraints(prt, 0);
13071 	print_template_choices(prt, 0);
13072 
13073 }
13074 
13075 /*
13076  * Outputs property info for the describe subcommand
13077  * Verbose output if templates == 2, -v option of svccfg describe
13078  * Displays template data if prop is not NULL, -t option of svccfg describe
13079  */
13080 static void
13081 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
13082 {
13083 	char *buf;
13084 	uint8_t u_buf;
13085 	int i;
13086 	uint64_t min, max;
13087 	scf_values_t values;
13088 
13089 	if (prt == NULL || templates == 0)
13090 		return;
13091 
13092 	if (prop == NULL) {
13093 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
13094 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
13095 			safe_printf("%s\n", buf);
13096 			free(buf);
13097 		} else
13098 			safe_printf("(%s)\n", gettext("any"));
13099 	}
13100 
13101 	if (prop == NULL || templates == 2) {
13102 		if (prop != NULL)
13103 			safe_printf("%s", TMPL_INDENT);
13104 		else
13105 			safe_printf("%s", TMPL_VALUE_INDENT);
13106 		safe_printf("%s: ", gettext("type"));
13107 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
13108 			safe_printf("%s\n", buf);
13109 			free(buf);
13110 		} else
13111 			safe_printf("(%s)\n", gettext("any"));
13112 	}
13113 
13114 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
13115 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
13116 		    u_buf ? "true" : "false");
13117 
13118 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
13119 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
13120 		    buf);
13121 		free(buf);
13122 	}
13123 
13124 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
13125 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
13126 		    buf);
13127 		free(buf);
13128 	}
13129 
13130 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
13131 		safe_printf("%s%s\n", TMPL_INDENT, buf);
13132 		free(buf);
13133 	}
13134 
13135 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
13136 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
13137 		    scf_tmpl_visibility_to_string(u_buf));
13138 
13139 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
13140 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13141 		    gettext("minimum number of values"), min);
13142 		if (max == ULLONG_MAX) {
13143 			safe_printf("%s%s: %s\n", TMPL_INDENT,
13144 			    gettext("maximum number of values"),
13145 			    gettext("unlimited"));
13146 		} else {
13147 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
13148 			    gettext("maximum number of values"), max);
13149 		}
13150 	}
13151 
13152 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
13153 		for (i = 0; i < values.value_count; i++) {
13154 			if (i == 0) {
13155 				safe_printf("%s%s:", TMPL_INDENT,
13156 				    gettext("internal separators"));
13157 			}
13158 			safe_printf(" \"%s\"", values.values_as_strings[i]);
13159 		}
13160 		safe_printf("\n");
13161 	}
13162 
13163 	if (templates != 2)
13164 		return;
13165 
13166 	if (prop != NULL)
13167 		list_values_tmpl(prt, prop);
13168 	else
13169 		list_values_by_template(prt);
13170 }
13171 
13172 static char *
13173 read_astring(scf_propertygroup_t *pg, const char *prop_name)
13174 {
13175 	char *rv;
13176 
13177 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
13178 	if (rv == NULL) {
13179 		switch (scf_error()) {
13180 		case SCF_ERROR_NOT_FOUND:
13181 			break;
13182 		default:
13183 			scfdie();
13184 		}
13185 	}
13186 	return (rv);
13187 }
13188 
13189 static void
13190 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
13191 {
13192 	size_t doc_len;
13193 	size_t man_len;
13194 	char *pg_name;
13195 	char *text = NULL;
13196 	int rv;
13197 
13198 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
13199 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
13200 	pg_name = safe_malloc(max_scf_name_len + 1);
13201 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
13202 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
13203 			scfdie();
13204 		}
13205 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
13206 			/* Display doc_link and and uri */
13207 			safe_printf("%s%s:\n", TMPL_INDENT,
13208 			    gettext("doc_link"));
13209 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
13210 			if (text != NULL) {
13211 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13212 				    TMPL_INDENT, gettext("name"), text);
13213 				uu_free(text);
13214 			}
13215 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
13216 			if (text != NULL) {
13217 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
13218 				    gettext("uri"), text);
13219 				uu_free(text);
13220 			}
13221 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
13222 		    man_len) == 0) {
13223 			/* Display manpage title, section and path */
13224 			safe_printf("%s%s:\n", TMPL_INDENT,
13225 			    gettext("manpage"));
13226 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
13227 			if (text != NULL) {
13228 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13229 				    TMPL_INDENT, gettext("title"), text);
13230 				uu_free(text);
13231 			}
13232 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
13233 			if (text != NULL) {
13234 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13235 				    TMPL_INDENT, gettext("section"), text);
13236 				uu_free(text);
13237 			}
13238 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
13239 			if (text != NULL) {
13240 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
13241 				    TMPL_INDENT, gettext("manpath"), text);
13242 				uu_free(text);
13243 			}
13244 		}
13245 	}
13246 	if (rv == -1)
13247 		scfdie();
13248 
13249 done:
13250 	free(pg_name);
13251 }
13252 
13253 static void
13254 list_entity_tmpl(int templates)
13255 {
13256 	char *common_name = NULL;
13257 	char *description = NULL;
13258 	char *locale = NULL;
13259 	scf_iter_t *iter;
13260 	scf_propertygroup_t *pg;
13261 	scf_property_t *prop;
13262 	int r;
13263 	scf_value_t *val;
13264 
13265 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13266 	    (prop = scf_property_create(g_hndl)) == NULL ||
13267 	    (val = scf_value_create(g_hndl)) == NULL ||
13268 	    (iter = scf_iter_create(g_hndl)) == NULL)
13269 		scfdie();
13270 
13271 	locale = setlocale(LC_MESSAGES, NULL);
13272 
13273 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13274 		common_name = safe_malloc(max_scf_value_len + 1);
13275 
13276 		/* Try both the current locale and the "C" locale. */
13277 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
13278 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
13279 		    scf_pg_get_property(pg, "C", prop) == 0)) {
13280 			if (prop_get_val(prop, val) == 0 &&
13281 			    scf_value_get_ustring(val, common_name,
13282 			    max_scf_value_len + 1) != -1) {
13283 				safe_printf("%s%s: %s\n", TMPL_INDENT,
13284 				    gettext("common name"), common_name);
13285 			}
13286 		}
13287 	}
13288 
13289 	/*
13290 	 * Do description, manpages, and doc links if templates == 2.
13291 	 */
13292 	if (templates == 2) {
13293 		/* Get the description. */
13294 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13295 			description = safe_malloc(max_scf_value_len + 1);
13296 
13297 			/* Try both the current locale and the "C" locale. */
13298 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
13299 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
13300 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13301 				if (prop_get_val(prop, val) == 0 &&
13302 				    scf_value_get_ustring(val, description,
13303 				    max_scf_value_len + 1) != -1) {
13304 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13305 					    gettext("description"),
13306 					    description);
13307 				}
13308 			}
13309 		}
13310 
13311 		/* Process doc_link & manpage elements. */
13312 		if (cur_level != NULL) {
13313 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13314 			    SCF_GROUP_TEMPLATE);
13315 		} else if (cur_inst != NULL) {
13316 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13317 			    SCF_GROUP_TEMPLATE);
13318 		} else {
13319 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13320 			    SCF_GROUP_TEMPLATE);
13321 		}
13322 		if (r == 0) {
13323 			display_documentation(iter, pg);
13324 		}
13325 	}
13326 
13327 	free(common_name);
13328 	free(description);
13329 	scf_pg_destroy(pg);
13330 	scf_property_destroy(prop);
13331 	scf_value_destroy(val);
13332 	scf_iter_destroy(iter);
13333 }
13334 
13335 static void
13336 listtmpl(const char *pattern, int templates)
13337 {
13338 	scf_pg_tmpl_t *pgt;
13339 	scf_prop_tmpl_t *prt;
13340 	char *snapbuf = NULL;
13341 	char *fmribuf;
13342 	char *pg_name = NULL, *prop_name = NULL;
13343 	ssize_t prop_name_size;
13344 	char *qual_prop_name;
13345 	char *search_name;
13346 	int listed = 0;
13347 
13348 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13349 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13350 		scfdie();
13351 
13352 	fmribuf = safe_malloc(max_scf_name_len + 1);
13353 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13354 
13355 	if (cur_snap != NULL) {
13356 		snapbuf = safe_malloc(max_scf_name_len + 1);
13357 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13358 		    max_scf_name_len + 1) < 0)
13359 			scfdie();
13360 	}
13361 
13362 	if (cur_inst != NULL) {
13363 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13364 		    max_scf_name_len + 1) < 0)
13365 			scfdie();
13366 	} else if (cur_svc != NULL) {
13367 		if (scf_service_to_fmri(cur_svc, fmribuf,
13368 		    max_scf_name_len + 1) < 0)
13369 			scfdie();
13370 	} else
13371 		abort();
13372 
13373 	/* If pattern is specified, we want to list only those items. */
13374 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13375 		listed = 0;
13376 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13377 		    fnmatch(pattern, pg_name, 0) == 0)) {
13378 			list_pg_tmpl(pgt, NULL, templates);
13379 			listed++;
13380 		}
13381 
13382 		scf_tmpl_prop_reset(prt);
13383 
13384 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13385 			search_name = NULL;
13386 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13387 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13388 				if (snprintf(qual_prop_name,
13389 				    max_scf_name_len + 1, "%s/%s",
13390 				    pg_name, prop_name) >=
13391 				    max_scf_name_len + 1) {
13392 					prop_name_size = -1;
13393 				} else {
13394 					search_name = qual_prop_name;
13395 				}
13396 			}
13397 			if (listed > 0 || pattern == NULL ||
13398 			    (prop_name_size > 0 &&
13399 			    fnmatch(pattern, search_name,
13400 			    FNM_PATHNAME) == 0))
13401 				list_prop_tmpl(prt, NULL, templates);
13402 			if (prop_name != NULL) {
13403 				free(prop_name);
13404 				prop_name = NULL;
13405 			}
13406 		}
13407 		if (pg_name != NULL) {
13408 			free(pg_name);
13409 			pg_name = NULL;
13410 		}
13411 	}
13412 
13413 	scf_tmpl_prop_destroy(prt);
13414 	scf_tmpl_pg_destroy(pgt);
13415 	free(snapbuf);
13416 	free(fmribuf);
13417 	free(qual_prop_name);
13418 }
13419 
13420 static void
13421 listprop(const char *pattern, int only_pgs, int templates)
13422 {
13423 	scf_propertygroup_t *pg;
13424 	scf_property_t *prop;
13425 	scf_iter_t *iter, *piter;
13426 	char *pgnbuf, *prnbuf, *ppnbuf;
13427 	scf_pg_tmpl_t *pgt, *pgtp;
13428 	scf_prop_tmpl_t *prt;
13429 
13430 	void **objects;
13431 	char **names;
13432 	void **tmpls;
13433 	int allocd, i;
13434 
13435 	int ret;
13436 	ssize_t pgnlen, prnlen, szret;
13437 	size_t max_len = 0;
13438 
13439 	if (cur_svc == NULL && cur_inst == NULL) {
13440 		semerr(emsg_entity_not_selected);
13441 		return;
13442 	}
13443 
13444 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13445 	    (prop = scf_property_create(g_hndl)) == NULL ||
13446 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13447 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13448 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13449 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13450 		scfdie();
13451 
13452 	prnbuf = safe_malloc(max_scf_name_len + 1);
13453 
13454 	if (cur_level != NULL)
13455 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13456 	else if (cur_inst != NULL)
13457 		ret = scf_iter_instance_pgs(iter, cur_inst);
13458 	else
13459 		ret = scf_iter_service_pgs(iter, cur_svc);
13460 	if (ret != 0) {
13461 		return;
13462 	}
13463 
13464 	/*
13465 	 * We want to only list items which match pattern, and we want the
13466 	 * second column to line up, so during the first pass we'll save
13467 	 * matching items, their names, and their templates in objects,
13468 	 * names, and tmpls, computing the maximum name length as we go,
13469 	 * and then we'll print them out.
13470 	 *
13471 	 * Note: We always keep an extra slot available so the array can be
13472 	 * NULL-terminated.
13473 	 */
13474 	i = 0;
13475 	allocd = 1;
13476 	objects = safe_malloc(sizeof (*objects));
13477 	names = safe_malloc(sizeof (*names));
13478 	tmpls = safe_malloc(sizeof (*tmpls));
13479 
13480 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13481 		int new_pg = 0;
13482 		int print_props = 0;
13483 		pgtp = NULL;
13484 
13485 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13486 		if (pgnlen < 0)
13487 			scfdie();
13488 
13489 		pgnbuf = safe_malloc(pgnlen + 1);
13490 
13491 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13492 		if (szret < 0)
13493 			scfdie();
13494 		assert(szret <= pgnlen);
13495 
13496 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13497 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13498 				scfdie();
13499 			pgtp = NULL;
13500 		} else {
13501 			pgtp = pgt;
13502 		}
13503 
13504 		if (pattern == NULL ||
13505 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13506 			if (i+1 >= allocd) {
13507 				allocd *= 2;
13508 				objects = realloc(objects,
13509 				    sizeof (*objects) * allocd);
13510 				names =
13511 				    realloc(names, sizeof (*names) * allocd);
13512 				tmpls = realloc(tmpls,
13513 				    sizeof (*tmpls) * allocd);
13514 				if (objects == NULL || names == NULL ||
13515 				    tmpls == NULL)
13516 					uu_die(gettext("Out of memory"));
13517 			}
13518 			objects[i] = pg;
13519 			names[i] = pgnbuf;
13520 
13521 			if (pgtp == NULL)
13522 				tmpls[i] = NULL;
13523 			else
13524 				tmpls[i] = pgt;
13525 
13526 			++i;
13527 
13528 			if (pgnlen > max_len)
13529 				max_len = pgnlen;
13530 
13531 			new_pg = 1;
13532 			print_props = 1;
13533 		}
13534 
13535 		if (only_pgs) {
13536 			if (new_pg) {
13537 				pg = scf_pg_create(g_hndl);
13538 				if (pg == NULL)
13539 					scfdie();
13540 				pgt = scf_tmpl_pg_create(g_hndl);
13541 				if (pgt == NULL)
13542 					scfdie();
13543 			} else
13544 				free(pgnbuf);
13545 
13546 			continue;
13547 		}
13548 
13549 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13550 			scfdie();
13551 
13552 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13553 			prnlen = scf_property_get_name(prop, prnbuf,
13554 			    max_scf_name_len + 1);
13555 			if (prnlen < 0)
13556 				scfdie();
13557 
13558 			/* Will prepend the property group name and a slash. */
13559 			prnlen += pgnlen + 1;
13560 
13561 			ppnbuf = safe_malloc(prnlen + 1);
13562 
13563 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13564 			    prnbuf) < 0)
13565 				uu_die("snprintf");
13566 
13567 			if (pattern == NULL || print_props == 1 ||
13568 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13569 				if (i+1 >= allocd) {
13570 					allocd *= 2;
13571 					objects = realloc(objects,
13572 					    sizeof (*objects) * allocd);
13573 					names = realloc(names,
13574 					    sizeof (*names) * allocd);
13575 					tmpls = realloc(tmpls,
13576 					    sizeof (*tmpls) * allocd);
13577 					if (objects == NULL || names == NULL ||
13578 					    tmpls == NULL)
13579 						uu_die(gettext(
13580 						    "Out of memory"));
13581 				}
13582 
13583 				objects[i] = prop;
13584 				names[i] = ppnbuf;
13585 
13586 				if (pgtp != NULL) {
13587 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13588 					    prt, 0) < 0) {
13589 						if (scf_error() !=
13590 						    SCF_ERROR_NOT_FOUND)
13591 							scfdie();
13592 						tmpls[i] = NULL;
13593 					} else {
13594 						tmpls[i] = prt;
13595 					}
13596 				} else {
13597 					tmpls[i] = NULL;
13598 				}
13599 
13600 				++i;
13601 
13602 				if (prnlen > max_len)
13603 					max_len = prnlen;
13604 
13605 				prop = scf_property_create(g_hndl);
13606 				prt = scf_tmpl_prop_create(g_hndl);
13607 			} else {
13608 				free(ppnbuf);
13609 			}
13610 		}
13611 
13612 		if (new_pg) {
13613 			pg = scf_pg_create(g_hndl);
13614 			if (pg == NULL)
13615 				scfdie();
13616 			pgt = scf_tmpl_pg_create(g_hndl);
13617 			if (pgt == NULL)
13618 				scfdie();
13619 		} else
13620 			free(pgnbuf);
13621 	}
13622 	if (ret != 0)
13623 		scfdie();
13624 
13625 	objects[i] = NULL;
13626 
13627 	scf_pg_destroy(pg);
13628 	scf_tmpl_pg_destroy(pgt);
13629 	scf_property_destroy(prop);
13630 	scf_tmpl_prop_destroy(prt);
13631 
13632 	for (i = 0; objects[i] != NULL; ++i) {
13633 		if (strchr(names[i], '/') == NULL) {
13634 			/* property group */
13635 			pg = (scf_propertygroup_t *)objects[i];
13636 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13637 			list_pg_info(pg, names[i], max_len);
13638 			list_pg_tmpl(pgt, pg, templates);
13639 			free(names[i]);
13640 			scf_pg_destroy(pg);
13641 			if (pgt != NULL)
13642 				scf_tmpl_pg_destroy(pgt);
13643 		} else {
13644 			/* property */
13645 			prop = (scf_property_t *)objects[i];
13646 			prt = (scf_prop_tmpl_t *)tmpls[i];
13647 			list_prop_info(prop, names[i], max_len);
13648 			list_prop_tmpl(prt, prop, templates);
13649 			free(names[i]);
13650 			scf_property_destroy(prop);
13651 			if (prt != NULL)
13652 				scf_tmpl_prop_destroy(prt);
13653 		}
13654 	}
13655 
13656 	free(names);
13657 	free(objects);
13658 	free(tmpls);
13659 }
13660 
13661 void
13662 lscf_listpg(const char *pattern)
13663 {
13664 	lscf_prep_hndl();
13665 
13666 	listprop(pattern, 1, 0);
13667 }
13668 
13669 /*
13670  * Property group and property creation, setting, and deletion.  setprop (and
13671  * its alias, addprop) can either create a property group of a given type, or
13672  * it can create or set a property to a given type and list of values.
13673  */
13674 void
13675 lscf_addpg(const char *name, const char *type, const char *flags)
13676 {
13677 	scf_propertygroup_t *pg;
13678 	int ret;
13679 	uint32_t flgs = 0;
13680 	const char *cp;
13681 
13682 
13683 	lscf_prep_hndl();
13684 
13685 	if (cur_snap != NULL) {
13686 		semerr(emsg_cant_modify_snapshots);
13687 		return;
13688 	}
13689 
13690 	if (cur_inst == NULL && cur_svc == NULL) {
13691 		semerr(emsg_entity_not_selected);
13692 		return;
13693 	}
13694 
13695 	if (flags != NULL) {
13696 		for (cp = flags; *cp != '\0'; ++cp) {
13697 			switch (*cp) {
13698 			case 'P':
13699 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13700 				break;
13701 
13702 			case 'p':
13703 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13704 				break;
13705 
13706 			default:
13707 				semerr(gettext("Invalid property group flag "
13708 				    "%c."), *cp);
13709 				return;
13710 			}
13711 		}
13712 	}
13713 
13714 	pg = scf_pg_create(g_hndl);
13715 	if (pg == NULL)
13716 		scfdie();
13717 
13718 	if (cur_inst != NULL)
13719 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13720 	else
13721 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13722 
13723 	if (ret != SCF_SUCCESS) {
13724 		switch (scf_error()) {
13725 		case SCF_ERROR_INVALID_ARGUMENT:
13726 			semerr(gettext("Name, type, or flags are invalid.\n"));
13727 			break;
13728 
13729 		case SCF_ERROR_EXISTS:
13730 			semerr(gettext("Property group already exists.\n"));
13731 			break;
13732 
13733 		case SCF_ERROR_PERMISSION_DENIED:
13734 			semerr(emsg_permission_denied);
13735 			break;
13736 
13737 		case SCF_ERROR_BACKEND_ACCESS:
13738 			semerr(gettext("Backend refused access.\n"));
13739 			break;
13740 
13741 		default:
13742 			scfdie();
13743 		}
13744 	}
13745 
13746 	scf_pg_destroy(pg);
13747 
13748 	private_refresh();
13749 }
13750 
13751 void
13752 lscf_delpg(char *name)
13753 {
13754 	lscf_prep_hndl();
13755 
13756 	if (cur_snap != NULL) {
13757 		semerr(emsg_cant_modify_snapshots);
13758 		return;
13759 	}
13760 
13761 	if (cur_inst == NULL && cur_svc == NULL) {
13762 		semerr(emsg_entity_not_selected);
13763 		return;
13764 	}
13765 
13766 	if (strchr(name, '/') != NULL) {
13767 		semerr(emsg_invalid_pg_name, name);
13768 		return;
13769 	}
13770 
13771 	lscf_delprop(name);
13772 }
13773 
13774 /*
13775  * scf_delhash() is used to remove the property group related to the
13776  * hash entry for a specific manifest in the repository. pgname will be
13777  * constructed from the location of the manifest file. If deathrow isn't 0,
13778  * manifest file doesn't need to exist (manifest string will be used as
13779  * an absolute path).
13780  */
13781 void
13782 lscf_delhash(char *manifest, int deathrow)
13783 {
13784 	char *pgname;
13785 
13786 	if (cur_snap != NULL ||
13787 	    cur_inst != NULL || cur_svc != NULL) {
13788 		warn(gettext("error, an entity is selected\n"));
13789 		return;
13790 	}
13791 
13792 	/* select smf/manifest */
13793 	lscf_select(HASH_SVC);
13794 	/*
13795 	 * Translate the manifest file name to property name. In the deathrow
13796 	 * case, the manifest file does not need to exist.
13797 	 */
13798 	pgname = mhash_filename_to_propname(manifest,
13799 	    deathrow ? B_TRUE : B_FALSE);
13800 	if (pgname == NULL) {
13801 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13802 		return;
13803 	}
13804 	/* delete the hash property name */
13805 	lscf_delpg(pgname);
13806 }
13807 
13808 void
13809 lscf_listprop(const char *pattern)
13810 {
13811 	lscf_prep_hndl();
13812 
13813 	listprop(pattern, 0, 0);
13814 }
13815 
13816 int
13817 lscf_setprop(const char *pgname, const char *type, const char *value,
13818     const uu_list_t *values)
13819 {
13820 	scf_type_t ty, current_ty;
13821 	scf_service_t *svc;
13822 	scf_propertygroup_t *pg, *parent_pg;
13823 	scf_property_t *prop, *parent_prop;
13824 	scf_pg_tmpl_t *pgt;
13825 	scf_prop_tmpl_t *prt;
13826 	int ret, result = 0;
13827 	scf_transaction_t *tx;
13828 	scf_transaction_entry_t *e;
13829 	scf_value_t *v;
13830 	uu_list_walk_t *walk;
13831 	string_list_t *sp;
13832 	char *propname;
13833 	int req_quotes = 0;
13834 
13835 	lscf_prep_hndl();
13836 
13837 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13838 	    (svc = scf_service_create(g_hndl)) == NULL ||
13839 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13840 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13841 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13842 	    (prop = scf_property_create(g_hndl)) == NULL ||
13843 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13844 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13845 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13846 		scfdie();
13847 
13848 	if (cur_snap != NULL) {
13849 		semerr(emsg_cant_modify_snapshots);
13850 		goto fail;
13851 	}
13852 
13853 	if (cur_inst == NULL && cur_svc == NULL) {
13854 		semerr(emsg_entity_not_selected);
13855 		goto fail;
13856 	}
13857 
13858 	propname = strchr(pgname, '/');
13859 	if (propname == NULL) {
13860 		semerr(gettext("Property names must contain a `/'.\n"));
13861 		goto fail;
13862 	}
13863 
13864 	*propname = '\0';
13865 	++propname;
13866 
13867 	if (type != NULL) {
13868 		ty = string_to_type(type);
13869 		if (ty == SCF_TYPE_INVALID) {
13870 			semerr(gettext("Unknown type \"%s\".\n"), type);
13871 			goto fail;
13872 		}
13873 	}
13874 
13875 	if (cur_inst != NULL)
13876 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13877 	else
13878 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13879 	if (ret != SCF_SUCCESS) {
13880 		switch (scf_error()) {
13881 		case SCF_ERROR_NOT_FOUND:
13882 			semerr(emsg_no_such_pg, pgname);
13883 			goto fail;
13884 
13885 		case SCF_ERROR_INVALID_ARGUMENT:
13886 			semerr(emsg_invalid_pg_name, pgname);
13887 			goto fail;
13888 
13889 		default:
13890 			scfdie();
13891 			break;
13892 		}
13893 	}
13894 
13895 	do {
13896 		if (scf_pg_update(pg) == -1)
13897 			scfdie();
13898 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13899 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13900 				scfdie();
13901 
13902 			semerr(emsg_permission_denied);
13903 			goto fail;
13904 		}
13905 
13906 		ret = scf_pg_get_property(pg, propname, prop);
13907 		if (ret == SCF_SUCCESS) {
13908 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13909 				scfdie();
13910 
13911 			if (type == NULL)
13912 				ty = current_ty;
13913 			if (scf_transaction_property_change_type(tx, e,
13914 			    propname, ty) == -1)
13915 				scfdie();
13916 
13917 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13918 			/* Infer the type, if possible. */
13919 			if (type == NULL) {
13920 				/*
13921 				 * First check if we're an instance and the
13922 				 * property is set on the service.
13923 				 */
13924 				if (cur_inst != NULL &&
13925 				    scf_instance_get_parent(cur_inst,
13926 				    svc) == 0 &&
13927 				    scf_service_get_pg(cur_svc, pgname,
13928 				    parent_pg) == 0 &&
13929 				    scf_pg_get_property(parent_pg, propname,
13930 				    parent_prop) == 0 &&
13931 				    scf_property_type(parent_prop,
13932 				    &current_ty) == 0) {
13933 					ty = current_ty;
13934 
13935 				/* Then check for a type set in a template. */
13936 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13937 				    0) == 0 &&
13938 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13939 				    0) == 0 &&
13940 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13941 					ty = current_ty;
13942 
13943 				/* If type can't be inferred, fail. */
13944 				} else {
13945 					semerr(gettext("Type required for new "
13946 					    "properties.\n"));
13947 					goto fail;
13948 				}
13949 			}
13950 			if (scf_transaction_property_new(tx, e, propname,
13951 			    ty) == -1)
13952 				scfdie();
13953 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13954 			semerr(emsg_invalid_prop_name, propname);
13955 			goto fail;
13956 		} else {
13957 			scfdie();
13958 		}
13959 
13960 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13961 			req_quotes = 1;
13962 
13963 		if (value != NULL) {
13964 			v = string_to_value(value, ty, 0);
13965 
13966 			if (v == NULL)
13967 				goto fail;
13968 
13969 			ret = scf_entry_add_value(e, v);
13970 			assert(ret == SCF_SUCCESS);
13971 		} else {
13972 			assert(values != NULL);
13973 
13974 			walk = uu_list_walk_start((uu_list_t *)values,
13975 			    UU_DEFAULT);
13976 			if (walk == NULL)
13977 				uu_die(gettext("Could not walk list"));
13978 
13979 			for (sp = uu_list_walk_next(walk); sp != NULL;
13980 			    sp = uu_list_walk_next(walk)) {
13981 				v = string_to_value(sp->str, ty, req_quotes);
13982 
13983 				if (v == NULL) {
13984 					scf_entry_destroy_children(e);
13985 					goto fail;
13986 				}
13987 
13988 				ret = scf_entry_add_value(e, v);
13989 				assert(ret == SCF_SUCCESS);
13990 			}
13991 			uu_list_walk_end(walk);
13992 		}
13993 		result = scf_transaction_commit(tx);
13994 
13995 		scf_transaction_reset(tx);
13996 		scf_entry_destroy_children(e);
13997 	} while (result == 0);
13998 
13999 	if (result < 0) {
14000 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14001 			scfdie();
14002 
14003 		semerr(emsg_permission_denied);
14004 		goto fail;
14005 	}
14006 
14007 	ret = 0;
14008 
14009 	private_refresh();
14010 
14011 	goto cleanup;
14012 
14013 fail:
14014 	ret = -1;
14015 
14016 cleanup:
14017 	scf_transaction_destroy(tx);
14018 	scf_entry_destroy(e);
14019 	scf_service_destroy(svc);
14020 	scf_pg_destroy(parent_pg);
14021 	scf_pg_destroy(pg);
14022 	scf_property_destroy(parent_prop);
14023 	scf_property_destroy(prop);
14024 	scf_tmpl_pg_destroy(pgt);
14025 	scf_tmpl_prop_destroy(prt);
14026 
14027 	return (ret);
14028 }
14029 
14030 void
14031 lscf_delprop(char *pgn)
14032 {
14033 	char *slash, *pn;
14034 	scf_propertygroup_t *pg;
14035 	scf_transaction_t *tx;
14036 	scf_transaction_entry_t *e;
14037 	int ret;
14038 
14039 
14040 	lscf_prep_hndl();
14041 
14042 	if (cur_snap != NULL) {
14043 		semerr(emsg_cant_modify_snapshots);
14044 		return;
14045 	}
14046 
14047 	if (cur_inst == NULL && cur_svc == NULL) {
14048 		semerr(emsg_entity_not_selected);
14049 		return;
14050 	}
14051 
14052 	pg = scf_pg_create(g_hndl);
14053 	if (pg == NULL)
14054 		scfdie();
14055 
14056 	slash = strchr(pgn, '/');
14057 	if (slash == NULL) {
14058 		pn = NULL;
14059 	} else {
14060 		*slash = '\0';
14061 		pn = slash + 1;
14062 	}
14063 
14064 	if (cur_inst != NULL)
14065 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
14066 	else
14067 		ret = scf_service_get_pg(cur_svc, pgn, pg);
14068 	if (ret != SCF_SUCCESS) {
14069 		switch (scf_error()) {
14070 		case SCF_ERROR_NOT_FOUND:
14071 			semerr(emsg_no_such_pg, pgn);
14072 			break;
14073 
14074 		case SCF_ERROR_INVALID_ARGUMENT:
14075 			semerr(emsg_invalid_pg_name, pgn);
14076 			break;
14077 
14078 		default:
14079 			scfdie();
14080 		}
14081 
14082 		scf_pg_destroy(pg);
14083 
14084 		return;
14085 	}
14086 
14087 	if (pn == NULL) {
14088 		/* Try to delete the property group. */
14089 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
14090 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14091 				scfdie();
14092 
14093 			semerr(emsg_permission_denied);
14094 		} else {
14095 			private_refresh();
14096 		}
14097 
14098 		scf_pg_destroy(pg);
14099 		return;
14100 	}
14101 
14102 	e = scf_entry_create(g_hndl);
14103 	tx = scf_transaction_create(g_hndl);
14104 
14105 	do {
14106 		if (scf_pg_update(pg) == -1)
14107 			scfdie();
14108 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
14109 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14110 				scfdie();
14111 
14112 			semerr(emsg_permission_denied);
14113 			break;
14114 		}
14115 
14116 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
14117 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
14118 				semerr(gettext("No such property %s/%s.\n"),
14119 				    pgn, pn);
14120 				break;
14121 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14122 				semerr(emsg_invalid_prop_name, pn);
14123 				break;
14124 			} else {
14125 				scfdie();
14126 			}
14127 		}
14128 
14129 		ret = scf_transaction_commit(tx);
14130 
14131 		if (ret == 0)
14132 			scf_transaction_reset(tx);
14133 	} while (ret == 0);
14134 
14135 	if (ret < 0) {
14136 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14137 			scfdie();
14138 
14139 		semerr(emsg_permission_denied);
14140 	} else {
14141 		private_refresh();
14142 	}
14143 
14144 	scf_transaction_destroy(tx);
14145 	scf_entry_destroy(e);
14146 	scf_pg_destroy(pg);
14147 }
14148 
14149 /*
14150  * Property editing.
14151  */
14152 
14153 static int
14154 write_edit_script(FILE *strm)
14155 {
14156 	char *fmribuf;
14157 	ssize_t fmrilen;
14158 
14159 	scf_propertygroup_t *pg;
14160 	scf_property_t *prop;
14161 	scf_value_t *val;
14162 	scf_type_t ty;
14163 	int ret, result = 0;
14164 	scf_iter_t *iter, *piter, *viter;
14165 	char *buf, *tybuf, *pname;
14166 	const char *emsg_write_error;
14167 
14168 
14169 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
14170 
14171 
14172 	/* select fmri */
14173 	if (cur_inst != NULL) {
14174 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
14175 		if (fmrilen < 0)
14176 			scfdie();
14177 		fmribuf = safe_malloc(fmrilen + 1);
14178 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
14179 			scfdie();
14180 	} else {
14181 		assert(cur_svc != NULL);
14182 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
14183 		if (fmrilen < 0)
14184 			scfdie();
14185 		fmribuf = safe_malloc(fmrilen + 1);
14186 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
14187 			scfdie();
14188 	}
14189 
14190 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
14191 		warn(emsg_write_error, strerror(errno));
14192 		free(fmribuf);
14193 		return (-1);
14194 	}
14195 
14196 	free(fmribuf);
14197 
14198 
14199 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
14200 	    (prop = scf_property_create(g_hndl)) == NULL ||
14201 	    (val = scf_value_create(g_hndl)) == NULL ||
14202 	    (iter = scf_iter_create(g_hndl)) == NULL ||
14203 	    (piter = scf_iter_create(g_hndl)) == NULL ||
14204 	    (viter = scf_iter_create(g_hndl)) == NULL)
14205 		scfdie();
14206 
14207 	buf = safe_malloc(max_scf_name_len + 1);
14208 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
14209 	pname = safe_malloc(max_scf_name_len + 1);
14210 
14211 	if (cur_inst != NULL)
14212 		ret = scf_iter_instance_pgs(iter, cur_inst);
14213 	else
14214 		ret = scf_iter_service_pgs(iter, cur_svc);
14215 	if (ret != SCF_SUCCESS)
14216 		scfdie();
14217 
14218 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
14219 		int ret2;
14220 
14221 		/*
14222 		 * # delprop pg
14223 		 * # addpg pg type
14224 		 */
14225 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
14226 			scfdie();
14227 
14228 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
14229 			scfdie();
14230 
14231 		if (fprintf(strm, "# Property group \"%s\"\n"
14232 		    "# delprop %s\n"
14233 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
14234 			warn(emsg_write_error, strerror(errno));
14235 			result = -1;
14236 			goto out;
14237 		}
14238 
14239 		/* # setprop pg/prop = (values) */
14240 
14241 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
14242 			scfdie();
14243 
14244 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
14245 			int first = 1;
14246 			int ret3;
14247 			int multiple;
14248 			int is_str;
14249 			scf_type_t bty;
14250 
14251 			if (scf_property_get_name(prop, pname,
14252 			    max_scf_name_len + 1) < 0)
14253 				scfdie();
14254 
14255 			if (scf_property_type(prop, &ty) != 0)
14256 				scfdie();
14257 
14258 			multiple = prop_has_multiple_values(prop, val);
14259 
14260 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
14261 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
14262 			    < 0) {
14263 				warn(emsg_write_error, strerror(errno));
14264 				result = -1;
14265 				goto out;
14266 			}
14267 
14268 			(void) scf_type_base_type(ty, &bty);
14269 			is_str = (bty == SCF_TYPE_ASTRING);
14270 
14271 			if (scf_iter_property_values(viter, prop) !=
14272 			    SCF_SUCCESS)
14273 				scfdie();
14274 
14275 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14276 				char *buf;
14277 				ssize_t buflen;
14278 
14279 				buflen = scf_value_get_as_string(val, NULL, 0);
14280 				if (buflen < 0)
14281 					scfdie();
14282 
14283 				buf = safe_malloc(buflen + 1);
14284 
14285 				if (scf_value_get_as_string(val, buf,
14286 				    buflen + 1) < 0)
14287 					scfdie();
14288 
14289 				if (first)
14290 					first = 0;
14291 				else {
14292 					if (putc(' ', strm) != ' ') {
14293 						warn(emsg_write_error,
14294 						    strerror(errno));
14295 						result = -1;
14296 						goto out;
14297 					}
14298 				}
14299 
14300 				if ((is_str && multiple) ||
14301 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14302 					(void) putc('"', strm);
14303 					(void) quote_and_print(buf, strm, 1);
14304 					(void) putc('"', strm);
14305 
14306 					if (ferror(strm)) {
14307 						warn(emsg_write_error,
14308 						    strerror(errno));
14309 						result = -1;
14310 						goto out;
14311 					}
14312 				} else {
14313 					if (fprintf(strm, "%s", buf) < 0) {
14314 						warn(emsg_write_error,
14315 						    strerror(errno));
14316 						result = -1;
14317 						goto out;
14318 					}
14319 				}
14320 
14321 				free(buf);
14322 			}
14323 			if (ret3 < 0 &&
14324 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14325 				scfdie();
14326 
14327 			/* Write closing paren if mult-value property */
14328 			if ((multiple && putc(')', strm) == EOF) ||
14329 
14330 			    /* Write final newline */
14331 			    fputc('\n', strm) == EOF) {
14332 				warn(emsg_write_error, strerror(errno));
14333 				result = -1;
14334 				goto out;
14335 			}
14336 		}
14337 		if (ret2 < 0)
14338 			scfdie();
14339 
14340 		if (fputc('\n', strm) == EOF) {
14341 			warn(emsg_write_error, strerror(errno));
14342 			result = -1;
14343 			goto out;
14344 		}
14345 	}
14346 	if (ret < 0)
14347 		scfdie();
14348 
14349 out:
14350 	free(pname);
14351 	free(tybuf);
14352 	free(buf);
14353 	scf_iter_destroy(viter);
14354 	scf_iter_destroy(piter);
14355 	scf_iter_destroy(iter);
14356 	scf_value_destroy(val);
14357 	scf_property_destroy(prop);
14358 	scf_pg_destroy(pg);
14359 
14360 	if (result == 0) {
14361 		if (fflush(strm) != 0) {
14362 			warn(emsg_write_error, strerror(errno));
14363 			return (-1);
14364 		}
14365 	}
14366 
14367 	return (result);
14368 }
14369 
14370 int
14371 lscf_editprop()
14372 {
14373 	char *buf, *editor;
14374 	size_t bufsz;
14375 	int tmpfd;
14376 	char tempname[] = TEMP_FILE_PATTERN;
14377 
14378 	lscf_prep_hndl();
14379 
14380 	if (cur_snap != NULL) {
14381 		semerr(emsg_cant_modify_snapshots);
14382 		return (-1);
14383 	}
14384 
14385 	if (cur_svc == NULL && cur_inst == NULL) {
14386 		semerr(emsg_entity_not_selected);
14387 		return (-1);
14388 	}
14389 
14390 	tmpfd = mkstemp(tempname);
14391 	if (tmpfd == -1) {
14392 		semerr(gettext("Could not create temporary file.\n"));
14393 		return (-1);
14394 	}
14395 
14396 	(void) strcpy(tempfilename, tempname);
14397 
14398 	tempfile = fdopen(tmpfd, "r+");
14399 	if (tempfile == NULL) {
14400 		warn(gettext("Could not create temporary file.\n"));
14401 		if (close(tmpfd) == -1)
14402 			warn(gettext("Could not close temporary file: %s.\n"),
14403 			    strerror(errno));
14404 
14405 		remove_tempfile();
14406 
14407 		return (-1);
14408 	}
14409 
14410 	if (write_edit_script(tempfile) == -1) {
14411 		remove_tempfile();
14412 		return (-1);
14413 	}
14414 
14415 	editor = getenv("EDITOR");
14416 	if (editor == NULL)
14417 		editor = "vi";
14418 
14419 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14420 	buf = safe_malloc(bufsz);
14421 
14422 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14423 		uu_die(gettext("Error creating editor command"));
14424 
14425 	if (system(buf) == -1) {
14426 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14427 		    strerror(errno));
14428 		free(buf);
14429 		remove_tempfile();
14430 		return (-1);
14431 	}
14432 
14433 	free(buf);
14434 
14435 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14436 
14437 	remove_tempfile();
14438 
14439 	return (0);
14440 }
14441 
14442 static void
14443 add_string(uu_list_t *strlist, const char *str)
14444 {
14445 	string_list_t *elem;
14446 	elem = safe_malloc(sizeof (*elem));
14447 	uu_list_node_init(elem, &elem->node, string_pool);
14448 	elem->str = safe_strdup(str);
14449 	if (uu_list_append(strlist, elem) != 0)
14450 		uu_die(gettext("libuutil error: %s\n"),
14451 		    uu_strerror(uu_error()));
14452 }
14453 
14454 static int
14455 remove_string(uu_list_t *strlist, const char *str)
14456 {
14457 	uu_list_walk_t	*elems;
14458 	string_list_t	*sp;
14459 
14460 	/*
14461 	 * Find the element that needs to be removed.
14462 	 */
14463 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14464 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14465 		if (strcmp(sp->str, str) == 0)
14466 			break;
14467 	}
14468 	uu_list_walk_end(elems);
14469 
14470 	/*
14471 	 * Returning 1 here as the value was not found, this
14472 	 * might not be an error.  Leave it to the caller to
14473 	 * decide.
14474 	 */
14475 	if (sp == NULL) {
14476 		return (1);
14477 	}
14478 
14479 	uu_list_remove(strlist, sp);
14480 
14481 	free(sp->str);
14482 	free(sp);
14483 
14484 	return (0);
14485 }
14486 
14487 /*
14488  * Get all property values that don't match the given glob pattern,
14489  * if a pattern is specified.
14490  */
14491 static void
14492 get_prop_values(scf_property_t *prop, uu_list_t *values,
14493     const char *pattern)
14494 {
14495 	scf_iter_t *iter;
14496 	scf_value_t *val;
14497 	int ret;
14498 
14499 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14500 	    (val = scf_value_create(g_hndl)) == NULL)
14501 		scfdie();
14502 
14503 	if (scf_iter_property_values(iter, prop) != 0)
14504 		scfdie();
14505 
14506 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14507 		char *buf;
14508 		ssize_t vlen, szret;
14509 
14510 		vlen = scf_value_get_as_string(val, NULL, 0);
14511 		if (vlen < 0)
14512 			scfdie();
14513 
14514 		buf = safe_malloc(vlen + 1);
14515 
14516 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14517 		if (szret < 0)
14518 			scfdie();
14519 		assert(szret <= vlen);
14520 
14521 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14522 			add_string(values, buf);
14523 
14524 		free(buf);
14525 	}
14526 
14527 	if (ret == -1)
14528 		scfdie();
14529 
14530 	scf_value_destroy(val);
14531 	scf_iter_destroy(iter);
14532 }
14533 
14534 static int
14535 lscf_setpropvalue(const char *pgname, const char *type,
14536     const char *arg, int isadd, int isnotfoundok)
14537 {
14538 	scf_type_t ty;
14539 	scf_propertygroup_t *pg;
14540 	scf_property_t *prop;
14541 	int ret, result = 0;
14542 	scf_transaction_t *tx;
14543 	scf_transaction_entry_t *e;
14544 	scf_value_t *v;
14545 	string_list_t *sp;
14546 	char *propname;
14547 	uu_list_t *values;
14548 	uu_list_walk_t *walk;
14549 	void *cookie = NULL;
14550 	char *pattern = NULL;
14551 
14552 	lscf_prep_hndl();
14553 
14554 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14555 		uu_die(gettext("Could not create property list: %s\n"),
14556 		    uu_strerror(uu_error()));
14557 
14558 	if (!isadd)
14559 		pattern = safe_strdup(arg);
14560 
14561 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14562 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14563 	    (prop = scf_property_create(g_hndl)) == NULL ||
14564 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14565 		scfdie();
14566 
14567 	if (cur_snap != NULL) {
14568 		semerr(emsg_cant_modify_snapshots);
14569 		goto fail;
14570 	}
14571 
14572 	if (cur_inst == NULL && cur_svc == NULL) {
14573 		semerr(emsg_entity_not_selected);
14574 		goto fail;
14575 	}
14576 
14577 	propname = strchr(pgname, '/');
14578 	if (propname == NULL) {
14579 		semerr(gettext("Property names must contain a `/'.\n"));
14580 		goto fail;
14581 	}
14582 
14583 	*propname = '\0';
14584 	++propname;
14585 
14586 	if (type != NULL) {
14587 		ty = string_to_type(type);
14588 		if (ty == SCF_TYPE_INVALID) {
14589 			semerr(gettext("Unknown type \"%s\".\n"), type);
14590 			goto fail;
14591 		}
14592 	}
14593 
14594 	if (cur_inst != NULL)
14595 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14596 	else
14597 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14598 	if (ret != 0) {
14599 		switch (scf_error()) {
14600 		case SCF_ERROR_NOT_FOUND:
14601 			if (isnotfoundok) {
14602 				result = 0;
14603 			} else {
14604 				semerr(emsg_no_such_pg, pgname);
14605 				result = -1;
14606 			}
14607 			goto out;
14608 
14609 		case SCF_ERROR_INVALID_ARGUMENT:
14610 			semerr(emsg_invalid_pg_name, pgname);
14611 			goto fail;
14612 
14613 		default:
14614 			scfdie();
14615 		}
14616 	}
14617 
14618 	do {
14619 		if (scf_pg_update(pg) == -1)
14620 			scfdie();
14621 		if (scf_transaction_start(tx, pg) != 0) {
14622 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14623 				scfdie();
14624 
14625 			semerr(emsg_permission_denied);
14626 			goto fail;
14627 		}
14628 
14629 		ret = scf_pg_get_property(pg, propname, prop);
14630 		if (ret == 0) {
14631 			scf_type_t ptype;
14632 			char *pat = pattern;
14633 
14634 			if (scf_property_type(prop, &ptype) != 0)
14635 				scfdie();
14636 
14637 			if (isadd) {
14638 				if (type != NULL && ptype != ty) {
14639 					semerr(gettext("Property \"%s\" is not "
14640 					    "of type \"%s\".\n"), propname,
14641 					    type);
14642 					goto fail;
14643 				}
14644 
14645 				pat = NULL;
14646 			} else {
14647 				size_t len = strlen(pat);
14648 				if (len > 0 && pat[len - 1] == '\"')
14649 					pat[len - 1] = '\0';
14650 				if (len > 0 && pat[0] == '\"')
14651 					pat++;
14652 			}
14653 
14654 			ty = ptype;
14655 
14656 			get_prop_values(prop, values, pat);
14657 
14658 			if (isadd)
14659 				add_string(values, arg);
14660 
14661 			if (scf_transaction_property_change(tx, e,
14662 			    propname, ty) == -1)
14663 				scfdie();
14664 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14665 			if (isadd) {
14666 				if (type == NULL) {
14667 					semerr(gettext("Type required "
14668 					    "for new properties.\n"));
14669 					goto fail;
14670 				}
14671 
14672 				add_string(values, arg);
14673 
14674 				if (scf_transaction_property_new(tx, e,
14675 				    propname, ty) == -1)
14676 					scfdie();
14677 			} else if (isnotfoundok) {
14678 				result = 0;
14679 				goto out;
14680 			} else {
14681 				semerr(gettext("No such property %s/%s.\n"),
14682 				    pgname, propname);
14683 				result = -1;
14684 				goto out;
14685 			}
14686 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14687 			semerr(emsg_invalid_prop_name, propname);
14688 			goto fail;
14689 		} else {
14690 			scfdie();
14691 		}
14692 
14693 		walk = uu_list_walk_start(values, UU_DEFAULT);
14694 		if (walk == NULL)
14695 			uu_die(gettext("Could not walk property list.\n"));
14696 
14697 		for (sp = uu_list_walk_next(walk); sp != NULL;
14698 		    sp = uu_list_walk_next(walk)) {
14699 			v = string_to_value(sp->str, ty, 0);
14700 
14701 			if (v == NULL) {
14702 				scf_entry_destroy_children(e);
14703 				goto fail;
14704 			}
14705 			ret = scf_entry_add_value(e, v);
14706 			assert(ret == 0);
14707 		}
14708 		uu_list_walk_end(walk);
14709 
14710 		result = scf_transaction_commit(tx);
14711 
14712 		scf_transaction_reset(tx);
14713 		scf_entry_destroy_children(e);
14714 	} while (result == 0);
14715 
14716 	if (result < 0) {
14717 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14718 			scfdie();
14719 
14720 		semerr(emsg_permission_denied);
14721 		goto fail;
14722 	}
14723 
14724 	result = 0;
14725 
14726 	private_refresh();
14727 
14728 out:
14729 	scf_transaction_destroy(tx);
14730 	scf_entry_destroy(e);
14731 	scf_pg_destroy(pg);
14732 	scf_property_destroy(prop);
14733 	free(pattern);
14734 
14735 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14736 		free(sp->str);
14737 		free(sp);
14738 	}
14739 
14740 	uu_list_destroy(values);
14741 
14742 	return (result);
14743 
14744 fail:
14745 	result = -1;
14746 	goto out;
14747 }
14748 
14749 int
14750 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14751 {
14752 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14753 }
14754 
14755 int
14756 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14757 {
14758 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14759 }
14760 
14761 /*
14762  * Look for a standard start method, first in the instance (if any),
14763  * then the service.
14764  */
14765 static const char *
14766 start_method_name(int *in_instance)
14767 {
14768 	scf_propertygroup_t *pg;
14769 	char **p;
14770 	int ret;
14771 	scf_instance_t *inst = cur_inst;
14772 
14773 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14774 		scfdie();
14775 
14776 again:
14777 	for (p = start_method_names; *p != NULL; p++) {
14778 		if (inst != NULL)
14779 			ret = scf_instance_get_pg(inst, *p, pg);
14780 		else
14781 			ret = scf_service_get_pg(cur_svc, *p, pg);
14782 
14783 		if (ret == 0) {
14784 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14785 			char *buf = safe_malloc(bufsz);
14786 
14787 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14788 				free(buf);
14789 				continue;
14790 			}
14791 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14792 				free(buf);
14793 				continue;
14794 			}
14795 
14796 			free(buf);
14797 			*in_instance = (inst != NULL);
14798 			scf_pg_destroy(pg);
14799 			return (*p);
14800 		}
14801 
14802 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14803 			continue;
14804 
14805 		scfdie();
14806 	}
14807 
14808 	if (inst != NULL) {
14809 		inst = NULL;
14810 		goto again;
14811 	}
14812 
14813 	scf_pg_destroy(pg);
14814 	return (NULL);
14815 }
14816 
14817 static int
14818 addpg(const char *name, const char *type)
14819 {
14820 	scf_propertygroup_t *pg;
14821 	int ret;
14822 
14823 	pg = scf_pg_create(g_hndl);
14824 	if (pg == NULL)
14825 		scfdie();
14826 
14827 	if (cur_inst != NULL)
14828 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14829 	else
14830 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14831 
14832 	if (ret != 0) {
14833 		switch (scf_error()) {
14834 		case SCF_ERROR_EXISTS:
14835 			ret = 0;
14836 			break;
14837 
14838 		case SCF_ERROR_PERMISSION_DENIED:
14839 			semerr(emsg_permission_denied);
14840 			break;
14841 
14842 		default:
14843 			scfdie();
14844 		}
14845 	}
14846 
14847 	scf_pg_destroy(pg);
14848 	return (ret);
14849 }
14850 
14851 int
14852 lscf_setenv(uu_list_t *args, int isunset)
14853 {
14854 	int ret = 0;
14855 	size_t i;
14856 	int argc;
14857 	char **argv = NULL;
14858 	string_list_t *slp;
14859 	char *pattern;
14860 	char *prop;
14861 	int do_service = 0;
14862 	int do_instance = 0;
14863 	const char *method = NULL;
14864 	const char *name = NULL;
14865 	const char *value = NULL;
14866 	scf_instance_t *saved_cur_inst = cur_inst;
14867 
14868 	lscf_prep_hndl();
14869 
14870 	argc = uu_list_numnodes(args);
14871 	if (argc < 1)
14872 		goto usage;
14873 
14874 	argv = calloc(argc + 1, sizeof (char *));
14875 	if (argv == NULL)
14876 		uu_die(gettext("Out of memory.\n"));
14877 
14878 	for (slp = uu_list_first(args), i = 0;
14879 	    slp != NULL;
14880 	    slp = uu_list_next(args, slp), ++i)
14881 		argv[i] = slp->str;
14882 
14883 	argv[i] = NULL;
14884 
14885 	opterr = 0;
14886 	optind = 0;
14887 	for (;;) {
14888 		ret = getopt(argc, argv, "sim:");
14889 		if (ret == -1)
14890 			break;
14891 
14892 		switch (ret) {
14893 		case 's':
14894 			do_service = 1;
14895 			cur_inst = NULL;
14896 			break;
14897 
14898 		case 'i':
14899 			do_instance = 1;
14900 			break;
14901 
14902 		case 'm':
14903 			method = optarg;
14904 			break;
14905 
14906 		case '?':
14907 			goto usage;
14908 
14909 		default:
14910 			bad_error("getopt", ret);
14911 		}
14912 	}
14913 
14914 	argc -= optind;
14915 	if ((do_service && do_instance) ||
14916 	    (isunset && argc != 1) ||
14917 	    (!isunset && argc != 2))
14918 		goto usage;
14919 
14920 	name = argv[optind];
14921 	if (!isunset)
14922 		value = argv[optind + 1];
14923 
14924 	if (cur_snap != NULL) {
14925 		semerr(emsg_cant_modify_snapshots);
14926 		ret = -1;
14927 		goto out;
14928 	}
14929 
14930 	if (cur_inst == NULL && cur_svc == NULL) {
14931 		semerr(emsg_entity_not_selected);
14932 		ret = -1;
14933 		goto out;
14934 	}
14935 
14936 	if (do_instance && cur_inst == NULL) {
14937 		semerr(gettext("No instance is selected.\n"));
14938 		ret = -1;
14939 		goto out;
14940 	}
14941 
14942 	if (do_service && cur_svc == NULL) {
14943 		semerr(gettext("No service is selected.\n"));
14944 		ret = -1;
14945 		goto out;
14946 	}
14947 
14948 	if (method == NULL) {
14949 		if (do_instance || do_service) {
14950 			method = "method_context";
14951 			if (!isunset) {
14952 				ret = addpg("method_context",
14953 				    SCF_GROUP_FRAMEWORK);
14954 				if (ret != 0)
14955 					goto out;
14956 			}
14957 		} else {
14958 			int in_instance;
14959 			method = start_method_name(&in_instance);
14960 			if (method == NULL) {
14961 				semerr(gettext(
14962 				    "Couldn't find start method; please "
14963 				    "specify a method with '-m'.\n"));
14964 				ret = -1;
14965 				goto out;
14966 			}
14967 			if (!in_instance)
14968 				cur_inst = NULL;
14969 		}
14970 	} else {
14971 		scf_propertygroup_t *pg;
14972 		size_t bufsz;
14973 		char *buf;
14974 		int ret;
14975 
14976 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14977 			scfdie();
14978 
14979 		if (cur_inst != NULL)
14980 			ret = scf_instance_get_pg(cur_inst, method, pg);
14981 		else
14982 			ret = scf_service_get_pg(cur_svc, method, pg);
14983 
14984 		if (ret != 0) {
14985 			scf_pg_destroy(pg);
14986 			switch (scf_error()) {
14987 			case SCF_ERROR_NOT_FOUND:
14988 				semerr(gettext("Couldn't find the method "
14989 				    "\"%s\".\n"), method);
14990 				goto out;
14991 
14992 			case SCF_ERROR_INVALID_ARGUMENT:
14993 				semerr(gettext("Invalid method name \"%s\".\n"),
14994 				    method);
14995 				goto out;
14996 
14997 			default:
14998 				scfdie();
14999 			}
15000 		}
15001 
15002 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
15003 		buf = safe_malloc(bufsz);
15004 
15005 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
15006 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
15007 			semerr(gettext("Property group \"%s\" is not of type "
15008 			    "\"method\".\n"), method);
15009 			ret = -1;
15010 			free(buf);
15011 			scf_pg_destroy(pg);
15012 			goto out;
15013 		}
15014 
15015 		free(buf);
15016 		scf_pg_destroy(pg);
15017 	}
15018 
15019 	prop = uu_msprintf("%s/environment", method);
15020 	pattern = uu_msprintf("%s=*", name);
15021 
15022 	if (prop == NULL || pattern == NULL)
15023 		uu_die(gettext("Out of memory.\n"));
15024 
15025 	ret = lscf_delpropvalue(prop, pattern, !isunset);
15026 
15027 	if (ret == 0 && !isunset) {
15028 		uu_free(pattern);
15029 		uu_free(prop);
15030 		prop = uu_msprintf("%s/environment", method);
15031 		pattern = uu_msprintf("%s=%s", name, value);
15032 		if (prop == NULL || pattern == NULL)
15033 			uu_die(gettext("Out of memory.\n"));
15034 		ret = lscf_addpropvalue(prop, "astring:", pattern);
15035 	}
15036 	uu_free(pattern);
15037 	uu_free(prop);
15038 
15039 out:
15040 	cur_inst = saved_cur_inst;
15041 
15042 	free(argv);
15043 	return (ret);
15044 usage:
15045 	ret = -2;
15046 	goto out;
15047 }
15048 
15049 /*
15050  * Snapshot commands
15051  */
15052 
15053 void
15054 lscf_listsnap()
15055 {
15056 	scf_snapshot_t *snap;
15057 	scf_iter_t *iter;
15058 	char *nb;
15059 	int r;
15060 
15061 	lscf_prep_hndl();
15062 
15063 	if (cur_inst == NULL) {
15064 		semerr(gettext("Instance not selected.\n"));
15065 		return;
15066 	}
15067 
15068 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15069 	    (iter = scf_iter_create(g_hndl)) == NULL)
15070 		scfdie();
15071 
15072 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
15073 		scfdie();
15074 
15075 	nb = safe_malloc(max_scf_name_len + 1);
15076 
15077 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
15078 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
15079 			scfdie();
15080 
15081 		(void) puts(nb);
15082 	}
15083 	if (r < 0)
15084 		scfdie();
15085 
15086 	free(nb);
15087 	scf_iter_destroy(iter);
15088 	scf_snapshot_destroy(snap);
15089 }
15090 
15091 void
15092 lscf_selectsnap(const char *name)
15093 {
15094 	scf_snapshot_t *snap;
15095 	scf_snaplevel_t *level;
15096 
15097 	lscf_prep_hndl();
15098 
15099 	if (cur_inst == NULL) {
15100 		semerr(gettext("Instance not selected.\n"));
15101 		return;
15102 	}
15103 
15104 	if (cur_snap != NULL) {
15105 		if (name != NULL) {
15106 			char *cur_snap_name;
15107 			boolean_t nochange;
15108 
15109 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
15110 
15111 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
15112 			    max_scf_name_len + 1) < 0)
15113 				scfdie();
15114 
15115 			nochange = strcmp(name, cur_snap_name) == 0;
15116 
15117 			free(cur_snap_name);
15118 
15119 			if (nochange)
15120 				return;
15121 		}
15122 
15123 		unselect_cursnap();
15124 	}
15125 
15126 	if (name == NULL)
15127 		return;
15128 
15129 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
15130 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
15131 		scfdie();
15132 
15133 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
15134 	    SCF_SUCCESS) {
15135 		switch (scf_error()) {
15136 		case SCF_ERROR_INVALID_ARGUMENT:
15137 			semerr(gettext("Invalid name \"%s\".\n"), name);
15138 			break;
15139 
15140 		case SCF_ERROR_NOT_FOUND:
15141 			semerr(gettext("No such snapshot \"%s\".\n"), name);
15142 			break;
15143 
15144 		default:
15145 			scfdie();
15146 		}
15147 
15148 		scf_snaplevel_destroy(level);
15149 		scf_snapshot_destroy(snap);
15150 		return;
15151 	}
15152 
15153 	/* Load the snaplevels into our list. */
15154 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
15155 	if (cur_levels == NULL)
15156 		uu_die(gettext("Could not create list: %s\n"),
15157 		    uu_strerror(uu_error()));
15158 
15159 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15160 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15161 			scfdie();
15162 
15163 		semerr(gettext("Snapshot has no snaplevels.\n"));
15164 
15165 		scf_snaplevel_destroy(level);
15166 		scf_snapshot_destroy(snap);
15167 		return;
15168 	}
15169 
15170 	cur_snap = snap;
15171 
15172 	for (;;) {
15173 		cur_elt = safe_malloc(sizeof (*cur_elt));
15174 		uu_list_node_init(cur_elt, &cur_elt->list_node,
15175 		    snaplevel_pool);
15176 		cur_elt->sl = level;
15177 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
15178 			uu_die(gettext("libuutil error: %s\n"),
15179 			    uu_strerror(uu_error()));
15180 
15181 		level = scf_snaplevel_create(g_hndl);
15182 		if (level == NULL)
15183 			scfdie();
15184 
15185 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
15186 		    level) != SCF_SUCCESS) {
15187 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15188 				scfdie();
15189 
15190 			scf_snaplevel_destroy(level);
15191 			break;
15192 		}
15193 	}
15194 
15195 	cur_elt = uu_list_last(cur_levels);
15196 	cur_level = cur_elt->sl;
15197 }
15198 
15199 /*
15200  * Copies the properties & values in src to dst.  Assumes src won't change.
15201  * Returns -1 if permission is denied, -2 if another transaction interrupts,
15202  * and 0 on success.
15203  *
15204  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
15205  * property, if it is copied and has type boolean.  (See comment in
15206  * lscf_revert()).
15207  */
15208 static int
15209 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
15210     uint8_t enabled)
15211 {
15212 	scf_transaction_t *tx;
15213 	scf_iter_t *iter, *viter;
15214 	scf_property_t *prop;
15215 	scf_value_t *v;
15216 	char *nbuf;
15217 	int r;
15218 
15219 	tx = scf_transaction_create(g_hndl);
15220 	if (tx == NULL)
15221 		scfdie();
15222 
15223 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
15224 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15225 			scfdie();
15226 
15227 		scf_transaction_destroy(tx);
15228 
15229 		return (-1);
15230 	}
15231 
15232 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
15233 	    (prop = scf_property_create(g_hndl)) == NULL ||
15234 	    (viter = scf_iter_create(g_hndl)) == NULL)
15235 		scfdie();
15236 
15237 	nbuf = safe_malloc(max_scf_name_len + 1);
15238 
15239 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
15240 		scfdie();
15241 
15242 	for (;;) {
15243 		scf_transaction_entry_t *e;
15244 		scf_type_t ty;
15245 
15246 		r = scf_iter_next_property(iter, prop);
15247 		if (r == -1)
15248 			scfdie();
15249 		if (r == 0)
15250 			break;
15251 
15252 		e = scf_entry_create(g_hndl);
15253 		if (e == NULL)
15254 			scfdie();
15255 
15256 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
15257 			scfdie();
15258 
15259 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
15260 			scfdie();
15261 
15262 		if (scf_transaction_property_new(tx, e, nbuf,
15263 		    ty) != SCF_SUCCESS)
15264 			scfdie();
15265 
15266 		if ((enabled == 0 || enabled == 1) &&
15267 		    strcmp(nbuf, scf_property_enabled) == 0 &&
15268 		    ty == SCF_TYPE_BOOLEAN) {
15269 			v = scf_value_create(g_hndl);
15270 			if (v == NULL)
15271 				scfdie();
15272 
15273 			scf_value_set_boolean(v, enabled);
15274 
15275 			if (scf_entry_add_value(e, v) != 0)
15276 				scfdie();
15277 		} else {
15278 			if (scf_iter_property_values(viter, prop) != 0)
15279 				scfdie();
15280 
15281 			for (;;) {
15282 				v = scf_value_create(g_hndl);
15283 				if (v == NULL)
15284 					scfdie();
15285 
15286 				r = scf_iter_next_value(viter, v);
15287 				if (r == -1)
15288 					scfdie();
15289 				if (r == 0) {
15290 					scf_value_destroy(v);
15291 					break;
15292 				}
15293 
15294 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15295 					scfdie();
15296 			}
15297 		}
15298 	}
15299 
15300 	free(nbuf);
15301 	scf_iter_destroy(viter);
15302 	scf_property_destroy(prop);
15303 	scf_iter_destroy(iter);
15304 
15305 	r = scf_transaction_commit(tx);
15306 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15307 		scfdie();
15308 
15309 	scf_transaction_destroy_children(tx);
15310 	scf_transaction_destroy(tx);
15311 
15312 	switch (r) {
15313 	case 1:		return (0);
15314 	case 0:		return (-2);
15315 	case -1:	return (-1);
15316 
15317 	default:
15318 		abort();
15319 	}
15320 
15321 	/* NOTREACHED */
15322 }
15323 
15324 void
15325 lscf_revert(const char *snapname)
15326 {
15327 	scf_snapshot_t *snap, *prev;
15328 	scf_snaplevel_t *level, *nlevel;
15329 	scf_iter_t *iter;
15330 	scf_propertygroup_t *pg, *npg;
15331 	scf_property_t *prop;
15332 	scf_value_t *val;
15333 	char *nbuf, *tbuf;
15334 	uint8_t enabled;
15335 
15336 	lscf_prep_hndl();
15337 
15338 	if (cur_inst == NULL) {
15339 		semerr(gettext("Instance not selected.\n"));
15340 		return;
15341 	}
15342 
15343 	if (snapname != NULL) {
15344 		snap = scf_snapshot_create(g_hndl);
15345 		if (snap == NULL)
15346 			scfdie();
15347 
15348 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15349 		    SCF_SUCCESS) {
15350 			switch (scf_error()) {
15351 			case SCF_ERROR_INVALID_ARGUMENT:
15352 				semerr(gettext("Invalid snapshot name "
15353 				    "\"%s\".\n"), snapname);
15354 				break;
15355 
15356 			case SCF_ERROR_NOT_FOUND:
15357 				semerr(gettext("No such snapshot.\n"));
15358 				break;
15359 
15360 			default:
15361 				scfdie();
15362 			}
15363 
15364 			scf_snapshot_destroy(snap);
15365 			return;
15366 		}
15367 	} else {
15368 		if (cur_snap != NULL) {
15369 			snap = cur_snap;
15370 		} else {
15371 			semerr(gettext("No snapshot selected.\n"));
15372 			return;
15373 		}
15374 	}
15375 
15376 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15377 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15378 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15379 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15380 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15381 	    (prop = scf_property_create(g_hndl)) == NULL ||
15382 	    (val = scf_value_create(g_hndl)) == NULL)
15383 		scfdie();
15384 
15385 	nbuf = safe_malloc(max_scf_name_len + 1);
15386 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15387 
15388 	/* Take the "previous" snapshot before we blow away the properties. */
15389 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15390 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15391 			scfdie();
15392 	} else {
15393 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15394 			scfdie();
15395 
15396 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15397 			scfdie();
15398 	}
15399 
15400 	/* Save general/enabled, since we're probably going to replace it. */
15401 	enabled = 2;
15402 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15403 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15404 	    scf_property_get_value(prop, val) == 0)
15405 		(void) scf_value_get_boolean(val, &enabled);
15406 
15407 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15408 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15409 			scfdie();
15410 
15411 		goto out;
15412 	}
15413 
15414 	for (;;) {
15415 		boolean_t isinst;
15416 		uint32_t flags;
15417 		int r;
15418 
15419 		/* Clear the properties from the corresponding entity. */
15420 		isinst = snaplevel_is_instance(level);
15421 
15422 		if (!isinst)
15423 			r = scf_iter_service_pgs(iter, cur_svc);
15424 		else
15425 			r = scf_iter_instance_pgs(iter, cur_inst);
15426 		if (r != SCF_SUCCESS)
15427 			scfdie();
15428 
15429 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15430 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15431 				scfdie();
15432 
15433 			/* Skip nonpersistent pgs. */
15434 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15435 				continue;
15436 
15437 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15438 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15439 					scfdie();
15440 
15441 				semerr(emsg_permission_denied);
15442 				goto out;
15443 			}
15444 		}
15445 		if (r == -1)
15446 			scfdie();
15447 
15448 		/* Copy the properties to the corresponding entity. */
15449 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15450 			scfdie();
15451 
15452 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15453 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15454 				scfdie();
15455 
15456 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15457 			    0)
15458 				scfdie();
15459 
15460 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15461 				scfdie();
15462 
15463 			if (!isinst)
15464 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15465 				    flags, npg);
15466 			else
15467 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15468 				    flags, npg);
15469 			if (r != SCF_SUCCESS) {
15470 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15471 					scfdie();
15472 
15473 				semerr(emsg_permission_denied);
15474 				goto out;
15475 			}
15476 
15477 			if ((enabled == 0 || enabled == 1) &&
15478 			    strcmp(nbuf, scf_pg_general) == 0)
15479 				r = pg_copy(pg, npg, enabled);
15480 			else
15481 				r = pg_copy(pg, npg, 2);
15482 
15483 			switch (r) {
15484 			case 0:
15485 				break;
15486 
15487 			case -1:
15488 				semerr(emsg_permission_denied);
15489 				goto out;
15490 
15491 			case -2:
15492 				semerr(gettext(
15493 				    "Interrupted by another change.\n"));
15494 				goto out;
15495 
15496 			default:
15497 				abort();
15498 			}
15499 		}
15500 		if (r == -1)
15501 			scfdie();
15502 
15503 		/* Get next level. */
15504 		nlevel = scf_snaplevel_create(g_hndl);
15505 		if (nlevel == NULL)
15506 			scfdie();
15507 
15508 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15509 		    SCF_SUCCESS) {
15510 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15511 				scfdie();
15512 
15513 			scf_snaplevel_destroy(nlevel);
15514 			break;
15515 		}
15516 
15517 		scf_snaplevel_destroy(level);
15518 		level = nlevel;
15519 	}
15520 
15521 	if (snapname == NULL) {
15522 		lscf_selectsnap(NULL);
15523 		snap = NULL;		/* cur_snap has been destroyed */
15524 	}
15525 
15526 out:
15527 	free(tbuf);
15528 	free(nbuf);
15529 	scf_value_destroy(val);
15530 	scf_property_destroy(prop);
15531 	scf_pg_destroy(npg);
15532 	scf_pg_destroy(pg);
15533 	scf_iter_destroy(iter);
15534 	scf_snaplevel_destroy(level);
15535 	scf_snapshot_destroy(prev);
15536 	if (snap != cur_snap)
15537 		scf_snapshot_destroy(snap);
15538 }
15539 
15540 void
15541 lscf_refresh(void)
15542 {
15543 	ssize_t fmrilen;
15544 	size_t bufsz;
15545 	char *fmribuf;
15546 	int r;
15547 
15548 	lscf_prep_hndl();
15549 
15550 	if (cur_inst == NULL) {
15551 		semerr(gettext("Instance not selected.\n"));
15552 		return;
15553 	}
15554 
15555 	bufsz = max_scf_fmri_len + 1;
15556 	fmribuf = safe_malloc(bufsz);
15557 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15558 	if (fmrilen < 0) {
15559 		free(fmribuf);
15560 		if (scf_error() != SCF_ERROR_DELETED)
15561 			scfdie();
15562 		scf_instance_destroy(cur_inst);
15563 		cur_inst = NULL;
15564 		warn(emsg_deleted);
15565 		return;
15566 	}
15567 	assert(fmrilen < bufsz);
15568 
15569 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15570 	switch (r) {
15571 	case 0:
15572 		break;
15573 
15574 	case ECONNABORTED:
15575 		warn(gettext("Could not refresh %s "
15576 		    "(repository connection broken).\n"), fmribuf);
15577 		break;
15578 
15579 	case ECANCELED:
15580 		warn(emsg_deleted);
15581 		break;
15582 
15583 	case EPERM:
15584 		warn(gettext("Could not refresh %s "
15585 		    "(permission denied).\n"), fmribuf);
15586 		break;
15587 
15588 	case ENOSPC:
15589 		warn(gettext("Could not refresh %s "
15590 		    "(repository server out of resources).\n"),
15591 		    fmribuf);
15592 		break;
15593 
15594 	case EACCES:
15595 	default:
15596 		bad_error("refresh_entity", scf_error());
15597 	}
15598 
15599 	free(fmribuf);
15600 }
15601 
15602 /*
15603  * describe [-v] [-t] [pg/prop]
15604  */
15605 int
15606 lscf_describe(uu_list_t *args, int hasargs)
15607 {
15608 	int ret = 0;
15609 	size_t i;
15610 	int argc;
15611 	char **argv = NULL;
15612 	string_list_t *slp;
15613 	int do_verbose = 0;
15614 	int do_templates = 0;
15615 	char *pattern = NULL;
15616 
15617 	lscf_prep_hndl();
15618 
15619 	if (hasargs != 0)  {
15620 		argc = uu_list_numnodes(args);
15621 		if (argc < 1)
15622 			goto usage;
15623 
15624 		argv = calloc(argc + 1, sizeof (char *));
15625 		if (argv == NULL)
15626 			uu_die(gettext("Out of memory.\n"));
15627 
15628 		for (slp = uu_list_first(args), i = 0;
15629 		    slp != NULL;
15630 		    slp = uu_list_next(args, slp), ++i)
15631 			argv[i] = slp->str;
15632 
15633 		argv[i] = NULL;
15634 
15635 		/*
15636 		 * We start optind = 0 because our list of arguments
15637 		 * starts at argv[0]
15638 		 */
15639 		optind = 0;
15640 		opterr = 0;
15641 		for (;;) {
15642 			ret = getopt(argc, argv, "vt");
15643 			if (ret == -1)
15644 				break;
15645 
15646 			switch (ret) {
15647 			case 'v':
15648 				do_verbose = 1;
15649 				break;
15650 
15651 			case 't':
15652 				do_templates = 1;
15653 				break;
15654 
15655 			case '?':
15656 				goto usage;
15657 
15658 			default:
15659 				bad_error("getopt", ret);
15660 			}
15661 		}
15662 
15663 		pattern = argv[optind];
15664 	}
15665 
15666 	if (cur_inst == NULL && cur_svc == NULL) {
15667 		semerr(emsg_entity_not_selected);
15668 		ret = -1;
15669 		goto out;
15670 	}
15671 
15672 	/*
15673 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15674 	 * output if their last parameter is set to 2.  Less information is
15675 	 * produced if the parameter is set to 1.
15676 	 */
15677 	if (pattern == NULL) {
15678 		if (do_verbose == 1)
15679 			list_entity_tmpl(2);
15680 		else
15681 			list_entity_tmpl(1);
15682 	}
15683 
15684 	if (do_templates == 0) {
15685 		if (do_verbose == 1)
15686 			listprop(pattern, 0, 2);
15687 		else
15688 			listprop(pattern, 0, 1);
15689 	} else {
15690 		if (do_verbose == 1)
15691 			listtmpl(pattern, 2);
15692 		else
15693 			listtmpl(pattern, 1);
15694 	}
15695 
15696 	ret = 0;
15697 out:
15698 	if (argv != NULL)
15699 		free(argv);
15700 	return (ret);
15701 usage:
15702 	ret = -2;
15703 	goto out;
15704 }
15705 
15706 #define	PARAM_ACTIVE	((const char *) "active")
15707 #define	PARAM_INACTIVE	((const char *) "inactive")
15708 #define	PARAM_SMTP_TO	((const char *) "to")
15709 
15710 /*
15711  * tokenize()
15712  * Breaks down the string according to the tokens passed.
15713  * Caller is responsible for freeing array of pointers returned.
15714  * Returns NULL on failure
15715  */
15716 char **
15717 tokenize(char *str, const char *sep)
15718 {
15719 	char *token, *lasts;
15720 	char **buf;
15721 	int n = 0;	/* number of elements */
15722 	int size = 8;	/* size of the array (initial) */
15723 
15724 	buf = safe_malloc(size * sizeof (char *));
15725 
15726 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15727 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15728 		if (n + 1 >= size) {
15729 			size *= 2;
15730 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15731 			    NULL) {
15732 				uu_die(gettext("Out of memory"));
15733 			}
15734 		}
15735 		buf[n] = token;
15736 	}
15737 	/* NULL terminate the pointer array */
15738 	buf[n] = NULL;
15739 
15740 	return (buf);
15741 }
15742 
15743 int32_t
15744 check_tokens(char **p)
15745 {
15746 	int32_t smf = 0;
15747 	int32_t fma = 0;
15748 
15749 	while (*p) {
15750 		int32_t t = string_to_tset(*p);
15751 
15752 		if (t == 0) {
15753 			if (is_fma_token(*p) == 0)
15754 				return (INVALID_TOKENS);
15755 			fma = 1; /* this token is an fma event */
15756 		} else {
15757 			smf |= t;
15758 		}
15759 
15760 		if (smf != 0 && fma == 1)
15761 			return (MIXED_TOKENS);
15762 		++p;
15763 	}
15764 
15765 	if (smf > 0)
15766 		return (smf);
15767 	else if (fma == 1)
15768 		return (FMA_TOKENS);
15769 
15770 	return (INVALID_TOKENS);
15771 }
15772 
15773 static int
15774 get_selection_str(char *fmri, size_t sz)
15775 {
15776 	if (g_hndl == NULL) {
15777 		semerr(emsg_entity_not_selected);
15778 		return (-1);
15779 	} else if (cur_level != NULL) {
15780 		semerr(emsg_invalid_for_snapshot);
15781 		return (-1);
15782 	} else {
15783 		lscf_get_selection_str(fmri, sz);
15784 	}
15785 
15786 	return (0);
15787 }
15788 
15789 void
15790 lscf_delnotify(const char *set, int global)
15791 {
15792 	char *str = strdup(set);
15793 	char **pgs;
15794 	char **p;
15795 	int32_t tset;
15796 	char *fmri = NULL;
15797 
15798 	if (str == NULL)
15799 		uu_die(gettext("Out of memory.\n"));
15800 
15801 	pgs = tokenize(str, ",");
15802 
15803 	if ((tset = check_tokens(pgs)) > 0) {
15804 		size_t sz = max_scf_fmri_len + 1;
15805 
15806 		fmri = safe_malloc(sz);
15807 		if (global) {
15808 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15809 		} else if (get_selection_str(fmri, sz) != 0) {
15810 			goto out;
15811 		}
15812 
15813 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15814 		    tset) != SCF_SUCCESS) {
15815 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15816 			    scf_strerror(scf_error()));
15817 		}
15818 	} else if (tset == FMA_TOKENS) {
15819 		if (global) {
15820 			semerr(gettext("Can't use option '-g' with FMA event "
15821 			    "definitions\n"));
15822 			goto out;
15823 		}
15824 
15825 		for (p = pgs; *p; ++p) {
15826 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15827 			    SCF_SUCCESS) {
15828 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15829 				    scf_strerror(scf_error()));
15830 				goto out;
15831 			}
15832 		}
15833 	} else if (tset == MIXED_TOKENS) {
15834 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15835 		goto out;
15836 	} else {
15837 		uu_die(gettext("Invalid input.\n"));
15838 	}
15839 
15840 out:
15841 	free(fmri);
15842 	free(pgs);
15843 	free(str);
15844 }
15845 
15846 void
15847 lscf_listnotify(const char *set, int global)
15848 {
15849 	char *str = safe_strdup(set);
15850 	char **pgs;
15851 	char **p;
15852 	int32_t tset;
15853 	nvlist_t *nvl;
15854 	char *fmri = NULL;
15855 
15856 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15857 		uu_die(gettext("Out of memory.\n"));
15858 
15859 	pgs = tokenize(str, ",");
15860 
15861 	if ((tset = check_tokens(pgs)) > 0) {
15862 		size_t sz = max_scf_fmri_len + 1;
15863 
15864 		fmri = safe_malloc(sz);
15865 		if (global) {
15866 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15867 		} else if (get_selection_str(fmri, sz) != 0) {
15868 			goto out;
15869 		}
15870 
15871 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15872 		    SCF_SUCCESS) {
15873 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15874 			    scf_error() != SCF_ERROR_DELETED)
15875 				uu_warn(gettext(
15876 				    "Failed listnotify: %s\n"),
15877 				    scf_strerror(scf_error()));
15878 			goto out;
15879 		}
15880 
15881 		listnotify_print(nvl, NULL);
15882 	} else if (tset == FMA_TOKENS) {
15883 		if (global) {
15884 			semerr(gettext("Can't use option '-g' with FMA event "
15885 			    "definitions\n"));
15886 			goto out;
15887 		}
15888 
15889 		for (p = pgs; *p; ++p) {
15890 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15891 			    SCF_SUCCESS) {
15892 				/*
15893 				 * if the preferences have just been deleted
15894 				 * or does not exist, just skip.
15895 				 */
15896 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15897 				    scf_error() == SCF_ERROR_DELETED)
15898 					continue;
15899 				uu_warn(gettext(
15900 				    "Failed listnotify: %s\n"),
15901 				    scf_strerror(scf_error()));
15902 				goto out;
15903 			}
15904 			listnotify_print(nvl, re_tag(*p));
15905 		}
15906 	} else if (tset == MIXED_TOKENS) {
15907 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15908 		goto out;
15909 	} else {
15910 		semerr(gettext("Invalid input.\n"));
15911 	}
15912 
15913 out:
15914 	nvlist_free(nvl);
15915 	free(fmri);
15916 	free(pgs);
15917 	free(str);
15918 }
15919 
15920 static char *
15921 strip_quotes_and_blanks(char *s)
15922 {
15923 	char *start = s;
15924 	char *end = strrchr(s, '\"');
15925 
15926 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15927 		start = s + 1;
15928 		while (isblank(*start))
15929 			start++;
15930 		while (isblank(*(end - 1)) && end > start) {
15931 			end--;
15932 		}
15933 		*end = '\0';
15934 	}
15935 
15936 	return (start);
15937 }
15938 
15939 static int
15940 set_active(nvlist_t *mech, const char *hier_part)
15941 {
15942 	boolean_t b;
15943 
15944 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15945 		b = B_TRUE;
15946 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15947 		b = B_FALSE;
15948 	} else {
15949 		return (-1);
15950 	}
15951 
15952 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15953 		uu_die(gettext("Out of memory.\n"));
15954 
15955 	return (0);
15956 }
15957 
15958 static int
15959 add_snmp_params(nvlist_t *mech, char *hier_part)
15960 {
15961 	return (set_active(mech, hier_part));
15962 }
15963 
15964 static int
15965 add_syslog_params(nvlist_t *mech, char *hier_part)
15966 {
15967 	return (set_active(mech, hier_part));
15968 }
15969 
15970 /*
15971  * add_mailto_paramas()
15972  * parse the hier_part of mailto URI
15973  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15974  * or mailto:{[active]|inactive}
15975  */
15976 static int
15977 add_mailto_params(nvlist_t *mech, char *hier_part)
15978 {
15979 	const char *tok = "?&";
15980 	char *p;
15981 	char *lasts;
15982 	char *param;
15983 	char *val;
15984 
15985 	/*
15986 	 * If the notification parametes are in the form of
15987 	 *
15988 	 *   malito:{[active]|inactive}
15989 	 *
15990 	 * we set the property accordingly and return.
15991 	 * Otherwise, we make the notification type active and
15992 	 * process the hier_part.
15993 	 */
15994 	if (set_active(mech, hier_part) == 0)
15995 		return (0);
15996 	else if (set_active(mech, PARAM_ACTIVE) != 0)
15997 		return (-1);
15998 
15999 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
16000 		/*
16001 		 * sanity check: we only get here if hier_part = "", but
16002 		 * that's handled by set_active
16003 		 */
16004 		uu_die("strtok_r");
16005 	}
16006 
16007 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
16008 		uu_die(gettext("Out of memory.\n"));
16009 
16010 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
16011 		if ((param = strtok_r(p, "=", &val)) != NULL)
16012 			if (nvlist_add_string(mech, param, val) != 0)
16013 				uu_die(gettext("Out of memory.\n"));
16014 
16015 	return (0);
16016 }
16017 
16018 static int
16019 uri_split(char *uri, char **scheme, char **hier_part)
16020 {
16021 	int r = -1;
16022 
16023 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
16024 	    *hier_part == NULL) {
16025 		semerr(gettext("'%s' is not an URI\n"), uri);
16026 		return (r);
16027 	}
16028 
16029 	if ((r = check_uri_scheme(*scheme)) < 0) {
16030 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
16031 		return (r);
16032 	}
16033 
16034 	return (r);
16035 }
16036 
16037 static int
16038 process_uri(nvlist_t *params, char *uri)
16039 {
16040 	char *scheme;
16041 	char *hier_part;
16042 	nvlist_t *mech;
16043 	int index;
16044 	int r;
16045 
16046 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
16047 		return (-1);
16048 
16049 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
16050 		uu_die(gettext("Out of memory.\n"));
16051 
16052 	switch (index) {
16053 	case 0:
16054 		/* error messages displayed by called function */
16055 		r = add_mailto_params(mech, hier_part);
16056 		break;
16057 
16058 	case 1:
16059 		if ((r = add_snmp_params(mech, hier_part)) != 0)
16060 			semerr(gettext("Not valid parameters: '%s'\n"),
16061 			    hier_part);
16062 		break;
16063 
16064 	case 2:
16065 		if ((r = add_syslog_params(mech, hier_part)) != 0)
16066 			semerr(gettext("Not valid parameters: '%s'\n"),
16067 			    hier_part);
16068 		break;
16069 
16070 	default:
16071 		r = -1;
16072 	}
16073 
16074 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
16075 	    mech) != 0)
16076 		uu_die(gettext("Out of memory.\n"));
16077 
16078 	nvlist_free(mech);
16079 	return (r);
16080 }
16081 
16082 static int
16083 set_params(nvlist_t *params, char **p)
16084 {
16085 	char *uri;
16086 
16087 	if (p == NULL)
16088 		/* sanity check */
16089 		uu_die("set_params");
16090 
16091 	while (*p) {
16092 		uri = strip_quotes_and_blanks(*p);
16093 		if (process_uri(params, uri) != 0)
16094 			return (-1);
16095 
16096 		++p;
16097 	}
16098 
16099 	return (0);
16100 }
16101 
16102 static int
16103 setnotify(const char *e, char **p, int global)
16104 {
16105 	char *str = safe_strdup(e);
16106 	char **events;
16107 	int32_t tset;
16108 	int r = -1;
16109 	nvlist_t *nvl, *params;
16110 	char *fmri = NULL;
16111 
16112 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
16113 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
16114 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
16115 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
16116 		uu_die(gettext("Out of memory.\n"));
16117 
16118 	events = tokenize(str, ",");
16119 
16120 	if ((tset = check_tokens(events)) > 0) {
16121 		/* SMF state transitions parameters */
16122 		size_t sz = max_scf_fmri_len + 1;
16123 
16124 		fmri = safe_malloc(sz);
16125 		if (global) {
16126 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
16127 		} else if (get_selection_str(fmri, sz) != 0) {
16128 			goto out;
16129 		}
16130 
16131 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
16132 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
16133 			uu_die(gettext("Out of memory.\n"));
16134 
16135 		if ((r = set_params(params, p)) == 0) {
16136 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
16137 			    params) != 0)
16138 				uu_die(gettext("Out of memory.\n"));
16139 
16140 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
16141 			    nvl) != SCF_SUCCESS) {
16142 				r = -1;
16143 				uu_warn(gettext(
16144 				    "Failed smf_notify_set_params(3SCF): %s\n"),
16145 				    scf_strerror(scf_error()));
16146 			}
16147 		}
16148 	} else if (tset == FMA_TOKENS) {
16149 		/* FMA event parameters */
16150 		if (global) {
16151 			semerr(gettext("Can't use option '-g' with FMA event "
16152 			    "definitions\n"));
16153 			goto out;
16154 		}
16155 
16156 		if ((r = set_params(params, p)) != 0)
16157 			goto out;
16158 
16159 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
16160 			uu_die(gettext("Out of memory.\n"));
16161 
16162 		while (*events) {
16163 			if (smf_notify_set_params(de_tag(*events), nvl) !=
16164 			    SCF_SUCCESS)
16165 				uu_warn(gettext(
16166 				    "Failed smf_notify_set_params(3SCF) for "
16167 				    "event %s: %s\n"), *events,
16168 				    scf_strerror(scf_error()));
16169 			events++;
16170 		}
16171 	} else if (tset == MIXED_TOKENS) {
16172 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
16173 	} else {
16174 		/* Sanity check */
16175 		uu_die(gettext("Invalid input.\n"));
16176 	}
16177 
16178 out:
16179 	nvlist_free(nvl);
16180 	nvlist_free(params);
16181 	free(fmri);
16182 	free(str);
16183 
16184 	return (r);
16185 }
16186 
16187 int
16188 lscf_setnotify(uu_list_t *args)
16189 {
16190 	int argc;
16191 	char **argv = NULL;
16192 	string_list_t *slp;
16193 	int global;
16194 	char *events;
16195 	char **p;
16196 	int i;
16197 	int ret;
16198 
16199 	if ((argc = uu_list_numnodes(args)) < 2)
16200 		goto usage;
16201 
16202 	argv = calloc(argc + 1, sizeof (char *));
16203 	if (argv == NULL)
16204 		uu_die(gettext("Out of memory.\n"));
16205 
16206 	for (slp = uu_list_first(args), i = 0;
16207 	    slp != NULL;
16208 	    slp = uu_list_next(args, slp), ++i)
16209 		argv[i] = slp->str;
16210 
16211 	argv[i] = NULL;
16212 
16213 	if (strcmp(argv[0], "-g") == 0) {
16214 		global = 1;
16215 		events = argv[1];
16216 		p = argv + 2;
16217 	} else {
16218 		global = 0;
16219 		events = argv[0];
16220 		p = argv + 1;
16221 	}
16222 
16223 	ret = setnotify(events, p, global);
16224 
16225 out:
16226 	free(argv);
16227 	return (ret);
16228 
16229 usage:
16230 	ret = -2;
16231 	goto out;
16232 }
16233 
16234 /*
16235  * Creates a list of instance name strings associated with a service. If
16236  * wohandcrafted flag is set, get only instances that have a last-import
16237  * snapshot, instances that were imported via svccfg.
16238  */
16239 static uu_list_t *
16240 create_instance_list(scf_service_t *svc, int wohandcrafted)
16241 {
16242 	scf_snapshot_t  *snap = NULL;
16243 	scf_instance_t  *inst;
16244 	scf_iter_t	*inst_iter;
16245 	uu_list_t	*instances;
16246 	char		*instname;
16247 	int		r;
16248 
16249 	inst_iter = scf_iter_create(g_hndl);
16250 	inst = scf_instance_create(g_hndl);
16251 	if (inst_iter == NULL || inst == NULL) {
16252 		uu_warn(gettext("Could not create instance or iterator\n"));
16253 		scfdie();
16254 	}
16255 
16256 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
16257 		return (instances);
16258 
16259 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
16260 		switch (scf_error()) {
16261 		case SCF_ERROR_CONNECTION_BROKEN:
16262 		case SCF_ERROR_DELETED:
16263 			uu_list_destroy(instances);
16264 			instances = NULL;
16265 			goto out;
16266 
16267 		case SCF_ERROR_HANDLE_MISMATCH:
16268 		case SCF_ERROR_NOT_BOUND:
16269 		case SCF_ERROR_NOT_SET:
16270 		default:
16271 			bad_error("scf_iter_service_instances", scf_error());
16272 		}
16273 	}
16274 
16275 	instname = safe_malloc(max_scf_name_len + 1);
16276 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16277 		if (r == -1) {
16278 			(void) uu_warn(gettext("Unable to iterate through "
16279 			    "instances to create instance list : %s\n"),
16280 			    scf_strerror(scf_error()));
16281 
16282 			uu_list_destroy(instances);
16283 			instances = NULL;
16284 			goto out;
16285 		}
16286 
16287 		/*
16288 		 * If the instance does not have a last-import snapshot
16289 		 * then do not add it to the list as it is a hand-crafted
16290 		 * instance that should not be managed.
16291 		 */
16292 		if (wohandcrafted) {
16293 			if (snap == NULL &&
16294 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
16295 				uu_warn(gettext("Unable to create snapshot "
16296 				    "entity\n"));
16297 				scfdie();
16298 			}
16299 
16300 			if (scf_instance_get_snapshot(inst,
16301 			    snap_lastimport, snap) != 0) {
16302 				switch (scf_error()) {
16303 				case SCF_ERROR_NOT_FOUND :
16304 				case SCF_ERROR_DELETED:
16305 					continue;
16306 
16307 				case SCF_ERROR_CONNECTION_BROKEN:
16308 					uu_list_destroy(instances);
16309 					instances = NULL;
16310 					goto out;
16311 
16312 				case SCF_ERROR_HANDLE_MISMATCH:
16313 				case SCF_ERROR_NOT_BOUND:
16314 				case SCF_ERROR_NOT_SET:
16315 				default:
16316 					bad_error("scf_iter_service_instances",
16317 					    scf_error());
16318 				}
16319 			}
16320 		}
16321 
16322 		if (scf_instance_get_name(inst, instname,
16323 		    max_scf_name_len + 1) < 0) {
16324 			switch (scf_error()) {
16325 			case SCF_ERROR_NOT_FOUND :
16326 				continue;
16327 
16328 			case SCF_ERROR_CONNECTION_BROKEN:
16329 			case SCF_ERROR_DELETED:
16330 				uu_list_destroy(instances);
16331 				instances = NULL;
16332 				goto out;
16333 
16334 			case SCF_ERROR_HANDLE_MISMATCH:
16335 			case SCF_ERROR_NOT_BOUND:
16336 			case SCF_ERROR_NOT_SET:
16337 			default:
16338 				bad_error("scf_iter_service_instances",
16339 				    scf_error());
16340 			}
16341 		}
16342 
16343 		add_string(instances, instname);
16344 	}
16345 
16346 out:
16347 	if (snap)
16348 		scf_snapshot_destroy(snap);
16349 
16350 	scf_instance_destroy(inst);
16351 	scf_iter_destroy(inst_iter);
16352 	free(instname);
16353 	return (instances);
16354 }
16355 
16356 /*
16357  * disable an instance but wait for the instance to
16358  * move out of the running state.
16359  *
16360  * Returns 0 : if the instance did not disable
16361  * Returns non-zero : if the instance disabled.
16362  *
16363  */
16364 static int
16365 disable_instance(scf_instance_t *instance)
16366 {
16367 	char	*fmribuf;
16368 	int	enabled = 10000;
16369 
16370 	if (inst_is_running(instance)) {
16371 		fmribuf = safe_malloc(max_scf_name_len + 1);
16372 		if (scf_instance_to_fmri(instance, fmribuf,
16373 		    max_scf_name_len + 1) < 0) {
16374 			free(fmribuf);
16375 			return (0);
16376 		}
16377 
16378 		/*
16379 		 * If the instance cannot be disabled then return
16380 		 * failure to disable and let the caller decide
16381 		 * if that is of importance.
16382 		 */
16383 		if (smf_disable_instance(fmribuf, 0) != 0) {
16384 			free(fmribuf);
16385 			return (0);
16386 		}
16387 
16388 		while (enabled) {
16389 			if (!inst_is_running(instance))
16390 				break;
16391 
16392 			(void) poll(NULL, 0, 5);
16393 			enabled = enabled - 5;
16394 		}
16395 
16396 		free(fmribuf);
16397 	}
16398 
16399 	return (enabled);
16400 }
16401 
16402 /*
16403  * Function to compare two service_manifest structures.
16404  */
16405 /* ARGSUSED2 */
16406 static int
16407 service_manifest_compare(const void *left, const void *right, void *unused)
16408 {
16409 	service_manifest_t *l = (service_manifest_t *)left;
16410 	service_manifest_t *r = (service_manifest_t *)right;
16411 	int rc;
16412 
16413 	rc = strcmp(l->servicename, r->servicename);
16414 
16415 	return (rc);
16416 }
16417 
16418 /*
16419  * Look for the provided service in the service to manifest
16420  * tree.  If the service exists, and a manifest was provided
16421  * then add the manifest to that service.  If the service
16422  * does not exist, then add the service and manifest to the
16423  * list.
16424  *
16425  * If the manifest is NULL, return the element if found.  If
16426  * the service is not found return NULL.
16427  */
16428 service_manifest_t *
16429 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16430 {
16431 	service_manifest_t	elem;
16432 	service_manifest_t	*fnelem;
16433 	uu_avl_index_t		marker;
16434 
16435 	elem.servicename = svnbuf;
16436 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16437 
16438 	if (mfst) {
16439 		if (fnelem) {
16440 			add_string(fnelem->mfstlist, strdup(mfst));
16441 		} else {
16442 			fnelem = safe_malloc(sizeof (*fnelem));
16443 			fnelem->servicename = safe_strdup(svnbuf);
16444 			if ((fnelem->mfstlist =
16445 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16446 				uu_die(gettext("Could not create property "
16447 				    "list: %s\n"), uu_strerror(uu_error()));
16448 
16449 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16450 
16451 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16452 		}
16453 	}
16454 
16455 	return (fnelem);
16456 }
16457 
16458 /*
16459  * Create the service to manifest avl tree.
16460  *
16461  * Walk each of the manifests currently installed in the supported
16462  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16463  * each of the manifests, inventory the services and add them to
16464  * the tree.
16465  *
16466  * Code that calls this function should make sure fileystem/minimal is online,
16467  * /var is available, since this function walks the /var/svc/manifest directory.
16468  */
16469 static void
16470 create_manifest_tree(void)
16471 {
16472 	manifest_info_t **entry;
16473 	manifest_info_t **manifests;
16474 	uu_list_walk_t	*svcs;
16475 	bundle_t	*b;
16476 	entity_t	*mfsvc;
16477 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16478 	int		c, status;
16479 
16480 	if (service_manifest_pool)
16481 		return;
16482 
16483 	/*
16484 	 * Create the list pool for the service manifest list
16485 	 */
16486 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16487 	    sizeof (service_manifest_t),
16488 	    offsetof(service_manifest_t, svcmfst_node),
16489 	    service_manifest_compare, UU_DEFAULT);
16490 	if (service_manifest_pool == NULL)
16491 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16492 		    uu_strerror(uu_error()));
16493 
16494 	/*
16495 	 * Create the list
16496 	 */
16497 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16498 	    UU_DEFAULT);
16499 	if (service_manifest_tree == NULL)
16500 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16501 		    uu_strerror(uu_error()));
16502 
16503 	/*
16504 	 * Walk the manifests adding the service(s) from each manifest.
16505 	 *
16506 	 * If a service already exists add the manifest to the manifest
16507 	 * list for that service.  This covers the case of a service that
16508 	 * is supported by multiple manifest files.
16509 	 */
16510 	for (c = 0; dirs[c]; c++) {
16511 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16512 		if (status < 0) {
16513 			uu_warn(gettext("file tree walk of %s encountered "
16514 			    "error %s\n"), dirs[c], strerror(errno));
16515 
16516 			uu_avl_destroy(service_manifest_tree);
16517 			service_manifest_tree = NULL;
16518 			return;
16519 		}
16520 
16521 		/*
16522 		 * If a manifest that was in the list is not found
16523 		 * then skip and go to the next manifest file.
16524 		 */
16525 		if (manifests != NULL) {
16526 			for (entry = manifests; *entry != NULL; entry++) {
16527 				b = internal_bundle_new();
16528 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16529 				    SVCCFG_OP_IMPORT) != 0) {
16530 					internal_bundle_free(b);
16531 					continue;
16532 				}
16533 
16534 				svcs = uu_list_walk_start(b->sc_bundle_services,
16535 				    0);
16536 				if (svcs == NULL) {
16537 					internal_bundle_free(b);
16538 					continue;
16539 				}
16540 
16541 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16542 				    NULL) {
16543 					/* Add manifest to service */
16544 					(void) find_add_svc_mfst(mfsvc->sc_name,
16545 					    (*entry)->mi_path);
16546 				}
16547 
16548 				uu_list_walk_end(svcs);
16549 				internal_bundle_free(b);
16550 			}
16551 
16552 			free_manifest_array(manifests);
16553 		}
16554 	}
16555 }
16556 
16557 /*
16558  * Check the manifest history file to see
16559  * if the service was ever installed from
16560  * one of the supported directories.
16561  *
16562  * Return Values :
16563  * 	-1 - if there's error reading manifest history file
16564  *	 1 - if the service is not found
16565  *	 0 - if the service is found
16566  */
16567 static int
16568 check_mfst_history(const char *svcname)
16569 {
16570 	struct stat	st;
16571 	caddr_t		mfsthist_start;
16572 	char		*svnbuf;
16573 	int		fd;
16574 	int		r = 1;
16575 
16576 	fd = open(MFSTHISTFILE, O_RDONLY);
16577 	if (fd == -1) {
16578 		uu_warn(gettext("Unable to open the history file\n"));
16579 		return (-1);
16580 	}
16581 
16582 	if (fstat(fd, &st) == -1) {
16583 		uu_warn(gettext("Unable to stat the history file\n"));
16584 		return (-1);
16585 	}
16586 
16587 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16588 	    MAP_PRIVATE, fd, 0);
16589 
16590 	(void) close(fd);
16591 	if (mfsthist_start == MAP_FAILED ||
16592 	    *(mfsthist_start + st.st_size) != '\0') {
16593 		(void) munmap(mfsthist_start, st.st_size);
16594 		return (-1);
16595 	}
16596 
16597 	/*
16598 	 * The manifest history file is a space delimited list
16599 	 * of service and instance to manifest linkage.  Adding
16600 	 * a space to the end of the service name so to get only
16601 	 * the service that is being searched for.
16602 	 */
16603 	svnbuf = uu_msprintf("%s ", svcname);
16604 	if (svnbuf == NULL)
16605 		uu_die(gettext("Out of memory"));
16606 
16607 	if (strstr(mfsthist_start, svnbuf) != NULL)
16608 		r = 0;
16609 
16610 	(void) munmap(mfsthist_start, st.st_size);
16611 	uu_free(svnbuf);
16612 	return (r);
16613 }
16614 
16615 /*
16616  * Take down each of the instances in the service
16617  * and remove them, then delete the service.
16618  */
16619 static void
16620 teardown_service(scf_service_t *svc, const char *svnbuf)
16621 {
16622 	scf_instance_t	*instance;
16623 	scf_iter_t	*iter;
16624 	int		r;
16625 
16626 	safe_printf(gettext("Delete service %s as there are no "
16627 	    "supporting manifests\n"), svnbuf);
16628 
16629 	instance = scf_instance_create(g_hndl);
16630 	iter = scf_iter_create(g_hndl);
16631 	if (iter == NULL || instance == NULL) {
16632 		uu_warn(gettext("Unable to create supporting entities to "
16633 		    "teardown the service\n"));
16634 		uu_warn(gettext("scf error is : %s\n"),
16635 		    scf_strerror(scf_error()));
16636 		scfdie();
16637 	}
16638 
16639 	if (scf_iter_service_instances(iter, svc) != 0) {
16640 		switch (scf_error()) {
16641 		case SCF_ERROR_CONNECTION_BROKEN:
16642 		case SCF_ERROR_DELETED:
16643 			goto out;
16644 
16645 		case SCF_ERROR_HANDLE_MISMATCH:
16646 		case SCF_ERROR_NOT_BOUND:
16647 		case SCF_ERROR_NOT_SET:
16648 		default:
16649 			bad_error("scf_iter_service_instances",
16650 			    scf_error());
16651 		}
16652 	}
16653 
16654 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16655 		if (r == -1) {
16656 			uu_warn(gettext("Error - %s\n"),
16657 			    scf_strerror(scf_error()));
16658 			goto out;
16659 		}
16660 
16661 		(void) disable_instance(instance);
16662 	}
16663 
16664 	/*
16665 	 * Delete the service... forcing the deletion in case
16666 	 * any of the instances did not disable.
16667 	 */
16668 	(void) lscf_service_delete(svc, 1);
16669 out:
16670 	scf_instance_destroy(instance);
16671 	scf_iter_destroy(iter);
16672 }
16673 
16674 /*
16675  * Get the list of instances supported by the manifest
16676  * file.
16677  *
16678  * Return 0 if there are no instances.
16679  *
16680  * Return -1 if there are errors attempting to collect instances.
16681  *
16682  * Return the count of instances found if there are no errors.
16683  *
16684  */
16685 static int
16686 check_instance_support(char *mfstfile, const char *svcname,
16687     uu_list_t *instances)
16688 {
16689 	uu_list_walk_t	*svcs, *insts;
16690 	uu_list_t	*ilist;
16691 	bundle_t	*b;
16692 	entity_t	*mfsvc, *mfinst;
16693 	const char	*svcn;
16694 	int		rminstcnt = 0;
16695 
16696 
16697 	b = internal_bundle_new();
16698 
16699 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16700 		/*
16701 		 * Unable to process the manifest file for
16702 		 * instance support, so just return as
16703 		 * don't want to remove instances that could
16704 		 * not be accounted for that might exist here.
16705 		 */
16706 		internal_bundle_free(b);
16707 		return (0);
16708 	}
16709 
16710 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16711 	if (svcs == NULL) {
16712 		internal_bundle_free(b);
16713 		return (0);
16714 	}
16715 
16716 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16717 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16718 
16719 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16720 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16721 			break;
16722 	}
16723 	uu_list_walk_end(svcs);
16724 
16725 	if (mfsvc == NULL) {
16726 		internal_bundle_free(b);
16727 		return (-1);
16728 	}
16729 
16730 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16731 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16732 		internal_bundle_free(b);
16733 		return (0);
16734 	}
16735 
16736 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16737 		/*
16738 		 * Remove the instance from the instances list.
16739 		 * The unaccounted for instances will be removed
16740 		 * from the service once all manifests are
16741 		 * processed.
16742 		 */
16743 		(void) remove_string(instances,
16744 		    mfinst->sc_name);
16745 		rminstcnt++;
16746 	}
16747 
16748 	uu_list_walk_end(insts);
16749 	internal_bundle_free(b);
16750 
16751 	return (rminstcnt);
16752 }
16753 
16754 /*
16755  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16756  * 'false' to indicate there's no manifest file(s) found for the service.
16757  */
16758 static void
16759 svc_add_no_support(scf_service_t *svc)
16760 {
16761 	char	*pname;
16762 
16763 	/* Add no support */
16764 	cur_svc = svc;
16765 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16766 		return;
16767 
16768 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16769 	if (pname == NULL)
16770 		uu_die(gettext("Out of memory.\n"));
16771 
16772 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16773 
16774 	uu_free(pname);
16775 	cur_svc = NULL;
16776 }
16777 
16778 /*
16779  * This function handles all upgrade scenarios for a service that doesn't have
16780  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16781  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16782  * manifest(s) mapping. Manifests under supported directories are inventoried
16783  * and a property is added for each file that delivers configuration to the
16784  * service.  A service that has no corresponding manifest files (deleted) are
16785  * removed from repository.
16786  *
16787  * Unsupported services:
16788  *
16789  * A service is considered unsupported if there is no corresponding manifest
16790  * in the supported directories for that service and the service isn't in the
16791  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16792  * services and instances that were delivered by Solaris before the introduction
16793  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16794  * the path to the manifest file that defined the service or instance.
16795  *
16796  * Another type of unsupported services is 'handcrafted' services,
16797  * programmatically created services or services created by dependent entries
16798  * in other manifests. A handcrafted service is identified by its lack of any
16799  * instance containing last-import snapshot which is created during svccfg
16800  * import.
16801  *
16802  * This function sets a flag for unsupported services by setting services'
16803  * SCF_PG_MANIFESTFILES/support property to false.
16804  */
16805 static void
16806 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16807 {
16808 	service_manifest_t	*elem;
16809 	uu_list_walk_t		*mfwalk;
16810 	string_list_t		*mfile;
16811 	uu_list_t		*instances;
16812 	const char		*sname;
16813 	char			*pname;
16814 	int			r;
16815 
16816 	/*
16817 	 * Since there's no guarantee manifests under /var are available during
16818 	 * early import, don't perform any upgrade during early import.
16819 	 */
16820 	if (IGNORE_VAR)
16821 		return;
16822 
16823 	if (service_manifest_tree == NULL) {
16824 		create_manifest_tree();
16825 	}
16826 
16827 	/*
16828 	 * Find service's supporting manifest(s) after
16829 	 * stripping off the svc:/ prefix that is part
16830 	 * of the fmri that is not used in the service
16831 	 * manifest bundle list.
16832 	 */
16833 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16834 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16835 	elem = find_add_svc_mfst(sname, NULL);
16836 	if (elem == NULL) {
16837 
16838 		/*
16839 		 * A handcrafted service, one that has no instance containing
16840 		 * last-import snapshot, should get unsupported flag.
16841 		 */
16842 		instances = create_instance_list(svc, 1);
16843 		if (instances == NULL) {
16844 			uu_warn(gettext("Unable to create instance list %s\n"),
16845 			    svcname);
16846 			return;
16847 		}
16848 
16849 		if (uu_list_numnodes(instances) == 0) {
16850 			svc_add_no_support(svc);
16851 			return;
16852 		}
16853 
16854 		/*
16855 		 * If the service is in the history file, and its supporting
16856 		 * manifests are not found, we can safely delete the service
16857 		 * because its manifests are removed from the system.
16858 		 *
16859 		 * Services not found in the history file are not delivered by
16860 		 * Solaris and/or delivered outside supported directories, set
16861 		 * unsupported flag for these services.
16862 		 */
16863 		r = check_mfst_history(svcname);
16864 		if (r == -1)
16865 			return;
16866 
16867 		if (r) {
16868 			/* Set unsupported flag for service  */
16869 			svc_add_no_support(svc);
16870 		} else {
16871 			/* Delete the service */
16872 			teardown_service(svc, svcname);
16873 		}
16874 
16875 		return;
16876 	}
16877 
16878 	/*
16879 	 * Walk through the list of manifests and add them
16880 	 * to the service.
16881 	 *
16882 	 * Create a manifestfiles pg and add the property.
16883 	 */
16884 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16885 	if (mfwalk == NULL)
16886 		return;
16887 
16888 	cur_svc = svc;
16889 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16890 	if (r != 0) {
16891 		cur_svc = NULL;
16892 		return;
16893 	}
16894 
16895 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16896 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16897 		    mhash_filename_to_propname(mfile->str, 0));
16898 		if (pname == NULL)
16899 			uu_die(gettext("Out of memory.\n"));
16900 
16901 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16902 		uu_free(pname);
16903 	}
16904 	uu_list_walk_end(mfwalk);
16905 
16906 	cur_svc = NULL;
16907 }
16908 
16909 /*
16910  * Take a service and process the manifest file entires to see if
16911  * there is continued support for the service and instances.  If
16912  * not cleanup as appropriate.
16913  *
16914  * If a service does not have a manifest files entry flag it for
16915  * upgrade and return.
16916  *
16917  * For each manifestfiles property check if the manifest file is
16918  * under the supported /lib/svc/manifest or /var/svc/manifest path
16919  * and if not then return immediately as this service is not supported
16920  * by the cleanup mechanism and should be ignored.
16921  *
16922  * For each manifest file that is supported, check to see if the
16923  * file exists.  If not then remove the manifest file property
16924  * from the service and the smf/manifest hash table.  If the manifest
16925  * file exists then verify that it supports the instances that are
16926  * part of the service.
16927  *
16928  * Once all manifest files have been accounted for remove any instances
16929  * that are no longer supported in the service.
16930  *
16931  * Return values :
16932  * 0 - Successfully processed the service
16933  * non-zero - failed to process the service
16934  *
16935  * On most errors, will just return to wait and get the next service,
16936  * unless in case of unable to create the needed structures which is
16937  * most likely a fatal error that is not going to be recoverable.
16938  */
16939 int
16940 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16941 {
16942 	struct mpg_mfile	*mpntov;
16943 	struct mpg_mfile	**mpvarry = NULL;
16944 	scf_service_t		*svc;
16945 	scf_propertygroup_t	*mpg;
16946 	scf_property_t		*mp;
16947 	scf_value_t		*mv;
16948 	scf_iter_t		*mi;
16949 	scf_instance_t		*instance;
16950 	uu_list_walk_t		*insts;
16951 	uu_list_t		*instances = NULL;
16952 	boolean_t		activity = (boolean_t)act;
16953 	char			*mpnbuf;
16954 	char			*mpvbuf;
16955 	char			*pgpropbuf;
16956 	int			mfstcnt, rminstct, instct, mfstmax;
16957 	int			index;
16958 	int			r = 0;
16959 
16960 	assert(g_hndl != NULL);
16961 	assert(wip->svc != NULL);
16962 	assert(wip->fmri != NULL);
16963 
16964 	svc = wip->svc;
16965 
16966 	mpg = scf_pg_create(g_hndl);
16967 	mp = scf_property_create(g_hndl);
16968 	mi = scf_iter_create(g_hndl);
16969 	mv = scf_value_create(g_hndl);
16970 	instance = scf_instance_create(g_hndl);
16971 
16972 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16973 	    instance == NULL) {
16974 		uu_warn(gettext("Unable to create the supporting entities\n"));
16975 		uu_warn(gettext("scf error is : %s\n"),
16976 		    scf_strerror(scf_error()));
16977 		scfdie();
16978 	}
16979 
16980 	/*
16981 	 * Get the manifestfiles property group to be parsed for
16982 	 * files existence.
16983 	 */
16984 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16985 		switch (scf_error()) {
16986 		case SCF_ERROR_NOT_FOUND:
16987 			upgrade_svc_mfst_connection(svc, wip->fmri);
16988 			break;
16989 		case SCF_ERROR_DELETED:
16990 		case SCF_ERROR_CONNECTION_BROKEN:
16991 			goto out;
16992 
16993 		case SCF_ERROR_HANDLE_MISMATCH:
16994 		case SCF_ERROR_NOT_BOUND:
16995 		case SCF_ERROR_NOT_SET:
16996 		default:
16997 			bad_error("scf_iter_pg_properties",
16998 			    scf_error());
16999 		}
17000 
17001 		goto out;
17002 	}
17003 
17004 	/*
17005 	 * Iterate through each of the manifestfiles properties
17006 	 * to determine what manifestfiles are available.
17007 	 *
17008 	 * If a manifest file is supported then increment the
17009 	 * count and therefore the service is safe.
17010 	 */
17011 	if (scf_iter_pg_properties(mi, mpg) != 0) {
17012 		switch (scf_error()) {
17013 		case SCF_ERROR_DELETED:
17014 		case SCF_ERROR_CONNECTION_BROKEN:
17015 			goto out;
17016 
17017 		case SCF_ERROR_HANDLE_MISMATCH:
17018 		case SCF_ERROR_NOT_BOUND:
17019 		case SCF_ERROR_NOT_SET:
17020 		default:
17021 			bad_error("scf_iter_pg_properties",
17022 			    scf_error());
17023 		}
17024 	}
17025 
17026 	mfstcnt = 0;
17027 	mfstmax = MFSTFILE_MAX;
17028 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
17029 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
17030 		if (r == -1)
17031 			bad_error(gettext("Unable to iterate through "
17032 			    "manifestfiles properties : %s"),
17033 			    scf_error());
17034 
17035 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
17036 		mpnbuf = safe_malloc(max_scf_name_len + 1);
17037 		mpvbuf = safe_malloc(max_scf_value_len + 1);
17038 		mpntov->mpg = mpnbuf;
17039 		mpntov->mfile = mpvbuf;
17040 		mpntov->access = 1;
17041 		if (scf_property_get_name(mp, mpnbuf,
17042 		    max_scf_name_len + 1) < 0) {
17043 			uu_warn(gettext("Unable to get manifest file "
17044 			    "property : %s\n"),
17045 			    scf_strerror(scf_error()));
17046 
17047 			switch (scf_error()) {
17048 			case SCF_ERROR_DELETED:
17049 			case SCF_ERROR_CONNECTION_BROKEN:
17050 				r = scferror2errno(scf_error());
17051 				goto out_free;
17052 
17053 			case SCF_ERROR_HANDLE_MISMATCH:
17054 			case SCF_ERROR_NOT_BOUND:
17055 			case SCF_ERROR_NOT_SET:
17056 			default:
17057 				bad_error("scf_iter_pg_properties",
17058 				    scf_error());
17059 			}
17060 		}
17061 
17062 		/*
17063 		 * The support property is a boolean value that indicates
17064 		 * if the service is supported for manifest file deletion.
17065 		 * Currently at this time there is no code that sets this
17066 		 * value to true.  So while we could just let this be caught
17067 		 * by the support check below, in the future this by be set
17068 		 * to true and require processing.  So for that, go ahead
17069 		 * and check here, and just return if false.  Otherwise,
17070 		 * fall through expecting that other support checks will
17071 		 * handle the entries.
17072 		 */
17073 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
17074 			uint8_t	support;
17075 
17076 			if (scf_property_get_value(mp, mv) != 0 ||
17077 			    scf_value_get_boolean(mv, &support) != 0) {
17078 				uu_warn(gettext("Unable to get the manifest "
17079 				    "support value: %s\n"),
17080 				    scf_strerror(scf_error()));
17081 
17082 				switch (scf_error()) {
17083 				case SCF_ERROR_DELETED:
17084 				case SCF_ERROR_CONNECTION_BROKEN:
17085 					r = scferror2errno(scf_error());
17086 					goto out_free;
17087 
17088 				case SCF_ERROR_HANDLE_MISMATCH:
17089 				case SCF_ERROR_NOT_BOUND:
17090 				case SCF_ERROR_NOT_SET:
17091 				default:
17092 					bad_error("scf_iter_pg_properties",
17093 					    scf_error());
17094 				}
17095 			}
17096 
17097 			if (support == B_FALSE)
17098 				goto out_free;
17099 		}
17100 
17101 		/*
17102 		 * Anything with a manifest outside of the supported
17103 		 * directories, immediately bail out because that makes
17104 		 * this service non-supported.  We don't even want
17105 		 * to do instance processing in this case because the
17106 		 * instances could be part of the non-supported manifest.
17107 		 */
17108 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
17109 			/*
17110 			 * Manifest is not in /lib/svc, so we need to
17111 			 * consider the /var/svc case.
17112 			 */
17113 			if (strncmp(mpnbuf, VARSVC_PR,
17114 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
17115 				/*
17116 				 * Either the manifest is not in /var/svc or
17117 				 * /var is not yet mounted.  We ignore the
17118 				 * manifest either because it is not in a
17119 				 * standard location or because we cannot
17120 				 * currently access the manifest.
17121 				 */
17122 				goto out_free;
17123 			}
17124 		}
17125 
17126 		/*
17127 		 * Get the value to of the manifest file for this entry
17128 		 * for access verification and instance support
17129 		 * verification if it still exists.
17130 		 *
17131 		 * During Early Manifest Import if the manifest is in
17132 		 * /var/svc then it may not yet be available for checking
17133 		 * so we must determine if /var/svc is available.  If not
17134 		 * then defer until Late Manifest Import to cleanup.
17135 		 */
17136 		if (scf_property_get_value(mp, mv) != 0) {
17137 			uu_warn(gettext("Unable to get the manifest file "
17138 			    "value: %s\n"),
17139 			    scf_strerror(scf_error()));
17140 
17141 			switch (scf_error()) {
17142 			case SCF_ERROR_DELETED:
17143 			case SCF_ERROR_CONNECTION_BROKEN:
17144 				r = scferror2errno(scf_error());
17145 				goto out_free;
17146 
17147 			case SCF_ERROR_HANDLE_MISMATCH:
17148 			case SCF_ERROR_NOT_BOUND:
17149 			case SCF_ERROR_NOT_SET:
17150 			default:
17151 				bad_error("scf_property_get_value",
17152 				    scf_error());
17153 			}
17154 		}
17155 
17156 		if (scf_value_get_astring(mv, mpvbuf,
17157 		    max_scf_value_len + 1) < 0) {
17158 			uu_warn(gettext("Unable to get the manifest "
17159 			    "file : %s\n"),
17160 			    scf_strerror(scf_error()));
17161 
17162 			switch (scf_error()) {
17163 			case SCF_ERROR_DELETED:
17164 			case SCF_ERROR_CONNECTION_BROKEN:
17165 				r = scferror2errno(scf_error());
17166 				goto out_free;
17167 
17168 			case SCF_ERROR_HANDLE_MISMATCH:
17169 			case SCF_ERROR_NOT_BOUND:
17170 			case SCF_ERROR_NOT_SET:
17171 			default:
17172 				bad_error("scf_value_get_astring",
17173 				    scf_error());
17174 			}
17175 		}
17176 
17177 		mpvarry[mfstcnt] = mpntov;
17178 		mfstcnt++;
17179 
17180 		/*
17181 		 * Check for the need to reallocate array
17182 		 */
17183 		if (mfstcnt >= (mfstmax - 1)) {
17184 			struct mpg_mfile **newmpvarry;
17185 
17186 			mfstmax = mfstmax * 2;
17187 			newmpvarry = realloc(mpvarry,
17188 			    sizeof (struct mpg_mfile *) * mfstmax);
17189 
17190 			if (newmpvarry == NULL)
17191 				goto out_free;
17192 
17193 			mpvarry = newmpvarry;
17194 		}
17195 
17196 		mpvarry[mfstcnt] = NULL;
17197 	}
17198 
17199 	for (index = 0; mpvarry[index]; index++) {
17200 		mpntov = mpvarry[index];
17201 
17202 		/*
17203 		 * Check to see if the manifestfile is accessable, if so hand
17204 		 * this service and manifestfile off to be processed for
17205 		 * instance support.
17206 		 */
17207 		mpnbuf = mpntov->mpg;
17208 		mpvbuf = mpntov->mfile;
17209 		if (access(mpvbuf, F_OK) != 0) {
17210 			mpntov->access = 0;
17211 			activity++;
17212 			mfstcnt--;
17213 			/* Remove the entry from the service */
17214 			cur_svc = svc;
17215 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
17216 			    mpnbuf);
17217 			if (pgpropbuf == NULL)
17218 				uu_die(gettext("Out of memory.\n"));
17219 
17220 			lscf_delprop(pgpropbuf);
17221 			cur_svc = NULL;
17222 
17223 			uu_free(pgpropbuf);
17224 		}
17225 	}
17226 
17227 	/*
17228 	 * If mfstcnt is 0, none of the manifests that supported the service
17229 	 * existed so remove the service.
17230 	 */
17231 	if (mfstcnt == 0) {
17232 		teardown_service(svc, wip->fmri);
17233 
17234 		goto out_free;
17235 	}
17236 
17237 	if (activity) {
17238 		int	nosvcsupport = 0;
17239 
17240 		/*
17241 		 * If the list of service instances is NULL then
17242 		 * create the list.
17243 		 */
17244 		instances = create_instance_list(svc, 1);
17245 		if (instances == NULL) {
17246 			uu_warn(gettext("Unable to create instance list %s\n"),
17247 			    wip->fmri);
17248 			goto out_free;
17249 		}
17250 
17251 		rminstct = uu_list_numnodes(instances);
17252 		instct = rminstct;
17253 
17254 		for (index = 0; mpvarry[index]; index++) {
17255 			mpntov = mpvarry[index];
17256 			if (mpntov->access == 0)
17257 				continue;
17258 
17259 			mpnbuf = mpntov->mpg;
17260 			mpvbuf = mpntov->mfile;
17261 			r = check_instance_support(mpvbuf, wip->fmri,
17262 			    instances);
17263 			if (r == -1) {
17264 				nosvcsupport++;
17265 			} else {
17266 				rminstct -= r;
17267 			}
17268 		}
17269 
17270 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17271 			teardown_service(svc, wip->fmri);
17272 
17273 			goto out_free;
17274 		}
17275 	}
17276 
17277 	/*
17278 	 * If there are instances left on the instance list, then
17279 	 * we must remove them.
17280 	 */
17281 	if (instances != NULL && uu_list_numnodes(instances)) {
17282 		string_list_t *sp;
17283 
17284 		insts = uu_list_walk_start(instances, 0);
17285 		while ((sp = uu_list_walk_next(insts)) != NULL) {
17286 			/*
17287 			 * Remove the instance from the instances list.
17288 			 */
17289 			safe_printf(gettext("Delete instance %s from "
17290 			    "service %s\n"), sp->str, wip->fmri);
17291 			if (scf_service_get_instance(svc, sp->str,
17292 			    instance) != SCF_SUCCESS) {
17293 				(void) uu_warn("scf_error - %s\n",
17294 				    scf_strerror(scf_error()));
17295 
17296 				continue;
17297 			}
17298 
17299 			(void) disable_instance(instance);
17300 
17301 			(void) lscf_instance_delete(instance, 1);
17302 		}
17303 		scf_instance_destroy(instance);
17304 		uu_list_walk_end(insts);
17305 	}
17306 
17307 out_free:
17308 	if (mpvarry) {
17309 		struct mpg_mfile *fmpntov;
17310 
17311 		for (index = 0; mpvarry[index]; index++) {
17312 			fmpntov  = mpvarry[index];
17313 			if (fmpntov->mpg == mpnbuf)
17314 				mpnbuf = NULL;
17315 			free(fmpntov->mpg);
17316 
17317 			if (fmpntov->mfile == mpvbuf)
17318 				mpvbuf = NULL;
17319 			free(fmpntov->mfile);
17320 
17321 			if (fmpntov == mpntov)
17322 				mpntov = NULL;
17323 			free(fmpntov);
17324 		}
17325 		if (mpnbuf)
17326 			free(mpnbuf);
17327 		if (mpvbuf)
17328 			free(mpvbuf);
17329 		if (mpntov)
17330 			free(mpntov);
17331 
17332 		free(mpvarry);
17333 	}
17334 out:
17335 	scf_pg_destroy(mpg);
17336 	scf_property_destroy(mp);
17337 	scf_iter_destroy(mi);
17338 	scf_value_destroy(mv);
17339 
17340 	return (0);
17341 }
17342 
17343 /*
17344  * Take the service and search for the manifestfiles property
17345  * in each of the property groups.  If the manifest file
17346  * associated with the property does not exist then remove
17347  * the property group.
17348  */
17349 int
17350 lscf_hash_cleanup()
17351 {
17352 	scf_service_t		*svc;
17353 	scf_scope_t		*scope;
17354 	scf_propertygroup_t	*pg;
17355 	scf_property_t		*prop;
17356 	scf_value_t		*val;
17357 	scf_iter_t		*iter;
17358 	char			*pgname = NULL;
17359 	char			*mfile = NULL;
17360 	int			r;
17361 
17362 	svc = scf_service_create(g_hndl);
17363 	scope = scf_scope_create(g_hndl);
17364 	pg = scf_pg_create(g_hndl);
17365 	prop = scf_property_create(g_hndl);
17366 	val = scf_value_create(g_hndl);
17367 	iter = scf_iter_create(g_hndl);
17368 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17369 	    svc == NULL || scope == NULL) {
17370 		uu_warn(gettext("Unable to create a property group, or "
17371 		    "property\n"));
17372 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17373 		    "pg is not NULL");
17374 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17375 		    "prop is not NULL");
17376 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17377 		    "val is not NULL");
17378 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17379 		    "iter is not NULL");
17380 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17381 		    "svc is not NULL");
17382 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17383 		    "scope is not NULL");
17384 		uu_warn(gettext("scf error is : %s\n"),
17385 		    scf_strerror(scf_error()));
17386 		scfdie();
17387 	}
17388 
17389 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17390 		switch (scf_error()) {
17391 		case SCF_ERROR_CONNECTION_BROKEN:
17392 		case SCF_ERROR_NOT_FOUND:
17393 			goto out;
17394 
17395 		case SCF_ERROR_HANDLE_MISMATCH:
17396 		case SCF_ERROR_NOT_BOUND:
17397 		case SCF_ERROR_INVALID_ARGUMENT:
17398 		default:
17399 			bad_error("scf_handle_get_scope", scf_error());
17400 		}
17401 	}
17402 
17403 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17404 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17405 		    HASH_SVC);
17406 		goto out;
17407 	}
17408 
17409 	pgname = safe_malloc(max_scf_name_len + 1);
17410 	mfile = safe_malloc(max_scf_value_len + 1);
17411 
17412 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17413 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17414 		    scf_strerror(scf_error()));
17415 		goto out;
17416 	}
17417 
17418 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17419 		if (r == -1)
17420 			goto out;
17421 
17422 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17423 			switch (scf_error()) {
17424 			case SCF_ERROR_DELETED:
17425 				return (ENODEV);
17426 
17427 			case SCF_ERROR_CONNECTION_BROKEN:
17428 				return (ECONNABORTED);
17429 
17430 			case SCF_ERROR_NOT_SET:
17431 			case SCF_ERROR_NOT_BOUND:
17432 			default:
17433 				bad_error("scf_pg_get_name", scf_error());
17434 			}
17435 		}
17436 		if (IGNORE_VAR) {
17437 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17438 				continue;
17439 		}
17440 
17441 		/*
17442 		 * If unable to get the property continue as this is an
17443 		 * entry that has no location to check against.
17444 		 */
17445 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17446 			continue;
17447 		}
17448 
17449 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17450 			uu_warn(gettext("Unable to get value from %s\n"),
17451 			    pgname);
17452 
17453 			switch (scf_error()) {
17454 			case SCF_ERROR_DELETED:
17455 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17456 			case SCF_ERROR_NOT_FOUND:
17457 			case SCF_ERROR_NOT_SET:
17458 				continue;
17459 
17460 			case SCF_ERROR_CONNECTION_BROKEN:
17461 				r = scferror2errno(scf_error());
17462 				goto out;
17463 
17464 			case SCF_ERROR_HANDLE_MISMATCH:
17465 			case SCF_ERROR_NOT_BOUND:
17466 			default:
17467 				bad_error("scf_property_get_value",
17468 				    scf_error());
17469 			}
17470 		}
17471 
17472 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17473 		    == -1) {
17474 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17475 			    pgname, scf_strerror(scf_error()));
17476 
17477 			switch (scf_error()) {
17478 			case SCF_ERROR_NOT_SET:
17479 			case SCF_ERROR_TYPE_MISMATCH:
17480 				continue;
17481 
17482 			default:
17483 				bad_error("scf_value_get_astring", scf_error());
17484 			}
17485 		}
17486 
17487 		if (access(mfile, F_OK) == 0)
17488 			continue;
17489 
17490 		(void) scf_pg_delete(pg);
17491 	}
17492 
17493 out:
17494 	scf_scope_destroy(scope);
17495 	scf_service_destroy(svc);
17496 	scf_pg_destroy(pg);
17497 	scf_property_destroy(prop);
17498 	scf_value_destroy(val);
17499 	scf_iter_destroy(iter);
17500 	free(pgname);
17501 	free(mfile);
17502 
17503 	return (0);
17504 }
17505 
17506 #ifndef NATIVE_BUILD
17507 /* ARGSUSED */
17508 CPL_MATCH_FN(complete_select)
17509 {
17510 	const char *arg0, *arg1, *arg1end;
17511 	int word_start, err = 0, r;
17512 	size_t len;
17513 	char *buf;
17514 
17515 	lscf_prep_hndl();
17516 
17517 	arg0 = line + strspn(line, " \t");
17518 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17519 
17520 	arg1 = arg0 + sizeof ("select") - 1;
17521 	arg1 += strspn(arg1, " \t");
17522 	word_start = arg1 - line;
17523 
17524 	arg1end = arg1 + strcspn(arg1, " \t");
17525 	if (arg1end < line + word_end)
17526 		return (0);
17527 
17528 	len = line + word_end - arg1;
17529 
17530 	buf = safe_malloc(max_scf_name_len + 1);
17531 
17532 	if (cur_snap != NULL) {
17533 		return (0);
17534 	} else if (cur_inst != NULL) {
17535 		return (0);
17536 	} else if (cur_svc != NULL) {
17537 		scf_instance_t *inst;
17538 		scf_iter_t *iter;
17539 
17540 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17541 		    (iter = scf_iter_create(g_hndl)) == NULL)
17542 			scfdie();
17543 
17544 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17545 			scfdie();
17546 
17547 		for (;;) {
17548 			r = scf_iter_next_instance(iter, inst);
17549 			if (r == 0)
17550 				break;
17551 			if (r != 1)
17552 				scfdie();
17553 
17554 			if (scf_instance_get_name(inst, buf,
17555 			    max_scf_name_len + 1) < 0)
17556 				scfdie();
17557 
17558 			if (strncmp(buf, arg1, len) == 0) {
17559 				err = cpl_add_completion(cpl, line, word_start,
17560 				    word_end, buf + len, "", " ");
17561 				if (err != 0)
17562 					break;
17563 			}
17564 		}
17565 
17566 		scf_iter_destroy(iter);
17567 		scf_instance_destroy(inst);
17568 
17569 		return (err);
17570 	} else {
17571 		scf_service_t *svc;
17572 		scf_iter_t *iter;
17573 
17574 		assert(cur_scope != NULL);
17575 
17576 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17577 		    (iter = scf_iter_create(g_hndl)) == NULL)
17578 			scfdie();
17579 
17580 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17581 			scfdie();
17582 
17583 		for (;;) {
17584 			r = scf_iter_next_service(iter, svc);
17585 			if (r == 0)
17586 				break;
17587 			if (r != 1)
17588 				scfdie();
17589 
17590 			if (scf_service_get_name(svc, buf,
17591 			    max_scf_name_len + 1) < 0)
17592 				scfdie();
17593 
17594 			if (strncmp(buf, arg1, len) == 0) {
17595 				err = cpl_add_completion(cpl, line, word_start,
17596 				    word_end, buf + len, "", " ");
17597 				if (err != 0)
17598 					break;
17599 			}
17600 		}
17601 
17602 		scf_iter_destroy(iter);
17603 		scf_service_destroy(svc);
17604 
17605 		return (err);
17606 	}
17607 }
17608 
17609 /* ARGSUSED */
17610 CPL_MATCH_FN(complete_command)
17611 {
17612 	uint32_t scope = 0;
17613 
17614 	if (cur_snap != NULL)
17615 		scope = CS_SNAP;
17616 	else if (cur_inst != NULL)
17617 		scope = CS_INST;
17618 	else if (cur_svc != NULL)
17619 		scope = CS_SVC;
17620 	else
17621 		scope = CS_SCOPE;
17622 
17623 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17624 }
17625 #endif	/* NATIVE_BUILD */
17626