xref: /titanic_51/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision 45e662eb8429b38c18931ebeed30f2e5287ae51b)
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  */
25 
26 
27 #include <alloca.h>
28 #include <assert.h>
29 #include <ctype.h>
30 #include <door.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <fnmatch.h>
34 #include <inttypes.h>
35 #include <libintl.h>
36 #include <libnvpair.h>
37 #include <libscf.h>
38 #include <libscf_priv.h>
39 #include <libtecla.h>
40 #include <libuutil.h>
41 #include <limits.h>
42 #include <locale.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <strings.h>
46 #include <unistd.h>
47 #include <wait.h>
48 #include <poll.h>
49 
50 #include <libxml/tree.h>
51 
52 #include <sys/param.h>
53 
54 #include <sys/stat.h>
55 #include <sys/mman.h>
56 
57 #include "svccfg.h"
58 #include "notify_params.h"
59 #include "manifest_hash.h"
60 #include "manifest_find.h"
61 
62 /* The colon namespaces in each entity (each followed by a newline). */
63 #define	COLON_NAMESPACES	":properties\n"
64 
65 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
66 
67 /* These are characters which the lexer requires to be in double-quotes. */
68 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
69 
70 #define	HASH_SIZE		16
71 #define	HASH_PG_TYPE		"framework"
72 #define	HASH_PG_FLAGS		0
73 #define	HASH_PROP		"md5sum"
74 
75 /*
76  * Indentation used in the output of the describe subcommand.
77  */
78 #define	TMPL_VALUE_INDENT	"  "
79 #define	TMPL_INDENT		"    "
80 #define	TMPL_INDENT_2X		"        "
81 #define	TMPL_CHOICE_INDENT	"      "
82 
83 /*
84  * Directory locations for manifests
85  */
86 #define	VARSVC_DIR		"/var/svc/manifest"
87 #define	LIBSVC_DIR		"/lib/svc/manifest"
88 #define	VARSVC_PR		"var_svc_manifest"
89 #define	LIBSVC_PR		"lib_svc_manifest"
90 #define	MFSTFILEPR		"manifestfile"
91 
92 #define	SUPPORTPROP		"support"
93 
94 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
95 
96 #define	MFSTFILE_MAX		16
97 
98 /*
99  * These are the classes of elements which may appear as children of service
100  * or instance elements in XML manifests.
101  */
102 struct entity_elts {
103 	xmlNodePtr	create_default_instance;
104 	xmlNodePtr	single_instance;
105 	xmlNodePtr	restarter;
106 	xmlNodePtr	dependencies;
107 	xmlNodePtr	dependents;
108 	xmlNodePtr	method_context;
109 	xmlNodePtr	exec_methods;
110 	xmlNodePtr	notify_params;
111 	xmlNodePtr	property_groups;
112 	xmlNodePtr	instances;
113 	xmlNodePtr	stability;
114 	xmlNodePtr	template;
115 };
116 
117 /*
118  * Likewise for property_group elements.
119  */
120 struct pg_elts {
121 	xmlNodePtr	stability;
122 	xmlNodePtr	propvals;
123 	xmlNodePtr	properties;
124 };
125 
126 /*
127  * Likewise for template elements.
128  */
129 struct template_elts {
130 	xmlNodePtr	common_name;
131 	xmlNodePtr	description;
132 	xmlNodePtr	documentation;
133 };
134 
135 /*
136  * Likewise for type (for notification parameters) elements.
137  */
138 struct params_elts {
139 	xmlNodePtr	paramval;
140 	xmlNodePtr	parameter;
141 };
142 
143 /*
144  * This structure is for snaplevel lists.  They are convenient because libscf
145  * only allows traversing snaplevels in one direction.
146  */
147 struct snaplevel {
148 	uu_list_node_t	list_node;
149 	scf_snaplevel_t	*sl;
150 };
151 
152 /*
153  * This is used for communication between lscf_service_export and
154  * export_callback.
155  */
156 struct export_args {
157 	const char	*filename;
158 	int 		flags;
159 };
160 
161 /*
162  * The service_manifest structure is used by the upgrade process
163  * to create a list of service to manifest linkages from the manifests
164  * in a set of given directories.
165  */
166 typedef struct service_manifest {
167 	const char 	*servicename;
168 	uu_list_t	*mfstlist;
169 	size_t	mfstlist_sz;
170 
171 	uu_avl_node_t	svcmfst_node;
172 } service_manifest_t;
173 
174 /*
175  * Structure to track the manifest file property group
176  * and the manifest file associated with that property
177  * group.  Also, a flag to keep the access once it has
178  * been checked.
179  */
180 struct mpg_mfile {
181 	char	*mpg;
182 	char	*mfile;
183 	int	access;
184 };
185 
186 const char * const scf_pg_general = SCF_PG_GENERAL;
187 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
188 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
189 const char * const scf_property_external = "external";
190 
191 const char * const snap_initial = "initial";
192 const char * const snap_lastimport = "last-import";
193 const char * const snap_previous = "previous";
194 const char * const snap_running = "running";
195 
196 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
197 
198 ssize_t max_scf_fmri_len;
199 ssize_t max_scf_name_len;
200 ssize_t max_scf_pg_type_len;
201 ssize_t max_scf_value_len;
202 static size_t max_scf_len;
203 
204 static scf_scope_t *cur_scope;
205 static scf_service_t *cur_svc = NULL;
206 static scf_instance_t *cur_inst = NULL;
207 static scf_snapshot_t *cur_snap = NULL;
208 static scf_snaplevel_t *cur_level = NULL;
209 
210 static uu_list_pool_t *snaplevel_pool;
211 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
212 static uu_list_t *cur_levels;
213 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
214 
215 static FILE *tempfile = NULL;
216 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
217 
218 static const char *emsg_entity_not_selected;
219 static const char *emsg_permission_denied;
220 static const char *emsg_create_xml;
221 static const char *emsg_cant_modify_snapshots;
222 static const char *emsg_invalid_for_snapshot;
223 static const char *emsg_read_only;
224 static const char *emsg_deleted;
225 static const char *emsg_invalid_pg_name;
226 static const char *emsg_invalid_prop_name;
227 static const char *emsg_no_such_pg;
228 static const char *emsg_fmri_invalid_pg_name;
229 static const char *emsg_fmri_invalid_pg_name_type;
230 static const char *emsg_pg_added;
231 static const char *emsg_pg_changed;
232 static const char *emsg_pg_deleted;
233 static const char *emsg_pg_mod_perm;
234 static const char *emsg_pg_add_perm;
235 static const char *emsg_pg_del_perm;
236 static const char *emsg_snap_perm;
237 static const char *emsg_dpt_dangling;
238 static const char *emsg_dpt_no_dep;
239 
240 static int li_only = 0;
241 static int no_refresh = 0;
242 
243 /* import globals, to minimize allocations */
244 static scf_scope_t *imp_scope = NULL;
245 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
246 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
247 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
248 static scf_snapshot_t *imp_rsnap = NULL;
249 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
250 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
251 static scf_property_t *imp_prop = NULL;
252 static scf_iter_t *imp_iter = NULL;
253 static scf_iter_t *imp_rpg_iter = NULL;
254 static scf_iter_t *imp_up_iter = NULL;
255 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
256 static char *imp_str = NULL;
257 static size_t imp_str_sz;
258 static char *imp_tsname = NULL;
259 static char *imp_fe1 = NULL;		/* for fmri_equal() */
260 static char *imp_fe2 = NULL;
261 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
262 
263 /* upgrade_dependents() globals */
264 static scf_instance_t *ud_inst = NULL;
265 static scf_snaplevel_t *ud_snpl = NULL;
266 static scf_propertygroup_t *ud_pg = NULL;
267 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
268 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
269 static int ud_run_dpts_pg_set = 0;
270 static scf_property_t *ud_prop = NULL;
271 static scf_property_t *ud_dpt_prop = NULL;
272 static scf_value_t *ud_val = NULL;
273 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
274 static scf_transaction_t *ud_tx = NULL;
275 static char *ud_ctarg = NULL;
276 static char *ud_oldtarg = NULL;
277 static char *ud_name = NULL;
278 
279 /* export globals */
280 static scf_instance_t *exp_inst;
281 static scf_propertygroup_t *exp_pg;
282 static scf_property_t *exp_prop;
283 static scf_value_t *exp_val;
284 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
285 static char *exp_str;
286 static size_t exp_str_sz;
287 
288 /* cleanup globals */
289 static uu_avl_pool_t *service_manifest_pool = NULL;
290 static uu_avl_t *service_manifest_tree = NULL;
291 
292 static void scfdie_lineno(int lineno) __NORETURN;
293 
294 static char *start_method_names[] = {
295 	"start",
296 	"inetd_start",
297 	NULL
298 };
299 
300 static struct uri_scheme {
301 	const char *scheme;
302 	const char *protocol;
303 } uri_scheme[] = {
304 	{ "mailto", "smtp" },
305 	{ "snmp", "snmp" },
306 	{ "syslog", "syslog" },
307 	{ NULL, NULL }
308 };
309 #define	URI_SCHEME_NUM ((sizeof (uri_scheme) / \
310     sizeof (struct uri_scheme)) - 1)
311 
312 static int
313 check_uri_scheme(const char *scheme)
314 {
315 	int i;
316 
317 	for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
318 		if (strcmp(scheme, uri_scheme[i].scheme) == 0)
319 			return (i);
320 	}
321 
322 	return (-1);
323 }
324 
325 static int
326 check_uri_protocol(const char *p)
327 {
328 	int i;
329 
330 	for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
331 		if (strcmp(p, uri_scheme[i].protocol) == 0)
332 			return (i);
333 	}
334 
335 	return (-1);
336 }
337 
338 /*
339  * For unexpected libscf errors.
340  */
341 #ifdef NDEBUG
342 
343 static void scfdie(void) __NORETURN;
344 
345 static void
346 scfdie(void)
347 {
348 	scf_error_t err = scf_error();
349 
350 	if (err == SCF_ERROR_CONNECTION_BROKEN)
351 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
352 
353 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
354 	    scf_strerror(err));
355 }
356 
357 #else
358 
359 #define	scfdie()	scfdie_lineno(__LINE__)
360 
361 static void
362 scfdie_lineno(int lineno)
363 {
364 	scf_error_t err = scf_error();
365 
366 	if (err == SCF_ERROR_CONNECTION_BROKEN)
367 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
368 
369 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
370 	    ": %s.\n"), lineno, scf_strerror(err));
371 }
372 
373 #endif
374 
375 static void
376 scfwarn(void)
377 {
378 	warn(gettext("Unexpected libscf error: %s.\n"),
379 	    scf_strerror(scf_error()));
380 }
381 
382 /*
383  * Clear a field of a structure.
384  */
385 static int
386 clear_int(void *a, void *b)
387 {
388 	/* LINTED */
389 	*(int *)((char *)a + (size_t)b) = 0;
390 
391 	return (UU_WALK_NEXT);
392 }
393 
394 static int
395 scferror2errno(scf_error_t err)
396 {
397 	switch (err) {
398 	case SCF_ERROR_BACKEND_ACCESS:
399 		return (EACCES);
400 
401 	case SCF_ERROR_BACKEND_READONLY:
402 		return (EROFS);
403 
404 	case SCF_ERROR_CONNECTION_BROKEN:
405 		return (ECONNABORTED);
406 
407 	case SCF_ERROR_CONSTRAINT_VIOLATED:
408 	case SCF_ERROR_INVALID_ARGUMENT:
409 		return (EINVAL);
410 
411 	case SCF_ERROR_DELETED:
412 		return (ECANCELED);
413 
414 	case SCF_ERROR_EXISTS:
415 		return (EEXIST);
416 
417 	case SCF_ERROR_NO_MEMORY:
418 		return (ENOMEM);
419 
420 	case SCF_ERROR_NO_RESOURCES:
421 		return (ENOSPC);
422 
423 	case SCF_ERROR_NOT_FOUND:
424 		return (ENOENT);
425 
426 	case SCF_ERROR_PERMISSION_DENIED:
427 		return (EPERM);
428 
429 	default:
430 #ifndef NDEBUG
431 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
432 		    __FILE__, __LINE__, err);
433 #else
434 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
435 #endif
436 		abort();
437 		/* NOTREACHED */
438 	}
439 }
440 
441 static int
442 entity_get_pg(void *ent, int issvc, const char *name,
443     scf_propertygroup_t *pg)
444 {
445 	if (issvc)
446 		return (scf_service_get_pg(ent, name, pg));
447 	else
448 		return (scf_instance_get_pg(ent, name, pg));
449 }
450 
451 static void
452 entity_destroy(void *ent, int issvc)
453 {
454 	if (issvc)
455 		scf_service_destroy(ent);
456 	else
457 		scf_instance_destroy(ent);
458 }
459 
460 static int
461 get_pg(const char *pg_name, scf_propertygroup_t *pg)
462 {
463 	int ret;
464 
465 	if (cur_level != NULL)
466 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
467 	else if (cur_inst != NULL)
468 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
469 	else
470 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
471 
472 	return (ret);
473 }
474 
475 /*
476  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
477  * snaplevel.  Otherwise find the instance snaplevel.
478  *
479  * Returns
480  *   0 - success
481  *   ECONNABORTED - repository connection broken
482  *   ECANCELED - instance containing snap was deleted
483  *   ENOENT - snap has no snaplevels
484  *	    - requested snaplevel not found
485  */
486 static int
487 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
488 {
489 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
490 		switch (scf_error()) {
491 		case SCF_ERROR_CONNECTION_BROKEN:
492 		case SCF_ERROR_DELETED:
493 		case SCF_ERROR_NOT_FOUND:
494 			return (scferror2errno(scf_error()));
495 
496 		case SCF_ERROR_HANDLE_MISMATCH:
497 		case SCF_ERROR_NOT_BOUND:
498 		case SCF_ERROR_NOT_SET:
499 		default:
500 			bad_error("scf_snapshot_get_base_snaplevel",
501 			    scf_error());
502 		}
503 	}
504 
505 	for (;;) {
506 		ssize_t ssz;
507 
508 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
509 		if (ssz >= 0) {
510 			if (!get_svc)
511 				return (0);
512 		} else {
513 			switch (scf_error()) {
514 			case SCF_ERROR_CONSTRAINT_VIOLATED:
515 				if (get_svc)
516 					return (0);
517 				break;
518 
519 			case SCF_ERROR_DELETED:
520 			case SCF_ERROR_CONNECTION_BROKEN:
521 				return (scferror2errno(scf_error()));
522 
523 			case SCF_ERROR_NOT_SET:
524 			case SCF_ERROR_NOT_BOUND:
525 			default:
526 				bad_error("scf_snaplevel_get_instance_name",
527 				    scf_error());
528 			}
529 		}
530 
531 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
532 			switch (scf_error()) {
533 			case SCF_ERROR_NOT_FOUND:
534 			case SCF_ERROR_CONNECTION_BROKEN:
535 			case SCF_ERROR_DELETED:
536 				return (scferror2errno(scf_error()));
537 
538 			case SCF_ERROR_HANDLE_MISMATCH:
539 			case SCF_ERROR_NOT_BOUND:
540 			case SCF_ERROR_NOT_SET:
541 			case SCF_ERROR_INVALID_ARGUMENT:
542 			default:
543 				bad_error("scf_snaplevel_get_next_snaplevel",
544 				    scf_error());
545 			}
546 		}
547 	}
548 }
549 
550 /*
551  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
552  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
553  * the property group named name in it.  If it doesn't have a running
554  * snapshot, set pg to the instance's current property group named name.
555  *
556  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
557  * its instances.  If one has a running snapshot with a service snaplevel, set
558  * pg to the property group named name in it.  If no such snaplevel could be
559  * found, set pg to the service's current property group named name.
560  *
561  * iter, inst, snap, and snpl are required scratch objects.
562  *
563  * Returns
564  *   0 - success
565  *   ECONNABORTED - repository connection broken
566  *   ECANCELED - ent was deleted
567  *   ENOENT - no such property group
568  *   EINVAL - name is an invalid property group name
569  *   EBADF - found running snapshot is missing a snaplevel
570  */
571 static int
572 entity_get_running_pg(void *ent, int issvc, const char *name,
573     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
574     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
575 {
576 	int r;
577 
578 	if (issvc) {
579 		/* Search for an instance with a running snapshot. */
580 		if (scf_iter_service_instances(iter, ent) != 0) {
581 			switch (scf_error()) {
582 			case SCF_ERROR_DELETED:
583 			case SCF_ERROR_CONNECTION_BROKEN:
584 				return (scferror2errno(scf_error()));
585 
586 			case SCF_ERROR_NOT_SET:
587 			case SCF_ERROR_NOT_BOUND:
588 			case SCF_ERROR_HANDLE_MISMATCH:
589 			default:
590 				bad_error("scf_iter_service_instances",
591 				    scf_error());
592 			}
593 		}
594 
595 		for (;;) {
596 			r = scf_iter_next_instance(iter, inst);
597 			if (r == 0) {
598 				if (scf_service_get_pg(ent, name, pg) == 0)
599 					return (0);
600 
601 				switch (scf_error()) {
602 				case SCF_ERROR_DELETED:
603 				case SCF_ERROR_NOT_FOUND:
604 				case SCF_ERROR_INVALID_ARGUMENT:
605 				case SCF_ERROR_CONNECTION_BROKEN:
606 					return (scferror2errno(scf_error()));
607 
608 				case SCF_ERROR_NOT_BOUND:
609 				case SCF_ERROR_HANDLE_MISMATCH:
610 				case SCF_ERROR_NOT_SET:
611 				default:
612 					bad_error("scf_service_get_pg",
613 					    scf_error());
614 				}
615 			}
616 			if (r != 1) {
617 				switch (scf_error()) {
618 				case SCF_ERROR_DELETED:
619 				case SCF_ERROR_CONNECTION_BROKEN:
620 					return (scferror2errno(scf_error()));
621 
622 				case SCF_ERROR_INVALID_ARGUMENT:
623 				case SCF_ERROR_NOT_SET:
624 				case SCF_ERROR_NOT_BOUND:
625 				case SCF_ERROR_HANDLE_MISMATCH:
626 				default:
627 					bad_error("scf_iter_next_instance",
628 					    scf_error());
629 				}
630 			}
631 
632 			if (scf_instance_get_snapshot(inst, snap_running,
633 			    snap) == 0)
634 				break;
635 
636 			switch (scf_error()) {
637 			case SCF_ERROR_NOT_FOUND:
638 			case SCF_ERROR_DELETED:
639 				continue;
640 
641 			case SCF_ERROR_CONNECTION_BROKEN:
642 				return (ECONNABORTED);
643 
644 			case SCF_ERROR_HANDLE_MISMATCH:
645 			case SCF_ERROR_INVALID_ARGUMENT:
646 			case SCF_ERROR_NOT_SET:
647 			case SCF_ERROR_NOT_BOUND:
648 			default:
649 				bad_error("scf_instance_get_snapshot",
650 				    scf_error());
651 			}
652 		}
653 	} else {
654 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
655 			switch (scf_error()) {
656 			case SCF_ERROR_NOT_FOUND:
657 				break;
658 
659 			case SCF_ERROR_DELETED:
660 			case SCF_ERROR_CONNECTION_BROKEN:
661 				return (scferror2errno(scf_error()));
662 
663 			case SCF_ERROR_NOT_BOUND:
664 			case SCF_ERROR_HANDLE_MISMATCH:
665 			case SCF_ERROR_INVALID_ARGUMENT:
666 			case SCF_ERROR_NOT_SET:
667 			default:
668 				bad_error("scf_instance_get_snapshot",
669 				    scf_error());
670 			}
671 
672 			if (scf_instance_get_pg(ent, name, pg) == 0)
673 				return (0);
674 
675 			switch (scf_error()) {
676 			case SCF_ERROR_DELETED:
677 			case SCF_ERROR_NOT_FOUND:
678 			case SCF_ERROR_INVALID_ARGUMENT:
679 			case SCF_ERROR_CONNECTION_BROKEN:
680 				return (scferror2errno(scf_error()));
681 
682 			case SCF_ERROR_NOT_BOUND:
683 			case SCF_ERROR_HANDLE_MISMATCH:
684 			case SCF_ERROR_NOT_SET:
685 			default:
686 				bad_error("scf_instance_get_pg", scf_error());
687 			}
688 		}
689 	}
690 
691 	r = get_snaplevel(snap, issvc, snpl);
692 	switch (r) {
693 	case 0:
694 		break;
695 
696 	case ECONNABORTED:
697 	case ECANCELED:
698 		return (r);
699 
700 	case ENOENT:
701 		return (EBADF);
702 
703 	default:
704 		bad_error("get_snaplevel", r);
705 	}
706 
707 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
708 		return (0);
709 
710 	switch (scf_error()) {
711 	case SCF_ERROR_DELETED:
712 	case SCF_ERROR_INVALID_ARGUMENT:
713 	case SCF_ERROR_CONNECTION_BROKEN:
714 	case SCF_ERROR_NOT_FOUND:
715 		return (scferror2errno(scf_error()));
716 
717 	case SCF_ERROR_NOT_BOUND:
718 	case SCF_ERROR_HANDLE_MISMATCH:
719 	case SCF_ERROR_NOT_SET:
720 	default:
721 		bad_error("scf_snaplevel_get_pg", scf_error());
722 		/* NOTREACHED */
723 	}
724 }
725 
726 /*
727  * To be registered with atexit().
728  */
729 static void
730 remove_tempfile(void)
731 {
732 	int ret;
733 
734 	if (tempfile != NULL) {
735 		if (fclose(tempfile) == EOF)
736 			(void) warn(gettext("Could not close temporary file"));
737 		tempfile = NULL;
738 	}
739 
740 	if (tempfilename[0] != '\0') {
741 		do {
742 			ret = remove(tempfilename);
743 		} while (ret == -1 && errno == EINTR);
744 		if (ret == -1)
745 			warn(gettext("Could not remove temporary file"));
746 		tempfilename[0] = '\0';
747 	}
748 }
749 
750 /*
751  * Launch private svc.configd(1M) for manipulating alternate repositories.
752  */
753 static void
754 start_private_repository(engine_state_t *est)
755 {
756 	int fd, stat;
757 	struct door_info info;
758 	pid_t pid;
759 
760 	/*
761 	 * 1.  Create a temporary file for the door.
762 	 */
763 	if (est->sc_repo_doorname != NULL)
764 		free((void *)est->sc_repo_doorname);
765 
766 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
767 	if (est->sc_repo_doorname == NULL)
768 		uu_die(gettext("Could not acquire temporary filename"));
769 
770 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
771 	if (fd < 0)
772 		uu_die(gettext("Could not create temporary file for "
773 		    "repository server"));
774 
775 	(void) close(fd);
776 
777 	/*
778 	 * 2.  Launch a configd with that door, using the specified
779 	 * repository.
780 	 */
781 	if ((est->sc_repo_pid = fork()) == 0) {
782 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
783 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
784 		    NULL);
785 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
786 	} else if (est->sc_repo_pid == -1)
787 		uu_die(gettext("Attempt to fork failed"));
788 
789 	do {
790 		pid = waitpid(est->sc_repo_pid, &stat, 0);
791 	} while (pid == -1 && errno == EINTR);
792 
793 	if (pid == -1)
794 		uu_die(gettext("Could not waitpid() for repository server"));
795 
796 	if (!WIFEXITED(stat)) {
797 		uu_die(gettext("Repository server failed (status %d).\n"),
798 		    stat);
799 	} else if (WEXITSTATUS(stat) != 0) {
800 		uu_die(gettext("Repository server failed (exit %d).\n"),
801 		    WEXITSTATUS(stat));
802 	}
803 
804 	/*
805 	 * See if it was successful by checking if the door is a door.
806 	 */
807 
808 	fd = open(est->sc_repo_doorname, O_RDWR);
809 	if (fd < 0)
810 		uu_die(gettext("Could not open door \"%s\""),
811 		    est->sc_repo_doorname);
812 
813 	if (door_info(fd, &info) < 0)
814 		uu_die(gettext("Unexpected door_info() error"));
815 
816 	if (close(fd) == -1)
817 		warn(gettext("Could not close repository door"),
818 		    strerror(errno));
819 
820 	est->sc_repo_pid = info.di_target;
821 }
822 
823 void
824 lscf_cleanup(void)
825 {
826 	/*
827 	 * In the case where we've launched a private svc.configd(1M)
828 	 * instance, we must terminate our child and remove the temporary
829 	 * rendezvous point.
830 	 */
831 	if (est->sc_repo_pid > 0) {
832 		(void) kill(est->sc_repo_pid, SIGTERM);
833 		(void) waitpid(est->sc_repo_pid, NULL, 0);
834 		(void) unlink(est->sc_repo_doorname);
835 
836 		est->sc_repo_pid = 0;
837 	}
838 }
839 
840 void
841 unselect_cursnap(void)
842 {
843 	void *cookie;
844 
845 	cur_level = NULL;
846 
847 	cookie = NULL;
848 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
849 		scf_snaplevel_destroy(cur_elt->sl);
850 		free(cur_elt);
851 	}
852 
853 	scf_snapshot_destroy(cur_snap);
854 	cur_snap = NULL;
855 }
856 
857 void
858 lscf_prep_hndl(void)
859 {
860 	if (g_hndl != NULL)
861 		return;
862 
863 	g_hndl = scf_handle_create(SCF_VERSION);
864 	if (g_hndl == NULL)
865 		scfdie();
866 
867 	if (est->sc_repo_filename != NULL)
868 		start_private_repository(est);
869 
870 	if (est->sc_repo_doorname != NULL) {
871 		scf_value_t *repo_value;
872 		int ret;
873 
874 		repo_value = scf_value_create(g_hndl);
875 		if (repo_value == NULL)
876 			scfdie();
877 
878 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
879 		assert(ret == SCF_SUCCESS);
880 
881 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
882 		    SCF_SUCCESS)
883 			scfdie();
884 
885 		scf_value_destroy(repo_value);
886 	}
887 
888 	if (scf_handle_bind(g_hndl) != 0)
889 		uu_die(gettext("Could not connect to repository server: %s.\n"),
890 		    scf_strerror(scf_error()));
891 
892 	cur_scope = scf_scope_create(g_hndl);
893 	if (cur_scope == NULL)
894 		scfdie();
895 
896 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
897 		scfdie();
898 }
899 
900 static void
901 repository_teardown(void)
902 {
903 	if (g_hndl != NULL) {
904 		if (cur_snap != NULL)
905 			unselect_cursnap();
906 		scf_instance_destroy(cur_inst);
907 		scf_service_destroy(cur_svc);
908 		scf_scope_destroy(cur_scope);
909 		scf_handle_destroy(g_hndl);
910 		cur_inst = NULL;
911 		cur_svc = NULL;
912 		cur_scope = NULL;
913 		g_hndl = NULL;
914 		lscf_cleanup();
915 	}
916 }
917 
918 void
919 lscf_set_repository(const char *repfile, int force)
920 {
921 	repository_teardown();
922 
923 	if (est->sc_repo_filename != NULL) {
924 		free((void *)est->sc_repo_filename);
925 		est->sc_repo_filename = NULL;
926 	}
927 
928 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
929 		/*
930 		 * Repository file does not exist
931 		 * or has no read permission.
932 		 */
933 		warn(gettext("Cannot access \"%s\": %s\n"),
934 		    repfile, strerror(errno));
935 	} else {
936 		est->sc_repo_filename = safe_strdup(repfile);
937 	}
938 
939 	lscf_prep_hndl();
940 }
941 
942 void
943 lscf_init()
944 {
945 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
946 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
947 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
948 	    0 ||
949 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
950 		scfdie();
951 
952 	max_scf_len = max_scf_fmri_len;
953 	if (max_scf_name_len > max_scf_len)
954 		max_scf_len = max_scf_name_len;
955 	if (max_scf_pg_type_len > max_scf_len)
956 		max_scf_len = max_scf_pg_type_len;
957 	/*
958 	 * When a value of type opaque is represented as a string, the
959 	 * string contains 2 characters for every byte of data.  That is
960 	 * because the string contains the hex representation of the opaque
961 	 * value.
962 	 */
963 	if (2 * max_scf_value_len > max_scf_len)
964 		max_scf_len = 2 * max_scf_value_len;
965 
966 	if (atexit(remove_tempfile) != 0)
967 		uu_die(gettext("Could not register atexit() function"));
968 
969 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
970 	emsg_permission_denied = gettext("Permission denied.\n");
971 	emsg_create_xml = gettext("Could not create XML node.\n");
972 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
973 	emsg_invalid_for_snapshot =
974 	    gettext("Invalid operation on a snapshot.\n");
975 	emsg_read_only = gettext("Backend read-only.\n");
976 	emsg_deleted = gettext("Current selection has been deleted.\n");
977 	emsg_invalid_pg_name =
978 	    gettext("Invalid property group name \"%s\".\n");
979 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
980 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
981 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
982 	    "with invalid name \"%s\".\n");
983 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
984 	    "group with invalid name \"%s\" or type \"%s\".\n");
985 	emsg_pg_added = gettext("%s changed unexpectedly "
986 	    "(property group \"%s\" added).\n");
987 	emsg_pg_changed = gettext("%s changed unexpectedly "
988 	    "(property group \"%s\" changed).\n");
989 	emsg_pg_deleted = gettext("%s changed unexpectedly "
990 	    "(property group \"%s\" or an ancestor was deleted).\n");
991 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
992 	    "in %s (permission denied).\n");
993 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
994 	    "in %s (permission denied).\n");
995 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
996 	    "in %s (permission denied).\n");
997 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
998 	    "(permission denied).\n");
999 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1000 	    "new dependent \"%s\" because it already exists).  Warning: The "
1001 	    "current dependent's target (%s) does not exist.\n");
1002 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1003 	    "dependent \"%s\" because it already exists).  Warning: The "
1004 	    "current dependent's target (%s) does not have a dependency named "
1005 	    "\"%s\" as expected.\n");
1006 
1007 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1008 	    offsetof(string_list_t, node), NULL, 0);
1009 	snaplevel_pool = uu_list_pool_create("snaplevels",
1010 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1011 	    NULL, 0);
1012 }
1013 
1014 
1015 static const char *
1016 prop_to_typestr(const scf_property_t *prop)
1017 {
1018 	scf_type_t ty;
1019 
1020 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1021 		scfdie();
1022 
1023 	return (scf_type_to_string(ty));
1024 }
1025 
1026 static scf_type_t
1027 string_to_type(const char *type)
1028 {
1029 	size_t len = strlen(type);
1030 	char *buf;
1031 
1032 	if (len == 0 || type[len - 1] != ':')
1033 		return (SCF_TYPE_INVALID);
1034 
1035 	buf = (char *)alloca(len + 1);
1036 	(void) strlcpy(buf, type, len + 1);
1037 	buf[len - 1] = 0;
1038 
1039 	return (scf_string_to_type(buf));
1040 }
1041 
1042 static scf_value_t *
1043 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1044 {
1045 	scf_value_t *v;
1046 	char *dup, *nstr;
1047 	size_t len;
1048 
1049 	v = scf_value_create(g_hndl);
1050 	if (v == NULL)
1051 		scfdie();
1052 
1053 	len = strlen(str);
1054 	if (require_quotes &&
1055 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1056 		semerr(gettext("Multiple string values or string values "
1057 		    "with spaces must be quoted with '\"'.\n"));
1058 		scf_value_destroy(v);
1059 		return (NULL);
1060 	}
1061 
1062 	nstr = dup = safe_strdup(str);
1063 	if (dup[0] == '\"') {
1064 		/*
1065 		 * Strip out the first and the last quote.
1066 		 */
1067 		dup[len - 1] = '\0';
1068 		nstr = dup + 1;
1069 	}
1070 
1071 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1072 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1073 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1074 		    scf_type_to_string(ty), nstr);
1075 		scf_value_destroy(v);
1076 		v = NULL;
1077 	}
1078 	free(dup);
1079 	return (v);
1080 }
1081 
1082 /*
1083  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1084  * Optionally append a comment prefix ('#') to newlines ('\n').
1085  */
1086 static int
1087 quote_and_print(const char *str, FILE *strm, int commentnl)
1088 {
1089 	const char *cp;
1090 
1091 	for (cp = str; *cp != '\0'; ++cp) {
1092 		if (*cp == '"' || *cp == '\\')
1093 			(void) putc('\\', strm);
1094 
1095 		(void) putc(*cp, strm);
1096 
1097 		if (commentnl && *cp == '\n') {
1098 			(void) putc('#', strm);
1099 		}
1100 	}
1101 
1102 	return (ferror(strm));
1103 }
1104 
1105 /*
1106  * These wrappers around lowlevel functions provide consistent error checking
1107  * and warnings.
1108  */
1109 static int
1110 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1111 {
1112 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1113 		return (0);
1114 
1115 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1116 		scfdie();
1117 
1118 	if (g_verbose) {
1119 		ssize_t len;
1120 		char *fmri;
1121 
1122 		len = scf_pg_to_fmri(pg, NULL, 0);
1123 		if (len < 0)
1124 			scfdie();
1125 
1126 		fmri = safe_malloc(len + 1);
1127 
1128 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1129 			scfdie();
1130 
1131 		warn(gettext("Expected property %s of property group %s is "
1132 		    "missing.\n"), propname, fmri);
1133 
1134 		free(fmri);
1135 	}
1136 
1137 	return (-1);
1138 }
1139 
1140 static int
1141 prop_check_type(scf_property_t *prop, scf_type_t ty)
1142 {
1143 	scf_type_t pty;
1144 
1145 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1146 		scfdie();
1147 
1148 	if (ty == pty)
1149 		return (0);
1150 
1151 	if (g_verbose) {
1152 		ssize_t len;
1153 		char *fmri;
1154 		const char *tystr;
1155 
1156 		len = scf_property_to_fmri(prop, NULL, 0);
1157 		if (len < 0)
1158 			scfdie();
1159 
1160 		fmri = safe_malloc(len + 1);
1161 
1162 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1163 			scfdie();
1164 
1165 		tystr = scf_type_to_string(ty);
1166 		if (tystr == NULL)
1167 			tystr = "?";
1168 
1169 		warn(gettext("Property %s is not of expected type %s.\n"),
1170 		    fmri, tystr);
1171 
1172 		free(fmri);
1173 	}
1174 
1175 	return (-1);
1176 }
1177 
1178 static int
1179 prop_get_val(scf_property_t *prop, scf_value_t *val)
1180 {
1181 	scf_error_t err;
1182 
1183 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1184 		return (0);
1185 
1186 	err = scf_error();
1187 
1188 	if (err != SCF_ERROR_NOT_FOUND &&
1189 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1190 	    err != SCF_ERROR_PERMISSION_DENIED)
1191 		scfdie();
1192 
1193 	if (g_verbose) {
1194 		ssize_t len;
1195 		char *fmri, *emsg;
1196 
1197 		len = scf_property_to_fmri(prop, NULL, 0);
1198 		if (len < 0)
1199 			scfdie();
1200 
1201 		fmri = safe_malloc(len + 1);
1202 
1203 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1204 			scfdie();
1205 
1206 		if (err == SCF_ERROR_NOT_FOUND)
1207 			emsg = gettext("Property %s has no values; expected "
1208 			    "one.\n");
1209 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1210 			emsg = gettext("Property %s has multiple values; "
1211 			    "expected one.\n");
1212 		else
1213 			emsg = gettext("No permission to read property %s.\n");
1214 
1215 		warn(emsg, fmri);
1216 
1217 		free(fmri);
1218 	}
1219 
1220 	return (-1);
1221 }
1222 
1223 
1224 static boolean_t
1225 snaplevel_is_instance(const scf_snaplevel_t *level)
1226 {
1227 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1228 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1229 			scfdie();
1230 		return (0);
1231 	} else {
1232 		return (1);
1233 	}
1234 }
1235 
1236 /*
1237  * Decode FMRI into a service or instance, and put the result in *ep.  If
1238  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1239  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1240  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1241  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1242  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1243  * whether *ep is a service.
1244  */
1245 static scf_error_t
1246 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1247 {
1248 	char *fmri_copy;
1249 	const char *sstr, *istr, *pgstr;
1250 	scf_service_t *svc;
1251 	scf_instance_t *inst;
1252 
1253 	fmri_copy = strdup(fmri);
1254 	if (fmri_copy == NULL)
1255 		return (SCF_ERROR_NO_MEMORY);
1256 
1257 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1258 	    SCF_SUCCESS) {
1259 		free(fmri_copy);
1260 		return (SCF_ERROR_INVALID_ARGUMENT);
1261 	}
1262 
1263 	free(fmri_copy);
1264 
1265 	if (sstr == NULL || pgstr != NULL)
1266 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1267 
1268 	if (istr == NULL) {
1269 		svc = scf_service_create(h);
1270 		if (svc == NULL)
1271 			return (SCF_ERROR_NO_MEMORY);
1272 
1273 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1274 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1275 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1276 				scfdie();
1277 
1278 			return (SCF_ERROR_NOT_FOUND);
1279 		}
1280 
1281 		*ep = svc;
1282 		*isservice = 1;
1283 	} else {
1284 		inst = scf_instance_create(h);
1285 		if (inst == NULL)
1286 			return (SCF_ERROR_NO_MEMORY);
1287 
1288 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1289 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1290 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1291 				scfdie();
1292 
1293 			return (SCF_ERROR_NOT_FOUND);
1294 		}
1295 
1296 		*ep = inst;
1297 		*isservice = 0;
1298 	}
1299 
1300 	return (SCF_ERROR_NONE);
1301 }
1302 
1303 /*
1304  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1305  * *ep, and set or clear *isservicep if it is a service or an instance.
1306  * Returns
1307  *   SCF_ERROR_NONE - success
1308  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1309  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1310  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1311  *   SCF_ERROR_NOT_FOUND - no such scope
1312  *   SCF_ERROR_PERMISSION_DENIED
1313  *   SCF_ERROR_BACKEND_READONLY
1314  *   SCF_ERROR_BACKEND_ACCESS
1315  */
1316 static scf_error_t
1317 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1318 {
1319 	char *fmri_copy;
1320 	const char *scstr, *sstr, *istr, *pgstr;
1321 	scf_scope_t *scope = NULL;
1322 	scf_service_t *svc = NULL;
1323 	scf_instance_t *inst = NULL;
1324 	scf_error_t scfe;
1325 
1326 	fmri_copy = safe_strdup(fmri);
1327 
1328 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1329 	    0) {
1330 		free(fmri_copy);
1331 		return (SCF_ERROR_INVALID_ARGUMENT);
1332 	}
1333 
1334 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1335 		free(fmri_copy);
1336 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1337 	}
1338 
1339 	*ep = NULL;
1340 
1341 	if ((scope = scf_scope_create(h)) == NULL ||
1342 	    (svc = scf_service_create(h)) == NULL ||
1343 	    (inst = scf_instance_create(h)) == NULL) {
1344 		scfe = SCF_ERROR_NO_MEMORY;
1345 		goto out;
1346 	}
1347 
1348 get_scope:
1349 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1350 		switch (scf_error()) {
1351 		case SCF_ERROR_CONNECTION_BROKEN:
1352 			scfdie();
1353 			/* NOTREACHED */
1354 
1355 		case SCF_ERROR_NOT_FOUND:
1356 			scfe = SCF_ERROR_NOT_FOUND;
1357 			goto out;
1358 
1359 		case SCF_ERROR_HANDLE_MISMATCH:
1360 		case SCF_ERROR_NOT_BOUND:
1361 		case SCF_ERROR_INVALID_ARGUMENT:
1362 		default:
1363 			bad_error("scf_handle_get_scope", scf_error());
1364 		}
1365 	}
1366 
1367 get_svc:
1368 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1369 		switch (scf_error()) {
1370 		case SCF_ERROR_CONNECTION_BROKEN:
1371 			scfdie();
1372 			/* NOTREACHED */
1373 
1374 		case SCF_ERROR_DELETED:
1375 			goto get_scope;
1376 
1377 		case SCF_ERROR_NOT_FOUND:
1378 			break;
1379 
1380 		case SCF_ERROR_HANDLE_MISMATCH:
1381 		case SCF_ERROR_INVALID_ARGUMENT:
1382 		case SCF_ERROR_NOT_BOUND:
1383 		case SCF_ERROR_NOT_SET:
1384 		default:
1385 			bad_error("scf_scope_get_service", scf_error());
1386 		}
1387 
1388 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1389 			switch (scf_error()) {
1390 			case SCF_ERROR_CONNECTION_BROKEN:
1391 				scfdie();
1392 				/* NOTREACHED */
1393 
1394 			case SCF_ERROR_DELETED:
1395 				goto get_scope;
1396 
1397 			case SCF_ERROR_PERMISSION_DENIED:
1398 			case SCF_ERROR_BACKEND_READONLY:
1399 			case SCF_ERROR_BACKEND_ACCESS:
1400 				scfe = scf_error();
1401 				goto out;
1402 
1403 			case SCF_ERROR_HANDLE_MISMATCH:
1404 			case SCF_ERROR_INVALID_ARGUMENT:
1405 			case SCF_ERROR_NOT_BOUND:
1406 			case SCF_ERROR_NOT_SET:
1407 			default:
1408 				bad_error("scf_scope_get_service", scf_error());
1409 			}
1410 		}
1411 	}
1412 
1413 	if (istr == NULL) {
1414 		scfe = SCF_ERROR_NONE;
1415 		*ep = svc;
1416 		*isservicep = 1;
1417 		goto out;
1418 	}
1419 
1420 get_inst:
1421 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1422 		switch (scf_error()) {
1423 		case SCF_ERROR_CONNECTION_BROKEN:
1424 			scfdie();
1425 			/* NOTREACHED */
1426 
1427 		case SCF_ERROR_DELETED:
1428 			goto get_svc;
1429 
1430 		case SCF_ERROR_NOT_FOUND:
1431 			break;
1432 
1433 		case SCF_ERROR_HANDLE_MISMATCH:
1434 		case SCF_ERROR_INVALID_ARGUMENT:
1435 		case SCF_ERROR_NOT_BOUND:
1436 		case SCF_ERROR_NOT_SET:
1437 		default:
1438 			bad_error("scf_service_get_instance", scf_error());
1439 		}
1440 
1441 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1442 			switch (scf_error()) {
1443 			case SCF_ERROR_CONNECTION_BROKEN:
1444 				scfdie();
1445 				/* NOTREACHED */
1446 
1447 			case SCF_ERROR_DELETED:
1448 				goto get_svc;
1449 
1450 			case SCF_ERROR_PERMISSION_DENIED:
1451 			case SCF_ERROR_BACKEND_READONLY:
1452 			case SCF_ERROR_BACKEND_ACCESS:
1453 				scfe = scf_error();
1454 				goto out;
1455 
1456 			case SCF_ERROR_HANDLE_MISMATCH:
1457 			case SCF_ERROR_INVALID_ARGUMENT:
1458 			case SCF_ERROR_NOT_BOUND:
1459 			case SCF_ERROR_NOT_SET:
1460 			default:
1461 				bad_error("scf_service_add_instance",
1462 				    scf_error());
1463 			}
1464 		}
1465 	}
1466 
1467 	scfe = SCF_ERROR_NONE;
1468 	*ep = inst;
1469 	*isservicep = 0;
1470 
1471 out:
1472 	if (*ep != inst)
1473 		scf_instance_destroy(inst);
1474 	if (*ep != svc)
1475 		scf_service_destroy(svc);
1476 	scf_scope_destroy(scope);
1477 	free(fmri_copy);
1478 	return (scfe);
1479 }
1480 
1481 /*
1482  * Create or update a snapshot of inst.  snap is a required scratch object.
1483  *
1484  * Returns
1485  *   0 - success
1486  *   ECONNABORTED - repository connection broken
1487  *   EPERM - permission denied
1488  *   ENOSPC - configd is out of resources
1489  *   ECANCELED - inst was deleted
1490  *   -1 - unknown libscf error (message printed)
1491  */
1492 static int
1493 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1494 {
1495 again:
1496 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1497 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1498 			switch (scf_error()) {
1499 			case SCF_ERROR_CONNECTION_BROKEN:
1500 			case SCF_ERROR_PERMISSION_DENIED:
1501 			case SCF_ERROR_NO_RESOURCES:
1502 				return (scferror2errno(scf_error()));
1503 
1504 			case SCF_ERROR_NOT_SET:
1505 			case SCF_ERROR_INVALID_ARGUMENT:
1506 			default:
1507 				bad_error("_scf_snapshot_take_attach",
1508 				    scf_error());
1509 			}
1510 		}
1511 	} else {
1512 		switch (scf_error()) {
1513 		case SCF_ERROR_NOT_FOUND:
1514 			break;
1515 
1516 		case SCF_ERROR_DELETED:
1517 		case SCF_ERROR_CONNECTION_BROKEN:
1518 			return (scferror2errno(scf_error()));
1519 
1520 		case SCF_ERROR_HANDLE_MISMATCH:
1521 		case SCF_ERROR_NOT_BOUND:
1522 		case SCF_ERROR_INVALID_ARGUMENT:
1523 		case SCF_ERROR_NOT_SET:
1524 		default:
1525 			bad_error("scf_instance_get_snapshot", scf_error());
1526 		}
1527 
1528 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1529 			switch (scf_error()) {
1530 			case SCF_ERROR_EXISTS:
1531 				goto again;
1532 
1533 			case SCF_ERROR_CONNECTION_BROKEN:
1534 			case SCF_ERROR_NO_RESOURCES:
1535 			case SCF_ERROR_PERMISSION_DENIED:
1536 				return (scferror2errno(scf_error()));
1537 
1538 			default:
1539 				scfwarn();
1540 				return (-1);
1541 
1542 			case SCF_ERROR_NOT_SET:
1543 			case SCF_ERROR_INTERNAL:
1544 			case SCF_ERROR_INVALID_ARGUMENT:
1545 			case SCF_ERROR_HANDLE_MISMATCH:
1546 				bad_error("_scf_snapshot_take_new",
1547 				    scf_error());
1548 			}
1549 		}
1550 	}
1551 
1552 	return (0);
1553 }
1554 
1555 static int
1556 refresh_running_snapshot(void *entity)
1557 {
1558 	scf_snapshot_t *snap;
1559 	int r;
1560 
1561 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1562 		scfdie();
1563 	r = take_snap(entity, snap_running, snap);
1564 	scf_snapshot_destroy(snap);
1565 
1566 	return (r);
1567 }
1568 
1569 /*
1570  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1571  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1572  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1573  * for scratch space.  Returns
1574  *   0 - success
1575  *   ECONNABORTED - repository connection broken
1576  *   ECANCELED - entity was deleted
1577  *   EACCES - backend denied access
1578  *   EPERM - permission denied
1579  *   ENOSPC - repository server out of resources
1580  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1581  */
1582 static int
1583 refresh_entity(int isservice, void *entity, const char *fmri,
1584     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1585 {
1586 	scf_error_t scfe;
1587 	int r;
1588 
1589 	if (!isservice) {
1590 		/*
1591 		 * Let restarter handles refreshing and making new running
1592 		 * snapshot only if operating on a live repository and not
1593 		 * running in early import.
1594 		 */
1595 		if (est->sc_repo_filename == NULL &&
1596 		    est->sc_repo_doorname == NULL &&
1597 		    est->sc_in_emi == 0) {
1598 			if (_smf_refresh_instance_i(entity) == 0) {
1599 				if (g_verbose)
1600 					warn(gettext("Refreshed %s.\n"), fmri);
1601 				return (0);
1602 			}
1603 
1604 			switch (scf_error()) {
1605 			case SCF_ERROR_BACKEND_ACCESS:
1606 				return (EACCES);
1607 
1608 			case SCF_ERROR_PERMISSION_DENIED:
1609 				return (EPERM);
1610 
1611 			default:
1612 				return (-1);
1613 			}
1614 		} else {
1615 			r = refresh_running_snapshot(entity);
1616 			switch (r) {
1617 			case 0:
1618 				break;
1619 
1620 			case ECONNABORTED:
1621 			case ECANCELED:
1622 			case EPERM:
1623 			case ENOSPC:
1624 				break;
1625 
1626 			default:
1627 				bad_error("refresh_running_snapshot",
1628 				    scf_error());
1629 			}
1630 
1631 			return (r);
1632 		}
1633 	}
1634 
1635 	if (scf_iter_service_instances(iter, entity) != 0) {
1636 		switch (scf_error()) {
1637 		case SCF_ERROR_CONNECTION_BROKEN:
1638 			return (ECONNABORTED);
1639 
1640 		case SCF_ERROR_DELETED:
1641 			return (ECANCELED);
1642 
1643 		case SCF_ERROR_HANDLE_MISMATCH:
1644 		case SCF_ERROR_NOT_BOUND:
1645 		case SCF_ERROR_NOT_SET:
1646 		default:
1647 			bad_error("scf_iter_service_instances", scf_error());
1648 		}
1649 	}
1650 
1651 	for (;;) {
1652 		r = scf_iter_next_instance(iter, inst);
1653 		if (r == 0)
1654 			break;
1655 		if (r != 1) {
1656 			switch (scf_error()) {
1657 			case SCF_ERROR_CONNECTION_BROKEN:
1658 				return (ECONNABORTED);
1659 
1660 			case SCF_ERROR_DELETED:
1661 				return (ECANCELED);
1662 
1663 			case SCF_ERROR_HANDLE_MISMATCH:
1664 			case SCF_ERROR_NOT_BOUND:
1665 			case SCF_ERROR_NOT_SET:
1666 			case SCF_ERROR_INVALID_ARGUMENT:
1667 			default:
1668 				bad_error("scf_iter_next_instance",
1669 				    scf_error());
1670 			}
1671 		}
1672 
1673 		/*
1674 		 * Similarly, just take a new running snapshot if operating on
1675 		 * a non-live repository or running during early import.
1676 		 */
1677 		if (est->sc_repo_filename != NULL ||
1678 		    est->sc_repo_doorname != NULL ||
1679 		    est->sc_in_emi == 1) {
1680 			r = refresh_running_snapshot(inst);
1681 			switch (r) {
1682 			case 0:
1683 				continue;
1684 
1685 			case ECONNABORTED:
1686 			case ECANCELED:
1687 			case EPERM:
1688 			case ENOSPC:
1689 				break;
1690 			default:
1691 				bad_error("refresh_running_snapshot",
1692 				    scf_error());
1693 			}
1694 
1695 			return (r);
1696 
1697 		}
1698 
1699 		if (_smf_refresh_instance_i(inst) == 0) {
1700 			if (g_verbose) {
1701 				if (scf_instance_get_name(inst, name_buf,
1702 				    max_scf_name_len + 1) < 0)
1703 					(void) strcpy(name_buf, "?");
1704 
1705 				warn(gettext("Refreshed %s:%s.\n"),
1706 				    fmri, name_buf);
1707 			}
1708 		} else {
1709 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1710 			    g_verbose) {
1711 				scfe = scf_error();
1712 
1713 				if (scf_instance_to_fmri(inst, name_buf,
1714 				    max_scf_name_len + 1) < 0)
1715 					(void) strcpy(name_buf, "?");
1716 
1717 				warn(gettext(
1718 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1719 				    name_buf, scf_strerror(scfe));
1720 			}
1721 		}
1722 	}
1723 
1724 	return (0);
1725 }
1726 
1727 static void
1728 private_refresh(void)
1729 {
1730 	scf_instance_t *pinst = NULL;
1731 	scf_iter_t *piter = NULL;
1732 	ssize_t fmrilen;
1733 	size_t bufsz;
1734 	char *fmribuf;
1735 	void *ent;
1736 	int issvc;
1737 	int r;
1738 
1739 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1740 		return;
1741 
1742 	assert(cur_svc != NULL);
1743 
1744 	bufsz = max_scf_fmri_len + 1;
1745 	fmribuf = safe_malloc(bufsz);
1746 	if (cur_inst) {
1747 		issvc = 0;
1748 		ent = cur_inst;
1749 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1750 	} else {
1751 		issvc = 1;
1752 		ent = cur_svc;
1753 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1754 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1755 			scfdie();
1756 
1757 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1758 			scfdie();
1759 	}
1760 	if (fmrilen < 0) {
1761 		free(fmribuf);
1762 		if (scf_error() != SCF_ERROR_DELETED)
1763 			scfdie();
1764 
1765 		warn(emsg_deleted);
1766 		return;
1767 	}
1768 	assert(fmrilen < bufsz);
1769 
1770 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1771 	switch (r) {
1772 	case 0:
1773 		break;
1774 
1775 	case ECONNABORTED:
1776 		warn(gettext("Could not refresh %s "
1777 		    "(repository connection broken).\n"), fmribuf);
1778 		break;
1779 
1780 	case ECANCELED:
1781 		warn(emsg_deleted);
1782 		break;
1783 
1784 	case EPERM:
1785 		warn(gettext("Could not refresh %s "
1786 		    "(permission denied).\n"), fmribuf);
1787 		break;
1788 
1789 	case ENOSPC:
1790 		warn(gettext("Could not refresh %s "
1791 		    "(repository server out of resources).\n"),
1792 		    fmribuf);
1793 		break;
1794 
1795 	case EACCES:
1796 	default:
1797 		bad_error("refresh_entity", scf_error());
1798 	}
1799 
1800 	if (issvc) {
1801 		scf_instance_destroy(pinst);
1802 		scf_iter_destroy(piter);
1803 	}
1804 
1805 	free(fmribuf);
1806 }
1807 
1808 
1809 static int
1810 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1811 {
1812 	cbp->sc_err = scferror2errno(err);
1813 	return (UU_WALK_ERROR);
1814 }
1815 
1816 static int
1817 stash_scferror(scf_callback_t *cbp)
1818 {
1819 	return (stash_scferror_err(cbp, scf_error()));
1820 }
1821 
1822 static int select_inst(const char *);
1823 static int select_svc(const char *);
1824 
1825 /*
1826  * Take a property that does not have a type and check to see if a type
1827  * exists or can be gleened from the current data.  Set the type.
1828  *
1829  * Check the current level (instance) and then check the higher level
1830  * (service).  This could be the case for adding a new property to
1831  * the instance that's going to "override" a service level property.
1832  *
1833  * For a property :
1834  * 1. Take the type from an existing property
1835  * 2. Take the type from a template entry
1836  *
1837  * If the type can not be found, then leave the type as is, and let the import
1838  * report the problem of the missing type.
1839  */
1840 static int
1841 find_current_prop_type(void *p, void *g)
1842 {
1843 	property_t *prop = p;
1844 	scf_callback_t *lcb = g;
1845 	pgroup_t *pg = NULL;
1846 
1847 	const char *fmri = NULL;
1848 	char *lfmri = NULL;
1849 	char *cur_selection = NULL;
1850 
1851 	scf_propertygroup_t *sc_pg = NULL;
1852 	scf_property_t *sc_prop = NULL;
1853 	scf_pg_tmpl_t *t_pg = NULL;
1854 	scf_prop_tmpl_t *t_prop = NULL;
1855 	scf_type_t prop_type;
1856 
1857 	value_t *vp;
1858 	int issvc = lcb->sc_service;
1859 	int r = UU_WALK_ERROR;
1860 
1861 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1862 		return (UU_WALK_NEXT);
1863 
1864 	t_prop = scf_tmpl_prop_create(g_hndl);
1865 	sc_prop = scf_property_create(g_hndl);
1866 	if (sc_prop == NULL || t_prop == NULL) {
1867 		warn(gettext("Unable to create the property to attempt and "
1868 		    "find a missing type.\n"));
1869 
1870 		scf_property_destroy(sc_prop);
1871 		scf_tmpl_prop_destroy(t_prop);
1872 
1873 		return (UU_WALK_ERROR);
1874 	}
1875 
1876 	if (lcb->sc_flags == 1) {
1877 		pg = lcb->sc_parent;
1878 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1879 		fmri = pg->sc_parent->sc_fmri;
1880 retry_pg:
1881 		if (cur_svc && cur_selection == NULL) {
1882 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1883 			lscf_get_selection_str(cur_selection,
1884 			    max_scf_fmri_len + 1);
1885 
1886 			if (strcmp(cur_selection, fmri) != 0) {
1887 				lscf_select(fmri);
1888 			} else {
1889 				free(cur_selection);
1890 				cur_selection = NULL;
1891 			}
1892 		} else {
1893 			lscf_select(fmri);
1894 		}
1895 
1896 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1897 			warn(gettext("Unable to create property group to "
1898 			    "find a missing property type.\n"));
1899 
1900 			goto out;
1901 		}
1902 
1903 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1904 			/*
1905 			 * If this is the sc_pg from the parent
1906 			 * let the caller clean up the sc_pg,
1907 			 * and just throw it away in this case.
1908 			 */
1909 			if (sc_pg != lcb->sc_parent)
1910 				scf_pg_destroy(sc_pg);
1911 
1912 			sc_pg = NULL;
1913 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1914 				warn(gettext("Unable to create template "
1915 				    "property group to find a property "
1916 				    "type.\n"));
1917 
1918 				goto out;
1919 			}
1920 
1921 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1922 			    pg->sc_pgroup_name, NULL, t_pg,
1923 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1924 				/*
1925 				 * if instance get service and jump back
1926 				 */
1927 				scf_tmpl_pg_destroy(t_pg);
1928 				t_pg = NULL;
1929 				if (issvc == 0) {
1930 					entity_t *e = pg->sc_parent->sc_parent;
1931 
1932 					fmri = e->sc_fmri;
1933 					issvc = 1;
1934 					goto retry_pg;
1935 				} else {
1936 					goto out;
1937 				}
1938 			}
1939 		}
1940 	} else {
1941 		sc_pg = lcb->sc_parent;
1942 	}
1943 
1944 	/*
1945 	 * Attempt to get the type from an existing property.  If the property
1946 	 * cannot be found then attempt to get the type from a template entry
1947 	 * for the property.
1948 	 *
1949 	 * Finally, if at the instance level look at the service level.
1950 	 */
1951 	if (sc_pg != NULL &&
1952 	    pg_get_prop(sc_pg, prop->sc_property_name,
1953 	    sc_prop) == SCF_SUCCESS &&
1954 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1955 		prop->sc_value_type = prop_type;
1956 
1957 		/*
1958 		 * Found a type, update the value types and validate
1959 		 * the actual value against this type.
1960 		 */
1961 		for (vp = uu_list_first(prop->sc_property_values);
1962 		    vp != NULL;
1963 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1964 			vp->sc_type = prop->sc_value_type;
1965 			lxml_store_value(vp, 0, NULL);
1966 		}
1967 
1968 		r = UU_WALK_NEXT;
1969 		goto out;
1970 	}
1971 
1972 	/*
1973 	 * If we get here with t_pg set to NULL then we had to have
1974 	 * gotten an sc_pg but that sc_pg did not have the property
1975 	 * we are looking for.   So if the t_pg is not null look up
1976 	 * the template entry for the property.
1977 	 *
1978 	 * If the t_pg is null then need to attempt to get a matching
1979 	 * template entry for the sc_pg, and see if there is a property
1980 	 * entry for that template entry.
1981 	 */
1982 do_tmpl :
1983 	if (t_pg != NULL &&
1984 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1985 	    t_prop, 0) == SCF_SUCCESS) {
1986 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1987 			prop->sc_value_type = prop_type;
1988 
1989 			/*
1990 			 * Found a type, update the value types and validate
1991 			 * the actual value against this type.
1992 			 */
1993 			for (vp = uu_list_first(prop->sc_property_values);
1994 			    vp != NULL;
1995 			    vp = uu_list_next(prop->sc_property_values, vp)) {
1996 				vp->sc_type = prop->sc_value_type;
1997 				lxml_store_value(vp, 0, NULL);
1998 			}
1999 
2000 			r = UU_WALK_NEXT;
2001 			goto out;
2002 		}
2003 	} else {
2004 		if (t_pg == NULL && sc_pg) {
2005 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2006 				warn(gettext("Unable to create template "
2007 				    "property group to find a property "
2008 				    "type.\n"));
2009 
2010 				goto out;
2011 			}
2012 
2013 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2014 				scf_tmpl_pg_destroy(t_pg);
2015 				t_pg = NULL;
2016 			} else {
2017 				goto do_tmpl;
2018 			}
2019 		}
2020 	}
2021 
2022 	if (issvc == 0) {
2023 		scf_instance_t *i;
2024 		scf_service_t *s;
2025 
2026 		issvc = 1;
2027 		if (lcb->sc_flags == 1) {
2028 			entity_t *e = pg->sc_parent->sc_parent;
2029 
2030 			fmri = e->sc_fmri;
2031 			goto retry_pg;
2032 		}
2033 
2034 		/*
2035 		 * because lcb->sc_flags was not set then this means
2036 		 * the pg was not used and can be used here.
2037 		 */
2038 		if ((pg = internal_pgroup_new()) == NULL) {
2039 			warn(gettext("Could not create internal property group "
2040 			    "to find a missing type."));
2041 
2042 			goto out;
2043 		}
2044 
2045 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2046 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2047 		    max_scf_name_len + 1) < 0)
2048 				goto out;
2049 
2050 		i = scf_instance_create(g_hndl);
2051 		s = scf_service_create(g_hndl);
2052 		if (i == NULL || s == NULL ||
2053 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2054 			warn(gettext("Could not get a service for the instance "
2055 			    "to find a missing type."));
2056 
2057 			goto out;
2058 		}
2059 
2060 		/*
2061 		 * Check to see truly at the instance level.
2062 		 */
2063 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2064 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2065 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2066 			goto out;
2067 		else
2068 			fmri = (const char *)lfmri;
2069 
2070 		goto retry_pg;
2071 	}
2072 
2073 out :
2074 	if (sc_pg != lcb->sc_parent) {
2075 		scf_pg_destroy(sc_pg);
2076 	}
2077 
2078 	/*
2079 	 * If this is true then the pg was allocated
2080 	 * here, and the name was set so need to free
2081 	 * the name and the pg.
2082 	 */
2083 	if (pg != NULL && pg != lcb->sc_parent) {
2084 		free((char *)pg->sc_pgroup_name);
2085 		internal_pgroup_free(pg);
2086 	}
2087 
2088 	if (cur_selection) {
2089 		lscf_select(cur_selection);
2090 		free(cur_selection);
2091 	}
2092 
2093 	scf_tmpl_pg_destroy(t_pg);
2094 	scf_tmpl_prop_destroy(t_prop);
2095 	scf_property_destroy(sc_prop);
2096 
2097 	if (r != UU_WALK_NEXT)
2098 		warn(gettext("Could not find property type for \"%s\" "
2099 		    "from \"%s\"\n"), prop->sc_property_name,
2100 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2101 
2102 	free(lfmri);
2103 
2104 	return (r);
2105 }
2106 
2107 /*
2108  * Take a property group that does not have a type and check to see if a type
2109  * exists or can be gleened from the current data.  Set the type.
2110  *
2111  * Check the current level (instance) and then check the higher level
2112  * (service).  This could be the case for adding a new property to
2113  * the instance that's going to "override" a service level property.
2114  *
2115  * For a property group
2116  * 1. Take the type from an existing property group
2117  * 2. Take the type from a template entry
2118  *
2119  * If the type can not be found, then leave the type as is, and let the import
2120  * report the problem of the missing type.
2121  */
2122 static int
2123 find_current_pg_type(void *p, void *sori)
2124 {
2125 	entity_t *si = sori;
2126 	pgroup_t *pg = p;
2127 
2128 	const char *ofmri, *fmri;
2129 	char *cur_selection = NULL;
2130 	char *pg_type = NULL;
2131 
2132 	scf_propertygroup_t *sc_pg = NULL;
2133 	scf_pg_tmpl_t *t_pg = NULL;
2134 
2135 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2136 	int r = UU_WALK_ERROR;
2137 
2138 	ofmri = fmri = si->sc_fmri;
2139 	if (pg->sc_pgroup_type != NULL) {
2140 		r = UU_WALK_NEXT;
2141 
2142 		goto out;
2143 	}
2144 
2145 	sc_pg = scf_pg_create(g_hndl);
2146 	if (sc_pg == NULL) {
2147 		warn(gettext("Unable to create property group to attempt "
2148 		    "and find a missing type.\n"));
2149 
2150 		return (UU_WALK_ERROR);
2151 	}
2152 
2153 	/*
2154 	 * Using get_pg() requires that the cur_svc/cur_inst be
2155 	 * via lscf_select.  Need to preserve the current selection
2156 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2157 	 */
2158 	if (cur_svc) {
2159 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2160 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2161 	}
2162 
2163 	/*
2164 	 * If the property group exists get the type, and set
2165 	 * the pgroup_t type of that type.
2166 	 *
2167 	 * If not the check for a template pg_pattern entry
2168 	 * and take the type from that.
2169 	 */
2170 retry_svc:
2171 	lscf_select(fmri);
2172 
2173 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2174 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2175 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2176 		    max_scf_pg_type_len + 1) != -1) {
2177 			pg->sc_pgroup_type = pg_type;
2178 
2179 			r = UU_WALK_NEXT;
2180 			goto out;
2181 		} else {
2182 			free(pg_type);
2183 		}
2184 	} else {
2185 		if ((t_pg == NULL) &&
2186 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2187 			goto out;
2188 
2189 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2190 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2191 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2192 			pg->sc_pgroup_type = pg_type;
2193 
2194 			r = UU_WALK_NEXT;
2195 			goto out;
2196 		}
2197 	}
2198 
2199 	/*
2200 	 * If type is not found at the instance level then attempt to
2201 	 * find the type at the service level.
2202 	 */
2203 	if (!issvc) {
2204 		si = si->sc_parent;
2205 		fmri = si->sc_fmri;
2206 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2207 		goto retry_svc;
2208 	}
2209 
2210 out :
2211 	if (cur_selection) {
2212 		lscf_select(cur_selection);
2213 		free(cur_selection);
2214 	}
2215 
2216 	/*
2217 	 * Now walk the properties of the property group to make sure that
2218 	 * all properties have the correct type and values are valid for
2219 	 * those types.
2220 	 */
2221 	if (r == UU_WALK_NEXT) {
2222 		scf_callback_t cb;
2223 
2224 		cb.sc_service = issvc;
2225 		cb.sc_source_fmri = ofmri;
2226 		if (sc_pg != NULL) {
2227 			cb.sc_parent = sc_pg;
2228 			cb.sc_flags = 0;
2229 		} else {
2230 			cb.sc_parent = pg;
2231 			cb.sc_flags = 1;
2232 		}
2233 
2234 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2235 		    &cb, UU_DEFAULT) != 0) {
2236 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2237 				bad_error("uu_list_walk", uu_error());
2238 
2239 			r = UU_WALK_ERROR;
2240 		}
2241 	} else {
2242 		warn(gettext("Could not find property group type for "
2243 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2244 	}
2245 
2246 	scf_tmpl_pg_destroy(t_pg);
2247 	scf_pg_destroy(sc_pg);
2248 
2249 	return (r);
2250 }
2251 
2252 /*
2253  * Import.  These functions import a bundle into the repository.
2254  */
2255 
2256 /*
2257  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2258  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2259  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2260  * lcbdata->sc_err to
2261  *   ENOMEM - out of memory
2262  *   ECONNABORTED - repository connection broken
2263  *   ECANCELED - sc_trans's property group was deleted
2264  *   EINVAL - p's name is invalid (error printed)
2265  *	    - p has an invalid value (error printed)
2266  */
2267 static int
2268 lscf_property_import(void *v, void *pvt)
2269 {
2270 	property_t *p = v;
2271 	scf_callback_t *lcbdata = pvt;
2272 	value_t *vp;
2273 	scf_transaction_t *trans = lcbdata->sc_trans;
2274 	scf_transaction_entry_t *entr;
2275 	scf_value_t *val;
2276 	scf_type_t tp;
2277 
2278 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2279 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2280 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2281 		lcbdata->sc_enable = p;
2282 		return (UU_WALK_NEXT);
2283 	}
2284 
2285 	entr = scf_entry_create(lcbdata->sc_handle);
2286 	if (entr == NULL) {
2287 		switch (scf_error()) {
2288 		case SCF_ERROR_NO_MEMORY:
2289 			return (stash_scferror(lcbdata));
2290 
2291 		case SCF_ERROR_INVALID_ARGUMENT:
2292 		default:
2293 			bad_error("scf_entry_create", scf_error());
2294 		}
2295 	}
2296 
2297 	tp = p->sc_value_type;
2298 
2299 	if (scf_transaction_property_new(trans, entr,
2300 	    p->sc_property_name, tp) != 0) {
2301 		switch (scf_error()) {
2302 		case SCF_ERROR_INVALID_ARGUMENT:
2303 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2304 			scf_entry_destroy(entr);
2305 			return (stash_scferror(lcbdata));
2306 
2307 		case SCF_ERROR_EXISTS:
2308 			break;
2309 
2310 		case SCF_ERROR_DELETED:
2311 		case SCF_ERROR_CONNECTION_BROKEN:
2312 			scf_entry_destroy(entr);
2313 			return (stash_scferror(lcbdata));
2314 
2315 		case SCF_ERROR_NOT_BOUND:
2316 		case SCF_ERROR_HANDLE_MISMATCH:
2317 		case SCF_ERROR_NOT_SET:
2318 		default:
2319 			bad_error("scf_transaction_property_new", scf_error());
2320 		}
2321 
2322 		if (scf_transaction_property_change_type(trans, entr,
2323 		    p->sc_property_name, tp) != 0) {
2324 			switch (scf_error()) {
2325 			case SCF_ERROR_DELETED:
2326 			case SCF_ERROR_CONNECTION_BROKEN:
2327 				scf_entry_destroy(entr);
2328 				return (stash_scferror(lcbdata));
2329 
2330 			case SCF_ERROR_INVALID_ARGUMENT:
2331 				semerr(emsg_invalid_prop_name,
2332 				    p->sc_property_name);
2333 				scf_entry_destroy(entr);
2334 				return (stash_scferror(lcbdata));
2335 
2336 			case SCF_ERROR_NOT_FOUND:
2337 			case SCF_ERROR_NOT_SET:
2338 			case SCF_ERROR_HANDLE_MISMATCH:
2339 			case SCF_ERROR_NOT_BOUND:
2340 			default:
2341 				bad_error(
2342 				    "scf_transaction_property_change_type",
2343 				    scf_error());
2344 			}
2345 		}
2346 	}
2347 
2348 	for (vp = uu_list_first(p->sc_property_values);
2349 	    vp != NULL;
2350 	    vp = uu_list_next(p->sc_property_values, vp)) {
2351 		val = scf_value_create(g_hndl);
2352 		if (val == NULL) {
2353 			switch (scf_error()) {
2354 			case SCF_ERROR_NO_MEMORY:
2355 				return (stash_scferror(lcbdata));
2356 
2357 			case SCF_ERROR_INVALID_ARGUMENT:
2358 			default:
2359 				bad_error("scf_value_create", scf_error());
2360 			}
2361 		}
2362 
2363 		switch (tp) {
2364 		case SCF_TYPE_BOOLEAN:
2365 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2366 			break;
2367 		case SCF_TYPE_COUNT:
2368 			scf_value_set_count(val, vp->sc_u.sc_count);
2369 			break;
2370 		case SCF_TYPE_INTEGER:
2371 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2372 			break;
2373 		default:
2374 			assert(vp->sc_u.sc_string != NULL);
2375 			if (scf_value_set_from_string(val, tp,
2376 			    vp->sc_u.sc_string) != 0) {
2377 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2378 					bad_error("scf_value_set_from_string",
2379 					    scf_error());
2380 
2381 				warn(gettext("Value \"%s\" is not a valid "
2382 				    "%s.\n"), vp->sc_u.sc_string,
2383 				    scf_type_to_string(tp));
2384 				scf_value_destroy(val);
2385 				return (stash_scferror(lcbdata));
2386 			}
2387 			break;
2388 		}
2389 
2390 		if (scf_entry_add_value(entr, val) != 0)
2391 			bad_error("scf_entry_add_value", scf_error());
2392 	}
2393 
2394 	return (UU_WALK_NEXT);
2395 }
2396 
2397 /*
2398  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2399  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2400  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2401  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2402  * lcbdata->sc_err to
2403  *   ECONNABORTED - repository connection broken
2404  *   ENOMEM - out of memory
2405  *   ENOSPC - svc.configd is out of resources
2406  *   ECANCELED - sc_parent was deleted
2407  *   EPERM - could not create property group (permission denied) (error printed)
2408  *	   - could not modify property group (permission denied) (error printed)
2409  *	   - could not delete property group (permission denied) (error	printed)
2410  *   EROFS - could not create property group (repository is read-only)
2411  *	   - could not delete property group (repository is read-only)
2412  *   EACCES - could not create property group (backend access denied)
2413  *	    - could not delete property group (backend access denied)
2414  *   EEXIST - could not create property group (already exists)
2415  *   EINVAL - invalid property group name (error printed)
2416  *	    - invalid property name (error printed)
2417  *	    - invalid value (error printed)
2418  *   EBUSY - new property group deleted (error printed)
2419  *	   - new property group changed (error printed)
2420  *	   - property group added (error printed)
2421  *	   - property group deleted (error printed)
2422  */
2423 static int
2424 entity_pgroup_import(void *v, void *pvt)
2425 {
2426 	pgroup_t *p = v;
2427 	scf_callback_t cbdata;
2428 	scf_callback_t *lcbdata = pvt;
2429 	void *ent = lcbdata->sc_parent;
2430 	int issvc = lcbdata->sc_service;
2431 	int r;
2432 
2433 	const char * const pg_changed = gettext("%s changed unexpectedly "
2434 	    "(new property group \"%s\" changed).\n");
2435 
2436 	/* Never import deleted property groups. */
2437 	if (p->sc_pgroup_delete) {
2438 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2439 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2440 			goto delete_pg;
2441 		}
2442 		return (UU_WALK_NEXT);
2443 	}
2444 
2445 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2446 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2447 		lcbdata->sc_general = p;
2448 		return (UU_WALK_NEXT);
2449 	}
2450 
2451 add_pg:
2452 	if (issvc)
2453 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2454 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2455 	else
2456 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2457 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2458 	if (r != 0) {
2459 		switch (scf_error()) {
2460 		case SCF_ERROR_DELETED:
2461 		case SCF_ERROR_CONNECTION_BROKEN:
2462 		case SCF_ERROR_BACKEND_READONLY:
2463 		case SCF_ERROR_BACKEND_ACCESS:
2464 		case SCF_ERROR_NO_RESOURCES:
2465 			return (stash_scferror(lcbdata));
2466 
2467 		case SCF_ERROR_EXISTS:
2468 			if (lcbdata->sc_flags & SCI_FORCE)
2469 				break;
2470 			return (stash_scferror(lcbdata));
2471 
2472 		case SCF_ERROR_INVALID_ARGUMENT:
2473 			warn(emsg_fmri_invalid_pg_name_type,
2474 			    lcbdata->sc_source_fmri,
2475 			    p->sc_pgroup_name, p->sc_pgroup_type);
2476 			return (stash_scferror(lcbdata));
2477 
2478 		case SCF_ERROR_PERMISSION_DENIED:
2479 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2480 			    lcbdata->sc_target_fmri);
2481 			return (stash_scferror(lcbdata));
2482 
2483 		case SCF_ERROR_NOT_BOUND:
2484 		case SCF_ERROR_HANDLE_MISMATCH:
2485 		case SCF_ERROR_NOT_SET:
2486 		default:
2487 			bad_error("scf_service_add_pg", scf_error());
2488 		}
2489 
2490 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2491 			switch (scf_error()) {
2492 			case SCF_ERROR_CONNECTION_BROKEN:
2493 			case SCF_ERROR_DELETED:
2494 				return (stash_scferror(lcbdata));
2495 
2496 			case SCF_ERROR_INVALID_ARGUMENT:
2497 				warn(emsg_fmri_invalid_pg_name,
2498 				    lcbdata->sc_source_fmri,
2499 				    p->sc_pgroup_name);
2500 				return (stash_scferror(lcbdata));
2501 
2502 			case SCF_ERROR_NOT_FOUND:
2503 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2504 				    p->sc_pgroup_name);
2505 				lcbdata->sc_err = EBUSY;
2506 				return (UU_WALK_ERROR);
2507 
2508 			case SCF_ERROR_NOT_BOUND:
2509 			case SCF_ERROR_HANDLE_MISMATCH:
2510 			case SCF_ERROR_NOT_SET:
2511 			default:
2512 				bad_error("entity_get_pg", scf_error());
2513 			}
2514 		}
2515 
2516 		if (lcbdata->sc_flags & SCI_KEEP)
2517 			goto props;
2518 
2519 delete_pg:
2520 		if (scf_pg_delete(imp_pg) != 0) {
2521 			switch (scf_error()) {
2522 			case SCF_ERROR_DELETED:
2523 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2524 				    p->sc_pgroup_name);
2525 				lcbdata->sc_err = EBUSY;
2526 				return (UU_WALK_ERROR);
2527 
2528 			case SCF_ERROR_PERMISSION_DENIED:
2529 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2530 				    lcbdata->sc_target_fmri);
2531 				return (stash_scferror(lcbdata));
2532 
2533 			case SCF_ERROR_BACKEND_READONLY:
2534 			case SCF_ERROR_BACKEND_ACCESS:
2535 			case SCF_ERROR_CONNECTION_BROKEN:
2536 				return (stash_scferror(lcbdata));
2537 
2538 			case SCF_ERROR_NOT_SET:
2539 			default:
2540 				bad_error("scf_pg_delete", scf_error());
2541 			}
2542 		}
2543 
2544 		if (p->sc_pgroup_delete)
2545 			return (UU_WALK_NEXT);
2546 
2547 		goto add_pg;
2548 	}
2549 
2550 props:
2551 
2552 	/*
2553 	 * Add properties to property group, if any.
2554 	 */
2555 	cbdata.sc_handle = lcbdata->sc_handle;
2556 	cbdata.sc_parent = imp_pg;
2557 	cbdata.sc_flags = lcbdata->sc_flags;
2558 	cbdata.sc_trans = imp_tx;
2559 	cbdata.sc_enable = NULL;
2560 
2561 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2562 		switch (scf_error()) {
2563 		case SCF_ERROR_BACKEND_ACCESS:
2564 		case SCF_ERROR_BACKEND_READONLY:
2565 		case SCF_ERROR_CONNECTION_BROKEN:
2566 			return (stash_scferror(lcbdata));
2567 
2568 		case SCF_ERROR_DELETED:
2569 			warn(pg_changed, lcbdata->sc_target_fmri,
2570 			    p->sc_pgroup_name);
2571 			lcbdata->sc_err = EBUSY;
2572 			return (UU_WALK_ERROR);
2573 
2574 		case SCF_ERROR_PERMISSION_DENIED:
2575 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2576 			    lcbdata->sc_target_fmri);
2577 			return (stash_scferror(lcbdata));
2578 
2579 		case SCF_ERROR_NOT_BOUND:
2580 		case SCF_ERROR_NOT_SET:
2581 		case SCF_ERROR_IN_USE:
2582 		case SCF_ERROR_HANDLE_MISMATCH:
2583 		default:
2584 			bad_error("scf_transaction_start", scf_error());
2585 		}
2586 	}
2587 
2588 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2589 	    UU_DEFAULT) != 0) {
2590 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2591 			bad_error("uu_list_walk", uu_error());
2592 		scf_transaction_reset(imp_tx);
2593 
2594 		lcbdata->sc_err = cbdata.sc_err;
2595 		if (cbdata.sc_err == ECANCELED) {
2596 			warn(pg_changed, lcbdata->sc_target_fmri,
2597 			    p->sc_pgroup_name);
2598 			lcbdata->sc_err = EBUSY;
2599 		}
2600 		return (UU_WALK_ERROR);
2601 	}
2602 
2603 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2604 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2605 
2606 		/*
2607 		 * take the snapshot running snapshot then
2608 		 * import the stored general/enable property
2609 		 */
2610 		r = take_snap(ent, snap_running, imp_rsnap);
2611 		switch (r) {
2612 		case 0:
2613 			break;
2614 
2615 		case ECONNABORTED:
2616 			warn(gettext("Could not take %s snapshot on import "
2617 			    "(repository connection broken).\n"),
2618 			    snap_running);
2619 			lcbdata->sc_err = r;
2620 			return (UU_WALK_ERROR);
2621 		case ECANCELED:
2622 			warn(emsg_deleted);
2623 			lcbdata->sc_err = r;
2624 			return (UU_WALK_ERROR);
2625 
2626 		case EPERM:
2627 			warn(gettext("Could not take %s snapshot "
2628 			    "(permission denied).\n"), snap_running);
2629 			lcbdata->sc_err = r;
2630 			return (UU_WALK_ERROR);
2631 
2632 		case ENOSPC:
2633 			warn(gettext("Could not take %s snapshot"
2634 			    "(repository server out of resources).\n"),
2635 			    snap_running);
2636 			lcbdata->sc_err = r;
2637 			return (UU_WALK_ERROR);
2638 
2639 		default:
2640 			bad_error("take_snap", r);
2641 		}
2642 
2643 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2644 		if (r != UU_WALK_NEXT) {
2645 			if (r != UU_WALK_ERROR)
2646 				bad_error("lscf_property_import", r);
2647 			return (EINVAL);
2648 		}
2649 	}
2650 
2651 	r = scf_transaction_commit(imp_tx);
2652 	switch (r) {
2653 	case 1:
2654 		r = UU_WALK_NEXT;
2655 		break;
2656 
2657 	case 0:
2658 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2659 		lcbdata->sc_err = EBUSY;
2660 		r = UU_WALK_ERROR;
2661 		break;
2662 
2663 	case -1:
2664 		switch (scf_error()) {
2665 		case SCF_ERROR_BACKEND_READONLY:
2666 		case SCF_ERROR_BACKEND_ACCESS:
2667 		case SCF_ERROR_CONNECTION_BROKEN:
2668 		case SCF_ERROR_NO_RESOURCES:
2669 			r = stash_scferror(lcbdata);
2670 			break;
2671 
2672 		case SCF_ERROR_DELETED:
2673 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2674 			    p->sc_pgroup_name);
2675 			lcbdata->sc_err = EBUSY;
2676 			r = UU_WALK_ERROR;
2677 			break;
2678 
2679 		case SCF_ERROR_PERMISSION_DENIED:
2680 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2681 			    lcbdata->sc_target_fmri);
2682 			r = stash_scferror(lcbdata);
2683 			break;
2684 
2685 		case SCF_ERROR_NOT_SET:
2686 		case SCF_ERROR_INVALID_ARGUMENT:
2687 		case SCF_ERROR_NOT_BOUND:
2688 		default:
2689 			bad_error("scf_transaction_commit", scf_error());
2690 		}
2691 		break;
2692 
2693 	default:
2694 		bad_error("scf_transaction_commit", r);
2695 	}
2696 
2697 	scf_transaction_destroy_children(imp_tx);
2698 
2699 	return (r);
2700 }
2701 
2702 /*
2703  * Returns
2704  *   0 - success
2705  *   ECONNABORTED - repository connection broken
2706  *   ENOMEM - out of memory
2707  *   ENOSPC - svc.configd is out of resources
2708  *   ECANCELED - inst was deleted
2709  *   EPERM - could not create property group (permission denied) (error printed)
2710  *	   - could not modify property group (permission denied) (error printed)
2711  *   EROFS - could not create property group (repository is read-only)
2712  *   EACCES - could not create property group (backend access denied)
2713  *   EEXIST - could not create property group (already exists)
2714  *   EINVAL - invalid property group name (error printed)
2715  *	    - invalid property name (error printed)
2716  *	    - invalid value (error printed)
2717  *   EBUSY - new property group changed (error printed)
2718  */
2719 static int
2720 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2721     const entity_t *isvc, int flags)
2722 {
2723 	scf_callback_t cbdata;
2724 
2725 	cbdata.sc_handle = scf_service_handle(svc);
2726 	cbdata.sc_parent = svc;
2727 	cbdata.sc_service = 1;
2728 	cbdata.sc_general = 0;
2729 	cbdata.sc_enable = 0;
2730 	cbdata.sc_flags = flags;
2731 	cbdata.sc_source_fmri = isvc->sc_fmri;
2732 	cbdata.sc_target_fmri = target_fmri;
2733 
2734 	/*
2735 	 * If the op is set, then add the flag to the callback
2736 	 * flags for later use.
2737 	 */
2738 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2739 		switch (isvc->sc_op) {
2740 		case SVCCFG_OP_IMPORT :
2741 			cbdata.sc_flags |= SCI_OP_IMPORT;
2742 			break;
2743 		case SVCCFG_OP_APPLY :
2744 			cbdata.sc_flags |= SCI_OP_APPLY;
2745 			break;
2746 		case SVCCFG_OP_RESTORE :
2747 			cbdata.sc_flags |= SCI_OP_RESTORE;
2748 			break;
2749 		default :
2750 			uu_die(gettext("lscf_import_service_pgs : "
2751 			    "Unknown op stored in the service entity\n"));
2752 
2753 		}
2754 	}
2755 
2756 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2757 	    UU_DEFAULT) != 0) {
2758 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2759 			bad_error("uu_list_walk", uu_error());
2760 
2761 		return (cbdata.sc_err);
2762 	}
2763 
2764 	return (0);
2765 }
2766 
2767 /*
2768  * Returns
2769  *   0 - success
2770  *   ECONNABORTED - repository connection broken
2771  *   ENOMEM - out of memory
2772  *   ENOSPC - svc.configd is out of resources
2773  *   ECANCELED - inst was deleted
2774  *   EPERM - could not create property group (permission denied) (error printed)
2775  *	   - could not modify property group (permission denied) (error printed)
2776  *   EROFS - could not create property group (repository is read-only)
2777  *   EACCES - could not create property group (backend access denied)
2778  *   EEXIST - could not create property group (already exists)
2779  *   EINVAL - invalid property group name (error printed)
2780  *	    - invalid property name (error printed)
2781  *	    - invalid value (error printed)
2782  *   EBUSY - new property group changed (error printed)
2783  */
2784 static int
2785 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2786     const entity_t *iinst, int flags)
2787 {
2788 	scf_callback_t cbdata;
2789 
2790 	cbdata.sc_handle = scf_instance_handle(inst);
2791 	cbdata.sc_parent = inst;
2792 	cbdata.sc_service = 0;
2793 	cbdata.sc_general = NULL;
2794 	cbdata.sc_enable = NULL;
2795 	cbdata.sc_flags = flags;
2796 	cbdata.sc_source_fmri = iinst->sc_fmri;
2797 	cbdata.sc_target_fmri = target_fmri;
2798 
2799 	/*
2800 	 * If the op is set, then add the flag to the callback
2801 	 * flags for later use.
2802 	 */
2803 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2804 		switch (iinst->sc_op) {
2805 		case SVCCFG_OP_IMPORT :
2806 			cbdata.sc_flags |= SCI_OP_IMPORT;
2807 			break;
2808 		case SVCCFG_OP_APPLY :
2809 			cbdata.sc_flags |= SCI_OP_APPLY;
2810 			break;
2811 		case SVCCFG_OP_RESTORE :
2812 			cbdata.sc_flags |= SCI_OP_RESTORE;
2813 			break;
2814 		default :
2815 			uu_die(gettext("lscf_import_instance_pgs : "
2816 			    "Unknown op stored in the instance entity\n"));
2817 		}
2818 	}
2819 
2820 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2821 	    UU_DEFAULT) != 0) {
2822 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2823 			bad_error("uu_list_walk", uu_error());
2824 
2825 		return (cbdata.sc_err);
2826 	}
2827 
2828 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2829 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2830 		/*
2831 		 * If importing with the SCI_NOENABLED flag then
2832 		 * skip the delay, but if not then add the delay
2833 		 * of the enable property.
2834 		 */
2835 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2836 			cbdata.sc_flags |= SCI_DELAYENABLE;
2837 		}
2838 
2839 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2840 		    != UU_WALK_NEXT)
2841 			return (cbdata.sc_err);
2842 	}
2843 
2844 	return (0);
2845 }
2846 
2847 /*
2848  * Report the reasons why we can't upgrade pg2 to pg1.
2849  */
2850 static void
2851 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2852     int new)
2853 {
2854 	property_t *p1, *p2;
2855 
2856 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2857 
2858 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2859 		return;
2860 
2861 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2862 	    p1 != NULL;
2863 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2864 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2865 		if (p2 != NULL) {
2866 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2867 			    new);
2868 			continue;
2869 		}
2870 
2871 		if (new)
2872 			warn(gettext("Conflict upgrading %s (new property "
2873 			    "group \"%s\" is missing property \"%s\").\n"),
2874 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2875 		else
2876 			warn(gettext("Conflict upgrading %s (property "
2877 			    "\"%s/%s\" is missing).\n"), fmri,
2878 			    pg1->sc_pgroup_name, p1->sc_property_name);
2879 	}
2880 
2881 	/*
2882 	 * Since pg1 should be from the manifest, any properties in pg2 which
2883 	 * aren't in pg1 shouldn't be reported as conflicts.
2884 	 */
2885 }
2886 
2887 /*
2888  * Add transaction entries to tx which will upgrade cur's pg according to old
2889  * & new.
2890  *
2891  * Returns
2892  *   0 - success
2893  *   EINVAL - new has a property with an invalid name or value (message emitted)
2894  *   ENOMEM - out of memory
2895  */
2896 static int
2897 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2898     pgroup_t *cur, int speak, const char *fmri)
2899 {
2900 	property_t *p, *new_p, *cur_p;
2901 	scf_transaction_entry_t *e;
2902 	int r;
2903 	int is_general;
2904 	int is_protected;
2905 
2906 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2907 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2908 		bad_error("uu_list_walk", uu_error());
2909 
2910 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2911 
2912 	for (p = uu_list_first(old->sc_pgroup_props);
2913 	    p != NULL;
2914 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2915 		/* p is a property in the old property group. */
2916 
2917 		/* Protect live properties. */
2918 		is_protected = 0;
2919 		if (is_general) {
2920 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2921 			    0 ||
2922 			    strcmp(p->sc_property_name,
2923 			    SCF_PROPERTY_RESTARTER) == 0)
2924 				is_protected = 1;
2925 		}
2926 
2927 		/* Look for the same property in the new properties. */
2928 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2929 		if (new_p != NULL) {
2930 			new_p->sc_seen = 1;
2931 
2932 			/*
2933 			 * If the new property is the same as the old, don't do
2934 			 * anything (leave any user customizations).
2935 			 */
2936 			if (prop_equal(p, new_p, NULL, NULL, 0))
2937 				continue;
2938 
2939 			if (new_p->sc_property_override)
2940 				goto upgrade;
2941 		}
2942 
2943 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2944 		if (cur_p == NULL) {
2945 			/*
2946 			 * p has been deleted from the repository.  If we were
2947 			 * going to delete it anyway, do nothing.  Otherwise
2948 			 * report a conflict.
2949 			 */
2950 			if (new_p == NULL)
2951 				continue;
2952 
2953 			if (is_protected)
2954 				continue;
2955 
2956 			warn(gettext("Conflict upgrading %s "
2957 			    "(property \"%s/%s\" is missing).\n"), fmri,
2958 			    old->sc_pgroup_name, p->sc_property_name);
2959 			continue;
2960 		}
2961 
2962 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2963 			/*
2964 			 * Conflict.  Don't warn if the property is already the
2965 			 * way we want it, though.
2966 			 */
2967 			if (is_protected)
2968 				continue;
2969 
2970 			if (new_p == NULL)
2971 				(void) prop_equal(p, cur_p, fmri,
2972 				    old->sc_pgroup_name, 0);
2973 			else
2974 				(void) prop_equal(cur_p, new_p, fmri,
2975 				    old->sc_pgroup_name, 0);
2976 			continue;
2977 		}
2978 
2979 		if (is_protected) {
2980 			if (speak)
2981 				warn(gettext("%s: Refusing to upgrade "
2982 				    "\"%s/%s\" (live property).\n"), fmri,
2983 				    old->sc_pgroup_name, p->sc_property_name);
2984 			continue;
2985 		}
2986 
2987 upgrade:
2988 		/* p hasn't been customized in the repository.  Upgrade it. */
2989 		if (new_p == NULL) {
2990 			/* p was deleted.  Delete from cur if unchanged. */
2991 			if (speak)
2992 				warn(gettext(
2993 				    "%s: Deleting property \"%s/%s\".\n"),
2994 				    fmri, old->sc_pgroup_name,
2995 				    p->sc_property_name);
2996 
2997 			e = scf_entry_create(g_hndl);
2998 			if (e == NULL)
2999 				return (ENOMEM);
3000 
3001 			if (scf_transaction_property_delete(tx, e,
3002 			    p->sc_property_name) != 0) {
3003 				switch (scf_error()) {
3004 				case SCF_ERROR_DELETED:
3005 					scf_entry_destroy(e);
3006 					return (ECANCELED);
3007 
3008 				case SCF_ERROR_CONNECTION_BROKEN:
3009 					scf_entry_destroy(e);
3010 					return (ECONNABORTED);
3011 
3012 				case SCF_ERROR_NOT_FOUND:
3013 					/*
3014 					 * This can happen if cur is from the
3015 					 * running snapshot (and it differs
3016 					 * from the live properties).
3017 					 */
3018 					scf_entry_destroy(e);
3019 					break;
3020 
3021 				case SCF_ERROR_HANDLE_MISMATCH:
3022 				case SCF_ERROR_NOT_BOUND:
3023 				case SCF_ERROR_NOT_SET:
3024 				case SCF_ERROR_INVALID_ARGUMENT:
3025 				default:
3026 					bad_error(
3027 					    "scf_transaction_property_delete",
3028 					    scf_error());
3029 				}
3030 			}
3031 		} else {
3032 			scf_callback_t ctx;
3033 
3034 			if (speak)
3035 				warn(gettext(
3036 				    "%s: Upgrading property \"%s/%s\".\n"),
3037 				    fmri, old->sc_pgroup_name,
3038 				    p->sc_property_name);
3039 
3040 			ctx.sc_handle = g_hndl;
3041 			ctx.sc_trans = tx;
3042 			ctx.sc_flags = 0;
3043 
3044 			r = lscf_property_import(new_p, &ctx);
3045 			if (r != UU_WALK_NEXT) {
3046 				if (r != UU_WALK_ERROR)
3047 					bad_error("lscf_property_import", r);
3048 				return (EINVAL);
3049 			}
3050 		}
3051 	}
3052 
3053 	/* Go over the properties which were added. */
3054 	for (new_p = uu_list_first(new->sc_pgroup_props);
3055 	    new_p != NULL;
3056 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3057 		if (new_p->sc_seen)
3058 			continue;
3059 
3060 		/* This is a new property. */
3061 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3062 		if (cur_p == NULL) {
3063 			scf_callback_t ctx;
3064 
3065 			ctx.sc_handle = g_hndl;
3066 			ctx.sc_trans = tx;
3067 			ctx.sc_flags = 0;
3068 
3069 			r = lscf_property_import(new_p, &ctx);
3070 			if (r != UU_WALK_NEXT) {
3071 				if (r != UU_WALK_ERROR)
3072 					bad_error("lscf_property_import", r);
3073 				return (EINVAL);
3074 			}
3075 			continue;
3076 		}
3077 
3078 		/*
3079 		 * Report a conflict if the new property differs from the
3080 		 * current one.  Unless it's general/enabled, since that's
3081 		 * never in the last-import snapshot.
3082 		 */
3083 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3084 		    0 &&
3085 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3086 			continue;
3087 
3088 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3089 	}
3090 
3091 	return (0);
3092 }
3093 
3094 /*
3095  * Upgrade pg according to old & new.
3096  *
3097  * Returns
3098  *   0 - success
3099  *   ECONNABORTED - repository connection broken
3100  *   ENOMEM - out of memory
3101  *   ENOSPC - svc.configd is out of resources
3102  *   ECANCELED - pg was deleted
3103  *   EPERM - couldn't modify pg (permission denied)
3104  *   EROFS - couldn't modify pg (backend read-only)
3105  *   EACCES - couldn't modify pg (backend access denied)
3106  *   EINVAL - new has a property with invalid name or value (error printed)
3107  *   EBUSY - pg changed unexpectedly
3108  */
3109 static int
3110 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3111     pgroup_t *new, int speak, const char *fmri)
3112 {
3113 	int r;
3114 
3115 	if (scf_transaction_start(imp_tx, pg) != 0) {
3116 		switch (scf_error()) {
3117 		case SCF_ERROR_CONNECTION_BROKEN:
3118 		case SCF_ERROR_DELETED:
3119 		case SCF_ERROR_PERMISSION_DENIED:
3120 		case SCF_ERROR_BACKEND_READONLY:
3121 		case SCF_ERROR_BACKEND_ACCESS:
3122 			return (scferror2errno(scf_error()));
3123 
3124 		case SCF_ERROR_HANDLE_MISMATCH:
3125 		case SCF_ERROR_IN_USE:
3126 		case SCF_ERROR_NOT_BOUND:
3127 		case SCF_ERROR_NOT_SET:
3128 		default:
3129 			bad_error("scf_transaction_start", scf_error());
3130 		}
3131 	}
3132 
3133 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3134 	switch (r) {
3135 	case 0:
3136 		break;
3137 
3138 	case EINVAL:
3139 	case ENOMEM:
3140 		scf_transaction_destroy_children(imp_tx);
3141 		return (r);
3142 
3143 	default:
3144 		bad_error("add_upgrade_entries", r);
3145 	}
3146 
3147 	r = scf_transaction_commit(imp_tx);
3148 
3149 	scf_transaction_destroy_children(imp_tx);
3150 
3151 	switch (r) {
3152 	case 1:
3153 		break;
3154 
3155 	case 0:
3156 		return (EBUSY);
3157 
3158 	case -1:
3159 		switch (scf_error()) {
3160 		case SCF_ERROR_CONNECTION_BROKEN:
3161 		case SCF_ERROR_NO_RESOURCES:
3162 		case SCF_ERROR_PERMISSION_DENIED:
3163 		case SCF_ERROR_BACKEND_READONLY:
3164 		case SCF_ERROR_BACKEND_ACCESS:
3165 		case SCF_ERROR_DELETED:
3166 			return (scferror2errno(scf_error()));
3167 
3168 		case SCF_ERROR_NOT_BOUND:
3169 		case SCF_ERROR_INVALID_ARGUMENT:
3170 		case SCF_ERROR_NOT_SET:
3171 		default:
3172 			bad_error("scf_transaction_commit", scf_error());
3173 		}
3174 
3175 	default:
3176 		bad_error("scf_transaction_commit", r);
3177 	}
3178 
3179 	return (0);
3180 }
3181 
3182 /*
3183  * Compares two entity FMRIs.  Returns
3184  *
3185  *   1 - equal
3186  *   0 - not equal
3187  *   -1 - f1 is invalid or not an entity
3188  *   -2 - f2 is invalid or not an entity
3189  */
3190 static int
3191 fmri_equal(const char *f1, const char *f2)
3192 {
3193 	int r;
3194 	const char *s1, *i1, *pg1;
3195 	const char *s2, *i2, *pg2;
3196 
3197 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3198 		return (-1);
3199 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3200 		return (-1);
3201 
3202 	if (s1 == NULL || pg1 != NULL)
3203 		return (-1);
3204 
3205 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3206 		return (-2);
3207 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3208 		return (-2);
3209 
3210 	if (s2 == NULL || pg2 != NULL)
3211 		return (-2);
3212 
3213 	r = strcmp(s1, s2);
3214 	if (r != 0)
3215 		return (0);
3216 
3217 	if (i1 == NULL && i2 == NULL)
3218 		return (1);
3219 
3220 	if (i1 == NULL || i2 == NULL)
3221 		return (0);
3222 
3223 	return (strcmp(i1, i2) == 0);
3224 }
3225 
3226 /*
3227  * Import a dependent by creating a dependency property group in the dependent
3228  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3229  * dependents pg, and add an entry to create a new property for this
3230  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3231  *
3232  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3233  * lcbdata->sc_err to
3234  *   ECONNABORTED - repository connection broken
3235  *   ENOMEM - out of memory
3236  *   ENOSPC - configd is out of resources
3237  *   EINVAL - target is invalid (error printed)
3238  *	    - target is not an entity (error printed)
3239  *	    - dependent has invalid name (error printed)
3240  *	    - invalid property name (error printed)
3241  *	    - invalid value (error printed)
3242  *	    - scope of target does not exist (error printed)
3243  *   EPERM - couldn't create target (permission denied) (error printed)
3244  *	   - couldn't create dependency pg (permission denied) (error printed)
3245  *	   - couldn't modify dependency pg (permission denied) (error printed)
3246  *   EROFS - couldn't create target (repository read-only)
3247  *	   - couldn't create dependency pg (repository read-only)
3248  *   EACCES - couldn't create target (backend access denied)
3249  *	    - couldn't create dependency pg (backend access denied)
3250  *   ECANCELED - sc_trans's pg was deleted
3251  *   EALREADY - property for dependent already exists in sc_trans's pg
3252  *   EEXIST - dependency pg already exists in target (error printed)
3253  *   EBUSY - target deleted (error printed)
3254  *         - property group changed during import (error printed)
3255  */
3256 static int
3257 lscf_dependent_import(void *a1, void *pvt)
3258 {
3259 	pgroup_t *pgrp = a1;
3260 	scf_callback_t *lcbdata = pvt;
3261 
3262 	int isservice;
3263 	int ret;
3264 	scf_transaction_entry_t *e;
3265 	scf_value_t *val;
3266 	scf_callback_t dependent_cbdata;
3267 	scf_error_t scfe;
3268 
3269 	/*
3270 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3271 	 * it's invalid, we fail before modifying the repository.
3272 	 */
3273 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3274 	    &dependent_cbdata.sc_parent, &isservice);
3275 	switch (scfe) {
3276 	case SCF_ERROR_NONE:
3277 		break;
3278 
3279 	case SCF_ERROR_NO_MEMORY:
3280 		return (stash_scferror_err(lcbdata, scfe));
3281 
3282 	case SCF_ERROR_INVALID_ARGUMENT:
3283 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3284 		    "invalid.\n"), pgrp->sc_pgroup_name);
3285 		return (stash_scferror_err(lcbdata, scfe));
3286 
3287 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3288 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3289 		    "specifies neither a service nor an instance.\n"),
3290 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3291 		return (stash_scferror_err(lcbdata, scfe));
3292 
3293 	case SCF_ERROR_NOT_FOUND:
3294 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3295 		    &dependent_cbdata.sc_parent, &isservice);
3296 		switch (scfe) {
3297 		case SCF_ERROR_NONE:
3298 			break;
3299 
3300 		case SCF_ERROR_NO_MEMORY:
3301 		case SCF_ERROR_BACKEND_READONLY:
3302 		case SCF_ERROR_BACKEND_ACCESS:
3303 			return (stash_scferror_err(lcbdata, scfe));
3304 
3305 		case SCF_ERROR_NOT_FOUND:
3306 			semerr(gettext("The scope in FMRI \"%s\" for the "
3307 			    "\"%s\" dependent does not exist.\n"),
3308 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3309 			lcbdata->sc_err = EINVAL;
3310 			return (UU_WALK_ERROR);
3311 
3312 		case SCF_ERROR_PERMISSION_DENIED:
3313 			warn(gettext(
3314 			    "Could not create %s (permission denied).\n"),
3315 			    pgrp->sc_pgroup_fmri);
3316 			return (stash_scferror_err(lcbdata, scfe));
3317 
3318 		case SCF_ERROR_INVALID_ARGUMENT:
3319 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3320 		default:
3321 			bad_error("create_entity", scfe);
3322 		}
3323 		break;
3324 
3325 	default:
3326 		bad_error("fmri_to_entity", scfe);
3327 	}
3328 
3329 	if (lcbdata->sc_trans != NULL) {
3330 		e = scf_entry_create(lcbdata->sc_handle);
3331 		if (e == NULL) {
3332 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3333 				bad_error("scf_entry_create", scf_error());
3334 
3335 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3336 			return (stash_scferror(lcbdata));
3337 		}
3338 
3339 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3340 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3341 			switch (scf_error()) {
3342 			case SCF_ERROR_INVALID_ARGUMENT:
3343 				warn(gettext("Dependent of %s has invalid name "
3344 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3345 				    pgrp->sc_pgroup_name);
3346 				/* FALLTHROUGH */
3347 
3348 			case SCF_ERROR_DELETED:
3349 			case SCF_ERROR_CONNECTION_BROKEN:
3350 				scf_entry_destroy(e);
3351 				entity_destroy(dependent_cbdata.sc_parent,
3352 				    isservice);
3353 				return (stash_scferror(lcbdata));
3354 
3355 			case SCF_ERROR_EXISTS:
3356 				scf_entry_destroy(e);
3357 				entity_destroy(dependent_cbdata.sc_parent,
3358 				    isservice);
3359 				lcbdata->sc_err = EALREADY;
3360 				return (UU_WALK_ERROR);
3361 
3362 			case SCF_ERROR_NOT_BOUND:
3363 			case SCF_ERROR_HANDLE_MISMATCH:
3364 			case SCF_ERROR_NOT_SET:
3365 			default:
3366 				bad_error("scf_transaction_property_new",
3367 				    scf_error());
3368 			}
3369 		}
3370 
3371 		val = scf_value_create(lcbdata->sc_handle);
3372 		if (val == NULL) {
3373 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3374 				bad_error("scf_value_create", scf_error());
3375 
3376 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3377 			return (stash_scferror(lcbdata));
3378 		}
3379 
3380 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3381 		    pgrp->sc_pgroup_fmri) != 0)
3382 			/* invalid should have been caught above */
3383 			bad_error("scf_value_set_from_string", scf_error());
3384 
3385 		if (scf_entry_add_value(e, val) != 0)
3386 			bad_error("scf_entry_add_value", scf_error());
3387 	}
3388 
3389 	/* Add the property group to the target entity. */
3390 
3391 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3392 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3393 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3394 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3395 
3396 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3397 
3398 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3399 
3400 	if (ret == UU_WALK_NEXT)
3401 		return (ret);
3402 
3403 	if (ret != UU_WALK_ERROR)
3404 		bad_error("entity_pgroup_import", ret);
3405 
3406 	switch (dependent_cbdata.sc_err) {
3407 	case ECANCELED:
3408 		warn(gettext("%s deleted unexpectedly.\n"),
3409 		    pgrp->sc_pgroup_fmri);
3410 		lcbdata->sc_err = EBUSY;
3411 		break;
3412 
3413 	case EEXIST:
3414 		warn(gettext("Could not create \"%s\" dependency in %s "
3415 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3416 		    pgrp->sc_pgroup_fmri);
3417 		/* FALLTHROUGH */
3418 
3419 	default:
3420 		lcbdata->sc_err = dependent_cbdata.sc_err;
3421 	}
3422 
3423 	return (UU_WALK_ERROR);
3424 }
3425 
3426 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3427     const scf_snaplevel_t *, scf_transaction_t *);
3428 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3429     const pgroup_t *);
3430 
3431 /*
3432  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3433  * the current dependent targets from running (the snaplevel of a running
3434  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3435  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3436  * dependent targets and dependency properties from li_dpts_pg (the
3437  * "dependents" property group in snpl) and snpl (the snaplevel which
3438  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3439  * snpl doesn't have a "dependents" property group, and any dependents in ient
3440  * are new.
3441  *
3442  * Returns
3443  *   0 - success
3444  *   ECONNABORTED - repository connection broken
3445  *   ENOMEM - out of memory
3446  *   ENOSPC - configd is out of resources
3447  *   ECANCELED - ent was deleted
3448  *   ENODEV - the entity containing li_dpts_pg was deleted
3449  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3450  *	   - couldn't upgrade dependent (permission denied) (error printed)
3451  *	   - couldn't create dependent (permission denied) (error printed)
3452  *   EROFS - could not modify dependents pg (repository read-only)
3453  *	   - couldn't upgrade dependent (repository read-only)
3454  *	   - couldn't create dependent (repository read-only)
3455  *   EACCES - could not modify dependents pg (backend access denied)
3456  *	    - could not upgrade dependent (backend access denied)
3457  *	    - could not create dependent (backend access denied)
3458  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3459  *	   - dependent target deleted (error printed)
3460  *	   - dependent pg changed (error printed)
3461  *   EINVAL - new dependent is invalid (error printed)
3462  *   EBADF - snpl is corrupt (error printed)
3463  *	   - snpl has corrupt pg (error printed)
3464  *	   - dependency pg in target is corrupt (error printed)
3465  *	   - target has corrupt snapshot (error printed)
3466  *   EEXIST - dependency pg already existed in target service (error printed)
3467  */
3468 static int
3469 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3470     const scf_snaplevel_t *snpl, const entity_t *ient,
3471     const scf_snaplevel_t *running, void *ent)
3472 {
3473 	pgroup_t *new_dpt_pgroup;
3474 	scf_callback_t cbdata;
3475 	int r, unseen, tx_started = 0;
3476 	int have_cur_depts;
3477 
3478 	const char * const dependents = "dependents";
3479 
3480 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3481 
3482 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3483 		/* Nothing to do. */
3484 		return (0);
3485 
3486 	/* Fetch the current version of the "dependents" property group. */
3487 	have_cur_depts = 1;
3488 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3489 		switch (scf_error()) {
3490 		case SCF_ERROR_NOT_FOUND:
3491 			break;
3492 
3493 		case SCF_ERROR_DELETED:
3494 		case SCF_ERROR_CONNECTION_BROKEN:
3495 			return (scferror2errno(scf_error()));
3496 
3497 		case SCF_ERROR_NOT_SET:
3498 		case SCF_ERROR_INVALID_ARGUMENT:
3499 		case SCF_ERROR_HANDLE_MISMATCH:
3500 		case SCF_ERROR_NOT_BOUND:
3501 		default:
3502 			bad_error("entity_get_pg", scf_error());
3503 		}
3504 
3505 		have_cur_depts = 0;
3506 	}
3507 
3508 	/* Fetch the running version of the "dependents" property group. */
3509 	ud_run_dpts_pg_set = 0;
3510 	if (running != NULL)
3511 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3512 	else
3513 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3514 	if (r == 0) {
3515 		ud_run_dpts_pg_set = 1;
3516 	} else {
3517 		switch (scf_error()) {
3518 		case SCF_ERROR_NOT_FOUND:
3519 			break;
3520 
3521 		case SCF_ERROR_DELETED:
3522 		case SCF_ERROR_CONNECTION_BROKEN:
3523 			return (scferror2errno(scf_error()));
3524 
3525 		case SCF_ERROR_NOT_SET:
3526 		case SCF_ERROR_INVALID_ARGUMENT:
3527 		case SCF_ERROR_HANDLE_MISMATCH:
3528 		case SCF_ERROR_NOT_BOUND:
3529 		default:
3530 			bad_error(running ? "scf_snaplevel_get_pg" :
3531 			    "entity_get_pg", scf_error());
3532 		}
3533 	}
3534 
3535 	/*
3536 	 * Clear the seen fields of the dependents, so we can tell which ones
3537 	 * are new.
3538 	 */
3539 	if (uu_list_walk(ient->sc_dependents, clear_int,
3540 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3541 		bad_error("uu_list_walk", uu_error());
3542 
3543 	if (li_dpts_pg != NULL) {
3544 		/*
3545 		 * Each property in li_dpts_pg represents a dependent tag in
3546 		 * the old manifest.  For each, call upgrade_dependent(),
3547 		 * which will change ud_cur_depts_pg or dependencies in other
3548 		 * services as appropriate.  Note (a) that changes to
3549 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3550 		 * made en masse, and (b) it's ok if the entity doesn't have
3551 		 * a current version of the "dependents" property group,
3552 		 * because we'll just consider all dependents as customized
3553 		 * (by being deleted).
3554 		 */
3555 
3556 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3557 			switch (scf_error()) {
3558 			case SCF_ERROR_DELETED:
3559 				return (ENODEV);
3560 
3561 			case SCF_ERROR_CONNECTION_BROKEN:
3562 				return (ECONNABORTED);
3563 
3564 			case SCF_ERROR_HANDLE_MISMATCH:
3565 			case SCF_ERROR_NOT_BOUND:
3566 			case SCF_ERROR_NOT_SET:
3567 			default:
3568 				bad_error("scf_iter_pg_properties",
3569 				    scf_error());
3570 			}
3571 		}
3572 
3573 		if (have_cur_depts &&
3574 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3575 			switch (scf_error()) {
3576 			case SCF_ERROR_BACKEND_ACCESS:
3577 			case SCF_ERROR_BACKEND_READONLY:
3578 			case SCF_ERROR_CONNECTION_BROKEN:
3579 				return (scferror2errno(scf_error()));
3580 
3581 			case SCF_ERROR_DELETED:
3582 				warn(emsg_pg_deleted, ient->sc_fmri,
3583 				    dependents);
3584 				return (EBUSY);
3585 
3586 			case SCF_ERROR_PERMISSION_DENIED:
3587 				warn(emsg_pg_mod_perm, dependents,
3588 				    ient->sc_fmri);
3589 				return (scferror2errno(scf_error()));
3590 
3591 			case SCF_ERROR_HANDLE_MISMATCH:
3592 			case SCF_ERROR_IN_USE:
3593 			case SCF_ERROR_NOT_BOUND:
3594 			case SCF_ERROR_NOT_SET:
3595 			default:
3596 				bad_error("scf_transaction_start", scf_error());
3597 			}
3598 		}
3599 		tx_started = have_cur_depts;
3600 
3601 		for (;;) {
3602 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3603 			if (r == 0)
3604 				break;
3605 			if (r == 1) {
3606 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3607 				    tx_started ? ud_tx : NULL);
3608 				switch (r) {
3609 				case 0:
3610 					continue;
3611 
3612 				case ECONNABORTED:
3613 				case ENOMEM:
3614 				case ENOSPC:
3615 				case EBADF:
3616 				case EBUSY:
3617 				case EINVAL:
3618 				case EPERM:
3619 				case EROFS:
3620 				case EACCES:
3621 				case EEXIST:
3622 					break;
3623 
3624 				case ECANCELED:
3625 					r = ENODEV;
3626 					break;
3627 
3628 				default:
3629 					bad_error("upgrade_dependent", r);
3630 				}
3631 
3632 				if (tx_started)
3633 					scf_transaction_destroy_children(ud_tx);
3634 				return (r);
3635 			}
3636 			if (r != -1)
3637 				bad_error("scf_iter_next_property", r);
3638 
3639 			switch (scf_error()) {
3640 			case SCF_ERROR_DELETED:
3641 				r = ENODEV;
3642 				break;
3643 
3644 			case SCF_ERROR_CONNECTION_BROKEN:
3645 				r = ECONNABORTED;
3646 				break;
3647 
3648 			case SCF_ERROR_NOT_SET:
3649 			case SCF_ERROR_INVALID_ARGUMENT:
3650 			case SCF_ERROR_NOT_BOUND:
3651 			case SCF_ERROR_HANDLE_MISMATCH:
3652 			default:
3653 				bad_error("scf_iter_next_property",
3654 				    scf_error());
3655 			}
3656 
3657 			if (tx_started)
3658 				scf_transaction_destroy_children(ud_tx);
3659 			return (r);
3660 		}
3661 	}
3662 
3663 	/* import unseen dependents */
3664 	unseen = 0;
3665 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3666 	    new_dpt_pgroup != NULL;
3667 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3668 	    new_dpt_pgroup)) {
3669 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3670 			unseen = 1;
3671 			break;
3672 		}
3673 	}
3674 
3675 	/* If there are none, exit early. */
3676 	if (unseen == 0)
3677 		goto commit;
3678 
3679 	/* Set up for lscf_dependent_import() */
3680 	cbdata.sc_handle = g_hndl;
3681 	cbdata.sc_parent = ent;
3682 	cbdata.sc_service = issvc;
3683 	cbdata.sc_flags = 0;
3684 
3685 	if (!have_cur_depts) {
3686 		/*
3687 		 * We have new dependents to import, so we need a "dependents"
3688 		 * property group.
3689 		 */
3690 		if (issvc)
3691 			r = scf_service_add_pg(ent, dependents,
3692 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3693 		else
3694 			r = scf_instance_add_pg(ent, dependents,
3695 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3696 		if (r != 0) {
3697 			switch (scf_error()) {
3698 			case SCF_ERROR_DELETED:
3699 			case SCF_ERROR_CONNECTION_BROKEN:
3700 			case SCF_ERROR_BACKEND_READONLY:
3701 			case SCF_ERROR_BACKEND_ACCESS:
3702 			case SCF_ERROR_NO_RESOURCES:
3703 				return (scferror2errno(scf_error()));
3704 
3705 			case SCF_ERROR_EXISTS:
3706 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3707 				return (EBUSY);
3708 
3709 			case SCF_ERROR_PERMISSION_DENIED:
3710 				warn(emsg_pg_add_perm, dependents,
3711 				    ient->sc_fmri);
3712 				return (scferror2errno(scf_error()));
3713 
3714 			case SCF_ERROR_NOT_BOUND:
3715 			case SCF_ERROR_HANDLE_MISMATCH:
3716 			case SCF_ERROR_INVALID_ARGUMENT:
3717 			case SCF_ERROR_NOT_SET:
3718 			default:
3719 				bad_error("scf_service_add_pg", scf_error());
3720 			}
3721 		}
3722 	}
3723 
3724 	cbdata.sc_trans = ud_tx;
3725 
3726 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3727 		switch (scf_error()) {
3728 		case SCF_ERROR_CONNECTION_BROKEN:
3729 		case SCF_ERROR_BACKEND_ACCESS:
3730 		case SCF_ERROR_BACKEND_READONLY:
3731 			return (scferror2errno(scf_error()));
3732 
3733 		case SCF_ERROR_DELETED:
3734 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3735 			return (EBUSY);
3736 
3737 		case SCF_ERROR_PERMISSION_DENIED:
3738 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3739 			return (scferror2errno(scf_error()));
3740 
3741 		case SCF_ERROR_HANDLE_MISMATCH:
3742 		case SCF_ERROR_IN_USE:
3743 		case SCF_ERROR_NOT_BOUND:
3744 		case SCF_ERROR_NOT_SET:
3745 		default:
3746 			bad_error("scf_transaction_start", scf_error());
3747 		}
3748 	}
3749 	tx_started = 1;
3750 
3751 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3752 	    new_dpt_pgroup != NULL;
3753 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3754 	    new_dpt_pgroup)) {
3755 		if (new_dpt_pgroup->sc_pgroup_seen)
3756 			continue;
3757 
3758 		if (ud_run_dpts_pg_set) {
3759 			/*
3760 			 * If the dependent is already there, then we have
3761 			 * a conflict.
3762 			 */
3763 			if (scf_pg_get_property(ud_run_dpts_pg,
3764 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3765 				r = handle_dependent_conflict(ient, ud_prop,
3766 				    new_dpt_pgroup);
3767 				switch (r) {
3768 				case 0:
3769 					continue;
3770 
3771 				case ECONNABORTED:
3772 				case ENOMEM:
3773 				case EBUSY:
3774 				case EBADF:
3775 				case EINVAL:
3776 					scf_transaction_destroy_children(ud_tx);
3777 					return (r);
3778 
3779 				default:
3780 					bad_error("handle_dependent_conflict",
3781 					    r);
3782 				}
3783 			} else {
3784 				switch (scf_error()) {
3785 				case SCF_ERROR_NOT_FOUND:
3786 					break;
3787 
3788 				case SCF_ERROR_INVALID_ARGUMENT:
3789 					warn(emsg_fmri_invalid_pg_name,
3790 					    ient->sc_fmri,
3791 					    new_dpt_pgroup->sc_pgroup_name);
3792 					scf_transaction_destroy_children(ud_tx);
3793 					return (EINVAL);
3794 
3795 				case SCF_ERROR_DELETED:
3796 					warn(emsg_pg_deleted, ient->sc_fmri,
3797 					    new_dpt_pgroup->sc_pgroup_name);
3798 					scf_transaction_destroy_children(ud_tx);
3799 					return (EBUSY);
3800 
3801 				case SCF_ERROR_CONNECTION_BROKEN:
3802 					scf_transaction_destroy_children(ud_tx);
3803 					return (ECONNABORTED);
3804 
3805 				case SCF_ERROR_NOT_BOUND:
3806 				case SCF_ERROR_HANDLE_MISMATCH:
3807 				case SCF_ERROR_NOT_SET:
3808 				default:
3809 					bad_error("scf_pg_get_property",
3810 					    scf_error());
3811 				}
3812 			}
3813 		}
3814 
3815 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3816 		if (r != UU_WALK_NEXT) {
3817 			if (r != UU_WALK_ERROR)
3818 				bad_error("lscf_dependent_import", r);
3819 
3820 			if (cbdata.sc_err == EALREADY) {
3821 				/* Collisions were handled preemptively. */
3822 				bad_error("lscf_dependent_import",
3823 				    cbdata.sc_err);
3824 			}
3825 
3826 			scf_transaction_destroy_children(ud_tx);
3827 			return (cbdata.sc_err);
3828 		}
3829 	}
3830 
3831 commit:
3832 	if (!tx_started)
3833 		return (0);
3834 
3835 	r = scf_transaction_commit(ud_tx);
3836 
3837 	scf_transaction_destroy_children(ud_tx);
3838 
3839 	switch (r) {
3840 	case 1:
3841 		return (0);
3842 
3843 	case 0:
3844 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3845 		return (EBUSY);
3846 
3847 	case -1:
3848 		break;
3849 
3850 	default:
3851 		bad_error("scf_transaction_commit", r);
3852 	}
3853 
3854 	switch (scf_error()) {
3855 	case SCF_ERROR_CONNECTION_BROKEN:
3856 	case SCF_ERROR_BACKEND_READONLY:
3857 	case SCF_ERROR_BACKEND_ACCESS:
3858 	case SCF_ERROR_NO_RESOURCES:
3859 		return (scferror2errno(scf_error()));
3860 
3861 	case SCF_ERROR_DELETED:
3862 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3863 		return (EBUSY);
3864 
3865 	case SCF_ERROR_PERMISSION_DENIED:
3866 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3867 		return (scferror2errno(scf_error()));
3868 
3869 	case SCF_ERROR_NOT_BOUND:
3870 	case SCF_ERROR_INVALID_ARGUMENT:
3871 	case SCF_ERROR_NOT_SET:
3872 	default:
3873 		bad_error("scf_transaction_destroy", scf_error());
3874 		/* NOTREACHED */
3875 	}
3876 }
3877 
3878 /*
3879  * Used to add the manifests to the list of currently supported manifests.
3880  * We can modify the existing manifest list removing entries if the files
3881  * don't exist.
3882  *
3883  * Get the old list and the new file name
3884  * If the new file name is in the list return
3885  * If not then add the file to the list.
3886  * As we process the list check to see if the files in the old list exist
3887  * 	if not then remove the file from the list.
3888  * Commit the list of manifest file names.
3889  *
3890  */
3891 static int
3892 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3893     const scf_snaplevel_t *running, void *ent)
3894 {
3895 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3896 	scf_property_t *ud_prop = NULL;
3897 	scf_iter_t *ud_prop_iter;
3898 	scf_value_t *fname_value;
3899 	scf_callback_t cbdata;
3900 	pgroup_t *mfst_pgroup;
3901 	property_t *mfst_prop;
3902 	property_t *old_prop;
3903 	char *pname = malloc(MAXPATHLEN);
3904 	char *fval = NULL;
3905 	char *old_pname;
3906 	char *old_fval;
3907 	int no_upgrade_pg;
3908 	int mfst_seen;
3909 	int r;
3910 
3911 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3912 
3913 	/*
3914 	 * This should always be the service base on the code
3915 	 * path, and the fact that the manifests pg is a service
3916 	 * level property group only.
3917 	 */
3918 	ud_mfsts_pg = scf_pg_create(g_hndl);
3919 	ud_prop = scf_property_create(g_hndl);
3920 	ud_prop_iter = scf_iter_create(g_hndl);
3921 	fname_value = scf_value_create(g_hndl);
3922 
3923 	/* Fetch the "manifests" property group */
3924 	no_upgrade_pg = 0;
3925 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3926 	    ud_mfsts_pg);
3927 	if (r != 0) {
3928 		switch (scf_error()) {
3929 		case SCF_ERROR_NOT_FOUND:
3930 			no_upgrade_pg = 1;
3931 			break;
3932 
3933 		case SCF_ERROR_DELETED:
3934 		case SCF_ERROR_CONNECTION_BROKEN:
3935 			return (scferror2errno(scf_error()));
3936 
3937 		case SCF_ERROR_NOT_SET:
3938 		case SCF_ERROR_INVALID_ARGUMENT:
3939 		case SCF_ERROR_HANDLE_MISMATCH:
3940 		case SCF_ERROR_NOT_BOUND:
3941 		default:
3942 			bad_error(running ? "scf_snaplevel_get_pg" :
3943 			    "entity_get_pg", scf_error());
3944 		}
3945 	}
3946 
3947 	if (no_upgrade_pg) {
3948 		cbdata.sc_handle = g_hndl;
3949 		cbdata.sc_parent = ent;
3950 		cbdata.sc_service = issvc;
3951 		cbdata.sc_flags = SCI_FORCE;
3952 		cbdata.sc_source_fmri = ient->sc_fmri;
3953 		cbdata.sc_target_fmri = ient->sc_fmri;
3954 
3955 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3956 			return (cbdata.sc_err);
3957 
3958 		return (0);
3959 	}
3960 
3961 	/* Fetch the new manifests property group */
3962 	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3963 	    mfst_pgroup != NULL;
3964 	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3965 		if (strcmp(mfst_pgroup->sc_pgroup_name,
3966 		    SCF_PG_MANIFESTFILES) == 0)
3967 			break;
3968 	}
3969 
3970 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3971 	    SCF_SUCCESS)
3972 		return (-1);
3973 
3974 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3975 		mfst_seen = 0;
3976 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3977 			continue;
3978 
3979 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3980 		    mfst_prop != NULL;
3981 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3982 		    mfst_prop)) {
3983 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3984 				mfst_seen = 1;
3985 			}
3986 		}
3987 
3988 		/*
3989 		 * If the manifest is not seen then add it to the new mfst
3990 		 * property list to get proccessed into the repo.
3991 		 */
3992 		if (mfst_seen == 0) {
3993 			if (fval == NULL)
3994 				fval = malloc(MAXPATHLEN);
3995 
3996 			/*
3997 			 * If we cannot get the value then there is no
3998 			 * reason to attempt to attach the value to
3999 			 * the property group
4000 			 */
4001 			if (fval != NULL &&
4002 			    prop_get_val(ud_prop, fname_value) == 0 &&
4003 			    scf_value_get_astring(fname_value, fval,
4004 			    MAXPATHLEN) != -1)  {
4005 				old_pname = safe_strdup(pname);
4006 				old_fval = safe_strdup(fval);
4007 				old_prop = internal_property_create(old_pname,
4008 				    SCF_TYPE_ASTRING, 1, old_fval);
4009 
4010 				/*
4011 				 * Already checked to see if the property exists
4012 				 * in the group, and it does not.
4013 				 */
4014 				(void) internal_attach_property(mfst_pgroup,
4015 				    old_prop);
4016 			}
4017 		}
4018 	}
4019 	free(fval);
4020 
4021 	cbdata.sc_handle = g_hndl;
4022 	cbdata.sc_parent = ent;
4023 	cbdata.sc_service = issvc;
4024 	cbdata.sc_flags = SCI_FORCE;
4025 	cbdata.sc_source_fmri = ient->sc_fmri;
4026 	cbdata.sc_target_fmri = ient->sc_fmri;
4027 
4028 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4029 		return (cbdata.sc_err);
4030 
4031 	return (r);
4032 }
4033 
4034 /*
4035  * prop is taken to be a property in the "dependents" property group of snpl,
4036  * which is taken to be the snaplevel of a last-import snapshot corresponding
4037  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4038  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4039  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4040  * of the entity ient represents (possibly in the running snapshot).  If it
4041  * needs to be changed, an entry will be added to tx, if not NULL.
4042  *
4043  * Returns
4044  *   0 - success
4045  *   ECONNABORTED - repository connection broken
4046  *   ENOMEM - out of memory
4047  *   ENOSPC - configd was out of resources
4048  *   ECANCELED - snpl's entity was deleted
4049  *   EINVAL - dependent target is invalid (error printed)
4050  *	    - dependent is invalid (error printed)
4051  *   EBADF - snpl is corrupt (error printed)
4052  *	   - snpl has corrupt pg (error printed)
4053  *	   - dependency pg in target is corrupt (error printed)
4054  *	   - running snapshot in dependent is missing snaplevel (error printed)
4055  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4056  *	   - couldn't create dependent (permission denied) (error printed)
4057  *	   - couldn't modify dependent pg (permission denied) (error printed)
4058  *   EROFS - couldn't delete dependency pg (repository read-only)
4059  *	   - couldn't create dependent (repository read-only)
4060  *   EACCES - couldn't delete dependency pg (backend access denied)
4061  *	    - couldn't create dependent (backend access denied)
4062  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4063  *	   - tx's pg was deleted (error printed)
4064  *	   - dependent pg was changed or deleted (error printed)
4065  *   EEXIST - dependency pg already exists in new target (error printed)
4066  */
4067 static int
4068 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4069     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4070 {
4071 	pgroup_t pgrp;
4072 	scf_type_t ty;
4073 	pgroup_t *new_dpt_pgroup;
4074 	pgroup_t *old_dpt_pgroup = NULL;
4075 	pgroup_t *current_pg;
4076 	pgroup_t *dpt;
4077 	scf_callback_t cbdata;
4078 	int tissvc;
4079 	void *target_ent;
4080 	scf_error_t serr;
4081 	int r;
4082 	scf_transaction_entry_t *ent;
4083 
4084 	const char * const cf_inval = gettext("Conflict upgrading %s "
4085 	    "(dependent \"%s\" has invalid dependents property).\n");
4086 	const char * const cf_missing = gettext("Conflict upgrading %s "
4087 	    "(dependent \"%s\" is missing).\n");
4088 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4089 	    "(dependent \"%s\" has new dependency property group).\n");
4090 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4091 	    "(dependent \"%s\" has new target).\n");
4092 	const char * const li_corrupt =
4093 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4094 	const char * const upgrading =
4095 	    gettext("%s: Upgrading dependent \"%s\".\n");
4096 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4097 	    "corrupt (missing snaplevel).\n");
4098 
4099 	if (scf_property_type(prop, &ty) != 0) {
4100 		switch (scf_error()) {
4101 		case SCF_ERROR_DELETED:
4102 		case SCF_ERROR_CONNECTION_BROKEN:
4103 			return (scferror2errno(scf_error()));
4104 
4105 		case SCF_ERROR_NOT_BOUND:
4106 		case SCF_ERROR_NOT_SET:
4107 		default:
4108 			bad_error("scf_property_type", scf_error());
4109 		}
4110 	}
4111 
4112 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4113 		warn(li_corrupt, ient->sc_fmri);
4114 		return (EBADF);
4115 	}
4116 
4117 	/*
4118 	 * prop represents a dependent in the old manifest.  It is named after
4119 	 * the dependent.
4120 	 */
4121 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4122 		switch (scf_error()) {
4123 		case SCF_ERROR_DELETED:
4124 		case SCF_ERROR_CONNECTION_BROKEN:
4125 			return (scferror2errno(scf_error()));
4126 
4127 		case SCF_ERROR_NOT_BOUND:
4128 		case SCF_ERROR_NOT_SET:
4129 		default:
4130 			bad_error("scf_property_get_name", scf_error());
4131 		}
4132 	}
4133 
4134 	/* See if it's in the new manifest. */
4135 	pgrp.sc_pgroup_name = ud_name;
4136 	new_dpt_pgroup =
4137 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4138 
4139 	/* If it's not, delete it... if it hasn't been customized. */
4140 	if (new_dpt_pgroup == NULL) {
4141 		if (!ud_run_dpts_pg_set)
4142 			return (0);
4143 
4144 		if (scf_property_get_value(prop, ud_val) != 0) {
4145 			switch (scf_error()) {
4146 			case SCF_ERROR_NOT_FOUND:
4147 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4148 				warn(li_corrupt, ient->sc_fmri);
4149 				return (EBADF);
4150 
4151 			case SCF_ERROR_DELETED:
4152 			case SCF_ERROR_CONNECTION_BROKEN:
4153 				return (scferror2errno(scf_error()));
4154 
4155 			case SCF_ERROR_HANDLE_MISMATCH:
4156 			case SCF_ERROR_NOT_BOUND:
4157 			case SCF_ERROR_NOT_SET:
4158 			case SCF_ERROR_PERMISSION_DENIED:
4159 			default:
4160 				bad_error("scf_property_get_value",
4161 				    scf_error());
4162 			}
4163 		}
4164 
4165 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4166 		    max_scf_value_len + 1) < 0)
4167 			bad_error("scf_value_get_as_string", scf_error());
4168 
4169 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4170 		    0) {
4171 			switch (scf_error()) {
4172 			case SCF_ERROR_NOT_FOUND:
4173 				return (0);
4174 
4175 			case SCF_ERROR_CONNECTION_BROKEN:
4176 				return (scferror2errno(scf_error()));
4177 
4178 			case SCF_ERROR_DELETED:
4179 				warn(emsg_pg_deleted, ient->sc_fmri,
4180 				    "dependents");
4181 				return (EBUSY);
4182 
4183 			case SCF_ERROR_INVALID_ARGUMENT:
4184 			case SCF_ERROR_NOT_BOUND:
4185 			case SCF_ERROR_HANDLE_MISMATCH:
4186 			case SCF_ERROR_NOT_SET:
4187 			default:
4188 				bad_error("scf_pg_get_property", scf_error());
4189 			}
4190 		}
4191 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4192 			switch (scf_error()) {
4193 			case SCF_ERROR_NOT_FOUND:
4194 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4195 				warn(cf_inval, ient->sc_fmri, ud_name);
4196 				return (0);
4197 
4198 			case SCF_ERROR_DELETED:
4199 			case SCF_ERROR_CONNECTION_BROKEN:
4200 				return (scferror2errno(scf_error()));
4201 
4202 			case SCF_ERROR_HANDLE_MISMATCH:
4203 			case SCF_ERROR_NOT_BOUND:
4204 			case SCF_ERROR_NOT_SET:
4205 			case SCF_ERROR_PERMISSION_DENIED:
4206 			default:
4207 				bad_error("scf_property_get_value",
4208 				    scf_error());
4209 			}
4210 		}
4211 
4212 		ty = scf_value_type(ud_val);
4213 		assert(ty != SCF_TYPE_INVALID);
4214 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4215 			warn(cf_inval, ient->sc_fmri, ud_name);
4216 			return (0);
4217 		}
4218 
4219 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4220 		    max_scf_value_len + 1) < 0)
4221 			bad_error("scf_value_get_as_string", scf_error());
4222 
4223 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4224 		switch (r) {
4225 		case 1:
4226 			break;
4227 
4228 		case 0:
4229 		case -1:	/* warn? */
4230 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4231 			return (0);
4232 
4233 		case -2:
4234 			warn(li_corrupt, ient->sc_fmri);
4235 			return (EBADF);
4236 
4237 		default:
4238 			bad_error("fmri_equal", r);
4239 		}
4240 
4241 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4242 			switch (scf_error()) {
4243 			case SCF_ERROR_NOT_FOUND:
4244 				warn(li_corrupt, ient->sc_fmri);
4245 				return (EBADF);
4246 
4247 			case SCF_ERROR_DELETED:
4248 			case SCF_ERROR_CONNECTION_BROKEN:
4249 				return (scferror2errno(scf_error()));
4250 
4251 			case SCF_ERROR_NOT_BOUND:
4252 			case SCF_ERROR_HANDLE_MISMATCH:
4253 			case SCF_ERROR_INVALID_ARGUMENT:
4254 			case SCF_ERROR_NOT_SET:
4255 			default:
4256 				bad_error("scf_snaplevel_get_pg", scf_error());
4257 			}
4258 		}
4259 
4260 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4261 		    snap_lastimport);
4262 		switch (r) {
4263 		case 0:
4264 			break;
4265 
4266 		case ECANCELED:
4267 		case ECONNABORTED:
4268 		case ENOMEM:
4269 		case EBADF:
4270 			return (r);
4271 
4272 		case EACCES:
4273 		default:
4274 			bad_error("load_pg", r);
4275 		}
4276 
4277 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4278 		switch (serr) {
4279 		case SCF_ERROR_NONE:
4280 			break;
4281 
4282 		case SCF_ERROR_NO_MEMORY:
4283 			internal_pgroup_free(old_dpt_pgroup);
4284 			return (ENOMEM);
4285 
4286 		case SCF_ERROR_NOT_FOUND:
4287 			internal_pgroup_free(old_dpt_pgroup);
4288 			goto delprop;
4289 
4290 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4291 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4292 		default:
4293 			bad_error("fmri_to_entity", serr);
4294 		}
4295 
4296 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4297 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4298 		switch (r) {
4299 		case 0:
4300 			break;
4301 
4302 		case ECONNABORTED:
4303 			internal_pgroup_free(old_dpt_pgroup);
4304 			return (r);
4305 
4306 		case ECANCELED:
4307 		case ENOENT:
4308 			internal_pgroup_free(old_dpt_pgroup);
4309 			goto delprop;
4310 
4311 		case EBADF:
4312 			warn(r_no_lvl, ud_ctarg);
4313 			internal_pgroup_free(old_dpt_pgroup);
4314 			return (r);
4315 
4316 		case EINVAL:
4317 		default:
4318 			bad_error("entity_get_running_pg", r);
4319 		}
4320 
4321 		/* load it */
4322 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4323 		switch (r) {
4324 		case 0:
4325 			break;
4326 
4327 		case ECANCELED:
4328 			internal_pgroup_free(old_dpt_pgroup);
4329 			goto delprop;
4330 
4331 		case ECONNABORTED:
4332 		case ENOMEM:
4333 		case EBADF:
4334 			internal_pgroup_free(old_dpt_pgroup);
4335 			return (r);
4336 
4337 		case EACCES:
4338 		default:
4339 			bad_error("load_pg", r);
4340 		}
4341 
4342 		/* compare property groups */
4343 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4344 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4345 			internal_pgroup_free(old_dpt_pgroup);
4346 			internal_pgroup_free(current_pg);
4347 			return (0);
4348 		}
4349 
4350 		internal_pgroup_free(old_dpt_pgroup);
4351 		internal_pgroup_free(current_pg);
4352 
4353 		if (g_verbose)
4354 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4355 			    ient->sc_fmri, ud_name);
4356 
4357 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4358 			switch (scf_error()) {
4359 			case SCF_ERROR_NOT_FOUND:
4360 			case SCF_ERROR_DELETED:
4361 				internal_pgroup_free(old_dpt_pgroup);
4362 				goto delprop;
4363 
4364 			case SCF_ERROR_CONNECTION_BROKEN:
4365 				internal_pgroup_free(old_dpt_pgroup);
4366 				return (ECONNABORTED);
4367 
4368 			case SCF_ERROR_NOT_SET:
4369 			case SCF_ERROR_INVALID_ARGUMENT:
4370 			case SCF_ERROR_HANDLE_MISMATCH:
4371 			case SCF_ERROR_NOT_BOUND:
4372 			default:
4373 				bad_error("entity_get_pg", scf_error());
4374 			}
4375 		}
4376 
4377 		if (scf_pg_delete(ud_pg) != 0) {
4378 			switch (scf_error()) {
4379 			case SCF_ERROR_DELETED:
4380 				break;
4381 
4382 			case SCF_ERROR_CONNECTION_BROKEN:
4383 			case SCF_ERROR_BACKEND_READONLY:
4384 			case SCF_ERROR_BACKEND_ACCESS:
4385 				return (scferror2errno(scf_error()));
4386 
4387 			case SCF_ERROR_PERMISSION_DENIED:
4388 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4389 				return (scferror2errno(scf_error()));
4390 
4391 			case SCF_ERROR_NOT_SET:
4392 			default:
4393 				bad_error("scf_pg_delete", scf_error());
4394 			}
4395 		}
4396 
4397 		/*
4398 		 * This service was changed, so it must be refreshed.  But
4399 		 * since it's not mentioned in the new manifest, we have to
4400 		 * record its FMRI here for use later.  We record the name
4401 		 * & the entity (via sc_parent) in case we need to print error
4402 		 * messages during the refresh.
4403 		 */
4404 		dpt = internal_pgroup_new();
4405 		if (dpt == NULL)
4406 			return (ENOMEM);
4407 		dpt->sc_pgroup_name = strdup(ud_name);
4408 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4409 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4410 			return (ENOMEM);
4411 		dpt->sc_parent = (entity_t *)ient;
4412 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4413 			uu_die(gettext("libuutil error: %s\n"),
4414 			    uu_strerror(uu_error()));
4415 
4416 delprop:
4417 		if (tx == NULL)
4418 			return (0);
4419 
4420 		ent = scf_entry_create(g_hndl);
4421 		if (ent == NULL)
4422 			return (ENOMEM);
4423 
4424 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4425 			scf_entry_destroy(ent);
4426 			switch (scf_error()) {
4427 			case SCF_ERROR_DELETED:
4428 				warn(emsg_pg_deleted, ient->sc_fmri,
4429 				    "dependents");
4430 				return (EBUSY);
4431 
4432 			case SCF_ERROR_CONNECTION_BROKEN:
4433 				return (scferror2errno(scf_error()));
4434 
4435 			case SCF_ERROR_NOT_FOUND:
4436 				break;
4437 
4438 			case SCF_ERROR_HANDLE_MISMATCH:
4439 			case SCF_ERROR_NOT_BOUND:
4440 			case SCF_ERROR_INVALID_ARGUMENT:
4441 			case SCF_ERROR_NOT_SET:
4442 			default:
4443 				bad_error("scf_transaction_property_delete",
4444 				    scf_error());
4445 			}
4446 		}
4447 
4448 		return (0);
4449 	}
4450 
4451 	new_dpt_pgroup->sc_pgroup_seen = 1;
4452 
4453 	/*
4454 	 * Decide whether the dependent has changed in the manifest.
4455 	 */
4456 	/* Compare the target. */
4457 	if (scf_property_get_value(prop, ud_val) != 0) {
4458 		switch (scf_error()) {
4459 		case SCF_ERROR_NOT_FOUND:
4460 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4461 			warn(li_corrupt, ient->sc_fmri);
4462 			return (EBADF);
4463 
4464 		case SCF_ERROR_DELETED:
4465 		case SCF_ERROR_CONNECTION_BROKEN:
4466 			return (scferror2errno(scf_error()));
4467 
4468 		case SCF_ERROR_HANDLE_MISMATCH:
4469 		case SCF_ERROR_NOT_BOUND:
4470 		case SCF_ERROR_NOT_SET:
4471 		case SCF_ERROR_PERMISSION_DENIED:
4472 		default:
4473 			bad_error("scf_property_get_value", scf_error());
4474 		}
4475 	}
4476 
4477 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4478 	    0)
4479 		bad_error("scf_value_get_as_string", scf_error());
4480 
4481 	/*
4482 	 * If the fmri's are not equal then the old fmri will need to
4483 	 * be refreshed to ensure that the changes are properly updated
4484 	 * in that service.
4485 	 */
4486 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4487 	switch (r) {
4488 	case 0:
4489 		dpt = internal_pgroup_new();
4490 		if (dpt == NULL)
4491 			return (ENOMEM);
4492 		dpt->sc_pgroup_name = strdup(ud_name);
4493 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4494 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4495 			return (ENOMEM);
4496 		dpt->sc_parent = (entity_t *)ient;
4497 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4498 			uu_die(gettext("libuutil error: %s\n"),
4499 			    uu_strerror(uu_error()));
4500 		break;
4501 
4502 	case 1:
4503 		/* Compare the dependency pgs. */
4504 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4505 			switch (scf_error()) {
4506 			case SCF_ERROR_NOT_FOUND:
4507 				warn(li_corrupt, ient->sc_fmri);
4508 				return (EBADF);
4509 
4510 			case SCF_ERROR_DELETED:
4511 			case SCF_ERROR_CONNECTION_BROKEN:
4512 				return (scferror2errno(scf_error()));
4513 
4514 			case SCF_ERROR_NOT_BOUND:
4515 			case SCF_ERROR_HANDLE_MISMATCH:
4516 			case SCF_ERROR_INVALID_ARGUMENT:
4517 			case SCF_ERROR_NOT_SET:
4518 			default:
4519 				bad_error("scf_snaplevel_get_pg", scf_error());
4520 			}
4521 		}
4522 
4523 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4524 		    snap_lastimport);
4525 		switch (r) {
4526 		case 0:
4527 			break;
4528 
4529 		case ECANCELED:
4530 		case ECONNABORTED:
4531 		case ENOMEM:
4532 		case EBADF:
4533 			return (r);
4534 
4535 		case EACCES:
4536 		default:
4537 			bad_error("load_pg", r);
4538 		}
4539 
4540 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4541 			/* no change, leave customizations */
4542 			internal_pgroup_free(old_dpt_pgroup);
4543 			return (0);
4544 		}
4545 		break;
4546 
4547 	case -1:
4548 		warn(li_corrupt, ient->sc_fmri);
4549 		return (EBADF);
4550 
4551 	case -2:
4552 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4553 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4554 		return (EINVAL);
4555 
4556 	default:
4557 		bad_error("fmri_equal", r);
4558 	}
4559 
4560 	/*
4561 	 * The dependent has changed in the manifest.  Upgrade the current
4562 	 * properties if they haven't been customized.
4563 	 */
4564 
4565 	/*
4566 	 * If new_dpt_pgroup->sc_override, then act as though the property
4567 	 * group hasn't been customized.
4568 	 */
4569 	if (new_dpt_pgroup->sc_pgroup_override) {
4570 		(void) strcpy(ud_ctarg, ud_oldtarg);
4571 		goto nocust;
4572 	}
4573 
4574 	if (!ud_run_dpts_pg_set) {
4575 		warn(cf_missing, ient->sc_fmri, ud_name);
4576 		r = 0;
4577 		goto out;
4578 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4579 		switch (scf_error()) {
4580 		case SCF_ERROR_NOT_FOUND:
4581 			warn(cf_missing, ient->sc_fmri, ud_name);
4582 			r = 0;
4583 			goto out;
4584 
4585 		case SCF_ERROR_CONNECTION_BROKEN:
4586 			r = scferror2errno(scf_error());
4587 			goto out;
4588 
4589 		case SCF_ERROR_DELETED:
4590 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4591 			r = EBUSY;
4592 			goto out;
4593 
4594 		case SCF_ERROR_INVALID_ARGUMENT:
4595 		case SCF_ERROR_NOT_BOUND:
4596 		case SCF_ERROR_HANDLE_MISMATCH:
4597 		case SCF_ERROR_NOT_SET:
4598 		default:
4599 			bad_error("scf_pg_get_property", scf_error());
4600 		}
4601 	}
4602 
4603 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4604 		switch (scf_error()) {
4605 		case SCF_ERROR_NOT_FOUND:
4606 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4607 			warn(cf_inval, ient->sc_fmri, ud_name);
4608 			r = 0;
4609 			goto out;
4610 
4611 		case SCF_ERROR_DELETED:
4612 		case SCF_ERROR_CONNECTION_BROKEN:
4613 			r = scferror2errno(scf_error());
4614 			goto out;
4615 
4616 		case SCF_ERROR_HANDLE_MISMATCH:
4617 		case SCF_ERROR_NOT_BOUND:
4618 		case SCF_ERROR_NOT_SET:
4619 		case SCF_ERROR_PERMISSION_DENIED:
4620 		default:
4621 			bad_error("scf_property_get_value", scf_error());
4622 		}
4623 	}
4624 
4625 	ty = scf_value_type(ud_val);
4626 	assert(ty != SCF_TYPE_INVALID);
4627 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4628 		warn(cf_inval, ient->sc_fmri, ud_name);
4629 		r = 0;
4630 		goto out;
4631 	}
4632 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4633 	    0)
4634 		bad_error("scf_value_get_as_string", scf_error());
4635 
4636 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4637 	if (r == -1) {
4638 		warn(cf_inval, ient->sc_fmri, ud_name);
4639 		r = 0;
4640 		goto out;
4641 	} else if (r == -2) {
4642 		warn(li_corrupt, ient->sc_fmri);
4643 		r = EBADF;
4644 		goto out;
4645 	} else if (r == 0) {
4646 		/*
4647 		 * Target has been changed.  Only abort now if it's been
4648 		 * changed to something other than what's in the manifest.
4649 		 */
4650 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4651 		if (r == -1) {
4652 			warn(cf_inval, ient->sc_fmri, ud_name);
4653 			r = 0;
4654 			goto out;
4655 		} else if (r == 0) {
4656 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4657 			r = 0;
4658 			goto out;
4659 		} else if (r != 1) {
4660 			/* invalid sc_pgroup_fmri caught above */
4661 			bad_error("fmri_equal", r);
4662 		}
4663 
4664 		/*
4665 		 * Fetch the current dependency pg.  If it's what the manifest
4666 		 * says, then no problem.
4667 		 */
4668 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4669 		switch (serr) {
4670 		case SCF_ERROR_NONE:
4671 			break;
4672 
4673 		case SCF_ERROR_NOT_FOUND:
4674 			warn(cf_missing, ient->sc_fmri, ud_name);
4675 			r = 0;
4676 			goto out;
4677 
4678 		case SCF_ERROR_NO_MEMORY:
4679 			r = ENOMEM;
4680 			goto out;
4681 
4682 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4683 		case SCF_ERROR_INVALID_ARGUMENT:
4684 		default:
4685 			bad_error("fmri_to_entity", serr);
4686 		}
4687 
4688 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4689 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4690 		switch (r) {
4691 		case 0:
4692 			break;
4693 
4694 		case ECONNABORTED:
4695 			goto out;
4696 
4697 		case ECANCELED:
4698 		case ENOENT:
4699 			warn(cf_missing, ient->sc_fmri, ud_name);
4700 			r = 0;
4701 			goto out;
4702 
4703 		case EBADF:
4704 			warn(r_no_lvl, ud_ctarg);
4705 			goto out;
4706 
4707 		case EINVAL:
4708 		default:
4709 			bad_error("entity_get_running_pg", r);
4710 		}
4711 
4712 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4713 		switch (r) {
4714 		case 0:
4715 			break;
4716 
4717 		case ECANCELED:
4718 			warn(cf_missing, ient->sc_fmri, ud_name);
4719 			r = 0;
4720 			goto out;
4721 
4722 		case ECONNABORTED:
4723 		case ENOMEM:
4724 		case EBADF:
4725 			goto out;
4726 
4727 		case EACCES:
4728 		default:
4729 			bad_error("load_pg", r);
4730 		}
4731 
4732 		if (!pg_equal(current_pg, new_dpt_pgroup))
4733 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4734 		internal_pgroup_free(current_pg);
4735 		r = 0;
4736 		goto out;
4737 	} else if (r != 1) {
4738 		bad_error("fmri_equal", r);
4739 	}
4740 
4741 nocust:
4742 	/*
4743 	 * Target has not been customized.  Check the dependency property
4744 	 * group.
4745 	 */
4746 
4747 	if (old_dpt_pgroup == NULL) {
4748 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4749 		    ud_pg) != 0) {
4750 			switch (scf_error()) {
4751 			case SCF_ERROR_NOT_FOUND:
4752 				warn(li_corrupt, ient->sc_fmri);
4753 				return (EBADF);
4754 
4755 			case SCF_ERROR_DELETED:
4756 			case SCF_ERROR_CONNECTION_BROKEN:
4757 				return (scferror2errno(scf_error()));
4758 
4759 			case SCF_ERROR_NOT_BOUND:
4760 			case SCF_ERROR_HANDLE_MISMATCH:
4761 			case SCF_ERROR_INVALID_ARGUMENT:
4762 			case SCF_ERROR_NOT_SET:
4763 			default:
4764 				bad_error("scf_snaplevel_get_pg", scf_error());
4765 			}
4766 		}
4767 
4768 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4769 		    snap_lastimport);
4770 		switch (r) {
4771 		case 0:
4772 			break;
4773 
4774 		case ECANCELED:
4775 		case ECONNABORTED:
4776 		case ENOMEM:
4777 		case EBADF:
4778 			return (r);
4779 
4780 		case EACCES:
4781 		default:
4782 			bad_error("load_pg", r);
4783 		}
4784 	}
4785 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4786 	switch (serr) {
4787 	case SCF_ERROR_NONE:
4788 		break;
4789 
4790 	case SCF_ERROR_NOT_FOUND:
4791 		warn(cf_missing, ient->sc_fmri, ud_name);
4792 		r = 0;
4793 		goto out;
4794 
4795 	case SCF_ERROR_NO_MEMORY:
4796 		r = ENOMEM;
4797 		goto out;
4798 
4799 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4800 	case SCF_ERROR_INVALID_ARGUMENT:
4801 	default:
4802 		bad_error("fmri_to_entity", serr);
4803 	}
4804 
4805 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4806 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4807 	switch (r) {
4808 	case 0:
4809 		break;
4810 
4811 	case ECONNABORTED:
4812 		goto out;
4813 
4814 	case ECANCELED:
4815 	case ENOENT:
4816 		warn(cf_missing, ient->sc_fmri, ud_name);
4817 		r = 0;
4818 		goto out;
4819 
4820 	case EBADF:
4821 		warn(r_no_lvl, ud_ctarg);
4822 		goto out;
4823 
4824 	case EINVAL:
4825 	default:
4826 		bad_error("entity_get_running_pg", r);
4827 	}
4828 
4829 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4830 	switch (r) {
4831 	case 0:
4832 		break;
4833 
4834 	case ECANCELED:
4835 		warn(cf_missing, ient->sc_fmri, ud_name);
4836 		goto out;
4837 
4838 	case ECONNABORTED:
4839 	case ENOMEM:
4840 	case EBADF:
4841 		goto out;
4842 
4843 	case EACCES:
4844 	default:
4845 		bad_error("load_pg", r);
4846 	}
4847 
4848 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4849 		if (!pg_equal(current_pg, new_dpt_pgroup))
4850 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4851 		internal_pgroup_free(current_pg);
4852 		r = 0;
4853 		goto out;
4854 	}
4855 
4856 	/* Uncustomized.  Upgrade. */
4857 
4858 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4859 	switch (r) {
4860 	case 1:
4861 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4862 			/* Already upgraded. */
4863 			internal_pgroup_free(current_pg);
4864 			r = 0;
4865 			goto out;
4866 		}
4867 
4868 		internal_pgroup_free(current_pg);
4869 
4870 		/* upgrade current_pg */
4871 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4872 			switch (scf_error()) {
4873 			case SCF_ERROR_CONNECTION_BROKEN:
4874 				r = scferror2errno(scf_error());
4875 				goto out;
4876 
4877 			case SCF_ERROR_DELETED:
4878 				warn(cf_missing, ient->sc_fmri, ud_name);
4879 				r = 0;
4880 				goto out;
4881 
4882 			case SCF_ERROR_NOT_FOUND:
4883 				break;
4884 
4885 			case SCF_ERROR_INVALID_ARGUMENT:
4886 			case SCF_ERROR_NOT_BOUND:
4887 			case SCF_ERROR_NOT_SET:
4888 			case SCF_ERROR_HANDLE_MISMATCH:
4889 			default:
4890 				bad_error("entity_get_pg", scf_error());
4891 			}
4892 
4893 			if (tissvc)
4894 				r = scf_service_add_pg(target_ent, ud_name,
4895 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4896 			else
4897 				r = scf_instance_add_pg(target_ent, ud_name,
4898 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4899 			if (r != 0) {
4900 				switch (scf_error()) {
4901 				case SCF_ERROR_CONNECTION_BROKEN:
4902 				case SCF_ERROR_NO_RESOURCES:
4903 				case SCF_ERROR_BACKEND_READONLY:
4904 				case SCF_ERROR_BACKEND_ACCESS:
4905 					r = scferror2errno(scf_error());
4906 					goto out;
4907 
4908 				case SCF_ERROR_DELETED:
4909 					warn(cf_missing, ient->sc_fmri,
4910 					    ud_name);
4911 					r = 0;
4912 					goto out;
4913 
4914 				case SCF_ERROR_PERMISSION_DENIED:
4915 					warn(emsg_pg_deleted, ud_ctarg,
4916 					    ud_name);
4917 					r = EPERM;
4918 					goto out;
4919 
4920 				case SCF_ERROR_EXISTS:
4921 					warn(emsg_pg_added, ud_ctarg, ud_name);
4922 					r = EBUSY;
4923 					goto out;
4924 
4925 				case SCF_ERROR_NOT_BOUND:
4926 				case SCF_ERROR_HANDLE_MISMATCH:
4927 				case SCF_ERROR_INVALID_ARGUMENT:
4928 				case SCF_ERROR_NOT_SET:
4929 				default:
4930 					bad_error("entity_add_pg", scf_error());
4931 				}
4932 			}
4933 		}
4934 
4935 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4936 		switch (r) {
4937 		case 0:
4938 			break;
4939 
4940 		case ECANCELED:
4941 			warn(cf_missing, ient->sc_fmri, ud_name);
4942 			goto out;
4943 
4944 		case ECONNABORTED:
4945 		case ENOMEM:
4946 		case EBADF:
4947 			goto out;
4948 
4949 		case EACCES:
4950 		default:
4951 			bad_error("load_pg", r);
4952 		}
4953 
4954 		if (g_verbose)
4955 			warn(upgrading, ient->sc_fmri, ud_name);
4956 
4957 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4958 		    new_dpt_pgroup, 0, ient->sc_fmri);
4959 		switch (r) {
4960 		case 0:
4961 			break;
4962 
4963 		case ECANCELED:
4964 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4965 			r = EBUSY;
4966 			goto out;
4967 
4968 		case EPERM:
4969 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4970 			goto out;
4971 
4972 		case EBUSY:
4973 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4974 			goto out;
4975 
4976 		case ECONNABORTED:
4977 		case ENOMEM:
4978 		case ENOSPC:
4979 		case EROFS:
4980 		case EACCES:
4981 		case EINVAL:
4982 			goto out;
4983 
4984 		default:
4985 			bad_error("upgrade_pg", r);
4986 		}
4987 		break;
4988 
4989 	case 0: {
4990 		scf_transaction_entry_t *ent;
4991 		scf_value_t *val;
4992 
4993 		internal_pgroup_free(current_pg);
4994 
4995 		/* delete old pg */
4996 		if (g_verbose)
4997 			warn(upgrading, ient->sc_fmri, ud_name);
4998 
4999 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5000 			switch (scf_error()) {
5001 			case SCF_ERROR_CONNECTION_BROKEN:
5002 				r = scferror2errno(scf_error());
5003 				goto out;
5004 
5005 			case SCF_ERROR_DELETED:
5006 				warn(cf_missing, ient->sc_fmri, ud_name);
5007 				r = 0;
5008 				goto out;
5009 
5010 			case SCF_ERROR_NOT_FOUND:
5011 				break;
5012 
5013 			case SCF_ERROR_INVALID_ARGUMENT:
5014 			case SCF_ERROR_NOT_BOUND:
5015 			case SCF_ERROR_NOT_SET:
5016 			case SCF_ERROR_HANDLE_MISMATCH:
5017 			default:
5018 				bad_error("entity_get_pg", scf_error());
5019 			}
5020 		} else if (scf_pg_delete(ud_pg) != 0) {
5021 			switch (scf_error()) {
5022 			case SCF_ERROR_DELETED:
5023 				break;
5024 
5025 			case SCF_ERROR_CONNECTION_BROKEN:
5026 			case SCF_ERROR_BACKEND_READONLY:
5027 			case SCF_ERROR_BACKEND_ACCESS:
5028 				r = scferror2errno(scf_error());
5029 				goto out;
5030 
5031 			case SCF_ERROR_PERMISSION_DENIED:
5032 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5033 				r = scferror2errno(scf_error());
5034 				goto out;
5035 
5036 			case SCF_ERROR_NOT_SET:
5037 			default:
5038 				bad_error("scf_pg_delete", scf_error());
5039 			}
5040 		}
5041 
5042 		/* import new one */
5043 		cbdata.sc_handle = g_hndl;
5044 		cbdata.sc_trans = NULL;		/* handled below */
5045 		cbdata.sc_flags = 0;
5046 
5047 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5048 		if (r != UU_WALK_NEXT) {
5049 			if (r != UU_WALK_ERROR)
5050 				bad_error("lscf_dependent_import", r);
5051 
5052 			r = cbdata.sc_err;
5053 			goto out;
5054 		}
5055 
5056 		if (tx == NULL)
5057 			break;
5058 
5059 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5060 		    (val = scf_value_create(g_hndl)) == NULL) {
5061 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5062 				return (ENOMEM);
5063 
5064 			bad_error("scf_entry_create", scf_error());
5065 		}
5066 
5067 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5068 		    SCF_TYPE_FMRI) != 0) {
5069 			switch (scf_error()) {
5070 			case SCF_ERROR_CONNECTION_BROKEN:
5071 				r = scferror2errno(scf_error());
5072 				goto out;
5073 
5074 			case SCF_ERROR_DELETED:
5075 				warn(emsg_pg_deleted, ient->sc_fmri,
5076 				    "dependents");
5077 				r = EBUSY;
5078 				goto out;
5079 
5080 			case SCF_ERROR_NOT_FOUND:
5081 				break;
5082 
5083 			case SCF_ERROR_NOT_BOUND:
5084 			case SCF_ERROR_HANDLE_MISMATCH:
5085 			case SCF_ERROR_INVALID_ARGUMENT:
5086 			case SCF_ERROR_NOT_SET:
5087 			default:
5088 				bad_error("scf_transaction_property_"
5089 				    "change_type", scf_error());
5090 			}
5091 
5092 			if (scf_transaction_property_new(tx, ent, ud_name,
5093 			    SCF_TYPE_FMRI) != 0) {
5094 				switch (scf_error()) {
5095 				case SCF_ERROR_CONNECTION_BROKEN:
5096 					r = scferror2errno(scf_error());
5097 					goto out;
5098 
5099 				case SCF_ERROR_DELETED:
5100 					warn(emsg_pg_deleted, ient->sc_fmri,
5101 					    "dependents");
5102 					r = EBUSY;
5103 					goto out;
5104 
5105 				case SCF_ERROR_EXISTS:
5106 					warn(emsg_pg_changed, ient->sc_fmri,
5107 					    "dependents");
5108 					r = EBUSY;
5109 					goto out;
5110 
5111 				case SCF_ERROR_INVALID_ARGUMENT:
5112 				case SCF_ERROR_HANDLE_MISMATCH:
5113 				case SCF_ERROR_NOT_BOUND:
5114 				case SCF_ERROR_NOT_SET:
5115 				default:
5116 					bad_error("scf_transaction_property_"
5117 					    "new", scf_error());
5118 				}
5119 			}
5120 		}
5121 
5122 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5123 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5124 			/* invalid sc_pgroup_fmri caught above */
5125 			bad_error("scf_value_set_from_string",
5126 			    scf_error());
5127 
5128 		if (scf_entry_add_value(ent, val) != 0)
5129 			bad_error("scf_entry_add_value", scf_error());
5130 		break;
5131 	}
5132 
5133 	case -2:
5134 		warn(li_corrupt, ient->sc_fmri);
5135 		internal_pgroup_free(current_pg);
5136 		r = EBADF;
5137 		goto out;
5138 
5139 	case -1:
5140 	default:
5141 		/* invalid sc_pgroup_fmri caught above */
5142 		bad_error("fmri_equal", r);
5143 	}
5144 
5145 	r = 0;
5146 
5147 out:
5148 	if (old_dpt_pgroup != NULL)
5149 		internal_pgroup_free(old_dpt_pgroup);
5150 
5151 	return (r);
5152 }
5153 
5154 /*
5155  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5156  * would import it, except it seems to exist in the service anyway.  Compare
5157  * the existent dependent with the one we would import, and report any
5158  * differences (if there are none, be silent).  prop is the property which
5159  * represents the existent dependent (in the dependents property group) in the
5160  * entity corresponding to ient.
5161  *
5162  * Returns
5163  *   0 - success (Sort of.  At least, we can continue importing.)
5164  *   ECONNABORTED - repository connection broken
5165  *   EBUSY - ancestor of prop was deleted (error printed)
5166  *   ENOMEM - out of memory
5167  *   EBADF - corrupt property group (error printed)
5168  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5169  */
5170 static int
5171 handle_dependent_conflict(const entity_t * const ient,
5172     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5173 {
5174 	int r;
5175 	scf_type_t ty;
5176 	scf_error_t scfe;
5177 	void *tptr;
5178 	int tissvc;
5179 	pgroup_t *pgroup;
5180 
5181 	if (scf_property_get_value(prop, ud_val) != 0) {
5182 		switch (scf_error()) {
5183 		case SCF_ERROR_CONNECTION_BROKEN:
5184 			return (scferror2errno(scf_error()));
5185 
5186 		case SCF_ERROR_DELETED:
5187 			warn(emsg_pg_deleted, ient->sc_fmri,
5188 			    new_dpt_pgroup->sc_pgroup_name);
5189 			return (EBUSY);
5190 
5191 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5192 		case SCF_ERROR_NOT_FOUND:
5193 			warn(gettext("Conflict upgrading %s (not importing "
5194 			    "dependent \"%s\" because it already exists.)  "
5195 			    "Warning: The \"%s/%2$s\" property has more or "
5196 			    "fewer than one value)).\n"), ient->sc_fmri,
5197 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5198 			return (0);
5199 
5200 		case SCF_ERROR_HANDLE_MISMATCH:
5201 		case SCF_ERROR_NOT_BOUND:
5202 		case SCF_ERROR_NOT_SET:
5203 		case SCF_ERROR_PERMISSION_DENIED:
5204 		default:
5205 			bad_error("scf_property_get_value",
5206 			    scf_error());
5207 		}
5208 	}
5209 
5210 	ty = scf_value_type(ud_val);
5211 	assert(ty != SCF_TYPE_INVALID);
5212 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5213 		warn(gettext("Conflict upgrading %s (not importing dependent "
5214 		    "\"%s\" because it already exists).  Warning: The "
5215 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5216 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5217 		    scf_type_to_string(ty), "dependents");
5218 		return (0);
5219 	}
5220 
5221 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5222 	    0)
5223 		bad_error("scf_value_get_as_string", scf_error());
5224 
5225 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5226 	switch (r) {
5227 	case 0:
5228 		warn(gettext("Conflict upgrading %s (not importing dependent "
5229 		    "\"%s\" (target \"%s\") because it already exists with "
5230 		    "target \"%s\").\n"), ient->sc_fmri,
5231 		    new_dpt_pgroup->sc_pgroup_name,
5232 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5233 		return (0);
5234 
5235 	case 1:
5236 		break;
5237 
5238 	case -1:
5239 		warn(gettext("Conflict upgrading %s (not importing dependent "
5240 		    "\"%s\" because it already exists).  Warning: The current "
5241 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5242 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5243 		return (0);
5244 
5245 	case -2:
5246 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5247 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5248 		    new_dpt_pgroup->sc_pgroup_fmri);
5249 		return (EINVAL);
5250 
5251 	default:
5252 		bad_error("fmri_equal", r);
5253 	}
5254 
5255 	/* compare dependency pgs in target */
5256 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5257 	switch (scfe) {
5258 	case SCF_ERROR_NONE:
5259 		break;
5260 
5261 	case SCF_ERROR_NO_MEMORY:
5262 		return (ENOMEM);
5263 
5264 	case SCF_ERROR_NOT_FOUND:
5265 		warn(emsg_dpt_dangling, ient->sc_fmri,
5266 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5267 		return (0);
5268 
5269 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5270 	case SCF_ERROR_INVALID_ARGUMENT:
5271 	default:
5272 		bad_error("fmri_to_entity", scfe);
5273 	}
5274 
5275 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5276 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5277 	switch (r) {
5278 	case 0:
5279 		break;
5280 
5281 	case ECONNABORTED:
5282 		return (r);
5283 
5284 	case ECANCELED:
5285 		warn(emsg_dpt_dangling, ient->sc_fmri,
5286 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5287 		return (0);
5288 
5289 	case EBADF:
5290 		if (tissvc)
5291 			warn(gettext("%s has an instance with a \"%s\" "
5292 			    "snapshot which is missing a snaplevel.\n"),
5293 			    ud_ctarg, "running");
5294 		else
5295 			warn(gettext("%s has a \"%s\" snapshot which is "
5296 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5297 		/* FALLTHROUGH */
5298 
5299 	case ENOENT:
5300 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5301 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5302 		    new_dpt_pgroup->sc_pgroup_name);
5303 		return (0);
5304 
5305 	case EINVAL:
5306 	default:
5307 		bad_error("entity_get_running_pg", r);
5308 	}
5309 
5310 	pgroup = internal_pgroup_new();
5311 	if (pgroup == NULL)
5312 		return (ENOMEM);
5313 
5314 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5315 	switch (r) {
5316 	case 0:
5317 		break;
5318 
5319 	case ECONNABORTED:
5320 	case EBADF:
5321 	case ENOMEM:
5322 		internal_pgroup_free(pgroup);
5323 		return (r);
5324 
5325 	case ECANCELED:
5326 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5327 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5328 		    new_dpt_pgroup->sc_pgroup_name);
5329 		internal_pgroup_free(pgroup);
5330 		return (0);
5331 
5332 	case EACCES:
5333 	default:
5334 		bad_error("load_pg", r);
5335 	}
5336 
5337 	/* report differences */
5338 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5339 	internal_pgroup_free(pgroup);
5340 	return (0);
5341 }
5342 
5343 /*
5344  * lipg is a property group in the last-import snapshot of ent, which is an
5345  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5346  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5347  * in ents's property groups, compare and upgrade ent appropriately.
5348  *
5349  * Returns
5350  *   0 - success
5351  *   ECONNABORTED - repository connection broken
5352  *   ENOMEM - out of memory
5353  *   ENOSPC - configd is out of resources
5354  *   EINVAL - ient has invalid dependent (error printed)
5355  *	    - ient has invalid pgroup_t (error printed)
5356  *   ECANCELED - ent has been deleted
5357  *   ENODEV - entity containing lipg has been deleted
5358  *	    - entity containing running has been deleted
5359  *   EPERM - could not delete pg (permission denied) (error printed)
5360  *	   - couldn't upgrade dependents (permission denied) (error printed)
5361  *	   - couldn't import pg (permission denied) (error printed)
5362  *	   - couldn't upgrade pg (permission denied) (error printed)
5363  *   EROFS - could not delete pg (repository read-only)
5364  *	   - couldn't upgrade dependents (repository read-only)
5365  *	   - couldn't import pg (repository read-only)
5366  *	   - couldn't upgrade pg (repository read-only)
5367  *   EACCES - could not delete pg (backend access denied)
5368  *	    - couldn't upgrade dependents (backend access denied)
5369  *	    - couldn't import pg (backend access denied)
5370  *	    - couldn't upgrade pg (backend access denied)
5371  *	    - couldn't read property (backend access denied)
5372  *   EBUSY - property group was added (error printed)
5373  *	   - property group was deleted (error printed)
5374  *	   - property group changed (error printed)
5375  *	   - "dependents" pg was added, changed, or deleted (error printed)
5376  *	   - dependent target deleted (error printed)
5377  *	   - dependent pg changed (error printed)
5378  *   EBADF - imp_snpl is corrupt (error printed)
5379  *	   - ent has bad pg (error printed)
5380  *   EEXIST - dependent collision in target service (error printed)
5381  */
5382 static int
5383 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5384     const scf_snaplevel_t *running)
5385 {
5386 	int r;
5387 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5388 	scf_callback_t cbdata;
5389 
5390 	const char * const cf_pg_missing =
5391 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5392 	const char * const deleting =
5393 	    gettext("%s: Deleting property group \"%s\".\n");
5394 
5395 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5396 
5397 	/* Skip dependent property groups. */
5398 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5399 		switch (scf_error()) {
5400 		case SCF_ERROR_DELETED:
5401 			return (ENODEV);
5402 
5403 		case SCF_ERROR_CONNECTION_BROKEN:
5404 			return (ECONNABORTED);
5405 
5406 		case SCF_ERROR_NOT_SET:
5407 		case SCF_ERROR_NOT_BOUND:
5408 		default:
5409 			bad_error("scf_pg_get_type", scf_error());
5410 		}
5411 	}
5412 
5413 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5414 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5415 			return (0);
5416 
5417 		switch (scf_error()) {
5418 		case SCF_ERROR_NOT_FOUND:
5419 			break;
5420 
5421 		case SCF_ERROR_CONNECTION_BROKEN:
5422 			return (ECONNABORTED);
5423 
5424 		case SCF_ERROR_DELETED:
5425 			return (ENODEV);
5426 
5427 		case SCF_ERROR_INVALID_ARGUMENT:
5428 		case SCF_ERROR_NOT_BOUND:
5429 		case SCF_ERROR_HANDLE_MISMATCH:
5430 		case SCF_ERROR_NOT_SET:
5431 		default:
5432 			bad_error("scf_pg_get_property", scf_error());
5433 		}
5434 	}
5435 
5436 	/* lookup pg in new properties */
5437 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5438 		switch (scf_error()) {
5439 		case SCF_ERROR_DELETED:
5440 			return (ENODEV);
5441 
5442 		case SCF_ERROR_CONNECTION_BROKEN:
5443 			return (ECONNABORTED);
5444 
5445 		case SCF_ERROR_NOT_SET:
5446 		case SCF_ERROR_NOT_BOUND:
5447 		default:
5448 			bad_error("scf_pg_get_name", scf_error());
5449 		}
5450 	}
5451 
5452 	pgrp.sc_pgroup_name = imp_str;
5453 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5454 
5455 	if (mpg != NULL)
5456 		mpg->sc_pgroup_seen = 1;
5457 
5458 	/* Special handling for dependents */
5459 	if (strcmp(imp_str, "dependents") == 0)
5460 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5461 
5462 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5463 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5464 
5465 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5466 		/* property group was deleted from manifest */
5467 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5468 			switch (scf_error()) {
5469 			case SCF_ERROR_NOT_FOUND:
5470 				return (0);
5471 
5472 			case SCF_ERROR_DELETED:
5473 			case SCF_ERROR_CONNECTION_BROKEN:
5474 				return (scferror2errno(scf_error()));
5475 
5476 			case SCF_ERROR_INVALID_ARGUMENT:
5477 			case SCF_ERROR_HANDLE_MISMATCH:
5478 			case SCF_ERROR_NOT_BOUND:
5479 			case SCF_ERROR_NOT_SET:
5480 			default:
5481 				bad_error("entity_get_pg", scf_error());
5482 			}
5483 		}
5484 
5485 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5486 			if (g_verbose)
5487 				warn(deleting, ient->sc_fmri, imp_str);
5488 			if (scf_pg_delete(imp_pg2) == 0)
5489 				return (0);
5490 
5491 			switch (scf_error()) {
5492 			case SCF_ERROR_DELETED:
5493 				return (0);
5494 
5495 			case SCF_ERROR_CONNECTION_BROKEN:
5496 			case SCF_ERROR_BACKEND_READONLY:
5497 			case SCF_ERROR_BACKEND_ACCESS:
5498 				return (scferror2errno(scf_error()));
5499 
5500 			case SCF_ERROR_PERMISSION_DENIED:
5501 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5502 				return (scferror2errno(scf_error()));
5503 
5504 			case SCF_ERROR_NOT_SET:
5505 			default:
5506 				bad_error("scf_pg_delete", scf_error());
5507 			}
5508 		}
5509 
5510 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5511 		switch (r) {
5512 		case 0:
5513 			break;
5514 
5515 		case ECANCELED:
5516 			return (ENODEV);
5517 
5518 		case ECONNABORTED:
5519 		case ENOMEM:
5520 		case EBADF:
5521 		case EACCES:
5522 			return (r);
5523 
5524 		default:
5525 			bad_error("load_pg", r);
5526 		}
5527 
5528 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5529 		switch (r) {
5530 		case 0:
5531 			break;
5532 
5533 		case ECANCELED:
5534 		case ECONNABORTED:
5535 		case ENOMEM:
5536 		case EBADF:
5537 		case EACCES:
5538 			internal_pgroup_free(lipg_i);
5539 			return (r);
5540 
5541 		default:
5542 			bad_error("load_pg", r);
5543 		}
5544 
5545 		if (pg_equal(lipg_i, curpg_i)) {
5546 			if (g_verbose)
5547 				warn(deleting, ient->sc_fmri, imp_str);
5548 			if (scf_pg_delete(imp_pg2) != 0) {
5549 				switch (scf_error()) {
5550 				case SCF_ERROR_DELETED:
5551 					break;
5552 
5553 				case SCF_ERROR_CONNECTION_BROKEN:
5554 					internal_pgroup_free(lipg_i);
5555 					internal_pgroup_free(curpg_i);
5556 					return (ECONNABORTED);
5557 
5558 				case SCF_ERROR_NOT_SET:
5559 				case SCF_ERROR_NOT_BOUND:
5560 				default:
5561 					bad_error("scf_pg_delete", scf_error());
5562 				}
5563 			}
5564 		} else {
5565 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5566 		}
5567 
5568 		internal_pgroup_free(lipg_i);
5569 		internal_pgroup_free(curpg_i);
5570 
5571 		return (0);
5572 	}
5573 
5574 	/*
5575 	 * Only dependent pgs can have override set, and we skipped those
5576 	 * above.
5577 	 */
5578 	assert(!mpg->sc_pgroup_override);
5579 
5580 	/* compare */
5581 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5582 	switch (r) {
5583 	case 0:
5584 		break;
5585 
5586 	case ECANCELED:
5587 		return (ENODEV);
5588 
5589 	case ECONNABORTED:
5590 	case EBADF:
5591 	case ENOMEM:
5592 	case EACCES:
5593 		return (r);
5594 
5595 	default:
5596 		bad_error("load_pg", r);
5597 	}
5598 
5599 	if (pg_equal(mpg, lipg_i)) {
5600 		/* The manifest pg has not changed.  Move on. */
5601 		r = 0;
5602 		goto out;
5603 	}
5604 
5605 	/* upgrade current properties according to lipg & mpg */
5606 	if (running != NULL)
5607 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5608 	else
5609 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5610 	if (r != 0) {
5611 		switch (scf_error()) {
5612 		case SCF_ERROR_CONNECTION_BROKEN:
5613 			r = scferror2errno(scf_error());
5614 			goto out;
5615 
5616 		case SCF_ERROR_DELETED:
5617 			if (running != NULL)
5618 				r = ENODEV;
5619 			else
5620 				r = ECANCELED;
5621 			goto out;
5622 
5623 		case SCF_ERROR_NOT_FOUND:
5624 			break;
5625 
5626 		case SCF_ERROR_INVALID_ARGUMENT:
5627 		case SCF_ERROR_HANDLE_MISMATCH:
5628 		case SCF_ERROR_NOT_BOUND:
5629 		case SCF_ERROR_NOT_SET:
5630 		default:
5631 			bad_error("entity_get_pg", scf_error());
5632 		}
5633 
5634 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5635 
5636 		r = 0;
5637 		goto out;
5638 	}
5639 
5640 	r = load_pg_attrs(imp_pg2, &curpg_i);
5641 	switch (r) {
5642 	case 0:
5643 		break;
5644 
5645 	case ECANCELED:
5646 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5647 		r = 0;
5648 		goto out;
5649 
5650 	case ECONNABORTED:
5651 	case ENOMEM:
5652 		goto out;
5653 
5654 	default:
5655 		bad_error("load_pg_attrs", r);
5656 	}
5657 
5658 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5659 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5660 		internal_pgroup_free(curpg_i);
5661 		r = 0;
5662 		goto out;
5663 	}
5664 
5665 	internal_pgroup_free(curpg_i);
5666 
5667 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5668 	switch (r) {
5669 	case 0:
5670 		break;
5671 
5672 	case ECANCELED:
5673 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5674 		r = 0;
5675 		goto out;
5676 
5677 	case ECONNABORTED:
5678 	case EBADF:
5679 	case ENOMEM:
5680 	case EACCES:
5681 		goto out;
5682 
5683 	default:
5684 		bad_error("load_pg", r);
5685 	}
5686 
5687 	if (pg_equal(lipg_i, curpg_i) &&
5688 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5689 		int do_delete = 1;
5690 
5691 		if (g_verbose)
5692 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5693 			    ient->sc_fmri, mpg->sc_pgroup_name);
5694 
5695 		internal_pgroup_free(curpg_i);
5696 
5697 		if (running != NULL &&
5698 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5699 			switch (scf_error()) {
5700 			case SCF_ERROR_DELETED:
5701 				r = ECANCELED;
5702 				goto out;
5703 
5704 			case SCF_ERROR_NOT_FOUND:
5705 				do_delete = 0;
5706 				break;
5707 
5708 			case SCF_ERROR_CONNECTION_BROKEN:
5709 				r = scferror2errno(scf_error());
5710 				goto out;
5711 
5712 			case SCF_ERROR_HANDLE_MISMATCH:
5713 			case SCF_ERROR_INVALID_ARGUMENT:
5714 			case SCF_ERROR_NOT_SET:
5715 			case SCF_ERROR_NOT_BOUND:
5716 			default:
5717 				bad_error("entity_get_pg", scf_error());
5718 			}
5719 		}
5720 
5721 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5722 			switch (scf_error()) {
5723 			case SCF_ERROR_DELETED:
5724 				break;
5725 
5726 			case SCF_ERROR_CONNECTION_BROKEN:
5727 			case SCF_ERROR_BACKEND_READONLY:
5728 			case SCF_ERROR_BACKEND_ACCESS:
5729 				r = scferror2errno(scf_error());
5730 				goto out;
5731 
5732 			case SCF_ERROR_PERMISSION_DENIED:
5733 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5734 				    ient->sc_fmri);
5735 				r = scferror2errno(scf_error());
5736 				goto out;
5737 
5738 			case SCF_ERROR_NOT_SET:
5739 			case SCF_ERROR_NOT_BOUND:
5740 			default:
5741 				bad_error("scf_pg_delete", scf_error());
5742 			}
5743 		}
5744 
5745 		cbdata.sc_handle = g_hndl;
5746 		cbdata.sc_parent = ent;
5747 		cbdata.sc_service = issvc;
5748 		cbdata.sc_flags = 0;
5749 		cbdata.sc_source_fmri = ient->sc_fmri;
5750 		cbdata.sc_target_fmri = ient->sc_fmri;
5751 
5752 		r = entity_pgroup_import(mpg, &cbdata);
5753 		switch (r) {
5754 		case UU_WALK_NEXT:
5755 			r = 0;
5756 			goto out;
5757 
5758 		case UU_WALK_ERROR:
5759 			if (cbdata.sc_err == EEXIST) {
5760 				warn(emsg_pg_added, ient->sc_fmri,
5761 				    mpg->sc_pgroup_name);
5762 				r = EBUSY;
5763 			} else {
5764 				r = cbdata.sc_err;
5765 			}
5766 			goto out;
5767 
5768 		default:
5769 			bad_error("entity_pgroup_import", r);
5770 		}
5771 	}
5772 
5773 	if (running != NULL &&
5774 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5775 		switch (scf_error()) {
5776 		case SCF_ERROR_CONNECTION_BROKEN:
5777 		case SCF_ERROR_DELETED:
5778 			r = scferror2errno(scf_error());
5779 			goto out;
5780 
5781 		case SCF_ERROR_NOT_FOUND:
5782 			break;
5783 
5784 		case SCF_ERROR_HANDLE_MISMATCH:
5785 		case SCF_ERROR_INVALID_ARGUMENT:
5786 		case SCF_ERROR_NOT_SET:
5787 		case SCF_ERROR_NOT_BOUND:
5788 		default:
5789 			bad_error("entity_get_pg", scf_error());
5790 		}
5791 
5792 		cbdata.sc_handle = g_hndl;
5793 		cbdata.sc_parent = ent;
5794 		cbdata.sc_service = issvc;
5795 		cbdata.sc_flags = SCI_FORCE;
5796 		cbdata.sc_source_fmri = ient->sc_fmri;
5797 		cbdata.sc_target_fmri = ient->sc_fmri;
5798 
5799 		r = entity_pgroup_import(mpg, &cbdata);
5800 		switch (r) {
5801 		case UU_WALK_NEXT:
5802 			r = 0;
5803 			goto out;
5804 
5805 		case UU_WALK_ERROR:
5806 			if (cbdata.sc_err == EEXIST) {
5807 				warn(emsg_pg_added, ient->sc_fmri,
5808 				    mpg->sc_pgroup_name);
5809 				r = EBUSY;
5810 			} else {
5811 				r = cbdata.sc_err;
5812 			}
5813 			goto out;
5814 
5815 		default:
5816 			bad_error("entity_pgroup_import", r);
5817 		}
5818 	}
5819 
5820 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5821 	internal_pgroup_free(curpg_i);
5822 	switch (r) {
5823 	case 0:
5824 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5825 		break;
5826 
5827 	case ECANCELED:
5828 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5829 		r = EBUSY;
5830 		break;
5831 
5832 	case EPERM:
5833 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5834 		break;
5835 
5836 	case EBUSY:
5837 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5838 		break;
5839 
5840 	case ECONNABORTED:
5841 	case ENOMEM:
5842 	case ENOSPC:
5843 	case EROFS:
5844 	case EACCES:
5845 	case EINVAL:
5846 		break;
5847 
5848 	default:
5849 		bad_error("upgrade_pg", r);
5850 	}
5851 
5852 out:
5853 	internal_pgroup_free(lipg_i);
5854 	return (r);
5855 }
5856 
5857 /*
5858  * Upgrade the properties of ent according to snpl & ient.
5859  *
5860  * Returns
5861  *   0 - success
5862  *   ECONNABORTED - repository connection broken
5863  *   ENOMEM - out of memory
5864  *   ENOSPC - configd is out of resources
5865  *   ECANCELED - ent was deleted
5866  *   ENODEV - entity containing snpl was deleted
5867  *	    - entity containing running was deleted
5868  *   EBADF - imp_snpl is corrupt (error printed)
5869  *	   - ent has corrupt pg (error printed)
5870  *	   - dependent has corrupt pg (error printed)
5871  *	   - dependent target has a corrupt snapshot (error printed)
5872  *   EBUSY - pg was added, changed, or deleted (error printed)
5873  *	   - dependent target was deleted (error printed)
5874  *	   - dependent pg changed (error printed)
5875  *   EINVAL - invalid property group name (error printed)
5876  *	    - invalid property name (error printed)
5877  *	    - invalid value (error printed)
5878  *	    - ient has invalid pgroup or dependent (error printed)
5879  *   EPERM - could not create property group (permission denied) (error printed)
5880  *	   - could not modify property group (permission denied) (error printed)
5881  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5882  *   EROFS - could not create property group (repository read-only)
5883  *	   - couldn't delete, upgrade, or import pg or dependent
5884  *   EACCES - could not create property group (backend access denied)
5885  *	    - couldn't delete, upgrade, or import pg or dependent
5886  *   EEXIST - dependent collision in target service (error printed)
5887  */
5888 static int
5889 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5890     entity_t *ient)
5891 {
5892 	pgroup_t *pg, *rpg;
5893 	int r;
5894 	uu_list_t *pgs = ient->sc_pgroups;
5895 
5896 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5897 
5898 	/* clear sc_sceen for pgs */
5899 	if (uu_list_walk(pgs, clear_int,
5900 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5901 		bad_error("uu_list_walk", uu_error());
5902 
5903 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5904 		switch (scf_error()) {
5905 		case SCF_ERROR_DELETED:
5906 			return (ENODEV);
5907 
5908 		case SCF_ERROR_CONNECTION_BROKEN:
5909 			return (ECONNABORTED);
5910 
5911 		case SCF_ERROR_NOT_SET:
5912 		case SCF_ERROR_NOT_BOUND:
5913 		case SCF_ERROR_HANDLE_MISMATCH:
5914 		default:
5915 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5916 		}
5917 	}
5918 
5919 	for (;;) {
5920 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5921 		if (r == 0)
5922 			break;
5923 		if (r == 1) {
5924 			r = process_old_pg(imp_pg, ient, ent, running);
5925 			switch (r) {
5926 			case 0:
5927 				break;
5928 
5929 			case ECONNABORTED:
5930 			case ENOMEM:
5931 			case ENOSPC:
5932 			case ECANCELED:
5933 			case ENODEV:
5934 			case EPERM:
5935 			case EROFS:
5936 			case EACCES:
5937 			case EBADF:
5938 			case EBUSY:
5939 			case EINVAL:
5940 			case EEXIST:
5941 				return (r);
5942 
5943 			default:
5944 				bad_error("process_old_pg", r);
5945 			}
5946 			continue;
5947 		}
5948 		if (r != -1)
5949 			bad_error("scf_iter_next_pg", r);
5950 
5951 		switch (scf_error()) {
5952 		case SCF_ERROR_DELETED:
5953 			return (ENODEV);
5954 
5955 		case SCF_ERROR_CONNECTION_BROKEN:
5956 			return (ECONNABORTED);
5957 
5958 		case SCF_ERROR_HANDLE_MISMATCH:
5959 		case SCF_ERROR_NOT_BOUND:
5960 		case SCF_ERROR_NOT_SET:
5961 		case SCF_ERROR_INVALID_ARGUMENT:
5962 		default:
5963 			bad_error("scf_iter_next_pg", scf_error());
5964 		}
5965 	}
5966 
5967 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5968 		if (pg->sc_pgroup_seen)
5969 			continue;
5970 
5971 		/* pg is new */
5972 
5973 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5974 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5975 			    ent);
5976 			switch (r) {
5977 			case 0:
5978 				break;
5979 
5980 			case ECONNABORTED:
5981 			case ENOMEM:
5982 			case ENOSPC:
5983 			case ECANCELED:
5984 			case ENODEV:
5985 			case EBADF:
5986 			case EBUSY:
5987 			case EINVAL:
5988 			case EPERM:
5989 			case EROFS:
5990 			case EACCES:
5991 			case EEXIST:
5992 				return (r);
5993 
5994 			default:
5995 				bad_error("upgrade_dependents", r);
5996 			}
5997 			continue;
5998 		}
5999 
6000 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6001 			r = upgrade_manifestfiles(pg, ient, running, ent);
6002 			switch (r) {
6003 			case 0:
6004 				break;
6005 
6006 			case ECONNABORTED:
6007 			case ENOMEM:
6008 			case ENOSPC:
6009 			case ECANCELED:
6010 			case ENODEV:
6011 			case EBADF:
6012 			case EBUSY:
6013 			case EINVAL:
6014 			case EPERM:
6015 			case EROFS:
6016 			case EACCES:
6017 			case EEXIST:
6018 				return (r);
6019 
6020 			default:
6021 				bad_error("upgrade_manifestfiles", r);
6022 			}
6023 			continue;
6024 		}
6025 
6026 		if (running != NULL) {
6027 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6028 			    imp_pg);
6029 		} else {
6030 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6031 			    imp_pg);
6032 		}
6033 		if (r != 0) {
6034 			scf_callback_t cbdata;
6035 
6036 			switch (scf_error()) {
6037 			case SCF_ERROR_NOT_FOUND:
6038 				break;
6039 
6040 			case SCF_ERROR_CONNECTION_BROKEN:
6041 				return (scferror2errno(scf_error()));
6042 
6043 			case SCF_ERROR_DELETED:
6044 				if (running != NULL)
6045 					return (ENODEV);
6046 				else
6047 					return (scferror2errno(scf_error()));
6048 
6049 			case SCF_ERROR_INVALID_ARGUMENT:
6050 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6051 				    pg->sc_pgroup_name);
6052 				return (EINVAL);
6053 
6054 			case SCF_ERROR_NOT_SET:
6055 			case SCF_ERROR_HANDLE_MISMATCH:
6056 			case SCF_ERROR_NOT_BOUND:
6057 			default:
6058 				bad_error("entity_get_pg", scf_error());
6059 			}
6060 
6061 			/* User doesn't have pg, so import it. */
6062 
6063 			cbdata.sc_handle = g_hndl;
6064 			cbdata.sc_parent = ent;
6065 			cbdata.sc_service = issvc;
6066 			cbdata.sc_flags = SCI_FORCE;
6067 			cbdata.sc_source_fmri = ient->sc_fmri;
6068 			cbdata.sc_target_fmri = ient->sc_fmri;
6069 
6070 			r = entity_pgroup_import(pg, &cbdata);
6071 			switch (r) {
6072 			case UU_WALK_NEXT:
6073 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6074 				continue;
6075 
6076 			case UU_WALK_ERROR:
6077 				if (cbdata.sc_err == EEXIST) {
6078 					warn(emsg_pg_added, ient->sc_fmri,
6079 					    pg->sc_pgroup_name);
6080 					return (EBUSY);
6081 				}
6082 				return (cbdata.sc_err);
6083 
6084 			default:
6085 				bad_error("entity_pgroup_import", r);
6086 			}
6087 		}
6088 
6089 		/* report differences between pg & current */
6090 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6091 		switch (r) {
6092 		case 0:
6093 			break;
6094 
6095 		case ECANCELED:
6096 			warn(emsg_pg_deleted, ient->sc_fmri,
6097 			    pg->sc_pgroup_name);
6098 			return (EBUSY);
6099 
6100 		case ECONNABORTED:
6101 		case EBADF:
6102 		case ENOMEM:
6103 		case EACCES:
6104 			return (r);
6105 
6106 		default:
6107 			bad_error("load_pg", r);
6108 		}
6109 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6110 		internal_pgroup_free(rpg);
6111 		rpg = NULL;
6112 	}
6113 
6114 	return (0);
6115 }
6116 
6117 /*
6118  * Import an instance.  If it doesn't exist, create it.  If it has
6119  * a last-import snapshot, upgrade its properties.  Finish by updating its
6120  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6121  * could have been created for a dependent tag in another manifest.  Import the
6122  * new properties.  If there's a conflict, don't override, like now?
6123  *
6124  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6125  * lcbdata->sc_err to
6126  *   ECONNABORTED - repository connection broken
6127  *   ENOMEM - out of memory
6128  *   ENOSPC - svc.configd is out of resources
6129  *   EEXIST - dependency collision in dependent service (error printed)
6130  *   EPERM - couldn't create temporary instance (permission denied)
6131  *	   - couldn't import into temporary instance (permission denied)
6132  *	   - couldn't take snapshot (permission denied)
6133  *	   - couldn't upgrade properties (permission denied)
6134  *	   - couldn't import properties (permission denied)
6135  *	   - couldn't import dependents (permission denied)
6136  *   EROFS - couldn't create temporary instance (repository read-only)
6137  *	   - couldn't import into temporary instance (repository read-only)
6138  *	   - couldn't upgrade properties (repository read-only)
6139  *	   - couldn't import properties (repository read-only)
6140  *	   - couldn't import dependents (repository read-only)
6141  *   EACCES - couldn't create temporary instance (backend access denied)
6142  *	    - couldn't import into temporary instance (backend access denied)
6143  *	    - couldn't upgrade properties (backend access denied)
6144  *	    - couldn't import properties (backend access denied)
6145  *	    - couldn't import dependents (backend access denied)
6146  *   EINVAL - invalid instance name (error printed)
6147  *	    - invalid pgroup_t's (error printed)
6148  *	    - invalid dependents (error printed)
6149  *   EBUSY - temporary service deleted (error printed)
6150  *	   - temporary instance deleted (error printed)
6151  *	   - temporary instance changed (error printed)
6152  *	   - temporary instance already exists (error printed)
6153  *	   - instance deleted (error printed)
6154  *   EBADF - instance has corrupt last-import snapshot (error printed)
6155  *	   - instance is corrupt (error printed)
6156  *	   - dependent has corrupt pg (error printed)
6157  *	   - dependent target has a corrupt snapshot (error printed)
6158  *   -1 - unknown libscf error (error printed)
6159  */
6160 static int
6161 lscf_instance_import(void *v, void *pvt)
6162 {
6163 	entity_t *inst = v;
6164 	scf_callback_t ctx;
6165 	scf_callback_t *lcbdata = pvt;
6166 	scf_service_t *rsvc = lcbdata->sc_parent;
6167 	int r;
6168 	scf_snaplevel_t *running;
6169 	int flags = lcbdata->sc_flags;
6170 
6171 	const char * const emsg_tdel =
6172 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6173 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6174 	    "changed unexpectedly.\n");
6175 	const char * const emsg_del = gettext("%s changed unexpectedly "
6176 	    "(instance \"%s\" was deleted.)\n");
6177 	const char * const emsg_badsnap = gettext(
6178 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6179 
6180 	/*
6181 	 * prepare last-import snapshot:
6182 	 * create temporary instance (service was precreated)
6183 	 * populate with properties from bundle
6184 	 * take snapshot
6185 	 */
6186 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6187 		switch (scf_error()) {
6188 		case SCF_ERROR_CONNECTION_BROKEN:
6189 		case SCF_ERROR_NO_RESOURCES:
6190 		case SCF_ERROR_BACKEND_READONLY:
6191 		case SCF_ERROR_BACKEND_ACCESS:
6192 			return (stash_scferror(lcbdata));
6193 
6194 		case SCF_ERROR_EXISTS:
6195 			warn(gettext("Temporary service svc:/%s "
6196 			    "changed unexpectedly (instance \"%s\" added).\n"),
6197 			    imp_tsname, inst->sc_name);
6198 			lcbdata->sc_err = EBUSY;
6199 			return (UU_WALK_ERROR);
6200 
6201 		case SCF_ERROR_DELETED:
6202 			warn(gettext("Temporary service svc:/%s "
6203 			    "was deleted unexpectedly.\n"), imp_tsname);
6204 			lcbdata->sc_err = EBUSY;
6205 			return (UU_WALK_ERROR);
6206 
6207 		case SCF_ERROR_INVALID_ARGUMENT:
6208 			warn(gettext("Invalid instance name \"%s\".\n"),
6209 			    inst->sc_name);
6210 			return (stash_scferror(lcbdata));
6211 
6212 		case SCF_ERROR_PERMISSION_DENIED:
6213 			warn(gettext("Could not create temporary instance "
6214 			    "\"%s\" in svc:/%s (permission denied).\n"),
6215 			    inst->sc_name, imp_tsname);
6216 			return (stash_scferror(lcbdata));
6217 
6218 		case SCF_ERROR_HANDLE_MISMATCH:
6219 		case SCF_ERROR_NOT_BOUND:
6220 		case SCF_ERROR_NOT_SET:
6221 		default:
6222 			bad_error("scf_service_add_instance", scf_error());
6223 		}
6224 	}
6225 
6226 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6227 	    inst->sc_name);
6228 	if (r < 0)
6229 		bad_error("snprintf", errno);
6230 
6231 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6232 	    lcbdata->sc_flags | SCI_NOENABLED);
6233 	switch (r) {
6234 	case 0:
6235 		break;
6236 
6237 	case ECANCELED:
6238 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6239 		lcbdata->sc_err = EBUSY;
6240 		r = UU_WALK_ERROR;
6241 		goto deltemp;
6242 
6243 	case EEXIST:
6244 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6245 		lcbdata->sc_err = EBUSY;
6246 		r = UU_WALK_ERROR;
6247 		goto deltemp;
6248 
6249 	case ECONNABORTED:
6250 		goto connaborted;
6251 
6252 	case ENOMEM:
6253 	case ENOSPC:
6254 	case EPERM:
6255 	case EROFS:
6256 	case EACCES:
6257 	case EINVAL:
6258 	case EBUSY:
6259 		lcbdata->sc_err = r;
6260 		r = UU_WALK_ERROR;
6261 		goto deltemp;
6262 
6263 	default:
6264 		bad_error("lscf_import_instance_pgs", r);
6265 	}
6266 
6267 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6268 	    inst->sc_name);
6269 	if (r < 0)
6270 		bad_error("snprintf", errno);
6271 
6272 	ctx.sc_handle = lcbdata->sc_handle;
6273 	ctx.sc_parent = imp_tinst;
6274 	ctx.sc_service = 0;
6275 	ctx.sc_source_fmri = inst->sc_fmri;
6276 	ctx.sc_target_fmri = imp_str;
6277 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6278 	    UU_DEFAULT) != 0) {
6279 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6280 			bad_error("uu_list_walk", uu_error());
6281 
6282 		switch (ctx.sc_err) {
6283 		case ECONNABORTED:
6284 			goto connaborted;
6285 
6286 		case ECANCELED:
6287 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6288 			lcbdata->sc_err = EBUSY;
6289 			break;
6290 
6291 		case EEXIST:
6292 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6293 			lcbdata->sc_err = EBUSY;
6294 			break;
6295 
6296 		default:
6297 			lcbdata->sc_err = ctx.sc_err;
6298 		}
6299 		r = UU_WALK_ERROR;
6300 		goto deltemp;
6301 	}
6302 
6303 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6304 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6305 		switch (scf_error()) {
6306 		case SCF_ERROR_CONNECTION_BROKEN:
6307 			goto connaborted;
6308 
6309 		case SCF_ERROR_NO_RESOURCES:
6310 			r = stash_scferror(lcbdata);
6311 			goto deltemp;
6312 
6313 		case SCF_ERROR_EXISTS:
6314 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6315 			lcbdata->sc_err = EBUSY;
6316 			r = UU_WALK_ERROR;
6317 			goto deltemp;
6318 
6319 		case SCF_ERROR_PERMISSION_DENIED:
6320 			warn(gettext("Could not take \"%s\" snapshot of %s "
6321 			    "(permission denied).\n"), snap_lastimport,
6322 			    imp_str);
6323 			r = stash_scferror(lcbdata);
6324 			goto deltemp;
6325 
6326 		default:
6327 			scfwarn();
6328 			lcbdata->sc_err = -1;
6329 			r = UU_WALK_ERROR;
6330 			goto deltemp;
6331 
6332 		case SCF_ERROR_HANDLE_MISMATCH:
6333 		case SCF_ERROR_INVALID_ARGUMENT:
6334 		case SCF_ERROR_NOT_SET:
6335 			bad_error("_scf_snapshot_take_new_named", scf_error());
6336 		}
6337 	}
6338 
6339 	if (lcbdata->sc_flags & SCI_FRESH)
6340 		goto fresh;
6341 
6342 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6343 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6344 		    imp_lisnap) != 0) {
6345 			switch (scf_error()) {
6346 			case SCF_ERROR_DELETED:
6347 				warn(emsg_del, inst->sc_parent->sc_fmri,
6348 				    inst->sc_name);
6349 				lcbdata->sc_err = EBUSY;
6350 				r = UU_WALK_ERROR;
6351 				goto deltemp;
6352 
6353 			case SCF_ERROR_NOT_FOUND:
6354 				flags |= SCI_FORCE;
6355 				goto nosnap;
6356 
6357 			case SCF_ERROR_CONNECTION_BROKEN:
6358 				goto connaborted;
6359 
6360 			case SCF_ERROR_INVALID_ARGUMENT:
6361 			case SCF_ERROR_HANDLE_MISMATCH:
6362 			case SCF_ERROR_NOT_BOUND:
6363 			case SCF_ERROR_NOT_SET:
6364 			default:
6365 				bad_error("scf_instance_get_snapshot",
6366 				    scf_error());
6367 			}
6368 		}
6369 
6370 		/* upgrade */
6371 
6372 		/*
6373 		 * compare new properties with last-import properties
6374 		 * upgrade current properties
6375 		 */
6376 		/* clear sc_sceen for pgs */
6377 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6378 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6379 		    0)
6380 			bad_error("uu_list_walk", uu_error());
6381 
6382 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6383 		switch (r) {
6384 		case 0:
6385 			break;
6386 
6387 		case ECONNABORTED:
6388 			goto connaborted;
6389 
6390 		case ECANCELED:
6391 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6392 			lcbdata->sc_err = EBUSY;
6393 			r = UU_WALK_ERROR;
6394 			goto deltemp;
6395 
6396 		case ENOENT:
6397 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6398 			lcbdata->sc_err = EBADF;
6399 			r = UU_WALK_ERROR;
6400 			goto deltemp;
6401 
6402 		default:
6403 			bad_error("get_snaplevel", r);
6404 		}
6405 
6406 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6407 		    imp_rsnap) != 0) {
6408 			switch (scf_error()) {
6409 			case SCF_ERROR_DELETED:
6410 				warn(emsg_del, inst->sc_parent->sc_fmri,
6411 				    inst->sc_name);
6412 				lcbdata->sc_err = EBUSY;
6413 				r = UU_WALK_ERROR;
6414 				goto deltemp;
6415 
6416 			case SCF_ERROR_NOT_FOUND:
6417 				break;
6418 
6419 			case SCF_ERROR_CONNECTION_BROKEN:
6420 				goto connaborted;
6421 
6422 			case SCF_ERROR_INVALID_ARGUMENT:
6423 			case SCF_ERROR_HANDLE_MISMATCH:
6424 			case SCF_ERROR_NOT_BOUND:
6425 			case SCF_ERROR_NOT_SET:
6426 			default:
6427 				bad_error("scf_instance_get_snapshot",
6428 				    scf_error());
6429 			}
6430 
6431 			running = NULL;
6432 		} else {
6433 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6434 			switch (r) {
6435 			case 0:
6436 				running = imp_rsnpl;
6437 				break;
6438 
6439 			case ECONNABORTED:
6440 				goto connaborted;
6441 
6442 			case ECANCELED:
6443 				warn(emsg_del, inst->sc_parent->sc_fmri,
6444 				    inst->sc_name);
6445 				lcbdata->sc_err = EBUSY;
6446 				r = UU_WALK_ERROR;
6447 				goto deltemp;
6448 
6449 			case ENOENT:
6450 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6451 				lcbdata->sc_err = EBADF;
6452 				r = UU_WALK_ERROR;
6453 				goto deltemp;
6454 
6455 			default:
6456 				bad_error("get_snaplevel", r);
6457 			}
6458 		}
6459 
6460 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6461 		switch (r) {
6462 		case 0:
6463 			break;
6464 
6465 		case ECANCELED:
6466 		case ENODEV:
6467 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6468 			lcbdata->sc_err = EBUSY;
6469 			r = UU_WALK_ERROR;
6470 			goto deltemp;
6471 
6472 		case ECONNABORTED:
6473 			goto connaborted;
6474 
6475 		case ENOMEM:
6476 		case ENOSPC:
6477 		case EBADF:
6478 		case EBUSY:
6479 		case EINVAL:
6480 		case EPERM:
6481 		case EROFS:
6482 		case EACCES:
6483 		case EEXIST:
6484 			lcbdata->sc_err = r;
6485 			r = UU_WALK_ERROR;
6486 			goto deltemp;
6487 
6488 		default:
6489 			bad_error("upgrade_props", r);
6490 		}
6491 
6492 		inst->sc_import_state = IMPORT_PROP_DONE;
6493 	} else {
6494 		switch (scf_error()) {
6495 		case SCF_ERROR_CONNECTION_BROKEN:
6496 			goto connaborted;
6497 
6498 		case SCF_ERROR_NOT_FOUND:
6499 			break;
6500 
6501 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6502 		case SCF_ERROR_HANDLE_MISMATCH:
6503 		case SCF_ERROR_NOT_BOUND:
6504 		case SCF_ERROR_NOT_SET:
6505 		default:
6506 			bad_error("scf_service_get_instance", scf_error());
6507 		}
6508 
6509 fresh:
6510 		/* create instance */
6511 		if (scf_service_add_instance(rsvc, inst->sc_name,
6512 		    imp_inst) != 0) {
6513 			switch (scf_error()) {
6514 			case SCF_ERROR_CONNECTION_BROKEN:
6515 				goto connaborted;
6516 
6517 			case SCF_ERROR_NO_RESOURCES:
6518 			case SCF_ERROR_BACKEND_READONLY:
6519 			case SCF_ERROR_BACKEND_ACCESS:
6520 				r = stash_scferror(lcbdata);
6521 				goto deltemp;
6522 
6523 			case SCF_ERROR_EXISTS:
6524 				warn(gettext("%s changed unexpectedly "
6525 				    "(instance \"%s\" added).\n"),
6526 				    inst->sc_parent->sc_fmri, inst->sc_name);
6527 				lcbdata->sc_err = EBUSY;
6528 				r = UU_WALK_ERROR;
6529 				goto deltemp;
6530 
6531 			case SCF_ERROR_PERMISSION_DENIED:
6532 				warn(gettext("Could not create \"%s\" instance "
6533 				    "in %s (permission denied).\n"),
6534 				    inst->sc_name, inst->sc_parent->sc_fmri);
6535 				r = stash_scferror(lcbdata);
6536 				goto deltemp;
6537 
6538 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6539 			case SCF_ERROR_HANDLE_MISMATCH:
6540 			case SCF_ERROR_NOT_BOUND:
6541 			case SCF_ERROR_NOT_SET:
6542 			default:
6543 				bad_error("scf_service_add_instance",
6544 				    scf_error());
6545 			}
6546 		}
6547 
6548 nosnap:
6549 		/*
6550 		 * Create a last-import snapshot to serve as an attachment
6551 		 * point for the real one from the temporary instance.  Since
6552 		 * the contents is irrelevant, take it now, while the instance
6553 		 * is empty, to minimize svc.configd's work.
6554 		 */
6555 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6556 		    imp_lisnap) != 0) {
6557 			switch (scf_error()) {
6558 			case SCF_ERROR_CONNECTION_BROKEN:
6559 				goto connaborted;
6560 
6561 			case SCF_ERROR_NO_RESOURCES:
6562 				r = stash_scferror(lcbdata);
6563 				goto deltemp;
6564 
6565 			case SCF_ERROR_EXISTS:
6566 				warn(gettext("%s changed unexpectedly "
6567 				    "(snapshot \"%s\" added).\n"),
6568 				    inst->sc_fmri, snap_lastimport);
6569 				lcbdata->sc_err = EBUSY;
6570 				r = UU_WALK_ERROR;
6571 				goto deltemp;
6572 
6573 			case SCF_ERROR_PERMISSION_DENIED:
6574 				warn(gettext("Could not take \"%s\" snapshot "
6575 				    "of %s (permission denied).\n"),
6576 				    snap_lastimport, inst->sc_fmri);
6577 				r = stash_scferror(lcbdata);
6578 				goto deltemp;
6579 
6580 			default:
6581 				scfwarn();
6582 				lcbdata->sc_err = -1;
6583 				r = UU_WALK_ERROR;
6584 				goto deltemp;
6585 
6586 			case SCF_ERROR_NOT_SET:
6587 			case SCF_ERROR_INTERNAL:
6588 			case SCF_ERROR_INVALID_ARGUMENT:
6589 			case SCF_ERROR_HANDLE_MISMATCH:
6590 				bad_error("_scf_snapshot_take_new",
6591 				    scf_error());
6592 			}
6593 		}
6594 
6595 		if (li_only)
6596 			goto lionly;
6597 
6598 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6599 
6600 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6601 		    flags);
6602 		switch (r) {
6603 		case 0:
6604 			break;
6605 
6606 		case ECONNABORTED:
6607 			goto connaborted;
6608 
6609 		case ECANCELED:
6610 			warn(gettext("%s changed unexpectedly "
6611 			    "(instance \"%s\" deleted).\n"),
6612 			    inst->sc_parent->sc_fmri, inst->sc_name);
6613 			lcbdata->sc_err = EBUSY;
6614 			r = UU_WALK_ERROR;
6615 			goto deltemp;
6616 
6617 		case EEXIST:
6618 			warn(gettext("%s changed unexpectedly "
6619 			    "(property group added).\n"), inst->sc_fmri);
6620 			lcbdata->sc_err = EBUSY;
6621 			r = UU_WALK_ERROR;
6622 			goto deltemp;
6623 
6624 		default:
6625 			lcbdata->sc_err = r;
6626 			r = UU_WALK_ERROR;
6627 			goto deltemp;
6628 
6629 		case EINVAL:	/* caught above */
6630 			bad_error("lscf_import_instance_pgs", r);
6631 		}
6632 
6633 		ctx.sc_parent = imp_inst;
6634 		ctx.sc_service = 0;
6635 		ctx.sc_trans = NULL;
6636 		ctx.sc_flags = 0;
6637 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6638 		    &ctx, UU_DEFAULT) != 0) {
6639 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6640 				bad_error("uu_list_walk", uu_error());
6641 
6642 			if (ctx.sc_err == ECONNABORTED)
6643 				goto connaborted;
6644 			lcbdata->sc_err = ctx.sc_err;
6645 			r = UU_WALK_ERROR;
6646 			goto deltemp;
6647 		}
6648 
6649 		inst->sc_import_state = IMPORT_PROP_DONE;
6650 
6651 		if (g_verbose)
6652 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6653 			    snap_initial, inst->sc_fmri);
6654 		r = take_snap(imp_inst, snap_initial, imp_snap);
6655 		switch (r) {
6656 		case 0:
6657 			break;
6658 
6659 		case ECONNABORTED:
6660 			goto connaborted;
6661 
6662 		case ENOSPC:
6663 		case -1:
6664 			lcbdata->sc_err = r;
6665 			r = UU_WALK_ERROR;
6666 			goto deltemp;
6667 
6668 		case ECANCELED:
6669 			warn(gettext("%s changed unexpectedly "
6670 			    "(instance %s deleted).\n"),
6671 			    inst->sc_parent->sc_fmri, inst->sc_name);
6672 			lcbdata->sc_err = r;
6673 			r = UU_WALK_ERROR;
6674 			goto deltemp;
6675 
6676 		case EPERM:
6677 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6678 			lcbdata->sc_err = r;
6679 			r = UU_WALK_ERROR;
6680 			goto deltemp;
6681 
6682 		default:
6683 			bad_error("take_snap", r);
6684 		}
6685 	}
6686 
6687 lionly:
6688 	if (lcbdata->sc_flags & SCI_NOSNAP)
6689 		goto deltemp;
6690 
6691 	/* transfer snapshot from temporary instance */
6692 	if (g_verbose)
6693 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6694 		    snap_lastimport, inst->sc_fmri);
6695 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6696 		switch (scf_error()) {
6697 		case SCF_ERROR_CONNECTION_BROKEN:
6698 			goto connaborted;
6699 
6700 		case SCF_ERROR_NO_RESOURCES:
6701 			r = stash_scferror(lcbdata);
6702 			goto deltemp;
6703 
6704 		case SCF_ERROR_PERMISSION_DENIED:
6705 			warn(gettext("Could not take \"%s\" snapshot for %s "
6706 			    "(permission denied).\n"), snap_lastimport,
6707 			    inst->sc_fmri);
6708 			r = stash_scferror(lcbdata);
6709 			goto deltemp;
6710 
6711 		case SCF_ERROR_NOT_SET:
6712 		case SCF_ERROR_HANDLE_MISMATCH:
6713 		default:
6714 			bad_error("_scf_snapshot_attach", scf_error());
6715 		}
6716 	}
6717 
6718 	inst->sc_import_state = IMPORT_COMPLETE;
6719 
6720 	r = UU_WALK_NEXT;
6721 
6722 deltemp:
6723 	/* delete temporary instance */
6724 	if (scf_instance_delete(imp_tinst) != 0) {
6725 		switch (scf_error()) {
6726 		case SCF_ERROR_DELETED:
6727 			break;
6728 
6729 		case SCF_ERROR_CONNECTION_BROKEN:
6730 			goto connaborted;
6731 
6732 		case SCF_ERROR_NOT_SET:
6733 		case SCF_ERROR_NOT_BOUND:
6734 		default:
6735 			bad_error("scf_instance_delete", scf_error());
6736 		}
6737 	}
6738 
6739 	return (r);
6740 
6741 connaborted:
6742 	warn(gettext("Could not delete svc:/%s:%s "
6743 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6744 	lcbdata->sc_err = ECONNABORTED;
6745 	return (UU_WALK_ERROR);
6746 }
6747 
6748 /*
6749  * If the service is missing, create it, import its properties, and import the
6750  * instances.  Since the service is brand new, it should be empty, and if we
6751  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6752  *
6753  * If the service exists, we want to upgrade its properties and import the
6754  * instances.  Upgrade requires a last-import snapshot, though, which are
6755  * children of instances, so first we'll have to go through the instances
6756  * looking for a last-import snapshot.  If we don't find one then we'll just
6757  * override-import the service properties (but don't delete existing
6758  * properties: another service might have declared us as a dependent).  Before
6759  * we change anything, though, we want to take the previous snapshots.  We
6760  * also give lscf_instance_import() a leg up on taking last-import snapshots
6761  * by importing the manifest's service properties into a temporary service.
6762  *
6763  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6764  * sets lcbdata->sc_err to
6765  *   ECONNABORTED - repository connection broken
6766  *   ENOMEM - out of memory
6767  *   ENOSPC - svc.configd is out of resources
6768  *   EPERM - couldn't create temporary service (error printed)
6769  *	   - couldn't import into temp service (error printed)
6770  *	   - couldn't create service (error printed)
6771  *	   - couldn't import dependent (error printed)
6772  *	   - couldn't take snapshot (error printed)
6773  *	   - couldn't create instance (error printed)
6774  *	   - couldn't create, modify, or delete pg (error printed)
6775  *	   - couldn't create, modify, or delete dependent (error printed)
6776  *	   - couldn't import instance (error printed)
6777  *   EROFS - couldn't create temporary service (repository read-only)
6778  *	   - couldn't import into temporary service (repository read-only)
6779  *	   - couldn't create service (repository read-only)
6780  *	   - couldn't import dependent (repository read-only)
6781  *	   - couldn't create instance (repository read-only)
6782  *	   - couldn't create, modify, or delete pg or dependent
6783  *	   - couldn't import instance (repository read-only)
6784  *   EACCES - couldn't create temporary service (backend access denied)
6785  *	    - couldn't import into temporary service (backend access denied)
6786  *	    - couldn't create service (backend access denied)
6787  *	    - couldn't import dependent (backend access denied)
6788  *	    - couldn't create instance (backend access denied)
6789  *	    - couldn't create, modify, or delete pg or dependent
6790  *	    - couldn't import instance (backend access denied)
6791  *   EINVAL - service name is invalid (error printed)
6792  *	    - service name is too long (error printed)
6793  *	    - s has invalid pgroup (error printed)
6794  *	    - s has invalid dependent (error printed)
6795  *	    - instance name is invalid (error printed)
6796  *	    - instance entity_t is invalid (error printed)
6797  *   EEXIST - couldn't create temporary service (already exists) (error printed)
6798  *	    - couldn't import dependent (dependency pg already exists) (printed)
6799  *	    - dependency collision in dependent service (error printed)
6800  *   EBUSY - temporary service deleted (error printed)
6801  *	   - property group added to temporary service (error printed)
6802  *	   - new property group changed or was deleted (error printed)
6803  *	   - service was added unexpectedly (error printed)
6804  *	   - service was deleted unexpectedly (error printed)
6805  *	   - property group added to new service (error printed)
6806  *	   - instance added unexpectedly (error printed)
6807  *	   - instance deleted unexpectedly (error printed)
6808  *	   - dependent service deleted unexpectedly (error printed)
6809  *	   - pg was added, changed, or deleted (error printed)
6810  *	   - dependent pg changed (error printed)
6811  *	   - temporary instance added, changed, or deleted (error printed)
6812  *   EBADF - a last-import snapshot is corrupt (error printed)
6813  *	   - the service is corrupt (error printed)
6814  *	   - a dependent is corrupt (error printed)
6815  *	   - an instance is corrupt (error printed)
6816  *	   - an instance has a corrupt last-import snapshot (error printed)
6817  *	   - dependent target has a corrupt snapshot (error printed)
6818  *   -1 - unknown libscf error (error printed)
6819  */
6820 static int
6821 lscf_service_import(void *v, void *pvt)
6822 {
6823 	entity_t *s = v;
6824 	scf_callback_t cbdata;
6825 	scf_callback_t *lcbdata = pvt;
6826 	scf_scope_t *scope = lcbdata->sc_parent;
6827 	entity_t *inst, linst;
6828 	int r;
6829 	int fresh = 0;
6830 	scf_snaplevel_t *running;
6831 	int have_ge = 0;
6832 
6833 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
6834 	    "was deleted unexpectedly.\n");
6835 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6836 	    "changed unexpectedly (property group added).\n");
6837 	const char * const s_deleted =
6838 	    gettext("%s was deleted unexpectedly.\n");
6839 	const char * const i_deleted =
6840 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6841 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6842 	    "is corrupt (missing service snaplevel).\n");
6843 	const char * const s_mfile_upd =
6844 	    gettext("Unable to update the manifest file connection "
6845 	    "for %s\n");
6846 
6847 	li_only = 0;
6848 	/* Validate the service name */
6849 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6850 		switch (scf_error()) {
6851 		case SCF_ERROR_CONNECTION_BROKEN:
6852 			return (stash_scferror(lcbdata));
6853 
6854 		case SCF_ERROR_INVALID_ARGUMENT:
6855 			warn(gettext("\"%s\" is an invalid service name.  "
6856 			    "Cannot import.\n"), s->sc_name);
6857 			return (stash_scferror(lcbdata));
6858 
6859 		case SCF_ERROR_NOT_FOUND:
6860 			break;
6861 
6862 		case SCF_ERROR_HANDLE_MISMATCH:
6863 		case SCF_ERROR_NOT_BOUND:
6864 		case SCF_ERROR_NOT_SET:
6865 		default:
6866 			bad_error("scf_scope_get_service", scf_error());
6867 		}
6868 	}
6869 
6870 	/* create temporary service */
6871 	/*
6872 	 * the size of the buffer was reduced to max_scf_name_len to prevent
6873 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6874 	 * should be restored to its original value (max_scf_name_len +1)
6875 	 */
6876 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6877 	if (r < 0)
6878 		bad_error("snprintf", errno);
6879 	if (r > max_scf_name_len) {
6880 		warn(gettext(
6881 		    "Service name \"%s\" is too long.  Cannot import.\n"),
6882 		    s->sc_name);
6883 		lcbdata->sc_err = EINVAL;
6884 		return (UU_WALK_ERROR);
6885 	}
6886 
6887 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6888 		switch (scf_error()) {
6889 		case SCF_ERROR_CONNECTION_BROKEN:
6890 		case SCF_ERROR_NO_RESOURCES:
6891 		case SCF_ERROR_BACKEND_READONLY:
6892 		case SCF_ERROR_BACKEND_ACCESS:
6893 			return (stash_scferror(lcbdata));
6894 
6895 		case SCF_ERROR_EXISTS:
6896 			warn(gettext(
6897 			    "Temporary service \"%s\" must be deleted before "
6898 			    "this manifest can be imported.\n"), imp_tsname);
6899 			return (stash_scferror(lcbdata));
6900 
6901 		case SCF_ERROR_PERMISSION_DENIED:
6902 			warn(gettext("Could not create temporary service "
6903 			    "\"%s\" (permission denied).\n"), imp_tsname);
6904 			return (stash_scferror(lcbdata));
6905 
6906 		case SCF_ERROR_INVALID_ARGUMENT:
6907 		case SCF_ERROR_HANDLE_MISMATCH:
6908 		case SCF_ERROR_NOT_BOUND:
6909 		case SCF_ERROR_NOT_SET:
6910 		default:
6911 			bad_error("scf_scope_add_service", scf_error());
6912 		}
6913 	}
6914 
6915 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6916 	if (r < 0)
6917 		bad_error("snprintf", errno);
6918 
6919 	cbdata.sc_handle = lcbdata->sc_handle;
6920 	cbdata.sc_parent = imp_tsvc;
6921 	cbdata.sc_service = 1;
6922 	cbdata.sc_source_fmri = s->sc_fmri;
6923 	cbdata.sc_target_fmri = imp_str;
6924 	cbdata.sc_flags = 0;
6925 
6926 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6927 	    UU_DEFAULT) != 0) {
6928 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6929 			bad_error("uu_list_walk", uu_error());
6930 
6931 		lcbdata->sc_err = cbdata.sc_err;
6932 		switch (cbdata.sc_err) {
6933 		case ECONNABORTED:
6934 			goto connaborted;
6935 
6936 		case ECANCELED:
6937 			warn(ts_deleted, imp_tsname);
6938 			lcbdata->sc_err = EBUSY;
6939 			return (UU_WALK_ERROR);
6940 
6941 		case EEXIST:
6942 			warn(ts_pg_added, imp_tsname);
6943 			lcbdata->sc_err = EBUSY;
6944 			return (UU_WALK_ERROR);
6945 		}
6946 
6947 		r = UU_WALK_ERROR;
6948 		goto deltemp;
6949 	}
6950 
6951 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6952 	    UU_DEFAULT) != 0) {
6953 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6954 			bad_error("uu_list_walk", uu_error());
6955 
6956 		lcbdata->sc_err = cbdata.sc_err;
6957 		switch (cbdata.sc_err) {
6958 		case ECONNABORTED:
6959 			goto connaborted;
6960 
6961 		case ECANCELED:
6962 			warn(ts_deleted, imp_tsname);
6963 			lcbdata->sc_err = EBUSY;
6964 			return (UU_WALK_ERROR);
6965 
6966 		case EEXIST:
6967 			warn(ts_pg_added, imp_tsname);
6968 			lcbdata->sc_err = EBUSY;
6969 			return (UU_WALK_ERROR);
6970 		}
6971 
6972 		r = UU_WALK_ERROR;
6973 		goto deltemp;
6974 	}
6975 
6976 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6977 		switch (scf_error()) {
6978 		case SCF_ERROR_NOT_FOUND:
6979 			break;
6980 
6981 		case SCF_ERROR_CONNECTION_BROKEN:
6982 			goto connaborted;
6983 
6984 		case SCF_ERROR_INVALID_ARGUMENT:
6985 		case SCF_ERROR_HANDLE_MISMATCH:
6986 		case SCF_ERROR_NOT_BOUND:
6987 		case SCF_ERROR_NOT_SET:
6988 		default:
6989 			bad_error("scf_scope_get_service", scf_error());
6990 		}
6991 
6992 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6993 			switch (scf_error()) {
6994 			case SCF_ERROR_CONNECTION_BROKEN:
6995 				goto connaborted;
6996 
6997 			case SCF_ERROR_NO_RESOURCES:
6998 			case SCF_ERROR_BACKEND_READONLY:
6999 			case SCF_ERROR_BACKEND_ACCESS:
7000 				r = stash_scferror(lcbdata);
7001 				goto deltemp;
7002 
7003 			case SCF_ERROR_EXISTS:
7004 				warn(gettext("Scope \"%s\" changed unexpectedly"
7005 				    " (service \"%s\" added).\n"),
7006 				    SCF_SCOPE_LOCAL, s->sc_name);
7007 				lcbdata->sc_err = EBUSY;
7008 				goto deltemp;
7009 
7010 			case SCF_ERROR_PERMISSION_DENIED:
7011 				warn(gettext("Could not create service \"%s\" "
7012 				    "(permission denied).\n"), s->sc_name);
7013 				goto deltemp;
7014 
7015 			case SCF_ERROR_INVALID_ARGUMENT:
7016 			case SCF_ERROR_HANDLE_MISMATCH:
7017 			case SCF_ERROR_NOT_BOUND:
7018 			case SCF_ERROR_NOT_SET:
7019 			default:
7020 				bad_error("scf_scope_add_service", scf_error());
7021 			}
7022 		}
7023 
7024 		s->sc_import_state = IMPORT_PROP_BEGUN;
7025 
7026 		/* import service properties */
7027 		cbdata.sc_handle = lcbdata->sc_handle;
7028 		cbdata.sc_parent = imp_svc;
7029 		cbdata.sc_service = 1;
7030 		cbdata.sc_flags = lcbdata->sc_flags;
7031 		cbdata.sc_source_fmri = s->sc_fmri;
7032 		cbdata.sc_target_fmri = s->sc_fmri;
7033 
7034 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7035 		    &cbdata, UU_DEFAULT) != 0) {
7036 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7037 				bad_error("uu_list_walk", uu_error());
7038 
7039 			lcbdata->sc_err = cbdata.sc_err;
7040 			switch (cbdata.sc_err) {
7041 			case ECONNABORTED:
7042 				goto connaborted;
7043 
7044 			case ECANCELED:
7045 				warn(s_deleted, s->sc_fmri);
7046 				lcbdata->sc_err = EBUSY;
7047 				return (UU_WALK_ERROR);
7048 
7049 			case EEXIST:
7050 				warn(gettext("%s changed unexpectedly "
7051 				    "(property group added).\n"), s->sc_fmri);
7052 				lcbdata->sc_err = EBUSY;
7053 				return (UU_WALK_ERROR);
7054 
7055 			case EINVAL:
7056 				/* caught above */
7057 				bad_error("entity_pgroup_import",
7058 				    cbdata.sc_err);
7059 			}
7060 
7061 			r = UU_WALK_ERROR;
7062 			goto deltemp;
7063 		}
7064 
7065 		cbdata.sc_trans = NULL;
7066 		cbdata.sc_flags = 0;
7067 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7068 		    &cbdata, UU_DEFAULT) != 0) {
7069 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7070 				bad_error("uu_list_walk", uu_error());
7071 
7072 			lcbdata->sc_err = cbdata.sc_err;
7073 			if (cbdata.sc_err == ECONNABORTED)
7074 				goto connaborted;
7075 			r = UU_WALK_ERROR;
7076 			goto deltemp;
7077 		}
7078 
7079 		s->sc_import_state = IMPORT_PROP_DONE;
7080 
7081 		/*
7082 		 * This is a new service, so we can't take previous snapshots
7083 		 * or upgrade service properties.
7084 		 */
7085 		fresh = 1;
7086 		goto instances;
7087 	}
7088 
7089 	/* Clear sc_seen for the instances. */
7090 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7091 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7092 		bad_error("uu_list_walk", uu_error());
7093 
7094 	/*
7095 	 * Take previous snapshots for all instances.  Even for ones not
7096 	 * mentioned in the bundle, since we might change their service
7097 	 * properties.
7098 	 */
7099 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7100 		switch (scf_error()) {
7101 		case SCF_ERROR_CONNECTION_BROKEN:
7102 			goto connaborted;
7103 
7104 		case SCF_ERROR_DELETED:
7105 			warn(s_deleted, s->sc_fmri);
7106 			lcbdata->sc_err = EBUSY;
7107 			r = UU_WALK_ERROR;
7108 			goto deltemp;
7109 
7110 		case SCF_ERROR_HANDLE_MISMATCH:
7111 		case SCF_ERROR_NOT_BOUND:
7112 		case SCF_ERROR_NOT_SET:
7113 		default:
7114 			bad_error("scf_iter_service_instances", scf_error());
7115 		}
7116 	}
7117 
7118 	for (;;) {
7119 		r = scf_iter_next_instance(imp_iter, imp_inst);
7120 		if (r == 0)
7121 			break;
7122 		if (r != 1) {
7123 			switch (scf_error()) {
7124 			case SCF_ERROR_DELETED:
7125 				warn(s_deleted, s->sc_fmri);
7126 				lcbdata->sc_err = EBUSY;
7127 				r = UU_WALK_ERROR;
7128 				goto deltemp;
7129 
7130 			case SCF_ERROR_CONNECTION_BROKEN:
7131 				goto connaborted;
7132 
7133 			case SCF_ERROR_NOT_BOUND:
7134 			case SCF_ERROR_HANDLE_MISMATCH:
7135 			case SCF_ERROR_INVALID_ARGUMENT:
7136 			case SCF_ERROR_NOT_SET:
7137 			default:
7138 				bad_error("scf_iter_next_instance",
7139 				    scf_error());
7140 			}
7141 		}
7142 
7143 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7144 			switch (scf_error()) {
7145 			case SCF_ERROR_DELETED:
7146 				continue;
7147 
7148 			case SCF_ERROR_CONNECTION_BROKEN:
7149 				goto connaborted;
7150 
7151 			case SCF_ERROR_NOT_SET:
7152 			case SCF_ERROR_NOT_BOUND:
7153 			default:
7154 				bad_error("scf_instance_get_name", scf_error());
7155 			}
7156 		}
7157 
7158 		if (g_verbose)
7159 			warn(gettext(
7160 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7161 			    snap_previous, s->sc_name, imp_str);
7162 
7163 		r = take_snap(imp_inst, snap_previous, imp_snap);
7164 		switch (r) {
7165 		case 0:
7166 			break;
7167 
7168 		case ECANCELED:
7169 			continue;
7170 
7171 		case ECONNABORTED:
7172 			goto connaborted;
7173 
7174 		case EPERM:
7175 			warn(gettext("Could not take \"%s\" snapshot of "
7176 			    "svc:/%s:%s (permission denied).\n"),
7177 			    snap_previous, s->sc_name, imp_str);
7178 			lcbdata->sc_err = r;
7179 			return (UU_WALK_ERROR);
7180 
7181 		case ENOSPC:
7182 		case -1:
7183 			lcbdata->sc_err = r;
7184 			r = UU_WALK_ERROR;
7185 			goto deltemp;
7186 
7187 		default:
7188 			bad_error("take_snap", r);
7189 		}
7190 
7191 		linst.sc_name = imp_str;
7192 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7193 		    &linst, NULL, NULL);
7194 		if (inst != NULL) {
7195 			inst->sc_import_state = IMPORT_PREVIOUS;
7196 			inst->sc_seen = 1;
7197 		}
7198 	}
7199 
7200 	/*
7201 	 * Create the new instances and take previous snapshots of
7202 	 * them.  This is not necessary, but it maximizes data preservation.
7203 	 */
7204 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7205 	    inst != NULL;
7206 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7207 	    inst)) {
7208 		if (inst->sc_seen)
7209 			continue;
7210 
7211 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7212 		    imp_inst) != 0) {
7213 			switch (scf_error()) {
7214 			case SCF_ERROR_CONNECTION_BROKEN:
7215 				goto connaborted;
7216 
7217 			case SCF_ERROR_BACKEND_READONLY:
7218 			case SCF_ERROR_BACKEND_ACCESS:
7219 			case SCF_ERROR_NO_RESOURCES:
7220 				r = stash_scferror(lcbdata);
7221 				goto deltemp;
7222 
7223 			case SCF_ERROR_EXISTS:
7224 				warn(gettext("%s changed unexpectedly "
7225 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7226 				    inst->sc_name);
7227 				lcbdata->sc_err = EBUSY;
7228 				r = UU_WALK_ERROR;
7229 				goto deltemp;
7230 
7231 			case SCF_ERROR_INVALID_ARGUMENT:
7232 				warn(gettext("Service \"%s\" has instance with "
7233 				    "invalid name \"%s\".\n"), s->sc_name,
7234 				    inst->sc_name);
7235 				r = stash_scferror(lcbdata);
7236 				goto deltemp;
7237 
7238 			case SCF_ERROR_PERMISSION_DENIED:
7239 				warn(gettext("Could not create instance \"%s\" "
7240 				    "in %s (permission denied).\n"),
7241 				    inst->sc_name, s->sc_fmri);
7242 				r = stash_scferror(lcbdata);
7243 				goto deltemp;
7244 
7245 			case SCF_ERROR_HANDLE_MISMATCH:
7246 			case SCF_ERROR_NOT_BOUND:
7247 			case SCF_ERROR_NOT_SET:
7248 			default:
7249 				bad_error("scf_service_add_instance",
7250 				    scf_error());
7251 			}
7252 		}
7253 
7254 		if (g_verbose)
7255 			warn(gettext("Taking \"%s\" snapshot for "
7256 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7257 		r = take_snap(imp_inst, snap_previous, imp_snap);
7258 		switch (r) {
7259 		case 0:
7260 			break;
7261 
7262 		case ECANCELED:
7263 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7264 			lcbdata->sc_err = EBUSY;
7265 			r = UU_WALK_ERROR;
7266 			goto deltemp;
7267 
7268 		case ECONNABORTED:
7269 			goto connaborted;
7270 
7271 		case EPERM:
7272 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7273 			lcbdata->sc_err = r;
7274 			r = UU_WALK_ERROR;
7275 			goto deltemp;
7276 
7277 		case ENOSPC:
7278 		case -1:
7279 			r = UU_WALK_ERROR;
7280 			goto deltemp;
7281 
7282 		default:
7283 			bad_error("take_snap", r);
7284 		}
7285 	}
7286 
7287 	s->sc_import_state = IMPORT_PREVIOUS;
7288 
7289 	/*
7290 	 * Upgrade service properties, if we can find a last-import snapshot.
7291 	 * Any will do because we don't support different service properties
7292 	 * in different manifests, so all snaplevels of the service in all of
7293 	 * the last-import snapshots of the instances should be the same.
7294 	 */
7295 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7296 		switch (scf_error()) {
7297 		case SCF_ERROR_CONNECTION_BROKEN:
7298 			goto connaborted;
7299 
7300 		case SCF_ERROR_DELETED:
7301 			warn(s_deleted, s->sc_fmri);
7302 			lcbdata->sc_err = EBUSY;
7303 			r = UU_WALK_ERROR;
7304 			goto deltemp;
7305 
7306 		case SCF_ERROR_HANDLE_MISMATCH:
7307 		case SCF_ERROR_NOT_BOUND:
7308 		case SCF_ERROR_NOT_SET:
7309 		default:
7310 			bad_error("scf_iter_service_instances", scf_error());
7311 		}
7312 	}
7313 
7314 	for (;;) {
7315 		r = scf_iter_next_instance(imp_iter, imp_inst);
7316 		if (r == -1) {
7317 			switch (scf_error()) {
7318 			case SCF_ERROR_DELETED:
7319 				warn(s_deleted, s->sc_fmri);
7320 				lcbdata->sc_err = EBUSY;
7321 				r = UU_WALK_ERROR;
7322 				goto deltemp;
7323 
7324 			case SCF_ERROR_CONNECTION_BROKEN:
7325 				goto connaborted;
7326 
7327 			case SCF_ERROR_NOT_BOUND:
7328 			case SCF_ERROR_HANDLE_MISMATCH:
7329 			case SCF_ERROR_INVALID_ARGUMENT:
7330 			case SCF_ERROR_NOT_SET:
7331 			default:
7332 				bad_error("scf_iter_next_instance",
7333 				    scf_error());
7334 			}
7335 		}
7336 
7337 		if (r == 0) {
7338 			/*
7339 			 * Didn't find any last-import snapshots.  Override-
7340 			 * import the properties.  Unless one of the instances
7341 			 * has a general/enabled property, in which case we're
7342 			 * probably running a last-import-capable svccfg for
7343 			 * the first time, and we should only take the
7344 			 * last-import snapshot.
7345 			 */
7346 			if (have_ge) {
7347 				pgroup_t *mfpg;
7348 				scf_callback_t mfcbdata;
7349 
7350 				li_only = 1;
7351 				no_refresh = 1;
7352 				/*
7353 				 * Need to go ahead and import the manifestfiles
7354 				 * pg if it exists. If the last-import snapshot
7355 				 * upgrade code is ever removed this code can
7356 				 * be removed as well.
7357 				 */
7358 				mfpg = internal_pgroup_find(s,
7359 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7360 
7361 				if (mfpg) {
7362 					mfcbdata.sc_handle = g_hndl;
7363 					mfcbdata.sc_parent = imp_svc;
7364 					mfcbdata.sc_service = 1;
7365 					mfcbdata.sc_flags = SCI_FORCE;
7366 					mfcbdata.sc_source_fmri = s->sc_fmri;
7367 					mfcbdata.sc_target_fmri = s->sc_fmri;
7368 					if (entity_pgroup_import(mfpg,
7369 					    &mfcbdata) != UU_WALK_NEXT) {
7370 						warn(s_mfile_upd, s->sc_fmri);
7371 						r = UU_WALK_ERROR;
7372 						goto deltemp;
7373 					}
7374 				}
7375 				break;
7376 			}
7377 
7378 			s->sc_import_state = IMPORT_PROP_BEGUN;
7379 
7380 			cbdata.sc_handle = g_hndl;
7381 			cbdata.sc_parent = imp_svc;
7382 			cbdata.sc_service = 1;
7383 			cbdata.sc_flags = SCI_FORCE;
7384 			cbdata.sc_source_fmri = s->sc_fmri;
7385 			cbdata.sc_target_fmri = s->sc_fmri;
7386 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7387 			    &cbdata, UU_DEFAULT) != 0) {
7388 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7389 					bad_error("uu_list_walk", uu_error());
7390 				lcbdata->sc_err = cbdata.sc_err;
7391 				switch (cbdata.sc_err) {
7392 				case ECONNABORTED:
7393 					goto connaborted;
7394 
7395 				case ECANCELED:
7396 					warn(s_deleted, s->sc_fmri);
7397 					lcbdata->sc_err = EBUSY;
7398 					break;
7399 
7400 				case EINVAL:	/* caught above */
7401 				case EEXIST:
7402 					bad_error("entity_pgroup_import",
7403 					    cbdata.sc_err);
7404 				}
7405 
7406 				r = UU_WALK_ERROR;
7407 				goto deltemp;
7408 			}
7409 
7410 			cbdata.sc_trans = NULL;
7411 			cbdata.sc_flags = 0;
7412 			if (uu_list_walk(s->sc_dependents,
7413 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7414 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7415 					bad_error("uu_list_walk", uu_error());
7416 				lcbdata->sc_err = cbdata.sc_err;
7417 				if (cbdata.sc_err == ECONNABORTED)
7418 					goto connaborted;
7419 				r = UU_WALK_ERROR;
7420 				goto deltemp;
7421 			}
7422 			break;
7423 		}
7424 
7425 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7426 		    imp_snap) != 0) {
7427 			switch (scf_error()) {
7428 			case SCF_ERROR_DELETED:
7429 				continue;
7430 
7431 			case SCF_ERROR_NOT_FOUND:
7432 				break;
7433 
7434 			case SCF_ERROR_CONNECTION_BROKEN:
7435 				goto connaborted;
7436 
7437 			case SCF_ERROR_HANDLE_MISMATCH:
7438 			case SCF_ERROR_NOT_BOUND:
7439 			case SCF_ERROR_INVALID_ARGUMENT:
7440 			case SCF_ERROR_NOT_SET:
7441 			default:
7442 				bad_error("scf_instance_get_snapshot",
7443 				    scf_error());
7444 			}
7445 
7446 			if (have_ge)
7447 				continue;
7448 
7449 			/*
7450 			 * Check for a general/enabled property.  This is how
7451 			 * we tell whether to import if there turn out to be
7452 			 * no last-import snapshots.
7453 			 */
7454 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7455 			    imp_pg) == 0) {
7456 				if (scf_pg_get_property(imp_pg,
7457 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7458 					have_ge = 1;
7459 				} else {
7460 					switch (scf_error()) {
7461 					case SCF_ERROR_DELETED:
7462 					case SCF_ERROR_NOT_FOUND:
7463 						continue;
7464 
7465 					case SCF_ERROR_INVALID_ARGUMENT:
7466 					case SCF_ERROR_HANDLE_MISMATCH:
7467 					case SCF_ERROR_CONNECTION_BROKEN:
7468 					case SCF_ERROR_NOT_BOUND:
7469 					case SCF_ERROR_NOT_SET:
7470 					default:
7471 						bad_error("scf_pg_get_property",
7472 						    scf_error());
7473 					}
7474 				}
7475 			} else {
7476 				switch (scf_error()) {
7477 				case SCF_ERROR_DELETED:
7478 				case SCF_ERROR_NOT_FOUND:
7479 					continue;
7480 
7481 				case SCF_ERROR_CONNECTION_BROKEN:
7482 					goto connaborted;
7483 
7484 				case SCF_ERROR_NOT_BOUND:
7485 				case SCF_ERROR_NOT_SET:
7486 				case SCF_ERROR_INVALID_ARGUMENT:
7487 				case SCF_ERROR_HANDLE_MISMATCH:
7488 				default:
7489 					bad_error("scf_instance_get_pg",
7490 					    scf_error());
7491 				}
7492 			}
7493 			continue;
7494 		}
7495 
7496 		/* find service snaplevel */
7497 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7498 		switch (r) {
7499 		case 0:
7500 			break;
7501 
7502 		case ECONNABORTED:
7503 			goto connaborted;
7504 
7505 		case ECANCELED:
7506 			continue;
7507 
7508 		case ENOENT:
7509 			if (scf_instance_get_name(imp_inst, imp_str,
7510 			    imp_str_sz) < 0)
7511 				(void) strcpy(imp_str, "?");
7512 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7513 			lcbdata->sc_err = EBADF;
7514 			r = UU_WALK_ERROR;
7515 			goto deltemp;
7516 
7517 		default:
7518 			bad_error("get_snaplevel", r);
7519 		}
7520 
7521 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7522 		    imp_rsnap) != 0) {
7523 			switch (scf_error()) {
7524 			case SCF_ERROR_DELETED:
7525 				continue;
7526 
7527 			case SCF_ERROR_NOT_FOUND:
7528 				break;
7529 
7530 			case SCF_ERROR_CONNECTION_BROKEN:
7531 				goto connaborted;
7532 
7533 			case SCF_ERROR_INVALID_ARGUMENT:
7534 			case SCF_ERROR_HANDLE_MISMATCH:
7535 			case SCF_ERROR_NOT_BOUND:
7536 			case SCF_ERROR_NOT_SET:
7537 			default:
7538 				bad_error("scf_instance_get_snapshot",
7539 				    scf_error());
7540 			}
7541 			running = NULL;
7542 		} else {
7543 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7544 			switch (r) {
7545 			case 0:
7546 				running = imp_rsnpl;
7547 				break;
7548 
7549 			case ECONNABORTED:
7550 				goto connaborted;
7551 
7552 			case ECANCELED:
7553 				continue;
7554 
7555 			case ENOENT:
7556 				if (scf_instance_get_name(imp_inst, imp_str,
7557 				    imp_str_sz) < 0)
7558 					(void) strcpy(imp_str, "?");
7559 				warn(badsnap, snap_running, s->sc_name,
7560 				    imp_str);
7561 				lcbdata->sc_err = EBADF;
7562 				r = UU_WALK_ERROR;
7563 				goto deltemp;
7564 
7565 			default:
7566 				bad_error("get_snaplevel", r);
7567 			}
7568 		}
7569 
7570 		if (g_verbose) {
7571 			if (scf_instance_get_name(imp_inst, imp_str,
7572 			    imp_str_sz) < 0)
7573 				(void) strcpy(imp_str, "?");
7574 			warn(gettext("Upgrading properties of %s according to "
7575 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7576 		}
7577 
7578 		/* upgrade service properties */
7579 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7580 		if (r == 0)
7581 			break;
7582 
7583 		switch (r) {
7584 		case ECONNABORTED:
7585 			goto connaborted;
7586 
7587 		case ECANCELED:
7588 			warn(s_deleted, s->sc_fmri);
7589 			lcbdata->sc_err = EBUSY;
7590 			break;
7591 
7592 		case ENODEV:
7593 			if (scf_instance_get_name(imp_inst, imp_str,
7594 			    imp_str_sz) < 0)
7595 				(void) strcpy(imp_str, "?");
7596 			warn(i_deleted, s->sc_fmri, imp_str);
7597 			lcbdata->sc_err = EBUSY;
7598 			break;
7599 
7600 		default:
7601 			lcbdata->sc_err = r;
7602 		}
7603 
7604 		r = UU_WALK_ERROR;
7605 		goto deltemp;
7606 	}
7607 
7608 	s->sc_import_state = IMPORT_PROP_DONE;
7609 
7610 instances:
7611 	/* import instances */
7612 	cbdata.sc_handle = lcbdata->sc_handle;
7613 	cbdata.sc_parent = imp_svc;
7614 	cbdata.sc_service = 1;
7615 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7616 	cbdata.sc_general = NULL;
7617 
7618 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7619 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7620 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7621 			bad_error("uu_list_walk", uu_error());
7622 
7623 		lcbdata->sc_err = cbdata.sc_err;
7624 		if (cbdata.sc_err == ECONNABORTED)
7625 			goto connaborted;
7626 		r = UU_WALK_ERROR;
7627 		goto deltemp;
7628 	}
7629 
7630 	s->sc_import_state = IMPORT_COMPLETE;
7631 	r = UU_WALK_NEXT;
7632 
7633 deltemp:
7634 	/* delete temporary service */
7635 	if (scf_service_delete(imp_tsvc) != 0) {
7636 		switch (scf_error()) {
7637 		case SCF_ERROR_DELETED:
7638 			break;
7639 
7640 		case SCF_ERROR_CONNECTION_BROKEN:
7641 			goto connaborted;
7642 
7643 		case SCF_ERROR_EXISTS:
7644 			warn(gettext(
7645 			    "Could not delete svc:/%s (instances exist).\n"),
7646 			    imp_tsname);
7647 			break;
7648 
7649 		case SCF_ERROR_NOT_SET:
7650 		case SCF_ERROR_NOT_BOUND:
7651 		default:
7652 			bad_error("scf_service_delete", scf_error());
7653 		}
7654 	}
7655 
7656 	return (r);
7657 
7658 connaborted:
7659 	warn(gettext("Could not delete svc:/%s "
7660 	    "(repository connection broken).\n"), imp_tsname);
7661 	lcbdata->sc_err = ECONNABORTED;
7662 	return (UU_WALK_ERROR);
7663 }
7664 
7665 static const char *
7666 import_progress(int st)
7667 {
7668 	switch (st) {
7669 	case 0:
7670 		return (gettext("not reached."));
7671 
7672 	case IMPORT_PREVIOUS:
7673 		return (gettext("previous snapshot taken."));
7674 
7675 	case IMPORT_PROP_BEGUN:
7676 		return (gettext("some properties imported."));
7677 
7678 	case IMPORT_PROP_DONE:
7679 		return (gettext("properties imported."));
7680 
7681 	case IMPORT_COMPLETE:
7682 		return (gettext("imported."));
7683 
7684 	case IMPORT_REFRESHED:
7685 		return (gettext("refresh requested."));
7686 
7687 	default:
7688 #ifndef NDEBUG
7689 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7690 		    __FILE__, __LINE__, st);
7691 #endif
7692 		abort();
7693 		/* NOTREACHED */
7694 	}
7695 }
7696 
7697 /*
7698  * Returns
7699  *   0 - success
7700  *     - fmri wasn't found (error printed)
7701  *     - entity was deleted (error printed)
7702  *     - backend denied access (error printed)
7703  *   ENOMEM - out of memory (error printed)
7704  *   ECONNABORTED - repository connection broken (error printed)
7705  *   EPERM - permission denied (error printed)
7706  *   -1 - unknown libscf error (error printed)
7707  */
7708 static int
7709 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7710 {
7711 	scf_error_t serr;
7712 	void *ent;
7713 	int issvc;
7714 	int r;
7715 
7716 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7717 	const char *dpt_deleted = gettext("Could not refresh %s "
7718 	    "(dependent \"%s\" of %s) (deleted).\n");
7719 
7720 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7721 	switch (serr) {
7722 	case SCF_ERROR_NONE:
7723 		break;
7724 
7725 	case SCF_ERROR_NO_MEMORY:
7726 		if (name == NULL)
7727 			warn(gettext("Could not refresh %s (out of memory).\n"),
7728 			    fmri);
7729 		else
7730 			warn(gettext("Could not refresh %s "
7731 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7732 			    fmri, name, d_fmri);
7733 		return (ENOMEM);
7734 
7735 	case SCF_ERROR_NOT_FOUND:
7736 		if (name == NULL)
7737 			warn(deleted, fmri);
7738 		else
7739 			warn(dpt_deleted, fmri, name, d_fmri);
7740 		return (0);
7741 
7742 	case SCF_ERROR_INVALID_ARGUMENT:
7743 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7744 	default:
7745 		bad_error("fmri_to_entity", serr);
7746 	}
7747 
7748 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7749 	switch (r) {
7750 	case 0:
7751 		break;
7752 
7753 	case ECONNABORTED:
7754 		if (name != NULL)
7755 			warn(gettext("Could not refresh %s "
7756 			    "(dependent \"%s\" of %s) "
7757 			    "(repository connection broken).\n"), fmri, name,
7758 			    d_fmri);
7759 		return (r);
7760 
7761 	case ECANCELED:
7762 		if (name == NULL)
7763 			warn(deleted, fmri);
7764 		else
7765 			warn(dpt_deleted, fmri, name, d_fmri);
7766 		return (0);
7767 
7768 	case EACCES:
7769 		if (!g_verbose)
7770 			return (0);
7771 		if (name == NULL)
7772 			warn(gettext("Could not refresh %s "
7773 			    "(backend access denied).\n"), fmri);
7774 		else
7775 			warn(gettext("Could not refresh %s "
7776 			    "(dependent \"%s\" of %s) "
7777 			    "(backend access denied).\n"), fmri, name, d_fmri);
7778 		return (0);
7779 
7780 	case EPERM:
7781 		if (name == NULL)
7782 			warn(gettext("Could not refresh %s "
7783 			    "(permission denied).\n"), fmri);
7784 		else
7785 			warn(gettext("Could not refresh %s "
7786 			    "(dependent \"%s\" of %s) "
7787 			    "(permission denied).\n"), fmri, name, d_fmri);
7788 		return (r);
7789 
7790 	case ENOSPC:
7791 		if (name == NULL)
7792 			warn(gettext("Could not refresh %s "
7793 			    "(repository server out of resources).\n"),
7794 			    fmri);
7795 		else
7796 			warn(gettext("Could not refresh %s "
7797 			    "(dependent \"%s\" of %s) "
7798 			    "(repository server out of resources).\n"),
7799 			    fmri, name, d_fmri);
7800 		return (r);
7801 
7802 	case -1:
7803 		scfwarn();
7804 		return (r);
7805 
7806 	default:
7807 		bad_error("refresh_entity", r);
7808 	}
7809 
7810 	if (issvc)
7811 		scf_service_destroy(ent);
7812 	else
7813 		scf_instance_destroy(ent);
7814 
7815 	return (0);
7816 }
7817 
7818 static int
7819 alloc_imp_globals()
7820 {
7821 	int r;
7822 
7823 	const char * const emsg_nomem = gettext("Out of memory.\n");
7824 	const char * const emsg_nores =
7825 	    gettext("svc.configd is out of resources.\n");
7826 
7827 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7828 	    max_scf_name_len : max_scf_fmri_len) + 1;
7829 
7830 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7831 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
7832 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7833 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7834 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7835 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7836 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7837 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7838 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7839 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7840 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7841 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7842 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7843 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7844 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7845 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7846 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7847 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7848 	    (imp_str = malloc(imp_str_sz)) == NULL ||
7849 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7850 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7851 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7852 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7853 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7854 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7855 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7856 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7857 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7858 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7859 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7860 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7861 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7862 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7863 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7864 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7865 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7866 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7867 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7868 			warn(emsg_nores);
7869 		else
7870 			warn(emsg_nomem);
7871 
7872 		return (-1);
7873 	}
7874 
7875 	r = load_init();
7876 	switch (r) {
7877 	case 0:
7878 		break;
7879 
7880 	case ENOMEM:
7881 		warn(emsg_nomem);
7882 		return (-1);
7883 
7884 	default:
7885 		bad_error("load_init", r);
7886 	}
7887 
7888 	return (0);
7889 }
7890 
7891 static void
7892 free_imp_globals()
7893 {
7894 	pgroup_t *old_dpt;
7895 	void *cookie;
7896 
7897 	load_fini();
7898 
7899 	free(ud_ctarg);
7900 	free(ud_oldtarg);
7901 	free(ud_name);
7902 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7903 
7904 	scf_transaction_destroy(ud_tx);
7905 	ud_tx = NULL;
7906 	scf_iter_destroy(ud_iter);
7907 	scf_iter_destroy(ud_iter2);
7908 	ud_iter = ud_iter2 = NULL;
7909 	scf_value_destroy(ud_val);
7910 	ud_val = NULL;
7911 	scf_property_destroy(ud_prop);
7912 	scf_property_destroy(ud_dpt_prop);
7913 	ud_prop = ud_dpt_prop = NULL;
7914 	scf_pg_destroy(ud_pg);
7915 	scf_pg_destroy(ud_cur_depts_pg);
7916 	scf_pg_destroy(ud_run_dpts_pg);
7917 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7918 	scf_snaplevel_destroy(ud_snpl);
7919 	ud_snpl = NULL;
7920 	scf_instance_destroy(ud_inst);
7921 	ud_inst = NULL;
7922 
7923 	free(imp_str);
7924 	free(imp_tsname);
7925 	free(imp_fe1);
7926 	free(imp_fe2);
7927 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7928 
7929 	cookie = NULL;
7930 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7931 	    NULL) {
7932 		free((char *)old_dpt->sc_pgroup_name);
7933 		free((char *)old_dpt->sc_pgroup_fmri);
7934 		internal_pgroup_free(old_dpt);
7935 	}
7936 	uu_list_destroy(imp_deleted_dpts);
7937 
7938 	scf_transaction_destroy(imp_tx);
7939 	imp_tx = NULL;
7940 	scf_iter_destroy(imp_iter);
7941 	scf_iter_destroy(imp_rpg_iter);
7942 	scf_iter_destroy(imp_up_iter);
7943 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7944 	scf_property_destroy(imp_prop);
7945 	imp_prop = NULL;
7946 	scf_pg_destroy(imp_pg);
7947 	scf_pg_destroy(imp_pg2);
7948 	imp_pg = imp_pg2 = NULL;
7949 	scf_snaplevel_destroy(imp_snpl);
7950 	scf_snaplevel_destroy(imp_rsnpl);
7951 	imp_snpl = imp_rsnpl = NULL;
7952 	scf_snapshot_destroy(imp_snap);
7953 	scf_snapshot_destroy(imp_lisnap);
7954 	scf_snapshot_destroy(imp_tlisnap);
7955 	scf_snapshot_destroy(imp_rsnap);
7956 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7957 	scf_instance_destroy(imp_inst);
7958 	scf_instance_destroy(imp_tinst);
7959 	imp_inst = imp_tinst = NULL;
7960 	scf_service_destroy(imp_svc);
7961 	scf_service_destroy(imp_tsvc);
7962 	imp_svc = imp_tsvc = NULL;
7963 	scf_scope_destroy(imp_scope);
7964 	imp_scope = NULL;
7965 
7966 	load_fini();
7967 }
7968 
7969 int
7970 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7971 {
7972 	scf_callback_t cbdata;
7973 	int result = 0;
7974 	entity_t *svc, *inst;
7975 	uu_list_t *insts;
7976 	int r;
7977 	pgroup_t *old_dpt;
7978 	int annotation_set = 0;
7979 
7980 	const char * const emsg_nomem = gettext("Out of memory.\n");
7981 	const char * const emsg_nores =
7982 	    gettext("svc.configd is out of resources.\n");
7983 
7984 	lscf_prep_hndl();
7985 
7986 	if (alloc_imp_globals())
7987 		goto out;
7988 
7989 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7990 		switch (scf_error()) {
7991 		case SCF_ERROR_CONNECTION_BROKEN:
7992 			warn(gettext("Repository connection broken.\n"));
7993 			repository_teardown();
7994 			result = -1;
7995 			goto out;
7996 
7997 		case SCF_ERROR_NOT_FOUND:
7998 		case SCF_ERROR_INVALID_ARGUMENT:
7999 		case SCF_ERROR_NOT_BOUND:
8000 		case SCF_ERROR_HANDLE_MISMATCH:
8001 		default:
8002 			bad_error("scf_handle_get_scope", scf_error());
8003 		}
8004 	}
8005 
8006 	/* Set up the auditing annotation. */
8007 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8008 		annotation_set = 1;
8009 	} else {
8010 		switch (scf_error()) {
8011 		case SCF_ERROR_CONNECTION_BROKEN:
8012 			warn(gettext("Repository connection broken.\n"));
8013 			repository_teardown();
8014 			result = -1;
8015 			goto out;
8016 
8017 		case SCF_ERROR_INVALID_ARGUMENT:
8018 		case SCF_ERROR_NOT_BOUND:
8019 		case SCF_ERROR_NO_RESOURCES:
8020 		case SCF_ERROR_INTERNAL:
8021 			bad_error("_scf_set_annotation", scf_error());
8022 			/* NOTREACHED */
8023 
8024 		default:
8025 			/*
8026 			 * Do not terminate import because of inability to
8027 			 * generate annotation audit event.
8028 			 */
8029 			warn(gettext("_scf_set_annotation() unexpectedly "
8030 			    "failed with return code of %d\n"), scf_error());
8031 			break;
8032 		}
8033 	}
8034 
8035 	/*
8036 	 * Clear the sc_import_state's of all services & instances so we can
8037 	 * report how far we got if we fail.
8038 	 */
8039 	for (svc = uu_list_first(bndl->sc_bundle_services);
8040 	    svc != NULL;
8041 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8042 		svc->sc_import_state = 0;
8043 
8044 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8045 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8046 		    UU_DEFAULT) != 0)
8047 			bad_error("uu_list_walk", uu_error());
8048 	}
8049 
8050 	cbdata.sc_handle = g_hndl;
8051 	cbdata.sc_parent = imp_scope;
8052 	cbdata.sc_flags = flags;
8053 	cbdata.sc_general = NULL;
8054 
8055 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8056 	    &cbdata, UU_DEFAULT) == 0) {
8057 		/* Success.  Refresh everything. */
8058 
8059 		if (flags & SCI_NOREFRESH || no_refresh) {
8060 			no_refresh = 0;
8061 			result = 0;
8062 			goto out;
8063 		}
8064 
8065 		for (svc = uu_list_first(bndl->sc_bundle_services);
8066 		    svc != NULL;
8067 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8068 			pgroup_t *dpt;
8069 
8070 			insts = svc->sc_u.sc_service.sc_service_instances;
8071 
8072 			for (inst = uu_list_first(insts);
8073 			    inst != NULL;
8074 			    inst = uu_list_next(insts, inst)) {
8075 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8076 				switch (r) {
8077 				case 0:
8078 					break;
8079 
8080 				case ENOMEM:
8081 				case ECONNABORTED:
8082 				case EPERM:
8083 				case -1:
8084 					goto progress;
8085 
8086 				default:
8087 					bad_error("imp_refresh_fmri", r);
8088 				}
8089 
8090 				inst->sc_import_state = IMPORT_REFRESHED;
8091 
8092 				for (dpt = uu_list_first(inst->sc_dependents);
8093 				    dpt != NULL;
8094 				    dpt = uu_list_next(inst->sc_dependents,
8095 				    dpt))
8096 					if (imp_refresh_fmri(
8097 					    dpt->sc_pgroup_fmri,
8098 					    dpt->sc_pgroup_name,
8099 					    inst->sc_fmri) != 0)
8100 						goto progress;
8101 			}
8102 
8103 			for (dpt = uu_list_first(svc->sc_dependents);
8104 			    dpt != NULL;
8105 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8106 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8107 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8108 					goto progress;
8109 		}
8110 
8111 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8112 		    old_dpt != NULL;
8113 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8114 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8115 			    old_dpt->sc_pgroup_name,
8116 			    old_dpt->sc_parent->sc_fmri) != 0)
8117 				goto progress;
8118 
8119 		result = 0;
8120 		goto out;
8121 	}
8122 
8123 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8124 		bad_error("uu_list_walk", uu_error());
8125 
8126 printerr:
8127 	/* If the error hasn't been printed yet, do so here. */
8128 	switch (cbdata.sc_err) {
8129 	case ECONNABORTED:
8130 		warn(gettext("Repository connection broken.\n"));
8131 		break;
8132 
8133 	case ENOMEM:
8134 		warn(emsg_nomem);
8135 		break;
8136 
8137 	case ENOSPC:
8138 		warn(emsg_nores);
8139 		break;
8140 
8141 	case EROFS:
8142 		warn(gettext("Repository is read-only.\n"));
8143 		break;
8144 
8145 	case EACCES:
8146 		warn(gettext("Repository backend denied access.\n"));
8147 		break;
8148 
8149 	case EPERM:
8150 	case EINVAL:
8151 	case EEXIST:
8152 	case EBUSY:
8153 	case EBADF:
8154 	case -1:
8155 		break;
8156 
8157 	default:
8158 		bad_error("lscf_service_import", cbdata.sc_err);
8159 	}
8160 
8161 progress:
8162 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8163 
8164 	for (svc = uu_list_first(bndl->sc_bundle_services);
8165 	    svc != NULL;
8166 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8167 		insts = svc->sc_u.sc_service.sc_service_instances;
8168 
8169 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8170 		    import_progress(svc->sc_import_state));
8171 
8172 		for (inst = uu_list_first(insts);
8173 		    inst != NULL;
8174 		    inst = uu_list_next(insts, inst))
8175 			warn(gettext("    Instance \"%s\": %s\n"),
8176 			    inst->sc_name,
8177 			    import_progress(inst->sc_import_state));
8178 	}
8179 
8180 	if (cbdata.sc_err == ECONNABORTED)
8181 		repository_teardown();
8182 
8183 
8184 	result = -1;
8185 
8186 out:
8187 	if (annotation_set != 0) {
8188 		/* Turn off annotation.  It is no longer needed. */
8189 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8190 	}
8191 
8192 	free_imp_globals();
8193 
8194 	return (result);
8195 }
8196 
8197 /*
8198  * _lscf_import_err() summarize the error handling returned by
8199  * lscf_import_{instance | service}_pgs
8200  * Return values are:
8201  * IMPORT_NEXT
8202  * IMPORT_OUT
8203  * IMPORT_BAD
8204  */
8205 
8206 #define	IMPORT_BAD	-1
8207 #define	IMPORT_NEXT	0
8208 #define	IMPORT_OUT	1
8209 
8210 static int
8211 _lscf_import_err(int err, const char *fmri)
8212 {
8213 	switch (err) {
8214 	case 0:
8215 		if (g_verbose)
8216 			warn(gettext("%s updated.\n"), fmri);
8217 		return (IMPORT_NEXT);
8218 
8219 	case ECONNABORTED:
8220 		warn(gettext("Could not update %s "
8221 		    "(repository connection broken).\n"), fmri);
8222 		return (IMPORT_OUT);
8223 
8224 	case ENOMEM:
8225 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8226 		return (IMPORT_OUT);
8227 
8228 	case ENOSPC:
8229 		warn(gettext("Could not update %s "
8230 		    "(repository server out of resources).\n"), fmri);
8231 		return (IMPORT_OUT);
8232 
8233 	case ECANCELED:
8234 		warn(gettext(
8235 		    "Could not update %s (deleted).\n"), fmri);
8236 		return (IMPORT_NEXT);
8237 
8238 	case EPERM:
8239 	case EINVAL:
8240 	case EBUSY:
8241 		return (IMPORT_NEXT);
8242 
8243 	case EROFS:
8244 		warn(gettext("Could not update %s (repository read-only).\n"),
8245 		    fmri);
8246 		return (IMPORT_OUT);
8247 
8248 	case EACCES:
8249 		warn(gettext("Could not update %s "
8250 		    "(backend access denied).\n"), fmri);
8251 		return (IMPORT_NEXT);
8252 
8253 	case EEXIST:
8254 	default:
8255 		return (IMPORT_BAD);
8256 	}
8257 
8258 	/*NOTREACHED*/
8259 }
8260 
8261 /*
8262  * The global imp_svc and imp_inst should be set by the caller in the
8263  * check to make sure the service and instance exist that the apply is
8264  * working on.
8265  */
8266 static int
8267 lscf_dependent_apply(void *dpg, void *e)
8268 {
8269 	scf_callback_t cb;
8270 	pgroup_t *dpt_pgroup = dpg;
8271 	pgroup_t *deldpt;
8272 	entity_t *ent = e;
8273 	int tissvc;
8274 	void *sc_ent, *tent;
8275 	scf_error_t serr;
8276 	int r;
8277 
8278 	const char * const dependents = "dependents";
8279 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8280 
8281 	if (issvc)
8282 		sc_ent = imp_svc;
8283 	else
8284 		sc_ent = imp_inst;
8285 
8286 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8287 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8288 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8289 	    imp_prop) != 0) {
8290 		switch (scf_error()) {
8291 		case SCF_ERROR_NOT_FOUND:
8292 		case SCF_ERROR_DELETED:
8293 			break;
8294 
8295 		case SCF_ERROR_CONNECTION_BROKEN:
8296 		case SCF_ERROR_NOT_SET:
8297 		case SCF_ERROR_INVALID_ARGUMENT:
8298 		case SCF_ERROR_HANDLE_MISMATCH:
8299 		case SCF_ERROR_NOT_BOUND:
8300 		default:
8301 			bad_error("entity_get_pg", scf_error());
8302 		}
8303 	} else {
8304 		/*
8305 		 * Found the dependents/<wip dep> so check to
8306 		 * see if the service is different.  If so
8307 		 * store the service for later refresh, and
8308 		 * delete the wip dependency from the service
8309 		 */
8310 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8311 			switch (scf_error()) {
8312 				case SCF_ERROR_DELETED:
8313 					break;
8314 
8315 				case SCF_ERROR_CONNECTION_BROKEN:
8316 				case SCF_ERROR_NOT_SET:
8317 				case SCF_ERROR_INVALID_ARGUMENT:
8318 				case SCF_ERROR_HANDLE_MISMATCH:
8319 				case SCF_ERROR_NOT_BOUND:
8320 				default:
8321 					bad_error("scf_property_get_value",
8322 					    scf_error());
8323 			}
8324 		}
8325 
8326 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8327 		    max_scf_value_len + 1) < 0)
8328 			bad_error("scf_value_get_as_string", scf_error());
8329 
8330 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8331 		switch (r) {
8332 		case 1:
8333 			break;
8334 		case 0:
8335 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8336 			    &tissvc)) != SCF_ERROR_NONE) {
8337 				if (serr == SCF_ERROR_NOT_FOUND) {
8338 					break;
8339 				} else {
8340 					bad_error("fmri_to_entity", serr);
8341 				}
8342 			}
8343 
8344 			if (entity_get_pg(tent, tissvc,
8345 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8346 				serr = scf_error();
8347 				if (serr == SCF_ERROR_NOT_FOUND ||
8348 				    serr == SCF_ERROR_DELETED) {
8349 					break;
8350 				} else {
8351 					bad_error("entity_get_pg", scf_error());
8352 				}
8353 			}
8354 
8355 			if (scf_pg_delete(imp_pg) != 0) {
8356 				serr = scf_error();
8357 				if (serr == SCF_ERROR_NOT_FOUND ||
8358 				    serr == SCF_ERROR_DELETED) {
8359 					break;
8360 				} else {
8361 					bad_error("scf_pg_delete", scf_error());
8362 				}
8363 			}
8364 
8365 			deldpt = internal_pgroup_new();
8366 			if (deldpt == NULL)
8367 				return (ENOMEM);
8368 			deldpt->sc_pgroup_name =
8369 			    strdup(dpt_pgroup->sc_pgroup_name);
8370 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8371 			if (deldpt->sc_pgroup_name == NULL ||
8372 			    deldpt->sc_pgroup_fmri == NULL)
8373 				return (ENOMEM);
8374 			deldpt->sc_parent = (entity_t *)ent;
8375 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8376 			    deldpt) != 0)
8377 				uu_die(gettext("libuutil error: %s\n"),
8378 				    uu_strerror(uu_error()));
8379 
8380 			break;
8381 		default:
8382 			bad_error("fmri_equal", r);
8383 		}
8384 	}
8385 
8386 	cb.sc_handle = g_hndl;
8387 	cb.sc_parent = ent;
8388 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8389 	cb.sc_source_fmri = ent->sc_fmri;
8390 	cb.sc_target_fmri = ent->sc_fmri;
8391 	cb.sc_trans = NULL;
8392 	cb.sc_flags = SCI_FORCE;
8393 
8394 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8395 		return (UU_WALK_ERROR);
8396 
8397 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8398 	switch (r) {
8399 	case 0:
8400 		break;
8401 
8402 	case ENOMEM:
8403 	case ECONNABORTED:
8404 	case EPERM:
8405 	case -1:
8406 		warn(gettext("Unable to refresh \"%s\"\n"),
8407 		    dpt_pgroup->sc_pgroup_fmri);
8408 		return (UU_WALK_ERROR);
8409 
8410 	default:
8411 		bad_error("imp_refresh_fmri", r);
8412 	}
8413 
8414 	return (UU_WALK_NEXT);
8415 }
8416 
8417 /*
8418  * Returns
8419  *   0 - success
8420  *   -1 - lscf_import_instance_pgs() failed.
8421  */
8422 int
8423 lscf_bundle_apply(bundle_t *bndl, const char *file)
8424 {
8425 	pgroup_t *old_dpt;
8426 	entity_t *svc, *inst;
8427 	int annotation_set = 0;
8428 	int ret = 0;
8429 	int r = 0;
8430 
8431 	lscf_prep_hndl();
8432 
8433 	if ((ret = alloc_imp_globals()))
8434 		goto out;
8435 
8436 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8437 		scfdie();
8438 
8439 	/*
8440 	 * Set the strings to be used for the security audit annotation
8441 	 * event.
8442 	 */
8443 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8444 		annotation_set = 1;
8445 	} else {
8446 		switch (scf_error()) {
8447 		case SCF_ERROR_CONNECTION_BROKEN:
8448 			warn(gettext("Repository connection broken.\n"));
8449 			goto out;
8450 
8451 		case SCF_ERROR_INVALID_ARGUMENT:
8452 		case SCF_ERROR_NOT_BOUND:
8453 		case SCF_ERROR_NO_RESOURCES:
8454 		case SCF_ERROR_INTERNAL:
8455 			bad_error("_scf_set_annotation", scf_error());
8456 			/* NOTREACHED */
8457 
8458 		default:
8459 			/*
8460 			 * Do not abort apply operation because of
8461 			 * inability to create annotation audit event.
8462 			 */
8463 			warn(gettext("_scf_set_annotation() unexpectedly "
8464 			    "failed with return code of %d\n"), scf_error());
8465 			break;
8466 		}
8467 	}
8468 
8469 	for (svc = uu_list_first(bndl->sc_bundle_services);
8470 	    svc != NULL;
8471 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8472 		int refresh = 0;
8473 
8474 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8475 		    imp_svc) != 0) {
8476 			switch (scf_error()) {
8477 			case SCF_ERROR_NOT_FOUND:
8478 				if (g_verbose)
8479 					warn(gettext("Ignoring nonexistent "
8480 					    "service %s.\n"), svc->sc_name);
8481 				continue;
8482 
8483 			default:
8484 				scfdie();
8485 			}
8486 		}
8487 
8488 		/*
8489 		 * If there were missing types in the profile, then need to
8490 		 * attempt to find the types.
8491 		 */
8492 		if (svc->sc_miss_type) {
8493 			if (uu_list_numnodes(svc->sc_pgroups) &&
8494 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8495 			    svc, UU_DEFAULT) != 0) {
8496 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8497 					bad_error("uu_list_walk", uu_error());
8498 
8499 				ret = -1;
8500 				continue;
8501 			}
8502 
8503 			for (inst = uu_list_first(
8504 			    svc->sc_u.sc_service.sc_service_instances);
8505 			    inst != NULL;
8506 			    inst = uu_list_next(
8507 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8508 				/*
8509 				 * If the instance doesn't exist just
8510 				 * skip to the next instance and let the
8511 				 * import note the missing instance.
8512 				 */
8513 				if (scf_service_get_instance(imp_svc,
8514 				    inst->sc_name, imp_inst) != 0)
8515 					continue;
8516 
8517 				if (uu_list_walk(inst->sc_pgroups,
8518 				    find_current_pg_type, inst,
8519 				    UU_DEFAULT) != 0) {
8520 					if (uu_error() !=
8521 					    UU_ERROR_CALLBACK_FAILED)
8522 						bad_error("uu_list_walk",
8523 						    uu_error());
8524 
8525 					ret = -1;
8526 					inst->sc_miss_type = B_TRUE;
8527 				}
8528 			}
8529 		}
8530 
8531 		/*
8532 		 * if we have pgs in the profile, we need to refresh ALL
8533 		 * instances of the service
8534 		 */
8535 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8536 			refresh = 1;
8537 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8538 			    SCI_FORCE | SCI_KEEP);
8539 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8540 			case IMPORT_NEXT:
8541 				break;
8542 
8543 			case IMPORT_OUT:
8544 				goto out;
8545 
8546 			case IMPORT_BAD:
8547 			default:
8548 				bad_error("lscf_import_service_pgs", r);
8549 			}
8550 		}
8551 
8552 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8553 			uu_list_walk(svc->sc_dependents,
8554 			    lscf_dependent_apply, svc, UU_DEFAULT);
8555 		}
8556 
8557 		for (inst = uu_list_first(
8558 		    svc->sc_u.sc_service.sc_service_instances);
8559 		    inst != NULL;
8560 		    inst = uu_list_next(
8561 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8562 			/*
8563 			 * This instance still has missing types
8564 			 * so skip it.
8565 			 */
8566 			if (inst->sc_miss_type) {
8567 				if (g_verbose)
8568 					warn(gettext("Ignoring instance "
8569 					    "%s:%s with missing types\n"),
8570 					    inst->sc_parent->sc_name,
8571 					    inst->sc_name);
8572 
8573 				continue;
8574 			}
8575 
8576 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8577 			    imp_inst) != 0) {
8578 				switch (scf_error()) {
8579 				case SCF_ERROR_NOT_FOUND:
8580 					if (g_verbose)
8581 						warn(gettext("Ignoring "
8582 						    "nonexistant instance "
8583 						    "%s:%s.\n"),
8584 						    inst->sc_parent->sc_name,
8585 						    inst->sc_name);
8586 					continue;
8587 
8588 				default:
8589 					scfdie();
8590 				}
8591 			}
8592 
8593 			/*
8594 			 * If the instance does not have a general/enabled
8595 			 * property and no last-import snapshot then the
8596 			 * instance is not a fully installed instance and
8597 			 * should not have a profile applied to it.
8598 			 *
8599 			 * This could happen if a service/instance declares
8600 			 * a dependent on behalf of another service/instance.
8601 			 *
8602 			 */
8603 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8604 			    imp_snap) != 0) {
8605 				if (scf_instance_get_pg(imp_inst,
8606 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8607 				    scf_pg_get_property(imp_pg,
8608 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8609 					if (g_verbose)
8610 						warn(gettext("Ignoreing "
8611 						    "partial instance "
8612 						    "%s:%s.\n"),
8613 						    inst->sc_parent->sc_name,
8614 						    inst->sc_name);
8615 					continue;
8616 				}
8617 			}
8618 
8619 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8620 			    inst, SCI_FORCE | SCI_KEEP);
8621 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8622 			case IMPORT_NEXT:
8623 				break;
8624 
8625 			case IMPORT_OUT:
8626 				goto out;
8627 
8628 			case IMPORT_BAD:
8629 			default:
8630 				bad_error("lscf_import_instance_pgs", r);
8631 			}
8632 
8633 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8634 				uu_list_walk(inst->sc_dependents,
8635 				    lscf_dependent_apply, inst, UU_DEFAULT);
8636 			}
8637 
8638 			/* refresh only if there is no pgs in the service */
8639 			if (refresh == 0)
8640 				(void) refresh_entity(0, imp_inst,
8641 				    inst->sc_fmri, NULL, NULL, NULL);
8642 		}
8643 
8644 		if (refresh == 1) {
8645 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8646 
8647 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8648 			    imp_inst, imp_iter, name_buf);
8649 			free(name_buf);
8650 		}
8651 
8652 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8653 		    old_dpt != NULL;
8654 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8655 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8656 			    old_dpt->sc_pgroup_name,
8657 			    old_dpt->sc_parent->sc_fmri) != 0) {
8658 				warn(gettext("Unable to refresh \"%s\"\n"),
8659 				    old_dpt->sc_pgroup_fmri);
8660 			}
8661 		}
8662 	}
8663 
8664 out:
8665 	if (annotation_set) {
8666 		/* Remove security audit annotation strings. */
8667 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8668 	}
8669 
8670 	free_imp_globals();
8671 	return (ret);
8672 }
8673 
8674 
8675 /*
8676  * Export.  These functions create and output an XML tree of a service
8677  * description from the repository.  This is largely the inverse of
8678  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8679  *
8680  * - We must include any properties which are not represented specifically by
8681  *   a service manifest, e.g., properties created by an admin post-import.  To
8682  *   do so we'll iterate through all properties and deal with each
8683  *   apropriately.
8684  *
8685  * - Children of services and instances must must be in the order set by the
8686  *   DTD, but we iterate over the properties in undefined order.  The elements
8687  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8688  *   number of classes of them, however, we'll keep the classes separate and
8689  *   assemble them in order.
8690  */
8691 
8692 /*
8693  * Convenience function to handle xmlSetProp errors (and type casting).
8694  */
8695 static void
8696 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8697 {
8698 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8699 		uu_die(gettext("Could not set XML property.\n"));
8700 }
8701 
8702 /*
8703  * Convenience function to set an XML attribute to the single value of an
8704  * astring property.  If the value happens to be the default, don't set the
8705  * attribute.  "dval" should be the default value supplied by the DTD, or
8706  * NULL for no default.
8707  */
8708 static int
8709 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8710     const char *name, const char *dval)
8711 {
8712 	scf_value_t *val;
8713 	ssize_t len;
8714 	char *str;
8715 
8716 	val = scf_value_create(g_hndl);
8717 	if (val == NULL)
8718 		scfdie();
8719 
8720 	if (prop_get_val(prop, val) != 0) {
8721 		scf_value_destroy(val);
8722 		return (-1);
8723 	}
8724 
8725 	len = scf_value_get_as_string(val, NULL, 0);
8726 	if (len < 0)
8727 		scfdie();
8728 
8729 	str = safe_malloc(len + 1);
8730 
8731 	if (scf_value_get_as_string(val, str, len + 1) < 0)
8732 		scfdie();
8733 
8734 	scf_value_destroy(val);
8735 
8736 	if (dval == NULL || strcmp(str, dval) != 0)
8737 		safe_setprop(n, name, str);
8738 
8739 	free(str);
8740 
8741 	return (0);
8742 }
8743 
8744 /*
8745  * As above, but the attribute is always set.
8746  */
8747 static int
8748 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
8749 {
8750 	return (set_attr_from_prop_default(prop, n, name, NULL));
8751 }
8752 
8753 /*
8754  * Dump the given document onto f, with "'s replaced by ''s.
8755  */
8756 static int
8757 write_service_bundle(xmlDocPtr doc, FILE *f)
8758 {
8759 	xmlChar *mem;
8760 	int sz, i;
8761 
8762 	mem = NULL;
8763 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
8764 
8765 	if (mem == NULL) {
8766 		semerr(gettext("Could not dump XML tree.\n"));
8767 		return (-1);
8768 	}
8769 
8770 	/*
8771 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
8772 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
8773 	 * &apos; code?!
8774 	 */
8775 	for (i = 0; i < sz; ++i) {
8776 		char c = (char)mem[i];
8777 
8778 		if (c == '"')
8779 			(void) fputc('\'', f);
8780 		else if (c == '\'')
8781 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
8782 		else
8783 			(void) fputc(c, f);
8784 	}
8785 
8786 	return (0);
8787 }
8788 
8789 /*
8790  * Create the DOM elements in elts necessary to (generically) represent prop
8791  * (i.e., a property or propval element).  If the name of the property is
8792  * known, it should be passed as name_arg.  Otherwise, pass NULL.
8793  */
8794 static void
8795 export_property(scf_property_t *prop, const char *name_arg,
8796     struct pg_elts *elts, int flags)
8797 {
8798 	const char *type;
8799 	scf_error_t err = 0;
8800 	xmlNodePtr pnode, lnode;
8801 	char *lnname;
8802 	int ret;
8803 
8804 	/* name */
8805 	if (name_arg != NULL) {
8806 		(void) strcpy(exp_str, name_arg);
8807 	} else {
8808 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8809 			scfdie();
8810 	}
8811 
8812 	/* type */
8813 	type = prop_to_typestr(prop);
8814 	if (type == NULL)
8815 		uu_die(gettext("Can't export property %s: unknown type.\n"),
8816 		    exp_str);
8817 
8818 	/* If we're exporting values, and there's just one, export it here. */
8819 	if (!(flags & SCE_ALL_VALUES))
8820 		goto empty;
8821 
8822 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8823 		xmlNodePtr n;
8824 
8825 		/* Single value, so use propval */
8826 		n = xmlNewNode(NULL, (xmlChar *)"propval");
8827 		if (n == NULL)
8828 			uu_die(emsg_create_xml);
8829 
8830 		safe_setprop(n, name_attr, exp_str);
8831 		safe_setprop(n, type_attr, type);
8832 
8833 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8834 			scfdie();
8835 		safe_setprop(n, value_attr, exp_str);
8836 
8837 		if (elts->propvals == NULL)
8838 			elts->propvals = n;
8839 		else
8840 			(void) xmlAddSibling(elts->propvals, n);
8841 
8842 		return;
8843 	}
8844 
8845 	err = scf_error();
8846 
8847 	if (err == SCF_ERROR_PERMISSION_DENIED) {
8848 		semerr(emsg_permission_denied);
8849 		return;
8850 	}
8851 
8852 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8853 	    err != SCF_ERROR_NOT_FOUND &&
8854 	    err != SCF_ERROR_PERMISSION_DENIED)
8855 		scfdie();
8856 
8857 empty:
8858 	/* Multiple (or no) values, so use property */
8859 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
8860 	if (pnode == NULL)
8861 		uu_die(emsg_create_xml);
8862 
8863 	safe_setprop(pnode, name_attr, exp_str);
8864 	safe_setprop(pnode, type_attr, type);
8865 
8866 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8867 		lnname = uu_msprintf("%s_list", type);
8868 		if (lnname == NULL)
8869 			uu_die(gettext("Could not create string"));
8870 
8871 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8872 		if (lnode == NULL)
8873 			uu_die(emsg_create_xml);
8874 
8875 		uu_free(lnname);
8876 
8877 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8878 			scfdie();
8879 
8880 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8881 		    1) {
8882 			xmlNodePtr vn;
8883 
8884 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8885 			    NULL);
8886 			if (vn == NULL)
8887 				uu_die(emsg_create_xml);
8888 
8889 			if (scf_value_get_as_string(exp_val, exp_str,
8890 			    exp_str_sz) < 0)
8891 				scfdie();
8892 			safe_setprop(vn, value_attr, exp_str);
8893 		}
8894 		if (ret != 0)
8895 			scfdie();
8896 	}
8897 
8898 	if (elts->properties == NULL)
8899 		elts->properties = pnode;
8900 	else
8901 		(void) xmlAddSibling(elts->properties, pnode);
8902 }
8903 
8904 /*
8905  * Add a property_group element for this property group to elts.
8906  */
8907 static void
8908 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8909 {
8910 	xmlNodePtr n;
8911 	struct pg_elts elts;
8912 	int ret;
8913 	boolean_t read_protected;
8914 
8915 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
8916 
8917 	/* name */
8918 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8919 		scfdie();
8920 	safe_setprop(n, name_attr, exp_str);
8921 
8922 	/* type */
8923 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8924 		scfdie();
8925 	safe_setprop(n, type_attr, exp_str);
8926 
8927 	/* properties */
8928 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8929 		scfdie();
8930 
8931 	(void) memset(&elts, 0, sizeof (elts));
8932 
8933 	/*
8934 	 * If this property group is not read protected, we always want to
8935 	 * output all the values.  Otherwise, we only output the values if the
8936 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8937 	 */
8938 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8939 		scfdie();
8940 
8941 	if (!read_protected)
8942 		flags |= SCE_ALL_VALUES;
8943 
8944 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8945 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8946 			scfdie();
8947 
8948 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8949 			xmlNodePtr m;
8950 
8951 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8952 			if (m == NULL)
8953 				uu_die(emsg_create_xml);
8954 
8955 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8956 				elts.stability = m;
8957 				continue;
8958 			}
8959 
8960 			xmlFreeNode(m);
8961 		}
8962 
8963 		export_property(exp_prop, NULL, &elts, flags);
8964 	}
8965 	if (ret == -1)
8966 		scfdie();
8967 
8968 	(void) xmlAddChild(n, elts.stability);
8969 	(void) xmlAddChildList(n, elts.propvals);
8970 	(void) xmlAddChildList(n, elts.properties);
8971 
8972 	if (eelts->property_groups == NULL)
8973 		eelts->property_groups = n;
8974 	else
8975 		(void) xmlAddSibling(eelts->property_groups, n);
8976 }
8977 
8978 /*
8979  * Create an XML node representing the dependency described by the given
8980  * property group and put it in eelts.  Unless the dependency is not valid, in
8981  * which case create a generic property_group element which represents it and
8982  * put it in eelts.
8983  */
8984 static void
8985 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8986 {
8987 	xmlNodePtr n;
8988 	int err = 0, ret;
8989 	struct pg_elts elts;
8990 
8991 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
8992 	if (n == NULL)
8993 		uu_die(emsg_create_xml);
8994 
8995 	/*
8996 	 * If the external flag is present, skip this dependency because it
8997 	 * should have been created by another manifest.
8998 	 */
8999 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9000 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9001 		    prop_get_val(exp_prop, exp_val) == 0) {
9002 			uint8_t b;
9003 
9004 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9005 				scfdie();
9006 
9007 			if (b)
9008 				return;
9009 		}
9010 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
9011 		scfdie();
9012 
9013 	/* Get the required attributes. */
9014 
9015 	/* name */
9016 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9017 		scfdie();
9018 	safe_setprop(n, name_attr, exp_str);
9019 
9020 	/* grouping */
9021 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9022 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9023 		err = 1;
9024 
9025 	/* restart_on */
9026 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9027 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9028 		err = 1;
9029 
9030 	/* type */
9031 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9032 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9033 		err = 1;
9034 
9035 	/*
9036 	 * entities: Not required, but if we create no children, it will be
9037 	 * created as empty on import, so fail if it's missing.
9038 	 */
9039 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9040 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9041 		scf_iter_t *eiter;
9042 		int ret2;
9043 
9044 		eiter = scf_iter_create(g_hndl);
9045 		if (eiter == NULL)
9046 			scfdie();
9047 
9048 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9049 			scfdie();
9050 
9051 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9052 			xmlNodePtr ch;
9053 
9054 			if (scf_value_get_astring(exp_val, exp_str,
9055 			    exp_str_sz) < 0)
9056 				scfdie();
9057 
9058 			/*
9059 			 * service_fmri's must be first, so we can add them
9060 			 * here.
9061 			 */
9062 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9063 			    NULL);
9064 			if (ch == NULL)
9065 				uu_die(emsg_create_xml);
9066 
9067 			safe_setprop(ch, value_attr, exp_str);
9068 		}
9069 		if (ret2 == -1)
9070 			scfdie();
9071 
9072 		scf_iter_destroy(eiter);
9073 	} else
9074 		err = 1;
9075 
9076 	if (err) {
9077 		xmlFreeNode(n);
9078 
9079 		export_pg(pg, eelts, 0);
9080 
9081 		return;
9082 	}
9083 
9084 	/* Iterate through the properties & handle each. */
9085 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9086 		scfdie();
9087 
9088 	(void) memset(&elts, 0, sizeof (elts));
9089 
9090 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9091 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9092 			scfdie();
9093 
9094 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9095 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9096 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9097 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9098 			continue;
9099 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9100 			xmlNodePtr m;
9101 
9102 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9103 			if (m == NULL)
9104 				uu_die(emsg_create_xml);
9105 
9106 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9107 				elts.stability = m;
9108 				continue;
9109 			}
9110 
9111 			xmlFreeNode(m);
9112 		}
9113 
9114 		export_property(exp_prop, exp_str, &elts, 0);
9115 	}
9116 	if (ret == -1)
9117 		scfdie();
9118 
9119 	(void) xmlAddChild(n, elts.stability);
9120 	(void) xmlAddChildList(n, elts.propvals);
9121 	(void) xmlAddChildList(n, elts.properties);
9122 
9123 	if (eelts->dependencies == NULL)
9124 		eelts->dependencies = n;
9125 	else
9126 		(void) xmlAddSibling(eelts->dependencies, n);
9127 }
9128 
9129 static xmlNodePtr
9130 export_method_environment(scf_propertygroup_t *pg)
9131 {
9132 	xmlNodePtr env;
9133 	int ret;
9134 	int children = 0;
9135 
9136 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9137 		return (NULL);
9138 
9139 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9140 	if (env == NULL)
9141 		uu_die(emsg_create_xml);
9142 
9143 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9144 		scfdie();
9145 
9146 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9147 		scfdie();
9148 
9149 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9150 		xmlNodePtr ev;
9151 		char *cp;
9152 
9153 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9154 			scfdie();
9155 
9156 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9157 			warn(gettext("Invalid environment variable \"%s\".\n"),
9158 			    exp_str);
9159 			continue;
9160 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9161 			warn(gettext("Invalid environment variable \"%s\"; "
9162 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9163 			continue;
9164 		}
9165 
9166 		*cp = '\0';
9167 		cp++;
9168 
9169 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9170 		if (ev == NULL)
9171 			uu_die(emsg_create_xml);
9172 
9173 		safe_setprop(ev, name_attr, exp_str);
9174 		safe_setprop(ev, value_attr, cp);
9175 		children++;
9176 	}
9177 
9178 	if (ret != 0)
9179 		scfdie();
9180 
9181 	if (children == 0) {
9182 		xmlFreeNode(env);
9183 		return (NULL);
9184 	}
9185 
9186 	return (env);
9187 }
9188 
9189 /*
9190  * As above, but for a method property group.
9191  */
9192 static void
9193 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9194 {
9195 	xmlNodePtr n, env;
9196 	char *str;
9197 	int err = 0, nonenv, ret;
9198 	uint8_t use_profile;
9199 	struct pg_elts elts;
9200 	xmlNodePtr ctxt = NULL;
9201 
9202 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9203 
9204 	/* Get the required attributes. */
9205 
9206 	/* name */
9207 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9208 		scfdie();
9209 	safe_setprop(n, name_attr, exp_str);
9210 
9211 	/* type */
9212 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9213 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9214 		err = 1;
9215 
9216 	/* exec */
9217 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9218 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9219 		err = 1;
9220 
9221 	/* timeout */
9222 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9223 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9224 	    prop_get_val(exp_prop, exp_val) == 0) {
9225 		uint64_t c;
9226 
9227 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9228 			scfdie();
9229 
9230 		str = uu_msprintf("%llu", c);
9231 		if (str == NULL)
9232 			uu_die(gettext("Could not create string"));
9233 
9234 		safe_setprop(n, "timeout_seconds", str);
9235 		free(str);
9236 	} else
9237 		err = 1;
9238 
9239 	if (err) {
9240 		xmlFreeNode(n);
9241 
9242 		export_pg(pg, eelts, 0);
9243 
9244 		return;
9245 	}
9246 
9247 
9248 	/*
9249 	 * If we're going to have a method_context child, we need to know
9250 	 * before we iterate through the properties.  Since method_context's
9251 	 * are optional, we don't want to complain about any properties
9252 	 * missing if none of them are there.  Thus we can't use the
9253 	 * convenience functions.
9254 	 */
9255 	nonenv =
9256 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9257 	    SCF_SUCCESS ||
9258 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9259 	    SCF_SUCCESS ||
9260 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9261 	    SCF_SUCCESS ||
9262 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9263 	    SCF_SUCCESS;
9264 
9265 	if (nonenv) {
9266 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9267 		if (ctxt == NULL)
9268 			uu_die(emsg_create_xml);
9269 
9270 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9271 		    0 &&
9272 		    set_attr_from_prop_default(exp_prop, ctxt,
9273 		    "working_directory", ":default") != 0)
9274 			err = 1;
9275 
9276 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9277 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9278 		    ":default") != 0)
9279 			err = 1;
9280 
9281 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9282 		    0 &&
9283 		    set_attr_from_prop_default(exp_prop, ctxt,
9284 		    "resource_pool", ":default") != 0)
9285 			err = 1;
9286 		/*
9287 		 * We only want to complain about profile or credential
9288 		 * properties if we will use them.  To determine that we must
9289 		 * examine USE_PROFILE.
9290 		 */
9291 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9292 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9293 		    prop_get_val(exp_prop, exp_val) == 0) {
9294 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9295 			    SCF_SUCCESS) {
9296 				scfdie();
9297 			}
9298 
9299 			if (use_profile) {
9300 				xmlNodePtr prof;
9301 
9302 				prof = xmlNewChild(ctxt, NULL,
9303 				    (xmlChar *)"method_profile", NULL);
9304 				if (prof == NULL)
9305 					uu_die(emsg_create_xml);
9306 
9307 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9308 				    exp_prop) != 0 ||
9309 				    set_attr_from_prop(exp_prop, prof,
9310 				    name_attr) != 0)
9311 					err = 1;
9312 			} else {
9313 				xmlNodePtr cred;
9314 
9315 				cred = xmlNewChild(ctxt, NULL,
9316 				    (xmlChar *)"method_credential", NULL);
9317 				if (cred == NULL)
9318 					uu_die(emsg_create_xml);
9319 
9320 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9321 				    exp_prop) != 0 ||
9322 				    set_attr_from_prop(exp_prop, cred,
9323 				    "user") != 0) {
9324 					err = 1;
9325 				}
9326 
9327 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9328 				    exp_prop) == 0 &&
9329 				    set_attr_from_prop_default(exp_prop, cred,
9330 				    "group", ":default") != 0)
9331 					err = 1;
9332 
9333 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9334 				    exp_prop) == 0 &&
9335 				    set_attr_from_prop_default(exp_prop, cred,
9336 				    "supp_groups", ":default") != 0)
9337 					err = 1;
9338 
9339 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9340 				    exp_prop) == 0 &&
9341 				    set_attr_from_prop_default(exp_prop, cred,
9342 				    "privileges", ":default") != 0)
9343 					err = 1;
9344 
9345 				if (pg_get_prop(pg,
9346 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9347 				    exp_prop) == 0 &&
9348 				    set_attr_from_prop_default(exp_prop, cred,
9349 				    "limit_privileges", ":default") != 0)
9350 					err = 1;
9351 			}
9352 		}
9353 	}
9354 
9355 	if ((env = export_method_environment(pg)) != NULL) {
9356 		if (ctxt == NULL) {
9357 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9358 			if (ctxt == NULL)
9359 				uu_die(emsg_create_xml);
9360 		}
9361 		(void) xmlAddChild(ctxt, env);
9362 	}
9363 
9364 	if (env != NULL || (nonenv && err == 0))
9365 		(void) xmlAddChild(n, ctxt);
9366 	else
9367 		xmlFreeNode(ctxt);
9368 
9369 	nonenv = (err == 0);
9370 
9371 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9372 		scfdie();
9373 
9374 	(void) memset(&elts, 0, sizeof (elts));
9375 
9376 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9377 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9378 			scfdie();
9379 
9380 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9381 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9382 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9383 			continue;
9384 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9385 			xmlNodePtr m;
9386 
9387 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9388 			if (m == NULL)
9389 				uu_die(emsg_create_xml);
9390 
9391 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9392 				elts.stability = m;
9393 				continue;
9394 			}
9395 
9396 			xmlFreeNode(m);
9397 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9398 		    0 ||
9399 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9400 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9401 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9402 			if (nonenv)
9403 				continue;
9404 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9405 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9406 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9407 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9408 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9409 			if (nonenv && !use_profile)
9410 				continue;
9411 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9412 			if (nonenv && use_profile)
9413 				continue;
9414 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9415 			if (env != NULL)
9416 				continue;
9417 		}
9418 
9419 		export_property(exp_prop, exp_str, &elts, 0);
9420 	}
9421 	if (ret == -1)
9422 		scfdie();
9423 
9424 	(void) xmlAddChild(n, elts.stability);
9425 	(void) xmlAddChildList(n, elts.propvals);
9426 	(void) xmlAddChildList(n, elts.properties);
9427 
9428 	if (eelts->exec_methods == NULL)
9429 		eelts->exec_methods = n;
9430 	else
9431 		(void) xmlAddSibling(eelts->exec_methods, n);
9432 }
9433 
9434 static void
9435 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9436     struct entity_elts *eelts)
9437 {
9438 	xmlNodePtr pgnode;
9439 
9440 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9441 	if (pgnode == NULL)
9442 		uu_die(emsg_create_xml);
9443 
9444 	safe_setprop(pgnode, name_attr, name);
9445 	safe_setprop(pgnode, type_attr, type);
9446 
9447 	(void) xmlAddChildList(pgnode, elts->propvals);
9448 	(void) xmlAddChildList(pgnode, elts->properties);
9449 
9450 	if (eelts->property_groups == NULL)
9451 		eelts->property_groups = pgnode;
9452 	else
9453 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9454 }
9455 
9456 /*
9457  * Process the general property group for a service.  This is the one with the
9458  * goodies.
9459  */
9460 static void
9461 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9462 {
9463 	struct pg_elts elts;
9464 	int ret;
9465 
9466 	/*
9467 	 * In case there are properties which don't correspond to child
9468 	 * entities of the service entity, we'll set up a pg_elts structure to
9469 	 * put them in.
9470 	 */
9471 	(void) memset(&elts, 0, sizeof (elts));
9472 
9473 	/* Walk the properties, looking for special ones. */
9474 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9475 		scfdie();
9476 
9477 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9478 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9479 			scfdie();
9480 
9481 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9482 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9483 			    prop_get_val(exp_prop, exp_val) == 0) {
9484 				uint8_t b;
9485 
9486 				if (scf_value_get_boolean(exp_val, &b) !=
9487 				    SCF_SUCCESS)
9488 					scfdie();
9489 
9490 				if (b) {
9491 					selts->single_instance =
9492 					    xmlNewNode(NULL,
9493 					    (xmlChar *)"single_instance");
9494 					if (selts->single_instance == NULL)
9495 						uu_die(emsg_create_xml);
9496 				}
9497 
9498 				continue;
9499 			}
9500 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9501 			xmlNodePtr rnode, sfnode;
9502 
9503 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9504 			if (rnode == NULL)
9505 				uu_die(emsg_create_xml);
9506 
9507 			sfnode = xmlNewChild(rnode, NULL,
9508 			    (xmlChar *)"service_fmri", NULL);
9509 			if (sfnode == NULL)
9510 				uu_die(emsg_create_xml);
9511 
9512 			if (set_attr_from_prop(exp_prop, sfnode,
9513 			    value_attr) == 0) {
9514 				selts->restarter = rnode;
9515 				continue;
9516 			}
9517 
9518 			xmlFreeNode(rnode);
9519 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9520 		    0) {
9521 			xmlNodePtr s;
9522 
9523 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9524 			if (s == NULL)
9525 				uu_die(emsg_create_xml);
9526 
9527 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9528 				selts->stability = s;
9529 				continue;
9530 			}
9531 
9532 			xmlFreeNode(s);
9533 		}
9534 
9535 		export_property(exp_prop, exp_str, &elts, 0);
9536 	}
9537 	if (ret == -1)
9538 		scfdie();
9539 
9540 	if (elts.propvals != NULL || elts.properties != NULL)
9541 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9542 		    selts);
9543 }
9544 
9545 static void
9546 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9547 {
9548 	xmlNodePtr n, prof, cred, env;
9549 	uint8_t use_profile;
9550 	int ret, err = 0;
9551 
9552 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9553 
9554 	env = export_method_environment(pg);
9555 
9556 	/* Need to know whether we'll use a profile or not. */
9557 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9558 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9559 	    prop_get_val(exp_prop, exp_val) == 0) {
9560 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9561 			scfdie();
9562 
9563 		if (use_profile)
9564 			prof =
9565 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9566 			    NULL);
9567 		else
9568 			cred =
9569 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9570 			    NULL);
9571 	}
9572 
9573 	if (env != NULL)
9574 		(void) xmlAddChild(n, env);
9575 
9576 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9577 		scfdie();
9578 
9579 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9580 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9581 			scfdie();
9582 
9583 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9584 			if (set_attr_from_prop(exp_prop, n,
9585 			    "working_directory") != 0)
9586 				err = 1;
9587 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9588 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9589 				err = 1;
9590 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9591 			if (set_attr_from_prop(exp_prop, n,
9592 			    "resource_pool") != 0)
9593 				err = 1;
9594 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9595 			/* EMPTY */
9596 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9597 			if (use_profile ||
9598 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9599 				err = 1;
9600 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9601 			if (use_profile ||
9602 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9603 				err = 1;
9604 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9605 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9606 			    "supp_groups") != 0)
9607 				err = 1;
9608 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9609 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9610 			    "privileges") != 0)
9611 				err = 1;
9612 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9613 		    0) {
9614 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9615 			    "limit_privileges") != 0)
9616 				err = 1;
9617 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9618 			if (!use_profile || set_attr_from_prop(exp_prop,
9619 			    prof, name_attr) != 0)
9620 				err = 1;
9621 		} else {
9622 			/* Can't have generic properties in method_context's */
9623 			err = 1;
9624 		}
9625 	}
9626 	if (ret == -1)
9627 		scfdie();
9628 
9629 	if (err && env == NULL) {
9630 		xmlFreeNode(n);
9631 		export_pg(pg, elts, 0);
9632 		return;
9633 	}
9634 
9635 	elts->method_context = n;
9636 }
9637 
9638 /*
9639  * Given a dependency property group in the tfmri entity (target fmri), return
9640  * a dependent element which represents it.
9641  */
9642 static xmlNodePtr
9643 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9644 {
9645 	uint8_t b;
9646 	xmlNodePtr n, sf;
9647 	int err = 0, ret;
9648 	struct pg_elts pgelts;
9649 
9650 	/*
9651 	 * If external isn't set to true then exporting the service will
9652 	 * export this as a normal dependency, so we should stop to avoid
9653 	 * duplication.
9654 	 */
9655 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9656 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9657 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9658 		if (g_verbose) {
9659 			warn(gettext("Dependent \"%s\" cannot be exported "
9660 			    "properly because the \"%s\" property of the "
9661 			    "\"%s\" dependency of %s is not set to true.\n"),
9662 			    name, scf_property_external, name, tfmri);
9663 		}
9664 
9665 		return (NULL);
9666 	}
9667 
9668 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9669 	if (n == NULL)
9670 		uu_die(emsg_create_xml);
9671 
9672 	safe_setprop(n, name_attr, name);
9673 
9674 	/* Get the required attributes */
9675 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9676 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9677 		err = 1;
9678 
9679 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9680 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9681 		err = 1;
9682 
9683 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9684 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9685 	    prop_get_val(exp_prop, exp_val) == 0) {
9686 		/* EMPTY */
9687 	} else
9688 		err = 1;
9689 
9690 	if (err) {
9691 		xmlFreeNode(n);
9692 		return (NULL);
9693 	}
9694 
9695 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9696 	if (sf == NULL)
9697 		uu_die(emsg_create_xml);
9698 
9699 	safe_setprop(sf, value_attr, tfmri);
9700 
9701 	/*
9702 	 * Now add elements for the other properties.
9703 	 */
9704 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9705 		scfdie();
9706 
9707 	(void) memset(&pgelts, 0, sizeof (pgelts));
9708 
9709 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9710 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9711 			scfdie();
9712 
9713 		if (strcmp(exp_str, scf_property_external) == 0 ||
9714 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9715 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9716 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9717 			continue;
9718 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9719 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9720 			    prop_get_val(exp_prop, exp_val) == 0) {
9721 				char type[sizeof ("service") + 1];
9722 
9723 				if (scf_value_get_astring(exp_val, type,
9724 				    sizeof (type)) < 0)
9725 					scfdie();
9726 
9727 				if (strcmp(type, "service") == 0)
9728 					continue;
9729 			}
9730 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9731 			xmlNodePtr s;
9732 
9733 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9734 			if (s == NULL)
9735 				uu_die(emsg_create_xml);
9736 
9737 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9738 				pgelts.stability = s;
9739 				continue;
9740 			}
9741 
9742 			xmlFreeNode(s);
9743 		}
9744 
9745 		export_property(exp_prop, exp_str, &pgelts, 0);
9746 	}
9747 	if (ret == -1)
9748 		scfdie();
9749 
9750 	(void) xmlAddChild(n, pgelts.stability);
9751 	(void) xmlAddChildList(n, pgelts.propvals);
9752 	(void) xmlAddChildList(n, pgelts.properties);
9753 
9754 	return (n);
9755 }
9756 
9757 static void
9758 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
9759 {
9760 	scf_propertygroup_t *opg;
9761 	scf_iter_t *iter;
9762 	char *type, *fmri;
9763 	int ret;
9764 	struct pg_elts pgelts;
9765 	xmlNodePtr n;
9766 	scf_error_t serr;
9767 
9768 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
9769 	    (iter = scf_iter_create(g_hndl)) == NULL)
9770 		scfdie();
9771 
9772 	/* Can't use exp_prop_iter due to export_dependent(). */
9773 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
9774 		scfdie();
9775 
9776 	type = safe_malloc(max_scf_pg_type_len + 1);
9777 
9778 	/* Get an extra byte so we can tell if values are too long. */
9779 	fmri = safe_malloc(max_scf_fmri_len + 2);
9780 
9781 	(void) memset(&pgelts, 0, sizeof (pgelts));
9782 
9783 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
9784 		void *entity;
9785 		int isservice;
9786 		scf_type_t ty;
9787 
9788 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
9789 			scfdie();
9790 
9791 		if ((ty != SCF_TYPE_ASTRING &&
9792 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
9793 		    prop_get_val(exp_prop, exp_val) != 0) {
9794 			export_property(exp_prop, NULL, &pgelts, 0);
9795 			continue;
9796 		}
9797 
9798 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9799 			scfdie();
9800 
9801 		if (scf_value_get_astring(exp_val, fmri,
9802 		    max_scf_fmri_len + 2) < 0)
9803 			scfdie();
9804 
9805 		/* Look for a dependency group in the target fmri. */
9806 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9807 		switch (serr) {
9808 		case SCF_ERROR_NONE:
9809 			break;
9810 
9811 		case SCF_ERROR_NO_MEMORY:
9812 			uu_die(gettext("Out of memory.\n"));
9813 			/* NOTREACHED */
9814 
9815 		case SCF_ERROR_INVALID_ARGUMENT:
9816 			if (g_verbose) {
9817 				if (scf_property_to_fmri(exp_prop, fmri,
9818 				    max_scf_fmri_len + 2) < 0)
9819 					scfdie();
9820 
9821 				warn(gettext("The value of %s is not a valid "
9822 				    "FMRI.\n"), fmri);
9823 			}
9824 
9825 			export_property(exp_prop, exp_str, &pgelts, 0);
9826 			continue;
9827 
9828 		case SCF_ERROR_CONSTRAINT_VIOLATED:
9829 			if (g_verbose) {
9830 				if (scf_property_to_fmri(exp_prop, fmri,
9831 				    max_scf_fmri_len + 2) < 0)
9832 					scfdie();
9833 
9834 				warn(gettext("The value of %s does not specify "
9835 				    "a service or an instance.\n"), fmri);
9836 			}
9837 
9838 			export_property(exp_prop, exp_str, &pgelts, 0);
9839 			continue;
9840 
9841 		case SCF_ERROR_NOT_FOUND:
9842 			if (g_verbose) {
9843 				if (scf_property_to_fmri(exp_prop, fmri,
9844 				    max_scf_fmri_len + 2) < 0)
9845 					scfdie();
9846 
9847 				warn(gettext("The entity specified by %s does "
9848 				    "not exist.\n"), fmri);
9849 			}
9850 
9851 			export_property(exp_prop, exp_str, &pgelts, 0);
9852 			continue;
9853 
9854 		default:
9855 #ifndef NDEBUG
9856 			(void) fprintf(stderr, "%s:%d: %s() failed with "
9857 			    "unexpected error %d.\n", __FILE__, __LINE__,
9858 			    "fmri_to_entity", serr);
9859 #endif
9860 			abort();
9861 		}
9862 
9863 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9864 			if (scf_error() != SCF_ERROR_NOT_FOUND)
9865 				scfdie();
9866 
9867 			warn(gettext("Entity %s is missing dependency property "
9868 			    "group %s.\n"), fmri, exp_str);
9869 
9870 			export_property(exp_prop, NULL, &pgelts, 0);
9871 			continue;
9872 		}
9873 
9874 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9875 			scfdie();
9876 
9877 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9878 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9879 				scfdie();
9880 
9881 			warn(gettext("Property group %s is not of "
9882 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9883 
9884 			export_property(exp_prop, NULL, &pgelts, 0);
9885 			continue;
9886 		}
9887 
9888 		n = export_dependent(opg, exp_str, fmri);
9889 		if (n == NULL)
9890 			export_property(exp_prop, exp_str, &pgelts, 0);
9891 		else {
9892 			if (eelts->dependents == NULL)
9893 				eelts->dependents = n;
9894 			else
9895 				(void) xmlAddSibling(eelts->dependents,
9896 				    n);
9897 		}
9898 	}
9899 	if (ret == -1)
9900 		scfdie();
9901 
9902 	free(fmri);
9903 	free(type);
9904 
9905 	scf_iter_destroy(iter);
9906 	scf_pg_destroy(opg);
9907 
9908 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9909 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9910 		    eelts);
9911 }
9912 
9913 static void
9914 make_node(xmlNodePtr *nodep, const char *name)
9915 {
9916 	if (*nodep == NULL) {
9917 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
9918 		if (*nodep == NULL)
9919 			uu_die(emsg_create_xml);
9920 	}
9921 }
9922 
9923 static xmlNodePtr
9924 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9925 {
9926 	int ret;
9927 	xmlNodePtr parent = NULL;
9928 	xmlNodePtr loctext = NULL;
9929 
9930 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9931 		scfdie();
9932 
9933 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9934 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9935 		    prop_get_val(exp_prop, exp_val) != 0)
9936 			continue;
9937 
9938 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9939 			scfdie();
9940 
9941 		make_node(&parent, parname);
9942 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9943 		    (xmlChar *)exp_str);
9944 		if (loctext == NULL)
9945 			uu_die(emsg_create_xml);
9946 
9947 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9948 			scfdie();
9949 
9950 		safe_setprop(loctext, "xml:lang", exp_str);
9951 	}
9952 
9953 	if (ret == -1)
9954 		scfdie();
9955 
9956 	return (parent);
9957 }
9958 
9959 static xmlNodePtr
9960 export_tm_manpage(scf_propertygroup_t *pg)
9961 {
9962 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9963 	if (manpage == NULL)
9964 		uu_die(emsg_create_xml);
9965 
9966 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9967 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9968 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9969 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9970 		xmlFreeNode(manpage);
9971 		return (NULL);
9972 	}
9973 
9974 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9975 		(void) set_attr_from_prop_default(exp_prop,
9976 		    manpage, "manpath", ":default");
9977 
9978 	return (manpage);
9979 }
9980 
9981 static xmlNodePtr
9982 export_tm_doc_link(scf_propertygroup_t *pg)
9983 {
9984 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9985 	if (doc_link == NULL)
9986 		uu_die(emsg_create_xml);
9987 
9988 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
9989 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
9990 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
9991 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
9992 		xmlFreeNode(doc_link);
9993 		return (NULL);
9994 	}
9995 	return (doc_link);
9996 }
9997 
9998 /*
9999  * Process template information for a service or instances.
10000  */
10001 static void
10002 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10003     struct template_elts *telts)
10004 {
10005 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10006 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10007 	xmlNodePtr child = NULL;
10008 
10009 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10010 		scfdie();
10011 
10012 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10013 		telts->common_name = export_tm_loctext(pg, "common_name");
10014 		if (telts->common_name == NULL)
10015 			export_pg(pg, elts, 0);
10016 		return;
10017 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10018 		telts->description = export_tm_loctext(pg, "description");
10019 		if (telts->description == NULL)
10020 			export_pg(pg, elts, 0);
10021 		return;
10022 	}
10023 
10024 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10025 		child = export_tm_manpage(pg);
10026 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10027 		child = export_tm_doc_link(pg);
10028 	}
10029 
10030 	if (child != NULL) {
10031 		make_node(&telts->documentation, "documentation");
10032 		(void) xmlAddChild(telts->documentation, child);
10033 	} else {
10034 		export_pg(pg, elts, 0);
10035 	}
10036 }
10037 
10038 /*
10039  * Process parameter and paramval elements
10040  */
10041 static void
10042 export_parameter(scf_property_t *prop, const char *name,
10043     struct params_elts *elts)
10044 {
10045 	xmlNodePtr param;
10046 	scf_error_t err = 0;
10047 	int ret;
10048 
10049 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10050 		if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10051 			uu_die(emsg_create_xml);
10052 
10053 		safe_setprop(param, name_attr, name);
10054 
10055 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10056 			scfdie();
10057 		safe_setprop(param, value_attr, exp_str);
10058 
10059 		if (elts->paramval == NULL)
10060 			elts->paramval = param;
10061 		else
10062 			(void) xmlAddSibling(elts->paramval, param);
10063 
10064 		return;
10065 	}
10066 
10067 	err = scf_error();
10068 
10069 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10070 	    err != SCF_ERROR_NOT_FOUND)
10071 		scfdie();
10072 
10073 	if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10074 		uu_die(emsg_create_xml);
10075 
10076 	safe_setprop(param, name_attr, name);
10077 
10078 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10079 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10080 			scfdie();
10081 
10082 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10083 		    1) {
10084 			xmlNodePtr vn;
10085 
10086 			if ((vn = xmlNewChild(param, NULL,
10087 			    (xmlChar *)"value_node", NULL)) == NULL)
10088 				uu_die(emsg_create_xml);
10089 
10090 			if (scf_value_get_as_string(exp_val, exp_str,
10091 			    exp_str_sz) < 0)
10092 				scfdie();
10093 
10094 			safe_setprop(vn, value_attr, exp_str);
10095 		}
10096 		if (ret != 0)
10097 			scfdie();
10098 	}
10099 
10100 	if (elts->parameter == NULL)
10101 		elts->parameter = param;
10102 	else
10103 		(void) xmlAddSibling(elts->parameter, param);
10104 }
10105 
10106 /*
10107  * Process notification parameters for a service or instance
10108  */
10109 static void
10110 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10111 {
10112 	xmlNodePtr n, event, *type;
10113 	struct params_elts *eelts;
10114 	int ret, err, i;
10115 
10116 	n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10117 	event = xmlNewNode(NULL, (xmlChar *)"event");
10118 	if (n == NULL || event == NULL)
10119 		uu_die(emsg_create_xml);
10120 
10121 	/* event value */
10122 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10123 		scfdie();
10124 	safe_setprop(event, value_attr, exp_str);
10125 
10126 	(void) xmlAddChild(n, event);
10127 
10128 	if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10129 	    (eelts = calloc(URI_SCHEME_NUM,
10130 	    sizeof (struct params_elts))) == NULL)
10131 		uu_die(gettext("Out of memory.\n"));
10132 
10133 	err = 0;
10134 
10135 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10136 		scfdie();
10137 
10138 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10139 		char *t, *p;
10140 
10141 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10142 			scfdie();
10143 
10144 		if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10145 			/*
10146 			 * this is not a well formed notification parameters
10147 			 * element, we should export as regular pg
10148 			 */
10149 			err = 1;
10150 			break;
10151 		}
10152 
10153 		if ((i = check_uri_protocol(t)) < 0) {
10154 			err = 1;
10155 			break;
10156 		}
10157 
10158 		if (type[i] == NULL) {
10159 			if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10160 			    NULL)
10161 				uu_die(emsg_create_xml);
10162 
10163 			safe_setprop(type[i], name_attr, t);
10164 		}
10165 		if (strcmp(p, active_attr) == 0) {
10166 			if (set_attr_from_prop(exp_prop, type[i],
10167 			    active_attr) != 0) {
10168 				err = 1;
10169 				break;
10170 			}
10171 			continue;
10172 		}
10173 		/*
10174 		 * We export the parameter
10175 		 */
10176 		export_parameter(exp_prop, p, &eelts[i]);
10177 	}
10178 
10179 	if (ret == -1)
10180 		scfdie();
10181 
10182 	if (err == 1) {
10183 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10184 			xmlFree(type[i]);
10185 		free(type);
10186 
10187 		export_pg(pg, elts, 0);
10188 
10189 		return;
10190 	} else {
10191 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10192 			if (type[i] != NULL) {
10193 				(void) xmlAddChildList(type[i],
10194 				    eelts[i].paramval);
10195 				(void) xmlAddChildList(type[i],
10196 				    eelts[i].parameter);
10197 				(void) xmlAddSibling(event, type[i]);
10198 			}
10199 	}
10200 	free(type);
10201 
10202 	if (elts->notify_params == NULL)
10203 		elts->notify_params = n;
10204 	else
10205 		(void) xmlAddSibling(elts->notify_params, n);
10206 }
10207 
10208 /*
10209  * Process the general property group for an instance.
10210  */
10211 static void
10212 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10213     struct entity_elts *elts)
10214 {
10215 	uint8_t enabled;
10216 	struct pg_elts pgelts;
10217 	int ret;
10218 
10219 	/* enabled */
10220 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10221 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10222 	    prop_get_val(exp_prop, exp_val) == 0) {
10223 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10224 			scfdie();
10225 	} else {
10226 		enabled = 0;
10227 	}
10228 
10229 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10230 
10231 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10232 		scfdie();
10233 
10234 	(void) memset(&pgelts, 0, sizeof (pgelts));
10235 
10236 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10237 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10238 			scfdie();
10239 
10240 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10241 			continue;
10242 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10243 			xmlNodePtr rnode, sfnode;
10244 
10245 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10246 			if (rnode == NULL)
10247 				uu_die(emsg_create_xml);
10248 
10249 			sfnode = xmlNewChild(rnode, NULL,
10250 			    (xmlChar *)"service_fmri", NULL);
10251 			if (sfnode == NULL)
10252 				uu_die(emsg_create_xml);
10253 
10254 			if (set_attr_from_prop(exp_prop, sfnode,
10255 			    value_attr) == 0) {
10256 				elts->restarter = rnode;
10257 				continue;
10258 			}
10259 
10260 			xmlFreeNode(rnode);
10261 		}
10262 
10263 		export_property(exp_prop, exp_str, &pgelts, 0);
10264 	}
10265 	if (ret == -1)
10266 		scfdie();
10267 
10268 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10269 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10270 		    elts);
10271 }
10272 
10273 /*
10274  * Put an instance element for the given instance into selts.
10275  */
10276 static void
10277 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10278 {
10279 	xmlNodePtr n;
10280 	boolean_t isdefault;
10281 	struct entity_elts elts;
10282 	struct template_elts template_elts;
10283 	int ret;
10284 
10285 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10286 	if (n == NULL)
10287 		uu_die(emsg_create_xml);
10288 
10289 	/* name */
10290 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10291 		scfdie();
10292 	safe_setprop(n, name_attr, exp_str);
10293 	isdefault = strcmp(exp_str, "default") == 0;
10294 
10295 	/* check existance of general pg (since general/enabled is required) */
10296 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10297 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10298 			scfdie();
10299 
10300 		if (g_verbose) {
10301 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10302 				scfdie();
10303 
10304 			warn(gettext("Instance %s has no general property "
10305 			    "group; it will be marked disabled.\n"), exp_str);
10306 		}
10307 
10308 		safe_setprop(n, enabled_attr, false);
10309 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10310 	    strcmp(exp_str, scf_group_framework) != 0) {
10311 		if (g_verbose) {
10312 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10313 				scfdie();
10314 
10315 			warn(gettext("Property group %s is not of type "
10316 			    "framework; the instance will be marked "
10317 			    "disabled.\n"), exp_str);
10318 		}
10319 
10320 		safe_setprop(n, enabled_attr, false);
10321 	}
10322 
10323 	/* property groups */
10324 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10325 		scfdie();
10326 
10327 	(void) memset(&elts, 0, sizeof (elts));
10328 	(void) memset(&template_elts, 0, sizeof (template_elts));
10329 
10330 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10331 		uint32_t pgflags;
10332 
10333 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10334 			scfdie();
10335 
10336 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10337 			continue;
10338 
10339 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10340 			scfdie();
10341 
10342 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10343 			export_dependency(exp_pg, &elts);
10344 			continue;
10345 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10346 			export_method(exp_pg, &elts);
10347 			continue;
10348 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10349 			if (scf_pg_get_name(exp_pg, exp_str,
10350 			    max_scf_name_len + 1) < 0)
10351 				scfdie();
10352 
10353 			if (strcmp(exp_str, scf_pg_general) == 0) {
10354 				export_inst_general(exp_pg, n, &elts);
10355 				continue;
10356 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10357 			    0) {
10358 				export_method_context(exp_pg, &elts);
10359 				continue;
10360 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10361 				export_dependents(exp_pg, &elts);
10362 				continue;
10363 			}
10364 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10365 			export_template(exp_pg, &elts, &template_elts);
10366 			continue;
10367 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10368 			export_notify_params(exp_pg, &elts);
10369 			continue;
10370 		}
10371 
10372 		/* Ordinary pg. */
10373 		export_pg(exp_pg, &elts, flags);
10374 	}
10375 	if (ret == -1)
10376 		scfdie();
10377 
10378 	if (template_elts.common_name != NULL) {
10379 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10380 		(void) xmlAddChild(elts.template, template_elts.common_name);
10381 		(void) xmlAddChild(elts.template, template_elts.description);
10382 		(void) xmlAddChild(elts.template, template_elts.documentation);
10383 	} else {
10384 		xmlFreeNode(template_elts.description);
10385 		xmlFreeNode(template_elts.documentation);
10386 	}
10387 
10388 	if (isdefault && elts.restarter == NULL &&
10389 	    elts.dependencies == NULL && elts.method_context == NULL &&
10390 	    elts.exec_methods == NULL && elts.notify_params == NULL &&
10391 	    elts.property_groups == NULL && elts.template == NULL) {
10392 		xmlChar *eval;
10393 
10394 		/* This is a default instance */
10395 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10396 
10397 		xmlFreeNode(n);
10398 
10399 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10400 		if (n == NULL)
10401 			uu_die(emsg_create_xml);
10402 
10403 		safe_setprop(n, enabled_attr, (char *)eval);
10404 		xmlFree(eval);
10405 
10406 		selts->create_default_instance = n;
10407 	} else {
10408 		/* Assemble the children in order. */
10409 		(void) xmlAddChild(n, elts.restarter);
10410 		(void) xmlAddChildList(n, elts.dependencies);
10411 		(void) xmlAddChildList(n, elts.dependents);
10412 		(void) xmlAddChild(n, elts.method_context);
10413 		(void) xmlAddChildList(n, elts.exec_methods);
10414 		(void) xmlAddChildList(n, elts.notify_params);
10415 		(void) xmlAddChildList(n, elts.property_groups);
10416 		(void) xmlAddChild(n, elts.template);
10417 
10418 		if (selts->instances == NULL)
10419 			selts->instances = n;
10420 		else
10421 			(void) xmlAddSibling(selts->instances, n);
10422 	}
10423 }
10424 
10425 /*
10426  * Return a service element for the given service.
10427  */
10428 static xmlNodePtr
10429 export_service(scf_service_t *svc, int flags)
10430 {
10431 	xmlNodePtr snode;
10432 	struct entity_elts elts;
10433 	struct template_elts template_elts;
10434 	int ret;
10435 
10436 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10437 	if (snode == NULL)
10438 		uu_die(emsg_create_xml);
10439 
10440 	/* Get & set name attribute */
10441 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10442 		scfdie();
10443 	safe_setprop(snode, name_attr, exp_str);
10444 
10445 	safe_setprop(snode, type_attr, "service");
10446 	safe_setprop(snode, "version", "0");
10447 
10448 	/* Acquire child elements. */
10449 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10450 		scfdie();
10451 
10452 	(void) memset(&elts, 0, sizeof (elts));
10453 	(void) memset(&template_elts, 0, sizeof (template_elts));
10454 
10455 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10456 		uint32_t pgflags;
10457 
10458 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10459 			scfdie();
10460 
10461 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10462 			continue;
10463 
10464 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10465 			scfdie();
10466 
10467 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10468 			export_dependency(exp_pg, &elts);
10469 			continue;
10470 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10471 			export_method(exp_pg, &elts);
10472 			continue;
10473 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10474 			if (scf_pg_get_name(exp_pg, exp_str,
10475 			    max_scf_name_len + 1) < 0)
10476 				scfdie();
10477 
10478 			if (strcmp(exp_str, scf_pg_general) == 0) {
10479 				export_svc_general(exp_pg, &elts);
10480 				continue;
10481 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10482 			    0) {
10483 				export_method_context(exp_pg, &elts);
10484 				continue;
10485 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10486 				export_dependents(exp_pg, &elts);
10487 				continue;
10488 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10489 				continue;
10490 			}
10491 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10492 			export_template(exp_pg, &elts, &template_elts);
10493 			continue;
10494 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10495 			export_notify_params(exp_pg, &elts);
10496 			continue;
10497 		}
10498 
10499 		export_pg(exp_pg, &elts, flags);
10500 	}
10501 	if (ret == -1)
10502 		scfdie();
10503 
10504 	if (template_elts.common_name != NULL) {
10505 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10506 		(void) xmlAddChild(elts.template, template_elts.common_name);
10507 		(void) xmlAddChild(elts.template, template_elts.description);
10508 		(void) xmlAddChild(elts.template, template_elts.documentation);
10509 	} else {
10510 		xmlFreeNode(template_elts.description);
10511 		xmlFreeNode(template_elts.documentation);
10512 	}
10513 
10514 	/* Iterate instances */
10515 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10516 		scfdie();
10517 
10518 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10519 		export_instance(exp_inst, &elts, flags);
10520 	if (ret == -1)
10521 		scfdie();
10522 
10523 	/* Now add all of the accumulated elements in order. */
10524 	(void) xmlAddChild(snode, elts.create_default_instance);
10525 	(void) xmlAddChild(snode, elts.single_instance);
10526 	(void) xmlAddChild(snode, elts.restarter);
10527 	(void) xmlAddChildList(snode, elts.dependencies);
10528 	(void) xmlAddChildList(snode, elts.dependents);
10529 	(void) xmlAddChild(snode, elts.method_context);
10530 	(void) xmlAddChildList(snode, elts.exec_methods);
10531 	(void) xmlAddChildList(snode, elts.notify_params);
10532 	(void) xmlAddChildList(snode, elts.property_groups);
10533 	(void) xmlAddChildList(snode, elts.instances);
10534 	(void) xmlAddChild(snode, elts.stability);
10535 	(void) xmlAddChild(snode, elts.template);
10536 
10537 	return (snode);
10538 }
10539 
10540 static int
10541 export_callback(void *data, scf_walkinfo_t *wip)
10542 {
10543 	FILE *f;
10544 	xmlDocPtr doc;
10545 	xmlNodePtr sb;
10546 	int result;
10547 	struct export_args *argsp = (struct export_args *)data;
10548 
10549 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10550 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10551 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10552 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10553 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10554 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10555 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10556 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10557 		scfdie();
10558 
10559 	exp_str_sz = max_scf_len + 1;
10560 	exp_str = safe_malloc(exp_str_sz);
10561 
10562 	if (argsp->filename != NULL) {
10563 		errno = 0;
10564 		f = fopen(argsp->filename, "wb");
10565 		if (f == NULL) {
10566 			if (errno == 0)
10567 				uu_die(gettext("Could not open \"%s\": no free "
10568 				    "stdio streams.\n"), argsp->filename);
10569 			else
10570 				uu_die(gettext("Could not open \"%s\""),
10571 				    argsp->filename);
10572 		}
10573 	} else
10574 		f = stdout;
10575 
10576 	doc = xmlNewDoc((xmlChar *)"1.0");
10577 	if (doc == NULL)
10578 		uu_die(gettext("Could not create XML document.\n"));
10579 
10580 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10581 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10582 		uu_die(emsg_create_xml);
10583 
10584 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10585 	if (sb == NULL)
10586 		uu_die(emsg_create_xml);
10587 	safe_setprop(sb, type_attr, "manifest");
10588 	safe_setprop(sb, name_attr, "export");
10589 	(void) xmlAddSibling(doc->children, sb);
10590 
10591 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10592 
10593 	result = write_service_bundle(doc, f);
10594 
10595 	free(exp_str);
10596 	scf_iter_destroy(exp_val_iter);
10597 	scf_iter_destroy(exp_prop_iter);
10598 	scf_iter_destroy(exp_pg_iter);
10599 	scf_iter_destroy(exp_inst_iter);
10600 	scf_value_destroy(exp_val);
10601 	scf_property_destroy(exp_prop);
10602 	scf_pg_destroy(exp_pg);
10603 	scf_instance_destroy(exp_inst);
10604 
10605 	xmlFreeDoc(doc);
10606 
10607 	if (f != stdout)
10608 		(void) fclose(f);
10609 
10610 	return (result);
10611 }
10612 
10613 /*
10614  * Get the service named by fmri, build an XML tree which represents it, and
10615  * dump it into filename (or stdout if filename is NULL).
10616  */
10617 int
10618 lscf_service_export(char *fmri, const char *filename, int flags)
10619 {
10620 	struct export_args args;
10621 	int ret, err;
10622 
10623 	lscf_prep_hndl();
10624 
10625 	bzero(&args, sizeof (args));
10626 	args.filename = filename;
10627 	args.flags = flags;
10628 
10629 	err = 0;
10630 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10631 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10632 	    &args, &err, semerr)) != 0) {
10633 		if (ret != -1)
10634 			semerr(gettext("Failed to walk instances: %s\n"),
10635 			    scf_strerror(ret));
10636 		return (-1);
10637 	}
10638 
10639 	/*
10640 	 * Error message has already been printed.
10641 	 */
10642 	if (err != 0)
10643 		return (-1);
10644 
10645 	return (0);
10646 }
10647 
10648 
10649 /*
10650  * Archive
10651  */
10652 
10653 static xmlNodePtr
10654 make_archive(int flags)
10655 {
10656 	xmlNodePtr sb;
10657 	scf_scope_t *scope;
10658 	scf_service_t *svc;
10659 	scf_iter_t *iter;
10660 	int r;
10661 
10662 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10663 	    (svc = scf_service_create(g_hndl)) == NULL ||
10664 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10665 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10666 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10667 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10668 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10669 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10670 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10671 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10672 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10673 		scfdie();
10674 
10675 	exp_str_sz = max_scf_len + 1;
10676 	exp_str = safe_malloc(exp_str_sz);
10677 
10678 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10679 	if (sb == NULL)
10680 		uu_die(emsg_create_xml);
10681 	safe_setprop(sb, type_attr, "archive");
10682 	safe_setprop(sb, name_attr, "none");
10683 
10684 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10685 		scfdie();
10686 	if (scf_iter_scope_services(iter, scope) != 0)
10687 		scfdie();
10688 
10689 	for (;;) {
10690 		r = scf_iter_next_service(iter, svc);
10691 		if (r == 0)
10692 			break;
10693 		if (r != 1)
10694 			scfdie();
10695 
10696 		if (scf_service_get_name(svc, exp_str,
10697 		    max_scf_name_len + 1) < 0)
10698 			scfdie();
10699 
10700 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10701 			continue;
10702 
10703 		(void) xmlAddChild(sb, export_service(svc, flags));
10704 	}
10705 
10706 	free(exp_str);
10707 
10708 	scf_iter_destroy(exp_val_iter);
10709 	scf_iter_destroy(exp_prop_iter);
10710 	scf_iter_destroy(exp_pg_iter);
10711 	scf_iter_destroy(exp_inst_iter);
10712 	scf_value_destroy(exp_val);
10713 	scf_property_destroy(exp_prop);
10714 	scf_pg_destroy(exp_pg);
10715 	scf_instance_destroy(exp_inst);
10716 	scf_iter_destroy(iter);
10717 	scf_service_destroy(svc);
10718 	scf_scope_destroy(scope);
10719 
10720 	return (sb);
10721 }
10722 
10723 int
10724 lscf_archive(const char *filename, int flags)
10725 {
10726 	FILE *f;
10727 	xmlDocPtr doc;
10728 	int result;
10729 
10730 	lscf_prep_hndl();
10731 
10732 	if (filename != NULL) {
10733 		errno = 0;
10734 		f = fopen(filename, "wb");
10735 		if (f == NULL) {
10736 			if (errno == 0)
10737 				uu_die(gettext("Could not open \"%s\": no free "
10738 				    "stdio streams.\n"), filename);
10739 			else
10740 				uu_die(gettext("Could not open \"%s\""),
10741 				    filename);
10742 		}
10743 	} else
10744 		f = stdout;
10745 
10746 	doc = xmlNewDoc((xmlChar *)"1.0");
10747 	if (doc == NULL)
10748 		uu_die(gettext("Could not create XML document.\n"));
10749 
10750 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10751 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10752 		uu_die(emsg_create_xml);
10753 
10754 	(void) xmlAddSibling(doc->children, make_archive(flags));
10755 
10756 	result = write_service_bundle(doc, f);
10757 
10758 	xmlFreeDoc(doc);
10759 
10760 	if (f != stdout)
10761 		(void) fclose(f);
10762 
10763 	return (result);
10764 }
10765 
10766 
10767 /*
10768  * "Extract" a profile.
10769  */
10770 int
10771 lscf_profile_extract(const char *filename)
10772 {
10773 	FILE *f;
10774 	xmlDocPtr doc;
10775 	xmlNodePtr sb, snode, inode;
10776 	scf_scope_t *scope;
10777 	scf_service_t *svc;
10778 	scf_instance_t *inst;
10779 	scf_propertygroup_t *pg;
10780 	scf_property_t *prop;
10781 	scf_value_t *val;
10782 	scf_iter_t *siter, *iiter;
10783 	int r, s;
10784 	char *namebuf;
10785 	uint8_t b;
10786 	int result;
10787 
10788 	lscf_prep_hndl();
10789 
10790 	if (filename != NULL) {
10791 		errno = 0;
10792 		f = fopen(filename, "wb");
10793 		if (f == NULL) {
10794 			if (errno == 0)
10795 				uu_die(gettext("Could not open \"%s\": no "
10796 				    "free stdio streams.\n"), filename);
10797 			else
10798 				uu_die(gettext("Could not open \"%s\""),
10799 				    filename);
10800 		}
10801 	} else
10802 		f = stdout;
10803 
10804 	doc = xmlNewDoc((xmlChar *)"1.0");
10805 	if (doc == NULL)
10806 		uu_die(gettext("Could not create XML document.\n"));
10807 
10808 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10809 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10810 		uu_die(emsg_create_xml);
10811 
10812 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10813 	if (sb == NULL)
10814 		uu_die(emsg_create_xml);
10815 	safe_setprop(sb, type_attr, "profile");
10816 	safe_setprop(sb, name_attr, "extract");
10817 	(void) xmlAddSibling(doc->children, sb);
10818 
10819 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10820 	    (svc = scf_service_create(g_hndl)) == NULL ||
10821 	    (inst = scf_instance_create(g_hndl)) == NULL ||
10822 	    (pg = scf_pg_create(g_hndl)) == NULL ||
10823 	    (prop = scf_property_create(g_hndl)) == NULL ||
10824 	    (val = scf_value_create(g_hndl)) == NULL ||
10825 	    (siter = scf_iter_create(g_hndl)) == NULL ||
10826 	    (iiter = scf_iter_create(g_hndl)) == NULL)
10827 		scfdie();
10828 
10829 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
10830 		scfdie();
10831 
10832 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
10833 		scfdie();
10834 
10835 	namebuf = safe_malloc(max_scf_name_len + 1);
10836 
10837 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
10838 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
10839 			scfdie();
10840 
10841 		snode = xmlNewNode(NULL, (xmlChar *)"service");
10842 		if (snode == NULL)
10843 			uu_die(emsg_create_xml);
10844 
10845 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
10846 		    0)
10847 			scfdie();
10848 
10849 		safe_setprop(snode, name_attr, namebuf);
10850 
10851 		safe_setprop(snode, type_attr, "service");
10852 		safe_setprop(snode, "version", "0");
10853 
10854 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
10855 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
10856 			    SCF_SUCCESS) {
10857 				if (scf_error() != SCF_ERROR_NOT_FOUND)
10858 					scfdie();
10859 
10860 				if (g_verbose) {
10861 					ssize_t len;
10862 					char *fmri;
10863 
10864 					len =
10865 					    scf_instance_to_fmri(inst, NULL, 0);
10866 					if (len < 0)
10867 						scfdie();
10868 
10869 					fmri = safe_malloc(len + 1);
10870 
10871 					if (scf_instance_to_fmri(inst, fmri,
10872 					    len + 1) < 0)
10873 						scfdie();
10874 
10875 					warn("Instance %s has no \"%s\" "
10876 					    "property group.\n", fmri,
10877 					    scf_pg_general);
10878 
10879 					free(fmri);
10880 				}
10881 
10882 				continue;
10883 			}
10884 
10885 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
10886 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
10887 			    prop_get_val(prop, val) != 0)
10888 				continue;
10889 
10890 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
10891 			    NULL);
10892 			if (inode == NULL)
10893 				uu_die(emsg_create_xml);
10894 
10895 			if (scf_instance_get_name(inst, namebuf,
10896 			    max_scf_name_len + 1) < 0)
10897 				scfdie();
10898 
10899 			safe_setprop(inode, name_attr, namebuf);
10900 
10901 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
10902 				scfdie();
10903 
10904 			safe_setprop(inode, enabled_attr, b ? true : false);
10905 		}
10906 		if (s < 0)
10907 			scfdie();
10908 
10909 		if (snode->children != NULL)
10910 			(void) xmlAddChild(sb, snode);
10911 		else
10912 			xmlFreeNode(snode);
10913 	}
10914 	if (r < 0)
10915 		scfdie();
10916 
10917 	free(namebuf);
10918 
10919 	result = write_service_bundle(doc, f);
10920 
10921 	xmlFreeDoc(doc);
10922 
10923 	if (f != stdout)
10924 		(void) fclose(f);
10925 
10926 	return (result);
10927 }
10928 
10929 
10930 /*
10931  * Entity manipulation commands
10932  */
10933 
10934 /*
10935  * Entity selection.  If no entity is selected, then the current scope is in
10936  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
10937  * only cur_inst is NULL, and when an instance is selected, none are NULL.
10938  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
10939  * cur_inst will be non-NULL.
10940  */
10941 
10942 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
10943 static int
10944 select_inst(const char *name)
10945 {
10946 	scf_instance_t *inst;
10947 	scf_error_t err;
10948 
10949 	assert(cur_svc != NULL);
10950 
10951 	inst = scf_instance_create(g_hndl);
10952 	if (inst == NULL)
10953 		scfdie();
10954 
10955 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10956 		cur_inst = inst;
10957 		return (0);
10958 	}
10959 
10960 	err = scf_error();
10961 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10962 		scfdie();
10963 
10964 	scf_instance_destroy(inst);
10965 	return (1);
10966 }
10967 
10968 /* Returns as above. */
10969 static int
10970 select_svc(const char *name)
10971 {
10972 	scf_service_t *svc;
10973 	scf_error_t err;
10974 
10975 	assert(cur_scope != NULL);
10976 
10977 	svc = scf_service_create(g_hndl);
10978 	if (svc == NULL)
10979 		scfdie();
10980 
10981 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10982 		cur_svc = svc;
10983 		return (0);
10984 	}
10985 
10986 	err = scf_error();
10987 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10988 		scfdie();
10989 
10990 	scf_service_destroy(svc);
10991 	return (1);
10992 }
10993 
10994 /* ARGSUSED */
10995 static int
10996 select_callback(void *unused, scf_walkinfo_t *wip)
10997 {
10998 	scf_instance_t *inst;
10999 	scf_service_t *svc;
11000 	scf_scope_t *scope;
11001 
11002 	if (wip->inst != NULL) {
11003 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11004 		    (svc = scf_service_create(g_hndl)) == NULL ||
11005 		    (inst = scf_instance_create(g_hndl)) == NULL)
11006 			scfdie();
11007 
11008 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11009 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11010 			scfdie();
11011 	} else {
11012 		assert(wip->svc != NULL);
11013 
11014 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11015 		    (svc = scf_service_create(g_hndl)) == NULL)
11016 			scfdie();
11017 
11018 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11019 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11020 			scfdie();
11021 
11022 		inst = NULL;
11023 	}
11024 
11025 	/* Clear out the current selection */
11026 	assert(cur_scope != NULL);
11027 	scf_scope_destroy(cur_scope);
11028 	scf_service_destroy(cur_svc);
11029 	scf_instance_destroy(cur_inst);
11030 
11031 	cur_scope = scope;
11032 	cur_svc = svc;
11033 	cur_inst = inst;
11034 
11035 	return (0);
11036 }
11037 
11038 static int
11039 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11040 {
11041 	char **fmri = fmri_p;
11042 
11043 	*fmri = strdup(wip->fmri);
11044 	if (*fmri == NULL)
11045 		uu_die(gettext("Out of memory.\n"));
11046 
11047 	return (0);
11048 }
11049 
11050 /*
11051  * validate [fmri]
11052  * Perform the validation of an FMRI instance.
11053  */
11054 void
11055 lscf_validate_fmri(const char *fmri)
11056 {
11057 	int ret = 0;
11058 	size_t inst_sz;
11059 	char *inst_fmri = NULL;
11060 	scf_tmpl_errors_t *errs = NULL;
11061 	char *snapbuf = NULL;
11062 
11063 	lscf_prep_hndl();
11064 
11065 	if (fmri == NULL) {
11066 		inst_sz = max_scf_fmri_len + 1;
11067 		inst_fmri = safe_malloc(inst_sz);
11068 
11069 		if (cur_snap != NULL) {
11070 			snapbuf = safe_malloc(max_scf_name_len + 1);
11071 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11072 			    max_scf_name_len + 1) < 0)
11073 				scfdie();
11074 		}
11075 		if (cur_inst == NULL) {
11076 			semerr(gettext("No instance selected\n"));
11077 			goto cleanup;
11078 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11079 		    inst_sz) >= inst_sz) {
11080 			/* sanity check. Should never get here */
11081 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11082 			    __FILE__, __LINE__);
11083 		}
11084 	} else {
11085 		scf_error_t scf_err;
11086 		int err = 0;
11087 
11088 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11089 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11090 			uu_warn("Failed to walk instances: %s\n",
11091 			    scf_strerror(scf_err));
11092 			goto cleanup;
11093 		}
11094 		if (err != 0) {
11095 			/* error message displayed by scf_walk_fmri */
11096 			goto cleanup;
11097 		}
11098 	}
11099 
11100 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11101 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11102 	if (ret == -1) {
11103 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11104 			warn(gettext("Template data for %s is invalid. "
11105 			    "Consider reverting to a previous snapshot or "
11106 			    "restoring original configuration.\n"), inst_fmri);
11107 		} else {
11108 			uu_warn("%s: %s\n",
11109 			    gettext("Error validating the instance"),
11110 			    scf_strerror(scf_error()));
11111 		}
11112 	} else if (ret == 1 && errs != NULL) {
11113 		scf_tmpl_error_t *err = NULL;
11114 		char *msg;
11115 		size_t len = 256;	/* initial error buffer size */
11116 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11117 		    SCF_TMPL_STRERROR_HUMAN : 0;
11118 
11119 		msg = safe_malloc(len);
11120 
11121 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11122 			int ret;
11123 
11124 			if ((ret = scf_tmpl_strerror(err, msg, len,
11125 			    flag)) >= len) {
11126 				len = ret + 1;
11127 				msg = realloc(msg, len);
11128 				if (msg == NULL)
11129 					uu_die(gettext(
11130 					    "Out of memory.\n"));
11131 				(void) scf_tmpl_strerror(err, msg, len,
11132 				    flag);
11133 			}
11134 			(void) fprintf(stderr, "%s\n", msg);
11135 		}
11136 		if (msg != NULL)
11137 			free(msg);
11138 	}
11139 	if (errs != NULL)
11140 		scf_tmpl_errors_destroy(errs);
11141 
11142 cleanup:
11143 	free(inst_fmri);
11144 	free(snapbuf);
11145 }
11146 
11147 static void
11148 lscf_validate_file(const char *filename)
11149 {
11150 	tmpl_errors_t *errs;
11151 
11152 	bundle_t *b = internal_bundle_new();
11153 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11154 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11155 			tmpl_errors_print(stderr, errs, "");
11156 			semerr(gettext("Validation failed.\n"));
11157 		}
11158 		tmpl_errors_destroy(errs);
11159 	}
11160 	(void) internal_bundle_free(b);
11161 }
11162 
11163 /*
11164  * validate [fmri|file]
11165  */
11166 void
11167 lscf_validate(const char *arg)
11168 {
11169 	const char *str;
11170 
11171 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11172 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11173 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11174 		lscf_validate_file(str);
11175 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11176 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11177 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11178 		lscf_validate_fmri(str);
11179 	} else if (access(arg, R_OK | F_OK) == 0) {
11180 		lscf_validate_file(arg);
11181 	} else {
11182 		lscf_validate_fmri(arg);
11183 	}
11184 }
11185 
11186 void
11187 lscf_select(const char *fmri)
11188 {
11189 	int ret, err;
11190 
11191 	lscf_prep_hndl();
11192 
11193 	if (cur_snap != NULL) {
11194 		struct snaplevel *elt;
11195 		char *buf;
11196 
11197 		/* Error unless name is that of the next level. */
11198 		elt = uu_list_next(cur_levels, cur_elt);
11199 		if (elt == NULL) {
11200 			semerr(gettext("No children.\n"));
11201 			return;
11202 		}
11203 
11204 		buf = safe_malloc(max_scf_name_len + 1);
11205 
11206 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11207 		    max_scf_name_len + 1) < 0)
11208 			scfdie();
11209 
11210 		if (strcmp(buf, fmri) != 0) {
11211 			semerr(gettext("No such child.\n"));
11212 			free(buf);
11213 			return;
11214 		}
11215 
11216 		free(buf);
11217 
11218 		cur_elt = elt;
11219 		cur_level = elt->sl;
11220 		return;
11221 	}
11222 
11223 	/*
11224 	 * Special case for 'svc:', which takes the user to the scope level.
11225 	 */
11226 	if (strcmp(fmri, "svc:") == 0) {
11227 		scf_instance_destroy(cur_inst);
11228 		scf_service_destroy(cur_svc);
11229 		cur_inst = NULL;
11230 		cur_svc = NULL;
11231 		return;
11232 	}
11233 
11234 	/*
11235 	 * Special case for ':properties'.  This appears as part of 'list' but
11236 	 * can't be selected.  Give a more helpful error message in this case.
11237 	 */
11238 	if (strcmp(fmri, ":properties") == 0) {
11239 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11240 		    "to list properties.\n"));
11241 		return;
11242 	}
11243 
11244 	/*
11245 	 * First try the argument as relative to the current selection.
11246 	 */
11247 	if (cur_inst != NULL) {
11248 		/* EMPTY */;
11249 	} else if (cur_svc != NULL) {
11250 		if (select_inst(fmri) != 1)
11251 			return;
11252 	} else {
11253 		if (select_svc(fmri) != 1)
11254 			return;
11255 	}
11256 
11257 	err = 0;
11258 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11259 	    select_callback, NULL, &err, semerr)) != 0) {
11260 		semerr(gettext("Failed to walk instances: %s\n"),
11261 		    scf_strerror(ret));
11262 	}
11263 }
11264 
11265 void
11266 lscf_unselect(void)
11267 {
11268 	lscf_prep_hndl();
11269 
11270 	if (cur_snap != NULL) {
11271 		struct snaplevel *elt;
11272 
11273 		elt = uu_list_prev(cur_levels, cur_elt);
11274 		if (elt == NULL) {
11275 			semerr(gettext("No parent levels.\n"));
11276 		} else {
11277 			cur_elt = elt;
11278 			cur_level = elt->sl;
11279 		}
11280 	} else if (cur_inst != NULL) {
11281 		scf_instance_destroy(cur_inst);
11282 		cur_inst = NULL;
11283 	} else if (cur_svc != NULL) {
11284 		scf_service_destroy(cur_svc);
11285 		cur_svc = NULL;
11286 	} else {
11287 		semerr(gettext("Cannot unselect at scope level.\n"));
11288 	}
11289 }
11290 
11291 /*
11292  * Return the FMRI of the current selection, for the prompt.
11293  */
11294 void
11295 lscf_get_selection_str(char *buf, size_t bufsz)
11296 {
11297 	char *cp;
11298 	ssize_t fmrilen, szret;
11299 	boolean_t deleted = B_FALSE;
11300 
11301 	if (g_hndl == NULL) {
11302 		(void) strlcpy(buf, "svc:", bufsz);
11303 		return;
11304 	}
11305 
11306 	if (cur_level != NULL) {
11307 		assert(cur_snap != NULL);
11308 
11309 		/* [ snapshot ] FMRI [: instance ] */
11310 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11311 		    + 2 + max_scf_name_len + 1 + 1);
11312 
11313 		buf[0] = '[';
11314 
11315 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11316 		    max_scf_name_len + 1);
11317 		if (szret < 0) {
11318 			if (scf_error() != SCF_ERROR_DELETED)
11319 				scfdie();
11320 
11321 			goto snap_deleted;
11322 		}
11323 
11324 		(void) strcat(buf, "]svc:/");
11325 
11326 		cp = strchr(buf, '\0');
11327 
11328 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11329 		    max_scf_name_len + 1);
11330 		if (szret < 0) {
11331 			if (scf_error() != SCF_ERROR_DELETED)
11332 				scfdie();
11333 
11334 			goto snap_deleted;
11335 		}
11336 
11337 		cp = strchr(cp, '\0');
11338 
11339 		if (snaplevel_is_instance(cur_level)) {
11340 			*cp++ = ':';
11341 
11342 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11343 			    max_scf_name_len + 1) < 0) {
11344 				if (scf_error() != SCF_ERROR_DELETED)
11345 					scfdie();
11346 
11347 				goto snap_deleted;
11348 			}
11349 		} else {
11350 			*cp++ = '[';
11351 			*cp++ = ':';
11352 
11353 			if (scf_instance_get_name(cur_inst, cp,
11354 			    max_scf_name_len + 1) < 0) {
11355 				if (scf_error() != SCF_ERROR_DELETED)
11356 					scfdie();
11357 
11358 				goto snap_deleted;
11359 			}
11360 
11361 			(void) strcat(buf, "]");
11362 		}
11363 
11364 		return;
11365 
11366 snap_deleted:
11367 		deleted = B_TRUE;
11368 		free(buf);
11369 		unselect_cursnap();
11370 	}
11371 
11372 	assert(cur_snap == NULL);
11373 
11374 	if (cur_inst != NULL) {
11375 		assert(cur_svc != NULL);
11376 		assert(cur_scope != NULL);
11377 
11378 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11379 		if (fmrilen >= 0) {
11380 			assert(fmrilen < bufsz);
11381 			if (deleted)
11382 				warn(emsg_deleted);
11383 			return;
11384 		}
11385 
11386 		if (scf_error() != SCF_ERROR_DELETED)
11387 			scfdie();
11388 
11389 		deleted = B_TRUE;
11390 
11391 		scf_instance_destroy(cur_inst);
11392 		cur_inst = NULL;
11393 	}
11394 
11395 	if (cur_svc != NULL) {
11396 		assert(cur_scope != NULL);
11397 
11398 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11399 		if (szret >= 0) {
11400 			assert(szret < bufsz);
11401 			if (deleted)
11402 				warn(emsg_deleted);
11403 			return;
11404 		}
11405 
11406 		if (scf_error() != SCF_ERROR_DELETED)
11407 			scfdie();
11408 
11409 		deleted = B_TRUE;
11410 		scf_service_destroy(cur_svc);
11411 		cur_svc = NULL;
11412 	}
11413 
11414 	assert(cur_scope != NULL);
11415 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11416 
11417 	if (fmrilen < 0)
11418 		scfdie();
11419 
11420 	assert(fmrilen < bufsz);
11421 	if (deleted)
11422 		warn(emsg_deleted);
11423 }
11424 
11425 /*
11426  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11427  * :statistics) are listed for the current selection.
11428  */
11429 void
11430 lscf_list(const char *pattern)
11431 {
11432 	scf_iter_t *iter;
11433 	char *buf;
11434 	int ret;
11435 
11436 	lscf_prep_hndl();
11437 
11438 	if (cur_level != NULL) {
11439 		struct snaplevel *elt;
11440 
11441 		(void) fputs(COLON_NAMESPACES, stdout);
11442 
11443 		elt = uu_list_next(cur_levels, cur_elt);
11444 		if (elt == NULL)
11445 			return;
11446 
11447 		/*
11448 		 * For now, we know that the next level is an instance.  But
11449 		 * if we ever have multiple scopes, this could be complicated.
11450 		 */
11451 		buf = safe_malloc(max_scf_name_len + 1);
11452 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11453 		    max_scf_name_len + 1) >= 0) {
11454 			(void) puts(buf);
11455 		} else {
11456 			if (scf_error() != SCF_ERROR_DELETED)
11457 				scfdie();
11458 		}
11459 
11460 		free(buf);
11461 
11462 		return;
11463 	}
11464 
11465 	if (cur_inst != NULL) {
11466 		(void) fputs(COLON_NAMESPACES, stdout);
11467 		return;
11468 	}
11469 
11470 	iter = scf_iter_create(g_hndl);
11471 	if (iter == NULL)
11472 		scfdie();
11473 
11474 	buf = safe_malloc(max_scf_name_len + 1);
11475 
11476 	if (cur_svc != NULL) {
11477 		/* List the instances in this service. */
11478 		scf_instance_t *inst;
11479 
11480 		inst = scf_instance_create(g_hndl);
11481 		if (inst == NULL)
11482 			scfdie();
11483 
11484 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11485 			safe_printf(COLON_NAMESPACES);
11486 
11487 			for (;;) {
11488 				ret = scf_iter_next_instance(iter, inst);
11489 				if (ret == 0)
11490 					break;
11491 				if (ret != 1) {
11492 					if (scf_error() != SCF_ERROR_DELETED)
11493 						scfdie();
11494 
11495 					break;
11496 				}
11497 
11498 				if (scf_instance_get_name(inst, buf,
11499 				    max_scf_name_len + 1) >= 0) {
11500 					if (pattern == NULL ||
11501 					    fnmatch(pattern, buf, 0) == 0)
11502 						(void) puts(buf);
11503 				} else {
11504 					if (scf_error() != SCF_ERROR_DELETED)
11505 						scfdie();
11506 				}
11507 			}
11508 		} else {
11509 			if (scf_error() != SCF_ERROR_DELETED)
11510 				scfdie();
11511 		}
11512 
11513 		scf_instance_destroy(inst);
11514 	} else {
11515 		/* List the services in this scope. */
11516 		scf_service_t *svc;
11517 
11518 		assert(cur_scope != NULL);
11519 
11520 		svc = scf_service_create(g_hndl);
11521 		if (svc == NULL)
11522 			scfdie();
11523 
11524 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11525 			scfdie();
11526 
11527 		for (;;) {
11528 			ret = scf_iter_next_service(iter, svc);
11529 			if (ret == 0)
11530 				break;
11531 			if (ret != 1)
11532 				scfdie();
11533 
11534 			if (scf_service_get_name(svc, buf,
11535 			    max_scf_name_len + 1) >= 0) {
11536 				if (pattern == NULL ||
11537 				    fnmatch(pattern, buf, 0) == 0)
11538 					safe_printf("%s\n", buf);
11539 			} else {
11540 				if (scf_error() != SCF_ERROR_DELETED)
11541 					scfdie();
11542 			}
11543 		}
11544 
11545 		scf_service_destroy(svc);
11546 	}
11547 
11548 	free(buf);
11549 	scf_iter_destroy(iter);
11550 }
11551 
11552 /*
11553  * Entity addition.  Creates an empty entity in the current selection.
11554  */
11555 void
11556 lscf_add(const char *name)
11557 {
11558 	lscf_prep_hndl();
11559 
11560 	if (cur_snap != NULL) {
11561 		semerr(emsg_cant_modify_snapshots);
11562 	} else if (cur_inst != NULL) {
11563 		semerr(gettext("Cannot add entities to an instance.\n"));
11564 	} else if (cur_svc != NULL) {
11565 
11566 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11567 		    SCF_SUCCESS) {
11568 			switch (scf_error()) {
11569 			case SCF_ERROR_INVALID_ARGUMENT:
11570 				semerr(gettext("Invalid name.\n"));
11571 				break;
11572 
11573 			case SCF_ERROR_EXISTS:
11574 				semerr(gettext("Instance already exists.\n"));
11575 				break;
11576 
11577 			case SCF_ERROR_PERMISSION_DENIED:
11578 				semerr(emsg_permission_denied);
11579 				break;
11580 
11581 			default:
11582 				scfdie();
11583 			}
11584 		}
11585 	} else {
11586 		assert(cur_scope != NULL);
11587 
11588 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11589 		    SCF_SUCCESS) {
11590 			switch (scf_error()) {
11591 			case SCF_ERROR_INVALID_ARGUMENT:
11592 				semerr(gettext("Invalid name.\n"));
11593 				break;
11594 
11595 			case SCF_ERROR_EXISTS:
11596 				semerr(gettext("Service already exists.\n"));
11597 				break;
11598 
11599 			case SCF_ERROR_PERMISSION_DENIED:
11600 				semerr(emsg_permission_denied);
11601 				break;
11602 
11603 			case SCF_ERROR_BACKEND_READONLY:
11604 				semerr(emsg_read_only);
11605 				break;
11606 
11607 			default:
11608 				scfdie();
11609 			}
11610 		}
11611 	}
11612 }
11613 
11614 /* return 1 if the entity has no persistent pgs, else return 0 */
11615 static int
11616 entity_has_no_pgs(void *ent, int isservice)
11617 {
11618 	scf_iter_t *iter = NULL;
11619 	scf_propertygroup_t *pg = NULL;
11620 	uint32_t flags;
11621 	int err;
11622 	int ret = 1;
11623 
11624 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11625 	    (pg = scf_pg_create(g_hndl)) == NULL)
11626 		scfdie();
11627 
11628 	if (isservice) {
11629 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11630 			scfdie();
11631 	} else {
11632 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11633 			scfdie();
11634 	}
11635 
11636 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11637 		if (scf_pg_get_flags(pg, &flags) != 0)
11638 			scfdie();
11639 
11640 		/* skip nonpersistent pgs */
11641 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11642 			continue;
11643 
11644 		ret = 0;
11645 		break;
11646 	}
11647 
11648 	if (err == -1)
11649 		scfdie();
11650 
11651 	scf_pg_destroy(pg);
11652 	scf_iter_destroy(iter);
11653 
11654 	return (ret);
11655 }
11656 
11657 /* return 1 if the service has no instances, else return 0 */
11658 static int
11659 svc_has_no_insts(scf_service_t *svc)
11660 {
11661 	scf_instance_t *inst;
11662 	scf_iter_t *iter;
11663 	int r;
11664 	int ret = 1;
11665 
11666 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11667 	    (iter = scf_iter_create(g_hndl)) == NULL)
11668 		scfdie();
11669 
11670 	if (scf_iter_service_instances(iter, svc) != 0)
11671 		scfdie();
11672 
11673 	r = scf_iter_next_instance(iter, inst);
11674 	if (r == 1) {
11675 		ret = 0;
11676 	} else if (r == 0) {
11677 		ret = 1;
11678 	} else if (r == -1) {
11679 		scfdie();
11680 	} else {
11681 		bad_error("scf_iter_next_instance", r);
11682 	}
11683 
11684 	scf_iter_destroy(iter);
11685 	scf_instance_destroy(inst);
11686 
11687 	return (ret);
11688 }
11689 
11690 /*
11691  * Entity deletion.
11692  */
11693 
11694 /*
11695  * Delete the property group <fmri>/:properties/<name>.  Returns
11696  * SCF_ERROR_NONE on success (or if the entity is not found),
11697  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11698  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11699  * denied.
11700  */
11701 static scf_error_t
11702 delete_dependency_pg(const char *fmri, const char *name)
11703 {
11704 	void *entity = NULL;
11705 	int isservice;
11706 	scf_propertygroup_t *pg = NULL;
11707 	scf_error_t result;
11708 	char *pgty;
11709 	scf_service_t *svc = NULL;
11710 	scf_instance_t *inst = NULL;
11711 	scf_iter_t *iter = NULL;
11712 	char *name_buf = NULL;
11713 
11714 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11715 	switch (result) {
11716 	case SCF_ERROR_NONE:
11717 		break;
11718 
11719 	case SCF_ERROR_NO_MEMORY:
11720 		uu_die(gettext("Out of memory.\n"));
11721 		/* NOTREACHED */
11722 
11723 	case SCF_ERROR_INVALID_ARGUMENT:
11724 	case SCF_ERROR_CONSTRAINT_VIOLATED:
11725 		return (SCF_ERROR_INVALID_ARGUMENT);
11726 
11727 	case SCF_ERROR_NOT_FOUND:
11728 		result = SCF_ERROR_NONE;
11729 		goto out;
11730 
11731 	default:
11732 		bad_error("fmri_to_entity", result);
11733 	}
11734 
11735 	pg = scf_pg_create(g_hndl);
11736 	if (pg == NULL)
11737 		scfdie();
11738 
11739 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
11740 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11741 			scfdie();
11742 
11743 		result = SCF_ERROR_NONE;
11744 		goto out;
11745 	}
11746 
11747 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11748 
11749 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11750 		scfdie();
11751 
11752 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
11753 		result = SCF_ERROR_TYPE_MISMATCH;
11754 		free(pgty);
11755 		goto out;
11756 	}
11757 
11758 	free(pgty);
11759 
11760 	if (scf_pg_delete(pg) != 0) {
11761 		result = scf_error();
11762 		if (result != SCF_ERROR_PERMISSION_DENIED)
11763 			scfdie();
11764 		goto out;
11765 	}
11766 
11767 	/*
11768 	 * We have to handle the case where we've just deleted the last
11769 	 * property group of a "dummy" entity (instance or service).
11770 	 * A "dummy" entity is an entity only present to hold an
11771 	 * external dependency.
11772 	 * So, in the case we deleted the last property group then we
11773 	 * can also delete the entity. If the entity is an instance then
11774 	 * we must verify if this was the last instance for the service
11775 	 * and if it is, we can also delete the service if it doesn't
11776 	 * have any property group either.
11777 	 */
11778 
11779 	result = SCF_ERROR_NONE;
11780 
11781 	if (isservice) {
11782 		svc = (scf_service_t *)entity;
11783 
11784 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
11785 		    (iter = scf_iter_create(g_hndl)) == NULL)
11786 			scfdie();
11787 
11788 		name_buf = safe_malloc(max_scf_name_len + 1);
11789 	} else {
11790 		inst = (scf_instance_t *)entity;
11791 	}
11792 
11793 	/*
11794 	 * If the entity is an instance and we've just deleted its last
11795 	 * property group then we should delete it.
11796 	 */
11797 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
11798 		/* find the service before deleting the inst. - needed later */
11799 		if ((svc = scf_service_create(g_hndl)) == NULL)
11800 			scfdie();
11801 
11802 		if (scf_instance_get_parent(inst, svc) != 0)
11803 			scfdie();
11804 
11805 		/* delete the instance */
11806 		if (scf_instance_delete(inst) != 0) {
11807 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11808 				scfdie();
11809 
11810 			result = SCF_ERROR_PERMISSION_DENIED;
11811 			goto out;
11812 		}
11813 		/* no need to refresh the instance */
11814 		inst = NULL;
11815 	}
11816 
11817 	/*
11818 	 * If the service has no more instances and pgs or we just deleted the
11819 	 * last instance and the service doesn't have anymore propery groups
11820 	 * then the service should be deleted.
11821 	 */
11822 	if (svc != NULL &&
11823 	    svc_has_no_insts(svc) &&
11824 	    entity_has_no_pgs((void *)svc, 1)) {
11825 		if (scf_service_delete(svc) == 0) {
11826 			if (isservice) {
11827 				/* no need to refresh the service */
11828 				svc = NULL;
11829 			}
11830 
11831 			goto out;
11832 		}
11833 
11834 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11835 			scfdie();
11836 
11837 		result = SCF_ERROR_PERMISSION_DENIED;
11838 	}
11839 
11840 	/* if the entity has not been deleted, refresh it */
11841 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
11842 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
11843 		    name_buf);
11844 	}
11845 
11846 out:
11847 	if (isservice && (inst != NULL && iter != NULL)) {
11848 		free(name_buf);
11849 		scf_iter_destroy(iter);
11850 		scf_instance_destroy(inst);
11851 	}
11852 
11853 	if (!isservice && svc != NULL) {
11854 		scf_service_destroy(svc);
11855 	}
11856 
11857 	scf_pg_destroy(pg);
11858 	if (entity != NULL)
11859 		entity_destroy(entity, isservice);
11860 
11861 	return (result);
11862 }
11863 
11864 static int
11865 delete_dependents(scf_propertygroup_t *pg)
11866 {
11867 	char *pgty, *name, *fmri;
11868 	scf_property_t *prop;
11869 	scf_value_t *val;
11870 	scf_iter_t *iter;
11871 	int r;
11872 	scf_error_t err;
11873 
11874 	/* Verify that the pg has the correct type. */
11875 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11876 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11877 		scfdie();
11878 
11879 	if (strcmp(pgty, scf_group_framework) != 0) {
11880 		if (g_verbose) {
11881 			fmri = safe_malloc(max_scf_fmri_len + 1);
11882 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
11883 				scfdie();
11884 
11885 			warn(gettext("Property group %s is not of expected "
11886 			    "type %s.\n"), fmri, scf_group_framework);
11887 
11888 			free(fmri);
11889 		}
11890 
11891 		free(pgty);
11892 		return (-1);
11893 	}
11894 
11895 	free(pgty);
11896 
11897 	/* map delete_dependency_pg onto the properties. */
11898 	if ((prop = scf_property_create(g_hndl)) == NULL ||
11899 	    (val = scf_value_create(g_hndl)) == NULL ||
11900 	    (iter = scf_iter_create(g_hndl)) == NULL)
11901 		scfdie();
11902 
11903 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
11904 		scfdie();
11905 
11906 	name = safe_malloc(max_scf_name_len + 1);
11907 	fmri = safe_malloc(max_scf_fmri_len + 2);
11908 
11909 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
11910 		scf_type_t ty;
11911 
11912 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
11913 			scfdie();
11914 
11915 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11916 			scfdie();
11917 
11918 		if ((ty != SCF_TYPE_ASTRING &&
11919 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
11920 		    prop_get_val(prop, val) != 0)
11921 			continue;
11922 
11923 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
11924 			scfdie();
11925 
11926 		err = delete_dependency_pg(fmri, name);
11927 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
11928 			if (scf_property_to_fmri(prop, fmri,
11929 			    max_scf_fmri_len + 2) < 0)
11930 				scfdie();
11931 
11932 			warn(gettext("Value of %s is not a valid FMRI.\n"),
11933 			    fmri);
11934 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
11935 			warn(gettext("Property group \"%s\" of entity \"%s\" "
11936 			    "does not have dependency type.\n"), name, fmri);
11937 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
11938 			warn(gettext("Could not delete property group \"%s\" "
11939 			    "of entity \"%s\" (permission denied).\n"), name,
11940 			    fmri);
11941 		}
11942 	}
11943 	if (r == -1)
11944 		scfdie();
11945 
11946 	scf_value_destroy(val);
11947 	scf_property_destroy(prop);
11948 
11949 	return (0);
11950 }
11951 
11952 /*
11953  * Returns 1 if the instance may be running, and 0 otherwise.
11954  */
11955 static int
11956 inst_is_running(scf_instance_t *inst)
11957 {
11958 	scf_propertygroup_t *pg;
11959 	scf_property_t *prop;
11960 	scf_value_t *val;
11961 	char buf[MAX_SCF_STATE_STRING_SZ];
11962 	int ret = 0;
11963 	ssize_t szret;
11964 
11965 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11966 	    (prop = scf_property_create(g_hndl)) == NULL ||
11967 	    (val = scf_value_create(g_hndl)) == NULL)
11968 		scfdie();
11969 
11970 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
11971 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11972 			scfdie();
11973 		goto out;
11974 	}
11975 
11976 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
11977 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
11978 	    prop_get_val(prop, val) != 0)
11979 		goto out;
11980 
11981 	szret = scf_value_get_astring(val, buf, sizeof (buf));
11982 	assert(szret >= 0);
11983 
11984 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11985 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11986 
11987 out:
11988 	scf_value_destroy(val);
11989 	scf_property_destroy(prop);
11990 	scf_pg_destroy(pg);
11991 	return (ret);
11992 }
11993 
11994 static uint8_t
11995 pg_is_external_dependency(scf_propertygroup_t *pg)
11996 {
11997 	char *type;
11998 	scf_value_t *val;
11999 	scf_property_t *prop;
12000 	uint8_t b = B_FALSE;
12001 
12002 	type = safe_malloc(max_scf_pg_type_len + 1);
12003 
12004 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12005 		scfdie();
12006 
12007 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12008 	    (val = scf_value_create(g_hndl)) == NULL)
12009 		scfdie();
12010 
12011 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12012 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12013 			if (scf_property_get_value(prop, val) != 0)
12014 				scfdie();
12015 			if (scf_value_get_boolean(val, &b) != 0)
12016 				scfdie();
12017 		}
12018 	}
12019 
12020 	free(type);
12021 	(void) scf_value_destroy(val);
12022 	(void) scf_property_destroy(prop);
12023 
12024 	return (b);
12025 }
12026 
12027 #define	DELETE_FAILURE			-1
12028 #define	DELETE_SUCCESS_NOEXTDEPS	0
12029 #define	DELETE_SUCCESS_EXTDEPS		1
12030 
12031 /*
12032  * lscf_instance_delete() deletes an instance.  Before calling
12033  * scf_instance_delete(), though, we make sure the instance isn't
12034  * running and delete dependencies in other entities which the instance
12035  * declared as "dependents".  If there are dependencies which were
12036  * created for other entities, then instead of deleting the instance we
12037  * make it "empty" by deleting all other property groups and all
12038  * snapshots.
12039  *
12040  * lscf_instance_delete() verifies that there is no external dependency pgs
12041  * before suppressing the instance. If there is, then we must not remove them
12042  * now in case the instance is re-created otherwise the dependencies would be
12043  * lost. The external dependency pgs will be removed if the dependencies are
12044  * removed.
12045  *
12046  * Returns:
12047  *  DELETE_FAILURE		on failure
12048  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12049  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12050  */
12051 static int
12052 lscf_instance_delete(scf_instance_t *inst, int force)
12053 {
12054 	scf_propertygroup_t *pg;
12055 	scf_snapshot_t *snap;
12056 	scf_iter_t *iter;
12057 	int err;
12058 	int external = 0;
12059 
12060 	/* If we're not forcing and the instance is running, refuse. */
12061 	if (!force && inst_is_running(inst)) {
12062 		char *fmri;
12063 
12064 		fmri = safe_malloc(max_scf_fmri_len + 1);
12065 
12066 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12067 			scfdie();
12068 
12069 		semerr(gettext("Instance %s may be running.  "
12070 		    "Use delete -f if it is not.\n"), fmri);
12071 
12072 		free(fmri);
12073 		return (DELETE_FAILURE);
12074 	}
12075 
12076 	pg = scf_pg_create(g_hndl);
12077 	if (pg == NULL)
12078 		scfdie();
12079 
12080 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12081 		(void) delete_dependents(pg);
12082 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12083 		scfdie();
12084 
12085 	scf_pg_destroy(pg);
12086 
12087 	/*
12088 	 * If the instance has some external dependencies then we must
12089 	 * keep them in case the instance is reimported otherwise the
12090 	 * dependencies would be lost on reimport.
12091 	 */
12092 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12093 	    (pg = scf_pg_create(g_hndl)) == NULL)
12094 		scfdie();
12095 
12096 	if (scf_iter_instance_pgs(iter, inst) < 0)
12097 		scfdie();
12098 
12099 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12100 		if (pg_is_external_dependency(pg)) {
12101 			external = 1;
12102 			continue;
12103 		}
12104 
12105 		if (scf_pg_delete(pg) != 0) {
12106 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12107 				scfdie();
12108 			else {
12109 				semerr(emsg_permission_denied);
12110 
12111 				(void) scf_iter_destroy(iter);
12112 				(void) scf_pg_destroy(pg);
12113 				return (DELETE_FAILURE);
12114 			}
12115 		}
12116 	}
12117 
12118 	if (err == -1)
12119 		scfdie();
12120 
12121 	(void) scf_iter_destroy(iter);
12122 	(void) scf_pg_destroy(pg);
12123 
12124 	if (external) {
12125 		/*
12126 		 * All the pgs have been deleted for the instance except
12127 		 * the ones holding the external dependencies.
12128 		 * For the job to be complete, we must also delete the
12129 		 * snapshots associated with the instance.
12130 		 */
12131 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12132 		    NULL)
12133 			scfdie();
12134 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12135 			scfdie();
12136 
12137 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12138 			scfdie();
12139 
12140 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12141 			if (_scf_snapshot_delete(snap) != 0) {
12142 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12143 					scfdie();
12144 
12145 				semerr(emsg_permission_denied);
12146 
12147 				(void) scf_iter_destroy(iter);
12148 				(void) scf_snapshot_destroy(snap);
12149 				return (DELETE_FAILURE);
12150 			}
12151 		}
12152 
12153 		if (err == -1)
12154 			scfdie();
12155 
12156 		(void) scf_iter_destroy(iter);
12157 		(void) scf_snapshot_destroy(snap);
12158 		return (DELETE_SUCCESS_EXTDEPS);
12159 	}
12160 
12161 	if (scf_instance_delete(inst) != 0) {
12162 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12163 			scfdie();
12164 
12165 		semerr(emsg_permission_denied);
12166 
12167 		return (DELETE_FAILURE);
12168 	}
12169 
12170 	return (DELETE_SUCCESS_NOEXTDEPS);
12171 }
12172 
12173 /*
12174  * lscf_service_delete() deletes a service.  Before calling
12175  * scf_service_delete(), though, we call lscf_instance_delete() for
12176  * each of the instances and delete dependencies in other entities
12177  * which were created as "dependents" of this service.  If there are
12178  * dependencies which were created for other entities, then we delete
12179  * all other property groups in the service and leave it as "empty".
12180  *
12181  * lscf_service_delete() verifies that there is no external dependency
12182  * pgs at the instance & service level before suppressing the service.
12183  * If there is, then we must not remove them now in case the service
12184  * is re-imported otherwise the dependencies would be lost. The external
12185  * dependency pgs will be removed if the dependencies are removed.
12186  *
12187  * Returns:
12188  *   DELETE_FAILURE		on failure
12189  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12190  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12191  */
12192 static int
12193 lscf_service_delete(scf_service_t *svc, int force)
12194 {
12195 	int r;
12196 	scf_instance_t *inst;
12197 	scf_propertygroup_t *pg;
12198 	scf_iter_t *iter;
12199 	int ret;
12200 	int external = 0;
12201 
12202 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12203 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12204 	    (iter = scf_iter_create(g_hndl)) == NULL)
12205 		scfdie();
12206 
12207 	if (scf_iter_service_instances(iter, svc) != 0)
12208 		scfdie();
12209 
12210 	for (r = scf_iter_next_instance(iter, inst);
12211 	    r == 1;
12212 	    r = scf_iter_next_instance(iter, inst)) {
12213 
12214 		ret = lscf_instance_delete(inst, force);
12215 		if (ret == DELETE_FAILURE) {
12216 			scf_iter_destroy(iter);
12217 			scf_pg_destroy(pg);
12218 			scf_instance_destroy(inst);
12219 			return (DELETE_FAILURE);
12220 		}
12221 
12222 		/*
12223 		 * Record the fact that there is some external dependencies
12224 		 * at the instance level.
12225 		 */
12226 		if (ret == DELETE_SUCCESS_EXTDEPS)
12227 			external |= 1;
12228 	}
12229 
12230 	if (r != 0)
12231 		scfdie();
12232 
12233 	/* Delete dependency property groups in dependent services. */
12234 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12235 		(void) delete_dependents(pg);
12236 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12237 		scfdie();
12238 
12239 	scf_iter_destroy(iter);
12240 	scf_pg_destroy(pg);
12241 	scf_instance_destroy(inst);
12242 
12243 	/*
12244 	 * If the service has some external dependencies then we don't
12245 	 * want to remove them in case the service is re-imported.
12246 	 */
12247 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12248 	    (iter = scf_iter_create(g_hndl)) == NULL)
12249 		scfdie();
12250 
12251 	if (scf_iter_service_pgs(iter, svc) < 0)
12252 		scfdie();
12253 
12254 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12255 		if (pg_is_external_dependency(pg)) {
12256 			external |= 2;
12257 			continue;
12258 		}
12259 
12260 		if (scf_pg_delete(pg) != 0) {
12261 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12262 				scfdie();
12263 			else {
12264 				semerr(emsg_permission_denied);
12265 
12266 				(void) scf_iter_destroy(iter);
12267 				(void) scf_pg_destroy(pg);
12268 				return (DELETE_FAILURE);
12269 			}
12270 		}
12271 	}
12272 
12273 	if (r == -1)
12274 		scfdie();
12275 
12276 	(void) scf_iter_destroy(iter);
12277 	(void) scf_pg_destroy(pg);
12278 
12279 	if (external != 0)
12280 		return (DELETE_SUCCESS_EXTDEPS);
12281 
12282 	if (scf_service_delete(svc) == 0)
12283 		return (DELETE_SUCCESS_NOEXTDEPS);
12284 
12285 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12286 		scfdie();
12287 
12288 	semerr(emsg_permission_denied);
12289 	return (DELETE_FAILURE);
12290 }
12291 
12292 static int
12293 delete_callback(void *data, scf_walkinfo_t *wip)
12294 {
12295 	int force = (int)data;
12296 
12297 	if (wip->inst != NULL)
12298 		(void) lscf_instance_delete(wip->inst, force);
12299 	else
12300 		(void) lscf_service_delete(wip->svc, force);
12301 
12302 	return (0);
12303 }
12304 
12305 void
12306 lscf_delete(const char *fmri, int force)
12307 {
12308 	scf_service_t *svc;
12309 	scf_instance_t *inst;
12310 	int ret;
12311 
12312 	lscf_prep_hndl();
12313 
12314 	if (cur_snap != NULL) {
12315 		if (!snaplevel_is_instance(cur_level)) {
12316 			char *buf;
12317 
12318 			buf = safe_malloc(max_scf_name_len + 1);
12319 			if (scf_instance_get_name(cur_inst, buf,
12320 			    max_scf_name_len + 1) >= 0) {
12321 				if (strcmp(buf, fmri) == 0) {
12322 					semerr(emsg_cant_modify_snapshots);
12323 					free(buf);
12324 					return;
12325 				}
12326 			} else if (scf_error() != SCF_ERROR_DELETED) {
12327 				scfdie();
12328 			}
12329 			free(buf);
12330 		}
12331 	} else if (cur_inst != NULL) {
12332 		/* EMPTY */;
12333 	} else if (cur_svc != NULL) {
12334 		inst = scf_instance_create(g_hndl);
12335 		if (inst == NULL)
12336 			scfdie();
12337 
12338 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12339 		    SCF_SUCCESS) {
12340 			(void) lscf_instance_delete(inst, force);
12341 			scf_instance_destroy(inst);
12342 			return;
12343 		}
12344 
12345 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12346 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12347 			scfdie();
12348 
12349 		scf_instance_destroy(inst);
12350 	} else {
12351 		assert(cur_scope != NULL);
12352 
12353 		svc = scf_service_create(g_hndl);
12354 		if (svc == NULL)
12355 			scfdie();
12356 
12357 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12358 		    SCF_SUCCESS) {
12359 			(void) lscf_service_delete(svc, force);
12360 			scf_service_destroy(svc);
12361 			return;
12362 		}
12363 
12364 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12365 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12366 			scfdie();
12367 
12368 		scf_service_destroy(svc);
12369 	}
12370 
12371 	/*
12372 	 * Match FMRI to entity.
12373 	 */
12374 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12375 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12376 		semerr(gettext("Failed to walk instances: %s\n"),
12377 		    scf_strerror(ret));
12378 	}
12379 }
12380 
12381 
12382 
12383 /*
12384  * :properties commands.  These all end with "pg" or "prop" and generally
12385  * operate on the currently selected entity.
12386  */
12387 
12388 /*
12389  * Property listing.  List the property groups, properties, their types and
12390  * their values for the currently selected entity.
12391  */
12392 static void
12393 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12394 {
12395 	char *buf;
12396 	uint32_t flags;
12397 
12398 	buf = safe_malloc(max_scf_pg_type_len + 1);
12399 
12400 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12401 		scfdie();
12402 
12403 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12404 		scfdie();
12405 
12406 	safe_printf("%-*s  %s", namewidth, name, buf);
12407 
12408 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12409 		safe_printf("\tNONPERSISTENT");
12410 
12411 	safe_printf("\n");
12412 
12413 	free(buf);
12414 }
12415 
12416 static boolean_t
12417 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12418 {
12419 	if (scf_property_get_value(prop, val) == 0) {
12420 		return (B_FALSE);
12421 	} else {
12422 		switch (scf_error()) {
12423 		case SCF_ERROR_NOT_FOUND:
12424 			return (B_FALSE);
12425 		case SCF_ERROR_PERMISSION_DENIED:
12426 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12427 			return (B_TRUE);
12428 		default:
12429 			scfdie();
12430 			/*NOTREACHED*/
12431 		}
12432 	}
12433 }
12434 
12435 static void
12436 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12437 {
12438 	scf_iter_t *iter;
12439 	scf_value_t *val;
12440 	const char *type;
12441 	int multiple_strings = 0;
12442 	int ret;
12443 
12444 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12445 	    (val = scf_value_create(g_hndl)) == NULL)
12446 		scfdie();
12447 
12448 	type = prop_to_typestr(prop);
12449 	assert(type != NULL);
12450 
12451 	safe_printf("%-*s  %-7s ", len, name, type);
12452 
12453 	if (prop_has_multiple_values(prop, val) &&
12454 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12455 	    scf_value_type(val) == SCF_TYPE_USTRING))
12456 		multiple_strings = 1;
12457 
12458 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12459 		scfdie();
12460 
12461 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12462 		char *buf;
12463 		ssize_t vlen, szret;
12464 
12465 		vlen = scf_value_get_as_string(val, NULL, 0);
12466 		if (vlen < 0)
12467 			scfdie();
12468 
12469 		buf = safe_malloc(vlen + 1);
12470 
12471 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12472 		if (szret < 0)
12473 			scfdie();
12474 		assert(szret <= vlen);
12475 
12476 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12477 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12478 			safe_printf(" \"");
12479 			(void) quote_and_print(buf, stdout, 0);
12480 			(void) putchar('"');
12481 			if (ferror(stdout)) {
12482 				(void) putchar('\n');
12483 				uu_die(gettext("Error writing to stdout.\n"));
12484 			}
12485 		} else {
12486 			safe_printf(" %s", buf);
12487 		}
12488 
12489 		free(buf);
12490 	}
12491 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12492 		scfdie();
12493 
12494 	if (putchar('\n') != '\n')
12495 		uu_die(gettext("Could not output newline"));
12496 }
12497 
12498 /*
12499  * Outputs template property group info for the describe subcommand.
12500  * If 'templates' == 2, verbose output is printed in the format expected
12501  * for describe -v, which includes all templates fields.  If pg is
12502  * not NULL, we're describing the template data, not an existing property
12503  * group, and formatting should be appropriate for describe -t.
12504  */
12505 static void
12506 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12507 {
12508 	char *buf;
12509 	uint8_t required;
12510 	scf_property_t *stability_prop;
12511 	scf_value_t *stability_val;
12512 
12513 	if (templates == 0)
12514 		return;
12515 
12516 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12517 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12518 		scfdie();
12519 
12520 	if (templates == 2 && pg != NULL) {
12521 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12522 		    stability_prop) == 0) {
12523 			if (prop_check_type(stability_prop,
12524 			    SCF_TYPE_ASTRING) == 0 &&
12525 			    prop_get_val(stability_prop, stability_val) == 0) {
12526 				char *stability;
12527 
12528 				stability = safe_malloc(max_scf_value_len + 1);
12529 
12530 				if (scf_value_get_astring(stability_val,
12531 				    stability, max_scf_value_len + 1) == -1 &&
12532 				    scf_error() != SCF_ERROR_NOT_FOUND)
12533 					scfdie();
12534 
12535 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12536 				    gettext("stability"), stability);
12537 
12538 				free(stability);
12539 			}
12540 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12541 			scfdie();
12542 	}
12543 
12544 	scf_property_destroy(stability_prop);
12545 	scf_value_destroy(stability_val);
12546 
12547 	if (pgt == NULL)
12548 		return;
12549 
12550 	if (pg == NULL || templates == 2) {
12551 		/* print type info only if scf_tmpl_pg_name succeeds */
12552 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12553 			if (pg != NULL)
12554 				safe_printf("%s", TMPL_INDENT);
12555 			safe_printf("%s: ", gettext("name"));
12556 			safe_printf("%s\n", buf);
12557 			free(buf);
12558 		}
12559 
12560 		/* print type info only if scf_tmpl_pg_type succeeds */
12561 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12562 			if (pg != NULL)
12563 				safe_printf("%s", TMPL_INDENT);
12564 			safe_printf("%s: ", gettext("type"));
12565 			safe_printf("%s\n", buf);
12566 			free(buf);
12567 		}
12568 	}
12569 
12570 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12571 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12572 		    required ? "true" : "false");
12573 
12574 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12575 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12576 		    buf);
12577 		free(buf);
12578 	}
12579 
12580 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12581 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12582 		    buf);
12583 		free(buf);
12584 	}
12585 
12586 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12587 		if (templates == 2)
12588 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12589 			    gettext("description"), buf);
12590 		else
12591 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12592 		free(buf);
12593 	}
12594 
12595 }
12596 
12597 /*
12598  * With as_value set to true, indent as appropriate for the value level.
12599  * If false, indent to appropriate level for inclusion in constraint
12600  * or choice printout.
12601  */
12602 static void
12603 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12604     int as_value)
12605 {
12606 	char *buf;
12607 
12608 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12609 		if (as_value == 0)
12610 			safe_printf("%s", TMPL_CHOICE_INDENT);
12611 		else
12612 			safe_printf("%s", TMPL_INDENT);
12613 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12614 		free(buf);
12615 	}
12616 
12617 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12618 		if (as_value == 0)
12619 			safe_printf("%s", TMPL_CHOICE_INDENT);
12620 		else
12621 			safe_printf("%s", TMPL_INDENT);
12622 		safe_printf("%s: %s\n", gettext("value description"), buf);
12623 		free(buf);
12624 	}
12625 }
12626 
12627 static void
12628 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12629 {
12630 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12631 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12632 	safe_printf("%s\n", val_buf);
12633 
12634 	print_template_value_details(prt, val_buf, 1);
12635 }
12636 
12637 static void
12638 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12639 {
12640 	int i, printed = 0;
12641 	scf_values_t values;
12642 	scf_count_ranges_t c_ranges;
12643 	scf_int_ranges_t i_ranges;
12644 
12645 	printed = 0;
12646 	i = 0;
12647 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12648 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12649 		    gettext("value constraints"));
12650 		printed++;
12651 		for (i = 0; i < values.value_count; ++i) {
12652 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12653 			    gettext("value name"), values.values_as_strings[i]);
12654 			if (verbose == 1)
12655 				print_template_value_details(prt,
12656 				    values.values_as_strings[i], 0);
12657 		}
12658 
12659 		scf_values_destroy(&values);
12660 	}
12661 
12662 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12663 		if (printed++ == 0)
12664 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12665 			    gettext("value constraints"));
12666 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12667 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12668 			    gettext("range"), c_ranges.scr_min[i],
12669 			    c_ranges.scr_max[i]);
12670 		}
12671 		scf_count_ranges_destroy(&c_ranges);
12672 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12673 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12674 		if (printed++ == 0)
12675 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12676 			    gettext("value constraints"));
12677 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12678 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12679 			    gettext("range"), i_ranges.sir_min[i],
12680 			    i_ranges.sir_max[i]);
12681 		}
12682 		scf_int_ranges_destroy(&i_ranges);
12683 	}
12684 }
12685 
12686 static void
12687 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12688 {
12689 	int i = 0, printed = 0;
12690 	scf_values_t values;
12691 	scf_count_ranges_t c_ranges;
12692 	scf_int_ranges_t i_ranges;
12693 
12694 	printed = 0;
12695 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12696 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12697 		    gettext("value constraints"));
12698 		printed++;
12699 		for (i = 0; i < values.value_count; i++) {
12700 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12701 			    gettext("value name"), values.values_as_strings[i]);
12702 			if (verbose == 1)
12703 				print_template_value_details(prt,
12704 				    values.values_as_strings[i], 0);
12705 		}
12706 
12707 		scf_values_destroy(&values);
12708 	}
12709 
12710 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12711 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12712 			if (printed++ == 0)
12713 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12714 				    gettext("value choices"));
12715 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12716 			    gettext("range"), c_ranges.scr_min[i],
12717 			    c_ranges.scr_max[i]);
12718 		}
12719 		scf_count_ranges_destroy(&c_ranges);
12720 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12721 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12722 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12723 			if (printed++ == 0)
12724 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12725 				    gettext("value choices"));
12726 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12727 			    gettext("range"), i_ranges.sir_min[i],
12728 			    i_ranges.sir_max[i]);
12729 		}
12730 		scf_int_ranges_destroy(&i_ranges);
12731 	}
12732 }
12733 
12734 static void
12735 list_values_by_template(scf_prop_tmpl_t *prt)
12736 {
12737 	print_template_constraints(prt, 1);
12738 	print_template_choices(prt, 1);
12739 }
12740 
12741 static void
12742 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
12743 {
12744 	char *val_buf;
12745 	scf_iter_t *iter;
12746 	scf_value_t *val;
12747 	int ret;
12748 
12749 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12750 	    (val = scf_value_create(g_hndl)) == NULL)
12751 		scfdie();
12752 
12753 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12754 		scfdie();
12755 
12756 	val_buf = safe_malloc(max_scf_value_len + 1);
12757 
12758 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12759 		if (scf_value_get_as_string(val, val_buf,
12760 		    max_scf_value_len + 1) < 0)
12761 			scfdie();
12762 
12763 		print_template_value(prt, val_buf);
12764 	}
12765 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12766 		scfdie();
12767 	free(val_buf);
12768 
12769 	print_template_constraints(prt, 0);
12770 	print_template_choices(prt, 0);
12771 
12772 }
12773 
12774 /*
12775  * Outputs property info for the describe subcommand
12776  * Verbose output if templates == 2, -v option of svccfg describe
12777  * Displays template data if prop is not NULL, -t option of svccfg describe
12778  */
12779 static void
12780 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
12781 {
12782 	char *buf;
12783 	uint8_t u_buf;
12784 	int i;
12785 	uint64_t min, max;
12786 	scf_values_t values;
12787 
12788 	if (prt == NULL || templates == 0)
12789 		return;
12790 
12791 	if (prop == NULL) {
12792 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
12793 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
12794 			safe_printf("%s\n", buf);
12795 			free(buf);
12796 		} else
12797 			safe_printf("(%s)\n", gettext("any"));
12798 	}
12799 
12800 	if (prop == NULL || templates == 2) {
12801 		if (prop != NULL)
12802 			safe_printf("%s", TMPL_INDENT);
12803 		else
12804 			safe_printf("%s", TMPL_VALUE_INDENT);
12805 		safe_printf("%s: ", gettext("type"));
12806 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
12807 			safe_printf("%s\n", buf);
12808 			free(buf);
12809 		} else
12810 			safe_printf("(%s)\n", gettext("any"));
12811 	}
12812 
12813 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
12814 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12815 		    u_buf ? "true" : "false");
12816 
12817 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
12818 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12819 		    buf);
12820 		free(buf);
12821 	}
12822 
12823 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
12824 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
12825 		    buf);
12826 		free(buf);
12827 	}
12828 
12829 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
12830 		safe_printf("%s%s\n", TMPL_INDENT, buf);
12831 		free(buf);
12832 	}
12833 
12834 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
12835 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
12836 		    scf_tmpl_visibility_to_string(u_buf));
12837 
12838 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
12839 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12840 		    gettext("minimum number of values"), min);
12841 		if (max == ULLONG_MAX) {
12842 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12843 			    gettext("maximum number of values"),
12844 			    gettext("unlimited"));
12845 		} else {
12846 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12847 			    gettext("maximum number of values"), max);
12848 		}
12849 	}
12850 
12851 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
12852 		for (i = 0; i < values.value_count; i++) {
12853 			if (i == 0) {
12854 				safe_printf("%s%s:", TMPL_INDENT,
12855 				    gettext("internal separators"));
12856 			}
12857 			safe_printf(" \"%s\"", values.values_as_strings[i]);
12858 		}
12859 		safe_printf("\n");
12860 	}
12861 
12862 	if (templates != 2)
12863 		return;
12864 
12865 	if (prop != NULL)
12866 		list_values_tmpl(prt, prop);
12867 	else
12868 		list_values_by_template(prt);
12869 }
12870 
12871 static char *
12872 read_astring(scf_propertygroup_t *pg, const char *prop_name)
12873 {
12874 	char *rv;
12875 
12876 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
12877 	if (rv == NULL) {
12878 		switch (scf_error()) {
12879 		case SCF_ERROR_NOT_FOUND:
12880 			break;
12881 		default:
12882 			scfdie();
12883 		}
12884 	}
12885 	return (rv);
12886 }
12887 
12888 static void
12889 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
12890 {
12891 	size_t doc_len;
12892 	size_t man_len;
12893 	char *pg_name;
12894 	char *text = NULL;
12895 	int rv;
12896 
12897 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
12898 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
12899 	pg_name = safe_malloc(max_scf_name_len + 1);
12900 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
12901 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
12902 			scfdie();
12903 		}
12904 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
12905 			/* Display doc_link and and uri */
12906 			safe_printf("%s%s:\n", TMPL_INDENT,
12907 			    gettext("doc_link"));
12908 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
12909 			if (text != NULL) {
12910 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12911 				    TMPL_INDENT, gettext("name"), text);
12912 				uu_free(text);
12913 			}
12914 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
12915 			if (text != NULL) {
12916 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
12917 				    gettext("uri"), text);
12918 				uu_free(text);
12919 			}
12920 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
12921 		    man_len) == 0) {
12922 			/* Display manpage title, section and path */
12923 			safe_printf("%s%s:\n", TMPL_INDENT,
12924 			    gettext("manpage"));
12925 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
12926 			if (text != NULL) {
12927 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12928 				    TMPL_INDENT, gettext("title"), text);
12929 				uu_free(text);
12930 			}
12931 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
12932 			if (text != NULL) {
12933 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12934 				    TMPL_INDENT, gettext("section"), text);
12935 				uu_free(text);
12936 			}
12937 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
12938 			if (text != NULL) {
12939 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12940 				    TMPL_INDENT, gettext("manpath"), text);
12941 				uu_free(text);
12942 			}
12943 		}
12944 	}
12945 	if (rv == -1)
12946 		scfdie();
12947 
12948 done:
12949 	free(pg_name);
12950 }
12951 
12952 static void
12953 list_entity_tmpl(int templates)
12954 {
12955 	char *common_name = NULL;
12956 	char *description = NULL;
12957 	char *locale = NULL;
12958 	scf_iter_t *iter;
12959 	scf_propertygroup_t *pg;
12960 	scf_property_t *prop;
12961 	int r;
12962 	scf_value_t *val;
12963 
12964 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12965 	    (prop = scf_property_create(g_hndl)) == NULL ||
12966 	    (val = scf_value_create(g_hndl)) == NULL ||
12967 	    (iter = scf_iter_create(g_hndl)) == NULL)
12968 		scfdie();
12969 
12970 	locale = setlocale(LC_MESSAGES, NULL);
12971 
12972 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
12973 		common_name = safe_malloc(max_scf_value_len + 1);
12974 
12975 		/* Try both the current locale and the "C" locale. */
12976 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
12977 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
12978 		    scf_pg_get_property(pg, "C", prop) == 0)) {
12979 			if (prop_get_val(prop, val) == 0 &&
12980 			    scf_value_get_ustring(val, common_name,
12981 			    max_scf_value_len + 1) != -1) {
12982 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12983 				    gettext("common name"), common_name);
12984 			}
12985 		}
12986 	}
12987 
12988 	/*
12989 	 * Do description, manpages, and doc links if templates == 2.
12990 	 */
12991 	if (templates == 2) {
12992 		/* Get the description. */
12993 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
12994 			description = safe_malloc(max_scf_value_len + 1);
12995 
12996 			/* Try both the current locale and the "C" locale. */
12997 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
12998 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
12999 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13000 				if (prop_get_val(prop, val) == 0 &&
13001 				    scf_value_get_ustring(val, description,
13002 				    max_scf_value_len + 1) != -1) {
13003 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13004 					    gettext("description"),
13005 					    description);
13006 				}
13007 			}
13008 		}
13009 
13010 		/* Process doc_link & manpage elements. */
13011 		if (cur_level != NULL) {
13012 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13013 			    SCF_GROUP_TEMPLATE);
13014 		} else if (cur_inst != NULL) {
13015 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13016 			    SCF_GROUP_TEMPLATE);
13017 		} else {
13018 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13019 			    SCF_GROUP_TEMPLATE);
13020 		}
13021 		if (r == 0) {
13022 			display_documentation(iter, pg);
13023 		}
13024 	}
13025 
13026 	free(common_name);
13027 	free(description);
13028 	scf_pg_destroy(pg);
13029 	scf_property_destroy(prop);
13030 	scf_value_destroy(val);
13031 	scf_iter_destroy(iter);
13032 }
13033 
13034 static void
13035 listtmpl(const char *pattern, int templates)
13036 {
13037 	scf_pg_tmpl_t *pgt;
13038 	scf_prop_tmpl_t *prt;
13039 	char *snapbuf = NULL;
13040 	char *fmribuf;
13041 	char *pg_name = NULL, *prop_name = NULL;
13042 	ssize_t prop_name_size;
13043 	char *qual_prop_name;
13044 	char *search_name;
13045 	int listed = 0;
13046 
13047 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13048 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13049 		scfdie();
13050 
13051 	fmribuf = safe_malloc(max_scf_name_len + 1);
13052 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13053 
13054 	if (cur_snap != NULL) {
13055 		snapbuf = safe_malloc(max_scf_name_len + 1);
13056 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13057 		    max_scf_name_len + 1) < 0)
13058 			scfdie();
13059 	}
13060 
13061 	if (cur_inst != NULL) {
13062 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13063 		    max_scf_name_len + 1) < 0)
13064 			scfdie();
13065 	} else if (cur_svc != NULL) {
13066 		if (scf_service_to_fmri(cur_svc, fmribuf,
13067 		    max_scf_name_len + 1) < 0)
13068 			scfdie();
13069 	} else
13070 		abort();
13071 
13072 	/* If pattern is specified, we want to list only those items. */
13073 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13074 		listed = 0;
13075 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13076 		    fnmatch(pattern, pg_name, 0) == 0)) {
13077 			list_pg_tmpl(pgt, NULL, templates);
13078 			listed++;
13079 		}
13080 
13081 		scf_tmpl_prop_reset(prt);
13082 
13083 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13084 			search_name = NULL;
13085 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13086 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13087 				if (snprintf(qual_prop_name,
13088 				    max_scf_name_len + 1, "%s/%s",
13089 				    pg_name, prop_name) >=
13090 				    max_scf_name_len + 1) {
13091 					prop_name_size = -1;
13092 				} else {
13093 					search_name = qual_prop_name;
13094 				}
13095 			}
13096 			if (listed > 0 || pattern == NULL ||
13097 			    (prop_name_size > 0 &&
13098 			    fnmatch(pattern, search_name,
13099 			    FNM_PATHNAME) == 0))
13100 				list_prop_tmpl(prt, NULL, templates);
13101 			if (prop_name != NULL) {
13102 				free(prop_name);
13103 				prop_name = NULL;
13104 			}
13105 		}
13106 		if (pg_name != NULL) {
13107 			free(pg_name);
13108 			pg_name = NULL;
13109 		}
13110 	}
13111 
13112 	scf_tmpl_prop_destroy(prt);
13113 	scf_tmpl_pg_destroy(pgt);
13114 	free(snapbuf);
13115 	free(fmribuf);
13116 	free(qual_prop_name);
13117 }
13118 
13119 static void
13120 listprop(const char *pattern, int only_pgs, int templates)
13121 {
13122 	scf_propertygroup_t *pg;
13123 	scf_property_t *prop;
13124 	scf_iter_t *iter, *piter;
13125 	char *pgnbuf, *prnbuf, *ppnbuf;
13126 	scf_pg_tmpl_t *pgt, *pgtp;
13127 	scf_prop_tmpl_t *prt;
13128 
13129 	void **objects;
13130 	char **names;
13131 	void **tmpls;
13132 	int allocd, i;
13133 
13134 	int ret;
13135 	ssize_t pgnlen, prnlen, szret;
13136 	size_t max_len = 0;
13137 
13138 	if (cur_svc == NULL && cur_inst == NULL) {
13139 		semerr(emsg_entity_not_selected);
13140 		return;
13141 	}
13142 
13143 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13144 	    (prop = scf_property_create(g_hndl)) == NULL ||
13145 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13146 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13147 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13148 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13149 		scfdie();
13150 
13151 	prnbuf = safe_malloc(max_scf_name_len + 1);
13152 
13153 	if (cur_level != NULL)
13154 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13155 	else if (cur_inst != NULL)
13156 		ret = scf_iter_instance_pgs(iter, cur_inst);
13157 	else
13158 		ret = scf_iter_service_pgs(iter, cur_svc);
13159 	if (ret != 0) {
13160 		return;
13161 	}
13162 
13163 	/*
13164 	 * We want to only list items which match pattern, and we want the
13165 	 * second column to line up, so during the first pass we'll save
13166 	 * matching items, their names, and their templates in objects,
13167 	 * names, and tmpls, computing the maximum name length as we go,
13168 	 * and then we'll print them out.
13169 	 *
13170 	 * Note: We always keep an extra slot available so the array can be
13171 	 * NULL-terminated.
13172 	 */
13173 	i = 0;
13174 	allocd = 1;
13175 	objects = safe_malloc(sizeof (*objects));
13176 	names = safe_malloc(sizeof (*names));
13177 	tmpls = safe_malloc(sizeof (*tmpls));
13178 
13179 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13180 		int new_pg = 0;
13181 		int print_props = 0;
13182 		pgtp = NULL;
13183 
13184 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13185 		if (pgnlen < 0)
13186 			scfdie();
13187 
13188 		pgnbuf = safe_malloc(pgnlen + 1);
13189 
13190 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13191 		if (szret < 0)
13192 			scfdie();
13193 		assert(szret <= pgnlen);
13194 
13195 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13196 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13197 				scfdie();
13198 			pgtp = NULL;
13199 		} else {
13200 			pgtp = pgt;
13201 		}
13202 
13203 		if (pattern == NULL ||
13204 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13205 			if (i+1 >= allocd) {
13206 				allocd *= 2;
13207 				objects = realloc(objects,
13208 				    sizeof (*objects) * allocd);
13209 				names =
13210 				    realloc(names, sizeof (*names) * allocd);
13211 				tmpls = realloc(tmpls,
13212 				    sizeof (*tmpls) * allocd);
13213 				if (objects == NULL || names == NULL ||
13214 				    tmpls == NULL)
13215 					uu_die(gettext("Out of memory"));
13216 			}
13217 			objects[i] = pg;
13218 			names[i] = pgnbuf;
13219 
13220 			if (pgtp == NULL)
13221 				tmpls[i] = NULL;
13222 			else
13223 				tmpls[i] = pgt;
13224 
13225 			++i;
13226 
13227 			if (pgnlen > max_len)
13228 				max_len = pgnlen;
13229 
13230 			new_pg = 1;
13231 			print_props = 1;
13232 		}
13233 
13234 		if (only_pgs) {
13235 			if (new_pg) {
13236 				pg = scf_pg_create(g_hndl);
13237 				if (pg == NULL)
13238 					scfdie();
13239 				pgt = scf_tmpl_pg_create(g_hndl);
13240 				if (pgt == NULL)
13241 					scfdie();
13242 			} else
13243 				free(pgnbuf);
13244 
13245 			continue;
13246 		}
13247 
13248 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13249 			scfdie();
13250 
13251 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13252 			prnlen = scf_property_get_name(prop, prnbuf,
13253 			    max_scf_name_len + 1);
13254 			if (prnlen < 0)
13255 				scfdie();
13256 
13257 			/* Will prepend the property group name and a slash. */
13258 			prnlen += pgnlen + 1;
13259 
13260 			ppnbuf = safe_malloc(prnlen + 1);
13261 
13262 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13263 			    prnbuf) < 0)
13264 				uu_die("snprintf");
13265 
13266 			if (pattern == NULL || print_props == 1 ||
13267 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13268 				if (i+1 >= allocd) {
13269 					allocd *= 2;
13270 					objects = realloc(objects,
13271 					    sizeof (*objects) * allocd);
13272 					names = realloc(names,
13273 					    sizeof (*names) * allocd);
13274 					tmpls = realloc(tmpls,
13275 					    sizeof (*tmpls) * allocd);
13276 					if (objects == NULL || names == NULL ||
13277 					    tmpls == NULL)
13278 						uu_die(gettext(
13279 						    "Out of memory"));
13280 				}
13281 
13282 				objects[i] = prop;
13283 				names[i] = ppnbuf;
13284 
13285 				if (pgtp != NULL) {
13286 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13287 					    prt, 0) < 0) {
13288 						if (scf_error() !=
13289 						    SCF_ERROR_NOT_FOUND)
13290 							scfdie();
13291 						tmpls[i] = NULL;
13292 					} else {
13293 						tmpls[i] = prt;
13294 					}
13295 				} else {
13296 					tmpls[i] = NULL;
13297 				}
13298 
13299 				++i;
13300 
13301 				if (prnlen > max_len)
13302 					max_len = prnlen;
13303 
13304 				prop = scf_property_create(g_hndl);
13305 				prt = scf_tmpl_prop_create(g_hndl);
13306 			} else {
13307 				free(ppnbuf);
13308 			}
13309 		}
13310 
13311 		if (new_pg) {
13312 			pg = scf_pg_create(g_hndl);
13313 			if (pg == NULL)
13314 				scfdie();
13315 			pgt = scf_tmpl_pg_create(g_hndl);
13316 			if (pgt == NULL)
13317 				scfdie();
13318 		} else
13319 			free(pgnbuf);
13320 	}
13321 	if (ret != 0)
13322 		scfdie();
13323 
13324 	objects[i] = NULL;
13325 
13326 	scf_pg_destroy(pg);
13327 	scf_tmpl_pg_destroy(pgt);
13328 	scf_property_destroy(prop);
13329 	scf_tmpl_prop_destroy(prt);
13330 
13331 	for (i = 0; objects[i] != NULL; ++i) {
13332 		if (strchr(names[i], '/') == NULL) {
13333 			/* property group */
13334 			pg = (scf_propertygroup_t *)objects[i];
13335 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13336 			list_pg_info(pg, names[i], max_len);
13337 			list_pg_tmpl(pgt, pg, templates);
13338 			free(names[i]);
13339 			scf_pg_destroy(pg);
13340 			if (pgt != NULL)
13341 				scf_tmpl_pg_destroy(pgt);
13342 		} else {
13343 			/* property */
13344 			prop = (scf_property_t *)objects[i];
13345 			prt = (scf_prop_tmpl_t *)tmpls[i];
13346 			list_prop_info(prop, names[i], max_len);
13347 			list_prop_tmpl(prt, prop, templates);
13348 			free(names[i]);
13349 			scf_property_destroy(prop);
13350 			if (prt != NULL)
13351 				scf_tmpl_prop_destroy(prt);
13352 		}
13353 	}
13354 
13355 	free(names);
13356 	free(objects);
13357 	free(tmpls);
13358 }
13359 
13360 void
13361 lscf_listpg(const char *pattern)
13362 {
13363 	lscf_prep_hndl();
13364 
13365 	listprop(pattern, 1, 0);
13366 }
13367 
13368 /*
13369  * Property group and property creation, setting, and deletion.  setprop (and
13370  * its alias, addprop) can either create a property group of a given type, or
13371  * it can create or set a property to a given type and list of values.
13372  */
13373 void
13374 lscf_addpg(const char *name, const char *type, const char *flags)
13375 {
13376 	scf_propertygroup_t *pg;
13377 	int ret;
13378 	uint32_t flgs = 0;
13379 	const char *cp;
13380 
13381 
13382 	lscf_prep_hndl();
13383 
13384 	if (cur_snap != NULL) {
13385 		semerr(emsg_cant_modify_snapshots);
13386 		return;
13387 	}
13388 
13389 	if (cur_inst == NULL && cur_svc == NULL) {
13390 		semerr(emsg_entity_not_selected);
13391 		return;
13392 	}
13393 
13394 	if (flags != NULL) {
13395 		for (cp = flags; *cp != '\0'; ++cp) {
13396 			switch (*cp) {
13397 			case 'P':
13398 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13399 				break;
13400 
13401 			case 'p':
13402 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13403 				break;
13404 
13405 			default:
13406 				semerr(gettext("Invalid property group flag "
13407 				    "%c."), *cp);
13408 				return;
13409 			}
13410 		}
13411 	}
13412 
13413 	pg = scf_pg_create(g_hndl);
13414 	if (pg == NULL)
13415 		scfdie();
13416 
13417 	if (cur_inst != NULL)
13418 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13419 	else
13420 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13421 
13422 	if (ret != SCF_SUCCESS) {
13423 		switch (scf_error()) {
13424 		case SCF_ERROR_INVALID_ARGUMENT:
13425 			semerr(gettext("Name, type, or flags are invalid.\n"));
13426 			break;
13427 
13428 		case SCF_ERROR_EXISTS:
13429 			semerr(gettext("Property group already exists.\n"));
13430 			break;
13431 
13432 		case SCF_ERROR_PERMISSION_DENIED:
13433 			semerr(emsg_permission_denied);
13434 			break;
13435 
13436 		case SCF_ERROR_BACKEND_ACCESS:
13437 			semerr(gettext("Backend refused access.\n"));
13438 			break;
13439 
13440 		default:
13441 			scfdie();
13442 		}
13443 	}
13444 
13445 	scf_pg_destroy(pg);
13446 
13447 	private_refresh();
13448 }
13449 
13450 void
13451 lscf_delpg(char *name)
13452 {
13453 	lscf_prep_hndl();
13454 
13455 	if (cur_snap != NULL) {
13456 		semerr(emsg_cant_modify_snapshots);
13457 		return;
13458 	}
13459 
13460 	if (cur_inst == NULL && cur_svc == NULL) {
13461 		semerr(emsg_entity_not_selected);
13462 		return;
13463 	}
13464 
13465 	if (strchr(name, '/') != NULL) {
13466 		semerr(emsg_invalid_pg_name, name);
13467 		return;
13468 	}
13469 
13470 	lscf_delprop(name);
13471 }
13472 
13473 /*
13474  * scf_delhash() is used to remove the property group related to the
13475  * hash entry for a specific manifest in the repository. pgname will be
13476  * constructed from the location of the manifest file. If deathrow isn't 0,
13477  * manifest file doesn't need to exist (manifest string will be used as
13478  * an absolute path).
13479  */
13480 void
13481 lscf_delhash(char *manifest, int deathrow)
13482 {
13483 	char *pgname;
13484 
13485 	if (cur_snap != NULL ||
13486 	    cur_inst != NULL || cur_svc != NULL) {
13487 		warn(gettext("error, an entity is selected\n"));
13488 		return;
13489 	}
13490 
13491 	/* select smf/manifest */
13492 	lscf_select(HASH_SVC);
13493 	/*
13494 	 * Translate the manifest file name to property name. In the deathrow
13495 	 * case, the manifest file does not need to exist.
13496 	 */
13497 	pgname = mhash_filename_to_propname(manifest,
13498 	    deathrow ? B_TRUE : B_FALSE);
13499 	if (pgname == NULL) {
13500 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13501 		return;
13502 	}
13503 	/* delete the hash property name */
13504 	lscf_delpg(pgname);
13505 }
13506 
13507 void
13508 lscf_listprop(const char *pattern)
13509 {
13510 	lscf_prep_hndl();
13511 
13512 	listprop(pattern, 0, 0);
13513 }
13514 
13515 int
13516 lscf_setprop(const char *pgname, const char *type, const char *value,
13517     const uu_list_t *values)
13518 {
13519 	scf_type_t ty, current_ty;
13520 	scf_service_t *svc;
13521 	scf_propertygroup_t *pg, *parent_pg;
13522 	scf_property_t *prop, *parent_prop;
13523 	scf_pg_tmpl_t *pgt;
13524 	scf_prop_tmpl_t *prt;
13525 	int ret, result = 0;
13526 	scf_transaction_t *tx;
13527 	scf_transaction_entry_t *e;
13528 	scf_value_t *v;
13529 	uu_list_walk_t *walk;
13530 	string_list_t *sp;
13531 	char *propname;
13532 	int req_quotes = 0;
13533 
13534 	lscf_prep_hndl();
13535 
13536 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13537 	    (svc = scf_service_create(g_hndl)) == NULL ||
13538 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13539 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13540 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13541 	    (prop = scf_property_create(g_hndl)) == NULL ||
13542 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13543 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13544 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13545 		scfdie();
13546 
13547 	if (cur_snap != NULL) {
13548 		semerr(emsg_cant_modify_snapshots);
13549 		goto fail;
13550 	}
13551 
13552 	if (cur_inst == NULL && cur_svc == NULL) {
13553 		semerr(emsg_entity_not_selected);
13554 		goto fail;
13555 	}
13556 
13557 	propname = strchr(pgname, '/');
13558 	if (propname == NULL) {
13559 		semerr(gettext("Property names must contain a `/'.\n"));
13560 		goto fail;
13561 	}
13562 
13563 	*propname = '\0';
13564 	++propname;
13565 
13566 	if (type != NULL) {
13567 		ty = string_to_type(type);
13568 		if (ty == SCF_TYPE_INVALID) {
13569 			semerr(gettext("Unknown type \"%s\".\n"), type);
13570 			goto fail;
13571 		}
13572 	}
13573 
13574 	if (cur_inst != NULL)
13575 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13576 	else
13577 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13578 	if (ret != SCF_SUCCESS) {
13579 		switch (scf_error()) {
13580 		case SCF_ERROR_NOT_FOUND:
13581 			semerr(emsg_no_such_pg, pgname);
13582 			goto fail;
13583 
13584 		case SCF_ERROR_INVALID_ARGUMENT:
13585 			semerr(emsg_invalid_pg_name, pgname);
13586 			goto fail;
13587 
13588 		default:
13589 			scfdie();
13590 			break;
13591 		}
13592 	}
13593 
13594 	do {
13595 		if (scf_pg_update(pg) == -1)
13596 			scfdie();
13597 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13598 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13599 				scfdie();
13600 
13601 			semerr(emsg_permission_denied);
13602 			goto fail;
13603 		}
13604 
13605 		ret = scf_pg_get_property(pg, propname, prop);
13606 		if (ret == SCF_SUCCESS) {
13607 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13608 				scfdie();
13609 
13610 			if (type == NULL)
13611 				ty = current_ty;
13612 			if (scf_transaction_property_change_type(tx, e,
13613 			    propname, ty) == -1)
13614 				scfdie();
13615 
13616 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13617 			/* Infer the type, if possible. */
13618 			if (type == NULL) {
13619 				/*
13620 				 * First check if we're an instance and the
13621 				 * property is set on the service.
13622 				 */
13623 				if (cur_inst != NULL &&
13624 				    scf_instance_get_parent(cur_inst,
13625 				    svc) == 0 &&
13626 				    scf_service_get_pg(cur_svc, pgname,
13627 				    parent_pg) == 0 &&
13628 				    scf_pg_get_property(parent_pg, propname,
13629 				    parent_prop) == 0 &&
13630 				    scf_property_type(parent_prop,
13631 				    &current_ty) == 0) {
13632 					ty = current_ty;
13633 
13634 				/* Then check for a type set in a template. */
13635 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13636 				    0) == 0 &&
13637 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13638 				    0) == 0 &&
13639 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13640 					ty = current_ty;
13641 
13642 				/* If type can't be inferred, fail. */
13643 				} else {
13644 					semerr(gettext("Type required for new "
13645 					    "properties.\n"));
13646 					goto fail;
13647 				}
13648 			}
13649 			if (scf_transaction_property_new(tx, e, propname,
13650 			    ty) == -1)
13651 				scfdie();
13652 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13653 			semerr(emsg_invalid_prop_name, propname);
13654 			goto fail;
13655 		} else {
13656 			scfdie();
13657 		}
13658 
13659 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13660 			req_quotes = 1;
13661 
13662 		if (value != NULL) {
13663 			v = string_to_value(value, ty, 0);
13664 
13665 			if (v == NULL)
13666 				goto fail;
13667 
13668 			ret = scf_entry_add_value(e, v);
13669 			assert(ret == SCF_SUCCESS);
13670 		} else {
13671 			assert(values != NULL);
13672 
13673 			walk = uu_list_walk_start((uu_list_t *)values,
13674 			    UU_DEFAULT);
13675 			if (walk == NULL)
13676 				uu_die(gettext("Could not walk list"));
13677 
13678 			for (sp = uu_list_walk_next(walk); sp != NULL;
13679 			    sp = uu_list_walk_next(walk)) {
13680 				v = string_to_value(sp->str, ty, req_quotes);
13681 
13682 				if (v == NULL) {
13683 					scf_entry_destroy_children(e);
13684 					goto fail;
13685 				}
13686 
13687 				ret = scf_entry_add_value(e, v);
13688 				assert(ret == SCF_SUCCESS);
13689 			}
13690 			uu_list_walk_end(walk);
13691 		}
13692 		result = scf_transaction_commit(tx);
13693 
13694 		scf_transaction_reset(tx);
13695 		scf_entry_destroy_children(e);
13696 	} while (result == 0);
13697 
13698 	if (result < 0) {
13699 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13700 			scfdie();
13701 
13702 		semerr(emsg_permission_denied);
13703 		goto fail;
13704 	}
13705 
13706 	ret = 0;
13707 
13708 	private_refresh();
13709 
13710 	goto cleanup;
13711 
13712 fail:
13713 	ret = -1;
13714 
13715 cleanup:
13716 	scf_transaction_destroy(tx);
13717 	scf_entry_destroy(e);
13718 	scf_service_destroy(svc);
13719 	scf_pg_destroy(parent_pg);
13720 	scf_pg_destroy(pg);
13721 	scf_property_destroy(parent_prop);
13722 	scf_property_destroy(prop);
13723 	scf_tmpl_pg_destroy(pgt);
13724 	scf_tmpl_prop_destroy(prt);
13725 
13726 	return (ret);
13727 }
13728 
13729 void
13730 lscf_delprop(char *pgn)
13731 {
13732 	char *slash, *pn;
13733 	scf_propertygroup_t *pg;
13734 	scf_transaction_t *tx;
13735 	scf_transaction_entry_t *e;
13736 	int ret;
13737 
13738 
13739 	lscf_prep_hndl();
13740 
13741 	if (cur_snap != NULL) {
13742 		semerr(emsg_cant_modify_snapshots);
13743 		return;
13744 	}
13745 
13746 	if (cur_inst == NULL && cur_svc == NULL) {
13747 		semerr(emsg_entity_not_selected);
13748 		return;
13749 	}
13750 
13751 	pg = scf_pg_create(g_hndl);
13752 	if (pg == NULL)
13753 		scfdie();
13754 
13755 	slash = strchr(pgn, '/');
13756 	if (slash == NULL) {
13757 		pn = NULL;
13758 	} else {
13759 		*slash = '\0';
13760 		pn = slash + 1;
13761 	}
13762 
13763 	if (cur_inst != NULL)
13764 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
13765 	else
13766 		ret = scf_service_get_pg(cur_svc, pgn, pg);
13767 	if (ret != SCF_SUCCESS) {
13768 		switch (scf_error()) {
13769 		case SCF_ERROR_NOT_FOUND:
13770 			semerr(emsg_no_such_pg, pgn);
13771 			break;
13772 
13773 		case SCF_ERROR_INVALID_ARGUMENT:
13774 			semerr(emsg_invalid_pg_name, pgn);
13775 			break;
13776 
13777 		default:
13778 			scfdie();
13779 		}
13780 
13781 		scf_pg_destroy(pg);
13782 
13783 		return;
13784 	}
13785 
13786 	if (pn == NULL) {
13787 		/* Try to delete the property group. */
13788 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
13789 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13790 				scfdie();
13791 
13792 			semerr(emsg_permission_denied);
13793 		} else {
13794 			private_refresh();
13795 		}
13796 
13797 		scf_pg_destroy(pg);
13798 		return;
13799 	}
13800 
13801 	e = scf_entry_create(g_hndl);
13802 	tx = scf_transaction_create(g_hndl);
13803 
13804 	do {
13805 		if (scf_pg_update(pg) == -1)
13806 			scfdie();
13807 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13808 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13809 				scfdie();
13810 
13811 			semerr(emsg_permission_denied);
13812 			break;
13813 		}
13814 
13815 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
13816 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
13817 				semerr(gettext("No such property %s/%s.\n"),
13818 				    pgn, pn);
13819 				break;
13820 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13821 				semerr(emsg_invalid_prop_name, pn);
13822 				break;
13823 			} else {
13824 				scfdie();
13825 			}
13826 		}
13827 
13828 		ret = scf_transaction_commit(tx);
13829 
13830 		if (ret == 0)
13831 			scf_transaction_reset(tx);
13832 	} while (ret == 0);
13833 
13834 	if (ret < 0) {
13835 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13836 			scfdie();
13837 
13838 		semerr(emsg_permission_denied);
13839 	} else {
13840 		private_refresh();
13841 	}
13842 
13843 	scf_transaction_destroy(tx);
13844 	scf_entry_destroy(e);
13845 	scf_pg_destroy(pg);
13846 }
13847 
13848 /*
13849  * Property editing.
13850  */
13851 
13852 static int
13853 write_edit_script(FILE *strm)
13854 {
13855 	char *fmribuf;
13856 	ssize_t fmrilen;
13857 
13858 	scf_propertygroup_t *pg;
13859 	scf_property_t *prop;
13860 	scf_value_t *val;
13861 	scf_type_t ty;
13862 	int ret, result = 0;
13863 	scf_iter_t *iter, *piter, *viter;
13864 	char *buf, *tybuf, *pname;
13865 	const char *emsg_write_error;
13866 
13867 
13868 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
13869 
13870 
13871 	/* select fmri */
13872 	if (cur_inst != NULL) {
13873 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
13874 		if (fmrilen < 0)
13875 			scfdie();
13876 		fmribuf = safe_malloc(fmrilen + 1);
13877 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
13878 			scfdie();
13879 	} else {
13880 		assert(cur_svc != NULL);
13881 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
13882 		if (fmrilen < 0)
13883 			scfdie();
13884 		fmribuf = safe_malloc(fmrilen + 1);
13885 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
13886 			scfdie();
13887 	}
13888 
13889 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
13890 		warn(emsg_write_error, strerror(errno));
13891 		free(fmribuf);
13892 		return (-1);
13893 	}
13894 
13895 	free(fmribuf);
13896 
13897 
13898 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13899 	    (prop = scf_property_create(g_hndl)) == NULL ||
13900 	    (val = scf_value_create(g_hndl)) == NULL ||
13901 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13902 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13903 	    (viter = scf_iter_create(g_hndl)) == NULL)
13904 		scfdie();
13905 
13906 	buf = safe_malloc(max_scf_name_len + 1);
13907 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
13908 	pname = safe_malloc(max_scf_name_len + 1);
13909 
13910 	if (cur_inst != NULL)
13911 		ret = scf_iter_instance_pgs(iter, cur_inst);
13912 	else
13913 		ret = scf_iter_service_pgs(iter, cur_svc);
13914 	if (ret != SCF_SUCCESS)
13915 		scfdie();
13916 
13917 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13918 		int ret2;
13919 
13920 		/*
13921 		 * # delprop pg
13922 		 * # addpg pg type
13923 		 */
13924 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
13925 			scfdie();
13926 
13927 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
13928 			scfdie();
13929 
13930 		if (fprintf(strm, "# Property group \"%s\"\n"
13931 		    "# delprop %s\n"
13932 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
13933 			warn(emsg_write_error, strerror(errno));
13934 			result = -1;
13935 			goto out;
13936 		}
13937 
13938 		/* # setprop pg/prop = (values) */
13939 
13940 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13941 			scfdie();
13942 
13943 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
13944 			int first = 1;
13945 			int ret3;
13946 			int multiple;
13947 			int is_str;
13948 			scf_type_t bty;
13949 
13950 			if (scf_property_get_name(prop, pname,
13951 			    max_scf_name_len + 1) < 0)
13952 				scfdie();
13953 
13954 			if (scf_property_type(prop, &ty) != 0)
13955 				scfdie();
13956 
13957 			multiple = prop_has_multiple_values(prop, val);
13958 
13959 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13960 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
13961 			    < 0) {
13962 				warn(emsg_write_error, strerror(errno));
13963 				result = -1;
13964 				goto out;
13965 			}
13966 
13967 			(void) scf_type_base_type(ty, &bty);
13968 			is_str = (bty == SCF_TYPE_ASTRING);
13969 
13970 			if (scf_iter_property_values(viter, prop) !=
13971 			    SCF_SUCCESS)
13972 				scfdie();
13973 
13974 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
13975 				char *buf;
13976 				ssize_t buflen;
13977 
13978 				buflen = scf_value_get_as_string(val, NULL, 0);
13979 				if (buflen < 0)
13980 					scfdie();
13981 
13982 				buf = safe_malloc(buflen + 1);
13983 
13984 				if (scf_value_get_as_string(val, buf,
13985 				    buflen + 1) < 0)
13986 					scfdie();
13987 
13988 				if (first)
13989 					first = 0;
13990 				else {
13991 					if (putc(' ', strm) != ' ') {
13992 						warn(emsg_write_error,
13993 						    strerror(errno));
13994 						result = -1;
13995 						goto out;
13996 					}
13997 				}
13998 
13999 				if ((is_str && multiple) ||
14000 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14001 					(void) putc('"', strm);
14002 					(void) quote_and_print(buf, strm, 1);
14003 					(void) putc('"', strm);
14004 
14005 					if (ferror(strm)) {
14006 						warn(emsg_write_error,
14007 						    strerror(errno));
14008 						result = -1;
14009 						goto out;
14010 					}
14011 				} else {
14012 					if (fprintf(strm, "%s", buf) < 0) {
14013 						warn(emsg_write_error,
14014 						    strerror(errno));
14015 						result = -1;
14016 						goto out;
14017 					}
14018 				}
14019 
14020 				free(buf);
14021 			}
14022 			if (ret3 < 0 &&
14023 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14024 				scfdie();
14025 
14026 			/* Write closing paren if mult-value property */
14027 			if ((multiple && putc(')', strm) == EOF) ||
14028 
14029 			    /* Write final newline */
14030 			    fputc('\n', strm) == EOF) {
14031 				warn(emsg_write_error, strerror(errno));
14032 				result = -1;
14033 				goto out;
14034 			}
14035 		}
14036 		if (ret2 < 0)
14037 			scfdie();
14038 
14039 		if (fputc('\n', strm) == EOF) {
14040 			warn(emsg_write_error, strerror(errno));
14041 			result = -1;
14042 			goto out;
14043 		}
14044 	}
14045 	if (ret < 0)
14046 		scfdie();
14047 
14048 out:
14049 	free(pname);
14050 	free(tybuf);
14051 	free(buf);
14052 	scf_iter_destroy(viter);
14053 	scf_iter_destroy(piter);
14054 	scf_iter_destroy(iter);
14055 	scf_value_destroy(val);
14056 	scf_property_destroy(prop);
14057 	scf_pg_destroy(pg);
14058 
14059 	if (result == 0) {
14060 		if (fflush(strm) != 0) {
14061 			warn(emsg_write_error, strerror(errno));
14062 			return (-1);
14063 		}
14064 	}
14065 
14066 	return (result);
14067 }
14068 
14069 int
14070 lscf_editprop()
14071 {
14072 	char *buf, *editor;
14073 	size_t bufsz;
14074 	int tmpfd;
14075 	char tempname[] = TEMP_FILE_PATTERN;
14076 
14077 	lscf_prep_hndl();
14078 
14079 	if (cur_snap != NULL) {
14080 		semerr(emsg_cant_modify_snapshots);
14081 		return (-1);
14082 	}
14083 
14084 	if (cur_svc == NULL && cur_inst == NULL) {
14085 		semerr(emsg_entity_not_selected);
14086 		return (-1);
14087 	}
14088 
14089 	tmpfd = mkstemp(tempname);
14090 	if (tmpfd == -1) {
14091 		semerr(gettext("Could not create temporary file.\n"));
14092 		return (-1);
14093 	}
14094 
14095 	(void) strcpy(tempfilename, tempname);
14096 
14097 	tempfile = fdopen(tmpfd, "r+");
14098 	if (tempfile == NULL) {
14099 		warn(gettext("Could not create temporary file.\n"));
14100 		if (close(tmpfd) == -1)
14101 			warn(gettext("Could not close temporary file: %s.\n"),
14102 			    strerror(errno));
14103 
14104 		remove_tempfile();
14105 
14106 		return (-1);
14107 	}
14108 
14109 	if (write_edit_script(tempfile) == -1) {
14110 		remove_tempfile();
14111 		return (-1);
14112 	}
14113 
14114 	editor = getenv("EDITOR");
14115 	if (editor == NULL)
14116 		editor = "vi";
14117 
14118 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14119 	buf = safe_malloc(bufsz);
14120 
14121 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14122 		uu_die(gettext("Error creating editor command"));
14123 
14124 	if (system(buf) == -1) {
14125 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14126 		    strerror(errno));
14127 		free(buf);
14128 		remove_tempfile();
14129 		return (-1);
14130 	}
14131 
14132 	free(buf);
14133 
14134 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14135 
14136 	remove_tempfile();
14137 
14138 	return (0);
14139 }
14140 
14141 static void
14142 add_string(uu_list_t *strlist, const char *str)
14143 {
14144 	string_list_t *elem;
14145 	elem = safe_malloc(sizeof (*elem));
14146 	uu_list_node_init(elem, &elem->node, string_pool);
14147 	elem->str = safe_strdup(str);
14148 	if (uu_list_append(strlist, elem) != 0)
14149 		uu_die(gettext("libuutil error: %s\n"),
14150 		    uu_strerror(uu_error()));
14151 }
14152 
14153 static int
14154 remove_string(uu_list_t *strlist, const char *str)
14155 {
14156 	uu_list_walk_t	*elems;
14157 	string_list_t	*sp;
14158 
14159 	/*
14160 	 * Find the element that needs to be removed.
14161 	 */
14162 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14163 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14164 		if (strcmp(sp->str, str) == 0)
14165 			break;
14166 	}
14167 	uu_list_walk_end(elems);
14168 
14169 	/*
14170 	 * Returning 1 here as the value was not found, this
14171 	 * might not be an error.  Leave it to the caller to
14172 	 * decide.
14173 	 */
14174 	if (sp == NULL) {
14175 		return (1);
14176 	}
14177 
14178 	uu_list_remove(strlist, sp);
14179 
14180 	free(sp->str);
14181 	free(sp);
14182 
14183 	return (0);
14184 }
14185 
14186 /*
14187  * Get all property values that don't match the given glob pattern,
14188  * if a pattern is specified.
14189  */
14190 static void
14191 get_prop_values(scf_property_t *prop, uu_list_t *values,
14192     const char *pattern)
14193 {
14194 	scf_iter_t *iter;
14195 	scf_value_t *val;
14196 	int ret;
14197 
14198 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14199 	    (val = scf_value_create(g_hndl)) == NULL)
14200 		scfdie();
14201 
14202 	if (scf_iter_property_values(iter, prop) != 0)
14203 		scfdie();
14204 
14205 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14206 		char *buf;
14207 		ssize_t vlen, szret;
14208 
14209 		vlen = scf_value_get_as_string(val, NULL, 0);
14210 		if (vlen < 0)
14211 			scfdie();
14212 
14213 		buf = safe_malloc(vlen + 1);
14214 
14215 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14216 		if (szret < 0)
14217 			scfdie();
14218 		assert(szret <= vlen);
14219 
14220 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14221 			add_string(values, buf);
14222 
14223 		free(buf);
14224 	}
14225 
14226 	if (ret == -1)
14227 		scfdie();
14228 
14229 	scf_value_destroy(val);
14230 	scf_iter_destroy(iter);
14231 }
14232 
14233 static int
14234 lscf_setpropvalue(const char *pgname, const char *type,
14235     const char *arg, int isadd, int isnotfoundok)
14236 {
14237 	scf_type_t ty;
14238 	scf_propertygroup_t *pg;
14239 	scf_property_t *prop;
14240 	int ret, result = 0;
14241 	scf_transaction_t *tx;
14242 	scf_transaction_entry_t *e;
14243 	scf_value_t *v;
14244 	string_list_t *sp;
14245 	char *propname;
14246 	uu_list_t *values;
14247 	uu_list_walk_t *walk;
14248 	void *cookie = NULL;
14249 	char *pattern = NULL;
14250 
14251 	lscf_prep_hndl();
14252 
14253 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14254 		uu_die(gettext("Could not create property list: %s\n"),
14255 		    uu_strerror(uu_error()));
14256 
14257 	if (!isadd)
14258 		pattern = safe_strdup(arg);
14259 
14260 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14261 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14262 	    (prop = scf_property_create(g_hndl)) == NULL ||
14263 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14264 		scfdie();
14265 
14266 	if (cur_snap != NULL) {
14267 		semerr(emsg_cant_modify_snapshots);
14268 		goto fail;
14269 	}
14270 
14271 	if (cur_inst == NULL && cur_svc == NULL) {
14272 		semerr(emsg_entity_not_selected);
14273 		goto fail;
14274 	}
14275 
14276 	propname = strchr(pgname, '/');
14277 	if (propname == NULL) {
14278 		semerr(gettext("Property names must contain a `/'.\n"));
14279 		goto fail;
14280 	}
14281 
14282 	*propname = '\0';
14283 	++propname;
14284 
14285 	if (type != NULL) {
14286 		ty = string_to_type(type);
14287 		if (ty == SCF_TYPE_INVALID) {
14288 			semerr(gettext("Unknown type \"%s\".\n"), type);
14289 			goto fail;
14290 		}
14291 	}
14292 
14293 	if (cur_inst != NULL)
14294 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14295 	else
14296 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14297 	if (ret != 0) {
14298 		switch (scf_error()) {
14299 		case SCF_ERROR_NOT_FOUND:
14300 			if (isnotfoundok) {
14301 				result = 0;
14302 			} else {
14303 				semerr(emsg_no_such_pg, pgname);
14304 				result = -1;
14305 			}
14306 			goto out;
14307 
14308 		case SCF_ERROR_INVALID_ARGUMENT:
14309 			semerr(emsg_invalid_pg_name, pgname);
14310 			goto fail;
14311 
14312 		default:
14313 			scfdie();
14314 		}
14315 	}
14316 
14317 	do {
14318 		if (scf_pg_update(pg) == -1)
14319 			scfdie();
14320 		if (scf_transaction_start(tx, pg) != 0) {
14321 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14322 				scfdie();
14323 
14324 			semerr(emsg_permission_denied);
14325 			goto fail;
14326 		}
14327 
14328 		ret = scf_pg_get_property(pg, propname, prop);
14329 		if (ret == 0) {
14330 			scf_type_t ptype;
14331 			char *pat = pattern;
14332 
14333 			if (scf_property_type(prop, &ptype) != 0)
14334 				scfdie();
14335 
14336 			if (isadd) {
14337 				if (type != NULL && ptype != ty) {
14338 					semerr(gettext("Property \"%s\" is not "
14339 					    "of type \"%s\".\n"), propname,
14340 					    type);
14341 					goto fail;
14342 				}
14343 
14344 				pat = NULL;
14345 			} else {
14346 				size_t len = strlen(pat);
14347 				if (len > 0 && pat[len - 1] == '\"')
14348 					pat[len - 1] = '\0';
14349 				if (len > 0 && pat[0] == '\"')
14350 					pat++;
14351 			}
14352 
14353 			ty = ptype;
14354 
14355 			get_prop_values(prop, values, pat);
14356 
14357 			if (isadd)
14358 				add_string(values, arg);
14359 
14360 			if (scf_transaction_property_change(tx, e,
14361 			    propname, ty) == -1)
14362 				scfdie();
14363 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14364 			if (isadd) {
14365 				if (type == NULL) {
14366 					semerr(gettext("Type required "
14367 					    "for new properties.\n"));
14368 					goto fail;
14369 				}
14370 
14371 				add_string(values, arg);
14372 
14373 				if (scf_transaction_property_new(tx, e,
14374 				    propname, ty) == -1)
14375 					scfdie();
14376 			} else if (isnotfoundok) {
14377 				result = 0;
14378 				goto out;
14379 			} else {
14380 				semerr(gettext("No such property %s/%s.\n"),
14381 				    pgname, propname);
14382 				result = -1;
14383 				goto out;
14384 			}
14385 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14386 			semerr(emsg_invalid_prop_name, propname);
14387 			goto fail;
14388 		} else {
14389 			scfdie();
14390 		}
14391 
14392 		walk = uu_list_walk_start(values, UU_DEFAULT);
14393 		if (walk == NULL)
14394 			uu_die(gettext("Could not walk property list.\n"));
14395 
14396 		for (sp = uu_list_walk_next(walk); sp != NULL;
14397 		    sp = uu_list_walk_next(walk)) {
14398 			v = string_to_value(sp->str, ty, 0);
14399 
14400 			if (v == NULL) {
14401 				scf_entry_destroy_children(e);
14402 				goto fail;
14403 			}
14404 			ret = scf_entry_add_value(e, v);
14405 			assert(ret == 0);
14406 		}
14407 		uu_list_walk_end(walk);
14408 
14409 		result = scf_transaction_commit(tx);
14410 
14411 		scf_transaction_reset(tx);
14412 		scf_entry_destroy_children(e);
14413 	} while (result == 0);
14414 
14415 	if (result < 0) {
14416 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14417 			scfdie();
14418 
14419 		semerr(emsg_permission_denied);
14420 		goto fail;
14421 	}
14422 
14423 	result = 0;
14424 
14425 	private_refresh();
14426 
14427 out:
14428 	scf_transaction_destroy(tx);
14429 	scf_entry_destroy(e);
14430 	scf_pg_destroy(pg);
14431 	scf_property_destroy(prop);
14432 	free(pattern);
14433 
14434 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14435 		free(sp->str);
14436 		free(sp);
14437 	}
14438 
14439 	uu_list_destroy(values);
14440 
14441 	return (result);
14442 
14443 fail:
14444 	result = -1;
14445 	goto out;
14446 }
14447 
14448 int
14449 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14450 {
14451 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14452 }
14453 
14454 int
14455 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14456 {
14457 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14458 }
14459 
14460 /*
14461  * Look for a standard start method, first in the instance (if any),
14462  * then the service.
14463  */
14464 static const char *
14465 start_method_name(int *in_instance)
14466 {
14467 	scf_propertygroup_t *pg;
14468 	char **p;
14469 	int ret;
14470 	scf_instance_t *inst = cur_inst;
14471 
14472 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14473 		scfdie();
14474 
14475 again:
14476 	for (p = start_method_names; *p != NULL; p++) {
14477 		if (inst != NULL)
14478 			ret = scf_instance_get_pg(inst, *p, pg);
14479 		else
14480 			ret = scf_service_get_pg(cur_svc, *p, pg);
14481 
14482 		if (ret == 0) {
14483 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14484 			char *buf = safe_malloc(bufsz);
14485 
14486 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14487 				free(buf);
14488 				continue;
14489 			}
14490 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14491 				free(buf);
14492 				continue;
14493 			}
14494 
14495 			free(buf);
14496 			*in_instance = (inst != NULL);
14497 			scf_pg_destroy(pg);
14498 			return (*p);
14499 		}
14500 
14501 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14502 			continue;
14503 
14504 		scfdie();
14505 	}
14506 
14507 	if (inst != NULL) {
14508 		inst = NULL;
14509 		goto again;
14510 	}
14511 
14512 	scf_pg_destroy(pg);
14513 	return (NULL);
14514 }
14515 
14516 static int
14517 addpg(const char *name, const char *type)
14518 {
14519 	scf_propertygroup_t *pg;
14520 	int ret;
14521 
14522 	pg = scf_pg_create(g_hndl);
14523 	if (pg == NULL)
14524 		scfdie();
14525 
14526 	if (cur_inst != NULL)
14527 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14528 	else
14529 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14530 
14531 	if (ret != 0) {
14532 		switch (scf_error()) {
14533 		case SCF_ERROR_EXISTS:
14534 			ret = 0;
14535 			break;
14536 
14537 		case SCF_ERROR_PERMISSION_DENIED:
14538 			semerr(emsg_permission_denied);
14539 			break;
14540 
14541 		default:
14542 			scfdie();
14543 		}
14544 	}
14545 
14546 	scf_pg_destroy(pg);
14547 	return (ret);
14548 }
14549 
14550 int
14551 lscf_setenv(uu_list_t *args, int isunset)
14552 {
14553 	int ret = 0;
14554 	size_t i;
14555 	int argc;
14556 	char **argv = NULL;
14557 	string_list_t *slp;
14558 	char *pattern;
14559 	char *prop;
14560 	int do_service = 0;
14561 	int do_instance = 0;
14562 	const char *method = NULL;
14563 	const char *name = NULL;
14564 	const char *value = NULL;
14565 	scf_instance_t *saved_cur_inst = cur_inst;
14566 
14567 	lscf_prep_hndl();
14568 
14569 	argc = uu_list_numnodes(args);
14570 	if (argc < 1)
14571 		goto usage;
14572 
14573 	argv = calloc(argc + 1, sizeof (char *));
14574 	if (argv == NULL)
14575 		uu_die(gettext("Out of memory.\n"));
14576 
14577 	for (slp = uu_list_first(args), i = 0;
14578 	    slp != NULL;
14579 	    slp = uu_list_next(args, slp), ++i)
14580 		argv[i] = slp->str;
14581 
14582 	argv[i] = NULL;
14583 
14584 	opterr = 0;
14585 	optind = 0;
14586 	for (;;) {
14587 		ret = getopt(argc, argv, "sim:");
14588 		if (ret == -1)
14589 			break;
14590 
14591 		switch (ret) {
14592 		case 's':
14593 			do_service = 1;
14594 			cur_inst = NULL;
14595 			break;
14596 
14597 		case 'i':
14598 			do_instance = 1;
14599 			break;
14600 
14601 		case 'm':
14602 			method = optarg;
14603 			break;
14604 
14605 		case '?':
14606 			goto usage;
14607 
14608 		default:
14609 			bad_error("getopt", ret);
14610 		}
14611 	}
14612 
14613 	argc -= optind;
14614 	if ((do_service && do_instance) ||
14615 	    (isunset && argc != 1) ||
14616 	    (!isunset && argc != 2))
14617 		goto usage;
14618 
14619 	name = argv[optind];
14620 	if (!isunset)
14621 		value = argv[optind + 1];
14622 
14623 	if (cur_snap != NULL) {
14624 		semerr(emsg_cant_modify_snapshots);
14625 		ret = -1;
14626 		goto out;
14627 	}
14628 
14629 	if (cur_inst == NULL && cur_svc == NULL) {
14630 		semerr(emsg_entity_not_selected);
14631 		ret = -1;
14632 		goto out;
14633 	}
14634 
14635 	if (do_instance && cur_inst == NULL) {
14636 		semerr(gettext("No instance is selected.\n"));
14637 		ret = -1;
14638 		goto out;
14639 	}
14640 
14641 	if (do_service && cur_svc == NULL) {
14642 		semerr(gettext("No service is selected.\n"));
14643 		ret = -1;
14644 		goto out;
14645 	}
14646 
14647 	if (method == NULL) {
14648 		if (do_instance || do_service) {
14649 			method = "method_context";
14650 			if (!isunset) {
14651 				ret = addpg("method_context",
14652 				    SCF_GROUP_FRAMEWORK);
14653 				if (ret != 0)
14654 					goto out;
14655 			}
14656 		} else {
14657 			int in_instance;
14658 			method = start_method_name(&in_instance);
14659 			if (method == NULL) {
14660 				semerr(gettext(
14661 				    "Couldn't find start method; please "
14662 				    "specify a method with '-m'.\n"));
14663 				ret = -1;
14664 				goto out;
14665 			}
14666 			if (!in_instance)
14667 				cur_inst = NULL;
14668 		}
14669 	} else {
14670 		scf_propertygroup_t *pg;
14671 		size_t bufsz;
14672 		char *buf;
14673 		int ret;
14674 
14675 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14676 			scfdie();
14677 
14678 		if (cur_inst != NULL)
14679 			ret = scf_instance_get_pg(cur_inst, method, pg);
14680 		else
14681 			ret = scf_service_get_pg(cur_svc, method, pg);
14682 
14683 		if (ret != 0) {
14684 			scf_pg_destroy(pg);
14685 			switch (scf_error()) {
14686 			case SCF_ERROR_NOT_FOUND:
14687 				semerr(gettext("Couldn't find the method "
14688 				    "\"%s\".\n"), method);
14689 				goto out;
14690 
14691 			case SCF_ERROR_INVALID_ARGUMENT:
14692 				semerr(gettext("Invalid method name \"%s\".\n"),
14693 				    method);
14694 				goto out;
14695 
14696 			default:
14697 				scfdie();
14698 			}
14699 		}
14700 
14701 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
14702 		buf = safe_malloc(bufsz);
14703 
14704 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14705 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
14706 			semerr(gettext("Property group \"%s\" is not of type "
14707 			    "\"method\".\n"), method);
14708 			ret = -1;
14709 			free(buf);
14710 			scf_pg_destroy(pg);
14711 			goto out;
14712 		}
14713 
14714 		free(buf);
14715 		scf_pg_destroy(pg);
14716 	}
14717 
14718 	prop = uu_msprintf("%s/environment", method);
14719 	pattern = uu_msprintf("%s=*", name);
14720 
14721 	if (prop == NULL || pattern == NULL)
14722 		uu_die(gettext("Out of memory.\n"));
14723 
14724 	ret = lscf_delpropvalue(prop, pattern, !isunset);
14725 
14726 	if (ret == 0 && !isunset) {
14727 		uu_free(pattern);
14728 		uu_free(prop);
14729 		prop = uu_msprintf("%s/environment", method);
14730 		pattern = uu_msprintf("%s=%s", name, value);
14731 		if (prop == NULL || pattern == NULL)
14732 			uu_die(gettext("Out of memory.\n"));
14733 		ret = lscf_addpropvalue(prop, "astring:", pattern);
14734 	}
14735 	uu_free(pattern);
14736 	uu_free(prop);
14737 
14738 out:
14739 	cur_inst = saved_cur_inst;
14740 
14741 	free(argv);
14742 	return (ret);
14743 usage:
14744 	ret = -2;
14745 	goto out;
14746 }
14747 
14748 /*
14749  * Snapshot commands
14750  */
14751 
14752 void
14753 lscf_listsnap()
14754 {
14755 	scf_snapshot_t *snap;
14756 	scf_iter_t *iter;
14757 	char *nb;
14758 	int r;
14759 
14760 	lscf_prep_hndl();
14761 
14762 	if (cur_inst == NULL) {
14763 		semerr(gettext("Instance not selected.\n"));
14764 		return;
14765 	}
14766 
14767 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14768 	    (iter = scf_iter_create(g_hndl)) == NULL)
14769 		scfdie();
14770 
14771 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
14772 		scfdie();
14773 
14774 	nb = safe_malloc(max_scf_name_len + 1);
14775 
14776 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
14777 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
14778 			scfdie();
14779 
14780 		(void) puts(nb);
14781 	}
14782 	if (r < 0)
14783 		scfdie();
14784 
14785 	free(nb);
14786 	scf_iter_destroy(iter);
14787 	scf_snapshot_destroy(snap);
14788 }
14789 
14790 void
14791 lscf_selectsnap(const char *name)
14792 {
14793 	scf_snapshot_t *snap;
14794 	scf_snaplevel_t *level;
14795 
14796 	lscf_prep_hndl();
14797 
14798 	if (cur_inst == NULL) {
14799 		semerr(gettext("Instance not selected.\n"));
14800 		return;
14801 	}
14802 
14803 	if (cur_snap != NULL) {
14804 		if (name != NULL) {
14805 			char *cur_snap_name;
14806 			boolean_t nochange;
14807 
14808 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
14809 
14810 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
14811 			    max_scf_name_len + 1) < 0)
14812 				scfdie();
14813 
14814 			nochange = strcmp(name, cur_snap_name) == 0;
14815 
14816 			free(cur_snap_name);
14817 
14818 			if (nochange)
14819 				return;
14820 		}
14821 
14822 		unselect_cursnap();
14823 	}
14824 
14825 	if (name == NULL)
14826 		return;
14827 
14828 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14829 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
14830 		scfdie();
14831 
14832 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
14833 	    SCF_SUCCESS) {
14834 		switch (scf_error()) {
14835 		case SCF_ERROR_INVALID_ARGUMENT:
14836 			semerr(gettext("Invalid name \"%s\".\n"), name);
14837 			break;
14838 
14839 		case SCF_ERROR_NOT_FOUND:
14840 			semerr(gettext("No such snapshot \"%s\".\n"), name);
14841 			break;
14842 
14843 		default:
14844 			scfdie();
14845 		}
14846 
14847 		scf_snaplevel_destroy(level);
14848 		scf_snapshot_destroy(snap);
14849 		return;
14850 	}
14851 
14852 	/* Load the snaplevels into our list. */
14853 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
14854 	if (cur_levels == NULL)
14855 		uu_die(gettext("Could not create list: %s\n"),
14856 		    uu_strerror(uu_error()));
14857 
14858 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14859 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14860 			scfdie();
14861 
14862 		semerr(gettext("Snapshot has no snaplevels.\n"));
14863 
14864 		scf_snaplevel_destroy(level);
14865 		scf_snapshot_destroy(snap);
14866 		return;
14867 	}
14868 
14869 	cur_snap = snap;
14870 
14871 	for (;;) {
14872 		cur_elt = safe_malloc(sizeof (*cur_elt));
14873 		uu_list_node_init(cur_elt, &cur_elt->list_node,
14874 		    snaplevel_pool);
14875 		cur_elt->sl = level;
14876 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
14877 			uu_die(gettext("libuutil error: %s\n"),
14878 			    uu_strerror(uu_error()));
14879 
14880 		level = scf_snaplevel_create(g_hndl);
14881 		if (level == NULL)
14882 			scfdie();
14883 
14884 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
14885 		    level) != SCF_SUCCESS) {
14886 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14887 				scfdie();
14888 
14889 			scf_snaplevel_destroy(level);
14890 			break;
14891 		}
14892 	}
14893 
14894 	cur_elt = uu_list_last(cur_levels);
14895 	cur_level = cur_elt->sl;
14896 }
14897 
14898 /*
14899  * Copies the properties & values in src to dst.  Assumes src won't change.
14900  * Returns -1 if permission is denied, -2 if another transaction interrupts,
14901  * and 0 on success.
14902  *
14903  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
14904  * property, if it is copied and has type boolean.  (See comment in
14905  * lscf_revert()).
14906  */
14907 static int
14908 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
14909     uint8_t enabled)
14910 {
14911 	scf_transaction_t *tx;
14912 	scf_iter_t *iter, *viter;
14913 	scf_property_t *prop;
14914 	scf_value_t *v;
14915 	char *nbuf;
14916 	int r;
14917 
14918 	tx = scf_transaction_create(g_hndl);
14919 	if (tx == NULL)
14920 		scfdie();
14921 
14922 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
14923 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14924 			scfdie();
14925 
14926 		scf_transaction_destroy(tx);
14927 
14928 		return (-1);
14929 	}
14930 
14931 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14932 	    (prop = scf_property_create(g_hndl)) == NULL ||
14933 	    (viter = scf_iter_create(g_hndl)) == NULL)
14934 		scfdie();
14935 
14936 	nbuf = safe_malloc(max_scf_name_len + 1);
14937 
14938 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
14939 		scfdie();
14940 
14941 	for (;;) {
14942 		scf_transaction_entry_t *e;
14943 		scf_type_t ty;
14944 
14945 		r = scf_iter_next_property(iter, prop);
14946 		if (r == -1)
14947 			scfdie();
14948 		if (r == 0)
14949 			break;
14950 
14951 		e = scf_entry_create(g_hndl);
14952 		if (e == NULL)
14953 			scfdie();
14954 
14955 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14956 			scfdie();
14957 
14958 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14959 			scfdie();
14960 
14961 		if (scf_transaction_property_new(tx, e, nbuf,
14962 		    ty) != SCF_SUCCESS)
14963 			scfdie();
14964 
14965 		if ((enabled == 0 || enabled == 1) &&
14966 		    strcmp(nbuf, scf_property_enabled) == 0 &&
14967 		    ty == SCF_TYPE_BOOLEAN) {
14968 			v = scf_value_create(g_hndl);
14969 			if (v == NULL)
14970 				scfdie();
14971 
14972 			scf_value_set_boolean(v, enabled);
14973 
14974 			if (scf_entry_add_value(e, v) != 0)
14975 				scfdie();
14976 		} else {
14977 			if (scf_iter_property_values(viter, prop) != 0)
14978 				scfdie();
14979 
14980 			for (;;) {
14981 				v = scf_value_create(g_hndl);
14982 				if (v == NULL)
14983 					scfdie();
14984 
14985 				r = scf_iter_next_value(viter, v);
14986 				if (r == -1)
14987 					scfdie();
14988 				if (r == 0) {
14989 					scf_value_destroy(v);
14990 					break;
14991 				}
14992 
14993 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
14994 					scfdie();
14995 			}
14996 		}
14997 	}
14998 
14999 	free(nbuf);
15000 	scf_iter_destroy(viter);
15001 	scf_property_destroy(prop);
15002 	scf_iter_destroy(iter);
15003 
15004 	r = scf_transaction_commit(tx);
15005 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15006 		scfdie();
15007 
15008 	scf_transaction_destroy_children(tx);
15009 	scf_transaction_destroy(tx);
15010 
15011 	switch (r) {
15012 	case 1:		return (0);
15013 	case 0:		return (-2);
15014 	case -1:	return (-1);
15015 
15016 	default:
15017 		abort();
15018 	}
15019 
15020 	/* NOTREACHED */
15021 }
15022 
15023 void
15024 lscf_revert(const char *snapname)
15025 {
15026 	scf_snapshot_t *snap, *prev;
15027 	scf_snaplevel_t *level, *nlevel;
15028 	scf_iter_t *iter;
15029 	scf_propertygroup_t *pg, *npg;
15030 	scf_property_t *prop;
15031 	scf_value_t *val;
15032 	char *nbuf, *tbuf;
15033 	uint8_t enabled;
15034 
15035 	lscf_prep_hndl();
15036 
15037 	if (cur_inst == NULL) {
15038 		semerr(gettext("Instance not selected.\n"));
15039 		return;
15040 	}
15041 
15042 	if (snapname != NULL) {
15043 		snap = scf_snapshot_create(g_hndl);
15044 		if (snap == NULL)
15045 			scfdie();
15046 
15047 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15048 		    SCF_SUCCESS) {
15049 			switch (scf_error()) {
15050 			case SCF_ERROR_INVALID_ARGUMENT:
15051 				semerr(gettext("Invalid snapshot name "
15052 				    "\"%s\".\n"), snapname);
15053 				break;
15054 
15055 			case SCF_ERROR_NOT_FOUND:
15056 				semerr(gettext("No such snapshot.\n"));
15057 				break;
15058 
15059 			default:
15060 				scfdie();
15061 			}
15062 
15063 			scf_snapshot_destroy(snap);
15064 			return;
15065 		}
15066 	} else {
15067 		if (cur_snap != NULL) {
15068 			snap = cur_snap;
15069 		} else {
15070 			semerr(gettext("No snapshot selected.\n"));
15071 			return;
15072 		}
15073 	}
15074 
15075 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15076 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15077 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15078 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15079 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15080 	    (prop = scf_property_create(g_hndl)) == NULL ||
15081 	    (val = scf_value_create(g_hndl)) == NULL)
15082 		scfdie();
15083 
15084 	nbuf = safe_malloc(max_scf_name_len + 1);
15085 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15086 
15087 	/* Take the "previous" snapshot before we blow away the properties. */
15088 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15089 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15090 			scfdie();
15091 	} else {
15092 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15093 			scfdie();
15094 
15095 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15096 			scfdie();
15097 	}
15098 
15099 	/* Save general/enabled, since we're probably going to replace it. */
15100 	enabled = 2;
15101 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15102 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15103 	    scf_property_get_value(prop, val) == 0)
15104 		(void) scf_value_get_boolean(val, &enabled);
15105 
15106 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15107 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15108 			scfdie();
15109 
15110 		goto out;
15111 	}
15112 
15113 	for (;;) {
15114 		boolean_t isinst;
15115 		uint32_t flags;
15116 		int r;
15117 
15118 		/* Clear the properties from the corresponding entity. */
15119 		isinst = snaplevel_is_instance(level);
15120 
15121 		if (!isinst)
15122 			r = scf_iter_service_pgs(iter, cur_svc);
15123 		else
15124 			r = scf_iter_instance_pgs(iter, cur_inst);
15125 		if (r != SCF_SUCCESS)
15126 			scfdie();
15127 
15128 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15129 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15130 				scfdie();
15131 
15132 			/* Skip nonpersistent pgs. */
15133 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15134 				continue;
15135 
15136 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15137 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15138 					scfdie();
15139 
15140 				semerr(emsg_permission_denied);
15141 				goto out;
15142 			}
15143 		}
15144 		if (r == -1)
15145 			scfdie();
15146 
15147 		/* Copy the properties to the corresponding entity. */
15148 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15149 			scfdie();
15150 
15151 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15152 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15153 				scfdie();
15154 
15155 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15156 			    0)
15157 				scfdie();
15158 
15159 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15160 				scfdie();
15161 
15162 			if (!isinst)
15163 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15164 				    flags, npg);
15165 			else
15166 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15167 				    flags, npg);
15168 			if (r != SCF_SUCCESS) {
15169 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15170 					scfdie();
15171 
15172 				semerr(emsg_permission_denied);
15173 				goto out;
15174 			}
15175 
15176 			if ((enabled == 0 || enabled == 1) &&
15177 			    strcmp(nbuf, scf_pg_general) == 0)
15178 				r = pg_copy(pg, npg, enabled);
15179 			else
15180 				r = pg_copy(pg, npg, 2);
15181 
15182 			switch (r) {
15183 			case 0:
15184 				break;
15185 
15186 			case -1:
15187 				semerr(emsg_permission_denied);
15188 				goto out;
15189 
15190 			case -2:
15191 				semerr(gettext(
15192 				    "Interrupted by another change.\n"));
15193 				goto out;
15194 
15195 			default:
15196 				abort();
15197 			}
15198 		}
15199 		if (r == -1)
15200 			scfdie();
15201 
15202 		/* Get next level. */
15203 		nlevel = scf_snaplevel_create(g_hndl);
15204 		if (nlevel == NULL)
15205 			scfdie();
15206 
15207 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15208 		    SCF_SUCCESS) {
15209 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15210 				scfdie();
15211 
15212 			scf_snaplevel_destroy(nlevel);
15213 			break;
15214 		}
15215 
15216 		scf_snaplevel_destroy(level);
15217 		level = nlevel;
15218 	}
15219 
15220 	if (snapname == NULL) {
15221 		lscf_selectsnap(NULL);
15222 		snap = NULL;		/* cur_snap has been destroyed */
15223 	}
15224 
15225 out:
15226 	free(tbuf);
15227 	free(nbuf);
15228 	scf_value_destroy(val);
15229 	scf_property_destroy(prop);
15230 	scf_pg_destroy(npg);
15231 	scf_pg_destroy(pg);
15232 	scf_iter_destroy(iter);
15233 	scf_snaplevel_destroy(level);
15234 	scf_snapshot_destroy(prev);
15235 	if (snap != cur_snap)
15236 		scf_snapshot_destroy(snap);
15237 }
15238 
15239 void
15240 lscf_refresh(void)
15241 {
15242 	ssize_t fmrilen;
15243 	size_t bufsz;
15244 	char *fmribuf;
15245 	int r;
15246 
15247 	lscf_prep_hndl();
15248 
15249 	if (cur_inst == NULL) {
15250 		semerr(gettext("Instance not selected.\n"));
15251 		return;
15252 	}
15253 
15254 	bufsz = max_scf_fmri_len + 1;
15255 	fmribuf = safe_malloc(bufsz);
15256 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15257 	if (fmrilen < 0) {
15258 		free(fmribuf);
15259 		if (scf_error() != SCF_ERROR_DELETED)
15260 			scfdie();
15261 		scf_instance_destroy(cur_inst);
15262 		cur_inst = NULL;
15263 		warn(emsg_deleted);
15264 		return;
15265 	}
15266 	assert(fmrilen < bufsz);
15267 
15268 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15269 	switch (r) {
15270 	case 0:
15271 		break;
15272 
15273 	case ECONNABORTED:
15274 		warn(gettext("Could not refresh %s "
15275 		    "(repository connection broken).\n"), fmribuf);
15276 		break;
15277 
15278 	case ECANCELED:
15279 		warn(emsg_deleted);
15280 		break;
15281 
15282 	case EPERM:
15283 		warn(gettext("Could not refresh %s "
15284 		    "(permission denied).\n"), fmribuf);
15285 		break;
15286 
15287 	case ENOSPC:
15288 		warn(gettext("Could not refresh %s "
15289 		    "(repository server out of resources).\n"),
15290 		    fmribuf);
15291 		break;
15292 
15293 	case EACCES:
15294 	default:
15295 		bad_error("refresh_entity", scf_error());
15296 	}
15297 
15298 	free(fmribuf);
15299 }
15300 
15301 /*
15302  * describe [-v] [-t] [pg/prop]
15303  */
15304 int
15305 lscf_describe(uu_list_t *args, int hasargs)
15306 {
15307 	int ret = 0;
15308 	size_t i;
15309 	int argc;
15310 	char **argv = NULL;
15311 	string_list_t *slp;
15312 	int do_verbose = 0;
15313 	int do_templates = 0;
15314 	char *pattern = NULL;
15315 
15316 	lscf_prep_hndl();
15317 
15318 	if (hasargs != 0)  {
15319 		argc = uu_list_numnodes(args);
15320 		if (argc < 1)
15321 			goto usage;
15322 
15323 		argv = calloc(argc + 1, sizeof (char *));
15324 		if (argv == NULL)
15325 			uu_die(gettext("Out of memory.\n"));
15326 
15327 		for (slp = uu_list_first(args), i = 0;
15328 		    slp != NULL;
15329 		    slp = uu_list_next(args, slp), ++i)
15330 			argv[i] = slp->str;
15331 
15332 		argv[i] = NULL;
15333 
15334 		/*
15335 		 * We start optind = 0 because our list of arguments
15336 		 * starts at argv[0]
15337 		 */
15338 		optind = 0;
15339 		opterr = 0;
15340 		for (;;) {
15341 			ret = getopt(argc, argv, "vt");
15342 			if (ret == -1)
15343 				break;
15344 
15345 			switch (ret) {
15346 			case 'v':
15347 				do_verbose = 1;
15348 				break;
15349 
15350 			case 't':
15351 				do_templates = 1;
15352 				break;
15353 
15354 			case '?':
15355 				goto usage;
15356 
15357 			default:
15358 				bad_error("getopt", ret);
15359 			}
15360 		}
15361 
15362 		pattern = argv[optind];
15363 	}
15364 
15365 	if (cur_inst == NULL && cur_svc == NULL) {
15366 		semerr(emsg_entity_not_selected);
15367 		ret = -1;
15368 		goto out;
15369 	}
15370 
15371 	/*
15372 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15373 	 * output if their last parameter is set to 2.  Less information is
15374 	 * produced if the parameter is set to 1.
15375 	 */
15376 	if (pattern == NULL) {
15377 		if (do_verbose == 1)
15378 			list_entity_tmpl(2);
15379 		else
15380 			list_entity_tmpl(1);
15381 	}
15382 
15383 	if (do_templates == 0) {
15384 		if (do_verbose == 1)
15385 			listprop(pattern, 0, 2);
15386 		else
15387 			listprop(pattern, 0, 1);
15388 	} else {
15389 		if (do_verbose == 1)
15390 			listtmpl(pattern, 2);
15391 		else
15392 			listtmpl(pattern, 1);
15393 	}
15394 
15395 	ret = 0;
15396 out:
15397 	if (argv != NULL)
15398 		free(argv);
15399 	return (ret);
15400 usage:
15401 	ret = -2;
15402 	goto out;
15403 }
15404 
15405 #define	PARAM_ACTIVE	((const char *) "active")
15406 #define	PARAM_INACTIVE	((const char *) "inactive")
15407 #define	PARAM_SMTP_TO	((const char *) "to")
15408 
15409 /*
15410  * tokenize()
15411  * Breaks down the string according to the tokens passed.
15412  * Caller is responsible for freeing array of pointers returned.
15413  * Returns NULL on failure
15414  */
15415 char **
15416 tokenize(char *str, const char *sep)
15417 {
15418 	char *token, *lasts;
15419 	char **buf;
15420 	int n = 0;	/* number of elements */
15421 	int size = 8;	/* size of the array (initial) */
15422 
15423 	buf = safe_malloc(size * sizeof (char *));
15424 
15425 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15426 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15427 		if (n + 1 >= size) {
15428 			size *= 2;
15429 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15430 			    NULL) {
15431 				uu_die(gettext("Out of memory"));
15432 			}
15433 		}
15434 		buf[n] = token;
15435 	}
15436 	/* NULL terminate the pointer array */
15437 	buf[n] = NULL;
15438 
15439 	return (buf);
15440 }
15441 
15442 int32_t
15443 check_tokens(char **p)
15444 {
15445 	int32_t smf = 0;
15446 	int32_t fma = 0;
15447 
15448 	while (*p) {
15449 		int32_t t = string_to_tset(*p);
15450 
15451 		if (t == 0) {
15452 			if (is_fma_token(*p) == 0)
15453 				return (INVALID_TOKENS);
15454 			fma = 1; /* this token is an fma event */
15455 		} else {
15456 			smf |= t;
15457 		}
15458 
15459 		if (smf != 0 && fma == 1)
15460 			return (MIXED_TOKENS);
15461 		++p;
15462 	}
15463 
15464 	if (smf > 0)
15465 		return (smf);
15466 	else if (fma == 1)
15467 		return (FMA_TOKENS);
15468 
15469 	return (INVALID_TOKENS);
15470 }
15471 
15472 static int
15473 get_selection_str(char *fmri, size_t sz)
15474 {
15475 	if (g_hndl == NULL) {
15476 		semerr(emsg_entity_not_selected);
15477 		return (-1);
15478 	} else if (cur_level != NULL) {
15479 		semerr(emsg_invalid_for_snapshot);
15480 		return (-1);
15481 	} else {
15482 		lscf_get_selection_str(fmri, sz);
15483 	}
15484 
15485 	return (0);
15486 }
15487 
15488 void
15489 lscf_delnotify(const char *set, int global)
15490 {
15491 	char *str = strdup(set);
15492 	char **pgs;
15493 	char **p;
15494 	int32_t tset;
15495 	char *fmri = NULL;
15496 
15497 	if (str == NULL)
15498 		uu_die(gettext("Out of memory.\n"));
15499 
15500 	pgs = tokenize(str, ",");
15501 
15502 	if ((tset = check_tokens(pgs)) > 0) {
15503 		size_t sz = max_scf_fmri_len + 1;
15504 
15505 		fmri = safe_malloc(sz);
15506 		if (global) {
15507 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15508 		} else if (get_selection_str(fmri, sz) != 0) {
15509 			goto out;
15510 		}
15511 
15512 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15513 		    tset) != SCF_SUCCESS) {
15514 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15515 			    scf_strerror(scf_error()));
15516 		}
15517 	} else if (tset == FMA_TOKENS) {
15518 		if (global) {
15519 			semerr(gettext("Can't use option '-g' with FMA event "
15520 			    "definitions\n"));
15521 			goto out;
15522 		}
15523 
15524 		for (p = pgs; *p; ++p) {
15525 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15526 			    SCF_SUCCESS) {
15527 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15528 				    scf_strerror(scf_error()));
15529 				goto out;
15530 			}
15531 		}
15532 	} else if (tset == MIXED_TOKENS) {
15533 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15534 		goto out;
15535 	} else {
15536 		uu_die(gettext("Invalid input.\n"));
15537 	}
15538 
15539 out:
15540 	free(fmri);
15541 	free(pgs);
15542 	free(str);
15543 }
15544 
15545 void
15546 lscf_listnotify(const char *set, int global)
15547 {
15548 	char *str = safe_strdup(set);
15549 	char **pgs;
15550 	char **p;
15551 	int32_t tset;
15552 	nvlist_t *nvl;
15553 	char *fmri = NULL;
15554 
15555 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15556 		uu_die(gettext("Out of memory.\n"));
15557 
15558 	pgs = tokenize(str, ",");
15559 
15560 	if ((tset = check_tokens(pgs)) > 0) {
15561 		size_t sz = max_scf_fmri_len + 1;
15562 
15563 		fmri = safe_malloc(sz);
15564 		if (global) {
15565 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15566 		} else if (get_selection_str(fmri, sz) != 0) {
15567 			goto out;
15568 		}
15569 
15570 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15571 		    SCF_SUCCESS) {
15572 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15573 			    scf_error() != SCF_ERROR_DELETED)
15574 				uu_warn(gettext(
15575 				    "Failed listnotify: %s\n"),
15576 				    scf_strerror(scf_error()));
15577 			goto out;
15578 		}
15579 
15580 		listnotify_print(nvl, NULL);
15581 	} else if (tset == FMA_TOKENS) {
15582 		if (global) {
15583 			semerr(gettext("Can't use option '-g' with FMA event "
15584 			    "definitions\n"));
15585 			goto out;
15586 		}
15587 
15588 		for (p = pgs; *p; ++p) {
15589 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15590 			    SCF_SUCCESS) {
15591 				/*
15592 				 * if the preferences have just been deleted
15593 				 * or does not exist, just skip.
15594 				 */
15595 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15596 				    scf_error() == SCF_ERROR_DELETED)
15597 					continue;
15598 				uu_warn(gettext(
15599 				    "Failed listnotify: %s\n"),
15600 				    scf_strerror(scf_error()));
15601 				goto out;
15602 			}
15603 			listnotify_print(nvl, re_tag(*p));
15604 		}
15605 	} else if (tset == MIXED_TOKENS) {
15606 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15607 		goto out;
15608 	} else {
15609 		semerr(gettext("Invalid input.\n"));
15610 	}
15611 
15612 out:
15613 	nvlist_free(nvl);
15614 	free(fmri);
15615 	free(pgs);
15616 	free(str);
15617 }
15618 
15619 static char *
15620 strip_quotes_and_blanks(char *s)
15621 {
15622 	char *start = s;
15623 	char *end = strrchr(s, '\"');
15624 
15625 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15626 		start = s + 1;
15627 		while (isblank(*start))
15628 			start++;
15629 		while (isblank(*(end - 1)) && end > start) {
15630 			end--;
15631 		}
15632 		*end = '\0';
15633 	}
15634 
15635 	return (start);
15636 }
15637 
15638 static int
15639 set_active(nvlist_t *mech, const char *hier_part)
15640 {
15641 	boolean_t b;
15642 
15643 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15644 		b = B_TRUE;
15645 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15646 		b = B_FALSE;
15647 	} else {
15648 		return (-1);
15649 	}
15650 
15651 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15652 		uu_die(gettext("Out of memory.\n"));
15653 
15654 	return (0);
15655 }
15656 
15657 static int
15658 add_snmp_params(nvlist_t *mech, char *hier_part)
15659 {
15660 	return (set_active(mech, hier_part));
15661 }
15662 
15663 static int
15664 add_syslog_params(nvlist_t *mech, char *hier_part)
15665 {
15666 	return (set_active(mech, hier_part));
15667 }
15668 
15669 /*
15670  * add_mailto_paramas()
15671  * parse the hier_part of mailto URI
15672  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15673  * or mailto:{[active]|inactive}
15674  */
15675 static int
15676 add_mailto_params(nvlist_t *mech, char *hier_part)
15677 {
15678 	const char *tok = "?&";
15679 	char *p;
15680 	char *lasts;
15681 	char *param;
15682 	char *val;
15683 
15684 	/*
15685 	 * If the notification parametes are in the form of
15686 	 *
15687 	 *   malito:{[active]|inactive}
15688 	 *
15689 	 * we set the property accordingly and return.
15690 	 * Otherwise, we make the notification type active and
15691 	 * process the hier_part.
15692 	 */
15693 	if (set_active(mech, hier_part) == 0)
15694 		return (0);
15695 	else if (set_active(mech, PARAM_ACTIVE) != 0)
15696 		return (-1);
15697 
15698 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15699 		/*
15700 		 * sanity check: we only get here if hier_part = "", but
15701 		 * that's handled by set_active
15702 		 */
15703 		uu_die("strtok_r");
15704 	}
15705 
15706 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15707 		uu_die(gettext("Out of memory.\n"));
15708 
15709 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
15710 		if ((param = strtok_r(p, "=", &val)) != NULL)
15711 			if (nvlist_add_string(mech, param, val) != 0)
15712 				uu_die(gettext("Out of memory.\n"));
15713 
15714 	return (0);
15715 }
15716 
15717 static int
15718 uri_split(char *uri, char **scheme, char **hier_part)
15719 {
15720 	int r = -1;
15721 
15722 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
15723 	    *hier_part == NULL) {
15724 		semerr(gettext("'%s' is not an URI\n"), uri);
15725 		return (r);
15726 	}
15727 
15728 	if ((r = check_uri_scheme(*scheme)) < 0) {
15729 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
15730 		return (r);
15731 	}
15732 
15733 	return (r);
15734 }
15735 
15736 static int
15737 process_uri(nvlist_t *params, char *uri)
15738 {
15739 	char *scheme;
15740 	char *hier_part;
15741 	nvlist_t *mech;
15742 	int index;
15743 	int r;
15744 
15745 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
15746 		return (-1);
15747 
15748 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
15749 		uu_die(gettext("Out of memory.\n"));
15750 
15751 	switch (index) {
15752 	case 0:
15753 		/* error messages displayed by called function */
15754 		r = add_mailto_params(mech, hier_part);
15755 		break;
15756 
15757 	case 1:
15758 		if ((r = add_snmp_params(mech, hier_part)) != 0)
15759 			semerr(gettext("Not valid parameters: '%s'\n"),
15760 			    hier_part);
15761 		break;
15762 
15763 	case 2:
15764 		if ((r = add_syslog_params(mech, hier_part)) != 0)
15765 			semerr(gettext("Not valid parameters: '%s'\n"),
15766 			    hier_part);
15767 		break;
15768 
15769 	default:
15770 		r = -1;
15771 	}
15772 
15773 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
15774 	    mech) != 0)
15775 		uu_die(gettext("Out of memory.\n"));
15776 
15777 	nvlist_free(mech);
15778 	return (r);
15779 }
15780 
15781 static int
15782 set_params(nvlist_t *params, char **p)
15783 {
15784 	char *uri;
15785 
15786 	if (p == NULL)
15787 		/* sanity check */
15788 		uu_die("set_params");
15789 
15790 	while (*p) {
15791 		uri = strip_quotes_and_blanks(*p);
15792 		if (process_uri(params, uri) != 0)
15793 			return (-1);
15794 
15795 		++p;
15796 	}
15797 
15798 	return (0);
15799 }
15800 
15801 static int
15802 setnotify(const char *e, char **p, int global)
15803 {
15804 	char *str = safe_strdup(e);
15805 	char **events;
15806 	int32_t tset;
15807 	int r = -1;
15808 	nvlist_t *nvl, *params;
15809 	char *fmri = NULL;
15810 
15811 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
15812 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
15813 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
15814 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
15815 		uu_die(gettext("Out of memory.\n"));
15816 
15817 	events = tokenize(str, ",");
15818 
15819 	if ((tset = check_tokens(events)) > 0) {
15820 		/* SMF state transitions parameters */
15821 		size_t sz = max_scf_fmri_len + 1;
15822 
15823 		fmri = safe_malloc(sz);
15824 		if (global) {
15825 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15826 		} else if (get_selection_str(fmri, sz) != 0) {
15827 			goto out;
15828 		}
15829 
15830 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
15831 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
15832 			uu_die(gettext("Out of memory.\n"));
15833 
15834 		if ((r = set_params(params, p)) == 0) {
15835 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
15836 			    params) != 0)
15837 				uu_die(gettext("Out of memory.\n"));
15838 
15839 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
15840 			    nvl) != SCF_SUCCESS) {
15841 				r = -1;
15842 				uu_warn(gettext(
15843 				    "Failed smf_notify_set_params(3SCF): %s\n"),
15844 				    scf_strerror(scf_error()));
15845 			}
15846 		}
15847 	} else if (tset == FMA_TOKENS) {
15848 		/* FMA event parameters */
15849 		if (global) {
15850 			semerr(gettext("Can't use option '-g' with FMA event "
15851 			    "definitions\n"));
15852 			goto out;
15853 		}
15854 
15855 		if ((r = set_params(params, p)) != 0)
15856 			goto out;
15857 
15858 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
15859 			uu_die(gettext("Out of memory.\n"));
15860 
15861 		while (*events) {
15862 			if (smf_notify_set_params(de_tag(*events), nvl) !=
15863 			    SCF_SUCCESS)
15864 				uu_warn(gettext(
15865 				    "Failed smf_notify_set_params(3SCF) for "
15866 				    "event %s: %s\n"), *events,
15867 				    scf_strerror(scf_error()));
15868 			events++;
15869 		}
15870 	} else if (tset == MIXED_TOKENS) {
15871 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15872 	} else {
15873 		/* Sanity check */
15874 		uu_die(gettext("Invalid input.\n"));
15875 	}
15876 
15877 out:
15878 	nvlist_free(nvl);
15879 	nvlist_free(params);
15880 	free(fmri);
15881 	free(str);
15882 
15883 	return (r);
15884 }
15885 
15886 int
15887 lscf_setnotify(uu_list_t *args)
15888 {
15889 	int argc;
15890 	char **argv = NULL;
15891 	string_list_t *slp;
15892 	int global;
15893 	char *events;
15894 	char **p;
15895 	int i;
15896 	int ret;
15897 
15898 	if ((argc = uu_list_numnodes(args)) < 2)
15899 		goto usage;
15900 
15901 	argv = calloc(argc + 1, sizeof (char *));
15902 	if (argv == NULL)
15903 		uu_die(gettext("Out of memory.\n"));
15904 
15905 	for (slp = uu_list_first(args), i = 0;
15906 	    slp != NULL;
15907 	    slp = uu_list_next(args, slp), ++i)
15908 		argv[i] = slp->str;
15909 
15910 	argv[i] = NULL;
15911 
15912 	if (strcmp(argv[0], "-g") == 0) {
15913 		global = 1;
15914 		events = argv[1];
15915 		p = argv + 2;
15916 	} else {
15917 		global = 0;
15918 		events = argv[0];
15919 		p = argv + 1;
15920 	}
15921 
15922 	ret = setnotify(events, p, global);
15923 
15924 out:
15925 	free(argv);
15926 	return (ret);
15927 
15928 usage:
15929 	ret = -2;
15930 	goto out;
15931 }
15932 
15933 /*
15934  * Creates a list of instance name strings associated with a service. If
15935  * wohandcrafted flag is set, get only instances that have a last-import
15936  * snapshot, instances that were imported via svccfg.
15937  */
15938 static uu_list_t *
15939 create_instance_list(scf_service_t *svc, int wohandcrafted)
15940 {
15941 	scf_snapshot_t  *snap = NULL;
15942 	scf_instance_t  *inst;
15943 	scf_iter_t	*inst_iter;
15944 	uu_list_t	*instances;
15945 	char		*instname;
15946 	int		r;
15947 
15948 	inst_iter = scf_iter_create(g_hndl);
15949 	inst = scf_instance_create(g_hndl);
15950 	if (inst_iter == NULL || inst == NULL) {
15951 		uu_warn(gettext("Could not create instance or iterator\n"));
15952 		scfdie();
15953 	}
15954 
15955 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
15956 		return (instances);
15957 
15958 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
15959 		switch (scf_error()) {
15960 		case SCF_ERROR_CONNECTION_BROKEN:
15961 		case SCF_ERROR_DELETED:
15962 			uu_list_destroy(instances);
15963 			instances = NULL;
15964 			goto out;
15965 
15966 		case SCF_ERROR_HANDLE_MISMATCH:
15967 		case SCF_ERROR_NOT_BOUND:
15968 		case SCF_ERROR_NOT_SET:
15969 		default:
15970 			bad_error("scf_iter_service_instances", scf_error());
15971 		}
15972 	}
15973 
15974 	instname = safe_malloc(max_scf_name_len + 1);
15975 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
15976 		if (r == -1) {
15977 			(void) uu_warn(gettext("Unable to iterate through "
15978 			    "instances to create instance list : %s\n"),
15979 			    scf_strerror(scf_error()));
15980 
15981 			uu_list_destroy(instances);
15982 			instances = NULL;
15983 			goto out;
15984 		}
15985 
15986 		/*
15987 		 * If the instance does not have a last-import snapshot
15988 		 * then do not add it to the list as it is a hand-crafted
15989 		 * instance that should not be managed.
15990 		 */
15991 		if (wohandcrafted) {
15992 			if (snap == NULL &&
15993 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
15994 				uu_warn(gettext("Unable to create snapshot "
15995 				    "entity\n"));
15996 				scfdie();
15997 			}
15998 
15999 			if (scf_instance_get_snapshot(inst,
16000 			    snap_lastimport, snap) != 0) {
16001 				switch (scf_error()) {
16002 				case SCF_ERROR_NOT_FOUND :
16003 				case SCF_ERROR_DELETED:
16004 					continue;
16005 
16006 				case SCF_ERROR_CONNECTION_BROKEN:
16007 					uu_list_destroy(instances);
16008 					instances = NULL;
16009 					goto out;
16010 
16011 				case SCF_ERROR_HANDLE_MISMATCH:
16012 				case SCF_ERROR_NOT_BOUND:
16013 				case SCF_ERROR_NOT_SET:
16014 				default:
16015 					bad_error("scf_iter_service_instances",
16016 					    scf_error());
16017 				}
16018 			}
16019 		}
16020 
16021 		if (scf_instance_get_name(inst, instname,
16022 		    max_scf_name_len + 1) < 0) {
16023 			switch (scf_error()) {
16024 			case SCF_ERROR_NOT_FOUND :
16025 				continue;
16026 
16027 			case SCF_ERROR_CONNECTION_BROKEN:
16028 			case SCF_ERROR_DELETED:
16029 				uu_list_destroy(instances);
16030 				instances = NULL;
16031 				goto out;
16032 
16033 			case SCF_ERROR_HANDLE_MISMATCH:
16034 			case SCF_ERROR_NOT_BOUND:
16035 			case SCF_ERROR_NOT_SET:
16036 			default:
16037 				bad_error("scf_iter_service_instances",
16038 				    scf_error());
16039 			}
16040 		}
16041 
16042 		add_string(instances, instname);
16043 	}
16044 
16045 out:
16046 	if (snap)
16047 		scf_snapshot_destroy(snap);
16048 
16049 	scf_instance_destroy(inst);
16050 	scf_iter_destroy(inst_iter);
16051 	free(instname);
16052 	return (instances);
16053 }
16054 
16055 /*
16056  * disable an instance but wait for the instance to
16057  * move out of the running state.
16058  *
16059  * Returns 0 : if the instance did not disable
16060  * Returns non-zero : if the instance disabled.
16061  *
16062  */
16063 static int
16064 disable_instance(scf_instance_t *instance)
16065 {
16066 	char	*fmribuf;
16067 	int	enabled = 10000;
16068 
16069 	if (inst_is_running(instance)) {
16070 		fmribuf = safe_malloc(max_scf_name_len + 1);
16071 		if (scf_instance_to_fmri(instance, fmribuf,
16072 		    max_scf_name_len + 1) < 0) {
16073 			free(fmribuf);
16074 			return (0);
16075 		}
16076 
16077 		/*
16078 		 * If the instance cannot be disabled then return
16079 		 * failure to disable and let the caller decide
16080 		 * if that is of importance.
16081 		 */
16082 		if (smf_disable_instance(fmribuf, 0) != 0) {
16083 			free(fmribuf);
16084 			return (0);
16085 		}
16086 
16087 		while (enabled) {
16088 			if (!inst_is_running(instance))
16089 				break;
16090 
16091 			(void) poll(NULL, 0, 5);
16092 			enabled = enabled - 5;
16093 		}
16094 
16095 		free(fmribuf);
16096 	}
16097 
16098 	return (enabled);
16099 }
16100 
16101 /*
16102  * Function to compare two service_manifest structures.
16103  */
16104 /* ARGSUSED2 */
16105 static int
16106 service_manifest_compare(const void *left, const void *right, void *unused)
16107 {
16108 	service_manifest_t *l = (service_manifest_t *)left;
16109 	service_manifest_t *r = (service_manifest_t *)right;
16110 	int rc;
16111 
16112 	rc = strcmp(l->servicename, r->servicename);
16113 
16114 	return (rc);
16115 }
16116 
16117 /*
16118  * Look for the provided service in the service to manifest
16119  * tree.  If the service exists, and a manifest was provided
16120  * then add the manifest to that service.  If the service
16121  * does not exist, then add the service and manifest to the
16122  * list.
16123  *
16124  * If the manifest is NULL, return the element if found.  If
16125  * the service is not found return NULL.
16126  */
16127 service_manifest_t *
16128 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16129 {
16130 	service_manifest_t	elem;
16131 	service_manifest_t	*fnelem;
16132 	uu_avl_index_t		marker;
16133 
16134 	elem.servicename = svnbuf;
16135 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16136 
16137 	if (mfst) {
16138 		if (fnelem) {
16139 			add_string(fnelem->mfstlist, strdup(mfst));
16140 		} else {
16141 			fnelem = safe_malloc(sizeof (*fnelem));
16142 			fnelem->servicename = safe_strdup(svnbuf);
16143 			if ((fnelem->mfstlist =
16144 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16145 				uu_die(gettext("Could not create property "
16146 				    "list: %s\n"), uu_strerror(uu_error()));
16147 
16148 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16149 
16150 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16151 		}
16152 	}
16153 
16154 	return (fnelem);
16155 }
16156 
16157 /*
16158  * Create the service to manifest avl tree.
16159  *
16160  * Walk each of the manifests currently installed in the supported
16161  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16162  * each of the manifests, inventory the services and add them to
16163  * the tree.
16164  *
16165  * Code that calls this function should make sure fileystem/minimal is online,
16166  * /var is available, since this function walks the /var/svc/manifest directory.
16167  */
16168 static void
16169 create_manifest_tree(void)
16170 {
16171 	manifest_info_t **entry;
16172 	manifest_info_t **manifests;
16173 	uu_list_walk_t	*svcs;
16174 	bundle_t	*b;
16175 	entity_t	*mfsvc;
16176 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16177 	int		c, status;
16178 
16179 	if (service_manifest_pool)
16180 		return;
16181 
16182 	/*
16183 	 * Create the list pool for the service manifest list
16184 	 */
16185 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16186 	    sizeof (service_manifest_t),
16187 	    offsetof(service_manifest_t, svcmfst_node),
16188 	    service_manifest_compare, UU_DEFAULT);
16189 	if (service_manifest_pool == NULL)
16190 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16191 		    uu_strerror(uu_error()));
16192 
16193 	/*
16194 	 * Create the list
16195 	 */
16196 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16197 	    UU_DEFAULT);
16198 	if (service_manifest_tree == NULL)
16199 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16200 		    uu_strerror(uu_error()));
16201 
16202 	/*
16203 	 * Walk the manifests adding the service(s) from each manifest.
16204 	 *
16205 	 * If a service already exists add the manifest to the manifest
16206 	 * list for that service.  This covers the case of a service that
16207 	 * is supported by multiple manifest files.
16208 	 */
16209 	for (c = 0; dirs[c]; c++) {
16210 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16211 		if (status < 0) {
16212 			uu_warn(gettext("file tree walk of %s encountered "
16213 			    "error %s\n"), dirs[c], strerror(errno));
16214 
16215 			uu_avl_destroy(service_manifest_tree);
16216 			service_manifest_tree = NULL;
16217 			return;
16218 		}
16219 
16220 		/*
16221 		 * If a manifest that was in the list is not found
16222 		 * then skip and go to the next manifest file.
16223 		 */
16224 		if (manifests != NULL) {
16225 			for (entry = manifests; *entry != NULL; entry++) {
16226 				b = internal_bundle_new();
16227 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16228 				    SVCCFG_OP_IMPORT) != 0) {
16229 					internal_bundle_free(b);
16230 					continue;
16231 				}
16232 
16233 				svcs = uu_list_walk_start(b->sc_bundle_services,
16234 				    0);
16235 				if (svcs == NULL) {
16236 					internal_bundle_free(b);
16237 					continue;
16238 				}
16239 
16240 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16241 				    NULL) {
16242 					/* Add manifest to service */
16243 					(void) find_add_svc_mfst(mfsvc->sc_name,
16244 					    (*entry)->mi_path);
16245 				}
16246 
16247 				uu_list_walk_end(svcs);
16248 				internal_bundle_free(b);
16249 			}
16250 
16251 			free_manifest_array(manifests);
16252 		}
16253 	}
16254 }
16255 
16256 /*
16257  * Check the manifest history file to see
16258  * if the service was ever installed from
16259  * one of the supported directories.
16260  *
16261  * Return Values :
16262  * 	-1 - if there's error reading manifest history file
16263  *	 1 - if the service is not found
16264  *	 0 - if the service is found
16265  */
16266 static int
16267 check_mfst_history(const char *svcname)
16268 {
16269 	struct stat	st;
16270 	caddr_t		mfsthist_start;
16271 	char		*svnbuf;
16272 	int		fd;
16273 	int		r = 1;
16274 
16275 	fd = open(MFSTHISTFILE, O_RDONLY);
16276 	if (fd == -1) {
16277 		uu_warn(gettext("Unable to open the history file\n"));
16278 		return (-1);
16279 	}
16280 
16281 	if (fstat(fd, &st) == -1) {
16282 		uu_warn(gettext("Unable to stat the history file\n"));
16283 		return (-1);
16284 	}
16285 
16286 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16287 	    MAP_PRIVATE, fd, 0);
16288 
16289 	(void) close(fd);
16290 	if (mfsthist_start == MAP_FAILED ||
16291 	    *(mfsthist_start + st.st_size) != '\0') {
16292 		(void) munmap(mfsthist_start, st.st_size);
16293 		return (-1);
16294 	}
16295 
16296 	/*
16297 	 * The manifest history file is a space delimited list
16298 	 * of service and instance to manifest linkage.  Adding
16299 	 * a space to the end of the service name so to get only
16300 	 * the service that is being searched for.
16301 	 */
16302 	svnbuf = uu_msprintf("%s ", svcname);
16303 	if (svnbuf == NULL)
16304 		uu_die(gettext("Out of memory"));
16305 
16306 	if (strstr(mfsthist_start, svnbuf) != NULL)
16307 		r = 0;
16308 
16309 	(void) munmap(mfsthist_start, st.st_size);
16310 	uu_free(svnbuf);
16311 	return (r);
16312 }
16313 
16314 /*
16315  * Take down each of the instances in the service
16316  * and remove them, then delete the service.
16317  */
16318 static void
16319 teardown_service(scf_service_t *svc, const char *svnbuf)
16320 {
16321 	scf_instance_t	*instance;
16322 	scf_iter_t	*iter;
16323 	int		r;
16324 
16325 	safe_printf(gettext("Delete service %s as there are no "
16326 	    "supporting manifests\n"), svnbuf);
16327 
16328 	instance = scf_instance_create(g_hndl);
16329 	iter = scf_iter_create(g_hndl);
16330 	if (iter == NULL || instance == NULL) {
16331 		uu_warn(gettext("Unable to create supporting entities to "
16332 		    "teardown the service\n"));
16333 		uu_warn(gettext("scf error is : %s\n"),
16334 		    scf_strerror(scf_error()));
16335 		scfdie();
16336 	}
16337 
16338 	if (scf_iter_service_instances(iter, svc) != 0) {
16339 		switch (scf_error()) {
16340 		case SCF_ERROR_CONNECTION_BROKEN:
16341 		case SCF_ERROR_DELETED:
16342 			goto out;
16343 
16344 		case SCF_ERROR_HANDLE_MISMATCH:
16345 		case SCF_ERROR_NOT_BOUND:
16346 		case SCF_ERROR_NOT_SET:
16347 		default:
16348 			bad_error("scf_iter_service_instances",
16349 			    scf_error());
16350 		}
16351 	}
16352 
16353 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16354 		if (r == -1) {
16355 			uu_warn(gettext("Error - %s\n"),
16356 			    scf_strerror(scf_error()));
16357 			goto out;
16358 		}
16359 
16360 		(void) disable_instance(instance);
16361 	}
16362 
16363 	/*
16364 	 * Delete the service... forcing the deletion in case
16365 	 * any of the instances did not disable.
16366 	 */
16367 	(void) lscf_service_delete(svc, 1);
16368 out:
16369 	scf_instance_destroy(instance);
16370 	scf_iter_destroy(iter);
16371 }
16372 
16373 /*
16374  * Get the list of instances supported by the manifest
16375  * file.
16376  *
16377  * Return 0 if there are no instances.
16378  *
16379  * Return -1 if there are errors attempting to collect instances.
16380  *
16381  * Return the count of instances found if there are no errors.
16382  *
16383  */
16384 static int
16385 check_instance_support(char *mfstfile, const char *svcname,
16386     uu_list_t *instances)
16387 {
16388 	uu_list_walk_t	*svcs, *insts;
16389 	uu_list_t	*ilist;
16390 	bundle_t	*b;
16391 	entity_t	*mfsvc, *mfinst;
16392 	const char	*svcn;
16393 	int		rminstcnt = 0;
16394 
16395 
16396 	b = internal_bundle_new();
16397 
16398 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16399 		/*
16400 		 * Unable to process the manifest file for
16401 		 * instance support, so just return as
16402 		 * don't want to remove instances that could
16403 		 * not be accounted for that might exist here.
16404 		 */
16405 		internal_bundle_free(b);
16406 		return (0);
16407 	}
16408 
16409 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16410 	if (svcs == NULL) {
16411 		internal_bundle_free(b);
16412 		return (0);
16413 	}
16414 
16415 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16416 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16417 
16418 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16419 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16420 			break;
16421 	}
16422 	uu_list_walk_end(svcs);
16423 
16424 	if (mfsvc == NULL) {
16425 		internal_bundle_free(b);
16426 		return (-1);
16427 	}
16428 
16429 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16430 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16431 		internal_bundle_free(b);
16432 		return (0);
16433 	}
16434 
16435 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16436 		/*
16437 		 * Remove the instance from the instances list.
16438 		 * The unaccounted for instances will be removed
16439 		 * from the service once all manifests are
16440 		 * processed.
16441 		 */
16442 		(void) remove_string(instances,
16443 		    mfinst->sc_name);
16444 		rminstcnt++;
16445 	}
16446 
16447 	uu_list_walk_end(insts);
16448 	internal_bundle_free(b);
16449 
16450 	return (rminstcnt);
16451 }
16452 
16453 /*
16454  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16455  * 'false' to indicate there's no manifest file(s) found for the service.
16456  */
16457 static void
16458 svc_add_no_support(scf_service_t *svc)
16459 {
16460 	char	*pname;
16461 
16462 	/* Add no support */
16463 	cur_svc = svc;
16464 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16465 		return;
16466 
16467 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16468 	if (pname == NULL)
16469 		uu_die(gettext("Out of memory.\n"));
16470 
16471 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16472 
16473 	uu_free(pname);
16474 	cur_svc = NULL;
16475 }
16476 
16477 /*
16478  * This function handles all upgrade scenarios for a service that doesn't have
16479  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16480  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16481  * manifest(s) mapping. Manifests under supported directories are inventoried
16482  * and a property is added for each file that delivers configuration to the
16483  * service.  A service that has no corresponding manifest files (deleted) are
16484  * removed from repository.
16485  *
16486  * Unsupported services:
16487  *
16488  * A service is considered unsupported if there is no corresponding manifest
16489  * in the supported directories for that service and the service isn't in the
16490  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16491  * services and instances that were delivered by Solaris before the introduction
16492  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16493  * the path to the manifest file that defined the service or instance.
16494  *
16495  * Another type of unsupported services is 'handcrafted' services,
16496  * programmatically created services or services created by dependent entries
16497  * in other manifests. A handcrafted service is identified by its lack of any
16498  * instance containing last-import snapshot which is created during svccfg
16499  * import.
16500  *
16501  * This function sets a flag for unsupported services by setting services'
16502  * SCF_PG_MANIFESTFILES/support property to false.
16503  */
16504 static void
16505 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16506 {
16507 	service_manifest_t	*elem;
16508 	uu_list_walk_t		*mfwalk;
16509 	string_list_t		*mfile;
16510 	uu_list_t		*instances;
16511 	const char		*sname;
16512 	char			*pname;
16513 	int			r;
16514 
16515 	/*
16516 	 * Since there's no guarantee manifests under /var are available during
16517 	 * early import, don't perform any upgrade during early import.
16518 	 */
16519 	if (IGNORE_VAR)
16520 		return;
16521 
16522 	if (service_manifest_tree == NULL) {
16523 		create_manifest_tree();
16524 	}
16525 
16526 	/*
16527 	 * Find service's supporting manifest(s) after
16528 	 * stripping off the svc:/ prefix that is part
16529 	 * of the fmri that is not used in the service
16530 	 * manifest bundle list.
16531 	 */
16532 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16533 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16534 	elem = find_add_svc_mfst(sname, NULL);
16535 	if (elem == NULL) {
16536 
16537 		/*
16538 		 * A handcrafted service, one that has no instance containing
16539 		 * last-import snapshot, should get unsupported flag.
16540 		 */
16541 		instances = create_instance_list(svc, 1);
16542 		if (instances == NULL) {
16543 			uu_warn(gettext("Unable to create instance list %s\n"),
16544 			    svcname);
16545 			return;
16546 		}
16547 
16548 		if (uu_list_numnodes(instances) == 0) {
16549 			svc_add_no_support(svc);
16550 			return;
16551 		}
16552 
16553 		/*
16554 		 * If the service is in the history file, and its supporting
16555 		 * manifests are not found, we can safely delete the service
16556 		 * because its manifests are removed from the system.
16557 		 *
16558 		 * Services not found in the history file are not delivered by
16559 		 * Solaris and/or delivered outside supported directories, set
16560 		 * unsupported flag for these services.
16561 		 */
16562 		r = check_mfst_history(svcname);
16563 		if (r == -1)
16564 			return;
16565 
16566 		if (r) {
16567 			/* Set unsupported flag for service  */
16568 			svc_add_no_support(svc);
16569 		} else {
16570 			/* Delete the service */
16571 			teardown_service(svc, svcname);
16572 		}
16573 
16574 		return;
16575 	}
16576 
16577 	/*
16578 	 * Walk through the list of manifests and add them
16579 	 * to the service.
16580 	 *
16581 	 * Create a manifestfiles pg and add the property.
16582 	 */
16583 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16584 	if (mfwalk == NULL)
16585 		return;
16586 
16587 	cur_svc = svc;
16588 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16589 	if (r != 0) {
16590 		cur_svc = NULL;
16591 		return;
16592 	}
16593 
16594 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16595 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16596 		    mhash_filename_to_propname(mfile->str, 0));
16597 		if (pname == NULL)
16598 			uu_die(gettext("Out of memory.\n"));
16599 
16600 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16601 		uu_free(pname);
16602 	}
16603 	uu_list_walk_end(mfwalk);
16604 
16605 	cur_svc = NULL;
16606 }
16607 
16608 /*
16609  * Take a service and process the manifest file entires to see if
16610  * there is continued support for the service and instances.  If
16611  * not cleanup as appropriate.
16612  *
16613  * If a service does not have a manifest files entry flag it for
16614  * upgrade and return.
16615  *
16616  * For each manifestfiles property check if the manifest file is
16617  * under the supported /lib/svc/manifest or /var/svc/manifest path
16618  * and if not then return immediately as this service is not supported
16619  * by the cleanup mechanism and should be ignored.
16620  *
16621  * For each manifest file that is supported, check to see if the
16622  * file exists.  If not then remove the manifest file property
16623  * from the service and the smf/manifest hash table.  If the manifest
16624  * file exists then verify that it supports the instances that are
16625  * part of the service.
16626  *
16627  * Once all manifest files have been accounted for remove any instances
16628  * that are no longer supported in the service.
16629  *
16630  * Return values :
16631  * 0 - Successfully processed the service
16632  * non-zero - failed to process the service
16633  *
16634  * On most errors, will just return to wait and get the next service,
16635  * unless in case of unable to create the needed structures which is
16636  * most likely a fatal error that is not going to be recoverable.
16637  */
16638 int
16639 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16640 {
16641 	struct mpg_mfile	*mpntov;
16642 	struct mpg_mfile	**mpvarry = NULL;
16643 	scf_service_t		*svc;
16644 	scf_propertygroup_t	*mpg;
16645 	scf_property_t		*mp;
16646 	scf_value_t		*mv;
16647 	scf_iter_t		*mi;
16648 	scf_instance_t		*instance;
16649 	uu_list_walk_t		*insts;
16650 	uu_list_t		*instances = NULL;
16651 	boolean_t		activity = (boolean_t)act;
16652 	char			*mpnbuf;
16653 	char			*mpvbuf;
16654 	char			*pgpropbuf;
16655 	int			mfstcnt, rminstct, instct, mfstmax;
16656 	int			index;
16657 	int			r = 0;
16658 
16659 	assert(g_hndl != NULL);
16660 	assert(wip->svc != NULL);
16661 	assert(wip->fmri != NULL);
16662 
16663 	svc = wip->svc;
16664 
16665 	mpg = scf_pg_create(g_hndl);
16666 	mp = scf_property_create(g_hndl);
16667 	mi = scf_iter_create(g_hndl);
16668 	mv = scf_value_create(g_hndl);
16669 	instance = scf_instance_create(g_hndl);
16670 
16671 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16672 	    instance == NULL) {
16673 		uu_warn(gettext("Unable to create the supporting entities\n"));
16674 		uu_warn(gettext("scf error is : %s\n"),
16675 		    scf_strerror(scf_error()));
16676 		scfdie();
16677 	}
16678 
16679 	/*
16680 	 * Get the manifestfiles property group to be parsed for
16681 	 * files existence.
16682 	 */
16683 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16684 		switch (scf_error()) {
16685 		case SCF_ERROR_NOT_FOUND:
16686 			upgrade_svc_mfst_connection(svc, wip->fmri);
16687 			break;
16688 		case SCF_ERROR_DELETED:
16689 		case SCF_ERROR_CONNECTION_BROKEN:
16690 			goto out;
16691 
16692 		case SCF_ERROR_HANDLE_MISMATCH:
16693 		case SCF_ERROR_NOT_BOUND:
16694 		case SCF_ERROR_NOT_SET:
16695 		default:
16696 			bad_error("scf_iter_pg_properties",
16697 			    scf_error());
16698 		}
16699 
16700 		goto out;
16701 	}
16702 
16703 	/*
16704 	 * Iterate through each of the manifestfiles properties
16705 	 * to determine what manifestfiles are available.
16706 	 *
16707 	 * If a manifest file is supported then increment the
16708 	 * count and therefore the service is safe.
16709 	 */
16710 	if (scf_iter_pg_properties(mi, mpg) != 0) {
16711 		switch (scf_error()) {
16712 		case SCF_ERROR_DELETED:
16713 		case SCF_ERROR_CONNECTION_BROKEN:
16714 			goto out;
16715 
16716 		case SCF_ERROR_HANDLE_MISMATCH:
16717 		case SCF_ERROR_NOT_BOUND:
16718 		case SCF_ERROR_NOT_SET:
16719 		default:
16720 			bad_error("scf_iter_pg_properties",
16721 			    scf_error());
16722 		}
16723 	}
16724 
16725 	mfstcnt = 0;
16726 	mfstmax = MFSTFILE_MAX;
16727 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
16728 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
16729 		if (r == -1)
16730 			bad_error(gettext("Unable to iterate through "
16731 			    "manifestfiles properties : %s"),
16732 			    scf_error());
16733 
16734 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
16735 		mpnbuf = safe_malloc(max_scf_name_len + 1);
16736 		mpvbuf = safe_malloc(max_scf_value_len + 1);
16737 		mpntov->mpg = mpnbuf;
16738 		mpntov->mfile = mpvbuf;
16739 		mpntov->access = 1;
16740 		if (scf_property_get_name(mp, mpnbuf,
16741 		    max_scf_name_len + 1) < 0) {
16742 			uu_warn(gettext("Unable to get manifest file "
16743 			    "property : %s\n"),
16744 			    scf_strerror(scf_error()));
16745 
16746 			switch (scf_error()) {
16747 			case SCF_ERROR_DELETED:
16748 			case SCF_ERROR_CONNECTION_BROKEN:
16749 				r = scferror2errno(scf_error());
16750 				goto out_free;
16751 
16752 			case SCF_ERROR_HANDLE_MISMATCH:
16753 			case SCF_ERROR_NOT_BOUND:
16754 			case SCF_ERROR_NOT_SET:
16755 			default:
16756 				bad_error("scf_iter_pg_properties",
16757 				    scf_error());
16758 			}
16759 		}
16760 
16761 		/*
16762 		 * The support property is a boolean value that indicates
16763 		 * if the service is supported for manifest file deletion.
16764 		 * Currently at this time there is no code that sets this
16765 		 * value to true.  So while we could just let this be caught
16766 		 * by the support check below, in the future this by be set
16767 		 * to true and require processing.  So for that, go ahead
16768 		 * and check here, and just return if false.  Otherwise,
16769 		 * fall through expecting that other support checks will
16770 		 * handle the entries.
16771 		 */
16772 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
16773 			uint8_t	support;
16774 
16775 			if (scf_property_get_value(mp, mv) != 0 ||
16776 			    scf_value_get_boolean(mv, &support) != 0) {
16777 				uu_warn(gettext("Unable to get the manifest "
16778 				    "support value: %s\n"),
16779 				    scf_strerror(scf_error()));
16780 
16781 				switch (scf_error()) {
16782 				case SCF_ERROR_DELETED:
16783 				case SCF_ERROR_CONNECTION_BROKEN:
16784 					r = scferror2errno(scf_error());
16785 					goto out_free;
16786 
16787 				case SCF_ERROR_HANDLE_MISMATCH:
16788 				case SCF_ERROR_NOT_BOUND:
16789 				case SCF_ERROR_NOT_SET:
16790 				default:
16791 					bad_error("scf_iter_pg_properties",
16792 					    scf_error());
16793 				}
16794 			}
16795 
16796 			if (support == B_FALSE)
16797 				goto out_free;
16798 		}
16799 
16800 		/*
16801 		 * Anything with a manifest outside of the supported
16802 		 * directories, immediately bail out because that makes
16803 		 * this service non-supported.  We don't even want
16804 		 * to do instance processing in this case because the
16805 		 * instances could be part of the non-supported manifest.
16806 		 */
16807 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
16808 			/*
16809 			 * Manifest is not in /lib/svc, so we need to
16810 			 * consider the /var/svc case.
16811 			 */
16812 			if (strncmp(mpnbuf, VARSVC_PR,
16813 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
16814 				/*
16815 				 * Either the manifest is not in /var/svc or
16816 				 * /var is not yet mounted.  We ignore the
16817 				 * manifest either because it is not in a
16818 				 * standard location or because we cannot
16819 				 * currently access the manifest.
16820 				 */
16821 				goto out_free;
16822 			}
16823 		}
16824 
16825 		/*
16826 		 * Get the value to of the manifest file for this entry
16827 		 * for access verification and instance support
16828 		 * verification if it still exists.
16829 		 *
16830 		 * During Early Manifest Import if the manifest is in
16831 		 * /var/svc then it may not yet be available for checking
16832 		 * so we must determine if /var/svc is available.  If not
16833 		 * then defer until Late Manifest Import to cleanup.
16834 		 */
16835 		if (scf_property_get_value(mp, mv) != 0) {
16836 			uu_warn(gettext("Unable to get the manifest file "
16837 			    "value: %s\n"),
16838 			    scf_strerror(scf_error()));
16839 
16840 			switch (scf_error()) {
16841 			case SCF_ERROR_DELETED:
16842 			case SCF_ERROR_CONNECTION_BROKEN:
16843 				r = scferror2errno(scf_error());
16844 				goto out_free;
16845 
16846 			case SCF_ERROR_HANDLE_MISMATCH:
16847 			case SCF_ERROR_NOT_BOUND:
16848 			case SCF_ERROR_NOT_SET:
16849 			default:
16850 				bad_error("scf_property_get_value",
16851 				    scf_error());
16852 			}
16853 		}
16854 
16855 		if (scf_value_get_astring(mv, mpvbuf,
16856 		    max_scf_value_len + 1) < 0) {
16857 			uu_warn(gettext("Unable to get the manifest "
16858 			    "file : %s\n"),
16859 			    scf_strerror(scf_error()));
16860 
16861 			switch (scf_error()) {
16862 			case SCF_ERROR_DELETED:
16863 			case SCF_ERROR_CONNECTION_BROKEN:
16864 				r = scferror2errno(scf_error());
16865 				goto out_free;
16866 
16867 			case SCF_ERROR_HANDLE_MISMATCH:
16868 			case SCF_ERROR_NOT_BOUND:
16869 			case SCF_ERROR_NOT_SET:
16870 			default:
16871 				bad_error("scf_value_get_astring",
16872 				    scf_error());
16873 			}
16874 		}
16875 
16876 		mpvarry[mfstcnt] = mpntov;
16877 		mfstcnt++;
16878 
16879 		/*
16880 		 * Check for the need to reallocate array
16881 		 */
16882 		if (mfstcnt >= (mfstmax - 1)) {
16883 			struct mpg_mfile **newmpvarry;
16884 
16885 			mfstmax = mfstmax * 2;
16886 			newmpvarry = realloc(mpvarry,
16887 			    sizeof (struct mpg_mfile *) * mfstmax);
16888 
16889 			if (newmpvarry == NULL)
16890 				goto out_free;
16891 
16892 			mpvarry = newmpvarry;
16893 		}
16894 
16895 		mpvarry[mfstcnt] = NULL;
16896 	}
16897 
16898 	for (index = 0; mpvarry[index]; index++) {
16899 		mpntov = mpvarry[index];
16900 
16901 		/*
16902 		 * Check to see if the manifestfile is accessable, if so hand
16903 		 * this service and manifestfile off to be processed for
16904 		 * instance support.
16905 		 */
16906 		mpnbuf = mpntov->mpg;
16907 		mpvbuf = mpntov->mfile;
16908 		if (access(mpvbuf, F_OK) != 0) {
16909 			mpntov->access = 0;
16910 			activity++;
16911 			mfstcnt--;
16912 			/* Remove the entry from the service */
16913 			cur_svc = svc;
16914 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16915 			    mpnbuf);
16916 			if (pgpropbuf == NULL)
16917 				uu_die(gettext("Out of memory.\n"));
16918 
16919 			lscf_delprop(pgpropbuf);
16920 			cur_svc = NULL;
16921 
16922 			uu_free(pgpropbuf);
16923 		}
16924 	}
16925 
16926 	/*
16927 	 * If mfstcnt is 0, none of the manifests that supported the service
16928 	 * existed so remove the service.
16929 	 */
16930 	if (mfstcnt == 0) {
16931 		teardown_service(svc, wip->fmri);
16932 
16933 		goto out_free;
16934 	}
16935 
16936 	if (activity) {
16937 		int	nosvcsupport = 0;
16938 
16939 		/*
16940 		 * If the list of service instances is NULL then
16941 		 * create the list.
16942 		 */
16943 		instances = create_instance_list(svc, 1);
16944 		if (instances == NULL) {
16945 			uu_warn(gettext("Unable to create instance list %s\n"),
16946 			    wip->fmri);
16947 			goto out_free;
16948 		}
16949 
16950 		rminstct = uu_list_numnodes(instances);
16951 		instct = rminstct;
16952 
16953 		for (index = 0; mpvarry[index]; index++) {
16954 			mpntov = mpvarry[index];
16955 			if (mpntov->access == 0)
16956 				continue;
16957 
16958 			mpnbuf = mpntov->mpg;
16959 			mpvbuf = mpntov->mfile;
16960 			r = check_instance_support(mpvbuf, wip->fmri,
16961 			    instances);
16962 			if (r == -1) {
16963 				nosvcsupport++;
16964 			} else {
16965 				rminstct -= r;
16966 			}
16967 		}
16968 
16969 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
16970 			teardown_service(svc, wip->fmri);
16971 
16972 			goto out_free;
16973 		}
16974 	}
16975 
16976 	/*
16977 	 * If there are instances left on the instance list, then
16978 	 * we must remove them.
16979 	 */
16980 	if (instances != NULL && uu_list_numnodes(instances)) {
16981 		string_list_t *sp;
16982 
16983 		insts = uu_list_walk_start(instances, 0);
16984 		while ((sp = uu_list_walk_next(insts)) != NULL) {
16985 			/*
16986 			 * Remove the instance from the instances list.
16987 			 */
16988 			safe_printf(gettext("Delete instance %s from "
16989 			    "service %s\n"), sp->str, wip->fmri);
16990 			if (scf_service_get_instance(svc, sp->str,
16991 			    instance) != SCF_SUCCESS) {
16992 				(void) uu_warn("scf_error - %s\n",
16993 				    scf_strerror(scf_error()));
16994 
16995 				continue;
16996 			}
16997 
16998 			(void) disable_instance(instance);
16999 
17000 			(void) lscf_instance_delete(instance, 1);
17001 		}
17002 		scf_instance_destroy(instance);
17003 		uu_list_walk_end(insts);
17004 	}
17005 
17006 out_free:
17007 	if (mpvarry) {
17008 		struct mpg_mfile *fmpntov;
17009 
17010 		for (index = 0; mpvarry[index]; index++) {
17011 			fmpntov  = mpvarry[index];
17012 			if (fmpntov->mpg == mpnbuf)
17013 				mpnbuf = NULL;
17014 			free(fmpntov->mpg);
17015 
17016 			if (fmpntov->mfile == mpvbuf)
17017 				mpvbuf = NULL;
17018 			free(fmpntov->mfile);
17019 
17020 			if (fmpntov == mpntov)
17021 				mpntov = NULL;
17022 			free(fmpntov);
17023 		}
17024 		if (mpnbuf)
17025 			free(mpnbuf);
17026 		if (mpvbuf)
17027 			free(mpvbuf);
17028 		if (mpntov)
17029 			free(mpntov);
17030 
17031 		free(mpvarry);
17032 	}
17033 out:
17034 	scf_pg_destroy(mpg);
17035 	scf_property_destroy(mp);
17036 	scf_iter_destroy(mi);
17037 	scf_value_destroy(mv);
17038 
17039 	return (0);
17040 }
17041 
17042 /*
17043  * Take the service and search for the manifestfiles property
17044  * in each of the property groups.  If the manifest file
17045  * associated with the property does not exist then remove
17046  * the property group.
17047  */
17048 int
17049 lscf_hash_cleanup()
17050 {
17051 	scf_service_t		*svc;
17052 	scf_scope_t		*scope;
17053 	scf_propertygroup_t	*pg;
17054 	scf_property_t		*prop;
17055 	scf_value_t		*val;
17056 	scf_iter_t		*iter;
17057 	char			*pgname = NULL;
17058 	char			*mfile = NULL;
17059 	int			r;
17060 
17061 	svc = scf_service_create(g_hndl);
17062 	scope = scf_scope_create(g_hndl);
17063 	pg = scf_pg_create(g_hndl);
17064 	prop = scf_property_create(g_hndl);
17065 	val = scf_value_create(g_hndl);
17066 	iter = scf_iter_create(g_hndl);
17067 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17068 	    svc == NULL || scope == NULL) {
17069 		uu_warn(gettext("Unable to create a property group, or "
17070 		    "property\n"));
17071 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17072 		    "pg is not NULL");
17073 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17074 		    "prop is not NULL");
17075 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17076 		    "val is not NULL");
17077 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17078 		    "iter is not NULL");
17079 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17080 		    "svc is not NULL");
17081 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17082 		    "scope is not NULL");
17083 		uu_warn(gettext("scf error is : %s\n"),
17084 		    scf_strerror(scf_error()));
17085 		scfdie();
17086 	}
17087 
17088 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17089 		switch (scf_error()) {
17090 		case SCF_ERROR_CONNECTION_BROKEN:
17091 		case SCF_ERROR_NOT_FOUND:
17092 			goto out;
17093 
17094 		case SCF_ERROR_HANDLE_MISMATCH:
17095 		case SCF_ERROR_NOT_BOUND:
17096 		case SCF_ERROR_INVALID_ARGUMENT:
17097 		default:
17098 			bad_error("scf_handle_get_scope", scf_error());
17099 		}
17100 	}
17101 
17102 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17103 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17104 		    HASH_SVC);
17105 		goto out;
17106 	}
17107 
17108 	pgname = safe_malloc(max_scf_name_len + 1);
17109 	mfile = safe_malloc(max_scf_value_len + 1);
17110 
17111 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17112 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17113 		    scf_strerror(scf_error()));
17114 		goto out;
17115 	}
17116 
17117 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17118 		if (r == -1)
17119 			goto out;
17120 
17121 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17122 			switch (scf_error()) {
17123 			case SCF_ERROR_DELETED:
17124 				return (ENODEV);
17125 
17126 			case SCF_ERROR_CONNECTION_BROKEN:
17127 				return (ECONNABORTED);
17128 
17129 			case SCF_ERROR_NOT_SET:
17130 			case SCF_ERROR_NOT_BOUND:
17131 			default:
17132 				bad_error("scf_pg_get_name", scf_error());
17133 			}
17134 		}
17135 		if (IGNORE_VAR) {
17136 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17137 				continue;
17138 		}
17139 
17140 		/*
17141 		 * If unable to get the property continue as this is an
17142 		 * entry that has no location to check against.
17143 		 */
17144 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17145 			continue;
17146 		}
17147 
17148 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17149 			uu_warn(gettext("Unable to get value from %s\n"),
17150 			    pgname);
17151 
17152 			switch (scf_error()) {
17153 			case SCF_ERROR_DELETED:
17154 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17155 			case SCF_ERROR_NOT_FOUND:
17156 			case SCF_ERROR_NOT_SET:
17157 				continue;
17158 
17159 			case SCF_ERROR_CONNECTION_BROKEN:
17160 				r = scferror2errno(scf_error());
17161 				goto out;
17162 
17163 			case SCF_ERROR_HANDLE_MISMATCH:
17164 			case SCF_ERROR_NOT_BOUND:
17165 			default:
17166 				bad_error("scf_property_get_value",
17167 				    scf_error());
17168 			}
17169 		}
17170 
17171 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17172 		    == -1) {
17173 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17174 			    pgname, scf_strerror(scf_error()));
17175 
17176 			switch (scf_error()) {
17177 			case SCF_ERROR_NOT_SET:
17178 			case SCF_ERROR_TYPE_MISMATCH:
17179 				continue;
17180 
17181 			default:
17182 				bad_error("scf_value_get_astring", scf_error());
17183 			}
17184 		}
17185 
17186 		if (access(mfile, F_OK) == 0)
17187 			continue;
17188 
17189 		(void) scf_pg_delete(pg);
17190 	}
17191 
17192 out:
17193 	scf_scope_destroy(scope);
17194 	scf_service_destroy(svc);
17195 	scf_pg_destroy(pg);
17196 	scf_property_destroy(prop);
17197 	scf_value_destroy(val);
17198 	scf_iter_destroy(iter);
17199 	free(pgname);
17200 	free(mfile);
17201 
17202 	return (0);
17203 }
17204 
17205 #ifndef NATIVE_BUILD
17206 /* ARGSUSED */
17207 CPL_MATCH_FN(complete_select)
17208 {
17209 	const char *arg0, *arg1, *arg1end;
17210 	int word_start, err = 0, r;
17211 	size_t len;
17212 	char *buf;
17213 
17214 	lscf_prep_hndl();
17215 
17216 	arg0 = line + strspn(line, " \t");
17217 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17218 
17219 	arg1 = arg0 + sizeof ("select") - 1;
17220 	arg1 += strspn(arg1, " \t");
17221 	word_start = arg1 - line;
17222 
17223 	arg1end = arg1 + strcspn(arg1, " \t");
17224 	if (arg1end < line + word_end)
17225 		return (0);
17226 
17227 	len = line + word_end - arg1;
17228 
17229 	buf = safe_malloc(max_scf_name_len + 1);
17230 
17231 	if (cur_snap != NULL) {
17232 		return (0);
17233 	} else if (cur_inst != NULL) {
17234 		return (0);
17235 	} else if (cur_svc != NULL) {
17236 		scf_instance_t *inst;
17237 		scf_iter_t *iter;
17238 
17239 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17240 		    (iter = scf_iter_create(g_hndl)) == NULL)
17241 			scfdie();
17242 
17243 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17244 			scfdie();
17245 
17246 		for (;;) {
17247 			r = scf_iter_next_instance(iter, inst);
17248 			if (r == 0)
17249 				break;
17250 			if (r != 1)
17251 				scfdie();
17252 
17253 			if (scf_instance_get_name(inst, buf,
17254 			    max_scf_name_len + 1) < 0)
17255 				scfdie();
17256 
17257 			if (strncmp(buf, arg1, len) == 0) {
17258 				err = cpl_add_completion(cpl, line, word_start,
17259 				    word_end, buf + len, "", " ");
17260 				if (err != 0)
17261 					break;
17262 			}
17263 		}
17264 
17265 		scf_iter_destroy(iter);
17266 		scf_instance_destroy(inst);
17267 
17268 		return (err);
17269 	} else {
17270 		scf_service_t *svc;
17271 		scf_iter_t *iter;
17272 
17273 		assert(cur_scope != NULL);
17274 
17275 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17276 		    (iter = scf_iter_create(g_hndl)) == NULL)
17277 			scfdie();
17278 
17279 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17280 			scfdie();
17281 
17282 		for (;;) {
17283 			r = scf_iter_next_service(iter, svc);
17284 			if (r == 0)
17285 				break;
17286 			if (r != 1)
17287 				scfdie();
17288 
17289 			if (scf_service_get_name(svc, buf,
17290 			    max_scf_name_len + 1) < 0)
17291 				scfdie();
17292 
17293 			if (strncmp(buf, arg1, len) == 0) {
17294 				err = cpl_add_completion(cpl, line, word_start,
17295 				    word_end, buf + len, "", " ");
17296 				if (err != 0)
17297 					break;
17298 			}
17299 		}
17300 
17301 		scf_iter_destroy(iter);
17302 		scf_service_destroy(svc);
17303 
17304 		return (err);
17305 	}
17306 }
17307 
17308 /* ARGSUSED */
17309 CPL_MATCH_FN(complete_command)
17310 {
17311 	uint32_t scope = 0;
17312 
17313 	if (cur_snap != NULL)
17314 		scope = CS_SNAP;
17315 	else if (cur_inst != NULL)
17316 		scope = CS_INST;
17317 	else if (cur_svc != NULL)
17318 		scope = CS_SVC;
17319 	else
17320 		scope = CS_SCOPE;
17321 
17322 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17323 }
17324 #endif	/* NATIVE_BUILD */
17325