xref: /titanic_50/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision 799823bbed51a695d01e13511bbb1369980bb714)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2012 Milan Jurik. All rights reserved.
25  */
26 
27 
28 #include <alloca.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <door.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <fnmatch.h>
35 #include <inttypes.h>
36 #include <libintl.h>
37 #include <libnvpair.h>
38 #include <libscf.h>
39 #include <libscf_priv.h>
40 #include <libtecla.h>
41 #include <libuutil.h>
42 #include <limits.h>
43 #include <locale.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <strings.h>
47 #include <unistd.h>
48 #include <wait.h>
49 #include <poll.h>
50 
51 #include <libxml/tree.h>
52 
53 #include <sys/param.h>
54 
55 #include <sys/stat.h>
56 #include <sys/mman.h>
57 
58 #include "svccfg.h"
59 #include "notify_params.h"
60 #include "manifest_hash.h"
61 #include "manifest_find.h"
62 
63 /* The colon namespaces in each entity (each followed by a newline). */
64 #define	COLON_NAMESPACES	":properties\n"
65 
66 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
67 
68 /* These are characters which the lexer requires to be in double-quotes. */
69 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
70 
71 #define	HASH_SIZE		16
72 #define	HASH_PG_TYPE		"framework"
73 #define	HASH_PG_FLAGS		0
74 #define	HASH_PROP		"md5sum"
75 
76 /*
77  * Indentation used in the output of the describe subcommand.
78  */
79 #define	TMPL_VALUE_INDENT	"  "
80 #define	TMPL_INDENT		"    "
81 #define	TMPL_INDENT_2X		"        "
82 #define	TMPL_CHOICE_INDENT	"      "
83 
84 /*
85  * Directory locations for manifests
86  */
87 #define	VARSVC_DIR		"/var/svc/manifest"
88 #define	LIBSVC_DIR		"/lib/svc/manifest"
89 #define	VARSVC_PR		"var_svc_manifest"
90 #define	LIBSVC_PR		"lib_svc_manifest"
91 #define	MFSTFILEPR		"manifestfile"
92 
93 #define	SUPPORTPROP		"support"
94 
95 #define	MFSTHISTFILE		"/lib/svc/share/mfsthistory"
96 
97 #define	MFSTFILE_MAX		16
98 
99 /*
100  * These are the classes of elements which may appear as children of service
101  * or instance elements in XML manifests.
102  */
103 struct entity_elts {
104 	xmlNodePtr	create_default_instance;
105 	xmlNodePtr	single_instance;
106 	xmlNodePtr	restarter;
107 	xmlNodePtr	dependencies;
108 	xmlNodePtr	dependents;
109 	xmlNodePtr	method_context;
110 	xmlNodePtr	exec_methods;
111 	xmlNodePtr	notify_params;
112 	xmlNodePtr	property_groups;
113 	xmlNodePtr	instances;
114 	xmlNodePtr	stability;
115 	xmlNodePtr	template;
116 };
117 
118 /*
119  * Likewise for property_group elements.
120  */
121 struct pg_elts {
122 	xmlNodePtr	stability;
123 	xmlNodePtr	propvals;
124 	xmlNodePtr	properties;
125 };
126 
127 /*
128  * Likewise for template elements.
129  */
130 struct template_elts {
131 	xmlNodePtr	common_name;
132 	xmlNodePtr	description;
133 	xmlNodePtr	documentation;
134 };
135 
136 /*
137  * Likewise for type (for notification parameters) elements.
138  */
139 struct params_elts {
140 	xmlNodePtr	paramval;
141 	xmlNodePtr	parameter;
142 };
143 
144 /*
145  * This structure is for snaplevel lists.  They are convenient because libscf
146  * only allows traversing snaplevels in one direction.
147  */
148 struct snaplevel {
149 	uu_list_node_t	list_node;
150 	scf_snaplevel_t	*sl;
151 };
152 
153 /*
154  * This is used for communication between lscf_service_export and
155  * export_callback.
156  */
157 struct export_args {
158 	const char	*filename;
159 	int 		flags;
160 };
161 
162 /*
163  * The service_manifest structure is used by the upgrade process
164  * to create a list of service to manifest linkages from the manifests
165  * in a set of given directories.
166  */
167 typedef struct service_manifest {
168 	const char 	*servicename;
169 	uu_list_t	*mfstlist;
170 	size_t	mfstlist_sz;
171 
172 	uu_avl_node_t	svcmfst_node;
173 } service_manifest_t;
174 
175 /*
176  * Structure to track the manifest file property group
177  * and the manifest file associated with that property
178  * group.  Also, a flag to keep the access once it has
179  * been checked.
180  */
181 struct mpg_mfile {
182 	char	*mpg;
183 	char	*mfile;
184 	int	access;
185 };
186 
187 const char * const scf_pg_general = SCF_PG_GENERAL;
188 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
189 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
190 const char * const scf_property_external = "external";
191 
192 const char * const snap_initial = "initial";
193 const char * const snap_lastimport = "last-import";
194 const char * const snap_previous = "previous";
195 const char * const snap_running = "running";
196 
197 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
198 
199 ssize_t max_scf_fmri_len;
200 ssize_t max_scf_name_len;
201 ssize_t max_scf_pg_type_len;
202 ssize_t max_scf_value_len;
203 static size_t max_scf_len;
204 
205 static scf_scope_t *cur_scope;
206 static scf_service_t *cur_svc = NULL;
207 static scf_instance_t *cur_inst = NULL;
208 static scf_snapshot_t *cur_snap = NULL;
209 static scf_snaplevel_t *cur_level = NULL;
210 
211 static uu_list_pool_t *snaplevel_pool;
212 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
213 static uu_list_t *cur_levels;
214 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
215 
216 static FILE *tempfile = NULL;
217 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
218 
219 static const char *emsg_entity_not_selected;
220 static const char *emsg_permission_denied;
221 static const char *emsg_create_xml;
222 static const char *emsg_cant_modify_snapshots;
223 static const char *emsg_invalid_for_snapshot;
224 static const char *emsg_read_only;
225 static const char *emsg_deleted;
226 static const char *emsg_invalid_pg_name;
227 static const char *emsg_invalid_prop_name;
228 static const char *emsg_no_such_pg;
229 static const char *emsg_fmri_invalid_pg_name;
230 static const char *emsg_fmri_invalid_pg_name_type;
231 static const char *emsg_pg_added;
232 static const char *emsg_pg_changed;
233 static const char *emsg_pg_deleted;
234 static const char *emsg_pg_mod_perm;
235 static const char *emsg_pg_add_perm;
236 static const char *emsg_pg_del_perm;
237 static const char *emsg_snap_perm;
238 static const char *emsg_dpt_dangling;
239 static const char *emsg_dpt_no_dep;
240 
241 static int li_only = 0;
242 static int no_refresh = 0;
243 
244 /* import globals, to minimize allocations */
245 static scf_scope_t *imp_scope = NULL;
246 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
247 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
248 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
249 static scf_snapshot_t *imp_rsnap = NULL;
250 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
251 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
252 static scf_property_t *imp_prop = NULL;
253 static scf_iter_t *imp_iter = NULL;
254 static scf_iter_t *imp_rpg_iter = NULL;
255 static scf_iter_t *imp_up_iter = NULL;
256 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
257 static char *imp_str = NULL;
258 static size_t imp_str_sz;
259 static char *imp_tsname = NULL;
260 static char *imp_fe1 = NULL;		/* for fmri_equal() */
261 static char *imp_fe2 = NULL;
262 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
263 
264 /* upgrade_dependents() globals */
265 static scf_instance_t *ud_inst = NULL;
266 static scf_snaplevel_t *ud_snpl = NULL;
267 static scf_propertygroup_t *ud_pg = NULL;
268 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
269 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
270 static int ud_run_dpts_pg_set = 0;
271 static scf_property_t *ud_prop = NULL;
272 static scf_property_t *ud_dpt_prop = NULL;
273 static scf_value_t *ud_val = NULL;
274 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
275 static scf_transaction_t *ud_tx = NULL;
276 static char *ud_ctarg = NULL;
277 static char *ud_oldtarg = NULL;
278 static char *ud_name = NULL;
279 
280 /* export globals */
281 static scf_instance_t *exp_inst;
282 static scf_propertygroup_t *exp_pg;
283 static scf_property_t *exp_prop;
284 static scf_value_t *exp_val;
285 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
286 static char *exp_str;
287 static size_t exp_str_sz;
288 
289 /* cleanup globals */
290 static uu_avl_pool_t *service_manifest_pool = NULL;
291 static uu_avl_t *service_manifest_tree = NULL;
292 
293 static void scfdie_lineno(int lineno) __NORETURN;
294 
295 static char *start_method_names[] = {
296 	"start",
297 	"inetd_start",
298 	NULL
299 };
300 
301 static struct uri_scheme {
302 	const char *scheme;
303 	const char *protocol;
304 } uri_scheme[] = {
305 	{ "mailto", "smtp" },
306 	{ "snmp", "snmp" },
307 	{ "syslog", "syslog" },
308 	{ NULL, NULL }
309 };
310 #define	URI_SCHEME_NUM ((sizeof (uri_scheme) / \
311     sizeof (struct uri_scheme)) - 1)
312 
313 static int
314 check_uri_scheme(const char *scheme)
315 {
316 	int i;
317 
318 	for (i = 0; uri_scheme[i].scheme != NULL; ++i) {
319 		if (strcmp(scheme, uri_scheme[i].scheme) == 0)
320 			return (i);
321 	}
322 
323 	return (-1);
324 }
325 
326 static int
327 check_uri_protocol(const char *p)
328 {
329 	int i;
330 
331 	for (i = 0; uri_scheme[i].protocol != NULL; ++i) {
332 		if (strcmp(p, uri_scheme[i].protocol) == 0)
333 			return (i);
334 	}
335 
336 	return (-1);
337 }
338 
339 /*
340  * For unexpected libscf errors.
341  */
342 #ifdef NDEBUG
343 
344 static void scfdie(void) __NORETURN;
345 
346 static void
347 scfdie(void)
348 {
349 	scf_error_t err = scf_error();
350 
351 	if (err == SCF_ERROR_CONNECTION_BROKEN)
352 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
353 
354 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
355 	    scf_strerror(err));
356 }
357 
358 #else
359 
360 #define	scfdie()	scfdie_lineno(__LINE__)
361 
362 static void
363 scfdie_lineno(int lineno)
364 {
365 	scf_error_t err = scf_error();
366 
367 	if (err == SCF_ERROR_CONNECTION_BROKEN)
368 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
369 
370 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
371 	    ": %s.\n"), lineno, scf_strerror(err));
372 }
373 
374 #endif
375 
376 static void
377 scfwarn(void)
378 {
379 	warn(gettext("Unexpected libscf error: %s.\n"),
380 	    scf_strerror(scf_error()));
381 }
382 
383 /*
384  * Clear a field of a structure.
385  */
386 static int
387 clear_int(void *a, void *b)
388 {
389 	/* LINTED */
390 	*(int *)((char *)a + (size_t)b) = 0;
391 
392 	return (UU_WALK_NEXT);
393 }
394 
395 static int
396 scferror2errno(scf_error_t err)
397 {
398 	switch (err) {
399 	case SCF_ERROR_BACKEND_ACCESS:
400 		return (EACCES);
401 
402 	case SCF_ERROR_BACKEND_READONLY:
403 		return (EROFS);
404 
405 	case SCF_ERROR_CONNECTION_BROKEN:
406 		return (ECONNABORTED);
407 
408 	case SCF_ERROR_CONSTRAINT_VIOLATED:
409 	case SCF_ERROR_INVALID_ARGUMENT:
410 		return (EINVAL);
411 
412 	case SCF_ERROR_DELETED:
413 		return (ECANCELED);
414 
415 	case SCF_ERROR_EXISTS:
416 		return (EEXIST);
417 
418 	case SCF_ERROR_NO_MEMORY:
419 		return (ENOMEM);
420 
421 	case SCF_ERROR_NO_RESOURCES:
422 		return (ENOSPC);
423 
424 	case SCF_ERROR_NOT_FOUND:
425 		return (ENOENT);
426 
427 	case SCF_ERROR_PERMISSION_DENIED:
428 		return (EPERM);
429 
430 	default:
431 #ifndef NDEBUG
432 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
433 		    __FILE__, __LINE__, err);
434 #else
435 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
436 #endif
437 		abort();
438 		/* NOTREACHED */
439 	}
440 }
441 
442 static int
443 entity_get_pg(void *ent, int issvc, const char *name,
444     scf_propertygroup_t *pg)
445 {
446 	if (issvc)
447 		return (scf_service_get_pg(ent, name, pg));
448 	else
449 		return (scf_instance_get_pg(ent, name, pg));
450 }
451 
452 static void
453 entity_destroy(void *ent, int issvc)
454 {
455 	if (issvc)
456 		scf_service_destroy(ent);
457 	else
458 		scf_instance_destroy(ent);
459 }
460 
461 static int
462 get_pg(const char *pg_name, scf_propertygroup_t *pg)
463 {
464 	int ret;
465 
466 	if (cur_level != NULL)
467 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
468 	else if (cur_inst != NULL)
469 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
470 	else
471 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
472 
473 	return (ret);
474 }
475 
476 /*
477  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
478  * snaplevel.  Otherwise find the instance snaplevel.
479  *
480  * Returns
481  *   0 - success
482  *   ECONNABORTED - repository connection broken
483  *   ECANCELED - instance containing snap was deleted
484  *   ENOENT - snap has no snaplevels
485  *	    - requested snaplevel not found
486  */
487 static int
488 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
489 {
490 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
491 		switch (scf_error()) {
492 		case SCF_ERROR_CONNECTION_BROKEN:
493 		case SCF_ERROR_DELETED:
494 		case SCF_ERROR_NOT_FOUND:
495 			return (scferror2errno(scf_error()));
496 
497 		case SCF_ERROR_HANDLE_MISMATCH:
498 		case SCF_ERROR_NOT_BOUND:
499 		case SCF_ERROR_NOT_SET:
500 		default:
501 			bad_error("scf_snapshot_get_base_snaplevel",
502 			    scf_error());
503 		}
504 	}
505 
506 	for (;;) {
507 		ssize_t ssz;
508 
509 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
510 		if (ssz >= 0) {
511 			if (!get_svc)
512 				return (0);
513 		} else {
514 			switch (scf_error()) {
515 			case SCF_ERROR_CONSTRAINT_VIOLATED:
516 				if (get_svc)
517 					return (0);
518 				break;
519 
520 			case SCF_ERROR_DELETED:
521 			case SCF_ERROR_CONNECTION_BROKEN:
522 				return (scferror2errno(scf_error()));
523 
524 			case SCF_ERROR_NOT_SET:
525 			case SCF_ERROR_NOT_BOUND:
526 			default:
527 				bad_error("scf_snaplevel_get_instance_name",
528 				    scf_error());
529 			}
530 		}
531 
532 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
533 			switch (scf_error()) {
534 			case SCF_ERROR_NOT_FOUND:
535 			case SCF_ERROR_CONNECTION_BROKEN:
536 			case SCF_ERROR_DELETED:
537 				return (scferror2errno(scf_error()));
538 
539 			case SCF_ERROR_HANDLE_MISMATCH:
540 			case SCF_ERROR_NOT_BOUND:
541 			case SCF_ERROR_NOT_SET:
542 			case SCF_ERROR_INVALID_ARGUMENT:
543 			default:
544 				bad_error("scf_snaplevel_get_next_snaplevel",
545 				    scf_error());
546 			}
547 		}
548 	}
549 }
550 
551 /*
552  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
553  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
554  * the property group named name in it.  If it doesn't have a running
555  * snapshot, set pg to the instance's current property group named name.
556  *
557  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
558  * its instances.  If one has a running snapshot with a service snaplevel, set
559  * pg to the property group named name in it.  If no such snaplevel could be
560  * found, set pg to the service's current property group named name.
561  *
562  * iter, inst, snap, and snpl are required scratch objects.
563  *
564  * Returns
565  *   0 - success
566  *   ECONNABORTED - repository connection broken
567  *   ECANCELED - ent was deleted
568  *   ENOENT - no such property group
569  *   EINVAL - name is an invalid property group name
570  *   EBADF - found running snapshot is missing a snaplevel
571  */
572 static int
573 entity_get_running_pg(void *ent, int issvc, const char *name,
574     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
575     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
576 {
577 	int r;
578 
579 	if (issvc) {
580 		/* Search for an instance with a running snapshot. */
581 		if (scf_iter_service_instances(iter, ent) != 0) {
582 			switch (scf_error()) {
583 			case SCF_ERROR_DELETED:
584 			case SCF_ERROR_CONNECTION_BROKEN:
585 				return (scferror2errno(scf_error()));
586 
587 			case SCF_ERROR_NOT_SET:
588 			case SCF_ERROR_NOT_BOUND:
589 			case SCF_ERROR_HANDLE_MISMATCH:
590 			default:
591 				bad_error("scf_iter_service_instances",
592 				    scf_error());
593 			}
594 		}
595 
596 		for (;;) {
597 			r = scf_iter_next_instance(iter, inst);
598 			if (r == 0) {
599 				if (scf_service_get_pg(ent, name, pg) == 0)
600 					return (0);
601 
602 				switch (scf_error()) {
603 				case SCF_ERROR_DELETED:
604 				case SCF_ERROR_NOT_FOUND:
605 				case SCF_ERROR_INVALID_ARGUMENT:
606 				case SCF_ERROR_CONNECTION_BROKEN:
607 					return (scferror2errno(scf_error()));
608 
609 				case SCF_ERROR_NOT_BOUND:
610 				case SCF_ERROR_HANDLE_MISMATCH:
611 				case SCF_ERROR_NOT_SET:
612 				default:
613 					bad_error("scf_service_get_pg",
614 					    scf_error());
615 				}
616 			}
617 			if (r != 1) {
618 				switch (scf_error()) {
619 				case SCF_ERROR_DELETED:
620 				case SCF_ERROR_CONNECTION_BROKEN:
621 					return (scferror2errno(scf_error()));
622 
623 				case SCF_ERROR_INVALID_ARGUMENT:
624 				case SCF_ERROR_NOT_SET:
625 				case SCF_ERROR_NOT_BOUND:
626 				case SCF_ERROR_HANDLE_MISMATCH:
627 				default:
628 					bad_error("scf_iter_next_instance",
629 					    scf_error());
630 				}
631 			}
632 
633 			if (scf_instance_get_snapshot(inst, snap_running,
634 			    snap) == 0)
635 				break;
636 
637 			switch (scf_error()) {
638 			case SCF_ERROR_NOT_FOUND:
639 			case SCF_ERROR_DELETED:
640 				continue;
641 
642 			case SCF_ERROR_CONNECTION_BROKEN:
643 				return (ECONNABORTED);
644 
645 			case SCF_ERROR_HANDLE_MISMATCH:
646 			case SCF_ERROR_INVALID_ARGUMENT:
647 			case SCF_ERROR_NOT_SET:
648 			case SCF_ERROR_NOT_BOUND:
649 			default:
650 				bad_error("scf_instance_get_snapshot",
651 				    scf_error());
652 			}
653 		}
654 	} else {
655 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
656 			switch (scf_error()) {
657 			case SCF_ERROR_NOT_FOUND:
658 				break;
659 
660 			case SCF_ERROR_DELETED:
661 			case SCF_ERROR_CONNECTION_BROKEN:
662 				return (scferror2errno(scf_error()));
663 
664 			case SCF_ERROR_NOT_BOUND:
665 			case SCF_ERROR_HANDLE_MISMATCH:
666 			case SCF_ERROR_INVALID_ARGUMENT:
667 			case SCF_ERROR_NOT_SET:
668 			default:
669 				bad_error("scf_instance_get_snapshot",
670 				    scf_error());
671 			}
672 
673 			if (scf_instance_get_pg(ent, name, pg) == 0)
674 				return (0);
675 
676 			switch (scf_error()) {
677 			case SCF_ERROR_DELETED:
678 			case SCF_ERROR_NOT_FOUND:
679 			case SCF_ERROR_INVALID_ARGUMENT:
680 			case SCF_ERROR_CONNECTION_BROKEN:
681 				return (scferror2errno(scf_error()));
682 
683 			case SCF_ERROR_NOT_BOUND:
684 			case SCF_ERROR_HANDLE_MISMATCH:
685 			case SCF_ERROR_NOT_SET:
686 			default:
687 				bad_error("scf_instance_get_pg", scf_error());
688 			}
689 		}
690 	}
691 
692 	r = get_snaplevel(snap, issvc, snpl);
693 	switch (r) {
694 	case 0:
695 		break;
696 
697 	case ECONNABORTED:
698 	case ECANCELED:
699 		return (r);
700 
701 	case ENOENT:
702 		return (EBADF);
703 
704 	default:
705 		bad_error("get_snaplevel", r);
706 	}
707 
708 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
709 		return (0);
710 
711 	switch (scf_error()) {
712 	case SCF_ERROR_DELETED:
713 	case SCF_ERROR_INVALID_ARGUMENT:
714 	case SCF_ERROR_CONNECTION_BROKEN:
715 	case SCF_ERROR_NOT_FOUND:
716 		return (scferror2errno(scf_error()));
717 
718 	case SCF_ERROR_NOT_BOUND:
719 	case SCF_ERROR_HANDLE_MISMATCH:
720 	case SCF_ERROR_NOT_SET:
721 	default:
722 		bad_error("scf_snaplevel_get_pg", scf_error());
723 		/* NOTREACHED */
724 	}
725 }
726 
727 /*
728  * To be registered with atexit().
729  */
730 static void
731 remove_tempfile(void)
732 {
733 	int ret;
734 
735 	if (tempfile != NULL) {
736 		if (fclose(tempfile) == EOF)
737 			(void) warn(gettext("Could not close temporary file"));
738 		tempfile = NULL;
739 	}
740 
741 	if (tempfilename[0] != '\0') {
742 		do {
743 			ret = remove(tempfilename);
744 		} while (ret == -1 && errno == EINTR);
745 		if (ret == -1)
746 			warn(gettext("Could not remove temporary file"));
747 		tempfilename[0] = '\0';
748 	}
749 }
750 
751 /*
752  * Launch private svc.configd(1M) for manipulating alternate repositories.
753  */
754 static void
755 start_private_repository(engine_state_t *est)
756 {
757 	int fd, stat;
758 	struct door_info info;
759 	pid_t pid;
760 
761 	/*
762 	 * 1.  Create a temporary file for the door.
763 	 */
764 	if (est->sc_repo_doorname != NULL)
765 		free((void *)est->sc_repo_doorname);
766 
767 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
768 	if (est->sc_repo_doorname == NULL)
769 		uu_die(gettext("Could not acquire temporary filename"));
770 
771 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
772 	if (fd < 0)
773 		uu_die(gettext("Could not create temporary file for "
774 		    "repository server"));
775 
776 	(void) close(fd);
777 
778 	/*
779 	 * 2.  Launch a configd with that door, using the specified
780 	 * repository.
781 	 */
782 	if ((est->sc_repo_pid = fork()) == 0) {
783 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
784 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
785 		    NULL);
786 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
787 	} else if (est->sc_repo_pid == -1)
788 		uu_die(gettext("Attempt to fork failed"));
789 
790 	do {
791 		pid = waitpid(est->sc_repo_pid, &stat, 0);
792 	} while (pid == -1 && errno == EINTR);
793 
794 	if (pid == -1)
795 		uu_die(gettext("Could not waitpid() for repository server"));
796 
797 	if (!WIFEXITED(stat)) {
798 		uu_die(gettext("Repository server failed (status %d).\n"),
799 		    stat);
800 	} else if (WEXITSTATUS(stat) != 0) {
801 		uu_die(gettext("Repository server failed (exit %d).\n"),
802 		    WEXITSTATUS(stat));
803 	}
804 
805 	/*
806 	 * See if it was successful by checking if the door is a door.
807 	 */
808 
809 	fd = open(est->sc_repo_doorname, O_RDWR);
810 	if (fd < 0)
811 		uu_die(gettext("Could not open door \"%s\""),
812 		    est->sc_repo_doorname);
813 
814 	if (door_info(fd, &info) < 0)
815 		uu_die(gettext("Unexpected door_info() error"));
816 
817 	if (close(fd) == -1)
818 		warn(gettext("Could not close repository door"),
819 		    strerror(errno));
820 
821 	est->sc_repo_pid = info.di_target;
822 }
823 
824 void
825 lscf_cleanup(void)
826 {
827 	/*
828 	 * In the case where we've launched a private svc.configd(1M)
829 	 * instance, we must terminate our child and remove the temporary
830 	 * rendezvous point.
831 	 */
832 	if (est->sc_repo_pid > 0) {
833 		(void) kill(est->sc_repo_pid, SIGTERM);
834 		(void) waitpid(est->sc_repo_pid, NULL, 0);
835 		(void) unlink(est->sc_repo_doorname);
836 
837 		est->sc_repo_pid = 0;
838 	}
839 }
840 
841 void
842 unselect_cursnap(void)
843 {
844 	void *cookie;
845 
846 	cur_level = NULL;
847 
848 	cookie = NULL;
849 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
850 		scf_snaplevel_destroy(cur_elt->sl);
851 		free(cur_elt);
852 	}
853 
854 	scf_snapshot_destroy(cur_snap);
855 	cur_snap = NULL;
856 }
857 
858 void
859 lscf_prep_hndl(void)
860 {
861 	if (g_hndl != NULL)
862 		return;
863 
864 	g_hndl = scf_handle_create(SCF_VERSION);
865 	if (g_hndl == NULL)
866 		scfdie();
867 
868 	if (est->sc_repo_filename != NULL)
869 		start_private_repository(est);
870 
871 	if (est->sc_repo_doorname != NULL) {
872 		scf_value_t *repo_value;
873 		int ret;
874 
875 		repo_value = scf_value_create(g_hndl);
876 		if (repo_value == NULL)
877 			scfdie();
878 
879 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
880 		assert(ret == SCF_SUCCESS);
881 
882 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
883 		    SCF_SUCCESS)
884 			scfdie();
885 
886 		scf_value_destroy(repo_value);
887 	}
888 
889 	if (scf_handle_bind(g_hndl) != 0)
890 		uu_die(gettext("Could not connect to repository server: %s.\n"),
891 		    scf_strerror(scf_error()));
892 
893 	cur_scope = scf_scope_create(g_hndl);
894 	if (cur_scope == NULL)
895 		scfdie();
896 
897 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
898 		scfdie();
899 }
900 
901 static void
902 repository_teardown(void)
903 {
904 	if (g_hndl != NULL) {
905 		if (cur_snap != NULL)
906 			unselect_cursnap();
907 		scf_instance_destroy(cur_inst);
908 		scf_service_destroy(cur_svc);
909 		scf_scope_destroy(cur_scope);
910 		scf_handle_destroy(g_hndl);
911 		cur_inst = NULL;
912 		cur_svc = NULL;
913 		cur_scope = NULL;
914 		g_hndl = NULL;
915 		lscf_cleanup();
916 	}
917 }
918 
919 void
920 lscf_set_repository(const char *repfile, int force)
921 {
922 	repository_teardown();
923 
924 	if (est->sc_repo_filename != NULL) {
925 		free((void *)est->sc_repo_filename);
926 		est->sc_repo_filename = NULL;
927 	}
928 
929 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
930 		/*
931 		 * Repository file does not exist
932 		 * or has no read permission.
933 		 */
934 		warn(gettext("Cannot access \"%s\": %s\n"),
935 		    repfile, strerror(errno));
936 	} else {
937 		est->sc_repo_filename = safe_strdup(repfile);
938 	}
939 
940 	lscf_prep_hndl();
941 }
942 
943 void
944 lscf_init()
945 {
946 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
947 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
948 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
949 	    0 ||
950 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
951 		scfdie();
952 
953 	max_scf_len = max_scf_fmri_len;
954 	if (max_scf_name_len > max_scf_len)
955 		max_scf_len = max_scf_name_len;
956 	if (max_scf_pg_type_len > max_scf_len)
957 		max_scf_len = max_scf_pg_type_len;
958 	/*
959 	 * When a value of type opaque is represented as a string, the
960 	 * string contains 2 characters for every byte of data.  That is
961 	 * because the string contains the hex representation of the opaque
962 	 * value.
963 	 */
964 	if (2 * max_scf_value_len > max_scf_len)
965 		max_scf_len = 2 * max_scf_value_len;
966 
967 	if (atexit(remove_tempfile) != 0)
968 		uu_die(gettext("Could not register atexit() function"));
969 
970 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
971 	emsg_permission_denied = gettext("Permission denied.\n");
972 	emsg_create_xml = gettext("Could not create XML node.\n");
973 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
974 	emsg_invalid_for_snapshot =
975 	    gettext("Invalid operation on a snapshot.\n");
976 	emsg_read_only = gettext("Backend read-only.\n");
977 	emsg_deleted = gettext("Current selection has been deleted.\n");
978 	emsg_invalid_pg_name =
979 	    gettext("Invalid property group name \"%s\".\n");
980 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
981 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
982 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
983 	    "with invalid name \"%s\".\n");
984 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
985 	    "group with invalid name \"%s\" or type \"%s\".\n");
986 	emsg_pg_added = gettext("%s changed unexpectedly "
987 	    "(property group \"%s\" added).\n");
988 	emsg_pg_changed = gettext("%s changed unexpectedly "
989 	    "(property group \"%s\" changed).\n");
990 	emsg_pg_deleted = gettext("%s changed unexpectedly "
991 	    "(property group \"%s\" or an ancestor was deleted).\n");
992 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
993 	    "in %s (permission denied).\n");
994 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
995 	    "in %s (permission denied).\n");
996 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
997 	    "in %s (permission denied).\n");
998 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
999 	    "(permission denied).\n");
1000 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
1001 	    "new dependent \"%s\" because it already exists).  Warning: The "
1002 	    "current dependent's target (%s) does not exist.\n");
1003 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
1004 	    "dependent \"%s\" because it already exists).  Warning: The "
1005 	    "current dependent's target (%s) does not have a dependency named "
1006 	    "\"%s\" as expected.\n");
1007 
1008 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
1009 	    offsetof(string_list_t, node), NULL, 0);
1010 	snaplevel_pool = uu_list_pool_create("snaplevels",
1011 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
1012 	    NULL, 0);
1013 }
1014 
1015 
1016 static const char *
1017 prop_to_typestr(const scf_property_t *prop)
1018 {
1019 	scf_type_t ty;
1020 
1021 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
1022 		scfdie();
1023 
1024 	return (scf_type_to_string(ty));
1025 }
1026 
1027 static scf_type_t
1028 string_to_type(const char *type)
1029 {
1030 	size_t len = strlen(type);
1031 	char *buf;
1032 
1033 	if (len == 0 || type[len - 1] != ':')
1034 		return (SCF_TYPE_INVALID);
1035 
1036 	buf = (char *)alloca(len + 1);
1037 	(void) strlcpy(buf, type, len + 1);
1038 	buf[len - 1] = 0;
1039 
1040 	return (scf_string_to_type(buf));
1041 }
1042 
1043 static scf_value_t *
1044 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
1045 {
1046 	scf_value_t *v;
1047 	char *dup, *nstr;
1048 	size_t len;
1049 
1050 	v = scf_value_create(g_hndl);
1051 	if (v == NULL)
1052 		scfdie();
1053 
1054 	len = strlen(str);
1055 	if (require_quotes &&
1056 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
1057 		semerr(gettext("Multiple string values or string values "
1058 		    "with spaces must be quoted with '\"'.\n"));
1059 		scf_value_destroy(v);
1060 		return (NULL);
1061 	}
1062 
1063 	nstr = dup = safe_strdup(str);
1064 	if (dup[0] == '\"') {
1065 		/*
1066 		 * Strip out the first and the last quote.
1067 		 */
1068 		dup[len - 1] = '\0';
1069 		nstr = dup + 1;
1070 	}
1071 
1072 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
1073 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
1074 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
1075 		    scf_type_to_string(ty), nstr);
1076 		scf_value_destroy(v);
1077 		v = NULL;
1078 	}
1079 	free(dup);
1080 	return (v);
1081 }
1082 
1083 /*
1084  * Print str to strm, quoting double-quotes and backslashes with backslashes.
1085  * Optionally append a comment prefix ('#') to newlines ('\n').
1086  */
1087 static int
1088 quote_and_print(const char *str, FILE *strm, int commentnl)
1089 {
1090 	const char *cp;
1091 
1092 	for (cp = str; *cp != '\0'; ++cp) {
1093 		if (*cp == '"' || *cp == '\\')
1094 			(void) putc('\\', strm);
1095 
1096 		(void) putc(*cp, strm);
1097 
1098 		if (commentnl && *cp == '\n') {
1099 			(void) putc('#', strm);
1100 		}
1101 	}
1102 
1103 	return (ferror(strm));
1104 }
1105 
1106 /*
1107  * These wrappers around lowlevel functions provide consistent error checking
1108  * and warnings.
1109  */
1110 static int
1111 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1112 {
1113 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1114 		return (0);
1115 
1116 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1117 		scfdie();
1118 
1119 	if (g_verbose) {
1120 		ssize_t len;
1121 		char *fmri;
1122 
1123 		len = scf_pg_to_fmri(pg, NULL, 0);
1124 		if (len < 0)
1125 			scfdie();
1126 
1127 		fmri = safe_malloc(len + 1);
1128 
1129 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1130 			scfdie();
1131 
1132 		warn(gettext("Expected property %s of property group %s is "
1133 		    "missing.\n"), propname, fmri);
1134 
1135 		free(fmri);
1136 	}
1137 
1138 	return (-1);
1139 }
1140 
1141 static int
1142 prop_check_type(scf_property_t *prop, scf_type_t ty)
1143 {
1144 	scf_type_t pty;
1145 
1146 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1147 		scfdie();
1148 
1149 	if (ty == pty)
1150 		return (0);
1151 
1152 	if (g_verbose) {
1153 		ssize_t len;
1154 		char *fmri;
1155 		const char *tystr;
1156 
1157 		len = scf_property_to_fmri(prop, NULL, 0);
1158 		if (len < 0)
1159 			scfdie();
1160 
1161 		fmri = safe_malloc(len + 1);
1162 
1163 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1164 			scfdie();
1165 
1166 		tystr = scf_type_to_string(ty);
1167 		if (tystr == NULL)
1168 			tystr = "?";
1169 
1170 		warn(gettext("Property %s is not of expected type %s.\n"),
1171 		    fmri, tystr);
1172 
1173 		free(fmri);
1174 	}
1175 
1176 	return (-1);
1177 }
1178 
1179 static int
1180 prop_get_val(scf_property_t *prop, scf_value_t *val)
1181 {
1182 	scf_error_t err;
1183 
1184 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1185 		return (0);
1186 
1187 	err = scf_error();
1188 
1189 	if (err != SCF_ERROR_NOT_FOUND &&
1190 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1191 	    err != SCF_ERROR_PERMISSION_DENIED)
1192 		scfdie();
1193 
1194 	if (g_verbose) {
1195 		ssize_t len;
1196 		char *fmri, *emsg;
1197 
1198 		len = scf_property_to_fmri(prop, NULL, 0);
1199 		if (len < 0)
1200 			scfdie();
1201 
1202 		fmri = safe_malloc(len + 1);
1203 
1204 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1205 			scfdie();
1206 
1207 		if (err == SCF_ERROR_NOT_FOUND)
1208 			emsg = gettext("Property %s has no values; expected "
1209 			    "one.\n");
1210 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1211 			emsg = gettext("Property %s has multiple values; "
1212 			    "expected one.\n");
1213 		else
1214 			emsg = gettext("No permission to read property %s.\n");
1215 
1216 		warn(emsg, fmri);
1217 
1218 		free(fmri);
1219 	}
1220 
1221 	return (-1);
1222 }
1223 
1224 
1225 static boolean_t
1226 snaplevel_is_instance(const scf_snaplevel_t *level)
1227 {
1228 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1229 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1230 			scfdie();
1231 		return (0);
1232 	} else {
1233 		return (1);
1234 	}
1235 }
1236 
1237 /*
1238  * Decode FMRI into a service or instance, and put the result in *ep.  If
1239  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1240  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1241  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1242  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1243  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1244  * whether *ep is a service.
1245  */
1246 static scf_error_t
1247 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1248 {
1249 	char *fmri_copy;
1250 	const char *sstr, *istr, *pgstr;
1251 	scf_service_t *svc;
1252 	scf_instance_t *inst;
1253 
1254 	fmri_copy = strdup(fmri);
1255 	if (fmri_copy == NULL)
1256 		return (SCF_ERROR_NO_MEMORY);
1257 
1258 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1259 	    SCF_SUCCESS) {
1260 		free(fmri_copy);
1261 		return (SCF_ERROR_INVALID_ARGUMENT);
1262 	}
1263 
1264 	free(fmri_copy);
1265 
1266 	if (sstr == NULL || pgstr != NULL)
1267 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1268 
1269 	if (istr == NULL) {
1270 		svc = scf_service_create(h);
1271 		if (svc == NULL)
1272 			return (SCF_ERROR_NO_MEMORY);
1273 
1274 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1275 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1276 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1277 				scfdie();
1278 
1279 			return (SCF_ERROR_NOT_FOUND);
1280 		}
1281 
1282 		*ep = svc;
1283 		*isservice = 1;
1284 	} else {
1285 		inst = scf_instance_create(h);
1286 		if (inst == NULL)
1287 			return (SCF_ERROR_NO_MEMORY);
1288 
1289 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1290 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1291 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1292 				scfdie();
1293 
1294 			return (SCF_ERROR_NOT_FOUND);
1295 		}
1296 
1297 		*ep = inst;
1298 		*isservice = 0;
1299 	}
1300 
1301 	return (SCF_ERROR_NONE);
1302 }
1303 
1304 /*
1305  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1306  * *ep, and set or clear *isservicep if it is a service or an instance.
1307  * Returns
1308  *   SCF_ERROR_NONE - success
1309  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1310  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1311  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1312  *   SCF_ERROR_NOT_FOUND - no such scope
1313  *   SCF_ERROR_PERMISSION_DENIED
1314  *   SCF_ERROR_BACKEND_READONLY
1315  *   SCF_ERROR_BACKEND_ACCESS
1316  */
1317 static scf_error_t
1318 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1319 {
1320 	char *fmri_copy;
1321 	const char *scstr, *sstr, *istr, *pgstr;
1322 	scf_scope_t *scope = NULL;
1323 	scf_service_t *svc = NULL;
1324 	scf_instance_t *inst = NULL;
1325 	scf_error_t scfe;
1326 
1327 	fmri_copy = safe_strdup(fmri);
1328 
1329 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1330 	    0) {
1331 		free(fmri_copy);
1332 		return (SCF_ERROR_INVALID_ARGUMENT);
1333 	}
1334 
1335 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1336 		free(fmri_copy);
1337 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1338 	}
1339 
1340 	*ep = NULL;
1341 
1342 	if ((scope = scf_scope_create(h)) == NULL ||
1343 	    (svc = scf_service_create(h)) == NULL ||
1344 	    (inst = scf_instance_create(h)) == NULL) {
1345 		scfe = SCF_ERROR_NO_MEMORY;
1346 		goto out;
1347 	}
1348 
1349 get_scope:
1350 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1351 		switch (scf_error()) {
1352 		case SCF_ERROR_CONNECTION_BROKEN:
1353 			scfdie();
1354 			/* NOTREACHED */
1355 
1356 		case SCF_ERROR_NOT_FOUND:
1357 			scfe = SCF_ERROR_NOT_FOUND;
1358 			goto out;
1359 
1360 		case SCF_ERROR_HANDLE_MISMATCH:
1361 		case SCF_ERROR_NOT_BOUND:
1362 		case SCF_ERROR_INVALID_ARGUMENT:
1363 		default:
1364 			bad_error("scf_handle_get_scope", scf_error());
1365 		}
1366 	}
1367 
1368 get_svc:
1369 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1370 		switch (scf_error()) {
1371 		case SCF_ERROR_CONNECTION_BROKEN:
1372 			scfdie();
1373 			/* NOTREACHED */
1374 
1375 		case SCF_ERROR_DELETED:
1376 			goto get_scope;
1377 
1378 		case SCF_ERROR_NOT_FOUND:
1379 			break;
1380 
1381 		case SCF_ERROR_HANDLE_MISMATCH:
1382 		case SCF_ERROR_INVALID_ARGUMENT:
1383 		case SCF_ERROR_NOT_BOUND:
1384 		case SCF_ERROR_NOT_SET:
1385 		default:
1386 			bad_error("scf_scope_get_service", scf_error());
1387 		}
1388 
1389 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1390 			switch (scf_error()) {
1391 			case SCF_ERROR_CONNECTION_BROKEN:
1392 				scfdie();
1393 				/* NOTREACHED */
1394 
1395 			case SCF_ERROR_DELETED:
1396 				goto get_scope;
1397 
1398 			case SCF_ERROR_PERMISSION_DENIED:
1399 			case SCF_ERROR_BACKEND_READONLY:
1400 			case SCF_ERROR_BACKEND_ACCESS:
1401 				scfe = scf_error();
1402 				goto out;
1403 
1404 			case SCF_ERROR_HANDLE_MISMATCH:
1405 			case SCF_ERROR_INVALID_ARGUMENT:
1406 			case SCF_ERROR_NOT_BOUND:
1407 			case SCF_ERROR_NOT_SET:
1408 			default:
1409 				bad_error("scf_scope_get_service", scf_error());
1410 			}
1411 		}
1412 	}
1413 
1414 	if (istr == NULL) {
1415 		scfe = SCF_ERROR_NONE;
1416 		*ep = svc;
1417 		*isservicep = 1;
1418 		goto out;
1419 	}
1420 
1421 get_inst:
1422 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1423 		switch (scf_error()) {
1424 		case SCF_ERROR_CONNECTION_BROKEN:
1425 			scfdie();
1426 			/* NOTREACHED */
1427 
1428 		case SCF_ERROR_DELETED:
1429 			goto get_svc;
1430 
1431 		case SCF_ERROR_NOT_FOUND:
1432 			break;
1433 
1434 		case SCF_ERROR_HANDLE_MISMATCH:
1435 		case SCF_ERROR_INVALID_ARGUMENT:
1436 		case SCF_ERROR_NOT_BOUND:
1437 		case SCF_ERROR_NOT_SET:
1438 		default:
1439 			bad_error("scf_service_get_instance", scf_error());
1440 		}
1441 
1442 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1443 			switch (scf_error()) {
1444 			case SCF_ERROR_CONNECTION_BROKEN:
1445 				scfdie();
1446 				/* NOTREACHED */
1447 
1448 			case SCF_ERROR_DELETED:
1449 				goto get_svc;
1450 
1451 			case SCF_ERROR_PERMISSION_DENIED:
1452 			case SCF_ERROR_BACKEND_READONLY:
1453 			case SCF_ERROR_BACKEND_ACCESS:
1454 				scfe = scf_error();
1455 				goto out;
1456 
1457 			case SCF_ERROR_HANDLE_MISMATCH:
1458 			case SCF_ERROR_INVALID_ARGUMENT:
1459 			case SCF_ERROR_NOT_BOUND:
1460 			case SCF_ERROR_NOT_SET:
1461 			default:
1462 				bad_error("scf_service_add_instance",
1463 				    scf_error());
1464 			}
1465 		}
1466 	}
1467 
1468 	scfe = SCF_ERROR_NONE;
1469 	*ep = inst;
1470 	*isservicep = 0;
1471 
1472 out:
1473 	if (*ep != inst)
1474 		scf_instance_destroy(inst);
1475 	if (*ep != svc)
1476 		scf_service_destroy(svc);
1477 	scf_scope_destroy(scope);
1478 	free(fmri_copy);
1479 	return (scfe);
1480 }
1481 
1482 /*
1483  * Create or update a snapshot of inst.  snap is a required scratch object.
1484  *
1485  * Returns
1486  *   0 - success
1487  *   ECONNABORTED - repository connection broken
1488  *   EPERM - permission denied
1489  *   ENOSPC - configd is out of resources
1490  *   ECANCELED - inst was deleted
1491  *   -1 - unknown libscf error (message printed)
1492  */
1493 static int
1494 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1495 {
1496 again:
1497 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1498 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1499 			switch (scf_error()) {
1500 			case SCF_ERROR_CONNECTION_BROKEN:
1501 			case SCF_ERROR_PERMISSION_DENIED:
1502 			case SCF_ERROR_NO_RESOURCES:
1503 				return (scferror2errno(scf_error()));
1504 
1505 			case SCF_ERROR_NOT_SET:
1506 			case SCF_ERROR_INVALID_ARGUMENT:
1507 			default:
1508 				bad_error("_scf_snapshot_take_attach",
1509 				    scf_error());
1510 			}
1511 		}
1512 	} else {
1513 		switch (scf_error()) {
1514 		case SCF_ERROR_NOT_FOUND:
1515 			break;
1516 
1517 		case SCF_ERROR_DELETED:
1518 		case SCF_ERROR_CONNECTION_BROKEN:
1519 			return (scferror2errno(scf_error()));
1520 
1521 		case SCF_ERROR_HANDLE_MISMATCH:
1522 		case SCF_ERROR_NOT_BOUND:
1523 		case SCF_ERROR_INVALID_ARGUMENT:
1524 		case SCF_ERROR_NOT_SET:
1525 		default:
1526 			bad_error("scf_instance_get_snapshot", scf_error());
1527 		}
1528 
1529 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1530 			switch (scf_error()) {
1531 			case SCF_ERROR_EXISTS:
1532 				goto again;
1533 
1534 			case SCF_ERROR_CONNECTION_BROKEN:
1535 			case SCF_ERROR_NO_RESOURCES:
1536 			case SCF_ERROR_PERMISSION_DENIED:
1537 				return (scferror2errno(scf_error()));
1538 
1539 			default:
1540 				scfwarn();
1541 				return (-1);
1542 
1543 			case SCF_ERROR_NOT_SET:
1544 			case SCF_ERROR_INTERNAL:
1545 			case SCF_ERROR_INVALID_ARGUMENT:
1546 			case SCF_ERROR_HANDLE_MISMATCH:
1547 				bad_error("_scf_snapshot_take_new",
1548 				    scf_error());
1549 			}
1550 		}
1551 	}
1552 
1553 	return (0);
1554 }
1555 
1556 static int
1557 refresh_running_snapshot(void *entity)
1558 {
1559 	scf_snapshot_t *snap;
1560 	int r;
1561 
1562 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1563 		scfdie();
1564 	r = take_snap(entity, snap_running, snap);
1565 	scf_snapshot_destroy(snap);
1566 
1567 	return (r);
1568 }
1569 
1570 /*
1571  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1572  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1573  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1574  * for scratch space.  Returns
1575  *   0 - success
1576  *   ECONNABORTED - repository connection broken
1577  *   ECANCELED - entity was deleted
1578  *   EACCES - backend denied access
1579  *   EPERM - permission denied
1580  *   ENOSPC - repository server out of resources
1581  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1582  */
1583 static int
1584 refresh_entity(int isservice, void *entity, const char *fmri,
1585     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1586 {
1587 	scf_error_t scfe;
1588 	int r;
1589 
1590 	if (!isservice) {
1591 		/*
1592 		 * Let restarter handles refreshing and making new running
1593 		 * snapshot only if operating on a live repository and not
1594 		 * running in early import.
1595 		 */
1596 		if (est->sc_repo_filename == NULL &&
1597 		    est->sc_repo_doorname == NULL &&
1598 		    est->sc_in_emi == 0) {
1599 			if (_smf_refresh_instance_i(entity) == 0) {
1600 				if (g_verbose)
1601 					warn(gettext("Refreshed %s.\n"), fmri);
1602 				return (0);
1603 			}
1604 
1605 			switch (scf_error()) {
1606 			case SCF_ERROR_BACKEND_ACCESS:
1607 				return (EACCES);
1608 
1609 			case SCF_ERROR_PERMISSION_DENIED:
1610 				return (EPERM);
1611 
1612 			default:
1613 				return (-1);
1614 			}
1615 		} else {
1616 			r = refresh_running_snapshot(entity);
1617 			switch (r) {
1618 			case 0:
1619 				break;
1620 
1621 			case ECONNABORTED:
1622 			case ECANCELED:
1623 			case EPERM:
1624 			case ENOSPC:
1625 				break;
1626 
1627 			default:
1628 				bad_error("refresh_running_snapshot",
1629 				    scf_error());
1630 			}
1631 
1632 			return (r);
1633 		}
1634 	}
1635 
1636 	if (scf_iter_service_instances(iter, entity) != 0) {
1637 		switch (scf_error()) {
1638 		case SCF_ERROR_CONNECTION_BROKEN:
1639 			return (ECONNABORTED);
1640 
1641 		case SCF_ERROR_DELETED:
1642 			return (ECANCELED);
1643 
1644 		case SCF_ERROR_HANDLE_MISMATCH:
1645 		case SCF_ERROR_NOT_BOUND:
1646 		case SCF_ERROR_NOT_SET:
1647 		default:
1648 			bad_error("scf_iter_service_instances", scf_error());
1649 		}
1650 	}
1651 
1652 	for (;;) {
1653 		r = scf_iter_next_instance(iter, inst);
1654 		if (r == 0)
1655 			break;
1656 		if (r != 1) {
1657 			switch (scf_error()) {
1658 			case SCF_ERROR_CONNECTION_BROKEN:
1659 				return (ECONNABORTED);
1660 
1661 			case SCF_ERROR_DELETED:
1662 				return (ECANCELED);
1663 
1664 			case SCF_ERROR_HANDLE_MISMATCH:
1665 			case SCF_ERROR_NOT_BOUND:
1666 			case SCF_ERROR_NOT_SET:
1667 			case SCF_ERROR_INVALID_ARGUMENT:
1668 			default:
1669 				bad_error("scf_iter_next_instance",
1670 				    scf_error());
1671 			}
1672 		}
1673 
1674 		/*
1675 		 * Similarly, just take a new running snapshot if operating on
1676 		 * a non-live repository or running during early import.
1677 		 */
1678 		if (est->sc_repo_filename != NULL ||
1679 		    est->sc_repo_doorname != NULL ||
1680 		    est->sc_in_emi == 1) {
1681 			r = refresh_running_snapshot(inst);
1682 			switch (r) {
1683 			case 0:
1684 				continue;
1685 
1686 			case ECONNABORTED:
1687 			case ECANCELED:
1688 			case EPERM:
1689 			case ENOSPC:
1690 				break;
1691 			default:
1692 				bad_error("refresh_running_snapshot",
1693 				    scf_error());
1694 			}
1695 
1696 			return (r);
1697 
1698 		}
1699 
1700 		if (_smf_refresh_instance_i(inst) == 0) {
1701 			if (g_verbose) {
1702 				if (scf_instance_get_name(inst, name_buf,
1703 				    max_scf_name_len + 1) < 0)
1704 					(void) strcpy(name_buf, "?");
1705 
1706 				warn(gettext("Refreshed %s:%s.\n"),
1707 				    fmri, name_buf);
1708 			}
1709 		} else {
1710 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1711 			    g_verbose) {
1712 				scfe = scf_error();
1713 
1714 				if (scf_instance_to_fmri(inst, name_buf,
1715 				    max_scf_name_len + 1) < 0)
1716 					(void) strcpy(name_buf, "?");
1717 
1718 				warn(gettext(
1719 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1720 				    name_buf, scf_strerror(scfe));
1721 			}
1722 		}
1723 	}
1724 
1725 	return (0);
1726 }
1727 
1728 static void
1729 private_refresh(void)
1730 {
1731 	scf_instance_t *pinst = NULL;
1732 	scf_iter_t *piter = NULL;
1733 	ssize_t fmrilen;
1734 	size_t bufsz;
1735 	char *fmribuf;
1736 	void *ent;
1737 	int issvc;
1738 	int r;
1739 
1740 	if (est->sc_repo_filename == NULL && est->sc_repo_doorname == NULL)
1741 		return;
1742 
1743 	assert(cur_svc != NULL);
1744 
1745 	bufsz = max_scf_fmri_len + 1;
1746 	fmribuf = safe_malloc(bufsz);
1747 	if (cur_inst) {
1748 		issvc = 0;
1749 		ent = cur_inst;
1750 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1751 	} else {
1752 		issvc = 1;
1753 		ent = cur_svc;
1754 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1755 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1756 			scfdie();
1757 
1758 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1759 			scfdie();
1760 	}
1761 	if (fmrilen < 0) {
1762 		free(fmribuf);
1763 		if (scf_error() != SCF_ERROR_DELETED)
1764 			scfdie();
1765 
1766 		warn(emsg_deleted);
1767 		return;
1768 	}
1769 	assert(fmrilen < bufsz);
1770 
1771 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1772 	switch (r) {
1773 	case 0:
1774 		break;
1775 
1776 	case ECONNABORTED:
1777 		warn(gettext("Could not refresh %s "
1778 		    "(repository connection broken).\n"), fmribuf);
1779 		break;
1780 
1781 	case ECANCELED:
1782 		warn(emsg_deleted);
1783 		break;
1784 
1785 	case EPERM:
1786 		warn(gettext("Could not refresh %s "
1787 		    "(permission denied).\n"), fmribuf);
1788 		break;
1789 
1790 	case ENOSPC:
1791 		warn(gettext("Could not refresh %s "
1792 		    "(repository server out of resources).\n"),
1793 		    fmribuf);
1794 		break;
1795 
1796 	case EACCES:
1797 	default:
1798 		bad_error("refresh_entity", scf_error());
1799 	}
1800 
1801 	if (issvc) {
1802 		scf_instance_destroy(pinst);
1803 		scf_iter_destroy(piter);
1804 	}
1805 
1806 	free(fmribuf);
1807 }
1808 
1809 
1810 static int
1811 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1812 {
1813 	cbp->sc_err = scferror2errno(err);
1814 	return (UU_WALK_ERROR);
1815 }
1816 
1817 static int
1818 stash_scferror(scf_callback_t *cbp)
1819 {
1820 	return (stash_scferror_err(cbp, scf_error()));
1821 }
1822 
1823 static int select_inst(const char *);
1824 static int select_svc(const char *);
1825 
1826 /*
1827  * Take a property that does not have a type and check to see if a type
1828  * exists or can be gleened from the current data.  Set the type.
1829  *
1830  * Check the current level (instance) and then check the higher level
1831  * (service).  This could be the case for adding a new property to
1832  * the instance that's going to "override" a service level property.
1833  *
1834  * For a property :
1835  * 1. Take the type from an existing property
1836  * 2. Take the type from a template entry
1837  *
1838  * If the type can not be found, then leave the type as is, and let the import
1839  * report the problem of the missing type.
1840  */
1841 static int
1842 find_current_prop_type(void *p, void *g)
1843 {
1844 	property_t *prop = p;
1845 	scf_callback_t *lcb = g;
1846 	pgroup_t *pg = NULL;
1847 
1848 	const char *fmri = NULL;
1849 	char *lfmri = NULL;
1850 	char *cur_selection = NULL;
1851 
1852 	scf_propertygroup_t *sc_pg = NULL;
1853 	scf_property_t *sc_prop = NULL;
1854 	scf_pg_tmpl_t *t_pg = NULL;
1855 	scf_prop_tmpl_t *t_prop = NULL;
1856 	scf_type_t prop_type;
1857 
1858 	value_t *vp;
1859 	int issvc = lcb->sc_service;
1860 	int r = UU_WALK_ERROR;
1861 
1862 	if (prop->sc_value_type != SCF_TYPE_INVALID)
1863 		return (UU_WALK_NEXT);
1864 
1865 	t_prop = scf_tmpl_prop_create(g_hndl);
1866 	sc_prop = scf_property_create(g_hndl);
1867 	if (sc_prop == NULL || t_prop == NULL) {
1868 		warn(gettext("Unable to create the property to attempt and "
1869 		    "find a missing type.\n"));
1870 
1871 		scf_property_destroy(sc_prop);
1872 		scf_tmpl_prop_destroy(t_prop);
1873 
1874 		return (UU_WALK_ERROR);
1875 	}
1876 
1877 	if (lcb->sc_flags == 1) {
1878 		pg = lcb->sc_parent;
1879 		issvc = (pg->sc_parent->sc_etype == SVCCFG_SERVICE_OBJECT);
1880 		fmri = pg->sc_parent->sc_fmri;
1881 retry_pg:
1882 		if (cur_svc && cur_selection == NULL) {
1883 			cur_selection = safe_malloc(max_scf_fmri_len + 1);
1884 			lscf_get_selection_str(cur_selection,
1885 			    max_scf_fmri_len + 1);
1886 
1887 			if (strcmp(cur_selection, fmri) != 0) {
1888 				lscf_select(fmri);
1889 			} else {
1890 				free(cur_selection);
1891 				cur_selection = NULL;
1892 			}
1893 		} else {
1894 			lscf_select(fmri);
1895 		}
1896 
1897 		if (sc_pg == NULL && (sc_pg = scf_pg_create(g_hndl)) == NULL) {
1898 			warn(gettext("Unable to create property group to "
1899 			    "find a missing property type.\n"));
1900 
1901 			goto out;
1902 		}
1903 
1904 		if (get_pg(pg->sc_pgroup_name, sc_pg) != SCF_SUCCESS) {
1905 			/*
1906 			 * If this is the sc_pg from the parent
1907 			 * let the caller clean up the sc_pg,
1908 			 * and just throw it away in this case.
1909 			 */
1910 			if (sc_pg != lcb->sc_parent)
1911 				scf_pg_destroy(sc_pg);
1912 
1913 			sc_pg = NULL;
1914 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
1915 				warn(gettext("Unable to create template "
1916 				    "property group to find a property "
1917 				    "type.\n"));
1918 
1919 				goto out;
1920 			}
1921 
1922 			if (scf_tmpl_get_by_pg_name(fmri, NULL,
1923 			    pg->sc_pgroup_name, NULL, t_pg,
1924 			    SCF_PG_TMPL_FLAG_EXACT) != SCF_SUCCESS) {
1925 				/*
1926 				 * if instance get service and jump back
1927 				 */
1928 				scf_tmpl_pg_destroy(t_pg);
1929 				t_pg = NULL;
1930 				if (issvc == 0) {
1931 					entity_t *e = pg->sc_parent->sc_parent;
1932 
1933 					fmri = e->sc_fmri;
1934 					issvc = 1;
1935 					goto retry_pg;
1936 				} else {
1937 					goto out;
1938 				}
1939 			}
1940 		}
1941 	} else {
1942 		sc_pg = lcb->sc_parent;
1943 	}
1944 
1945 	/*
1946 	 * Attempt to get the type from an existing property.  If the property
1947 	 * cannot be found then attempt to get the type from a template entry
1948 	 * for the property.
1949 	 *
1950 	 * Finally, if at the instance level look at the service level.
1951 	 */
1952 	if (sc_pg != NULL &&
1953 	    pg_get_prop(sc_pg, prop->sc_property_name,
1954 	    sc_prop) == SCF_SUCCESS &&
1955 	    scf_property_type(sc_prop, &prop_type) == SCF_SUCCESS) {
1956 		prop->sc_value_type = prop_type;
1957 
1958 		/*
1959 		 * Found a type, update the value types and validate
1960 		 * the actual value against this type.
1961 		 */
1962 		for (vp = uu_list_first(prop->sc_property_values);
1963 		    vp != NULL;
1964 		    vp = uu_list_next(prop->sc_property_values, vp)) {
1965 			vp->sc_type = prop->sc_value_type;
1966 			lxml_store_value(vp, 0, NULL);
1967 		}
1968 
1969 		r = UU_WALK_NEXT;
1970 		goto out;
1971 	}
1972 
1973 	/*
1974 	 * If we get here with t_pg set to NULL then we had to have
1975 	 * gotten an sc_pg but that sc_pg did not have the property
1976 	 * we are looking for.   So if the t_pg is not null look up
1977 	 * the template entry for the property.
1978 	 *
1979 	 * If the t_pg is null then need to attempt to get a matching
1980 	 * template entry for the sc_pg, and see if there is a property
1981 	 * entry for that template entry.
1982 	 */
1983 do_tmpl :
1984 	if (t_pg != NULL &&
1985 	    scf_tmpl_get_by_prop(t_pg, prop->sc_property_name,
1986 	    t_prop, 0) == SCF_SUCCESS) {
1987 		if (scf_tmpl_prop_type(t_prop, &prop_type) == SCF_SUCCESS) {
1988 			prop->sc_value_type = prop_type;
1989 
1990 			/*
1991 			 * Found a type, update the value types and validate
1992 			 * the actual value against this type.
1993 			 */
1994 			for (vp = uu_list_first(prop->sc_property_values);
1995 			    vp != NULL;
1996 			    vp = uu_list_next(prop->sc_property_values, vp)) {
1997 				vp->sc_type = prop->sc_value_type;
1998 				lxml_store_value(vp, 0, NULL);
1999 			}
2000 
2001 			r = UU_WALK_NEXT;
2002 			goto out;
2003 		}
2004 	} else {
2005 		if (t_pg == NULL && sc_pg) {
2006 			if ((t_pg = scf_tmpl_pg_create(g_hndl)) == NULL) {
2007 				warn(gettext("Unable to create template "
2008 				    "property group to find a property "
2009 				    "type.\n"));
2010 
2011 				goto out;
2012 			}
2013 
2014 			if (scf_tmpl_get_by_pg(sc_pg, t_pg, 0) != SCF_SUCCESS) {
2015 				scf_tmpl_pg_destroy(t_pg);
2016 				t_pg = NULL;
2017 			} else {
2018 				goto do_tmpl;
2019 			}
2020 		}
2021 	}
2022 
2023 	if (issvc == 0) {
2024 		scf_instance_t *i;
2025 		scf_service_t *s;
2026 
2027 		issvc = 1;
2028 		if (lcb->sc_flags == 1) {
2029 			entity_t *e = pg->sc_parent->sc_parent;
2030 
2031 			fmri = e->sc_fmri;
2032 			goto retry_pg;
2033 		}
2034 
2035 		/*
2036 		 * because lcb->sc_flags was not set then this means
2037 		 * the pg was not used and can be used here.
2038 		 */
2039 		if ((pg = internal_pgroup_new()) == NULL) {
2040 			warn(gettext("Could not create internal property group "
2041 			    "to find a missing type."));
2042 
2043 			goto out;
2044 		}
2045 
2046 		pg->sc_pgroup_name = safe_malloc(max_scf_name_len + 1);
2047 		if (scf_pg_get_name(sc_pg, (char *)pg->sc_pgroup_name,
2048 		    max_scf_name_len + 1) < 0)
2049 				goto out;
2050 
2051 		i = scf_instance_create(g_hndl);
2052 		s = scf_service_create(g_hndl);
2053 		if (i == NULL || s == NULL ||
2054 		    scf_pg_get_parent_instance(sc_pg, i) != SCF_SUCCESS) {
2055 			warn(gettext("Could not get a service for the instance "
2056 			    "to find a missing type."));
2057 
2058 			goto out;
2059 		}
2060 
2061 		/*
2062 		 * Check to see truly at the instance level.
2063 		 */
2064 		lfmri = safe_malloc(max_scf_fmri_len + 1);
2065 		if (scf_instance_get_parent(i, s) == SCF_SUCCESS &&
2066 		    scf_service_to_fmri(s, lfmri, max_scf_fmri_len + 1) < 0)
2067 			goto out;
2068 		else
2069 			fmri = (const char *)lfmri;
2070 
2071 		goto retry_pg;
2072 	}
2073 
2074 out :
2075 	if (sc_pg != lcb->sc_parent) {
2076 		scf_pg_destroy(sc_pg);
2077 	}
2078 
2079 	/*
2080 	 * If this is true then the pg was allocated
2081 	 * here, and the name was set so need to free
2082 	 * the name and the pg.
2083 	 */
2084 	if (pg != NULL && pg != lcb->sc_parent) {
2085 		free((char *)pg->sc_pgroup_name);
2086 		internal_pgroup_free(pg);
2087 	}
2088 
2089 	if (cur_selection) {
2090 		lscf_select(cur_selection);
2091 		free(cur_selection);
2092 	}
2093 
2094 	scf_tmpl_pg_destroy(t_pg);
2095 	scf_tmpl_prop_destroy(t_prop);
2096 	scf_property_destroy(sc_prop);
2097 
2098 	if (r != UU_WALK_NEXT)
2099 		warn(gettext("Could not find property type for \"%s\" "
2100 		    "from \"%s\"\n"), prop->sc_property_name,
2101 		    fmri != NULL ? fmri : lcb->sc_source_fmri);
2102 
2103 	free(lfmri);
2104 
2105 	return (r);
2106 }
2107 
2108 /*
2109  * Take a property group that does not have a type and check to see if a type
2110  * exists or can be gleened from the current data.  Set the type.
2111  *
2112  * Check the current level (instance) and then check the higher level
2113  * (service).  This could be the case for adding a new property to
2114  * the instance that's going to "override" a service level property.
2115  *
2116  * For a property group
2117  * 1. Take the type from an existing property group
2118  * 2. Take the type from a template entry
2119  *
2120  * If the type can not be found, then leave the type as is, and let the import
2121  * report the problem of the missing type.
2122  */
2123 static int
2124 find_current_pg_type(void *p, void *sori)
2125 {
2126 	entity_t *si = sori;
2127 	pgroup_t *pg = p;
2128 
2129 	const char *ofmri, *fmri;
2130 	char *cur_selection = NULL;
2131 	char *pg_type = NULL;
2132 
2133 	scf_propertygroup_t *sc_pg = NULL;
2134 	scf_pg_tmpl_t *t_pg = NULL;
2135 
2136 	int issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2137 	int r = UU_WALK_ERROR;
2138 
2139 	ofmri = fmri = si->sc_fmri;
2140 	if (pg->sc_pgroup_type != NULL) {
2141 		r = UU_WALK_NEXT;
2142 
2143 		goto out;
2144 	}
2145 
2146 	sc_pg = scf_pg_create(g_hndl);
2147 	if (sc_pg == NULL) {
2148 		warn(gettext("Unable to create property group to attempt "
2149 		    "and find a missing type.\n"));
2150 
2151 		return (UU_WALK_ERROR);
2152 	}
2153 
2154 	/*
2155 	 * Using get_pg() requires that the cur_svc/cur_inst be
2156 	 * via lscf_select.  Need to preserve the current selection
2157 	 * if going to use lscf_select() to set up the cur_svc/cur_inst
2158 	 */
2159 	if (cur_svc) {
2160 		cur_selection = safe_malloc(max_scf_fmri_len + 1);
2161 		lscf_get_selection_str(cur_selection, max_scf_fmri_len + 1);
2162 	}
2163 
2164 	/*
2165 	 * If the property group exists get the type, and set
2166 	 * the pgroup_t type of that type.
2167 	 *
2168 	 * If not the check for a template pg_pattern entry
2169 	 * and take the type from that.
2170 	 */
2171 retry_svc:
2172 	lscf_select(fmri);
2173 
2174 	if (get_pg(pg->sc_pgroup_name, sc_pg) == SCF_SUCCESS) {
2175 		pg_type = safe_malloc(max_scf_pg_type_len + 1);
2176 		if (pg_type != NULL && scf_pg_get_type(sc_pg, pg_type,
2177 		    max_scf_pg_type_len + 1) != -1) {
2178 			pg->sc_pgroup_type = pg_type;
2179 
2180 			r = UU_WALK_NEXT;
2181 			goto out;
2182 		} else {
2183 			free(pg_type);
2184 		}
2185 	} else {
2186 		if ((t_pg == NULL) &&
2187 		    (t_pg = scf_tmpl_pg_create(g_hndl)) == NULL)
2188 			goto out;
2189 
2190 		if (scf_tmpl_get_by_pg_name(fmri, NULL, pg->sc_pgroup_name,
2191 		    NULL, t_pg, SCF_PG_TMPL_FLAG_EXACT) == SCF_SUCCESS &&
2192 		    scf_tmpl_pg_type(t_pg, &pg_type) != -1) {
2193 			pg->sc_pgroup_type = pg_type;
2194 
2195 			r = UU_WALK_NEXT;
2196 			goto out;
2197 		}
2198 	}
2199 
2200 	/*
2201 	 * If type is not found at the instance level then attempt to
2202 	 * find the type at the service level.
2203 	 */
2204 	if (!issvc) {
2205 		si = si->sc_parent;
2206 		fmri = si->sc_fmri;
2207 		issvc = (si->sc_etype == SVCCFG_SERVICE_OBJECT);
2208 		goto retry_svc;
2209 	}
2210 
2211 out :
2212 	if (cur_selection) {
2213 		lscf_select(cur_selection);
2214 		free(cur_selection);
2215 	}
2216 
2217 	/*
2218 	 * Now walk the properties of the property group to make sure that
2219 	 * all properties have the correct type and values are valid for
2220 	 * those types.
2221 	 */
2222 	if (r == UU_WALK_NEXT) {
2223 		scf_callback_t cb;
2224 
2225 		cb.sc_service = issvc;
2226 		cb.sc_source_fmri = ofmri;
2227 		if (sc_pg != NULL) {
2228 			cb.sc_parent = sc_pg;
2229 			cb.sc_flags = 0;
2230 		} else {
2231 			cb.sc_parent = pg;
2232 			cb.sc_flags = 1;
2233 		}
2234 
2235 		if (uu_list_walk(pg->sc_pgroup_props, find_current_prop_type,
2236 		    &cb, UU_DEFAULT) != 0) {
2237 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2238 				bad_error("uu_list_walk", uu_error());
2239 
2240 			r = UU_WALK_ERROR;
2241 		}
2242 	} else {
2243 		warn(gettext("Could not find property group type for "
2244 		    "\"%s\" from \"%s\"\n"), pg->sc_pgroup_name, fmri);
2245 	}
2246 
2247 	scf_tmpl_pg_destroy(t_pg);
2248 	scf_pg_destroy(sc_pg);
2249 
2250 	return (r);
2251 }
2252 
2253 /*
2254  * Import.  These functions import a bundle into the repository.
2255  */
2256 
2257 /*
2258  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
2259  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
2260  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2261  * lcbdata->sc_err to
2262  *   ENOMEM - out of memory
2263  *   ECONNABORTED - repository connection broken
2264  *   ECANCELED - sc_trans's property group was deleted
2265  *   EINVAL - p's name is invalid (error printed)
2266  *	    - p has an invalid value (error printed)
2267  */
2268 static int
2269 lscf_property_import(void *v, void *pvt)
2270 {
2271 	property_t *p = v;
2272 	scf_callback_t *lcbdata = pvt;
2273 	value_t *vp;
2274 	scf_transaction_t *trans = lcbdata->sc_trans;
2275 	scf_transaction_entry_t *entr;
2276 	scf_value_t *val;
2277 	scf_type_t tp;
2278 
2279 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
2280 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
2281 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
2282 		lcbdata->sc_enable = p;
2283 		return (UU_WALK_NEXT);
2284 	}
2285 
2286 	entr = scf_entry_create(lcbdata->sc_handle);
2287 	if (entr == NULL) {
2288 		switch (scf_error()) {
2289 		case SCF_ERROR_NO_MEMORY:
2290 			return (stash_scferror(lcbdata));
2291 
2292 		case SCF_ERROR_INVALID_ARGUMENT:
2293 		default:
2294 			bad_error("scf_entry_create", scf_error());
2295 		}
2296 	}
2297 
2298 	tp = p->sc_value_type;
2299 
2300 	if (scf_transaction_property_new(trans, entr,
2301 	    p->sc_property_name, tp) != 0) {
2302 		switch (scf_error()) {
2303 		case SCF_ERROR_INVALID_ARGUMENT:
2304 			semerr(emsg_invalid_prop_name, p->sc_property_name);
2305 			scf_entry_destroy(entr);
2306 			return (stash_scferror(lcbdata));
2307 
2308 		case SCF_ERROR_EXISTS:
2309 			break;
2310 
2311 		case SCF_ERROR_DELETED:
2312 		case SCF_ERROR_CONNECTION_BROKEN:
2313 			scf_entry_destroy(entr);
2314 			return (stash_scferror(lcbdata));
2315 
2316 		case SCF_ERROR_NOT_BOUND:
2317 		case SCF_ERROR_HANDLE_MISMATCH:
2318 		case SCF_ERROR_NOT_SET:
2319 		default:
2320 			bad_error("scf_transaction_property_new", scf_error());
2321 		}
2322 
2323 		if (scf_transaction_property_change_type(trans, entr,
2324 		    p->sc_property_name, tp) != 0) {
2325 			switch (scf_error()) {
2326 			case SCF_ERROR_DELETED:
2327 			case SCF_ERROR_CONNECTION_BROKEN:
2328 				scf_entry_destroy(entr);
2329 				return (stash_scferror(lcbdata));
2330 
2331 			case SCF_ERROR_INVALID_ARGUMENT:
2332 				semerr(emsg_invalid_prop_name,
2333 				    p->sc_property_name);
2334 				scf_entry_destroy(entr);
2335 				return (stash_scferror(lcbdata));
2336 
2337 			case SCF_ERROR_NOT_FOUND:
2338 			case SCF_ERROR_NOT_SET:
2339 			case SCF_ERROR_HANDLE_MISMATCH:
2340 			case SCF_ERROR_NOT_BOUND:
2341 			default:
2342 				bad_error(
2343 				    "scf_transaction_property_change_type",
2344 				    scf_error());
2345 			}
2346 		}
2347 	}
2348 
2349 	for (vp = uu_list_first(p->sc_property_values);
2350 	    vp != NULL;
2351 	    vp = uu_list_next(p->sc_property_values, vp)) {
2352 		val = scf_value_create(g_hndl);
2353 		if (val == NULL) {
2354 			switch (scf_error()) {
2355 			case SCF_ERROR_NO_MEMORY:
2356 				return (stash_scferror(lcbdata));
2357 
2358 			case SCF_ERROR_INVALID_ARGUMENT:
2359 			default:
2360 				bad_error("scf_value_create", scf_error());
2361 			}
2362 		}
2363 
2364 		switch (tp) {
2365 		case SCF_TYPE_BOOLEAN:
2366 			scf_value_set_boolean(val, vp->sc_u.sc_count);
2367 			break;
2368 		case SCF_TYPE_COUNT:
2369 			scf_value_set_count(val, vp->sc_u.sc_count);
2370 			break;
2371 		case SCF_TYPE_INTEGER:
2372 			scf_value_set_integer(val, vp->sc_u.sc_integer);
2373 			break;
2374 		default:
2375 			assert(vp->sc_u.sc_string != NULL);
2376 			if (scf_value_set_from_string(val, tp,
2377 			    vp->sc_u.sc_string) != 0) {
2378 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
2379 					bad_error("scf_value_set_from_string",
2380 					    scf_error());
2381 
2382 				warn(gettext("Value \"%s\" is not a valid "
2383 				    "%s.\n"), vp->sc_u.sc_string,
2384 				    scf_type_to_string(tp));
2385 				scf_value_destroy(val);
2386 				return (stash_scferror(lcbdata));
2387 			}
2388 			break;
2389 		}
2390 
2391 		if (scf_entry_add_value(entr, val) != 0)
2392 			bad_error("scf_entry_add_value", scf_error());
2393 	}
2394 
2395 	return (UU_WALK_NEXT);
2396 }
2397 
2398 /*
2399  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
2400  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
2401  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
2402  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
2403  * lcbdata->sc_err to
2404  *   ECONNABORTED - repository connection broken
2405  *   ENOMEM - out of memory
2406  *   ENOSPC - svc.configd is out of resources
2407  *   ECANCELED - sc_parent was deleted
2408  *   EPERM - could not create property group (permission denied) (error printed)
2409  *	   - could not modify property group (permission denied) (error printed)
2410  *	   - could not delete property group (permission denied) (error	printed)
2411  *   EROFS - could not create property group (repository is read-only)
2412  *	   - could not delete property group (repository is read-only)
2413  *   EACCES - could not create property group (backend access denied)
2414  *	    - could not delete property group (backend access denied)
2415  *   EEXIST - could not create property group (already exists)
2416  *   EINVAL - invalid property group name (error printed)
2417  *	    - invalid property name (error printed)
2418  *	    - invalid value (error printed)
2419  *   EBUSY - new property group deleted (error printed)
2420  *	   - new property group changed (error printed)
2421  *	   - property group added (error printed)
2422  *	   - property group deleted (error printed)
2423  */
2424 static int
2425 entity_pgroup_import(void *v, void *pvt)
2426 {
2427 	pgroup_t *p = v;
2428 	scf_callback_t cbdata;
2429 	scf_callback_t *lcbdata = pvt;
2430 	void *ent = lcbdata->sc_parent;
2431 	int issvc = lcbdata->sc_service;
2432 	int r;
2433 
2434 	const char * const pg_changed = gettext("%s changed unexpectedly "
2435 	    "(new property group \"%s\" changed).\n");
2436 
2437 	/* Never import deleted property groups. */
2438 	if (p->sc_pgroup_delete) {
2439 		if ((lcbdata->sc_flags & SCI_OP_APPLY) == SCI_OP_APPLY &&
2440 		    entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) == 0) {
2441 			goto delete_pg;
2442 		}
2443 		return (UU_WALK_NEXT);
2444 	}
2445 
2446 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
2447 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
2448 		lcbdata->sc_general = p;
2449 		return (UU_WALK_NEXT);
2450 	}
2451 
2452 add_pg:
2453 	if (issvc)
2454 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
2455 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2456 	else
2457 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
2458 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
2459 	if (r != 0) {
2460 		switch (scf_error()) {
2461 		case SCF_ERROR_DELETED:
2462 		case SCF_ERROR_CONNECTION_BROKEN:
2463 		case SCF_ERROR_BACKEND_READONLY:
2464 		case SCF_ERROR_BACKEND_ACCESS:
2465 		case SCF_ERROR_NO_RESOURCES:
2466 			return (stash_scferror(lcbdata));
2467 
2468 		case SCF_ERROR_EXISTS:
2469 			if (lcbdata->sc_flags & SCI_FORCE)
2470 				break;
2471 			return (stash_scferror(lcbdata));
2472 
2473 		case SCF_ERROR_INVALID_ARGUMENT:
2474 			warn(emsg_fmri_invalid_pg_name_type,
2475 			    lcbdata->sc_source_fmri,
2476 			    p->sc_pgroup_name, p->sc_pgroup_type);
2477 			return (stash_scferror(lcbdata));
2478 
2479 		case SCF_ERROR_PERMISSION_DENIED:
2480 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
2481 			    lcbdata->sc_target_fmri);
2482 			return (stash_scferror(lcbdata));
2483 
2484 		case SCF_ERROR_NOT_BOUND:
2485 		case SCF_ERROR_HANDLE_MISMATCH:
2486 		case SCF_ERROR_NOT_SET:
2487 		default:
2488 			bad_error("scf_service_add_pg", scf_error());
2489 		}
2490 
2491 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
2492 			switch (scf_error()) {
2493 			case SCF_ERROR_CONNECTION_BROKEN:
2494 			case SCF_ERROR_DELETED:
2495 				return (stash_scferror(lcbdata));
2496 
2497 			case SCF_ERROR_INVALID_ARGUMENT:
2498 				warn(emsg_fmri_invalid_pg_name,
2499 				    lcbdata->sc_source_fmri,
2500 				    p->sc_pgroup_name);
2501 				return (stash_scferror(lcbdata));
2502 
2503 			case SCF_ERROR_NOT_FOUND:
2504 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2505 				    p->sc_pgroup_name);
2506 				lcbdata->sc_err = EBUSY;
2507 				return (UU_WALK_ERROR);
2508 
2509 			case SCF_ERROR_NOT_BOUND:
2510 			case SCF_ERROR_HANDLE_MISMATCH:
2511 			case SCF_ERROR_NOT_SET:
2512 			default:
2513 				bad_error("entity_get_pg", scf_error());
2514 			}
2515 		}
2516 
2517 		if (lcbdata->sc_flags & SCI_KEEP)
2518 			goto props;
2519 
2520 delete_pg:
2521 		if (scf_pg_delete(imp_pg) != 0) {
2522 			switch (scf_error()) {
2523 			case SCF_ERROR_DELETED:
2524 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2525 				    p->sc_pgroup_name);
2526 				lcbdata->sc_err = EBUSY;
2527 				return (UU_WALK_ERROR);
2528 
2529 			case SCF_ERROR_PERMISSION_DENIED:
2530 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
2531 				    lcbdata->sc_target_fmri);
2532 				return (stash_scferror(lcbdata));
2533 
2534 			case SCF_ERROR_BACKEND_READONLY:
2535 			case SCF_ERROR_BACKEND_ACCESS:
2536 			case SCF_ERROR_CONNECTION_BROKEN:
2537 				return (stash_scferror(lcbdata));
2538 
2539 			case SCF_ERROR_NOT_SET:
2540 			default:
2541 				bad_error("scf_pg_delete", scf_error());
2542 			}
2543 		}
2544 
2545 		if (p->sc_pgroup_delete)
2546 			return (UU_WALK_NEXT);
2547 
2548 		goto add_pg;
2549 	}
2550 
2551 props:
2552 
2553 	/*
2554 	 * Add properties to property group, if any.
2555 	 */
2556 	cbdata.sc_handle = lcbdata->sc_handle;
2557 	cbdata.sc_parent = imp_pg;
2558 	cbdata.sc_flags = lcbdata->sc_flags;
2559 	cbdata.sc_trans = imp_tx;
2560 	cbdata.sc_enable = NULL;
2561 
2562 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2563 		switch (scf_error()) {
2564 		case SCF_ERROR_BACKEND_ACCESS:
2565 		case SCF_ERROR_BACKEND_READONLY:
2566 		case SCF_ERROR_CONNECTION_BROKEN:
2567 			return (stash_scferror(lcbdata));
2568 
2569 		case SCF_ERROR_DELETED:
2570 			warn(pg_changed, lcbdata->sc_target_fmri,
2571 			    p->sc_pgroup_name);
2572 			lcbdata->sc_err = EBUSY;
2573 			return (UU_WALK_ERROR);
2574 
2575 		case SCF_ERROR_PERMISSION_DENIED:
2576 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2577 			    lcbdata->sc_target_fmri);
2578 			return (stash_scferror(lcbdata));
2579 
2580 		case SCF_ERROR_NOT_BOUND:
2581 		case SCF_ERROR_NOT_SET:
2582 		case SCF_ERROR_IN_USE:
2583 		case SCF_ERROR_HANDLE_MISMATCH:
2584 		default:
2585 			bad_error("scf_transaction_start", scf_error());
2586 		}
2587 	}
2588 
2589 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2590 	    UU_DEFAULT) != 0) {
2591 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2592 			bad_error("uu_list_walk", uu_error());
2593 		scf_transaction_reset(imp_tx);
2594 
2595 		lcbdata->sc_err = cbdata.sc_err;
2596 		if (cbdata.sc_err == ECANCELED) {
2597 			warn(pg_changed, lcbdata->sc_target_fmri,
2598 			    p->sc_pgroup_name);
2599 			lcbdata->sc_err = EBUSY;
2600 		}
2601 		return (UU_WALK_ERROR);
2602 	}
2603 
2604 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2605 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2606 
2607 		/*
2608 		 * take the snapshot running snapshot then
2609 		 * import the stored general/enable property
2610 		 */
2611 		r = take_snap(ent, snap_running, imp_rsnap);
2612 		switch (r) {
2613 		case 0:
2614 			break;
2615 
2616 		case ECONNABORTED:
2617 			warn(gettext("Could not take %s snapshot on import "
2618 			    "(repository connection broken).\n"),
2619 			    snap_running);
2620 			lcbdata->sc_err = r;
2621 			return (UU_WALK_ERROR);
2622 		case ECANCELED:
2623 			warn(emsg_deleted);
2624 			lcbdata->sc_err = r;
2625 			return (UU_WALK_ERROR);
2626 
2627 		case EPERM:
2628 			warn(gettext("Could not take %s snapshot "
2629 			    "(permission denied).\n"), snap_running);
2630 			lcbdata->sc_err = r;
2631 			return (UU_WALK_ERROR);
2632 
2633 		case ENOSPC:
2634 			warn(gettext("Could not take %s snapshot"
2635 			    "(repository server out of resources).\n"),
2636 			    snap_running);
2637 			lcbdata->sc_err = r;
2638 			return (UU_WALK_ERROR);
2639 
2640 		default:
2641 			bad_error("take_snap", r);
2642 		}
2643 
2644 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2645 		if (r != UU_WALK_NEXT) {
2646 			if (r != UU_WALK_ERROR)
2647 				bad_error("lscf_property_import", r);
2648 			return (EINVAL);
2649 		}
2650 	}
2651 
2652 	r = scf_transaction_commit(imp_tx);
2653 	switch (r) {
2654 	case 1:
2655 		r = UU_WALK_NEXT;
2656 		break;
2657 
2658 	case 0:
2659 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2660 		lcbdata->sc_err = EBUSY;
2661 		r = UU_WALK_ERROR;
2662 		break;
2663 
2664 	case -1:
2665 		switch (scf_error()) {
2666 		case SCF_ERROR_BACKEND_READONLY:
2667 		case SCF_ERROR_BACKEND_ACCESS:
2668 		case SCF_ERROR_CONNECTION_BROKEN:
2669 		case SCF_ERROR_NO_RESOURCES:
2670 			r = stash_scferror(lcbdata);
2671 			break;
2672 
2673 		case SCF_ERROR_DELETED:
2674 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2675 			    p->sc_pgroup_name);
2676 			lcbdata->sc_err = EBUSY;
2677 			r = UU_WALK_ERROR;
2678 			break;
2679 
2680 		case SCF_ERROR_PERMISSION_DENIED:
2681 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2682 			    lcbdata->sc_target_fmri);
2683 			r = stash_scferror(lcbdata);
2684 			break;
2685 
2686 		case SCF_ERROR_NOT_SET:
2687 		case SCF_ERROR_INVALID_ARGUMENT:
2688 		case SCF_ERROR_NOT_BOUND:
2689 		default:
2690 			bad_error("scf_transaction_commit", scf_error());
2691 		}
2692 		break;
2693 
2694 	default:
2695 		bad_error("scf_transaction_commit", r);
2696 	}
2697 
2698 	scf_transaction_destroy_children(imp_tx);
2699 
2700 	return (r);
2701 }
2702 
2703 /*
2704  * Returns
2705  *   0 - success
2706  *   ECONNABORTED - repository connection broken
2707  *   ENOMEM - out of memory
2708  *   ENOSPC - svc.configd is out of resources
2709  *   ECANCELED - inst was deleted
2710  *   EPERM - could not create property group (permission denied) (error printed)
2711  *	   - could not modify property group (permission denied) (error printed)
2712  *   EROFS - could not create property group (repository is read-only)
2713  *   EACCES - could not create property group (backend access denied)
2714  *   EEXIST - could not create property group (already exists)
2715  *   EINVAL - invalid property group name (error printed)
2716  *	    - invalid property name (error printed)
2717  *	    - invalid value (error printed)
2718  *   EBUSY - new property group changed (error printed)
2719  */
2720 static int
2721 lscf_import_service_pgs(scf_service_t *svc, const char *target_fmri,
2722     const entity_t *isvc, int flags)
2723 {
2724 	scf_callback_t cbdata;
2725 
2726 	cbdata.sc_handle = scf_service_handle(svc);
2727 	cbdata.sc_parent = svc;
2728 	cbdata.sc_service = 1;
2729 	cbdata.sc_general = 0;
2730 	cbdata.sc_enable = 0;
2731 	cbdata.sc_flags = flags;
2732 	cbdata.sc_source_fmri = isvc->sc_fmri;
2733 	cbdata.sc_target_fmri = target_fmri;
2734 
2735 	/*
2736 	 * If the op is set, then add the flag to the callback
2737 	 * flags for later use.
2738 	 */
2739 	if (isvc->sc_op != SVCCFG_OP_NONE) {
2740 		switch (isvc->sc_op) {
2741 		case SVCCFG_OP_IMPORT :
2742 			cbdata.sc_flags |= SCI_OP_IMPORT;
2743 			break;
2744 		case SVCCFG_OP_APPLY :
2745 			cbdata.sc_flags |= SCI_OP_APPLY;
2746 			break;
2747 		case SVCCFG_OP_RESTORE :
2748 			cbdata.sc_flags |= SCI_OP_RESTORE;
2749 			break;
2750 		default :
2751 			uu_die(gettext("lscf_import_service_pgs : "
2752 			    "Unknown op stored in the service entity\n"));
2753 
2754 		}
2755 	}
2756 
2757 	if (uu_list_walk(isvc->sc_pgroups, entity_pgroup_import, &cbdata,
2758 	    UU_DEFAULT) != 0) {
2759 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2760 			bad_error("uu_list_walk", uu_error());
2761 
2762 		return (cbdata.sc_err);
2763 	}
2764 
2765 	return (0);
2766 }
2767 
2768 /*
2769  * Returns
2770  *   0 - success
2771  *   ECONNABORTED - repository connection broken
2772  *   ENOMEM - out of memory
2773  *   ENOSPC - svc.configd is out of resources
2774  *   ECANCELED - inst was deleted
2775  *   EPERM - could not create property group (permission denied) (error printed)
2776  *	   - could not modify property group (permission denied) (error printed)
2777  *   EROFS - could not create property group (repository is read-only)
2778  *   EACCES - could not create property group (backend access denied)
2779  *   EEXIST - could not create property group (already exists)
2780  *   EINVAL - invalid property group name (error printed)
2781  *	    - invalid property name (error printed)
2782  *	    - invalid value (error printed)
2783  *   EBUSY - new property group changed (error printed)
2784  */
2785 static int
2786 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2787     const entity_t *iinst, int flags)
2788 {
2789 	scf_callback_t cbdata;
2790 
2791 	cbdata.sc_handle = scf_instance_handle(inst);
2792 	cbdata.sc_parent = inst;
2793 	cbdata.sc_service = 0;
2794 	cbdata.sc_general = NULL;
2795 	cbdata.sc_enable = NULL;
2796 	cbdata.sc_flags = flags;
2797 	cbdata.sc_source_fmri = iinst->sc_fmri;
2798 	cbdata.sc_target_fmri = target_fmri;
2799 
2800 	/*
2801 	 * If the op is set, then add the flag to the callback
2802 	 * flags for later use.
2803 	 */
2804 	if (iinst->sc_op != SVCCFG_OP_NONE) {
2805 		switch (iinst->sc_op) {
2806 		case SVCCFG_OP_IMPORT :
2807 			cbdata.sc_flags |= SCI_OP_IMPORT;
2808 			break;
2809 		case SVCCFG_OP_APPLY :
2810 			cbdata.sc_flags |= SCI_OP_APPLY;
2811 			break;
2812 		case SVCCFG_OP_RESTORE :
2813 			cbdata.sc_flags |= SCI_OP_RESTORE;
2814 			break;
2815 		default :
2816 			uu_die(gettext("lscf_import_instance_pgs : "
2817 			    "Unknown op stored in the instance entity\n"));
2818 		}
2819 	}
2820 
2821 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2822 	    UU_DEFAULT) != 0) {
2823 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2824 			bad_error("uu_list_walk", uu_error());
2825 
2826 		return (cbdata.sc_err);
2827 	}
2828 
2829 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2830 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2831 		/*
2832 		 * If importing with the SCI_NOENABLED flag then
2833 		 * skip the delay, but if not then add the delay
2834 		 * of the enable property.
2835 		 */
2836 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2837 			cbdata.sc_flags |= SCI_DELAYENABLE;
2838 		}
2839 
2840 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2841 		    != UU_WALK_NEXT)
2842 			return (cbdata.sc_err);
2843 	}
2844 
2845 	return (0);
2846 }
2847 
2848 /*
2849  * Report the reasons why we can't upgrade pg2 to pg1.
2850  */
2851 static void
2852 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2853     int new)
2854 {
2855 	property_t *p1, *p2;
2856 
2857 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2858 
2859 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2860 		return;
2861 
2862 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2863 	    p1 != NULL;
2864 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2865 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2866 		if (p2 != NULL) {
2867 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2868 			    new);
2869 			continue;
2870 		}
2871 
2872 		if (new)
2873 			warn(gettext("Conflict upgrading %s (new property "
2874 			    "group \"%s\" is missing property \"%s\").\n"),
2875 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2876 		else
2877 			warn(gettext("Conflict upgrading %s (property "
2878 			    "\"%s/%s\" is missing).\n"), fmri,
2879 			    pg1->sc_pgroup_name, p1->sc_property_name);
2880 	}
2881 
2882 	/*
2883 	 * Since pg1 should be from the manifest, any properties in pg2 which
2884 	 * aren't in pg1 shouldn't be reported as conflicts.
2885 	 */
2886 }
2887 
2888 /*
2889  * Add transaction entries to tx which will upgrade cur's pg according to old
2890  * & new.
2891  *
2892  * Returns
2893  *   0 - success
2894  *   EINVAL - new has a property with an invalid name or value (message emitted)
2895  *   ENOMEM - out of memory
2896  */
2897 static int
2898 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2899     pgroup_t *cur, int speak, const char *fmri)
2900 {
2901 	property_t *p, *new_p, *cur_p;
2902 	scf_transaction_entry_t *e;
2903 	int r;
2904 	int is_general;
2905 	int is_protected;
2906 
2907 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2908 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2909 		bad_error("uu_list_walk", uu_error());
2910 
2911 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2912 
2913 	for (p = uu_list_first(old->sc_pgroup_props);
2914 	    p != NULL;
2915 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2916 		/* p is a property in the old property group. */
2917 
2918 		/* Protect live properties. */
2919 		is_protected = 0;
2920 		if (is_general) {
2921 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2922 			    0 ||
2923 			    strcmp(p->sc_property_name,
2924 			    SCF_PROPERTY_RESTARTER) == 0)
2925 				is_protected = 1;
2926 		}
2927 
2928 		/* Look for the same property in the new properties. */
2929 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2930 		if (new_p != NULL) {
2931 			new_p->sc_seen = 1;
2932 
2933 			/*
2934 			 * If the new property is the same as the old, don't do
2935 			 * anything (leave any user customizations).
2936 			 */
2937 			if (prop_equal(p, new_p, NULL, NULL, 0))
2938 				continue;
2939 
2940 			if (new_p->sc_property_override)
2941 				goto upgrade;
2942 		}
2943 
2944 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2945 		if (cur_p == NULL) {
2946 			/*
2947 			 * p has been deleted from the repository.  If we were
2948 			 * going to delete it anyway, do nothing.  Otherwise
2949 			 * report a conflict.
2950 			 */
2951 			if (new_p == NULL)
2952 				continue;
2953 
2954 			if (is_protected)
2955 				continue;
2956 
2957 			warn(gettext("Conflict upgrading %s "
2958 			    "(property \"%s/%s\" is missing).\n"), fmri,
2959 			    old->sc_pgroup_name, p->sc_property_name);
2960 			continue;
2961 		}
2962 
2963 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2964 			/*
2965 			 * Conflict.  Don't warn if the property is already the
2966 			 * way we want it, though.
2967 			 */
2968 			if (is_protected)
2969 				continue;
2970 
2971 			if (new_p == NULL)
2972 				(void) prop_equal(p, cur_p, fmri,
2973 				    old->sc_pgroup_name, 0);
2974 			else
2975 				(void) prop_equal(cur_p, new_p, fmri,
2976 				    old->sc_pgroup_name, 0);
2977 			continue;
2978 		}
2979 
2980 		if (is_protected) {
2981 			if (speak)
2982 				warn(gettext("%s: Refusing to upgrade "
2983 				    "\"%s/%s\" (live property).\n"), fmri,
2984 				    old->sc_pgroup_name, p->sc_property_name);
2985 			continue;
2986 		}
2987 
2988 upgrade:
2989 		/* p hasn't been customized in the repository.  Upgrade it. */
2990 		if (new_p == NULL) {
2991 			/* p was deleted.  Delete from cur if unchanged. */
2992 			if (speak)
2993 				warn(gettext(
2994 				    "%s: Deleting property \"%s/%s\".\n"),
2995 				    fmri, old->sc_pgroup_name,
2996 				    p->sc_property_name);
2997 
2998 			e = scf_entry_create(g_hndl);
2999 			if (e == NULL)
3000 				return (ENOMEM);
3001 
3002 			if (scf_transaction_property_delete(tx, e,
3003 			    p->sc_property_name) != 0) {
3004 				switch (scf_error()) {
3005 				case SCF_ERROR_DELETED:
3006 					scf_entry_destroy(e);
3007 					return (ECANCELED);
3008 
3009 				case SCF_ERROR_CONNECTION_BROKEN:
3010 					scf_entry_destroy(e);
3011 					return (ECONNABORTED);
3012 
3013 				case SCF_ERROR_NOT_FOUND:
3014 					/*
3015 					 * This can happen if cur is from the
3016 					 * running snapshot (and it differs
3017 					 * from the live properties).
3018 					 */
3019 					scf_entry_destroy(e);
3020 					break;
3021 
3022 				case SCF_ERROR_HANDLE_MISMATCH:
3023 				case SCF_ERROR_NOT_BOUND:
3024 				case SCF_ERROR_NOT_SET:
3025 				case SCF_ERROR_INVALID_ARGUMENT:
3026 				default:
3027 					bad_error(
3028 					    "scf_transaction_property_delete",
3029 					    scf_error());
3030 				}
3031 			}
3032 		} else {
3033 			scf_callback_t ctx;
3034 
3035 			if (speak)
3036 				warn(gettext(
3037 				    "%s: Upgrading property \"%s/%s\".\n"),
3038 				    fmri, old->sc_pgroup_name,
3039 				    p->sc_property_name);
3040 
3041 			ctx.sc_handle = g_hndl;
3042 			ctx.sc_trans = tx;
3043 			ctx.sc_flags = 0;
3044 
3045 			r = lscf_property_import(new_p, &ctx);
3046 			if (r != UU_WALK_NEXT) {
3047 				if (r != UU_WALK_ERROR)
3048 					bad_error("lscf_property_import", r);
3049 				return (EINVAL);
3050 			}
3051 		}
3052 	}
3053 
3054 	/* Go over the properties which were added. */
3055 	for (new_p = uu_list_first(new->sc_pgroup_props);
3056 	    new_p != NULL;
3057 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
3058 		if (new_p->sc_seen)
3059 			continue;
3060 
3061 		/* This is a new property. */
3062 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
3063 		if (cur_p == NULL) {
3064 			scf_callback_t ctx;
3065 
3066 			ctx.sc_handle = g_hndl;
3067 			ctx.sc_trans = tx;
3068 			ctx.sc_flags = 0;
3069 
3070 			r = lscf_property_import(new_p, &ctx);
3071 			if (r != UU_WALK_NEXT) {
3072 				if (r != UU_WALK_ERROR)
3073 					bad_error("lscf_property_import", r);
3074 				return (EINVAL);
3075 			}
3076 			continue;
3077 		}
3078 
3079 		/*
3080 		 * Report a conflict if the new property differs from the
3081 		 * current one.  Unless it's general/enabled, since that's
3082 		 * never in the last-import snapshot.
3083 		 */
3084 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
3085 		    0 &&
3086 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
3087 			continue;
3088 
3089 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
3090 	}
3091 
3092 	return (0);
3093 }
3094 
3095 /*
3096  * Upgrade pg according to old & new.
3097  *
3098  * Returns
3099  *   0 - success
3100  *   ECONNABORTED - repository connection broken
3101  *   ENOMEM - out of memory
3102  *   ENOSPC - svc.configd is out of resources
3103  *   ECANCELED - pg was deleted
3104  *   EPERM - couldn't modify pg (permission denied)
3105  *   EROFS - couldn't modify pg (backend read-only)
3106  *   EACCES - couldn't modify pg (backend access denied)
3107  *   EINVAL - new has a property with invalid name or value (error printed)
3108  *   EBUSY - pg changed unexpectedly
3109  */
3110 static int
3111 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
3112     pgroup_t *new, int speak, const char *fmri)
3113 {
3114 	int r;
3115 
3116 	if (scf_transaction_start(imp_tx, pg) != 0) {
3117 		switch (scf_error()) {
3118 		case SCF_ERROR_CONNECTION_BROKEN:
3119 		case SCF_ERROR_DELETED:
3120 		case SCF_ERROR_PERMISSION_DENIED:
3121 		case SCF_ERROR_BACKEND_READONLY:
3122 		case SCF_ERROR_BACKEND_ACCESS:
3123 			return (scferror2errno(scf_error()));
3124 
3125 		case SCF_ERROR_HANDLE_MISMATCH:
3126 		case SCF_ERROR_IN_USE:
3127 		case SCF_ERROR_NOT_BOUND:
3128 		case SCF_ERROR_NOT_SET:
3129 		default:
3130 			bad_error("scf_transaction_start", scf_error());
3131 		}
3132 	}
3133 
3134 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
3135 	switch (r) {
3136 	case 0:
3137 		break;
3138 
3139 	case EINVAL:
3140 	case ENOMEM:
3141 		scf_transaction_destroy_children(imp_tx);
3142 		return (r);
3143 
3144 	default:
3145 		bad_error("add_upgrade_entries", r);
3146 	}
3147 
3148 	r = scf_transaction_commit(imp_tx);
3149 
3150 	scf_transaction_destroy_children(imp_tx);
3151 
3152 	switch (r) {
3153 	case 1:
3154 		break;
3155 
3156 	case 0:
3157 		return (EBUSY);
3158 
3159 	case -1:
3160 		switch (scf_error()) {
3161 		case SCF_ERROR_CONNECTION_BROKEN:
3162 		case SCF_ERROR_NO_RESOURCES:
3163 		case SCF_ERROR_PERMISSION_DENIED:
3164 		case SCF_ERROR_BACKEND_READONLY:
3165 		case SCF_ERROR_BACKEND_ACCESS:
3166 		case SCF_ERROR_DELETED:
3167 			return (scferror2errno(scf_error()));
3168 
3169 		case SCF_ERROR_NOT_BOUND:
3170 		case SCF_ERROR_INVALID_ARGUMENT:
3171 		case SCF_ERROR_NOT_SET:
3172 		default:
3173 			bad_error("scf_transaction_commit", scf_error());
3174 		}
3175 
3176 	default:
3177 		bad_error("scf_transaction_commit", r);
3178 	}
3179 
3180 	return (0);
3181 }
3182 
3183 /*
3184  * Compares two entity FMRIs.  Returns
3185  *
3186  *   1 - equal
3187  *   0 - not equal
3188  *   -1 - f1 is invalid or not an entity
3189  *   -2 - f2 is invalid or not an entity
3190  */
3191 static int
3192 fmri_equal(const char *f1, const char *f2)
3193 {
3194 	int r;
3195 	const char *s1, *i1, *pg1;
3196 	const char *s2, *i2, *pg2;
3197 
3198 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3199 		return (-1);
3200 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
3201 		return (-1);
3202 
3203 	if (s1 == NULL || pg1 != NULL)
3204 		return (-1);
3205 
3206 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
3207 		return (-2);
3208 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
3209 		return (-2);
3210 
3211 	if (s2 == NULL || pg2 != NULL)
3212 		return (-2);
3213 
3214 	r = strcmp(s1, s2);
3215 	if (r != 0)
3216 		return (0);
3217 
3218 	if (i1 == NULL && i2 == NULL)
3219 		return (1);
3220 
3221 	if (i1 == NULL || i2 == NULL)
3222 		return (0);
3223 
3224 	return (strcmp(i1, i2) == 0);
3225 }
3226 
3227 /*
3228  * Import a dependent by creating a dependency property group in the dependent
3229  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
3230  * dependents pg, and add an entry to create a new property for this
3231  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
3232  *
3233  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
3234  * lcbdata->sc_err to
3235  *   ECONNABORTED - repository connection broken
3236  *   ENOMEM - out of memory
3237  *   ENOSPC - configd is out of resources
3238  *   EINVAL - target is invalid (error printed)
3239  *	    - target is not an entity (error printed)
3240  *	    - dependent has invalid name (error printed)
3241  *	    - invalid property name (error printed)
3242  *	    - invalid value (error printed)
3243  *	    - scope of target does not exist (error printed)
3244  *   EPERM - couldn't create target (permission denied) (error printed)
3245  *	   - couldn't create dependency pg (permission denied) (error printed)
3246  *	   - couldn't modify dependency pg (permission denied) (error printed)
3247  *   EROFS - couldn't create target (repository read-only)
3248  *	   - couldn't create dependency pg (repository read-only)
3249  *   EACCES - couldn't create target (backend access denied)
3250  *	    - couldn't create dependency pg (backend access denied)
3251  *   ECANCELED - sc_trans's pg was deleted
3252  *   EALREADY - property for dependent already exists in sc_trans's pg
3253  *   EEXIST - dependency pg already exists in target (error printed)
3254  *   EBUSY - target deleted (error printed)
3255  *         - property group changed during import (error printed)
3256  */
3257 static int
3258 lscf_dependent_import(void *a1, void *pvt)
3259 {
3260 	pgroup_t *pgrp = a1;
3261 	scf_callback_t *lcbdata = pvt;
3262 
3263 	int isservice;
3264 	int ret;
3265 	scf_transaction_entry_t *e;
3266 	scf_value_t *val;
3267 	scf_callback_t dependent_cbdata;
3268 	scf_error_t scfe;
3269 
3270 	/*
3271 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
3272 	 * it's invalid, we fail before modifying the repository.
3273 	 */
3274 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3275 	    &dependent_cbdata.sc_parent, &isservice);
3276 	switch (scfe) {
3277 	case SCF_ERROR_NONE:
3278 		break;
3279 
3280 	case SCF_ERROR_NO_MEMORY:
3281 		return (stash_scferror_err(lcbdata, scfe));
3282 
3283 	case SCF_ERROR_INVALID_ARGUMENT:
3284 		semerr(gettext("The FMRI for the \"%s\" dependent is "
3285 		    "invalid.\n"), pgrp->sc_pgroup_name);
3286 		return (stash_scferror_err(lcbdata, scfe));
3287 
3288 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3289 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
3290 		    "specifies neither a service nor an instance.\n"),
3291 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3292 		return (stash_scferror_err(lcbdata, scfe));
3293 
3294 	case SCF_ERROR_NOT_FOUND:
3295 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
3296 		    &dependent_cbdata.sc_parent, &isservice);
3297 		switch (scfe) {
3298 		case SCF_ERROR_NONE:
3299 			break;
3300 
3301 		case SCF_ERROR_NO_MEMORY:
3302 		case SCF_ERROR_BACKEND_READONLY:
3303 		case SCF_ERROR_BACKEND_ACCESS:
3304 			return (stash_scferror_err(lcbdata, scfe));
3305 
3306 		case SCF_ERROR_NOT_FOUND:
3307 			semerr(gettext("The scope in FMRI \"%s\" for the "
3308 			    "\"%s\" dependent does not exist.\n"),
3309 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
3310 			lcbdata->sc_err = EINVAL;
3311 			return (UU_WALK_ERROR);
3312 
3313 		case SCF_ERROR_PERMISSION_DENIED:
3314 			warn(gettext(
3315 			    "Could not create %s (permission denied).\n"),
3316 			    pgrp->sc_pgroup_fmri);
3317 			return (stash_scferror_err(lcbdata, scfe));
3318 
3319 		case SCF_ERROR_INVALID_ARGUMENT:
3320 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3321 		default:
3322 			bad_error("create_entity", scfe);
3323 		}
3324 		break;
3325 
3326 	default:
3327 		bad_error("fmri_to_entity", scfe);
3328 	}
3329 
3330 	if (lcbdata->sc_trans != NULL) {
3331 		e = scf_entry_create(lcbdata->sc_handle);
3332 		if (e == NULL) {
3333 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3334 				bad_error("scf_entry_create", scf_error());
3335 
3336 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3337 			return (stash_scferror(lcbdata));
3338 		}
3339 
3340 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
3341 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
3342 			switch (scf_error()) {
3343 			case SCF_ERROR_INVALID_ARGUMENT:
3344 				warn(gettext("Dependent of %s has invalid name "
3345 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
3346 				    pgrp->sc_pgroup_name);
3347 				/* FALLTHROUGH */
3348 
3349 			case SCF_ERROR_DELETED:
3350 			case SCF_ERROR_CONNECTION_BROKEN:
3351 				scf_entry_destroy(e);
3352 				entity_destroy(dependent_cbdata.sc_parent,
3353 				    isservice);
3354 				return (stash_scferror(lcbdata));
3355 
3356 			case SCF_ERROR_EXISTS:
3357 				scf_entry_destroy(e);
3358 				entity_destroy(dependent_cbdata.sc_parent,
3359 				    isservice);
3360 				lcbdata->sc_err = EALREADY;
3361 				return (UU_WALK_ERROR);
3362 
3363 			case SCF_ERROR_NOT_BOUND:
3364 			case SCF_ERROR_HANDLE_MISMATCH:
3365 			case SCF_ERROR_NOT_SET:
3366 			default:
3367 				bad_error("scf_transaction_property_new",
3368 				    scf_error());
3369 			}
3370 		}
3371 
3372 		val = scf_value_create(lcbdata->sc_handle);
3373 		if (val == NULL) {
3374 			if (scf_error() != SCF_ERROR_NO_MEMORY)
3375 				bad_error("scf_value_create", scf_error());
3376 
3377 			entity_destroy(dependent_cbdata.sc_parent, isservice);
3378 			return (stash_scferror(lcbdata));
3379 		}
3380 
3381 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
3382 		    pgrp->sc_pgroup_fmri) != 0)
3383 			/* invalid should have been caught above */
3384 			bad_error("scf_value_set_from_string", scf_error());
3385 
3386 		if (scf_entry_add_value(e, val) != 0)
3387 			bad_error("scf_entry_add_value", scf_error());
3388 	}
3389 
3390 	/* Add the property group to the target entity. */
3391 
3392 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
3393 	dependent_cbdata.sc_flags = lcbdata->sc_flags;
3394 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
3395 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
3396 
3397 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
3398 
3399 	entity_destroy(dependent_cbdata.sc_parent, isservice);
3400 
3401 	if (ret == UU_WALK_NEXT)
3402 		return (ret);
3403 
3404 	if (ret != UU_WALK_ERROR)
3405 		bad_error("entity_pgroup_import", ret);
3406 
3407 	switch (dependent_cbdata.sc_err) {
3408 	case ECANCELED:
3409 		warn(gettext("%s deleted unexpectedly.\n"),
3410 		    pgrp->sc_pgroup_fmri);
3411 		lcbdata->sc_err = EBUSY;
3412 		break;
3413 
3414 	case EEXIST:
3415 		warn(gettext("Could not create \"%s\" dependency in %s "
3416 		    "(already exists).\n"), pgrp->sc_pgroup_name,
3417 		    pgrp->sc_pgroup_fmri);
3418 		/* FALLTHROUGH */
3419 
3420 	default:
3421 		lcbdata->sc_err = dependent_cbdata.sc_err;
3422 	}
3423 
3424 	return (UU_WALK_ERROR);
3425 }
3426 
3427 static int upgrade_dependent(const scf_property_t *, const entity_t *,
3428     const scf_snaplevel_t *, scf_transaction_t *);
3429 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
3430     const pgroup_t *);
3431 
3432 /*
3433  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
3434  * the current dependent targets from running (the snaplevel of a running
3435  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
3436  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
3437  * dependent targets and dependency properties from li_dpts_pg (the
3438  * "dependents" property group in snpl) and snpl (the snaplevel which
3439  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
3440  * snpl doesn't have a "dependents" property group, and any dependents in ient
3441  * are new.
3442  *
3443  * Returns
3444  *   0 - success
3445  *   ECONNABORTED - repository connection broken
3446  *   ENOMEM - out of memory
3447  *   ENOSPC - configd is out of resources
3448  *   ECANCELED - ent was deleted
3449  *   ENODEV - the entity containing li_dpts_pg was deleted
3450  *   EPERM - could not modify dependents pg (permission denied) (error printed)
3451  *	   - couldn't upgrade dependent (permission denied) (error printed)
3452  *	   - couldn't create dependent (permission denied) (error printed)
3453  *   EROFS - could not modify dependents pg (repository read-only)
3454  *	   - couldn't upgrade dependent (repository read-only)
3455  *	   - couldn't create dependent (repository read-only)
3456  *   EACCES - could not modify dependents pg (backend access denied)
3457  *	    - could not upgrade dependent (backend access denied)
3458  *	    - could not create dependent (backend access denied)
3459  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
3460  *	   - dependent target deleted (error printed)
3461  *	   - dependent pg changed (error printed)
3462  *   EINVAL - new dependent is invalid (error printed)
3463  *   EBADF - snpl is corrupt (error printed)
3464  *	   - snpl has corrupt pg (error printed)
3465  *	   - dependency pg in target is corrupt (error printed)
3466  *	   - target has corrupt snapshot (error printed)
3467  *   EEXIST - dependency pg already existed in target service (error printed)
3468  */
3469 static int
3470 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
3471     const scf_snaplevel_t *snpl, const entity_t *ient,
3472     const scf_snaplevel_t *running, void *ent)
3473 {
3474 	pgroup_t *new_dpt_pgroup;
3475 	scf_callback_t cbdata;
3476 	int r, unseen, tx_started = 0;
3477 	int have_cur_depts;
3478 
3479 	const char * const dependents = "dependents";
3480 
3481 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3482 
3483 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
3484 		/* Nothing to do. */
3485 		return (0);
3486 
3487 	/* Fetch the current version of the "dependents" property group. */
3488 	have_cur_depts = 1;
3489 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
3490 		switch (scf_error()) {
3491 		case SCF_ERROR_NOT_FOUND:
3492 			break;
3493 
3494 		case SCF_ERROR_DELETED:
3495 		case SCF_ERROR_CONNECTION_BROKEN:
3496 			return (scferror2errno(scf_error()));
3497 
3498 		case SCF_ERROR_NOT_SET:
3499 		case SCF_ERROR_INVALID_ARGUMENT:
3500 		case SCF_ERROR_HANDLE_MISMATCH:
3501 		case SCF_ERROR_NOT_BOUND:
3502 		default:
3503 			bad_error("entity_get_pg", scf_error());
3504 		}
3505 
3506 		have_cur_depts = 0;
3507 	}
3508 
3509 	/* Fetch the running version of the "dependents" property group. */
3510 	ud_run_dpts_pg_set = 0;
3511 	if (running != NULL)
3512 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
3513 	else
3514 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
3515 	if (r == 0) {
3516 		ud_run_dpts_pg_set = 1;
3517 	} else {
3518 		switch (scf_error()) {
3519 		case SCF_ERROR_NOT_FOUND:
3520 			break;
3521 
3522 		case SCF_ERROR_DELETED:
3523 		case SCF_ERROR_CONNECTION_BROKEN:
3524 			return (scferror2errno(scf_error()));
3525 
3526 		case SCF_ERROR_NOT_SET:
3527 		case SCF_ERROR_INVALID_ARGUMENT:
3528 		case SCF_ERROR_HANDLE_MISMATCH:
3529 		case SCF_ERROR_NOT_BOUND:
3530 		default:
3531 			bad_error(running ? "scf_snaplevel_get_pg" :
3532 			    "entity_get_pg", scf_error());
3533 		}
3534 	}
3535 
3536 	/*
3537 	 * Clear the seen fields of the dependents, so we can tell which ones
3538 	 * are new.
3539 	 */
3540 	if (uu_list_walk(ient->sc_dependents, clear_int,
3541 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
3542 		bad_error("uu_list_walk", uu_error());
3543 
3544 	if (li_dpts_pg != NULL) {
3545 		/*
3546 		 * Each property in li_dpts_pg represents a dependent tag in
3547 		 * the old manifest.  For each, call upgrade_dependent(),
3548 		 * which will change ud_cur_depts_pg or dependencies in other
3549 		 * services as appropriate.  Note (a) that changes to
3550 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
3551 		 * made en masse, and (b) it's ok if the entity doesn't have
3552 		 * a current version of the "dependents" property group,
3553 		 * because we'll just consider all dependents as customized
3554 		 * (by being deleted).
3555 		 */
3556 
3557 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
3558 			switch (scf_error()) {
3559 			case SCF_ERROR_DELETED:
3560 				return (ENODEV);
3561 
3562 			case SCF_ERROR_CONNECTION_BROKEN:
3563 				return (ECONNABORTED);
3564 
3565 			case SCF_ERROR_HANDLE_MISMATCH:
3566 			case SCF_ERROR_NOT_BOUND:
3567 			case SCF_ERROR_NOT_SET:
3568 			default:
3569 				bad_error("scf_iter_pg_properties",
3570 				    scf_error());
3571 			}
3572 		}
3573 
3574 		if (have_cur_depts &&
3575 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3576 			switch (scf_error()) {
3577 			case SCF_ERROR_BACKEND_ACCESS:
3578 			case SCF_ERROR_BACKEND_READONLY:
3579 			case SCF_ERROR_CONNECTION_BROKEN:
3580 				return (scferror2errno(scf_error()));
3581 
3582 			case SCF_ERROR_DELETED:
3583 				warn(emsg_pg_deleted, ient->sc_fmri,
3584 				    dependents);
3585 				return (EBUSY);
3586 
3587 			case SCF_ERROR_PERMISSION_DENIED:
3588 				warn(emsg_pg_mod_perm, dependents,
3589 				    ient->sc_fmri);
3590 				return (scferror2errno(scf_error()));
3591 
3592 			case SCF_ERROR_HANDLE_MISMATCH:
3593 			case SCF_ERROR_IN_USE:
3594 			case SCF_ERROR_NOT_BOUND:
3595 			case SCF_ERROR_NOT_SET:
3596 			default:
3597 				bad_error("scf_transaction_start", scf_error());
3598 			}
3599 		}
3600 		tx_started = have_cur_depts;
3601 
3602 		for (;;) {
3603 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
3604 			if (r == 0)
3605 				break;
3606 			if (r == 1) {
3607 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
3608 				    tx_started ? ud_tx : NULL);
3609 				switch (r) {
3610 				case 0:
3611 					continue;
3612 
3613 				case ECONNABORTED:
3614 				case ENOMEM:
3615 				case ENOSPC:
3616 				case EBADF:
3617 				case EBUSY:
3618 				case EINVAL:
3619 				case EPERM:
3620 				case EROFS:
3621 				case EACCES:
3622 				case EEXIST:
3623 					break;
3624 
3625 				case ECANCELED:
3626 					r = ENODEV;
3627 					break;
3628 
3629 				default:
3630 					bad_error("upgrade_dependent", r);
3631 				}
3632 
3633 				if (tx_started)
3634 					scf_transaction_destroy_children(ud_tx);
3635 				return (r);
3636 			}
3637 			if (r != -1)
3638 				bad_error("scf_iter_next_property", r);
3639 
3640 			switch (scf_error()) {
3641 			case SCF_ERROR_DELETED:
3642 				r = ENODEV;
3643 				break;
3644 
3645 			case SCF_ERROR_CONNECTION_BROKEN:
3646 				r = ECONNABORTED;
3647 				break;
3648 
3649 			case SCF_ERROR_NOT_SET:
3650 			case SCF_ERROR_INVALID_ARGUMENT:
3651 			case SCF_ERROR_NOT_BOUND:
3652 			case SCF_ERROR_HANDLE_MISMATCH:
3653 			default:
3654 				bad_error("scf_iter_next_property",
3655 				    scf_error());
3656 			}
3657 
3658 			if (tx_started)
3659 				scf_transaction_destroy_children(ud_tx);
3660 			return (r);
3661 		}
3662 	}
3663 
3664 	/* import unseen dependents */
3665 	unseen = 0;
3666 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3667 	    new_dpt_pgroup != NULL;
3668 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3669 	    new_dpt_pgroup)) {
3670 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3671 			unseen = 1;
3672 			break;
3673 		}
3674 	}
3675 
3676 	/* If there are none, exit early. */
3677 	if (unseen == 0)
3678 		goto commit;
3679 
3680 	/* Set up for lscf_dependent_import() */
3681 	cbdata.sc_handle = g_hndl;
3682 	cbdata.sc_parent = ent;
3683 	cbdata.sc_service = issvc;
3684 	cbdata.sc_flags = 0;
3685 
3686 	if (!have_cur_depts) {
3687 		/*
3688 		 * We have new dependents to import, so we need a "dependents"
3689 		 * property group.
3690 		 */
3691 		if (issvc)
3692 			r = scf_service_add_pg(ent, dependents,
3693 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3694 		else
3695 			r = scf_instance_add_pg(ent, dependents,
3696 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3697 		if (r != 0) {
3698 			switch (scf_error()) {
3699 			case SCF_ERROR_DELETED:
3700 			case SCF_ERROR_CONNECTION_BROKEN:
3701 			case SCF_ERROR_BACKEND_READONLY:
3702 			case SCF_ERROR_BACKEND_ACCESS:
3703 			case SCF_ERROR_NO_RESOURCES:
3704 				return (scferror2errno(scf_error()));
3705 
3706 			case SCF_ERROR_EXISTS:
3707 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3708 				return (EBUSY);
3709 
3710 			case SCF_ERROR_PERMISSION_DENIED:
3711 				warn(emsg_pg_add_perm, dependents,
3712 				    ient->sc_fmri);
3713 				return (scferror2errno(scf_error()));
3714 
3715 			case SCF_ERROR_NOT_BOUND:
3716 			case SCF_ERROR_HANDLE_MISMATCH:
3717 			case SCF_ERROR_INVALID_ARGUMENT:
3718 			case SCF_ERROR_NOT_SET:
3719 			default:
3720 				bad_error("scf_service_add_pg", scf_error());
3721 			}
3722 		}
3723 	}
3724 
3725 	cbdata.sc_trans = ud_tx;
3726 
3727 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3728 		switch (scf_error()) {
3729 		case SCF_ERROR_CONNECTION_BROKEN:
3730 		case SCF_ERROR_BACKEND_ACCESS:
3731 		case SCF_ERROR_BACKEND_READONLY:
3732 			return (scferror2errno(scf_error()));
3733 
3734 		case SCF_ERROR_DELETED:
3735 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3736 			return (EBUSY);
3737 
3738 		case SCF_ERROR_PERMISSION_DENIED:
3739 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3740 			return (scferror2errno(scf_error()));
3741 
3742 		case SCF_ERROR_HANDLE_MISMATCH:
3743 		case SCF_ERROR_IN_USE:
3744 		case SCF_ERROR_NOT_BOUND:
3745 		case SCF_ERROR_NOT_SET:
3746 		default:
3747 			bad_error("scf_transaction_start", scf_error());
3748 		}
3749 	}
3750 	tx_started = 1;
3751 
3752 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3753 	    new_dpt_pgroup != NULL;
3754 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3755 	    new_dpt_pgroup)) {
3756 		if (new_dpt_pgroup->sc_pgroup_seen)
3757 			continue;
3758 
3759 		if (ud_run_dpts_pg_set) {
3760 			/*
3761 			 * If the dependent is already there, then we have
3762 			 * a conflict.
3763 			 */
3764 			if (scf_pg_get_property(ud_run_dpts_pg,
3765 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3766 				r = handle_dependent_conflict(ient, ud_prop,
3767 				    new_dpt_pgroup);
3768 				switch (r) {
3769 				case 0:
3770 					continue;
3771 
3772 				case ECONNABORTED:
3773 				case ENOMEM:
3774 				case EBUSY:
3775 				case EBADF:
3776 				case EINVAL:
3777 					scf_transaction_destroy_children(ud_tx);
3778 					return (r);
3779 
3780 				default:
3781 					bad_error("handle_dependent_conflict",
3782 					    r);
3783 				}
3784 			} else {
3785 				switch (scf_error()) {
3786 				case SCF_ERROR_NOT_FOUND:
3787 					break;
3788 
3789 				case SCF_ERROR_INVALID_ARGUMENT:
3790 					warn(emsg_fmri_invalid_pg_name,
3791 					    ient->sc_fmri,
3792 					    new_dpt_pgroup->sc_pgroup_name);
3793 					scf_transaction_destroy_children(ud_tx);
3794 					return (EINVAL);
3795 
3796 				case SCF_ERROR_DELETED:
3797 					warn(emsg_pg_deleted, ient->sc_fmri,
3798 					    new_dpt_pgroup->sc_pgroup_name);
3799 					scf_transaction_destroy_children(ud_tx);
3800 					return (EBUSY);
3801 
3802 				case SCF_ERROR_CONNECTION_BROKEN:
3803 					scf_transaction_destroy_children(ud_tx);
3804 					return (ECONNABORTED);
3805 
3806 				case SCF_ERROR_NOT_BOUND:
3807 				case SCF_ERROR_HANDLE_MISMATCH:
3808 				case SCF_ERROR_NOT_SET:
3809 				default:
3810 					bad_error("scf_pg_get_property",
3811 					    scf_error());
3812 				}
3813 			}
3814 		}
3815 
3816 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3817 		if (r != UU_WALK_NEXT) {
3818 			if (r != UU_WALK_ERROR)
3819 				bad_error("lscf_dependent_import", r);
3820 
3821 			if (cbdata.sc_err == EALREADY) {
3822 				/* Collisions were handled preemptively. */
3823 				bad_error("lscf_dependent_import",
3824 				    cbdata.sc_err);
3825 			}
3826 
3827 			scf_transaction_destroy_children(ud_tx);
3828 			return (cbdata.sc_err);
3829 		}
3830 	}
3831 
3832 commit:
3833 	if (!tx_started)
3834 		return (0);
3835 
3836 	r = scf_transaction_commit(ud_tx);
3837 
3838 	scf_transaction_destroy_children(ud_tx);
3839 
3840 	switch (r) {
3841 	case 1:
3842 		return (0);
3843 
3844 	case 0:
3845 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3846 		return (EBUSY);
3847 
3848 	case -1:
3849 		break;
3850 
3851 	default:
3852 		bad_error("scf_transaction_commit", r);
3853 	}
3854 
3855 	switch (scf_error()) {
3856 	case SCF_ERROR_CONNECTION_BROKEN:
3857 	case SCF_ERROR_BACKEND_READONLY:
3858 	case SCF_ERROR_BACKEND_ACCESS:
3859 	case SCF_ERROR_NO_RESOURCES:
3860 		return (scferror2errno(scf_error()));
3861 
3862 	case SCF_ERROR_DELETED:
3863 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3864 		return (EBUSY);
3865 
3866 	case SCF_ERROR_PERMISSION_DENIED:
3867 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3868 		return (scferror2errno(scf_error()));
3869 
3870 	case SCF_ERROR_NOT_BOUND:
3871 	case SCF_ERROR_INVALID_ARGUMENT:
3872 	case SCF_ERROR_NOT_SET:
3873 	default:
3874 		bad_error("scf_transaction_destroy", scf_error());
3875 		/* NOTREACHED */
3876 	}
3877 }
3878 
3879 /*
3880  * Used to add the manifests to the list of currently supported manifests.
3881  * We can modify the existing manifest list removing entries if the files
3882  * don't exist.
3883  *
3884  * Get the old list and the new file name
3885  * If the new file name is in the list return
3886  * If not then add the file to the list.
3887  * As we process the list check to see if the files in the old list exist
3888  * 	if not then remove the file from the list.
3889  * Commit the list of manifest file names.
3890  *
3891  */
3892 static int
3893 upgrade_manifestfiles(pgroup_t *pg, const entity_t *ient,
3894     const scf_snaplevel_t *running, void *ent)
3895 {
3896 	scf_propertygroup_t *ud_mfsts_pg = NULL;
3897 	scf_property_t *ud_prop = NULL;
3898 	scf_iter_t *ud_prop_iter;
3899 	scf_value_t *fname_value;
3900 	scf_callback_t cbdata;
3901 	pgroup_t *mfst_pgroup;
3902 	property_t *mfst_prop;
3903 	property_t *old_prop;
3904 	char *pname;
3905 	char *fval;
3906 	char *old_pname;
3907 	char *old_fval;
3908 	int no_upgrade_pg;
3909 	int mfst_seen;
3910 	int r;
3911 
3912 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
3913 
3914 	/*
3915 	 * This should always be the service base on the code
3916 	 * path, and the fact that the manifests pg is a service
3917 	 * level property group only.
3918 	 */
3919 	ud_mfsts_pg = scf_pg_create(g_hndl);
3920 	ud_prop = scf_property_create(g_hndl);
3921 	ud_prop_iter = scf_iter_create(g_hndl);
3922 	fname_value = scf_value_create(g_hndl);
3923 
3924 	/* Fetch the "manifests" property group */
3925 	no_upgrade_pg = 0;
3926 	r = entity_get_pg(ent, issvc, SCF_PG_MANIFESTFILES,
3927 	    ud_mfsts_pg);
3928 	if (r != 0) {
3929 		switch (scf_error()) {
3930 		case SCF_ERROR_NOT_FOUND:
3931 			no_upgrade_pg = 1;
3932 			break;
3933 
3934 		case SCF_ERROR_DELETED:
3935 		case SCF_ERROR_CONNECTION_BROKEN:
3936 			return (scferror2errno(scf_error()));
3937 
3938 		case SCF_ERROR_NOT_SET:
3939 		case SCF_ERROR_INVALID_ARGUMENT:
3940 		case SCF_ERROR_HANDLE_MISMATCH:
3941 		case SCF_ERROR_NOT_BOUND:
3942 		default:
3943 			bad_error(running ? "scf_snaplevel_get_pg" :
3944 			    "entity_get_pg", scf_error());
3945 		}
3946 	}
3947 
3948 	if (no_upgrade_pg) {
3949 		cbdata.sc_handle = g_hndl;
3950 		cbdata.sc_parent = ent;
3951 		cbdata.sc_service = issvc;
3952 		cbdata.sc_flags = SCI_FORCE;
3953 		cbdata.sc_source_fmri = ient->sc_fmri;
3954 		cbdata.sc_target_fmri = ient->sc_fmri;
3955 
3956 		if (entity_pgroup_import(pg, &cbdata) != UU_WALK_NEXT)
3957 			return (cbdata.sc_err);
3958 
3959 		return (0);
3960 	}
3961 
3962 	/* Fetch the new manifests property group */
3963 	for (mfst_pgroup = uu_list_first(ient->sc_pgroups);
3964 	    mfst_pgroup != NULL;
3965 	    mfst_pgroup = uu_list_next(ient->sc_pgroups, mfst_pgroup)) {
3966 		if (strcmp(mfst_pgroup->sc_pgroup_name,
3967 		    SCF_PG_MANIFESTFILES) == 0)
3968 			break;
3969 	}
3970 
3971 	if ((r = scf_iter_pg_properties(ud_prop_iter, ud_mfsts_pg)) !=
3972 	    SCF_SUCCESS)
3973 		return (-1);
3974 
3975 	if ((pname = malloc(MAXPATHLEN)) == NULL)
3976 		return (ENOMEM);
3977 	if ((fval = malloc(MAXPATHLEN)) == NULL) {
3978 		free(pname);
3979 		return (ENOMEM);
3980 	}
3981 
3982 	while ((r = scf_iter_next_property(ud_prop_iter, ud_prop)) == 1) {
3983 		mfst_seen = 0;
3984 		if (scf_property_get_name(ud_prop, pname, MAXPATHLEN) < 0)
3985 			continue;
3986 
3987 		for (mfst_prop = uu_list_first(mfst_pgroup->sc_pgroup_props);
3988 		    mfst_prop != NULL;
3989 		    mfst_prop = uu_list_next(mfst_pgroup->sc_pgroup_props,
3990 		    mfst_prop)) {
3991 			if (strcmp(mfst_prop->sc_property_name, pname) == 0) {
3992 				mfst_seen = 1;
3993 			}
3994 		}
3995 
3996 		/*
3997 		 * If the manifest is not seen then add it to the new mfst
3998 		 * property list to get proccessed into the repo.
3999 		 */
4000 		if (mfst_seen == 0) {
4001 			/*
4002 			 * If we cannot get the value then there is no
4003 			 * reason to attempt to attach the value to
4004 			 * the property group
4005 			 */
4006 			if (prop_get_val(ud_prop, fname_value) == 0 &&
4007 			    scf_value_get_astring(fname_value, fval,
4008 			    MAXPATHLEN) != -1)  {
4009 				old_pname = safe_strdup(pname);
4010 				old_fval = safe_strdup(fval);
4011 				old_prop = internal_property_create(old_pname,
4012 				    SCF_TYPE_ASTRING, 1, old_fval);
4013 
4014 				/*
4015 				 * Already checked to see if the property exists
4016 				 * in the group, and it does not.
4017 				 */
4018 				(void) internal_attach_property(mfst_pgroup,
4019 				    old_prop);
4020 			}
4021 		}
4022 	}
4023 	free(pname);
4024 	free(fval);
4025 
4026 	cbdata.sc_handle = g_hndl;
4027 	cbdata.sc_parent = ent;
4028 	cbdata.sc_service = issvc;
4029 	cbdata.sc_flags = SCI_FORCE;
4030 	cbdata.sc_source_fmri = ient->sc_fmri;
4031 	cbdata.sc_target_fmri = ient->sc_fmri;
4032 
4033 	if (entity_pgroup_import(mfst_pgroup, &cbdata) != UU_WALK_NEXT)
4034 		return (cbdata.sc_err);
4035 
4036 	return (r);
4037 }
4038 
4039 /*
4040  * prop is taken to be a property in the "dependents" property group of snpl,
4041  * which is taken to be the snaplevel of a last-import snapshot corresponding
4042  * to ient.  If prop is a valid dependents property, upgrade the dependent it
4043  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
4044  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
4045  * of the entity ient represents (possibly in the running snapshot).  If it
4046  * needs to be changed, an entry will be added to tx, if not NULL.
4047  *
4048  * Returns
4049  *   0 - success
4050  *   ECONNABORTED - repository connection broken
4051  *   ENOMEM - out of memory
4052  *   ENOSPC - configd was out of resources
4053  *   ECANCELED - snpl's entity was deleted
4054  *   EINVAL - dependent target is invalid (error printed)
4055  *	    - dependent is invalid (error printed)
4056  *   EBADF - snpl is corrupt (error printed)
4057  *	   - snpl has corrupt pg (error printed)
4058  *	   - dependency pg in target is corrupt (error printed)
4059  *	   - running snapshot in dependent is missing snaplevel (error printed)
4060  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
4061  *	   - couldn't create dependent (permission denied) (error printed)
4062  *	   - couldn't modify dependent pg (permission denied) (error printed)
4063  *   EROFS - couldn't delete dependency pg (repository read-only)
4064  *	   - couldn't create dependent (repository read-only)
4065  *   EACCES - couldn't delete dependency pg (backend access denied)
4066  *	    - couldn't create dependent (backend access denied)
4067  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
4068  *	   - tx's pg was deleted (error printed)
4069  *	   - dependent pg was changed or deleted (error printed)
4070  *   EEXIST - dependency pg already exists in new target (error printed)
4071  */
4072 static int
4073 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
4074     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
4075 {
4076 	pgroup_t pgrp;
4077 	scf_type_t ty;
4078 	pgroup_t *new_dpt_pgroup;
4079 	pgroup_t *old_dpt_pgroup = NULL;
4080 	pgroup_t *current_pg;
4081 	pgroup_t *dpt;
4082 	scf_callback_t cbdata;
4083 	int tissvc;
4084 	void *target_ent;
4085 	scf_error_t serr;
4086 	int r;
4087 	scf_transaction_entry_t *ent;
4088 
4089 	const char * const cf_inval = gettext("Conflict upgrading %s "
4090 	    "(dependent \"%s\" has invalid dependents property).\n");
4091 	const char * const cf_missing = gettext("Conflict upgrading %s "
4092 	    "(dependent \"%s\" is missing).\n");
4093 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
4094 	    "(dependent \"%s\" has new dependency property group).\n");
4095 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
4096 	    "(dependent \"%s\" has new target).\n");
4097 	const char * const li_corrupt =
4098 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
4099 	const char * const upgrading =
4100 	    gettext("%s: Upgrading dependent \"%s\".\n");
4101 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
4102 	    "corrupt (missing snaplevel).\n");
4103 
4104 	if (scf_property_type(prop, &ty) != 0) {
4105 		switch (scf_error()) {
4106 		case SCF_ERROR_DELETED:
4107 		case SCF_ERROR_CONNECTION_BROKEN:
4108 			return (scferror2errno(scf_error()));
4109 
4110 		case SCF_ERROR_NOT_BOUND:
4111 		case SCF_ERROR_NOT_SET:
4112 		default:
4113 			bad_error("scf_property_type", scf_error());
4114 		}
4115 	}
4116 
4117 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4118 		warn(li_corrupt, ient->sc_fmri);
4119 		return (EBADF);
4120 	}
4121 
4122 	/*
4123 	 * prop represents a dependent in the old manifest.  It is named after
4124 	 * the dependent.
4125 	 */
4126 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
4127 		switch (scf_error()) {
4128 		case SCF_ERROR_DELETED:
4129 		case SCF_ERROR_CONNECTION_BROKEN:
4130 			return (scferror2errno(scf_error()));
4131 
4132 		case SCF_ERROR_NOT_BOUND:
4133 		case SCF_ERROR_NOT_SET:
4134 		default:
4135 			bad_error("scf_property_get_name", scf_error());
4136 		}
4137 	}
4138 
4139 	/* See if it's in the new manifest. */
4140 	pgrp.sc_pgroup_name = ud_name;
4141 	new_dpt_pgroup =
4142 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
4143 
4144 	/* If it's not, delete it... if it hasn't been customized. */
4145 	if (new_dpt_pgroup == NULL) {
4146 		if (!ud_run_dpts_pg_set)
4147 			return (0);
4148 
4149 		if (scf_property_get_value(prop, ud_val) != 0) {
4150 			switch (scf_error()) {
4151 			case SCF_ERROR_NOT_FOUND:
4152 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4153 				warn(li_corrupt, ient->sc_fmri);
4154 				return (EBADF);
4155 
4156 			case SCF_ERROR_DELETED:
4157 			case SCF_ERROR_CONNECTION_BROKEN:
4158 				return (scferror2errno(scf_error()));
4159 
4160 			case SCF_ERROR_HANDLE_MISMATCH:
4161 			case SCF_ERROR_NOT_BOUND:
4162 			case SCF_ERROR_NOT_SET:
4163 			case SCF_ERROR_PERMISSION_DENIED:
4164 			default:
4165 				bad_error("scf_property_get_value",
4166 				    scf_error());
4167 			}
4168 		}
4169 
4170 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
4171 		    max_scf_value_len + 1) < 0)
4172 			bad_error("scf_value_get_as_string", scf_error());
4173 
4174 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
4175 		    0) {
4176 			switch (scf_error()) {
4177 			case SCF_ERROR_NOT_FOUND:
4178 				return (0);
4179 
4180 			case SCF_ERROR_CONNECTION_BROKEN:
4181 				return (scferror2errno(scf_error()));
4182 
4183 			case SCF_ERROR_DELETED:
4184 				warn(emsg_pg_deleted, ient->sc_fmri,
4185 				    "dependents");
4186 				return (EBUSY);
4187 
4188 			case SCF_ERROR_INVALID_ARGUMENT:
4189 			case SCF_ERROR_NOT_BOUND:
4190 			case SCF_ERROR_HANDLE_MISMATCH:
4191 			case SCF_ERROR_NOT_SET:
4192 			default:
4193 				bad_error("scf_pg_get_property", scf_error());
4194 			}
4195 		}
4196 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
4197 			switch (scf_error()) {
4198 			case SCF_ERROR_NOT_FOUND:
4199 			case SCF_ERROR_CONSTRAINT_VIOLATED:
4200 				warn(cf_inval, ient->sc_fmri, ud_name);
4201 				return (0);
4202 
4203 			case SCF_ERROR_DELETED:
4204 			case SCF_ERROR_CONNECTION_BROKEN:
4205 				return (scferror2errno(scf_error()));
4206 
4207 			case SCF_ERROR_HANDLE_MISMATCH:
4208 			case SCF_ERROR_NOT_BOUND:
4209 			case SCF_ERROR_NOT_SET:
4210 			case SCF_ERROR_PERMISSION_DENIED:
4211 			default:
4212 				bad_error("scf_property_get_value",
4213 				    scf_error());
4214 			}
4215 		}
4216 
4217 		ty = scf_value_type(ud_val);
4218 		assert(ty != SCF_TYPE_INVALID);
4219 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4220 			warn(cf_inval, ient->sc_fmri, ud_name);
4221 			return (0);
4222 		}
4223 
4224 		if (scf_value_get_as_string(ud_val, ud_ctarg,
4225 		    max_scf_value_len + 1) < 0)
4226 			bad_error("scf_value_get_as_string", scf_error());
4227 
4228 		r = fmri_equal(ud_ctarg, ud_oldtarg);
4229 		switch (r) {
4230 		case 1:
4231 			break;
4232 
4233 		case 0:
4234 		case -1:	/* warn? */
4235 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4236 			return (0);
4237 
4238 		case -2:
4239 			warn(li_corrupt, ient->sc_fmri);
4240 			return (EBADF);
4241 
4242 		default:
4243 			bad_error("fmri_equal", r);
4244 		}
4245 
4246 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4247 			switch (scf_error()) {
4248 			case SCF_ERROR_NOT_FOUND:
4249 				warn(li_corrupt, ient->sc_fmri);
4250 				return (EBADF);
4251 
4252 			case SCF_ERROR_DELETED:
4253 			case SCF_ERROR_CONNECTION_BROKEN:
4254 				return (scferror2errno(scf_error()));
4255 
4256 			case SCF_ERROR_NOT_BOUND:
4257 			case SCF_ERROR_HANDLE_MISMATCH:
4258 			case SCF_ERROR_INVALID_ARGUMENT:
4259 			case SCF_ERROR_NOT_SET:
4260 			default:
4261 				bad_error("scf_snaplevel_get_pg", scf_error());
4262 			}
4263 		}
4264 
4265 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4266 		    snap_lastimport);
4267 		switch (r) {
4268 		case 0:
4269 			break;
4270 
4271 		case ECANCELED:
4272 		case ECONNABORTED:
4273 		case ENOMEM:
4274 		case EBADF:
4275 			return (r);
4276 
4277 		case EACCES:
4278 		default:
4279 			bad_error("load_pg", r);
4280 		}
4281 
4282 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4283 		switch (serr) {
4284 		case SCF_ERROR_NONE:
4285 			break;
4286 
4287 		case SCF_ERROR_NO_MEMORY:
4288 			internal_pgroup_free(old_dpt_pgroup);
4289 			return (ENOMEM);
4290 
4291 		case SCF_ERROR_NOT_FOUND:
4292 			internal_pgroup_free(old_dpt_pgroup);
4293 			goto delprop;
4294 
4295 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
4296 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
4297 		default:
4298 			bad_error("fmri_to_entity", serr);
4299 		}
4300 
4301 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4302 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4303 		switch (r) {
4304 		case 0:
4305 			break;
4306 
4307 		case ECONNABORTED:
4308 			internal_pgroup_free(old_dpt_pgroup);
4309 			return (r);
4310 
4311 		case ECANCELED:
4312 		case ENOENT:
4313 			internal_pgroup_free(old_dpt_pgroup);
4314 			goto delprop;
4315 
4316 		case EBADF:
4317 			warn(r_no_lvl, ud_ctarg);
4318 			internal_pgroup_free(old_dpt_pgroup);
4319 			return (r);
4320 
4321 		case EINVAL:
4322 		default:
4323 			bad_error("entity_get_running_pg", r);
4324 		}
4325 
4326 		/* load it */
4327 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4328 		switch (r) {
4329 		case 0:
4330 			break;
4331 
4332 		case ECANCELED:
4333 			internal_pgroup_free(old_dpt_pgroup);
4334 			goto delprop;
4335 
4336 		case ECONNABORTED:
4337 		case ENOMEM:
4338 		case EBADF:
4339 			internal_pgroup_free(old_dpt_pgroup);
4340 			return (r);
4341 
4342 		case EACCES:
4343 		default:
4344 			bad_error("load_pg", r);
4345 		}
4346 
4347 		/* compare property groups */
4348 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
4349 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4350 			internal_pgroup_free(old_dpt_pgroup);
4351 			internal_pgroup_free(current_pg);
4352 			return (0);
4353 		}
4354 
4355 		internal_pgroup_free(old_dpt_pgroup);
4356 		internal_pgroup_free(current_pg);
4357 
4358 		if (g_verbose)
4359 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
4360 			    ient->sc_fmri, ud_name);
4361 
4362 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4363 			switch (scf_error()) {
4364 			case SCF_ERROR_NOT_FOUND:
4365 			case SCF_ERROR_DELETED:
4366 				internal_pgroup_free(old_dpt_pgroup);
4367 				goto delprop;
4368 
4369 			case SCF_ERROR_CONNECTION_BROKEN:
4370 				internal_pgroup_free(old_dpt_pgroup);
4371 				return (ECONNABORTED);
4372 
4373 			case SCF_ERROR_NOT_SET:
4374 			case SCF_ERROR_INVALID_ARGUMENT:
4375 			case SCF_ERROR_HANDLE_MISMATCH:
4376 			case SCF_ERROR_NOT_BOUND:
4377 			default:
4378 				bad_error("entity_get_pg", scf_error());
4379 			}
4380 		}
4381 
4382 		if (scf_pg_delete(ud_pg) != 0) {
4383 			switch (scf_error()) {
4384 			case SCF_ERROR_DELETED:
4385 				break;
4386 
4387 			case SCF_ERROR_CONNECTION_BROKEN:
4388 			case SCF_ERROR_BACKEND_READONLY:
4389 			case SCF_ERROR_BACKEND_ACCESS:
4390 				return (scferror2errno(scf_error()));
4391 
4392 			case SCF_ERROR_PERMISSION_DENIED:
4393 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4394 				return (scferror2errno(scf_error()));
4395 
4396 			case SCF_ERROR_NOT_SET:
4397 			default:
4398 				bad_error("scf_pg_delete", scf_error());
4399 			}
4400 		}
4401 
4402 		/*
4403 		 * This service was changed, so it must be refreshed.  But
4404 		 * since it's not mentioned in the new manifest, we have to
4405 		 * record its FMRI here for use later.  We record the name
4406 		 * & the entity (via sc_parent) in case we need to print error
4407 		 * messages during the refresh.
4408 		 */
4409 		dpt = internal_pgroup_new();
4410 		if (dpt == NULL)
4411 			return (ENOMEM);
4412 		dpt->sc_pgroup_name = strdup(ud_name);
4413 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
4414 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4415 			return (ENOMEM);
4416 		dpt->sc_parent = (entity_t *)ient;
4417 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4418 			uu_die(gettext("libuutil error: %s\n"),
4419 			    uu_strerror(uu_error()));
4420 
4421 delprop:
4422 		if (tx == NULL)
4423 			return (0);
4424 
4425 		ent = scf_entry_create(g_hndl);
4426 		if (ent == NULL)
4427 			return (ENOMEM);
4428 
4429 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
4430 			scf_entry_destroy(ent);
4431 			switch (scf_error()) {
4432 			case SCF_ERROR_DELETED:
4433 				warn(emsg_pg_deleted, ient->sc_fmri,
4434 				    "dependents");
4435 				return (EBUSY);
4436 
4437 			case SCF_ERROR_CONNECTION_BROKEN:
4438 				return (scferror2errno(scf_error()));
4439 
4440 			case SCF_ERROR_NOT_FOUND:
4441 				break;
4442 
4443 			case SCF_ERROR_HANDLE_MISMATCH:
4444 			case SCF_ERROR_NOT_BOUND:
4445 			case SCF_ERROR_INVALID_ARGUMENT:
4446 			case SCF_ERROR_NOT_SET:
4447 			default:
4448 				bad_error("scf_transaction_property_delete",
4449 				    scf_error());
4450 			}
4451 		}
4452 
4453 		return (0);
4454 	}
4455 
4456 	new_dpt_pgroup->sc_pgroup_seen = 1;
4457 
4458 	/*
4459 	 * Decide whether the dependent has changed in the manifest.
4460 	 */
4461 	/* Compare the target. */
4462 	if (scf_property_get_value(prop, ud_val) != 0) {
4463 		switch (scf_error()) {
4464 		case SCF_ERROR_NOT_FOUND:
4465 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4466 			warn(li_corrupt, ient->sc_fmri);
4467 			return (EBADF);
4468 
4469 		case SCF_ERROR_DELETED:
4470 		case SCF_ERROR_CONNECTION_BROKEN:
4471 			return (scferror2errno(scf_error()));
4472 
4473 		case SCF_ERROR_HANDLE_MISMATCH:
4474 		case SCF_ERROR_NOT_BOUND:
4475 		case SCF_ERROR_NOT_SET:
4476 		case SCF_ERROR_PERMISSION_DENIED:
4477 		default:
4478 			bad_error("scf_property_get_value", scf_error());
4479 		}
4480 	}
4481 
4482 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
4483 	    0)
4484 		bad_error("scf_value_get_as_string", scf_error());
4485 
4486 	/*
4487 	 * If the fmri's are not equal then the old fmri will need to
4488 	 * be refreshed to ensure that the changes are properly updated
4489 	 * in that service.
4490 	 */
4491 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
4492 	switch (r) {
4493 	case 0:
4494 		dpt = internal_pgroup_new();
4495 		if (dpt == NULL)
4496 			return (ENOMEM);
4497 		dpt->sc_pgroup_name = strdup(ud_name);
4498 		dpt->sc_pgroup_fmri = strdup(ud_oldtarg);
4499 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
4500 			return (ENOMEM);
4501 		dpt->sc_parent = (entity_t *)ient;
4502 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
4503 			uu_die(gettext("libuutil error: %s\n"),
4504 			    uu_strerror(uu_error()));
4505 		break;
4506 
4507 	case 1:
4508 		/* Compare the dependency pgs. */
4509 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
4510 			switch (scf_error()) {
4511 			case SCF_ERROR_NOT_FOUND:
4512 				warn(li_corrupt, ient->sc_fmri);
4513 				return (EBADF);
4514 
4515 			case SCF_ERROR_DELETED:
4516 			case SCF_ERROR_CONNECTION_BROKEN:
4517 				return (scferror2errno(scf_error()));
4518 
4519 			case SCF_ERROR_NOT_BOUND:
4520 			case SCF_ERROR_HANDLE_MISMATCH:
4521 			case SCF_ERROR_INVALID_ARGUMENT:
4522 			case SCF_ERROR_NOT_SET:
4523 			default:
4524 				bad_error("scf_snaplevel_get_pg", scf_error());
4525 			}
4526 		}
4527 
4528 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4529 		    snap_lastimport);
4530 		switch (r) {
4531 		case 0:
4532 			break;
4533 
4534 		case ECANCELED:
4535 		case ECONNABORTED:
4536 		case ENOMEM:
4537 		case EBADF:
4538 			return (r);
4539 
4540 		case EACCES:
4541 		default:
4542 			bad_error("load_pg", r);
4543 		}
4544 
4545 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
4546 			/* no change, leave customizations */
4547 			internal_pgroup_free(old_dpt_pgroup);
4548 			return (0);
4549 		}
4550 		break;
4551 
4552 	case -1:
4553 		warn(li_corrupt, ient->sc_fmri);
4554 		return (EBADF);
4555 
4556 	case -2:
4557 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
4558 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
4559 		return (EINVAL);
4560 
4561 	default:
4562 		bad_error("fmri_equal", r);
4563 	}
4564 
4565 	/*
4566 	 * The dependent has changed in the manifest.  Upgrade the current
4567 	 * properties if they haven't been customized.
4568 	 */
4569 
4570 	/*
4571 	 * If new_dpt_pgroup->sc_override, then act as though the property
4572 	 * group hasn't been customized.
4573 	 */
4574 	if (new_dpt_pgroup->sc_pgroup_override) {
4575 		(void) strcpy(ud_ctarg, ud_oldtarg);
4576 		goto nocust;
4577 	}
4578 
4579 	if (!ud_run_dpts_pg_set) {
4580 		warn(cf_missing, ient->sc_fmri, ud_name);
4581 		r = 0;
4582 		goto out;
4583 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
4584 		switch (scf_error()) {
4585 		case SCF_ERROR_NOT_FOUND:
4586 			warn(cf_missing, ient->sc_fmri, ud_name);
4587 			r = 0;
4588 			goto out;
4589 
4590 		case SCF_ERROR_CONNECTION_BROKEN:
4591 			r = scferror2errno(scf_error());
4592 			goto out;
4593 
4594 		case SCF_ERROR_DELETED:
4595 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
4596 			r = EBUSY;
4597 			goto out;
4598 
4599 		case SCF_ERROR_INVALID_ARGUMENT:
4600 		case SCF_ERROR_NOT_BOUND:
4601 		case SCF_ERROR_HANDLE_MISMATCH:
4602 		case SCF_ERROR_NOT_SET:
4603 		default:
4604 			bad_error("scf_pg_get_property", scf_error());
4605 		}
4606 	}
4607 
4608 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
4609 		switch (scf_error()) {
4610 		case SCF_ERROR_NOT_FOUND:
4611 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4612 			warn(cf_inval, ient->sc_fmri, ud_name);
4613 			r = 0;
4614 			goto out;
4615 
4616 		case SCF_ERROR_DELETED:
4617 		case SCF_ERROR_CONNECTION_BROKEN:
4618 			r = scferror2errno(scf_error());
4619 			goto out;
4620 
4621 		case SCF_ERROR_HANDLE_MISMATCH:
4622 		case SCF_ERROR_NOT_BOUND:
4623 		case SCF_ERROR_NOT_SET:
4624 		case SCF_ERROR_PERMISSION_DENIED:
4625 		default:
4626 			bad_error("scf_property_get_value", scf_error());
4627 		}
4628 	}
4629 
4630 	ty = scf_value_type(ud_val);
4631 	assert(ty != SCF_TYPE_INVALID);
4632 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4633 		warn(cf_inval, ient->sc_fmri, ud_name);
4634 		r = 0;
4635 		goto out;
4636 	}
4637 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4638 	    0)
4639 		bad_error("scf_value_get_as_string", scf_error());
4640 
4641 	r = fmri_equal(ud_ctarg, ud_oldtarg);
4642 	if (r == -1) {
4643 		warn(cf_inval, ient->sc_fmri, ud_name);
4644 		r = 0;
4645 		goto out;
4646 	} else if (r == -2) {
4647 		warn(li_corrupt, ient->sc_fmri);
4648 		r = EBADF;
4649 		goto out;
4650 	} else if (r == 0) {
4651 		/*
4652 		 * Target has been changed.  Only abort now if it's been
4653 		 * changed to something other than what's in the manifest.
4654 		 */
4655 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4656 		if (r == -1) {
4657 			warn(cf_inval, ient->sc_fmri, ud_name);
4658 			r = 0;
4659 			goto out;
4660 		} else if (r == 0) {
4661 			warn(cf_newtarg, ient->sc_fmri, ud_name);
4662 			r = 0;
4663 			goto out;
4664 		} else if (r != 1) {
4665 			/* invalid sc_pgroup_fmri caught above */
4666 			bad_error("fmri_equal", r);
4667 		}
4668 
4669 		/*
4670 		 * Fetch the current dependency pg.  If it's what the manifest
4671 		 * says, then no problem.
4672 		 */
4673 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4674 		switch (serr) {
4675 		case SCF_ERROR_NONE:
4676 			break;
4677 
4678 		case SCF_ERROR_NOT_FOUND:
4679 			warn(cf_missing, ient->sc_fmri, ud_name);
4680 			r = 0;
4681 			goto out;
4682 
4683 		case SCF_ERROR_NO_MEMORY:
4684 			r = ENOMEM;
4685 			goto out;
4686 
4687 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4688 		case SCF_ERROR_INVALID_ARGUMENT:
4689 		default:
4690 			bad_error("fmri_to_entity", serr);
4691 		}
4692 
4693 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
4694 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
4695 		switch (r) {
4696 		case 0:
4697 			break;
4698 
4699 		case ECONNABORTED:
4700 			goto out;
4701 
4702 		case ECANCELED:
4703 		case ENOENT:
4704 			warn(cf_missing, ient->sc_fmri, ud_name);
4705 			r = 0;
4706 			goto out;
4707 
4708 		case EBADF:
4709 			warn(r_no_lvl, ud_ctarg);
4710 			goto out;
4711 
4712 		case EINVAL:
4713 		default:
4714 			bad_error("entity_get_running_pg", r);
4715 		}
4716 
4717 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4718 		switch (r) {
4719 		case 0:
4720 			break;
4721 
4722 		case ECANCELED:
4723 			warn(cf_missing, ient->sc_fmri, ud_name);
4724 			r = 0;
4725 			goto out;
4726 
4727 		case ECONNABORTED:
4728 		case ENOMEM:
4729 		case EBADF:
4730 			goto out;
4731 
4732 		case EACCES:
4733 		default:
4734 			bad_error("load_pg", r);
4735 		}
4736 
4737 		if (!pg_equal(current_pg, new_dpt_pgroup))
4738 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4739 		internal_pgroup_free(current_pg);
4740 		r = 0;
4741 		goto out;
4742 	} else if (r != 1) {
4743 		bad_error("fmri_equal", r);
4744 	}
4745 
4746 nocust:
4747 	/*
4748 	 * Target has not been customized.  Check the dependency property
4749 	 * group.
4750 	 */
4751 
4752 	if (old_dpt_pgroup == NULL) {
4753 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
4754 		    ud_pg) != 0) {
4755 			switch (scf_error()) {
4756 			case SCF_ERROR_NOT_FOUND:
4757 				warn(li_corrupt, ient->sc_fmri);
4758 				return (EBADF);
4759 
4760 			case SCF_ERROR_DELETED:
4761 			case SCF_ERROR_CONNECTION_BROKEN:
4762 				return (scferror2errno(scf_error()));
4763 
4764 			case SCF_ERROR_NOT_BOUND:
4765 			case SCF_ERROR_HANDLE_MISMATCH:
4766 			case SCF_ERROR_INVALID_ARGUMENT:
4767 			case SCF_ERROR_NOT_SET:
4768 			default:
4769 				bad_error("scf_snaplevel_get_pg", scf_error());
4770 			}
4771 		}
4772 
4773 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
4774 		    snap_lastimport);
4775 		switch (r) {
4776 		case 0:
4777 			break;
4778 
4779 		case ECANCELED:
4780 		case ECONNABORTED:
4781 		case ENOMEM:
4782 		case EBADF:
4783 			return (r);
4784 
4785 		case EACCES:
4786 		default:
4787 			bad_error("load_pg", r);
4788 		}
4789 	}
4790 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
4791 	switch (serr) {
4792 	case SCF_ERROR_NONE:
4793 		break;
4794 
4795 	case SCF_ERROR_NOT_FOUND:
4796 		warn(cf_missing, ient->sc_fmri, ud_name);
4797 		r = 0;
4798 		goto out;
4799 
4800 	case SCF_ERROR_NO_MEMORY:
4801 		r = ENOMEM;
4802 		goto out;
4803 
4804 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4805 	case SCF_ERROR_INVALID_ARGUMENT:
4806 	default:
4807 		bad_error("fmri_to_entity", serr);
4808 	}
4809 
4810 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
4811 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4812 	switch (r) {
4813 	case 0:
4814 		break;
4815 
4816 	case ECONNABORTED:
4817 		goto out;
4818 
4819 	case ECANCELED:
4820 	case ENOENT:
4821 		warn(cf_missing, ient->sc_fmri, ud_name);
4822 		r = 0;
4823 		goto out;
4824 
4825 	case EBADF:
4826 		warn(r_no_lvl, ud_ctarg);
4827 		goto out;
4828 
4829 	case EINVAL:
4830 	default:
4831 		bad_error("entity_get_running_pg", r);
4832 	}
4833 
4834 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4835 	switch (r) {
4836 	case 0:
4837 		break;
4838 
4839 	case ECANCELED:
4840 		warn(cf_missing, ient->sc_fmri, ud_name);
4841 		goto out;
4842 
4843 	case ECONNABORTED:
4844 	case ENOMEM:
4845 	case EBADF:
4846 		goto out;
4847 
4848 	case EACCES:
4849 	default:
4850 		bad_error("load_pg", r);
4851 	}
4852 
4853 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4854 		if (!pg_equal(current_pg, new_dpt_pgroup))
4855 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4856 		internal_pgroup_free(current_pg);
4857 		r = 0;
4858 		goto out;
4859 	}
4860 
4861 	/* Uncustomized.  Upgrade. */
4862 
4863 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4864 	switch (r) {
4865 	case 1:
4866 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4867 			/* Already upgraded. */
4868 			internal_pgroup_free(current_pg);
4869 			r = 0;
4870 			goto out;
4871 		}
4872 
4873 		internal_pgroup_free(current_pg);
4874 
4875 		/* upgrade current_pg */
4876 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4877 			switch (scf_error()) {
4878 			case SCF_ERROR_CONNECTION_BROKEN:
4879 				r = scferror2errno(scf_error());
4880 				goto out;
4881 
4882 			case SCF_ERROR_DELETED:
4883 				warn(cf_missing, ient->sc_fmri, ud_name);
4884 				r = 0;
4885 				goto out;
4886 
4887 			case SCF_ERROR_NOT_FOUND:
4888 				break;
4889 
4890 			case SCF_ERROR_INVALID_ARGUMENT:
4891 			case SCF_ERROR_NOT_BOUND:
4892 			case SCF_ERROR_NOT_SET:
4893 			case SCF_ERROR_HANDLE_MISMATCH:
4894 			default:
4895 				bad_error("entity_get_pg", scf_error());
4896 			}
4897 
4898 			if (tissvc)
4899 				r = scf_service_add_pg(target_ent, ud_name,
4900 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4901 			else
4902 				r = scf_instance_add_pg(target_ent, ud_name,
4903 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4904 			if (r != 0) {
4905 				switch (scf_error()) {
4906 				case SCF_ERROR_CONNECTION_BROKEN:
4907 				case SCF_ERROR_NO_RESOURCES:
4908 				case SCF_ERROR_BACKEND_READONLY:
4909 				case SCF_ERROR_BACKEND_ACCESS:
4910 					r = scferror2errno(scf_error());
4911 					goto out;
4912 
4913 				case SCF_ERROR_DELETED:
4914 					warn(cf_missing, ient->sc_fmri,
4915 					    ud_name);
4916 					r = 0;
4917 					goto out;
4918 
4919 				case SCF_ERROR_PERMISSION_DENIED:
4920 					warn(emsg_pg_deleted, ud_ctarg,
4921 					    ud_name);
4922 					r = EPERM;
4923 					goto out;
4924 
4925 				case SCF_ERROR_EXISTS:
4926 					warn(emsg_pg_added, ud_ctarg, ud_name);
4927 					r = EBUSY;
4928 					goto out;
4929 
4930 				case SCF_ERROR_NOT_BOUND:
4931 				case SCF_ERROR_HANDLE_MISMATCH:
4932 				case SCF_ERROR_INVALID_ARGUMENT:
4933 				case SCF_ERROR_NOT_SET:
4934 				default:
4935 					bad_error("entity_add_pg", scf_error());
4936 				}
4937 			}
4938 		}
4939 
4940 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4941 		switch (r) {
4942 		case 0:
4943 			break;
4944 
4945 		case ECANCELED:
4946 			warn(cf_missing, ient->sc_fmri, ud_name);
4947 			goto out;
4948 
4949 		case ECONNABORTED:
4950 		case ENOMEM:
4951 		case EBADF:
4952 			goto out;
4953 
4954 		case EACCES:
4955 		default:
4956 			bad_error("load_pg", r);
4957 		}
4958 
4959 		if (g_verbose)
4960 			warn(upgrading, ient->sc_fmri, ud_name);
4961 
4962 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4963 		    new_dpt_pgroup, 0, ient->sc_fmri);
4964 		switch (r) {
4965 		case 0:
4966 			break;
4967 
4968 		case ECANCELED:
4969 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4970 			r = EBUSY;
4971 			goto out;
4972 
4973 		case EPERM:
4974 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4975 			goto out;
4976 
4977 		case EBUSY:
4978 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4979 			goto out;
4980 
4981 		case ECONNABORTED:
4982 		case ENOMEM:
4983 		case ENOSPC:
4984 		case EROFS:
4985 		case EACCES:
4986 		case EINVAL:
4987 			goto out;
4988 
4989 		default:
4990 			bad_error("upgrade_pg", r);
4991 		}
4992 		break;
4993 
4994 	case 0: {
4995 		scf_transaction_entry_t *ent;
4996 		scf_value_t *val;
4997 
4998 		internal_pgroup_free(current_pg);
4999 
5000 		/* delete old pg */
5001 		if (g_verbose)
5002 			warn(upgrading, ient->sc_fmri, ud_name);
5003 
5004 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
5005 			switch (scf_error()) {
5006 			case SCF_ERROR_CONNECTION_BROKEN:
5007 				r = scferror2errno(scf_error());
5008 				goto out;
5009 
5010 			case SCF_ERROR_DELETED:
5011 				warn(cf_missing, ient->sc_fmri, ud_name);
5012 				r = 0;
5013 				goto out;
5014 
5015 			case SCF_ERROR_NOT_FOUND:
5016 				break;
5017 
5018 			case SCF_ERROR_INVALID_ARGUMENT:
5019 			case SCF_ERROR_NOT_BOUND:
5020 			case SCF_ERROR_NOT_SET:
5021 			case SCF_ERROR_HANDLE_MISMATCH:
5022 			default:
5023 				bad_error("entity_get_pg", scf_error());
5024 			}
5025 		} else if (scf_pg_delete(ud_pg) != 0) {
5026 			switch (scf_error()) {
5027 			case SCF_ERROR_DELETED:
5028 				break;
5029 
5030 			case SCF_ERROR_CONNECTION_BROKEN:
5031 			case SCF_ERROR_BACKEND_READONLY:
5032 			case SCF_ERROR_BACKEND_ACCESS:
5033 				r = scferror2errno(scf_error());
5034 				goto out;
5035 
5036 			case SCF_ERROR_PERMISSION_DENIED:
5037 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
5038 				r = scferror2errno(scf_error());
5039 				goto out;
5040 
5041 			case SCF_ERROR_NOT_SET:
5042 			default:
5043 				bad_error("scf_pg_delete", scf_error());
5044 			}
5045 		}
5046 
5047 		/* import new one */
5048 		cbdata.sc_handle = g_hndl;
5049 		cbdata.sc_trans = NULL;		/* handled below */
5050 		cbdata.sc_flags = 0;
5051 
5052 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
5053 		if (r != UU_WALK_NEXT) {
5054 			if (r != UU_WALK_ERROR)
5055 				bad_error("lscf_dependent_import", r);
5056 
5057 			r = cbdata.sc_err;
5058 			goto out;
5059 		}
5060 
5061 		if (tx == NULL)
5062 			break;
5063 
5064 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
5065 		    (val = scf_value_create(g_hndl)) == NULL) {
5066 			if (scf_error() == SCF_ERROR_NO_MEMORY)
5067 				return (ENOMEM);
5068 
5069 			bad_error("scf_entry_create", scf_error());
5070 		}
5071 
5072 		if (scf_transaction_property_change_type(tx, ent, ud_name,
5073 		    SCF_TYPE_FMRI) != 0) {
5074 			switch (scf_error()) {
5075 			case SCF_ERROR_CONNECTION_BROKEN:
5076 				r = scferror2errno(scf_error());
5077 				goto out;
5078 
5079 			case SCF_ERROR_DELETED:
5080 				warn(emsg_pg_deleted, ient->sc_fmri,
5081 				    "dependents");
5082 				r = EBUSY;
5083 				goto out;
5084 
5085 			case SCF_ERROR_NOT_FOUND:
5086 				break;
5087 
5088 			case SCF_ERROR_NOT_BOUND:
5089 			case SCF_ERROR_HANDLE_MISMATCH:
5090 			case SCF_ERROR_INVALID_ARGUMENT:
5091 			case SCF_ERROR_NOT_SET:
5092 			default:
5093 				bad_error("scf_transaction_property_"
5094 				    "change_type", scf_error());
5095 			}
5096 
5097 			if (scf_transaction_property_new(tx, ent, ud_name,
5098 			    SCF_TYPE_FMRI) != 0) {
5099 				switch (scf_error()) {
5100 				case SCF_ERROR_CONNECTION_BROKEN:
5101 					r = scferror2errno(scf_error());
5102 					goto out;
5103 
5104 				case SCF_ERROR_DELETED:
5105 					warn(emsg_pg_deleted, ient->sc_fmri,
5106 					    "dependents");
5107 					r = EBUSY;
5108 					goto out;
5109 
5110 				case SCF_ERROR_EXISTS:
5111 					warn(emsg_pg_changed, ient->sc_fmri,
5112 					    "dependents");
5113 					r = EBUSY;
5114 					goto out;
5115 
5116 				case SCF_ERROR_INVALID_ARGUMENT:
5117 				case SCF_ERROR_HANDLE_MISMATCH:
5118 				case SCF_ERROR_NOT_BOUND:
5119 				case SCF_ERROR_NOT_SET:
5120 				default:
5121 					bad_error("scf_transaction_property_"
5122 					    "new", scf_error());
5123 				}
5124 			}
5125 		}
5126 
5127 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
5128 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
5129 			/* invalid sc_pgroup_fmri caught above */
5130 			bad_error("scf_value_set_from_string",
5131 			    scf_error());
5132 
5133 		if (scf_entry_add_value(ent, val) != 0)
5134 			bad_error("scf_entry_add_value", scf_error());
5135 		break;
5136 	}
5137 
5138 	case -2:
5139 		warn(li_corrupt, ient->sc_fmri);
5140 		internal_pgroup_free(current_pg);
5141 		r = EBADF;
5142 		goto out;
5143 
5144 	case -1:
5145 	default:
5146 		/* invalid sc_pgroup_fmri caught above */
5147 		bad_error("fmri_equal", r);
5148 	}
5149 
5150 	r = 0;
5151 
5152 out:
5153 	if (old_dpt_pgroup != NULL)
5154 		internal_pgroup_free(old_dpt_pgroup);
5155 
5156 	return (r);
5157 }
5158 
5159 /*
5160  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
5161  * would import it, except it seems to exist in the service anyway.  Compare
5162  * the existent dependent with the one we would import, and report any
5163  * differences (if there are none, be silent).  prop is the property which
5164  * represents the existent dependent (in the dependents property group) in the
5165  * entity corresponding to ient.
5166  *
5167  * Returns
5168  *   0 - success (Sort of.  At least, we can continue importing.)
5169  *   ECONNABORTED - repository connection broken
5170  *   EBUSY - ancestor of prop was deleted (error printed)
5171  *   ENOMEM - out of memory
5172  *   EBADF - corrupt property group (error printed)
5173  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
5174  */
5175 static int
5176 handle_dependent_conflict(const entity_t * const ient,
5177     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
5178 {
5179 	int r;
5180 	scf_type_t ty;
5181 	scf_error_t scfe;
5182 	void *tptr;
5183 	int tissvc;
5184 	pgroup_t *pgroup;
5185 
5186 	if (scf_property_get_value(prop, ud_val) != 0) {
5187 		switch (scf_error()) {
5188 		case SCF_ERROR_CONNECTION_BROKEN:
5189 			return (scferror2errno(scf_error()));
5190 
5191 		case SCF_ERROR_DELETED:
5192 			warn(emsg_pg_deleted, ient->sc_fmri,
5193 			    new_dpt_pgroup->sc_pgroup_name);
5194 			return (EBUSY);
5195 
5196 		case SCF_ERROR_CONSTRAINT_VIOLATED:
5197 		case SCF_ERROR_NOT_FOUND:
5198 			warn(gettext("Conflict upgrading %s (not importing "
5199 			    "dependent \"%s\" because it already exists.)  "
5200 			    "Warning: The \"%s/%2$s\" property has more or "
5201 			    "fewer than one value)).\n"), ient->sc_fmri,
5202 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
5203 			return (0);
5204 
5205 		case SCF_ERROR_HANDLE_MISMATCH:
5206 		case SCF_ERROR_NOT_BOUND:
5207 		case SCF_ERROR_NOT_SET:
5208 		case SCF_ERROR_PERMISSION_DENIED:
5209 		default:
5210 			bad_error("scf_property_get_value",
5211 			    scf_error());
5212 		}
5213 	}
5214 
5215 	ty = scf_value_type(ud_val);
5216 	assert(ty != SCF_TYPE_INVALID);
5217 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
5218 		warn(gettext("Conflict upgrading %s (not importing dependent "
5219 		    "\"%s\" because it already exists).  Warning: The "
5220 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
5221 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
5222 		    scf_type_to_string(ty), "dependents");
5223 		return (0);
5224 	}
5225 
5226 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
5227 	    0)
5228 		bad_error("scf_value_get_as_string", scf_error());
5229 
5230 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
5231 	switch (r) {
5232 	case 0:
5233 		warn(gettext("Conflict upgrading %s (not importing dependent "
5234 		    "\"%s\" (target \"%s\") because it already exists with "
5235 		    "target \"%s\").\n"), ient->sc_fmri,
5236 		    new_dpt_pgroup->sc_pgroup_name,
5237 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
5238 		return (0);
5239 
5240 	case 1:
5241 		break;
5242 
5243 	case -1:
5244 		warn(gettext("Conflict upgrading %s (not importing dependent "
5245 		    "\"%s\" because it already exists).  Warning: The current "
5246 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
5247 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5248 		return (0);
5249 
5250 	case -2:
5251 		warn(gettext("Dependent \"%s\" of %s has invalid target "
5252 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
5253 		    new_dpt_pgroup->sc_pgroup_fmri);
5254 		return (EINVAL);
5255 
5256 	default:
5257 		bad_error("fmri_equal", r);
5258 	}
5259 
5260 	/* compare dependency pgs in target */
5261 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
5262 	switch (scfe) {
5263 	case SCF_ERROR_NONE:
5264 		break;
5265 
5266 	case SCF_ERROR_NO_MEMORY:
5267 		return (ENOMEM);
5268 
5269 	case SCF_ERROR_NOT_FOUND:
5270 		warn(emsg_dpt_dangling, ient->sc_fmri,
5271 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5272 		return (0);
5273 
5274 	case SCF_ERROR_CONSTRAINT_VIOLATED:
5275 	case SCF_ERROR_INVALID_ARGUMENT:
5276 	default:
5277 		bad_error("fmri_to_entity", scfe);
5278 	}
5279 
5280 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
5281 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
5282 	switch (r) {
5283 	case 0:
5284 		break;
5285 
5286 	case ECONNABORTED:
5287 		return (r);
5288 
5289 	case ECANCELED:
5290 		warn(emsg_dpt_dangling, ient->sc_fmri,
5291 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
5292 		return (0);
5293 
5294 	case EBADF:
5295 		if (tissvc)
5296 			warn(gettext("%s has an instance with a \"%s\" "
5297 			    "snapshot which is missing a snaplevel.\n"),
5298 			    ud_ctarg, "running");
5299 		else
5300 			warn(gettext("%s has a \"%s\" snapshot which is "
5301 			    "missing a snaplevel.\n"), ud_ctarg, "running");
5302 		/* FALLTHROUGH */
5303 
5304 	case ENOENT:
5305 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5306 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5307 		    new_dpt_pgroup->sc_pgroup_name);
5308 		return (0);
5309 
5310 	case EINVAL:
5311 	default:
5312 		bad_error("entity_get_running_pg", r);
5313 	}
5314 
5315 	pgroup = internal_pgroup_new();
5316 	if (pgroup == NULL)
5317 		return (ENOMEM);
5318 
5319 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
5320 	switch (r) {
5321 	case 0:
5322 		break;
5323 
5324 	case ECONNABORTED:
5325 	case EBADF:
5326 	case ENOMEM:
5327 		internal_pgroup_free(pgroup);
5328 		return (r);
5329 
5330 	case ECANCELED:
5331 		warn(emsg_dpt_no_dep, ient->sc_fmri,
5332 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
5333 		    new_dpt_pgroup->sc_pgroup_name);
5334 		internal_pgroup_free(pgroup);
5335 		return (0);
5336 
5337 	case EACCES:
5338 	default:
5339 		bad_error("load_pg", r);
5340 	}
5341 
5342 	/* report differences */
5343 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
5344 	internal_pgroup_free(pgroup);
5345 	return (0);
5346 }
5347 
5348 /*
5349  * lipg is a property group in the last-import snapshot of ent, which is an
5350  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
5351  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
5352  * in ents's property groups, compare and upgrade ent appropriately.
5353  *
5354  * Returns
5355  *   0 - success
5356  *   ECONNABORTED - repository connection broken
5357  *   ENOMEM - out of memory
5358  *   ENOSPC - configd is out of resources
5359  *   EINVAL - ient has invalid dependent (error printed)
5360  *	    - ient has invalid pgroup_t (error printed)
5361  *   ECANCELED - ent has been deleted
5362  *   ENODEV - entity containing lipg has been deleted
5363  *	    - entity containing running has been deleted
5364  *   EPERM - could not delete pg (permission denied) (error printed)
5365  *	   - couldn't upgrade dependents (permission denied) (error printed)
5366  *	   - couldn't import pg (permission denied) (error printed)
5367  *	   - couldn't upgrade pg (permission denied) (error printed)
5368  *   EROFS - could not delete pg (repository read-only)
5369  *	   - couldn't upgrade dependents (repository read-only)
5370  *	   - couldn't import pg (repository read-only)
5371  *	   - couldn't upgrade pg (repository read-only)
5372  *   EACCES - could not delete pg (backend access denied)
5373  *	    - couldn't upgrade dependents (backend access denied)
5374  *	    - couldn't import pg (backend access denied)
5375  *	    - couldn't upgrade pg (backend access denied)
5376  *	    - couldn't read property (backend access denied)
5377  *   EBUSY - property group was added (error printed)
5378  *	   - property group was deleted (error printed)
5379  *	   - property group changed (error printed)
5380  *	   - "dependents" pg was added, changed, or deleted (error printed)
5381  *	   - dependent target deleted (error printed)
5382  *	   - dependent pg changed (error printed)
5383  *   EBADF - imp_snpl is corrupt (error printed)
5384  *	   - ent has bad pg (error printed)
5385  *   EEXIST - dependent collision in target service (error printed)
5386  */
5387 static int
5388 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
5389     const scf_snaplevel_t *running)
5390 {
5391 	int r;
5392 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
5393 	scf_callback_t cbdata;
5394 
5395 	const char * const cf_pg_missing =
5396 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
5397 	const char * const deleting =
5398 	    gettext("%s: Deleting property group \"%s\".\n");
5399 
5400 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5401 
5402 	/* Skip dependent property groups. */
5403 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
5404 		switch (scf_error()) {
5405 		case SCF_ERROR_DELETED:
5406 			return (ENODEV);
5407 
5408 		case SCF_ERROR_CONNECTION_BROKEN:
5409 			return (ECONNABORTED);
5410 
5411 		case SCF_ERROR_NOT_SET:
5412 		case SCF_ERROR_NOT_BOUND:
5413 		default:
5414 			bad_error("scf_pg_get_type", scf_error());
5415 		}
5416 	}
5417 
5418 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
5419 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
5420 			return (0);
5421 
5422 		switch (scf_error()) {
5423 		case SCF_ERROR_NOT_FOUND:
5424 			break;
5425 
5426 		case SCF_ERROR_CONNECTION_BROKEN:
5427 			return (ECONNABORTED);
5428 
5429 		case SCF_ERROR_DELETED:
5430 			return (ENODEV);
5431 
5432 		case SCF_ERROR_INVALID_ARGUMENT:
5433 		case SCF_ERROR_NOT_BOUND:
5434 		case SCF_ERROR_HANDLE_MISMATCH:
5435 		case SCF_ERROR_NOT_SET:
5436 		default:
5437 			bad_error("scf_pg_get_property", scf_error());
5438 		}
5439 	}
5440 
5441 	/* lookup pg in new properties */
5442 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
5443 		switch (scf_error()) {
5444 		case SCF_ERROR_DELETED:
5445 			return (ENODEV);
5446 
5447 		case SCF_ERROR_CONNECTION_BROKEN:
5448 			return (ECONNABORTED);
5449 
5450 		case SCF_ERROR_NOT_SET:
5451 		case SCF_ERROR_NOT_BOUND:
5452 		default:
5453 			bad_error("scf_pg_get_name", scf_error());
5454 		}
5455 	}
5456 
5457 	pgrp.sc_pgroup_name = imp_str;
5458 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
5459 
5460 	if (mpg != NULL)
5461 		mpg->sc_pgroup_seen = 1;
5462 
5463 	/* Special handling for dependents */
5464 	if (strcmp(imp_str, "dependents") == 0)
5465 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
5466 
5467 	if (strcmp(imp_str, SCF_PG_MANIFESTFILES) == 0)
5468 		return (upgrade_manifestfiles(NULL, ient, running, ent));
5469 
5470 	if (mpg == NULL || mpg->sc_pgroup_delete) {
5471 		/* property group was deleted from manifest */
5472 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5473 			switch (scf_error()) {
5474 			case SCF_ERROR_NOT_FOUND:
5475 				return (0);
5476 
5477 			case SCF_ERROR_DELETED:
5478 			case SCF_ERROR_CONNECTION_BROKEN:
5479 				return (scferror2errno(scf_error()));
5480 
5481 			case SCF_ERROR_INVALID_ARGUMENT:
5482 			case SCF_ERROR_HANDLE_MISMATCH:
5483 			case SCF_ERROR_NOT_BOUND:
5484 			case SCF_ERROR_NOT_SET:
5485 			default:
5486 				bad_error("entity_get_pg", scf_error());
5487 			}
5488 		}
5489 
5490 		if (mpg != NULL && mpg->sc_pgroup_delete) {
5491 			if (g_verbose)
5492 				warn(deleting, ient->sc_fmri, imp_str);
5493 			if (scf_pg_delete(imp_pg2) == 0)
5494 				return (0);
5495 
5496 			switch (scf_error()) {
5497 			case SCF_ERROR_DELETED:
5498 				return (0);
5499 
5500 			case SCF_ERROR_CONNECTION_BROKEN:
5501 			case SCF_ERROR_BACKEND_READONLY:
5502 			case SCF_ERROR_BACKEND_ACCESS:
5503 				return (scferror2errno(scf_error()));
5504 
5505 			case SCF_ERROR_PERMISSION_DENIED:
5506 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
5507 				return (scferror2errno(scf_error()));
5508 
5509 			case SCF_ERROR_NOT_SET:
5510 			default:
5511 				bad_error("scf_pg_delete", scf_error());
5512 			}
5513 		}
5514 
5515 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5516 		switch (r) {
5517 		case 0:
5518 			break;
5519 
5520 		case ECANCELED:
5521 			return (ENODEV);
5522 
5523 		case ECONNABORTED:
5524 		case ENOMEM:
5525 		case EBADF:
5526 		case EACCES:
5527 			return (r);
5528 
5529 		default:
5530 			bad_error("load_pg", r);
5531 		}
5532 
5533 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5534 		switch (r) {
5535 		case 0:
5536 			break;
5537 
5538 		case ECANCELED:
5539 		case ECONNABORTED:
5540 		case ENOMEM:
5541 		case EBADF:
5542 		case EACCES:
5543 			internal_pgroup_free(lipg_i);
5544 			return (r);
5545 
5546 		default:
5547 			bad_error("load_pg", r);
5548 		}
5549 
5550 		if (pg_equal(lipg_i, curpg_i)) {
5551 			if (g_verbose)
5552 				warn(deleting, ient->sc_fmri, imp_str);
5553 			if (scf_pg_delete(imp_pg2) != 0) {
5554 				switch (scf_error()) {
5555 				case SCF_ERROR_DELETED:
5556 					break;
5557 
5558 				case SCF_ERROR_CONNECTION_BROKEN:
5559 					internal_pgroup_free(lipg_i);
5560 					internal_pgroup_free(curpg_i);
5561 					return (ECONNABORTED);
5562 
5563 				case SCF_ERROR_NOT_SET:
5564 				case SCF_ERROR_NOT_BOUND:
5565 				default:
5566 					bad_error("scf_pg_delete", scf_error());
5567 				}
5568 			}
5569 		} else {
5570 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
5571 		}
5572 
5573 		internal_pgroup_free(lipg_i);
5574 		internal_pgroup_free(curpg_i);
5575 
5576 		return (0);
5577 	}
5578 
5579 	/*
5580 	 * Only dependent pgs can have override set, and we skipped those
5581 	 * above.
5582 	 */
5583 	assert(!mpg->sc_pgroup_override);
5584 
5585 	/* compare */
5586 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
5587 	switch (r) {
5588 	case 0:
5589 		break;
5590 
5591 	case ECANCELED:
5592 		return (ENODEV);
5593 
5594 	case ECONNABORTED:
5595 	case EBADF:
5596 	case ENOMEM:
5597 	case EACCES:
5598 		return (r);
5599 
5600 	default:
5601 		bad_error("load_pg", r);
5602 	}
5603 
5604 	if (pg_equal(mpg, lipg_i)) {
5605 		/* The manifest pg has not changed.  Move on. */
5606 		r = 0;
5607 		goto out;
5608 	}
5609 
5610 	/* upgrade current properties according to lipg & mpg */
5611 	if (running != NULL)
5612 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
5613 	else
5614 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
5615 	if (r != 0) {
5616 		switch (scf_error()) {
5617 		case SCF_ERROR_CONNECTION_BROKEN:
5618 			r = scferror2errno(scf_error());
5619 			goto out;
5620 
5621 		case SCF_ERROR_DELETED:
5622 			if (running != NULL)
5623 				r = ENODEV;
5624 			else
5625 				r = ECANCELED;
5626 			goto out;
5627 
5628 		case SCF_ERROR_NOT_FOUND:
5629 			break;
5630 
5631 		case SCF_ERROR_INVALID_ARGUMENT:
5632 		case SCF_ERROR_HANDLE_MISMATCH:
5633 		case SCF_ERROR_NOT_BOUND:
5634 		case SCF_ERROR_NOT_SET:
5635 		default:
5636 			bad_error("entity_get_pg", scf_error());
5637 		}
5638 
5639 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5640 
5641 		r = 0;
5642 		goto out;
5643 	}
5644 
5645 	r = load_pg_attrs(imp_pg2, &curpg_i);
5646 	switch (r) {
5647 	case 0:
5648 		break;
5649 
5650 	case ECANCELED:
5651 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5652 		r = 0;
5653 		goto out;
5654 
5655 	case ECONNABORTED:
5656 	case ENOMEM:
5657 		goto out;
5658 
5659 	default:
5660 		bad_error("load_pg_attrs", r);
5661 	}
5662 
5663 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
5664 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
5665 		internal_pgroup_free(curpg_i);
5666 		r = 0;
5667 		goto out;
5668 	}
5669 
5670 	internal_pgroup_free(curpg_i);
5671 
5672 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
5673 	switch (r) {
5674 	case 0:
5675 		break;
5676 
5677 	case ECANCELED:
5678 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
5679 		r = 0;
5680 		goto out;
5681 
5682 	case ECONNABORTED:
5683 	case EBADF:
5684 	case ENOMEM:
5685 	case EACCES:
5686 		goto out;
5687 
5688 	default:
5689 		bad_error("load_pg", r);
5690 	}
5691 
5692 	if (pg_equal(lipg_i, curpg_i) &&
5693 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
5694 		int do_delete = 1;
5695 
5696 		if (g_verbose)
5697 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
5698 			    ient->sc_fmri, mpg->sc_pgroup_name);
5699 
5700 		internal_pgroup_free(curpg_i);
5701 
5702 		if (running != NULL &&
5703 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5704 			switch (scf_error()) {
5705 			case SCF_ERROR_DELETED:
5706 				r = ECANCELED;
5707 				goto out;
5708 
5709 			case SCF_ERROR_NOT_FOUND:
5710 				do_delete = 0;
5711 				break;
5712 
5713 			case SCF_ERROR_CONNECTION_BROKEN:
5714 				r = scferror2errno(scf_error());
5715 				goto out;
5716 
5717 			case SCF_ERROR_HANDLE_MISMATCH:
5718 			case SCF_ERROR_INVALID_ARGUMENT:
5719 			case SCF_ERROR_NOT_SET:
5720 			case SCF_ERROR_NOT_BOUND:
5721 			default:
5722 				bad_error("entity_get_pg", scf_error());
5723 			}
5724 		}
5725 
5726 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
5727 			switch (scf_error()) {
5728 			case SCF_ERROR_DELETED:
5729 				break;
5730 
5731 			case SCF_ERROR_CONNECTION_BROKEN:
5732 			case SCF_ERROR_BACKEND_READONLY:
5733 			case SCF_ERROR_BACKEND_ACCESS:
5734 				r = scferror2errno(scf_error());
5735 				goto out;
5736 
5737 			case SCF_ERROR_PERMISSION_DENIED:
5738 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
5739 				    ient->sc_fmri);
5740 				r = scferror2errno(scf_error());
5741 				goto out;
5742 
5743 			case SCF_ERROR_NOT_SET:
5744 			case SCF_ERROR_NOT_BOUND:
5745 			default:
5746 				bad_error("scf_pg_delete", scf_error());
5747 			}
5748 		}
5749 
5750 		cbdata.sc_handle = g_hndl;
5751 		cbdata.sc_parent = ent;
5752 		cbdata.sc_service = issvc;
5753 		cbdata.sc_flags = 0;
5754 		cbdata.sc_source_fmri = ient->sc_fmri;
5755 		cbdata.sc_target_fmri = ient->sc_fmri;
5756 
5757 		r = entity_pgroup_import(mpg, &cbdata);
5758 		switch (r) {
5759 		case UU_WALK_NEXT:
5760 			r = 0;
5761 			goto out;
5762 
5763 		case UU_WALK_ERROR:
5764 			if (cbdata.sc_err == EEXIST) {
5765 				warn(emsg_pg_added, ient->sc_fmri,
5766 				    mpg->sc_pgroup_name);
5767 				r = EBUSY;
5768 			} else {
5769 				r = cbdata.sc_err;
5770 			}
5771 			goto out;
5772 
5773 		default:
5774 			bad_error("entity_pgroup_import", r);
5775 		}
5776 	}
5777 
5778 	if (running != NULL &&
5779 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
5780 		switch (scf_error()) {
5781 		case SCF_ERROR_CONNECTION_BROKEN:
5782 		case SCF_ERROR_DELETED:
5783 			r = scferror2errno(scf_error());
5784 			goto out;
5785 
5786 		case SCF_ERROR_NOT_FOUND:
5787 			break;
5788 
5789 		case SCF_ERROR_HANDLE_MISMATCH:
5790 		case SCF_ERROR_INVALID_ARGUMENT:
5791 		case SCF_ERROR_NOT_SET:
5792 		case SCF_ERROR_NOT_BOUND:
5793 		default:
5794 			bad_error("entity_get_pg", scf_error());
5795 		}
5796 
5797 		cbdata.sc_handle = g_hndl;
5798 		cbdata.sc_parent = ent;
5799 		cbdata.sc_service = issvc;
5800 		cbdata.sc_flags = SCI_FORCE;
5801 		cbdata.sc_source_fmri = ient->sc_fmri;
5802 		cbdata.sc_target_fmri = ient->sc_fmri;
5803 
5804 		r = entity_pgroup_import(mpg, &cbdata);
5805 		switch (r) {
5806 		case UU_WALK_NEXT:
5807 			r = 0;
5808 			goto out;
5809 
5810 		case UU_WALK_ERROR:
5811 			if (cbdata.sc_err == EEXIST) {
5812 				warn(emsg_pg_added, ient->sc_fmri,
5813 				    mpg->sc_pgroup_name);
5814 				r = EBUSY;
5815 			} else {
5816 				r = cbdata.sc_err;
5817 			}
5818 			goto out;
5819 
5820 		default:
5821 			bad_error("entity_pgroup_import", r);
5822 		}
5823 	}
5824 
5825 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5826 	internal_pgroup_free(curpg_i);
5827 	switch (r) {
5828 	case 0:
5829 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5830 		break;
5831 
5832 	case ECANCELED:
5833 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5834 		r = EBUSY;
5835 		break;
5836 
5837 	case EPERM:
5838 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5839 		break;
5840 
5841 	case EBUSY:
5842 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5843 		break;
5844 
5845 	case ECONNABORTED:
5846 	case ENOMEM:
5847 	case ENOSPC:
5848 	case EROFS:
5849 	case EACCES:
5850 	case EINVAL:
5851 		break;
5852 
5853 	default:
5854 		bad_error("upgrade_pg", r);
5855 	}
5856 
5857 out:
5858 	internal_pgroup_free(lipg_i);
5859 	return (r);
5860 }
5861 
5862 /*
5863  * Upgrade the properties of ent according to snpl & ient.
5864  *
5865  * Returns
5866  *   0 - success
5867  *   ECONNABORTED - repository connection broken
5868  *   ENOMEM - out of memory
5869  *   ENOSPC - configd is out of resources
5870  *   ECANCELED - ent was deleted
5871  *   ENODEV - entity containing snpl was deleted
5872  *	    - entity containing running was deleted
5873  *   EBADF - imp_snpl is corrupt (error printed)
5874  *	   - ent has corrupt pg (error printed)
5875  *	   - dependent has corrupt pg (error printed)
5876  *	   - dependent target has a corrupt snapshot (error printed)
5877  *   EBUSY - pg was added, changed, or deleted (error printed)
5878  *	   - dependent target was deleted (error printed)
5879  *	   - dependent pg changed (error printed)
5880  *   EINVAL - invalid property group name (error printed)
5881  *	    - invalid property name (error printed)
5882  *	    - invalid value (error printed)
5883  *	    - ient has invalid pgroup or dependent (error printed)
5884  *   EPERM - could not create property group (permission denied) (error printed)
5885  *	   - could not modify property group (permission denied) (error printed)
5886  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5887  *   EROFS - could not create property group (repository read-only)
5888  *	   - couldn't delete, upgrade, or import pg or dependent
5889  *   EACCES - could not create property group (backend access denied)
5890  *	    - couldn't delete, upgrade, or import pg or dependent
5891  *   EEXIST - dependent collision in target service (error printed)
5892  */
5893 static int
5894 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5895     entity_t *ient)
5896 {
5897 	pgroup_t *pg, *rpg;
5898 	int r;
5899 	uu_list_t *pgs = ient->sc_pgroups;
5900 
5901 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5902 
5903 	/* clear sc_sceen for pgs */
5904 	if (uu_list_walk(pgs, clear_int,
5905 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5906 		bad_error("uu_list_walk", uu_error());
5907 
5908 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5909 		switch (scf_error()) {
5910 		case SCF_ERROR_DELETED:
5911 			return (ENODEV);
5912 
5913 		case SCF_ERROR_CONNECTION_BROKEN:
5914 			return (ECONNABORTED);
5915 
5916 		case SCF_ERROR_NOT_SET:
5917 		case SCF_ERROR_NOT_BOUND:
5918 		case SCF_ERROR_HANDLE_MISMATCH:
5919 		default:
5920 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5921 		}
5922 	}
5923 
5924 	for (;;) {
5925 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5926 		if (r == 0)
5927 			break;
5928 		if (r == 1) {
5929 			r = process_old_pg(imp_pg, ient, ent, running);
5930 			switch (r) {
5931 			case 0:
5932 				break;
5933 
5934 			case ECONNABORTED:
5935 			case ENOMEM:
5936 			case ENOSPC:
5937 			case ECANCELED:
5938 			case ENODEV:
5939 			case EPERM:
5940 			case EROFS:
5941 			case EACCES:
5942 			case EBADF:
5943 			case EBUSY:
5944 			case EINVAL:
5945 			case EEXIST:
5946 				return (r);
5947 
5948 			default:
5949 				bad_error("process_old_pg", r);
5950 			}
5951 			continue;
5952 		}
5953 		if (r != -1)
5954 			bad_error("scf_iter_next_pg", r);
5955 
5956 		switch (scf_error()) {
5957 		case SCF_ERROR_DELETED:
5958 			return (ENODEV);
5959 
5960 		case SCF_ERROR_CONNECTION_BROKEN:
5961 			return (ECONNABORTED);
5962 
5963 		case SCF_ERROR_HANDLE_MISMATCH:
5964 		case SCF_ERROR_NOT_BOUND:
5965 		case SCF_ERROR_NOT_SET:
5966 		case SCF_ERROR_INVALID_ARGUMENT:
5967 		default:
5968 			bad_error("scf_iter_next_pg", scf_error());
5969 		}
5970 	}
5971 
5972 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5973 		if (pg->sc_pgroup_seen)
5974 			continue;
5975 
5976 		/* pg is new */
5977 
5978 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5979 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5980 			    ent);
5981 			switch (r) {
5982 			case 0:
5983 				break;
5984 
5985 			case ECONNABORTED:
5986 			case ENOMEM:
5987 			case ENOSPC:
5988 			case ECANCELED:
5989 			case ENODEV:
5990 			case EBADF:
5991 			case EBUSY:
5992 			case EINVAL:
5993 			case EPERM:
5994 			case EROFS:
5995 			case EACCES:
5996 			case EEXIST:
5997 				return (r);
5998 
5999 			default:
6000 				bad_error("upgrade_dependents", r);
6001 			}
6002 			continue;
6003 		}
6004 
6005 		if (strcmp(pg->sc_pgroup_name, SCF_PG_MANIFESTFILES) == 0) {
6006 			r = upgrade_manifestfiles(pg, ient, running, ent);
6007 			switch (r) {
6008 			case 0:
6009 				break;
6010 
6011 			case ECONNABORTED:
6012 			case ENOMEM:
6013 			case ENOSPC:
6014 			case ECANCELED:
6015 			case ENODEV:
6016 			case EBADF:
6017 			case EBUSY:
6018 			case EINVAL:
6019 			case EPERM:
6020 			case EROFS:
6021 			case EACCES:
6022 			case EEXIST:
6023 				return (r);
6024 
6025 			default:
6026 				bad_error("upgrade_manifestfiles", r);
6027 			}
6028 			continue;
6029 		}
6030 
6031 		if (running != NULL) {
6032 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
6033 			    imp_pg);
6034 		} else {
6035 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
6036 			    imp_pg);
6037 		}
6038 		if (r != 0) {
6039 			scf_callback_t cbdata;
6040 
6041 			switch (scf_error()) {
6042 			case SCF_ERROR_NOT_FOUND:
6043 				break;
6044 
6045 			case SCF_ERROR_CONNECTION_BROKEN:
6046 				return (scferror2errno(scf_error()));
6047 
6048 			case SCF_ERROR_DELETED:
6049 				if (running != NULL)
6050 					return (ENODEV);
6051 				else
6052 					return (scferror2errno(scf_error()));
6053 
6054 			case SCF_ERROR_INVALID_ARGUMENT:
6055 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
6056 				    pg->sc_pgroup_name);
6057 				return (EINVAL);
6058 
6059 			case SCF_ERROR_NOT_SET:
6060 			case SCF_ERROR_HANDLE_MISMATCH:
6061 			case SCF_ERROR_NOT_BOUND:
6062 			default:
6063 				bad_error("entity_get_pg", scf_error());
6064 			}
6065 
6066 			/* User doesn't have pg, so import it. */
6067 
6068 			cbdata.sc_handle = g_hndl;
6069 			cbdata.sc_parent = ent;
6070 			cbdata.sc_service = issvc;
6071 			cbdata.sc_flags = SCI_FORCE;
6072 			cbdata.sc_source_fmri = ient->sc_fmri;
6073 			cbdata.sc_target_fmri = ient->sc_fmri;
6074 
6075 			r = entity_pgroup_import(pg, &cbdata);
6076 			switch (r) {
6077 			case UU_WALK_NEXT:
6078 				ient->sc_import_state = IMPORT_PROP_BEGUN;
6079 				continue;
6080 
6081 			case UU_WALK_ERROR:
6082 				if (cbdata.sc_err == EEXIST) {
6083 					warn(emsg_pg_added, ient->sc_fmri,
6084 					    pg->sc_pgroup_name);
6085 					return (EBUSY);
6086 				}
6087 				return (cbdata.sc_err);
6088 
6089 			default:
6090 				bad_error("entity_pgroup_import", r);
6091 			}
6092 		}
6093 
6094 		/* report differences between pg & current */
6095 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
6096 		switch (r) {
6097 		case 0:
6098 			break;
6099 
6100 		case ECANCELED:
6101 			warn(emsg_pg_deleted, ient->sc_fmri,
6102 			    pg->sc_pgroup_name);
6103 			return (EBUSY);
6104 
6105 		case ECONNABORTED:
6106 		case EBADF:
6107 		case ENOMEM:
6108 		case EACCES:
6109 			return (r);
6110 
6111 		default:
6112 			bad_error("load_pg", r);
6113 		}
6114 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
6115 		internal_pgroup_free(rpg);
6116 		rpg = NULL;
6117 	}
6118 
6119 	return (0);
6120 }
6121 
6122 /*
6123  * Import an instance.  If it doesn't exist, create it.  If it has
6124  * a last-import snapshot, upgrade its properties.  Finish by updating its
6125  * last-import snapshot.  If it doesn't have a last-import snapshot then it
6126  * could have been created for a dependent tag in another manifest.  Import the
6127  * new properties.  If there's a conflict, don't override, like now?
6128  *
6129  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
6130  * lcbdata->sc_err to
6131  *   ECONNABORTED - repository connection broken
6132  *   ENOMEM - out of memory
6133  *   ENOSPC - svc.configd is out of resources
6134  *   EEXIST - dependency collision in dependent service (error printed)
6135  *   EPERM - couldn't create temporary instance (permission denied)
6136  *	   - couldn't import into temporary instance (permission denied)
6137  *	   - couldn't take snapshot (permission denied)
6138  *	   - couldn't upgrade properties (permission denied)
6139  *	   - couldn't import properties (permission denied)
6140  *	   - couldn't import dependents (permission denied)
6141  *   EROFS - couldn't create temporary instance (repository read-only)
6142  *	   - couldn't import into temporary instance (repository read-only)
6143  *	   - couldn't upgrade properties (repository read-only)
6144  *	   - couldn't import properties (repository read-only)
6145  *	   - couldn't import dependents (repository read-only)
6146  *   EACCES - couldn't create temporary instance (backend access denied)
6147  *	    - couldn't import into temporary instance (backend access denied)
6148  *	    - couldn't upgrade properties (backend access denied)
6149  *	    - couldn't import properties (backend access denied)
6150  *	    - couldn't import dependents (backend access denied)
6151  *   EINVAL - invalid instance name (error printed)
6152  *	    - invalid pgroup_t's (error printed)
6153  *	    - invalid dependents (error printed)
6154  *   EBUSY - temporary service deleted (error printed)
6155  *	   - temporary instance deleted (error printed)
6156  *	   - temporary instance changed (error printed)
6157  *	   - temporary instance already exists (error printed)
6158  *	   - instance deleted (error printed)
6159  *   EBADF - instance has corrupt last-import snapshot (error printed)
6160  *	   - instance is corrupt (error printed)
6161  *	   - dependent has corrupt pg (error printed)
6162  *	   - dependent target has a corrupt snapshot (error printed)
6163  *   -1 - unknown libscf error (error printed)
6164  */
6165 static int
6166 lscf_instance_import(void *v, void *pvt)
6167 {
6168 	entity_t *inst = v;
6169 	scf_callback_t ctx;
6170 	scf_callback_t *lcbdata = pvt;
6171 	scf_service_t *rsvc = lcbdata->sc_parent;
6172 	int r;
6173 	scf_snaplevel_t *running;
6174 	int flags = lcbdata->sc_flags;
6175 
6176 	const char * const emsg_tdel =
6177 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
6178 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
6179 	    "changed unexpectedly.\n");
6180 	const char * const emsg_del = gettext("%s changed unexpectedly "
6181 	    "(instance \"%s\" was deleted.)\n");
6182 	const char * const emsg_badsnap = gettext(
6183 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
6184 
6185 	/*
6186 	 * prepare last-import snapshot:
6187 	 * create temporary instance (service was precreated)
6188 	 * populate with properties from bundle
6189 	 * take snapshot
6190 	 */
6191 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
6192 		switch (scf_error()) {
6193 		case SCF_ERROR_CONNECTION_BROKEN:
6194 		case SCF_ERROR_NO_RESOURCES:
6195 		case SCF_ERROR_BACKEND_READONLY:
6196 		case SCF_ERROR_BACKEND_ACCESS:
6197 			return (stash_scferror(lcbdata));
6198 
6199 		case SCF_ERROR_EXISTS:
6200 			warn(gettext("Temporary service svc:/%s "
6201 			    "changed unexpectedly (instance \"%s\" added).\n"),
6202 			    imp_tsname, inst->sc_name);
6203 			lcbdata->sc_err = EBUSY;
6204 			return (UU_WALK_ERROR);
6205 
6206 		case SCF_ERROR_DELETED:
6207 			warn(gettext("Temporary service svc:/%s "
6208 			    "was deleted unexpectedly.\n"), imp_tsname);
6209 			lcbdata->sc_err = EBUSY;
6210 			return (UU_WALK_ERROR);
6211 
6212 		case SCF_ERROR_INVALID_ARGUMENT:
6213 			warn(gettext("Invalid instance name \"%s\".\n"),
6214 			    inst->sc_name);
6215 			return (stash_scferror(lcbdata));
6216 
6217 		case SCF_ERROR_PERMISSION_DENIED:
6218 			warn(gettext("Could not create temporary instance "
6219 			    "\"%s\" in svc:/%s (permission denied).\n"),
6220 			    inst->sc_name, imp_tsname);
6221 			return (stash_scferror(lcbdata));
6222 
6223 		case SCF_ERROR_HANDLE_MISMATCH:
6224 		case SCF_ERROR_NOT_BOUND:
6225 		case SCF_ERROR_NOT_SET:
6226 		default:
6227 			bad_error("scf_service_add_instance", scf_error());
6228 		}
6229 	}
6230 
6231 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6232 	    inst->sc_name);
6233 	if (r < 0)
6234 		bad_error("snprintf", errno);
6235 
6236 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
6237 	    lcbdata->sc_flags | SCI_NOENABLED);
6238 	switch (r) {
6239 	case 0:
6240 		break;
6241 
6242 	case ECANCELED:
6243 		warn(emsg_tdel, imp_tsname, inst->sc_name);
6244 		lcbdata->sc_err = EBUSY;
6245 		r = UU_WALK_ERROR;
6246 		goto deltemp;
6247 
6248 	case EEXIST:
6249 		warn(emsg_tchg, imp_tsname, inst->sc_name);
6250 		lcbdata->sc_err = EBUSY;
6251 		r = UU_WALK_ERROR;
6252 		goto deltemp;
6253 
6254 	case ECONNABORTED:
6255 		goto connaborted;
6256 
6257 	case ENOMEM:
6258 	case ENOSPC:
6259 	case EPERM:
6260 	case EROFS:
6261 	case EACCES:
6262 	case EINVAL:
6263 	case EBUSY:
6264 		lcbdata->sc_err = r;
6265 		r = UU_WALK_ERROR;
6266 		goto deltemp;
6267 
6268 	default:
6269 		bad_error("lscf_import_instance_pgs", r);
6270 	}
6271 
6272 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
6273 	    inst->sc_name);
6274 	if (r < 0)
6275 		bad_error("snprintf", errno);
6276 
6277 	ctx.sc_handle = lcbdata->sc_handle;
6278 	ctx.sc_parent = imp_tinst;
6279 	ctx.sc_service = 0;
6280 	ctx.sc_source_fmri = inst->sc_fmri;
6281 	ctx.sc_target_fmri = imp_str;
6282 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
6283 	    UU_DEFAULT) != 0) {
6284 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6285 			bad_error("uu_list_walk", uu_error());
6286 
6287 		switch (ctx.sc_err) {
6288 		case ECONNABORTED:
6289 			goto connaborted;
6290 
6291 		case ECANCELED:
6292 			warn(emsg_tdel, imp_tsname, inst->sc_name);
6293 			lcbdata->sc_err = EBUSY;
6294 			break;
6295 
6296 		case EEXIST:
6297 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6298 			lcbdata->sc_err = EBUSY;
6299 			break;
6300 
6301 		default:
6302 			lcbdata->sc_err = ctx.sc_err;
6303 		}
6304 		r = UU_WALK_ERROR;
6305 		goto deltemp;
6306 	}
6307 
6308 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
6309 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
6310 		switch (scf_error()) {
6311 		case SCF_ERROR_CONNECTION_BROKEN:
6312 			goto connaborted;
6313 
6314 		case SCF_ERROR_NO_RESOURCES:
6315 			r = stash_scferror(lcbdata);
6316 			goto deltemp;
6317 
6318 		case SCF_ERROR_EXISTS:
6319 			warn(emsg_tchg, imp_tsname, inst->sc_name);
6320 			lcbdata->sc_err = EBUSY;
6321 			r = UU_WALK_ERROR;
6322 			goto deltemp;
6323 
6324 		case SCF_ERROR_PERMISSION_DENIED:
6325 			warn(gettext("Could not take \"%s\" snapshot of %s "
6326 			    "(permission denied).\n"), snap_lastimport,
6327 			    imp_str);
6328 			r = stash_scferror(lcbdata);
6329 			goto deltemp;
6330 
6331 		default:
6332 			scfwarn();
6333 			lcbdata->sc_err = -1;
6334 			r = UU_WALK_ERROR;
6335 			goto deltemp;
6336 
6337 		case SCF_ERROR_HANDLE_MISMATCH:
6338 		case SCF_ERROR_INVALID_ARGUMENT:
6339 		case SCF_ERROR_NOT_SET:
6340 			bad_error("_scf_snapshot_take_new_named", scf_error());
6341 		}
6342 	}
6343 
6344 	if (lcbdata->sc_flags & SCI_FRESH)
6345 		goto fresh;
6346 
6347 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
6348 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6349 		    imp_lisnap) != 0) {
6350 			switch (scf_error()) {
6351 			case SCF_ERROR_DELETED:
6352 				warn(emsg_del, inst->sc_parent->sc_fmri,
6353 				    inst->sc_name);
6354 				lcbdata->sc_err = EBUSY;
6355 				r = UU_WALK_ERROR;
6356 				goto deltemp;
6357 
6358 			case SCF_ERROR_NOT_FOUND:
6359 				flags |= SCI_FORCE;
6360 				goto nosnap;
6361 
6362 			case SCF_ERROR_CONNECTION_BROKEN:
6363 				goto connaborted;
6364 
6365 			case SCF_ERROR_INVALID_ARGUMENT:
6366 			case SCF_ERROR_HANDLE_MISMATCH:
6367 			case SCF_ERROR_NOT_BOUND:
6368 			case SCF_ERROR_NOT_SET:
6369 			default:
6370 				bad_error("scf_instance_get_snapshot",
6371 				    scf_error());
6372 			}
6373 		}
6374 
6375 		/* upgrade */
6376 
6377 		/*
6378 		 * compare new properties with last-import properties
6379 		 * upgrade current properties
6380 		 */
6381 		/* clear sc_sceen for pgs */
6382 		if (uu_list_walk(inst->sc_pgroups, clear_int,
6383 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
6384 		    0)
6385 			bad_error("uu_list_walk", uu_error());
6386 
6387 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
6388 		switch (r) {
6389 		case 0:
6390 			break;
6391 
6392 		case ECONNABORTED:
6393 			goto connaborted;
6394 
6395 		case ECANCELED:
6396 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6397 			lcbdata->sc_err = EBUSY;
6398 			r = UU_WALK_ERROR;
6399 			goto deltemp;
6400 
6401 		case ENOENT:
6402 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
6403 			lcbdata->sc_err = EBADF;
6404 			r = UU_WALK_ERROR;
6405 			goto deltemp;
6406 
6407 		default:
6408 			bad_error("get_snaplevel", r);
6409 		}
6410 
6411 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6412 		    imp_rsnap) != 0) {
6413 			switch (scf_error()) {
6414 			case SCF_ERROR_DELETED:
6415 				warn(emsg_del, inst->sc_parent->sc_fmri,
6416 				    inst->sc_name);
6417 				lcbdata->sc_err = EBUSY;
6418 				r = UU_WALK_ERROR;
6419 				goto deltemp;
6420 
6421 			case SCF_ERROR_NOT_FOUND:
6422 				break;
6423 
6424 			case SCF_ERROR_CONNECTION_BROKEN:
6425 				goto connaborted;
6426 
6427 			case SCF_ERROR_INVALID_ARGUMENT:
6428 			case SCF_ERROR_HANDLE_MISMATCH:
6429 			case SCF_ERROR_NOT_BOUND:
6430 			case SCF_ERROR_NOT_SET:
6431 			default:
6432 				bad_error("scf_instance_get_snapshot",
6433 				    scf_error());
6434 			}
6435 
6436 			running = NULL;
6437 		} else {
6438 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
6439 			switch (r) {
6440 			case 0:
6441 				running = imp_rsnpl;
6442 				break;
6443 
6444 			case ECONNABORTED:
6445 				goto connaborted;
6446 
6447 			case ECANCELED:
6448 				warn(emsg_del, inst->sc_parent->sc_fmri,
6449 				    inst->sc_name);
6450 				lcbdata->sc_err = EBUSY;
6451 				r = UU_WALK_ERROR;
6452 				goto deltemp;
6453 
6454 			case ENOENT:
6455 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
6456 				lcbdata->sc_err = EBADF;
6457 				r = UU_WALK_ERROR;
6458 				goto deltemp;
6459 
6460 			default:
6461 				bad_error("get_snaplevel", r);
6462 			}
6463 		}
6464 
6465 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
6466 		switch (r) {
6467 		case 0:
6468 			break;
6469 
6470 		case ECANCELED:
6471 		case ENODEV:
6472 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
6473 			lcbdata->sc_err = EBUSY;
6474 			r = UU_WALK_ERROR;
6475 			goto deltemp;
6476 
6477 		case ECONNABORTED:
6478 			goto connaborted;
6479 
6480 		case ENOMEM:
6481 		case ENOSPC:
6482 		case EBADF:
6483 		case EBUSY:
6484 		case EINVAL:
6485 		case EPERM:
6486 		case EROFS:
6487 		case EACCES:
6488 		case EEXIST:
6489 			lcbdata->sc_err = r;
6490 			r = UU_WALK_ERROR;
6491 			goto deltemp;
6492 
6493 		default:
6494 			bad_error("upgrade_props", r);
6495 		}
6496 
6497 		inst->sc_import_state = IMPORT_PROP_DONE;
6498 	} else {
6499 		switch (scf_error()) {
6500 		case SCF_ERROR_CONNECTION_BROKEN:
6501 			goto connaborted;
6502 
6503 		case SCF_ERROR_NOT_FOUND:
6504 			break;
6505 
6506 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
6507 		case SCF_ERROR_HANDLE_MISMATCH:
6508 		case SCF_ERROR_NOT_BOUND:
6509 		case SCF_ERROR_NOT_SET:
6510 		default:
6511 			bad_error("scf_service_get_instance", scf_error());
6512 		}
6513 
6514 fresh:
6515 		/* create instance */
6516 		if (scf_service_add_instance(rsvc, inst->sc_name,
6517 		    imp_inst) != 0) {
6518 			switch (scf_error()) {
6519 			case SCF_ERROR_CONNECTION_BROKEN:
6520 				goto connaborted;
6521 
6522 			case SCF_ERROR_NO_RESOURCES:
6523 			case SCF_ERROR_BACKEND_READONLY:
6524 			case SCF_ERROR_BACKEND_ACCESS:
6525 				r = stash_scferror(lcbdata);
6526 				goto deltemp;
6527 
6528 			case SCF_ERROR_EXISTS:
6529 				warn(gettext("%s changed unexpectedly "
6530 				    "(instance \"%s\" added).\n"),
6531 				    inst->sc_parent->sc_fmri, inst->sc_name);
6532 				lcbdata->sc_err = EBUSY;
6533 				r = UU_WALK_ERROR;
6534 				goto deltemp;
6535 
6536 			case SCF_ERROR_PERMISSION_DENIED:
6537 				warn(gettext("Could not create \"%s\" instance "
6538 				    "in %s (permission denied).\n"),
6539 				    inst->sc_name, inst->sc_parent->sc_fmri);
6540 				r = stash_scferror(lcbdata);
6541 				goto deltemp;
6542 
6543 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
6544 			case SCF_ERROR_HANDLE_MISMATCH:
6545 			case SCF_ERROR_NOT_BOUND:
6546 			case SCF_ERROR_NOT_SET:
6547 			default:
6548 				bad_error("scf_service_add_instance",
6549 				    scf_error());
6550 			}
6551 		}
6552 
6553 nosnap:
6554 		/*
6555 		 * Create a last-import snapshot to serve as an attachment
6556 		 * point for the real one from the temporary instance.  Since
6557 		 * the contents is irrelevant, take it now, while the instance
6558 		 * is empty, to minimize svc.configd's work.
6559 		 */
6560 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
6561 		    imp_lisnap) != 0) {
6562 			switch (scf_error()) {
6563 			case SCF_ERROR_CONNECTION_BROKEN:
6564 				goto connaborted;
6565 
6566 			case SCF_ERROR_NO_RESOURCES:
6567 				r = stash_scferror(lcbdata);
6568 				goto deltemp;
6569 
6570 			case SCF_ERROR_EXISTS:
6571 				warn(gettext("%s changed unexpectedly "
6572 				    "(snapshot \"%s\" added).\n"),
6573 				    inst->sc_fmri, snap_lastimport);
6574 				lcbdata->sc_err = EBUSY;
6575 				r = UU_WALK_ERROR;
6576 				goto deltemp;
6577 
6578 			case SCF_ERROR_PERMISSION_DENIED:
6579 				warn(gettext("Could not take \"%s\" snapshot "
6580 				    "of %s (permission denied).\n"),
6581 				    snap_lastimport, inst->sc_fmri);
6582 				r = stash_scferror(lcbdata);
6583 				goto deltemp;
6584 
6585 			default:
6586 				scfwarn();
6587 				lcbdata->sc_err = -1;
6588 				r = UU_WALK_ERROR;
6589 				goto deltemp;
6590 
6591 			case SCF_ERROR_NOT_SET:
6592 			case SCF_ERROR_INTERNAL:
6593 			case SCF_ERROR_INVALID_ARGUMENT:
6594 			case SCF_ERROR_HANDLE_MISMATCH:
6595 				bad_error("_scf_snapshot_take_new",
6596 				    scf_error());
6597 			}
6598 		}
6599 
6600 		if (li_only)
6601 			goto lionly;
6602 
6603 		inst->sc_import_state = IMPORT_PROP_BEGUN;
6604 
6605 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
6606 		    flags);
6607 		switch (r) {
6608 		case 0:
6609 			break;
6610 
6611 		case ECONNABORTED:
6612 			goto connaborted;
6613 
6614 		case ECANCELED:
6615 			warn(gettext("%s changed unexpectedly "
6616 			    "(instance \"%s\" deleted).\n"),
6617 			    inst->sc_parent->sc_fmri, inst->sc_name);
6618 			lcbdata->sc_err = EBUSY;
6619 			r = UU_WALK_ERROR;
6620 			goto deltemp;
6621 
6622 		case EEXIST:
6623 			warn(gettext("%s changed unexpectedly "
6624 			    "(property group added).\n"), inst->sc_fmri);
6625 			lcbdata->sc_err = EBUSY;
6626 			r = UU_WALK_ERROR;
6627 			goto deltemp;
6628 
6629 		default:
6630 			lcbdata->sc_err = r;
6631 			r = UU_WALK_ERROR;
6632 			goto deltemp;
6633 
6634 		case EINVAL:	/* caught above */
6635 			bad_error("lscf_import_instance_pgs", r);
6636 		}
6637 
6638 		ctx.sc_parent = imp_inst;
6639 		ctx.sc_service = 0;
6640 		ctx.sc_trans = NULL;
6641 		ctx.sc_flags = 0;
6642 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
6643 		    &ctx, UU_DEFAULT) != 0) {
6644 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6645 				bad_error("uu_list_walk", uu_error());
6646 
6647 			if (ctx.sc_err == ECONNABORTED)
6648 				goto connaborted;
6649 			lcbdata->sc_err = ctx.sc_err;
6650 			r = UU_WALK_ERROR;
6651 			goto deltemp;
6652 		}
6653 
6654 		inst->sc_import_state = IMPORT_PROP_DONE;
6655 
6656 		if (g_verbose)
6657 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6658 			    snap_initial, inst->sc_fmri);
6659 		r = take_snap(imp_inst, snap_initial, imp_snap);
6660 		switch (r) {
6661 		case 0:
6662 			break;
6663 
6664 		case ECONNABORTED:
6665 			goto connaborted;
6666 
6667 		case ENOSPC:
6668 		case -1:
6669 			lcbdata->sc_err = r;
6670 			r = UU_WALK_ERROR;
6671 			goto deltemp;
6672 
6673 		case ECANCELED:
6674 			warn(gettext("%s changed unexpectedly "
6675 			    "(instance %s deleted).\n"),
6676 			    inst->sc_parent->sc_fmri, inst->sc_name);
6677 			lcbdata->sc_err = r;
6678 			r = UU_WALK_ERROR;
6679 			goto deltemp;
6680 
6681 		case EPERM:
6682 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
6683 			lcbdata->sc_err = r;
6684 			r = UU_WALK_ERROR;
6685 			goto deltemp;
6686 
6687 		default:
6688 			bad_error("take_snap", r);
6689 		}
6690 	}
6691 
6692 lionly:
6693 	if (lcbdata->sc_flags & SCI_NOSNAP)
6694 		goto deltemp;
6695 
6696 	/* transfer snapshot from temporary instance */
6697 	if (g_verbose)
6698 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
6699 		    snap_lastimport, inst->sc_fmri);
6700 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
6701 		switch (scf_error()) {
6702 		case SCF_ERROR_CONNECTION_BROKEN:
6703 			goto connaborted;
6704 
6705 		case SCF_ERROR_NO_RESOURCES:
6706 			r = stash_scferror(lcbdata);
6707 			goto deltemp;
6708 
6709 		case SCF_ERROR_PERMISSION_DENIED:
6710 			warn(gettext("Could not take \"%s\" snapshot for %s "
6711 			    "(permission denied).\n"), snap_lastimport,
6712 			    inst->sc_fmri);
6713 			r = stash_scferror(lcbdata);
6714 			goto deltemp;
6715 
6716 		case SCF_ERROR_NOT_SET:
6717 		case SCF_ERROR_HANDLE_MISMATCH:
6718 		default:
6719 			bad_error("_scf_snapshot_attach", scf_error());
6720 		}
6721 	}
6722 
6723 	inst->sc_import_state = IMPORT_COMPLETE;
6724 
6725 	r = UU_WALK_NEXT;
6726 
6727 deltemp:
6728 	/* delete temporary instance */
6729 	if (scf_instance_delete(imp_tinst) != 0) {
6730 		switch (scf_error()) {
6731 		case SCF_ERROR_DELETED:
6732 			break;
6733 
6734 		case SCF_ERROR_CONNECTION_BROKEN:
6735 			goto connaborted;
6736 
6737 		case SCF_ERROR_NOT_SET:
6738 		case SCF_ERROR_NOT_BOUND:
6739 		default:
6740 			bad_error("scf_instance_delete", scf_error());
6741 		}
6742 	}
6743 
6744 	return (r);
6745 
6746 connaborted:
6747 	warn(gettext("Could not delete svc:/%s:%s "
6748 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
6749 	lcbdata->sc_err = ECONNABORTED;
6750 	return (UU_WALK_ERROR);
6751 }
6752 
6753 /*
6754  * If the service is missing, create it, import its properties, and import the
6755  * instances.  Since the service is brand new, it should be empty, and if we
6756  * run into any existing entities (SCF_ERROR_EXISTS), abort.
6757  *
6758  * If the service exists, we want to upgrade its properties and import the
6759  * instances.  Upgrade requires a last-import snapshot, though, which are
6760  * children of instances, so first we'll have to go through the instances
6761  * looking for a last-import snapshot.  If we don't find one then we'll just
6762  * override-import the service properties (but don't delete existing
6763  * properties: another service might have declared us as a dependent).  Before
6764  * we change anything, though, we want to take the previous snapshots.  We
6765  * also give lscf_instance_import() a leg up on taking last-import snapshots
6766  * by importing the manifest's service properties into a temporary service.
6767  *
6768  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
6769  * sets lcbdata->sc_err to
6770  *   ECONNABORTED - repository connection broken
6771  *   ENOMEM - out of memory
6772  *   ENOSPC - svc.configd is out of resources
6773  *   EPERM - couldn't create temporary service (error printed)
6774  *	   - couldn't import into temp service (error printed)
6775  *	   - couldn't create service (error printed)
6776  *	   - couldn't import dependent (error printed)
6777  *	   - couldn't take snapshot (error printed)
6778  *	   - couldn't create instance (error printed)
6779  *	   - couldn't create, modify, or delete pg (error printed)
6780  *	   - couldn't create, modify, or delete dependent (error printed)
6781  *	   - couldn't import instance (error printed)
6782  *   EROFS - couldn't create temporary service (repository read-only)
6783  *	   - couldn't import into temporary service (repository read-only)
6784  *	   - couldn't create service (repository read-only)
6785  *	   - couldn't import dependent (repository read-only)
6786  *	   - couldn't create instance (repository read-only)
6787  *	   - couldn't create, modify, or delete pg or dependent
6788  *	   - couldn't import instance (repository read-only)
6789  *   EACCES - couldn't create temporary service (backend access denied)
6790  *	    - couldn't import into temporary service (backend access denied)
6791  *	    - couldn't create service (backend access denied)
6792  *	    - couldn't import dependent (backend access denied)
6793  *	    - couldn't create instance (backend access denied)
6794  *	    - couldn't create, modify, or delete pg or dependent
6795  *	    - couldn't import instance (backend access denied)
6796  *   EINVAL - service name is invalid (error printed)
6797  *	    - service name is too long (error printed)
6798  *	    - s has invalid pgroup (error printed)
6799  *	    - s has invalid dependent (error printed)
6800  *	    - instance name is invalid (error printed)
6801  *	    - instance entity_t is invalid (error printed)
6802  *   EEXIST - couldn't create temporary service (already exists) (error printed)
6803  *	    - couldn't import dependent (dependency pg already exists) (printed)
6804  *	    - dependency collision in dependent service (error printed)
6805  *   EBUSY - temporary service deleted (error printed)
6806  *	   - property group added to temporary service (error printed)
6807  *	   - new property group changed or was deleted (error printed)
6808  *	   - service was added unexpectedly (error printed)
6809  *	   - service was deleted unexpectedly (error printed)
6810  *	   - property group added to new service (error printed)
6811  *	   - instance added unexpectedly (error printed)
6812  *	   - instance deleted unexpectedly (error printed)
6813  *	   - dependent service deleted unexpectedly (error printed)
6814  *	   - pg was added, changed, or deleted (error printed)
6815  *	   - dependent pg changed (error printed)
6816  *	   - temporary instance added, changed, or deleted (error printed)
6817  *   EBADF - a last-import snapshot is corrupt (error printed)
6818  *	   - the service is corrupt (error printed)
6819  *	   - a dependent is corrupt (error printed)
6820  *	   - an instance is corrupt (error printed)
6821  *	   - an instance has a corrupt last-import snapshot (error printed)
6822  *	   - dependent target has a corrupt snapshot (error printed)
6823  *   -1 - unknown libscf error (error printed)
6824  */
6825 static int
6826 lscf_service_import(void *v, void *pvt)
6827 {
6828 	entity_t *s = v;
6829 	scf_callback_t cbdata;
6830 	scf_callback_t *lcbdata = pvt;
6831 	scf_scope_t *scope = lcbdata->sc_parent;
6832 	entity_t *inst, linst;
6833 	int r;
6834 	int fresh = 0;
6835 	scf_snaplevel_t *running;
6836 	int have_ge = 0;
6837 
6838 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
6839 	    "was deleted unexpectedly.\n");
6840 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
6841 	    "changed unexpectedly (property group added).\n");
6842 	const char * const s_deleted =
6843 	    gettext("%s was deleted unexpectedly.\n");
6844 	const char * const i_deleted =
6845 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6846 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6847 	    "is corrupt (missing service snaplevel).\n");
6848 	const char * const s_mfile_upd =
6849 	    gettext("Unable to update the manifest file connection "
6850 	    "for %s\n");
6851 
6852 	li_only = 0;
6853 	/* Validate the service name */
6854 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6855 		switch (scf_error()) {
6856 		case SCF_ERROR_CONNECTION_BROKEN:
6857 			return (stash_scferror(lcbdata));
6858 
6859 		case SCF_ERROR_INVALID_ARGUMENT:
6860 			warn(gettext("\"%s\" is an invalid service name.  "
6861 			    "Cannot import.\n"), s->sc_name);
6862 			return (stash_scferror(lcbdata));
6863 
6864 		case SCF_ERROR_NOT_FOUND:
6865 			break;
6866 
6867 		case SCF_ERROR_HANDLE_MISMATCH:
6868 		case SCF_ERROR_NOT_BOUND:
6869 		case SCF_ERROR_NOT_SET:
6870 		default:
6871 			bad_error("scf_scope_get_service", scf_error());
6872 		}
6873 	}
6874 
6875 	/* create temporary service */
6876 	/*
6877 	 * the size of the buffer was reduced to max_scf_name_len to prevent
6878 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6879 	 * should be restored to its original value (max_scf_name_len +1)
6880 	 */
6881 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6882 	if (r < 0)
6883 		bad_error("snprintf", errno);
6884 	if (r > max_scf_name_len) {
6885 		warn(gettext(
6886 		    "Service name \"%s\" is too long.  Cannot import.\n"),
6887 		    s->sc_name);
6888 		lcbdata->sc_err = EINVAL;
6889 		return (UU_WALK_ERROR);
6890 	}
6891 
6892 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6893 		switch (scf_error()) {
6894 		case SCF_ERROR_CONNECTION_BROKEN:
6895 		case SCF_ERROR_NO_RESOURCES:
6896 		case SCF_ERROR_BACKEND_READONLY:
6897 		case SCF_ERROR_BACKEND_ACCESS:
6898 			return (stash_scferror(lcbdata));
6899 
6900 		case SCF_ERROR_EXISTS:
6901 			warn(gettext(
6902 			    "Temporary service \"%s\" must be deleted before "
6903 			    "this manifest can be imported.\n"), imp_tsname);
6904 			return (stash_scferror(lcbdata));
6905 
6906 		case SCF_ERROR_PERMISSION_DENIED:
6907 			warn(gettext("Could not create temporary service "
6908 			    "\"%s\" (permission denied).\n"), imp_tsname);
6909 			return (stash_scferror(lcbdata));
6910 
6911 		case SCF_ERROR_INVALID_ARGUMENT:
6912 		case SCF_ERROR_HANDLE_MISMATCH:
6913 		case SCF_ERROR_NOT_BOUND:
6914 		case SCF_ERROR_NOT_SET:
6915 		default:
6916 			bad_error("scf_scope_add_service", scf_error());
6917 		}
6918 	}
6919 
6920 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6921 	if (r < 0)
6922 		bad_error("snprintf", errno);
6923 
6924 	cbdata.sc_handle = lcbdata->sc_handle;
6925 	cbdata.sc_parent = imp_tsvc;
6926 	cbdata.sc_service = 1;
6927 	cbdata.sc_source_fmri = s->sc_fmri;
6928 	cbdata.sc_target_fmri = imp_str;
6929 	cbdata.sc_flags = 0;
6930 
6931 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6932 	    UU_DEFAULT) != 0) {
6933 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6934 			bad_error("uu_list_walk", uu_error());
6935 
6936 		lcbdata->sc_err = cbdata.sc_err;
6937 		switch (cbdata.sc_err) {
6938 		case ECONNABORTED:
6939 			goto connaborted;
6940 
6941 		case ECANCELED:
6942 			warn(ts_deleted, imp_tsname);
6943 			lcbdata->sc_err = EBUSY;
6944 			return (UU_WALK_ERROR);
6945 
6946 		case EEXIST:
6947 			warn(ts_pg_added, imp_tsname);
6948 			lcbdata->sc_err = EBUSY;
6949 			return (UU_WALK_ERROR);
6950 		}
6951 
6952 		r = UU_WALK_ERROR;
6953 		goto deltemp;
6954 	}
6955 
6956 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6957 	    UU_DEFAULT) != 0) {
6958 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6959 			bad_error("uu_list_walk", uu_error());
6960 
6961 		lcbdata->sc_err = cbdata.sc_err;
6962 		switch (cbdata.sc_err) {
6963 		case ECONNABORTED:
6964 			goto connaborted;
6965 
6966 		case ECANCELED:
6967 			warn(ts_deleted, imp_tsname);
6968 			lcbdata->sc_err = EBUSY;
6969 			return (UU_WALK_ERROR);
6970 
6971 		case EEXIST:
6972 			warn(ts_pg_added, imp_tsname);
6973 			lcbdata->sc_err = EBUSY;
6974 			return (UU_WALK_ERROR);
6975 		}
6976 
6977 		r = UU_WALK_ERROR;
6978 		goto deltemp;
6979 	}
6980 
6981 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6982 		switch (scf_error()) {
6983 		case SCF_ERROR_NOT_FOUND:
6984 			break;
6985 
6986 		case SCF_ERROR_CONNECTION_BROKEN:
6987 			goto connaborted;
6988 
6989 		case SCF_ERROR_INVALID_ARGUMENT:
6990 		case SCF_ERROR_HANDLE_MISMATCH:
6991 		case SCF_ERROR_NOT_BOUND:
6992 		case SCF_ERROR_NOT_SET:
6993 		default:
6994 			bad_error("scf_scope_get_service", scf_error());
6995 		}
6996 
6997 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6998 			switch (scf_error()) {
6999 			case SCF_ERROR_CONNECTION_BROKEN:
7000 				goto connaborted;
7001 
7002 			case SCF_ERROR_NO_RESOURCES:
7003 			case SCF_ERROR_BACKEND_READONLY:
7004 			case SCF_ERROR_BACKEND_ACCESS:
7005 				r = stash_scferror(lcbdata);
7006 				goto deltemp;
7007 
7008 			case SCF_ERROR_EXISTS:
7009 				warn(gettext("Scope \"%s\" changed unexpectedly"
7010 				    " (service \"%s\" added).\n"),
7011 				    SCF_SCOPE_LOCAL, s->sc_name);
7012 				lcbdata->sc_err = EBUSY;
7013 				goto deltemp;
7014 
7015 			case SCF_ERROR_PERMISSION_DENIED:
7016 				warn(gettext("Could not create service \"%s\" "
7017 				    "(permission denied).\n"), s->sc_name);
7018 				goto deltemp;
7019 
7020 			case SCF_ERROR_INVALID_ARGUMENT:
7021 			case SCF_ERROR_HANDLE_MISMATCH:
7022 			case SCF_ERROR_NOT_BOUND:
7023 			case SCF_ERROR_NOT_SET:
7024 			default:
7025 				bad_error("scf_scope_add_service", scf_error());
7026 			}
7027 		}
7028 
7029 		s->sc_import_state = IMPORT_PROP_BEGUN;
7030 
7031 		/* import service properties */
7032 		cbdata.sc_handle = lcbdata->sc_handle;
7033 		cbdata.sc_parent = imp_svc;
7034 		cbdata.sc_service = 1;
7035 		cbdata.sc_flags = lcbdata->sc_flags;
7036 		cbdata.sc_source_fmri = s->sc_fmri;
7037 		cbdata.sc_target_fmri = s->sc_fmri;
7038 
7039 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7040 		    &cbdata, UU_DEFAULT) != 0) {
7041 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7042 				bad_error("uu_list_walk", uu_error());
7043 
7044 			lcbdata->sc_err = cbdata.sc_err;
7045 			switch (cbdata.sc_err) {
7046 			case ECONNABORTED:
7047 				goto connaborted;
7048 
7049 			case ECANCELED:
7050 				warn(s_deleted, s->sc_fmri);
7051 				lcbdata->sc_err = EBUSY;
7052 				return (UU_WALK_ERROR);
7053 
7054 			case EEXIST:
7055 				warn(gettext("%s changed unexpectedly "
7056 				    "(property group added).\n"), s->sc_fmri);
7057 				lcbdata->sc_err = EBUSY;
7058 				return (UU_WALK_ERROR);
7059 
7060 			case EINVAL:
7061 				/* caught above */
7062 				bad_error("entity_pgroup_import",
7063 				    cbdata.sc_err);
7064 			}
7065 
7066 			r = UU_WALK_ERROR;
7067 			goto deltemp;
7068 		}
7069 
7070 		cbdata.sc_trans = NULL;
7071 		cbdata.sc_flags = 0;
7072 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
7073 		    &cbdata, UU_DEFAULT) != 0) {
7074 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7075 				bad_error("uu_list_walk", uu_error());
7076 
7077 			lcbdata->sc_err = cbdata.sc_err;
7078 			if (cbdata.sc_err == ECONNABORTED)
7079 				goto connaborted;
7080 			r = UU_WALK_ERROR;
7081 			goto deltemp;
7082 		}
7083 
7084 		s->sc_import_state = IMPORT_PROP_DONE;
7085 
7086 		/*
7087 		 * This is a new service, so we can't take previous snapshots
7088 		 * or upgrade service properties.
7089 		 */
7090 		fresh = 1;
7091 		goto instances;
7092 	}
7093 
7094 	/* Clear sc_seen for the instances. */
7095 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
7096 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
7097 		bad_error("uu_list_walk", uu_error());
7098 
7099 	/*
7100 	 * Take previous snapshots for all instances.  Even for ones not
7101 	 * mentioned in the bundle, since we might change their service
7102 	 * properties.
7103 	 */
7104 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7105 		switch (scf_error()) {
7106 		case SCF_ERROR_CONNECTION_BROKEN:
7107 			goto connaborted;
7108 
7109 		case SCF_ERROR_DELETED:
7110 			warn(s_deleted, s->sc_fmri);
7111 			lcbdata->sc_err = EBUSY;
7112 			r = UU_WALK_ERROR;
7113 			goto deltemp;
7114 
7115 		case SCF_ERROR_HANDLE_MISMATCH:
7116 		case SCF_ERROR_NOT_BOUND:
7117 		case SCF_ERROR_NOT_SET:
7118 		default:
7119 			bad_error("scf_iter_service_instances", scf_error());
7120 		}
7121 	}
7122 
7123 	for (;;) {
7124 		r = scf_iter_next_instance(imp_iter, imp_inst);
7125 		if (r == 0)
7126 			break;
7127 		if (r != 1) {
7128 			switch (scf_error()) {
7129 			case SCF_ERROR_DELETED:
7130 				warn(s_deleted, s->sc_fmri);
7131 				lcbdata->sc_err = EBUSY;
7132 				r = UU_WALK_ERROR;
7133 				goto deltemp;
7134 
7135 			case SCF_ERROR_CONNECTION_BROKEN:
7136 				goto connaborted;
7137 
7138 			case SCF_ERROR_NOT_BOUND:
7139 			case SCF_ERROR_HANDLE_MISMATCH:
7140 			case SCF_ERROR_INVALID_ARGUMENT:
7141 			case SCF_ERROR_NOT_SET:
7142 			default:
7143 				bad_error("scf_iter_next_instance",
7144 				    scf_error());
7145 			}
7146 		}
7147 
7148 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
7149 			switch (scf_error()) {
7150 			case SCF_ERROR_DELETED:
7151 				continue;
7152 
7153 			case SCF_ERROR_CONNECTION_BROKEN:
7154 				goto connaborted;
7155 
7156 			case SCF_ERROR_NOT_SET:
7157 			case SCF_ERROR_NOT_BOUND:
7158 			default:
7159 				bad_error("scf_instance_get_name", scf_error());
7160 			}
7161 		}
7162 
7163 		if (g_verbose)
7164 			warn(gettext(
7165 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
7166 			    snap_previous, s->sc_name, imp_str);
7167 
7168 		r = take_snap(imp_inst, snap_previous, imp_snap);
7169 		switch (r) {
7170 		case 0:
7171 			break;
7172 
7173 		case ECANCELED:
7174 			continue;
7175 
7176 		case ECONNABORTED:
7177 			goto connaborted;
7178 
7179 		case EPERM:
7180 			warn(gettext("Could not take \"%s\" snapshot of "
7181 			    "svc:/%s:%s (permission denied).\n"),
7182 			    snap_previous, s->sc_name, imp_str);
7183 			lcbdata->sc_err = r;
7184 			return (UU_WALK_ERROR);
7185 
7186 		case ENOSPC:
7187 		case -1:
7188 			lcbdata->sc_err = r;
7189 			r = UU_WALK_ERROR;
7190 			goto deltemp;
7191 
7192 		default:
7193 			bad_error("take_snap", r);
7194 		}
7195 
7196 		linst.sc_name = imp_str;
7197 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
7198 		    &linst, NULL, NULL);
7199 		if (inst != NULL) {
7200 			inst->sc_import_state = IMPORT_PREVIOUS;
7201 			inst->sc_seen = 1;
7202 		}
7203 	}
7204 
7205 	/*
7206 	 * Create the new instances and take previous snapshots of
7207 	 * them.  This is not necessary, but it maximizes data preservation.
7208 	 */
7209 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
7210 	    inst != NULL;
7211 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
7212 	    inst)) {
7213 		if (inst->sc_seen)
7214 			continue;
7215 
7216 		if (scf_service_add_instance(imp_svc, inst->sc_name,
7217 		    imp_inst) != 0) {
7218 			switch (scf_error()) {
7219 			case SCF_ERROR_CONNECTION_BROKEN:
7220 				goto connaborted;
7221 
7222 			case SCF_ERROR_BACKEND_READONLY:
7223 			case SCF_ERROR_BACKEND_ACCESS:
7224 			case SCF_ERROR_NO_RESOURCES:
7225 				r = stash_scferror(lcbdata);
7226 				goto deltemp;
7227 
7228 			case SCF_ERROR_EXISTS:
7229 				warn(gettext("%s changed unexpectedly "
7230 				    "(instance \"%s\" added).\n"), s->sc_fmri,
7231 				    inst->sc_name);
7232 				lcbdata->sc_err = EBUSY;
7233 				r = UU_WALK_ERROR;
7234 				goto deltemp;
7235 
7236 			case SCF_ERROR_INVALID_ARGUMENT:
7237 				warn(gettext("Service \"%s\" has instance with "
7238 				    "invalid name \"%s\".\n"), s->sc_name,
7239 				    inst->sc_name);
7240 				r = stash_scferror(lcbdata);
7241 				goto deltemp;
7242 
7243 			case SCF_ERROR_PERMISSION_DENIED:
7244 				warn(gettext("Could not create instance \"%s\" "
7245 				    "in %s (permission denied).\n"),
7246 				    inst->sc_name, s->sc_fmri);
7247 				r = stash_scferror(lcbdata);
7248 				goto deltemp;
7249 
7250 			case SCF_ERROR_HANDLE_MISMATCH:
7251 			case SCF_ERROR_NOT_BOUND:
7252 			case SCF_ERROR_NOT_SET:
7253 			default:
7254 				bad_error("scf_service_add_instance",
7255 				    scf_error());
7256 			}
7257 		}
7258 
7259 		if (g_verbose)
7260 			warn(gettext("Taking \"%s\" snapshot for "
7261 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
7262 		r = take_snap(imp_inst, snap_previous, imp_snap);
7263 		switch (r) {
7264 		case 0:
7265 			break;
7266 
7267 		case ECANCELED:
7268 			warn(i_deleted, s->sc_fmri, inst->sc_name);
7269 			lcbdata->sc_err = EBUSY;
7270 			r = UU_WALK_ERROR;
7271 			goto deltemp;
7272 
7273 		case ECONNABORTED:
7274 			goto connaborted;
7275 
7276 		case EPERM:
7277 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
7278 			lcbdata->sc_err = r;
7279 			r = UU_WALK_ERROR;
7280 			goto deltemp;
7281 
7282 		case ENOSPC:
7283 		case -1:
7284 			r = UU_WALK_ERROR;
7285 			goto deltemp;
7286 
7287 		default:
7288 			bad_error("take_snap", r);
7289 		}
7290 	}
7291 
7292 	s->sc_import_state = IMPORT_PREVIOUS;
7293 
7294 	/*
7295 	 * Upgrade service properties, if we can find a last-import snapshot.
7296 	 * Any will do because we don't support different service properties
7297 	 * in different manifests, so all snaplevels of the service in all of
7298 	 * the last-import snapshots of the instances should be the same.
7299 	 */
7300 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
7301 		switch (scf_error()) {
7302 		case SCF_ERROR_CONNECTION_BROKEN:
7303 			goto connaborted;
7304 
7305 		case SCF_ERROR_DELETED:
7306 			warn(s_deleted, s->sc_fmri);
7307 			lcbdata->sc_err = EBUSY;
7308 			r = UU_WALK_ERROR;
7309 			goto deltemp;
7310 
7311 		case SCF_ERROR_HANDLE_MISMATCH:
7312 		case SCF_ERROR_NOT_BOUND:
7313 		case SCF_ERROR_NOT_SET:
7314 		default:
7315 			bad_error("scf_iter_service_instances", scf_error());
7316 		}
7317 	}
7318 
7319 	for (;;) {
7320 		r = scf_iter_next_instance(imp_iter, imp_inst);
7321 		if (r == -1) {
7322 			switch (scf_error()) {
7323 			case SCF_ERROR_DELETED:
7324 				warn(s_deleted, s->sc_fmri);
7325 				lcbdata->sc_err = EBUSY;
7326 				r = UU_WALK_ERROR;
7327 				goto deltemp;
7328 
7329 			case SCF_ERROR_CONNECTION_BROKEN:
7330 				goto connaborted;
7331 
7332 			case SCF_ERROR_NOT_BOUND:
7333 			case SCF_ERROR_HANDLE_MISMATCH:
7334 			case SCF_ERROR_INVALID_ARGUMENT:
7335 			case SCF_ERROR_NOT_SET:
7336 			default:
7337 				bad_error("scf_iter_next_instance",
7338 				    scf_error());
7339 			}
7340 		}
7341 
7342 		if (r == 0) {
7343 			/*
7344 			 * Didn't find any last-import snapshots.  Override-
7345 			 * import the properties.  Unless one of the instances
7346 			 * has a general/enabled property, in which case we're
7347 			 * probably running a last-import-capable svccfg for
7348 			 * the first time, and we should only take the
7349 			 * last-import snapshot.
7350 			 */
7351 			if (have_ge) {
7352 				pgroup_t *mfpg;
7353 				scf_callback_t mfcbdata;
7354 
7355 				li_only = 1;
7356 				no_refresh = 1;
7357 				/*
7358 				 * Need to go ahead and import the manifestfiles
7359 				 * pg if it exists. If the last-import snapshot
7360 				 * upgrade code is ever removed this code can
7361 				 * be removed as well.
7362 				 */
7363 				mfpg = internal_pgroup_find(s,
7364 				    SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
7365 
7366 				if (mfpg) {
7367 					mfcbdata.sc_handle = g_hndl;
7368 					mfcbdata.sc_parent = imp_svc;
7369 					mfcbdata.sc_service = 1;
7370 					mfcbdata.sc_flags = SCI_FORCE;
7371 					mfcbdata.sc_source_fmri = s->sc_fmri;
7372 					mfcbdata.sc_target_fmri = s->sc_fmri;
7373 					if (entity_pgroup_import(mfpg,
7374 					    &mfcbdata) != UU_WALK_NEXT) {
7375 						warn(s_mfile_upd, s->sc_fmri);
7376 						r = UU_WALK_ERROR;
7377 						goto deltemp;
7378 					}
7379 				}
7380 				break;
7381 			}
7382 
7383 			s->sc_import_state = IMPORT_PROP_BEGUN;
7384 
7385 			cbdata.sc_handle = g_hndl;
7386 			cbdata.sc_parent = imp_svc;
7387 			cbdata.sc_service = 1;
7388 			cbdata.sc_flags = SCI_FORCE;
7389 			cbdata.sc_source_fmri = s->sc_fmri;
7390 			cbdata.sc_target_fmri = s->sc_fmri;
7391 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
7392 			    &cbdata, UU_DEFAULT) != 0) {
7393 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7394 					bad_error("uu_list_walk", uu_error());
7395 				lcbdata->sc_err = cbdata.sc_err;
7396 				switch (cbdata.sc_err) {
7397 				case ECONNABORTED:
7398 					goto connaborted;
7399 
7400 				case ECANCELED:
7401 					warn(s_deleted, s->sc_fmri);
7402 					lcbdata->sc_err = EBUSY;
7403 					break;
7404 
7405 				case EINVAL:	/* caught above */
7406 				case EEXIST:
7407 					bad_error("entity_pgroup_import",
7408 					    cbdata.sc_err);
7409 				}
7410 
7411 				r = UU_WALK_ERROR;
7412 				goto deltemp;
7413 			}
7414 
7415 			cbdata.sc_trans = NULL;
7416 			cbdata.sc_flags = 0;
7417 			if (uu_list_walk(s->sc_dependents,
7418 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
7419 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7420 					bad_error("uu_list_walk", uu_error());
7421 				lcbdata->sc_err = cbdata.sc_err;
7422 				if (cbdata.sc_err == ECONNABORTED)
7423 					goto connaborted;
7424 				r = UU_WALK_ERROR;
7425 				goto deltemp;
7426 			}
7427 			break;
7428 		}
7429 
7430 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
7431 		    imp_snap) != 0) {
7432 			switch (scf_error()) {
7433 			case SCF_ERROR_DELETED:
7434 				continue;
7435 
7436 			case SCF_ERROR_NOT_FOUND:
7437 				break;
7438 
7439 			case SCF_ERROR_CONNECTION_BROKEN:
7440 				goto connaborted;
7441 
7442 			case SCF_ERROR_HANDLE_MISMATCH:
7443 			case SCF_ERROR_NOT_BOUND:
7444 			case SCF_ERROR_INVALID_ARGUMENT:
7445 			case SCF_ERROR_NOT_SET:
7446 			default:
7447 				bad_error("scf_instance_get_snapshot",
7448 				    scf_error());
7449 			}
7450 
7451 			if (have_ge)
7452 				continue;
7453 
7454 			/*
7455 			 * Check for a general/enabled property.  This is how
7456 			 * we tell whether to import if there turn out to be
7457 			 * no last-import snapshots.
7458 			 */
7459 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
7460 			    imp_pg) == 0) {
7461 				if (scf_pg_get_property(imp_pg,
7462 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
7463 					have_ge = 1;
7464 				} else {
7465 					switch (scf_error()) {
7466 					case SCF_ERROR_DELETED:
7467 					case SCF_ERROR_NOT_FOUND:
7468 						continue;
7469 
7470 					case SCF_ERROR_INVALID_ARGUMENT:
7471 					case SCF_ERROR_HANDLE_MISMATCH:
7472 					case SCF_ERROR_CONNECTION_BROKEN:
7473 					case SCF_ERROR_NOT_BOUND:
7474 					case SCF_ERROR_NOT_SET:
7475 					default:
7476 						bad_error("scf_pg_get_property",
7477 						    scf_error());
7478 					}
7479 				}
7480 			} else {
7481 				switch (scf_error()) {
7482 				case SCF_ERROR_DELETED:
7483 				case SCF_ERROR_NOT_FOUND:
7484 					continue;
7485 
7486 				case SCF_ERROR_CONNECTION_BROKEN:
7487 					goto connaborted;
7488 
7489 				case SCF_ERROR_NOT_BOUND:
7490 				case SCF_ERROR_NOT_SET:
7491 				case SCF_ERROR_INVALID_ARGUMENT:
7492 				case SCF_ERROR_HANDLE_MISMATCH:
7493 				default:
7494 					bad_error("scf_instance_get_pg",
7495 					    scf_error());
7496 				}
7497 			}
7498 			continue;
7499 		}
7500 
7501 		/* find service snaplevel */
7502 		r = get_snaplevel(imp_snap, 1, imp_snpl);
7503 		switch (r) {
7504 		case 0:
7505 			break;
7506 
7507 		case ECONNABORTED:
7508 			goto connaborted;
7509 
7510 		case ECANCELED:
7511 			continue;
7512 
7513 		case ENOENT:
7514 			if (scf_instance_get_name(imp_inst, imp_str,
7515 			    imp_str_sz) < 0)
7516 				(void) strcpy(imp_str, "?");
7517 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
7518 			lcbdata->sc_err = EBADF;
7519 			r = UU_WALK_ERROR;
7520 			goto deltemp;
7521 
7522 		default:
7523 			bad_error("get_snaplevel", r);
7524 		}
7525 
7526 		if (scf_instance_get_snapshot(imp_inst, snap_running,
7527 		    imp_rsnap) != 0) {
7528 			switch (scf_error()) {
7529 			case SCF_ERROR_DELETED:
7530 				continue;
7531 
7532 			case SCF_ERROR_NOT_FOUND:
7533 				break;
7534 
7535 			case SCF_ERROR_CONNECTION_BROKEN:
7536 				goto connaborted;
7537 
7538 			case SCF_ERROR_INVALID_ARGUMENT:
7539 			case SCF_ERROR_HANDLE_MISMATCH:
7540 			case SCF_ERROR_NOT_BOUND:
7541 			case SCF_ERROR_NOT_SET:
7542 			default:
7543 				bad_error("scf_instance_get_snapshot",
7544 				    scf_error());
7545 			}
7546 			running = NULL;
7547 		} else {
7548 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
7549 			switch (r) {
7550 			case 0:
7551 				running = imp_rsnpl;
7552 				break;
7553 
7554 			case ECONNABORTED:
7555 				goto connaborted;
7556 
7557 			case ECANCELED:
7558 				continue;
7559 
7560 			case ENOENT:
7561 				if (scf_instance_get_name(imp_inst, imp_str,
7562 				    imp_str_sz) < 0)
7563 					(void) strcpy(imp_str, "?");
7564 				warn(badsnap, snap_running, s->sc_name,
7565 				    imp_str);
7566 				lcbdata->sc_err = EBADF;
7567 				r = UU_WALK_ERROR;
7568 				goto deltemp;
7569 
7570 			default:
7571 				bad_error("get_snaplevel", r);
7572 			}
7573 		}
7574 
7575 		if (g_verbose) {
7576 			if (scf_instance_get_name(imp_inst, imp_str,
7577 			    imp_str_sz) < 0)
7578 				(void) strcpy(imp_str, "?");
7579 			warn(gettext("Upgrading properties of %s according to "
7580 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
7581 		}
7582 
7583 		/* upgrade service properties */
7584 		r = upgrade_props(imp_svc, running, imp_snpl, s);
7585 		if (r == 0)
7586 			break;
7587 
7588 		switch (r) {
7589 		case ECONNABORTED:
7590 			goto connaborted;
7591 
7592 		case ECANCELED:
7593 			warn(s_deleted, s->sc_fmri);
7594 			lcbdata->sc_err = EBUSY;
7595 			break;
7596 
7597 		case ENODEV:
7598 			if (scf_instance_get_name(imp_inst, imp_str,
7599 			    imp_str_sz) < 0)
7600 				(void) strcpy(imp_str, "?");
7601 			warn(i_deleted, s->sc_fmri, imp_str);
7602 			lcbdata->sc_err = EBUSY;
7603 			break;
7604 
7605 		default:
7606 			lcbdata->sc_err = r;
7607 		}
7608 
7609 		r = UU_WALK_ERROR;
7610 		goto deltemp;
7611 	}
7612 
7613 	s->sc_import_state = IMPORT_PROP_DONE;
7614 
7615 instances:
7616 	/* import instances */
7617 	cbdata.sc_handle = lcbdata->sc_handle;
7618 	cbdata.sc_parent = imp_svc;
7619 	cbdata.sc_service = 1;
7620 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
7621 	cbdata.sc_general = NULL;
7622 
7623 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
7624 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
7625 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7626 			bad_error("uu_list_walk", uu_error());
7627 
7628 		lcbdata->sc_err = cbdata.sc_err;
7629 		if (cbdata.sc_err == ECONNABORTED)
7630 			goto connaborted;
7631 		r = UU_WALK_ERROR;
7632 		goto deltemp;
7633 	}
7634 
7635 	s->sc_import_state = IMPORT_COMPLETE;
7636 	r = UU_WALK_NEXT;
7637 
7638 deltemp:
7639 	/* delete temporary service */
7640 	if (scf_service_delete(imp_tsvc) != 0) {
7641 		switch (scf_error()) {
7642 		case SCF_ERROR_DELETED:
7643 			break;
7644 
7645 		case SCF_ERROR_CONNECTION_BROKEN:
7646 			goto connaborted;
7647 
7648 		case SCF_ERROR_EXISTS:
7649 			warn(gettext(
7650 			    "Could not delete svc:/%s (instances exist).\n"),
7651 			    imp_tsname);
7652 			break;
7653 
7654 		case SCF_ERROR_NOT_SET:
7655 		case SCF_ERROR_NOT_BOUND:
7656 		default:
7657 			bad_error("scf_service_delete", scf_error());
7658 		}
7659 	}
7660 
7661 	return (r);
7662 
7663 connaborted:
7664 	warn(gettext("Could not delete svc:/%s "
7665 	    "(repository connection broken).\n"), imp_tsname);
7666 	lcbdata->sc_err = ECONNABORTED;
7667 	return (UU_WALK_ERROR);
7668 }
7669 
7670 static const char *
7671 import_progress(int st)
7672 {
7673 	switch (st) {
7674 	case 0:
7675 		return (gettext("not reached."));
7676 
7677 	case IMPORT_PREVIOUS:
7678 		return (gettext("previous snapshot taken."));
7679 
7680 	case IMPORT_PROP_BEGUN:
7681 		return (gettext("some properties imported."));
7682 
7683 	case IMPORT_PROP_DONE:
7684 		return (gettext("properties imported."));
7685 
7686 	case IMPORT_COMPLETE:
7687 		return (gettext("imported."));
7688 
7689 	case IMPORT_REFRESHED:
7690 		return (gettext("refresh requested."));
7691 
7692 	default:
7693 #ifndef NDEBUG
7694 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
7695 		    __FILE__, __LINE__, st);
7696 #endif
7697 		abort();
7698 		/* NOTREACHED */
7699 	}
7700 }
7701 
7702 /*
7703  * Returns
7704  *   0 - success
7705  *     - fmri wasn't found (error printed)
7706  *     - entity was deleted (error printed)
7707  *     - backend denied access (error printed)
7708  *   ENOMEM - out of memory (error printed)
7709  *   ECONNABORTED - repository connection broken (error printed)
7710  *   EPERM - permission denied (error printed)
7711  *   -1 - unknown libscf error (error printed)
7712  */
7713 static int
7714 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
7715 {
7716 	scf_error_t serr;
7717 	void *ent;
7718 	int issvc;
7719 	int r;
7720 
7721 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
7722 	const char *dpt_deleted = gettext("Could not refresh %s "
7723 	    "(dependent \"%s\" of %s) (deleted).\n");
7724 
7725 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
7726 	switch (serr) {
7727 	case SCF_ERROR_NONE:
7728 		break;
7729 
7730 	case SCF_ERROR_NO_MEMORY:
7731 		if (name == NULL)
7732 			warn(gettext("Could not refresh %s (out of memory).\n"),
7733 			    fmri);
7734 		else
7735 			warn(gettext("Could not refresh %s "
7736 			    "(dependent \"%s\" of %s) (out of memory).\n"),
7737 			    fmri, name, d_fmri);
7738 		return (ENOMEM);
7739 
7740 	case SCF_ERROR_NOT_FOUND:
7741 		if (name == NULL)
7742 			warn(deleted, fmri);
7743 		else
7744 			warn(dpt_deleted, fmri, name, d_fmri);
7745 		return (0);
7746 
7747 	case SCF_ERROR_INVALID_ARGUMENT:
7748 	case SCF_ERROR_CONSTRAINT_VIOLATED:
7749 	default:
7750 		bad_error("fmri_to_entity", serr);
7751 	}
7752 
7753 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
7754 	switch (r) {
7755 	case 0:
7756 		break;
7757 
7758 	case ECONNABORTED:
7759 		if (name != NULL)
7760 			warn(gettext("Could not refresh %s "
7761 			    "(dependent \"%s\" of %s) "
7762 			    "(repository connection broken).\n"), fmri, name,
7763 			    d_fmri);
7764 		return (r);
7765 
7766 	case ECANCELED:
7767 		if (name == NULL)
7768 			warn(deleted, fmri);
7769 		else
7770 			warn(dpt_deleted, fmri, name, d_fmri);
7771 		return (0);
7772 
7773 	case EACCES:
7774 		if (!g_verbose)
7775 			return (0);
7776 		if (name == NULL)
7777 			warn(gettext("Could not refresh %s "
7778 			    "(backend access denied).\n"), fmri);
7779 		else
7780 			warn(gettext("Could not refresh %s "
7781 			    "(dependent \"%s\" of %s) "
7782 			    "(backend access denied).\n"), fmri, name, d_fmri);
7783 		return (0);
7784 
7785 	case EPERM:
7786 		if (name == NULL)
7787 			warn(gettext("Could not refresh %s "
7788 			    "(permission denied).\n"), fmri);
7789 		else
7790 			warn(gettext("Could not refresh %s "
7791 			    "(dependent \"%s\" of %s) "
7792 			    "(permission denied).\n"), fmri, name, d_fmri);
7793 		return (r);
7794 
7795 	case ENOSPC:
7796 		if (name == NULL)
7797 			warn(gettext("Could not refresh %s "
7798 			    "(repository server out of resources).\n"),
7799 			    fmri);
7800 		else
7801 			warn(gettext("Could not refresh %s "
7802 			    "(dependent \"%s\" of %s) "
7803 			    "(repository server out of resources).\n"),
7804 			    fmri, name, d_fmri);
7805 		return (r);
7806 
7807 	case -1:
7808 		scfwarn();
7809 		return (r);
7810 
7811 	default:
7812 		bad_error("refresh_entity", r);
7813 	}
7814 
7815 	if (issvc)
7816 		scf_service_destroy(ent);
7817 	else
7818 		scf_instance_destroy(ent);
7819 
7820 	return (0);
7821 }
7822 
7823 static int
7824 alloc_imp_globals()
7825 {
7826 	int r;
7827 
7828 	const char * const emsg_nomem = gettext("Out of memory.\n");
7829 	const char * const emsg_nores =
7830 	    gettext("svc.configd is out of resources.\n");
7831 
7832 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
7833 	    max_scf_name_len : max_scf_fmri_len) + 1;
7834 
7835 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
7836 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
7837 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
7838 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
7839 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
7840 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
7841 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
7842 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
7843 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
7844 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7845 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
7846 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7847 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
7848 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
7849 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
7850 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
7851 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
7852 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
7853 	    (imp_str = malloc(imp_str_sz)) == NULL ||
7854 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
7855 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
7856 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
7857 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
7858 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
7859 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
7860 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
7861 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
7862 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
7863 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7864 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7865 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7866 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7867 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7868 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7869 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7870 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7871 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7872 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7873 			warn(emsg_nores);
7874 		else
7875 			warn(emsg_nomem);
7876 
7877 		return (-1);
7878 	}
7879 
7880 	r = load_init();
7881 	switch (r) {
7882 	case 0:
7883 		break;
7884 
7885 	case ENOMEM:
7886 		warn(emsg_nomem);
7887 		return (-1);
7888 
7889 	default:
7890 		bad_error("load_init", r);
7891 	}
7892 
7893 	return (0);
7894 }
7895 
7896 static void
7897 free_imp_globals()
7898 {
7899 	pgroup_t *old_dpt;
7900 	void *cookie;
7901 
7902 	load_fini();
7903 
7904 	free(ud_ctarg);
7905 	free(ud_oldtarg);
7906 	free(ud_name);
7907 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7908 
7909 	scf_transaction_destroy(ud_tx);
7910 	ud_tx = NULL;
7911 	scf_iter_destroy(ud_iter);
7912 	scf_iter_destroy(ud_iter2);
7913 	ud_iter = ud_iter2 = NULL;
7914 	scf_value_destroy(ud_val);
7915 	ud_val = NULL;
7916 	scf_property_destroy(ud_prop);
7917 	scf_property_destroy(ud_dpt_prop);
7918 	ud_prop = ud_dpt_prop = NULL;
7919 	scf_pg_destroy(ud_pg);
7920 	scf_pg_destroy(ud_cur_depts_pg);
7921 	scf_pg_destroy(ud_run_dpts_pg);
7922 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7923 	scf_snaplevel_destroy(ud_snpl);
7924 	ud_snpl = NULL;
7925 	scf_instance_destroy(ud_inst);
7926 	ud_inst = NULL;
7927 
7928 	free(imp_str);
7929 	free(imp_tsname);
7930 	free(imp_fe1);
7931 	free(imp_fe2);
7932 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7933 
7934 	cookie = NULL;
7935 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7936 	    NULL) {
7937 		free((char *)old_dpt->sc_pgroup_name);
7938 		free((char *)old_dpt->sc_pgroup_fmri);
7939 		internal_pgroup_free(old_dpt);
7940 	}
7941 	uu_list_destroy(imp_deleted_dpts);
7942 
7943 	scf_transaction_destroy(imp_tx);
7944 	imp_tx = NULL;
7945 	scf_iter_destroy(imp_iter);
7946 	scf_iter_destroy(imp_rpg_iter);
7947 	scf_iter_destroy(imp_up_iter);
7948 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7949 	scf_property_destroy(imp_prop);
7950 	imp_prop = NULL;
7951 	scf_pg_destroy(imp_pg);
7952 	scf_pg_destroy(imp_pg2);
7953 	imp_pg = imp_pg2 = NULL;
7954 	scf_snaplevel_destroy(imp_snpl);
7955 	scf_snaplevel_destroy(imp_rsnpl);
7956 	imp_snpl = imp_rsnpl = NULL;
7957 	scf_snapshot_destroy(imp_snap);
7958 	scf_snapshot_destroy(imp_lisnap);
7959 	scf_snapshot_destroy(imp_tlisnap);
7960 	scf_snapshot_destroy(imp_rsnap);
7961 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7962 	scf_instance_destroy(imp_inst);
7963 	scf_instance_destroy(imp_tinst);
7964 	imp_inst = imp_tinst = NULL;
7965 	scf_service_destroy(imp_svc);
7966 	scf_service_destroy(imp_tsvc);
7967 	imp_svc = imp_tsvc = NULL;
7968 	scf_scope_destroy(imp_scope);
7969 	imp_scope = NULL;
7970 
7971 	load_fini();
7972 }
7973 
7974 int
7975 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
7976 {
7977 	scf_callback_t cbdata;
7978 	int result = 0;
7979 	entity_t *svc, *inst;
7980 	uu_list_t *insts;
7981 	int r;
7982 	pgroup_t *old_dpt;
7983 	int annotation_set = 0;
7984 
7985 	const char * const emsg_nomem = gettext("Out of memory.\n");
7986 	const char * const emsg_nores =
7987 	    gettext("svc.configd is out of resources.\n");
7988 
7989 	lscf_prep_hndl();
7990 
7991 	if (alloc_imp_globals())
7992 		goto out;
7993 
7994 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7995 		switch (scf_error()) {
7996 		case SCF_ERROR_CONNECTION_BROKEN:
7997 			warn(gettext("Repository connection broken.\n"));
7998 			repository_teardown();
7999 			result = -1;
8000 			goto out;
8001 
8002 		case SCF_ERROR_NOT_FOUND:
8003 		case SCF_ERROR_INVALID_ARGUMENT:
8004 		case SCF_ERROR_NOT_BOUND:
8005 		case SCF_ERROR_HANDLE_MISMATCH:
8006 		default:
8007 			bad_error("scf_handle_get_scope", scf_error());
8008 		}
8009 	}
8010 
8011 	/* Set up the auditing annotation. */
8012 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
8013 		annotation_set = 1;
8014 	} else {
8015 		switch (scf_error()) {
8016 		case SCF_ERROR_CONNECTION_BROKEN:
8017 			warn(gettext("Repository connection broken.\n"));
8018 			repository_teardown();
8019 			result = -1;
8020 			goto out;
8021 
8022 		case SCF_ERROR_INVALID_ARGUMENT:
8023 		case SCF_ERROR_NOT_BOUND:
8024 		case SCF_ERROR_NO_RESOURCES:
8025 		case SCF_ERROR_INTERNAL:
8026 			bad_error("_scf_set_annotation", scf_error());
8027 			/* NOTREACHED */
8028 
8029 		default:
8030 			/*
8031 			 * Do not terminate import because of inability to
8032 			 * generate annotation audit event.
8033 			 */
8034 			warn(gettext("_scf_set_annotation() unexpectedly "
8035 			    "failed with return code of %d\n"), scf_error());
8036 			break;
8037 		}
8038 	}
8039 
8040 	/*
8041 	 * Clear the sc_import_state's of all services & instances so we can
8042 	 * report how far we got if we fail.
8043 	 */
8044 	for (svc = uu_list_first(bndl->sc_bundle_services);
8045 	    svc != NULL;
8046 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8047 		svc->sc_import_state = 0;
8048 
8049 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
8050 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
8051 		    UU_DEFAULT) != 0)
8052 			bad_error("uu_list_walk", uu_error());
8053 	}
8054 
8055 	cbdata.sc_handle = g_hndl;
8056 	cbdata.sc_parent = imp_scope;
8057 	cbdata.sc_flags = flags;
8058 	cbdata.sc_general = NULL;
8059 
8060 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
8061 	    &cbdata, UU_DEFAULT) == 0) {
8062 		/* Success.  Refresh everything. */
8063 
8064 		if (flags & SCI_NOREFRESH || no_refresh) {
8065 			no_refresh = 0;
8066 			result = 0;
8067 			goto out;
8068 		}
8069 
8070 		for (svc = uu_list_first(bndl->sc_bundle_services);
8071 		    svc != NULL;
8072 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8073 			pgroup_t *dpt;
8074 
8075 			insts = svc->sc_u.sc_service.sc_service_instances;
8076 
8077 			for (inst = uu_list_first(insts);
8078 			    inst != NULL;
8079 			    inst = uu_list_next(insts, inst)) {
8080 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
8081 				switch (r) {
8082 				case 0:
8083 					break;
8084 
8085 				case ENOMEM:
8086 				case ECONNABORTED:
8087 				case EPERM:
8088 				case -1:
8089 					goto progress;
8090 
8091 				default:
8092 					bad_error("imp_refresh_fmri", r);
8093 				}
8094 
8095 				inst->sc_import_state = IMPORT_REFRESHED;
8096 
8097 				for (dpt = uu_list_first(inst->sc_dependents);
8098 				    dpt != NULL;
8099 				    dpt = uu_list_next(inst->sc_dependents,
8100 				    dpt))
8101 					if (imp_refresh_fmri(
8102 					    dpt->sc_pgroup_fmri,
8103 					    dpt->sc_pgroup_name,
8104 					    inst->sc_fmri) != 0)
8105 						goto progress;
8106 			}
8107 
8108 			for (dpt = uu_list_first(svc->sc_dependents);
8109 			    dpt != NULL;
8110 			    dpt = uu_list_next(svc->sc_dependents, dpt))
8111 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
8112 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
8113 					goto progress;
8114 		}
8115 
8116 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8117 		    old_dpt != NULL;
8118 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
8119 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8120 			    old_dpt->sc_pgroup_name,
8121 			    old_dpt->sc_parent->sc_fmri) != 0)
8122 				goto progress;
8123 
8124 		result = 0;
8125 		goto out;
8126 	}
8127 
8128 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8129 		bad_error("uu_list_walk", uu_error());
8130 
8131 printerr:
8132 	/* If the error hasn't been printed yet, do so here. */
8133 	switch (cbdata.sc_err) {
8134 	case ECONNABORTED:
8135 		warn(gettext("Repository connection broken.\n"));
8136 		break;
8137 
8138 	case ENOMEM:
8139 		warn(emsg_nomem);
8140 		break;
8141 
8142 	case ENOSPC:
8143 		warn(emsg_nores);
8144 		break;
8145 
8146 	case EROFS:
8147 		warn(gettext("Repository is read-only.\n"));
8148 		break;
8149 
8150 	case EACCES:
8151 		warn(gettext("Repository backend denied access.\n"));
8152 		break;
8153 
8154 	case EPERM:
8155 	case EINVAL:
8156 	case EEXIST:
8157 	case EBUSY:
8158 	case EBADF:
8159 	case -1:
8160 		break;
8161 
8162 	default:
8163 		bad_error("lscf_service_import", cbdata.sc_err);
8164 	}
8165 
8166 progress:
8167 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
8168 
8169 	for (svc = uu_list_first(bndl->sc_bundle_services);
8170 	    svc != NULL;
8171 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8172 		insts = svc->sc_u.sc_service.sc_service_instances;
8173 
8174 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
8175 		    import_progress(svc->sc_import_state));
8176 
8177 		for (inst = uu_list_first(insts);
8178 		    inst != NULL;
8179 		    inst = uu_list_next(insts, inst))
8180 			warn(gettext("    Instance \"%s\": %s\n"),
8181 			    inst->sc_name,
8182 			    import_progress(inst->sc_import_state));
8183 	}
8184 
8185 	if (cbdata.sc_err == ECONNABORTED)
8186 		repository_teardown();
8187 
8188 
8189 	result = -1;
8190 
8191 out:
8192 	if (annotation_set != 0) {
8193 		/* Turn off annotation.  It is no longer needed. */
8194 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8195 	}
8196 
8197 	free_imp_globals();
8198 
8199 	return (result);
8200 }
8201 
8202 /*
8203  * _lscf_import_err() summarize the error handling returned by
8204  * lscf_import_{instance | service}_pgs
8205  * Return values are:
8206  * IMPORT_NEXT
8207  * IMPORT_OUT
8208  * IMPORT_BAD
8209  */
8210 
8211 #define	IMPORT_BAD	-1
8212 #define	IMPORT_NEXT	0
8213 #define	IMPORT_OUT	1
8214 
8215 static int
8216 _lscf_import_err(int err, const char *fmri)
8217 {
8218 	switch (err) {
8219 	case 0:
8220 		if (g_verbose)
8221 			warn(gettext("%s updated.\n"), fmri);
8222 		return (IMPORT_NEXT);
8223 
8224 	case ECONNABORTED:
8225 		warn(gettext("Could not update %s "
8226 		    "(repository connection broken).\n"), fmri);
8227 		return (IMPORT_OUT);
8228 
8229 	case ENOMEM:
8230 		warn(gettext("Could not update %s (out of memory).\n"), fmri);
8231 		return (IMPORT_OUT);
8232 
8233 	case ENOSPC:
8234 		warn(gettext("Could not update %s "
8235 		    "(repository server out of resources).\n"), fmri);
8236 		return (IMPORT_OUT);
8237 
8238 	case ECANCELED:
8239 		warn(gettext(
8240 		    "Could not update %s (deleted).\n"), fmri);
8241 		return (IMPORT_NEXT);
8242 
8243 	case EPERM:
8244 	case EINVAL:
8245 	case EBUSY:
8246 		return (IMPORT_NEXT);
8247 
8248 	case EROFS:
8249 		warn(gettext("Could not update %s (repository read-only).\n"),
8250 		    fmri);
8251 		return (IMPORT_OUT);
8252 
8253 	case EACCES:
8254 		warn(gettext("Could not update %s "
8255 		    "(backend access denied).\n"), fmri);
8256 		return (IMPORT_NEXT);
8257 
8258 	case EEXIST:
8259 	default:
8260 		return (IMPORT_BAD);
8261 	}
8262 
8263 	/*NOTREACHED*/
8264 }
8265 
8266 /*
8267  * The global imp_svc and imp_inst should be set by the caller in the
8268  * check to make sure the service and instance exist that the apply is
8269  * working on.
8270  */
8271 static int
8272 lscf_dependent_apply(void *dpg, void *e)
8273 {
8274 	scf_callback_t cb;
8275 	pgroup_t *dpt_pgroup = dpg;
8276 	pgroup_t *deldpt;
8277 	entity_t *ent = e;
8278 	int tissvc;
8279 	void *sc_ent, *tent;
8280 	scf_error_t serr;
8281 	int r;
8282 
8283 	const char * const dependents = "dependents";
8284 	const int issvc = (ent->sc_etype == SVCCFG_SERVICE_OBJECT);
8285 
8286 	if (issvc)
8287 		sc_ent = imp_svc;
8288 	else
8289 		sc_ent = imp_inst;
8290 
8291 	if (entity_get_running_pg(sc_ent, issvc, dependents, imp_pg,
8292 	    imp_iter, imp_tinst, imp_snap, imp_snpl) != 0 ||
8293 	    scf_pg_get_property(imp_pg, dpt_pgroup->sc_pgroup_name,
8294 	    imp_prop) != 0) {
8295 		switch (scf_error()) {
8296 		case SCF_ERROR_NOT_FOUND:
8297 		case SCF_ERROR_DELETED:
8298 			break;
8299 
8300 		case SCF_ERROR_CONNECTION_BROKEN:
8301 		case SCF_ERROR_NOT_SET:
8302 		case SCF_ERROR_INVALID_ARGUMENT:
8303 		case SCF_ERROR_HANDLE_MISMATCH:
8304 		case SCF_ERROR_NOT_BOUND:
8305 		default:
8306 			bad_error("entity_get_pg", scf_error());
8307 		}
8308 	} else {
8309 		/*
8310 		 * Found the dependents/<wip dep> so check to
8311 		 * see if the service is different.  If so
8312 		 * store the service for later refresh, and
8313 		 * delete the wip dependency from the service
8314 		 */
8315 		if (scf_property_get_value(imp_prop, ud_val) != 0) {
8316 			switch (scf_error()) {
8317 				case SCF_ERROR_DELETED:
8318 					break;
8319 
8320 				case SCF_ERROR_CONNECTION_BROKEN:
8321 				case SCF_ERROR_NOT_SET:
8322 				case SCF_ERROR_INVALID_ARGUMENT:
8323 				case SCF_ERROR_HANDLE_MISMATCH:
8324 				case SCF_ERROR_NOT_BOUND:
8325 				default:
8326 					bad_error("scf_property_get_value",
8327 					    scf_error());
8328 			}
8329 		}
8330 
8331 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
8332 		    max_scf_value_len + 1) < 0)
8333 			bad_error("scf_value_get_as_string", scf_error());
8334 
8335 		r = fmri_equal(dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
8336 		switch (r) {
8337 		case 1:
8338 			break;
8339 		case 0:
8340 			if ((serr = fmri_to_entity(g_hndl, ud_oldtarg, &tent,
8341 			    &tissvc)) != SCF_ERROR_NONE) {
8342 				if (serr == SCF_ERROR_NOT_FOUND) {
8343 					break;
8344 				} else {
8345 					bad_error("fmri_to_entity", serr);
8346 				}
8347 			}
8348 
8349 			if (entity_get_pg(tent, tissvc,
8350 			    dpt_pgroup->sc_pgroup_name, imp_pg) != 0) {
8351 				serr = scf_error();
8352 				if (serr == SCF_ERROR_NOT_FOUND ||
8353 				    serr == SCF_ERROR_DELETED) {
8354 					break;
8355 				} else {
8356 					bad_error("entity_get_pg", scf_error());
8357 				}
8358 			}
8359 
8360 			if (scf_pg_delete(imp_pg) != 0) {
8361 				serr = scf_error();
8362 				if (serr == SCF_ERROR_NOT_FOUND ||
8363 				    serr == SCF_ERROR_DELETED) {
8364 					break;
8365 				} else {
8366 					bad_error("scf_pg_delete", scf_error());
8367 				}
8368 			}
8369 
8370 			deldpt = internal_pgroup_new();
8371 			if (deldpt == NULL)
8372 				return (ENOMEM);
8373 			deldpt->sc_pgroup_name =
8374 			    strdup(dpt_pgroup->sc_pgroup_name);
8375 			deldpt->sc_pgroup_fmri = strdup(ud_oldtarg);
8376 			if (deldpt->sc_pgroup_name == NULL ||
8377 			    deldpt->sc_pgroup_fmri == NULL)
8378 				return (ENOMEM);
8379 			deldpt->sc_parent = (entity_t *)ent;
8380 			if (uu_list_insert_after(imp_deleted_dpts, NULL,
8381 			    deldpt) != 0)
8382 				uu_die(gettext("libuutil error: %s\n"),
8383 				    uu_strerror(uu_error()));
8384 
8385 			break;
8386 		default:
8387 			bad_error("fmri_equal", r);
8388 		}
8389 	}
8390 
8391 	cb.sc_handle = g_hndl;
8392 	cb.sc_parent = ent;
8393 	cb.sc_service = ent->sc_etype == SVCCFG_SERVICE_OBJECT;
8394 	cb.sc_source_fmri = ent->sc_fmri;
8395 	cb.sc_target_fmri = ent->sc_fmri;
8396 	cb.sc_trans = NULL;
8397 	cb.sc_flags = SCI_FORCE;
8398 
8399 	if (lscf_dependent_import(dpt_pgroup, &cb) != UU_WALK_NEXT)
8400 		return (UU_WALK_ERROR);
8401 
8402 	r = imp_refresh_fmri(dpt_pgroup->sc_pgroup_fmri, NULL, NULL);
8403 	switch (r) {
8404 	case 0:
8405 		break;
8406 
8407 	case ENOMEM:
8408 	case ECONNABORTED:
8409 	case EPERM:
8410 	case -1:
8411 		warn(gettext("Unable to refresh \"%s\"\n"),
8412 		    dpt_pgroup->sc_pgroup_fmri);
8413 		return (UU_WALK_ERROR);
8414 
8415 	default:
8416 		bad_error("imp_refresh_fmri", r);
8417 	}
8418 
8419 	return (UU_WALK_NEXT);
8420 }
8421 
8422 /*
8423  * Returns
8424  *   0 - success
8425  *   -1 - lscf_import_instance_pgs() failed.
8426  */
8427 int
8428 lscf_bundle_apply(bundle_t *bndl, const char *file)
8429 {
8430 	pgroup_t *old_dpt;
8431 	entity_t *svc, *inst;
8432 	int annotation_set = 0;
8433 	int ret = 0;
8434 	int r = 0;
8435 
8436 	lscf_prep_hndl();
8437 
8438 	if ((ret = alloc_imp_globals()))
8439 		goto out;
8440 
8441 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0)
8442 		scfdie();
8443 
8444 	/*
8445 	 * Set the strings to be used for the security audit annotation
8446 	 * event.
8447 	 */
8448 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
8449 		annotation_set = 1;
8450 	} else {
8451 		switch (scf_error()) {
8452 		case SCF_ERROR_CONNECTION_BROKEN:
8453 			warn(gettext("Repository connection broken.\n"));
8454 			goto out;
8455 
8456 		case SCF_ERROR_INVALID_ARGUMENT:
8457 		case SCF_ERROR_NOT_BOUND:
8458 		case SCF_ERROR_NO_RESOURCES:
8459 		case SCF_ERROR_INTERNAL:
8460 			bad_error("_scf_set_annotation", scf_error());
8461 			/* NOTREACHED */
8462 
8463 		default:
8464 			/*
8465 			 * Do not abort apply operation because of
8466 			 * inability to create annotation audit event.
8467 			 */
8468 			warn(gettext("_scf_set_annotation() unexpectedly "
8469 			    "failed with return code of %d\n"), scf_error());
8470 			break;
8471 		}
8472 	}
8473 
8474 	for (svc = uu_list_first(bndl->sc_bundle_services);
8475 	    svc != NULL;
8476 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
8477 		int refresh = 0;
8478 
8479 		if (scf_scope_get_service(imp_scope, svc->sc_name,
8480 		    imp_svc) != 0) {
8481 			switch (scf_error()) {
8482 			case SCF_ERROR_NOT_FOUND:
8483 				if (g_verbose)
8484 					warn(gettext("Ignoring nonexistent "
8485 					    "service %s.\n"), svc->sc_name);
8486 				continue;
8487 
8488 			default:
8489 				scfdie();
8490 			}
8491 		}
8492 
8493 		/*
8494 		 * If there were missing types in the profile, then need to
8495 		 * attempt to find the types.
8496 		 */
8497 		if (svc->sc_miss_type) {
8498 			if (uu_list_numnodes(svc->sc_pgroups) &&
8499 			    uu_list_walk(svc->sc_pgroups, find_current_pg_type,
8500 			    svc, UU_DEFAULT) != 0) {
8501 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
8502 					bad_error("uu_list_walk", uu_error());
8503 
8504 				ret = -1;
8505 				continue;
8506 			}
8507 
8508 			for (inst = uu_list_first(
8509 			    svc->sc_u.sc_service.sc_service_instances);
8510 			    inst != NULL;
8511 			    inst = uu_list_next(
8512 			    svc->sc_u.sc_service.sc_service_instances, inst)) {
8513 				/*
8514 				 * If the instance doesn't exist just
8515 				 * skip to the next instance and let the
8516 				 * import note the missing instance.
8517 				 */
8518 				if (scf_service_get_instance(imp_svc,
8519 				    inst->sc_name, imp_inst) != 0)
8520 					continue;
8521 
8522 				if (uu_list_walk(inst->sc_pgroups,
8523 				    find_current_pg_type, inst,
8524 				    UU_DEFAULT) != 0) {
8525 					if (uu_error() !=
8526 					    UU_ERROR_CALLBACK_FAILED)
8527 						bad_error("uu_list_walk",
8528 						    uu_error());
8529 
8530 					ret = -1;
8531 					inst->sc_miss_type = B_TRUE;
8532 				}
8533 			}
8534 		}
8535 
8536 		/*
8537 		 * if we have pgs in the profile, we need to refresh ALL
8538 		 * instances of the service
8539 		 */
8540 		if (uu_list_numnodes(svc->sc_pgroups) != 0) {
8541 			refresh = 1;
8542 			r = lscf_import_service_pgs(imp_svc, svc->sc_fmri, svc,
8543 			    SCI_FORCE | SCI_KEEP);
8544 			switch (_lscf_import_err(r, svc->sc_fmri)) {
8545 			case IMPORT_NEXT:
8546 				break;
8547 
8548 			case IMPORT_OUT:
8549 				goto out;
8550 
8551 			case IMPORT_BAD:
8552 			default:
8553 				bad_error("lscf_import_service_pgs", r);
8554 			}
8555 		}
8556 
8557 		if (uu_list_numnodes(svc->sc_dependents) != 0) {
8558 			uu_list_walk(svc->sc_dependents,
8559 			    lscf_dependent_apply, svc, UU_DEFAULT);
8560 		}
8561 
8562 		for (inst = uu_list_first(
8563 		    svc->sc_u.sc_service.sc_service_instances);
8564 		    inst != NULL;
8565 		    inst = uu_list_next(
8566 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
8567 			/*
8568 			 * This instance still has missing types
8569 			 * so skip it.
8570 			 */
8571 			if (inst->sc_miss_type) {
8572 				if (g_verbose)
8573 					warn(gettext("Ignoring instance "
8574 					    "%s:%s with missing types\n"),
8575 					    inst->sc_parent->sc_name,
8576 					    inst->sc_name);
8577 
8578 				continue;
8579 			}
8580 
8581 			if (scf_service_get_instance(imp_svc, inst->sc_name,
8582 			    imp_inst) != 0) {
8583 				switch (scf_error()) {
8584 				case SCF_ERROR_NOT_FOUND:
8585 					if (g_verbose)
8586 						warn(gettext("Ignoring "
8587 						    "nonexistant instance "
8588 						    "%s:%s.\n"),
8589 						    inst->sc_parent->sc_name,
8590 						    inst->sc_name);
8591 					continue;
8592 
8593 				default:
8594 					scfdie();
8595 				}
8596 			}
8597 
8598 			/*
8599 			 * If the instance does not have a general/enabled
8600 			 * property and no last-import snapshot then the
8601 			 * instance is not a fully installed instance and
8602 			 * should not have a profile applied to it.
8603 			 *
8604 			 * This could happen if a service/instance declares
8605 			 * a dependent on behalf of another service/instance.
8606 			 *
8607 			 */
8608 			if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
8609 			    imp_snap) != 0) {
8610 				if (scf_instance_get_pg(imp_inst,
8611 				    SCF_PG_GENERAL, imp_pg) != 0 ||
8612 				    scf_pg_get_property(imp_pg,
8613 				    SCF_PROPERTY_ENABLED, imp_prop) != 0) {
8614 					if (g_verbose)
8615 						warn(gettext("Ignoreing "
8616 						    "partial instance "
8617 						    "%s:%s.\n"),
8618 						    inst->sc_parent->sc_name,
8619 						    inst->sc_name);
8620 					continue;
8621 				}
8622 			}
8623 
8624 			r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri,
8625 			    inst, SCI_FORCE | SCI_KEEP);
8626 			switch (_lscf_import_err(r, inst->sc_fmri)) {
8627 			case IMPORT_NEXT:
8628 				break;
8629 
8630 			case IMPORT_OUT:
8631 				goto out;
8632 
8633 			case IMPORT_BAD:
8634 			default:
8635 				bad_error("lscf_import_instance_pgs", r);
8636 			}
8637 
8638 			if (uu_list_numnodes(inst->sc_dependents) != 0) {
8639 				uu_list_walk(inst->sc_dependents,
8640 				    lscf_dependent_apply, inst, UU_DEFAULT);
8641 			}
8642 
8643 			/* refresh only if there is no pgs in the service */
8644 			if (refresh == 0)
8645 				(void) refresh_entity(0, imp_inst,
8646 				    inst->sc_fmri, NULL, NULL, NULL);
8647 		}
8648 
8649 		if (refresh == 1) {
8650 			char *name_buf = safe_malloc(max_scf_name_len + 1);
8651 
8652 			(void) refresh_entity(1, imp_svc, svc->sc_name,
8653 			    imp_inst, imp_iter, name_buf);
8654 			free(name_buf);
8655 		}
8656 
8657 		for (old_dpt = uu_list_first(imp_deleted_dpts);
8658 		    old_dpt != NULL;
8659 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt)) {
8660 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
8661 			    old_dpt->sc_pgroup_name,
8662 			    old_dpt->sc_parent->sc_fmri) != 0) {
8663 				warn(gettext("Unable to refresh \"%s\"\n"),
8664 				    old_dpt->sc_pgroup_fmri);
8665 			}
8666 		}
8667 	}
8668 
8669 out:
8670 	if (annotation_set) {
8671 		/* Remove security audit annotation strings. */
8672 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
8673 	}
8674 
8675 	free_imp_globals();
8676 	return (ret);
8677 }
8678 
8679 
8680 /*
8681  * Export.  These functions create and output an XML tree of a service
8682  * description from the repository.  This is largely the inverse of
8683  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
8684  *
8685  * - We must include any properties which are not represented specifically by
8686  *   a service manifest, e.g., properties created by an admin post-import.  To
8687  *   do so we'll iterate through all properties and deal with each
8688  *   apropriately.
8689  *
8690  * - Children of services and instances must must be in the order set by the
8691  *   DTD, but we iterate over the properties in undefined order.  The elements
8692  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
8693  *   number of classes of them, however, we'll keep the classes separate and
8694  *   assemble them in order.
8695  */
8696 
8697 /*
8698  * Convenience function to handle xmlSetProp errors (and type casting).
8699  */
8700 static void
8701 safe_setprop(xmlNodePtr n, const char *name, const char *val)
8702 {
8703 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
8704 		uu_die(gettext("Could not set XML property.\n"));
8705 }
8706 
8707 /*
8708  * Convenience function to set an XML attribute to the single value of an
8709  * astring property.  If the value happens to be the default, don't set the
8710  * attribute.  "dval" should be the default value supplied by the DTD, or
8711  * NULL for no default.
8712  */
8713 static int
8714 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
8715     const char *name, const char *dval)
8716 {
8717 	scf_value_t *val;
8718 	ssize_t len;
8719 	char *str;
8720 
8721 	val = scf_value_create(g_hndl);
8722 	if (val == NULL)
8723 		scfdie();
8724 
8725 	if (prop_get_val(prop, val) != 0) {
8726 		scf_value_destroy(val);
8727 		return (-1);
8728 	}
8729 
8730 	len = scf_value_get_as_string(val, NULL, 0);
8731 	if (len < 0)
8732 		scfdie();
8733 
8734 	str = safe_malloc(len + 1);
8735 
8736 	if (scf_value_get_as_string(val, str, len + 1) < 0)
8737 		scfdie();
8738 
8739 	scf_value_destroy(val);
8740 
8741 	if (dval == NULL || strcmp(str, dval) != 0)
8742 		safe_setprop(n, name, str);
8743 
8744 	free(str);
8745 
8746 	return (0);
8747 }
8748 
8749 /*
8750  * As above, but the attribute is always set.
8751  */
8752 static int
8753 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
8754 {
8755 	return (set_attr_from_prop_default(prop, n, name, NULL));
8756 }
8757 
8758 /*
8759  * Dump the given document onto f, with "'s replaced by ''s.
8760  */
8761 static int
8762 write_service_bundle(xmlDocPtr doc, FILE *f)
8763 {
8764 	xmlChar *mem;
8765 	int sz, i;
8766 
8767 	mem = NULL;
8768 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
8769 
8770 	if (mem == NULL) {
8771 		semerr(gettext("Could not dump XML tree.\n"));
8772 		return (-1);
8773 	}
8774 
8775 	/*
8776 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
8777 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
8778 	 * &apos; code?!
8779 	 */
8780 	for (i = 0; i < sz; ++i) {
8781 		char c = (char)mem[i];
8782 
8783 		if (c == '"')
8784 			(void) fputc('\'', f);
8785 		else if (c == '\'')
8786 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
8787 		else
8788 			(void) fputc(c, f);
8789 	}
8790 
8791 	return (0);
8792 }
8793 
8794 /*
8795  * Create the DOM elements in elts necessary to (generically) represent prop
8796  * (i.e., a property or propval element).  If the name of the property is
8797  * known, it should be passed as name_arg.  Otherwise, pass NULL.
8798  */
8799 static void
8800 export_property(scf_property_t *prop, const char *name_arg,
8801     struct pg_elts *elts, int flags)
8802 {
8803 	const char *type;
8804 	scf_error_t err = 0;
8805 	xmlNodePtr pnode, lnode;
8806 	char *lnname;
8807 	int ret;
8808 
8809 	/* name */
8810 	if (name_arg != NULL) {
8811 		(void) strcpy(exp_str, name_arg);
8812 	} else {
8813 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
8814 			scfdie();
8815 	}
8816 
8817 	/* type */
8818 	type = prop_to_typestr(prop);
8819 	if (type == NULL)
8820 		uu_die(gettext("Can't export property %s: unknown type.\n"),
8821 		    exp_str);
8822 
8823 	/* If we're exporting values, and there's just one, export it here. */
8824 	if (!(flags & SCE_ALL_VALUES))
8825 		goto empty;
8826 
8827 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
8828 		xmlNodePtr n;
8829 
8830 		/* Single value, so use propval */
8831 		n = xmlNewNode(NULL, (xmlChar *)"propval");
8832 		if (n == NULL)
8833 			uu_die(emsg_create_xml);
8834 
8835 		safe_setprop(n, name_attr, exp_str);
8836 		safe_setprop(n, type_attr, type);
8837 
8838 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
8839 			scfdie();
8840 		safe_setprop(n, value_attr, exp_str);
8841 
8842 		if (elts->propvals == NULL)
8843 			elts->propvals = n;
8844 		else
8845 			(void) xmlAddSibling(elts->propvals, n);
8846 
8847 		return;
8848 	}
8849 
8850 	err = scf_error();
8851 
8852 	if (err == SCF_ERROR_PERMISSION_DENIED) {
8853 		semerr(emsg_permission_denied);
8854 		return;
8855 	}
8856 
8857 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
8858 	    err != SCF_ERROR_NOT_FOUND &&
8859 	    err != SCF_ERROR_PERMISSION_DENIED)
8860 		scfdie();
8861 
8862 empty:
8863 	/* Multiple (or no) values, so use property */
8864 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
8865 	if (pnode == NULL)
8866 		uu_die(emsg_create_xml);
8867 
8868 	safe_setprop(pnode, name_attr, exp_str);
8869 	safe_setprop(pnode, type_attr, type);
8870 
8871 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
8872 		lnname = uu_msprintf("%s_list", type);
8873 		if (lnname == NULL)
8874 			uu_die(gettext("Could not create string"));
8875 
8876 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
8877 		if (lnode == NULL)
8878 			uu_die(emsg_create_xml);
8879 
8880 		uu_free(lnname);
8881 
8882 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
8883 			scfdie();
8884 
8885 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
8886 		    1) {
8887 			xmlNodePtr vn;
8888 
8889 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
8890 			    NULL);
8891 			if (vn == NULL)
8892 				uu_die(emsg_create_xml);
8893 
8894 			if (scf_value_get_as_string(exp_val, exp_str,
8895 			    exp_str_sz) < 0)
8896 				scfdie();
8897 			safe_setprop(vn, value_attr, exp_str);
8898 		}
8899 		if (ret != 0)
8900 			scfdie();
8901 	}
8902 
8903 	if (elts->properties == NULL)
8904 		elts->properties = pnode;
8905 	else
8906 		(void) xmlAddSibling(elts->properties, pnode);
8907 }
8908 
8909 /*
8910  * Add a property_group element for this property group to elts.
8911  */
8912 static void
8913 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
8914 {
8915 	xmlNodePtr n;
8916 	struct pg_elts elts;
8917 	int ret;
8918 	boolean_t read_protected;
8919 
8920 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
8921 
8922 	/* name */
8923 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8924 		scfdie();
8925 	safe_setprop(n, name_attr, exp_str);
8926 
8927 	/* type */
8928 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
8929 		scfdie();
8930 	safe_setprop(n, type_attr, exp_str);
8931 
8932 	/* properties */
8933 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8934 		scfdie();
8935 
8936 	(void) memset(&elts, 0, sizeof (elts));
8937 
8938 	/*
8939 	 * If this property group is not read protected, we always want to
8940 	 * output all the values.  Otherwise, we only output the values if the
8941 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
8942 	 */
8943 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
8944 		scfdie();
8945 
8946 	if (!read_protected)
8947 		flags |= SCE_ALL_VALUES;
8948 
8949 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8950 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8951 			scfdie();
8952 
8953 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8954 			xmlNodePtr m;
8955 
8956 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8957 			if (m == NULL)
8958 				uu_die(emsg_create_xml);
8959 
8960 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8961 				elts.stability = m;
8962 				continue;
8963 			}
8964 
8965 			xmlFreeNode(m);
8966 		}
8967 
8968 		export_property(exp_prop, NULL, &elts, flags);
8969 	}
8970 	if (ret == -1)
8971 		scfdie();
8972 
8973 	(void) xmlAddChild(n, elts.stability);
8974 	(void) xmlAddChildList(n, elts.propvals);
8975 	(void) xmlAddChildList(n, elts.properties);
8976 
8977 	if (eelts->property_groups == NULL)
8978 		eelts->property_groups = n;
8979 	else
8980 		(void) xmlAddSibling(eelts->property_groups, n);
8981 }
8982 
8983 /*
8984  * Create an XML node representing the dependency described by the given
8985  * property group and put it in eelts.  Unless the dependency is not valid, in
8986  * which case create a generic property_group element which represents it and
8987  * put it in eelts.
8988  */
8989 static void
8990 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
8991 {
8992 	xmlNodePtr n;
8993 	int err = 0, ret;
8994 	struct pg_elts elts;
8995 
8996 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
8997 	if (n == NULL)
8998 		uu_die(emsg_create_xml);
8999 
9000 	/*
9001 	 * If the external flag is present, skip this dependency because it
9002 	 * should have been created by another manifest.
9003 	 */
9004 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
9005 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9006 		    prop_get_val(exp_prop, exp_val) == 0) {
9007 			uint8_t b;
9008 
9009 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
9010 				scfdie();
9011 
9012 			if (b)
9013 				return;
9014 		}
9015 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
9016 		scfdie();
9017 
9018 	/* Get the required attributes. */
9019 
9020 	/* name */
9021 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9022 		scfdie();
9023 	safe_setprop(n, name_attr, exp_str);
9024 
9025 	/* grouping */
9026 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9027 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9028 		err = 1;
9029 
9030 	/* restart_on */
9031 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9032 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9033 		err = 1;
9034 
9035 	/* type */
9036 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9037 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9038 		err = 1;
9039 
9040 	/*
9041 	 * entities: Not required, but if we create no children, it will be
9042 	 * created as empty on import, so fail if it's missing.
9043 	 */
9044 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9045 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
9046 		scf_iter_t *eiter;
9047 		int ret2;
9048 
9049 		eiter = scf_iter_create(g_hndl);
9050 		if (eiter == NULL)
9051 			scfdie();
9052 
9053 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
9054 			scfdie();
9055 
9056 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
9057 			xmlNodePtr ch;
9058 
9059 			if (scf_value_get_astring(exp_val, exp_str,
9060 			    exp_str_sz) < 0)
9061 				scfdie();
9062 
9063 			/*
9064 			 * service_fmri's must be first, so we can add them
9065 			 * here.
9066 			 */
9067 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
9068 			    NULL);
9069 			if (ch == NULL)
9070 				uu_die(emsg_create_xml);
9071 
9072 			safe_setprop(ch, value_attr, exp_str);
9073 		}
9074 		if (ret2 == -1)
9075 			scfdie();
9076 
9077 		scf_iter_destroy(eiter);
9078 	} else
9079 		err = 1;
9080 
9081 	if (err) {
9082 		xmlFreeNode(n);
9083 
9084 		export_pg(pg, eelts, SCE_ALL_VALUES);
9085 
9086 		return;
9087 	}
9088 
9089 	/* Iterate through the properties & handle each. */
9090 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9091 		scfdie();
9092 
9093 	(void) memset(&elts, 0, sizeof (elts));
9094 
9095 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9096 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9097 			scfdie();
9098 
9099 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9100 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9101 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9102 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9103 			continue;
9104 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9105 			xmlNodePtr m;
9106 
9107 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9108 			if (m == NULL)
9109 				uu_die(emsg_create_xml);
9110 
9111 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9112 				elts.stability = m;
9113 				continue;
9114 			}
9115 
9116 			xmlFreeNode(m);
9117 		}
9118 
9119 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9120 	}
9121 	if (ret == -1)
9122 		scfdie();
9123 
9124 	(void) xmlAddChild(n, elts.stability);
9125 	(void) xmlAddChildList(n, elts.propvals);
9126 	(void) xmlAddChildList(n, elts.properties);
9127 
9128 	if (eelts->dependencies == NULL)
9129 		eelts->dependencies = n;
9130 	else
9131 		(void) xmlAddSibling(eelts->dependencies, n);
9132 }
9133 
9134 static xmlNodePtr
9135 export_method_environment(scf_propertygroup_t *pg)
9136 {
9137 	xmlNodePtr env;
9138 	int ret;
9139 	int children = 0;
9140 
9141 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
9142 		return (NULL);
9143 
9144 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
9145 	if (env == NULL)
9146 		uu_die(emsg_create_xml);
9147 
9148 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
9149 		scfdie();
9150 
9151 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
9152 		scfdie();
9153 
9154 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
9155 		xmlNodePtr ev;
9156 		char *cp;
9157 
9158 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
9159 			scfdie();
9160 
9161 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
9162 			warn(gettext("Invalid environment variable \"%s\".\n"),
9163 			    exp_str);
9164 			continue;
9165 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
9166 			warn(gettext("Invalid environment variable \"%s\"; "
9167 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
9168 			continue;
9169 		}
9170 
9171 		*cp = '\0';
9172 		cp++;
9173 
9174 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
9175 		if (ev == NULL)
9176 			uu_die(emsg_create_xml);
9177 
9178 		safe_setprop(ev, name_attr, exp_str);
9179 		safe_setprop(ev, value_attr, cp);
9180 		children++;
9181 	}
9182 
9183 	if (ret != 0)
9184 		scfdie();
9185 
9186 	if (children == 0) {
9187 		xmlFreeNode(env);
9188 		return (NULL);
9189 	}
9190 
9191 	return (env);
9192 }
9193 
9194 /*
9195  * As above, but for a method property group.
9196  */
9197 static void
9198 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
9199 {
9200 	xmlNodePtr n, env;
9201 	char *str;
9202 	int err = 0, nonenv, ret;
9203 	uint8_t use_profile;
9204 	struct pg_elts elts;
9205 	xmlNodePtr ctxt = NULL;
9206 
9207 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
9208 
9209 	/* Get the required attributes. */
9210 
9211 	/* name */
9212 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
9213 		scfdie();
9214 	safe_setprop(n, name_attr, exp_str);
9215 
9216 	/* type */
9217 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
9218 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
9219 		err = 1;
9220 
9221 	/* exec */
9222 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
9223 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
9224 		err = 1;
9225 
9226 	/* timeout */
9227 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
9228 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
9229 	    prop_get_val(exp_prop, exp_val) == 0) {
9230 		uint64_t c;
9231 
9232 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
9233 			scfdie();
9234 
9235 		str = uu_msprintf("%llu", c);
9236 		if (str == NULL)
9237 			uu_die(gettext("Could not create string"));
9238 
9239 		safe_setprop(n, "timeout_seconds", str);
9240 		free(str);
9241 	} else
9242 		err = 1;
9243 
9244 	if (err) {
9245 		xmlFreeNode(n);
9246 
9247 		export_pg(pg, eelts, SCE_ALL_VALUES);
9248 
9249 		return;
9250 	}
9251 
9252 
9253 	/*
9254 	 * If we're going to have a method_context child, we need to know
9255 	 * before we iterate through the properties.  Since method_context's
9256 	 * are optional, we don't want to complain about any properties
9257 	 * missing if none of them are there.  Thus we can't use the
9258 	 * convenience functions.
9259 	 */
9260 	nonenv =
9261 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
9262 	    SCF_SUCCESS ||
9263 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
9264 	    SCF_SUCCESS ||
9265 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
9266 	    SCF_SUCCESS ||
9267 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
9268 	    SCF_SUCCESS;
9269 
9270 	if (nonenv) {
9271 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9272 		if (ctxt == NULL)
9273 			uu_die(emsg_create_xml);
9274 
9275 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
9276 		    0 &&
9277 		    set_attr_from_prop_default(exp_prop, ctxt,
9278 		    "working_directory", ":default") != 0)
9279 			err = 1;
9280 
9281 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
9282 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
9283 		    ":default") != 0)
9284 			err = 1;
9285 
9286 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
9287 		    0 &&
9288 		    set_attr_from_prop_default(exp_prop, ctxt,
9289 		    "resource_pool", ":default") != 0)
9290 			err = 1;
9291 		/*
9292 		 * We only want to complain about profile or credential
9293 		 * properties if we will use them.  To determine that we must
9294 		 * examine USE_PROFILE.
9295 		 */
9296 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9297 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9298 		    prop_get_val(exp_prop, exp_val) == 0) {
9299 			if (scf_value_get_boolean(exp_val, &use_profile) !=
9300 			    SCF_SUCCESS) {
9301 				scfdie();
9302 			}
9303 
9304 			if (use_profile) {
9305 				xmlNodePtr prof;
9306 
9307 				prof = xmlNewChild(ctxt, NULL,
9308 				    (xmlChar *)"method_profile", NULL);
9309 				if (prof == NULL)
9310 					uu_die(emsg_create_xml);
9311 
9312 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
9313 				    exp_prop) != 0 ||
9314 				    set_attr_from_prop(exp_prop, prof,
9315 				    name_attr) != 0)
9316 					err = 1;
9317 			} else {
9318 				xmlNodePtr cred;
9319 
9320 				cred = xmlNewChild(ctxt, NULL,
9321 				    (xmlChar *)"method_credential", NULL);
9322 				if (cred == NULL)
9323 					uu_die(emsg_create_xml);
9324 
9325 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
9326 				    exp_prop) != 0 ||
9327 				    set_attr_from_prop(exp_prop, cred,
9328 				    "user") != 0) {
9329 					err = 1;
9330 				}
9331 
9332 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
9333 				    exp_prop) == 0 &&
9334 				    set_attr_from_prop_default(exp_prop, cred,
9335 				    "group", ":default") != 0)
9336 					err = 1;
9337 
9338 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
9339 				    exp_prop) == 0 &&
9340 				    set_attr_from_prop_default(exp_prop, cred,
9341 				    "supp_groups", ":default") != 0)
9342 					err = 1;
9343 
9344 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
9345 				    exp_prop) == 0 &&
9346 				    set_attr_from_prop_default(exp_prop, cred,
9347 				    "privileges", ":default") != 0)
9348 					err = 1;
9349 
9350 				if (pg_get_prop(pg,
9351 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
9352 				    exp_prop) == 0 &&
9353 				    set_attr_from_prop_default(exp_prop, cred,
9354 				    "limit_privileges", ":default") != 0)
9355 					err = 1;
9356 			}
9357 		}
9358 	}
9359 
9360 	if ((env = export_method_environment(pg)) != NULL) {
9361 		if (ctxt == NULL) {
9362 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
9363 			if (ctxt == NULL)
9364 				uu_die(emsg_create_xml);
9365 		}
9366 		(void) xmlAddChild(ctxt, env);
9367 	}
9368 
9369 	if (env != NULL || (nonenv && err == 0))
9370 		(void) xmlAddChild(n, ctxt);
9371 	else
9372 		xmlFreeNode(ctxt);
9373 
9374 	nonenv = (err == 0);
9375 
9376 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9377 		scfdie();
9378 
9379 	(void) memset(&elts, 0, sizeof (elts));
9380 
9381 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9382 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9383 			scfdie();
9384 
9385 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
9386 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
9387 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
9388 			continue;
9389 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9390 			xmlNodePtr m;
9391 
9392 			m = xmlNewNode(NULL, (xmlChar *)"stability");
9393 			if (m == NULL)
9394 				uu_die(emsg_create_xml);
9395 
9396 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
9397 				elts.stability = m;
9398 				continue;
9399 			}
9400 
9401 			xmlFreeNode(m);
9402 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
9403 		    0 ||
9404 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
9405 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
9406 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9407 			if (nonenv)
9408 				continue;
9409 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
9410 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
9411 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
9412 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
9413 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
9414 			if (nonenv && !use_profile)
9415 				continue;
9416 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9417 			if (nonenv && use_profile)
9418 				continue;
9419 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
9420 			if (env != NULL)
9421 				continue;
9422 		}
9423 
9424 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9425 	}
9426 	if (ret == -1)
9427 		scfdie();
9428 
9429 	(void) xmlAddChild(n, elts.stability);
9430 	(void) xmlAddChildList(n, elts.propvals);
9431 	(void) xmlAddChildList(n, elts.properties);
9432 
9433 	if (eelts->exec_methods == NULL)
9434 		eelts->exec_methods = n;
9435 	else
9436 		(void) xmlAddSibling(eelts->exec_methods, n);
9437 }
9438 
9439 static void
9440 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
9441     struct entity_elts *eelts)
9442 {
9443 	xmlNodePtr pgnode;
9444 
9445 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
9446 	if (pgnode == NULL)
9447 		uu_die(emsg_create_xml);
9448 
9449 	safe_setprop(pgnode, name_attr, name);
9450 	safe_setprop(pgnode, type_attr, type);
9451 
9452 	(void) xmlAddChildList(pgnode, elts->propvals);
9453 	(void) xmlAddChildList(pgnode, elts->properties);
9454 
9455 	if (eelts->property_groups == NULL)
9456 		eelts->property_groups = pgnode;
9457 	else
9458 		(void) xmlAddSibling(eelts->property_groups, pgnode);
9459 }
9460 
9461 /*
9462  * Process the general property group for a service.  This is the one with the
9463  * goodies.
9464  */
9465 static void
9466 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
9467 {
9468 	struct pg_elts elts;
9469 	int ret;
9470 
9471 	/*
9472 	 * In case there are properties which don't correspond to child
9473 	 * entities of the service entity, we'll set up a pg_elts structure to
9474 	 * put them in.
9475 	 */
9476 	(void) memset(&elts, 0, sizeof (elts));
9477 
9478 	/* Walk the properties, looking for special ones. */
9479 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9480 		scfdie();
9481 
9482 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9483 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9484 			scfdie();
9485 
9486 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
9487 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9488 			    prop_get_val(exp_prop, exp_val) == 0) {
9489 				uint8_t b;
9490 
9491 				if (scf_value_get_boolean(exp_val, &b) !=
9492 				    SCF_SUCCESS)
9493 					scfdie();
9494 
9495 				if (b) {
9496 					selts->single_instance =
9497 					    xmlNewNode(NULL,
9498 					    (xmlChar *)"single_instance");
9499 					if (selts->single_instance == NULL)
9500 						uu_die(emsg_create_xml);
9501 				}
9502 
9503 				continue;
9504 			}
9505 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
9506 			xmlNodePtr rnode, sfnode;
9507 
9508 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
9509 			if (rnode == NULL)
9510 				uu_die(emsg_create_xml);
9511 
9512 			sfnode = xmlNewChild(rnode, NULL,
9513 			    (xmlChar *)"service_fmri", NULL);
9514 			if (sfnode == NULL)
9515 				uu_die(emsg_create_xml);
9516 
9517 			if (set_attr_from_prop(exp_prop, sfnode,
9518 			    value_attr) == 0) {
9519 				selts->restarter = rnode;
9520 				continue;
9521 			}
9522 
9523 			xmlFreeNode(rnode);
9524 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
9525 		    0) {
9526 			xmlNodePtr s;
9527 
9528 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9529 			if (s == NULL)
9530 				uu_die(emsg_create_xml);
9531 
9532 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9533 				selts->stability = s;
9534 				continue;
9535 			}
9536 
9537 			xmlFreeNode(s);
9538 		}
9539 
9540 		export_property(exp_prop, exp_str, &elts, SCE_ALL_VALUES);
9541 	}
9542 	if (ret == -1)
9543 		scfdie();
9544 
9545 	if (elts.propvals != NULL || elts.properties != NULL)
9546 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
9547 		    selts);
9548 }
9549 
9550 static void
9551 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
9552 {
9553 	xmlNodePtr n, prof, cred, env;
9554 	uint8_t use_profile;
9555 	int ret, err = 0;
9556 
9557 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
9558 
9559 	env = export_method_environment(pg);
9560 
9561 	/* Need to know whether we'll use a profile or not. */
9562 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
9563 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
9564 	    prop_get_val(exp_prop, exp_val) == 0) {
9565 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
9566 			scfdie();
9567 
9568 		if (use_profile)
9569 			prof =
9570 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
9571 			    NULL);
9572 		else
9573 			cred =
9574 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
9575 			    NULL);
9576 	}
9577 
9578 	if (env != NULL)
9579 		(void) xmlAddChild(n, env);
9580 
9581 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9582 		scfdie();
9583 
9584 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9585 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9586 			scfdie();
9587 
9588 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
9589 			if (set_attr_from_prop(exp_prop, n,
9590 			    "working_directory") != 0)
9591 				err = 1;
9592 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
9593 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
9594 				err = 1;
9595 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
9596 			if (set_attr_from_prop(exp_prop, n,
9597 			    "resource_pool") != 0)
9598 				err = 1;
9599 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
9600 			/* EMPTY */
9601 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
9602 			if (use_profile ||
9603 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
9604 				err = 1;
9605 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
9606 			if (use_profile ||
9607 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
9608 				err = 1;
9609 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
9610 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9611 			    "supp_groups") != 0)
9612 				err = 1;
9613 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
9614 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9615 			    "privileges") != 0)
9616 				err = 1;
9617 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
9618 		    0) {
9619 			if (use_profile || set_attr_from_prop(exp_prop, cred,
9620 			    "limit_privileges") != 0)
9621 				err = 1;
9622 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
9623 			if (!use_profile || set_attr_from_prop(exp_prop,
9624 			    prof, name_attr) != 0)
9625 				err = 1;
9626 		} else {
9627 			/* Can't have generic properties in method_context's */
9628 			err = 1;
9629 		}
9630 	}
9631 	if (ret == -1)
9632 		scfdie();
9633 
9634 	if (err && env == NULL) {
9635 		xmlFreeNode(n);
9636 		export_pg(pg, elts, SCE_ALL_VALUES);
9637 		return;
9638 	}
9639 
9640 	elts->method_context = n;
9641 }
9642 
9643 /*
9644  * Given a dependency property group in the tfmri entity (target fmri), return
9645  * a dependent element which represents it.
9646  */
9647 static xmlNodePtr
9648 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
9649 {
9650 	uint8_t b;
9651 	xmlNodePtr n, sf;
9652 	int err = 0, ret;
9653 	struct pg_elts pgelts;
9654 
9655 	/*
9656 	 * If external isn't set to true then exporting the service will
9657 	 * export this as a normal dependency, so we should stop to avoid
9658 	 * duplication.
9659 	 */
9660 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
9661 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
9662 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
9663 		if (g_verbose) {
9664 			warn(gettext("Dependent \"%s\" cannot be exported "
9665 			    "properly because the \"%s\" property of the "
9666 			    "\"%s\" dependency of %s is not set to true.\n"),
9667 			    name, scf_property_external, name, tfmri);
9668 		}
9669 
9670 		return (NULL);
9671 	}
9672 
9673 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
9674 	if (n == NULL)
9675 		uu_die(emsg_create_xml);
9676 
9677 	safe_setprop(n, name_attr, name);
9678 
9679 	/* Get the required attributes */
9680 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
9681 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
9682 		err = 1;
9683 
9684 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
9685 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
9686 		err = 1;
9687 
9688 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
9689 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
9690 	    prop_get_val(exp_prop, exp_val) == 0) {
9691 		/* EMPTY */
9692 	} else
9693 		err = 1;
9694 
9695 	if (err) {
9696 		xmlFreeNode(n);
9697 		return (NULL);
9698 	}
9699 
9700 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
9701 	if (sf == NULL)
9702 		uu_die(emsg_create_xml);
9703 
9704 	safe_setprop(sf, value_attr, tfmri);
9705 
9706 	/*
9707 	 * Now add elements for the other properties.
9708 	 */
9709 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9710 		scfdie();
9711 
9712 	(void) memset(&pgelts, 0, sizeof (pgelts));
9713 
9714 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9715 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9716 			scfdie();
9717 
9718 		if (strcmp(exp_str, scf_property_external) == 0 ||
9719 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
9720 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
9721 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
9722 			continue;
9723 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
9724 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
9725 			    prop_get_val(exp_prop, exp_val) == 0) {
9726 				char type[sizeof ("service") + 1];
9727 
9728 				if (scf_value_get_astring(exp_val, type,
9729 				    sizeof (type)) < 0)
9730 					scfdie();
9731 
9732 				if (strcmp(type, "service") == 0)
9733 					continue;
9734 			}
9735 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
9736 			xmlNodePtr s;
9737 
9738 			s = xmlNewNode(NULL, (xmlChar *)"stability");
9739 			if (s == NULL)
9740 				uu_die(emsg_create_xml);
9741 
9742 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
9743 				pgelts.stability = s;
9744 				continue;
9745 			}
9746 
9747 			xmlFreeNode(s);
9748 		}
9749 
9750 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
9751 	}
9752 	if (ret == -1)
9753 		scfdie();
9754 
9755 	(void) xmlAddChild(n, pgelts.stability);
9756 	(void) xmlAddChildList(n, pgelts.propvals);
9757 	(void) xmlAddChildList(n, pgelts.properties);
9758 
9759 	return (n);
9760 }
9761 
9762 static void
9763 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
9764 {
9765 	scf_propertygroup_t *opg;
9766 	scf_iter_t *iter;
9767 	char *type, *fmri;
9768 	int ret;
9769 	struct pg_elts pgelts;
9770 	xmlNodePtr n;
9771 	scf_error_t serr;
9772 
9773 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
9774 	    (iter = scf_iter_create(g_hndl)) == NULL)
9775 		scfdie();
9776 
9777 	/* Can't use exp_prop_iter due to export_dependent(). */
9778 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
9779 		scfdie();
9780 
9781 	type = safe_malloc(max_scf_pg_type_len + 1);
9782 
9783 	/* Get an extra byte so we can tell if values are too long. */
9784 	fmri = safe_malloc(max_scf_fmri_len + 2);
9785 
9786 	(void) memset(&pgelts, 0, sizeof (pgelts));
9787 
9788 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
9789 		void *entity;
9790 		int isservice;
9791 		scf_type_t ty;
9792 
9793 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
9794 			scfdie();
9795 
9796 		if ((ty != SCF_TYPE_ASTRING &&
9797 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
9798 		    prop_get_val(exp_prop, exp_val) != 0) {
9799 			export_property(exp_prop, NULL, &pgelts,
9800 			    SCE_ALL_VALUES);
9801 			continue;
9802 		}
9803 
9804 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9805 			scfdie();
9806 
9807 		if (scf_value_get_astring(exp_val, fmri,
9808 		    max_scf_fmri_len + 2) < 0)
9809 			scfdie();
9810 
9811 		/* Look for a dependency group in the target fmri. */
9812 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
9813 		switch (serr) {
9814 		case SCF_ERROR_NONE:
9815 			break;
9816 
9817 		case SCF_ERROR_NO_MEMORY:
9818 			uu_die(gettext("Out of memory.\n"));
9819 			/* NOTREACHED */
9820 
9821 		case SCF_ERROR_INVALID_ARGUMENT:
9822 			if (g_verbose) {
9823 				if (scf_property_to_fmri(exp_prop, fmri,
9824 				    max_scf_fmri_len + 2) < 0)
9825 					scfdie();
9826 
9827 				warn(gettext("The value of %s is not a valid "
9828 				    "FMRI.\n"), fmri);
9829 			}
9830 
9831 			export_property(exp_prop, exp_str, &pgelts,
9832 			    SCE_ALL_VALUES);
9833 			continue;
9834 
9835 		case SCF_ERROR_CONSTRAINT_VIOLATED:
9836 			if (g_verbose) {
9837 				if (scf_property_to_fmri(exp_prop, fmri,
9838 				    max_scf_fmri_len + 2) < 0)
9839 					scfdie();
9840 
9841 				warn(gettext("The value of %s does not specify "
9842 				    "a service or an instance.\n"), fmri);
9843 			}
9844 
9845 			export_property(exp_prop, exp_str, &pgelts,
9846 			    SCE_ALL_VALUES);
9847 			continue;
9848 
9849 		case SCF_ERROR_NOT_FOUND:
9850 			if (g_verbose) {
9851 				if (scf_property_to_fmri(exp_prop, fmri,
9852 				    max_scf_fmri_len + 2) < 0)
9853 					scfdie();
9854 
9855 				warn(gettext("The entity specified by %s does "
9856 				    "not exist.\n"), fmri);
9857 			}
9858 
9859 			export_property(exp_prop, exp_str, &pgelts,
9860 			    SCE_ALL_VALUES);
9861 			continue;
9862 
9863 		default:
9864 #ifndef NDEBUG
9865 			(void) fprintf(stderr, "%s:%d: %s() failed with "
9866 			    "unexpected error %d.\n", __FILE__, __LINE__,
9867 			    "fmri_to_entity", serr);
9868 #endif
9869 			abort();
9870 		}
9871 
9872 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
9873 			if (scf_error() != SCF_ERROR_NOT_FOUND)
9874 				scfdie();
9875 
9876 			warn(gettext("Entity %s is missing dependency property "
9877 			    "group %s.\n"), fmri, exp_str);
9878 
9879 			export_property(exp_prop, NULL, &pgelts,
9880 			    SCE_ALL_VALUES);
9881 			continue;
9882 		}
9883 
9884 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
9885 			scfdie();
9886 
9887 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
9888 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
9889 				scfdie();
9890 
9891 			warn(gettext("Property group %s is not of "
9892 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
9893 
9894 			export_property(exp_prop, NULL, &pgelts,
9895 			    SCE_ALL_VALUES);
9896 			continue;
9897 		}
9898 
9899 		n = export_dependent(opg, exp_str, fmri);
9900 		if (n == NULL) {
9901 			export_property(exp_prop, exp_str, &pgelts,
9902 			    SCE_ALL_VALUES);
9903 		} else {
9904 			if (eelts->dependents == NULL)
9905 				eelts->dependents = n;
9906 			else
9907 				(void) xmlAddSibling(eelts->dependents,
9908 				    n);
9909 		}
9910 	}
9911 	if (ret == -1)
9912 		scfdie();
9913 
9914 	free(fmri);
9915 	free(type);
9916 
9917 	scf_iter_destroy(iter);
9918 	scf_pg_destroy(opg);
9919 
9920 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
9921 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
9922 		    eelts);
9923 }
9924 
9925 static void
9926 make_node(xmlNodePtr *nodep, const char *name)
9927 {
9928 	if (*nodep == NULL) {
9929 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
9930 		if (*nodep == NULL)
9931 			uu_die(emsg_create_xml);
9932 	}
9933 }
9934 
9935 static xmlNodePtr
9936 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
9937 {
9938 	int ret;
9939 	xmlNodePtr parent = NULL;
9940 	xmlNodePtr loctext = NULL;
9941 
9942 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
9943 		scfdie();
9944 
9945 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
9946 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
9947 		    prop_get_val(exp_prop, exp_val) != 0)
9948 			continue;
9949 
9950 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
9951 			scfdie();
9952 
9953 		make_node(&parent, parname);
9954 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
9955 		    (xmlChar *)exp_str);
9956 		if (loctext == NULL)
9957 			uu_die(emsg_create_xml);
9958 
9959 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
9960 			scfdie();
9961 
9962 		safe_setprop(loctext, "xml:lang", exp_str);
9963 	}
9964 
9965 	if (ret == -1)
9966 		scfdie();
9967 
9968 	return (parent);
9969 }
9970 
9971 static xmlNodePtr
9972 export_tm_manpage(scf_propertygroup_t *pg)
9973 {
9974 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
9975 	if (manpage == NULL)
9976 		uu_die(emsg_create_xml);
9977 
9978 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
9979 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
9980 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
9981 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
9982 		xmlFreeNode(manpage);
9983 		return (NULL);
9984 	}
9985 
9986 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
9987 		(void) set_attr_from_prop_default(exp_prop,
9988 		    manpage, "manpath", ":default");
9989 
9990 	return (manpage);
9991 }
9992 
9993 static xmlNodePtr
9994 export_tm_doc_link(scf_propertygroup_t *pg)
9995 {
9996 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
9997 	if (doc_link == NULL)
9998 		uu_die(emsg_create_xml);
9999 
10000 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
10001 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
10002 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
10003 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
10004 		xmlFreeNode(doc_link);
10005 		return (NULL);
10006 	}
10007 	return (doc_link);
10008 }
10009 
10010 /*
10011  * Process template information for a service or instances.
10012  */
10013 static void
10014 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
10015     struct template_elts *telts)
10016 {
10017 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
10018 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
10019 	xmlNodePtr child = NULL;
10020 
10021 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
10022 		scfdie();
10023 
10024 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
10025 		telts->common_name = export_tm_loctext(pg, "common_name");
10026 		if (telts->common_name == NULL)
10027 			export_pg(pg, elts, SCE_ALL_VALUES);
10028 		return;
10029 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
10030 		telts->description = export_tm_loctext(pg, "description");
10031 		if (telts->description == NULL)
10032 			export_pg(pg, elts, SCE_ALL_VALUES);
10033 		return;
10034 	}
10035 
10036 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
10037 		child = export_tm_manpage(pg);
10038 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
10039 		child = export_tm_doc_link(pg);
10040 	}
10041 
10042 	if (child != NULL) {
10043 		make_node(&telts->documentation, "documentation");
10044 		(void) xmlAddChild(telts->documentation, child);
10045 	} else {
10046 		export_pg(pg, elts, SCE_ALL_VALUES);
10047 	}
10048 }
10049 
10050 /*
10051  * Process parameter and paramval elements
10052  */
10053 static void
10054 export_parameter(scf_property_t *prop, const char *name,
10055     struct params_elts *elts)
10056 {
10057 	xmlNodePtr param;
10058 	scf_error_t err = 0;
10059 	int ret;
10060 
10061 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
10062 		if ((param = xmlNewNode(NULL, (xmlChar *)"paramval")) == NULL)
10063 			uu_die(emsg_create_xml);
10064 
10065 		safe_setprop(param, name_attr, name);
10066 
10067 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
10068 			scfdie();
10069 		safe_setprop(param, value_attr, exp_str);
10070 
10071 		if (elts->paramval == NULL)
10072 			elts->paramval = param;
10073 		else
10074 			(void) xmlAddSibling(elts->paramval, param);
10075 
10076 		return;
10077 	}
10078 
10079 	err = scf_error();
10080 
10081 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
10082 	    err != SCF_ERROR_NOT_FOUND)
10083 		scfdie();
10084 
10085 	if ((param = xmlNewNode(NULL, (xmlChar *)"parameter")) == NULL)
10086 		uu_die(emsg_create_xml);
10087 
10088 	safe_setprop(param, name_attr, name);
10089 
10090 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
10091 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
10092 			scfdie();
10093 
10094 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
10095 		    1) {
10096 			xmlNodePtr vn;
10097 
10098 			if ((vn = xmlNewChild(param, NULL,
10099 			    (xmlChar *)"value_node", NULL)) == NULL)
10100 				uu_die(emsg_create_xml);
10101 
10102 			if (scf_value_get_as_string(exp_val, exp_str,
10103 			    exp_str_sz) < 0)
10104 				scfdie();
10105 
10106 			safe_setprop(vn, value_attr, exp_str);
10107 		}
10108 		if (ret != 0)
10109 			scfdie();
10110 	}
10111 
10112 	if (elts->parameter == NULL)
10113 		elts->parameter = param;
10114 	else
10115 		(void) xmlAddSibling(elts->parameter, param);
10116 }
10117 
10118 /*
10119  * Process notification parameters for a service or instance
10120  */
10121 static void
10122 export_notify_params(scf_propertygroup_t *pg, struct entity_elts *elts)
10123 {
10124 	xmlNodePtr n, event, *type;
10125 	struct params_elts *eelts;
10126 	int ret, err, i;
10127 
10128 	n = xmlNewNode(NULL, (xmlChar *)"notification_parameters");
10129 	event = xmlNewNode(NULL, (xmlChar *)"event");
10130 	if (n == NULL || event == NULL)
10131 		uu_die(emsg_create_xml);
10132 
10133 	/* event value */
10134 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
10135 		scfdie();
10136 	safe_setprop(event, value_attr, exp_str);
10137 
10138 	(void) xmlAddChild(n, event);
10139 
10140 	if ((type = calloc(URI_SCHEME_NUM, sizeof (xmlNodePtr))) == NULL ||
10141 	    (eelts = calloc(URI_SCHEME_NUM,
10142 	    sizeof (struct params_elts))) == NULL)
10143 		uu_die(gettext("Out of memory.\n"));
10144 
10145 	err = 0;
10146 
10147 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10148 		scfdie();
10149 
10150 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10151 		char *t, *p;
10152 
10153 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10154 			scfdie();
10155 
10156 		if ((t = strtok_r(exp_str, ",", &p)) == NULL || p == NULL) {
10157 			/*
10158 			 * this is not a well formed notification parameters
10159 			 * element, we should export as regular pg
10160 			 */
10161 			err = 1;
10162 			break;
10163 		}
10164 
10165 		if ((i = check_uri_protocol(t)) < 0) {
10166 			err = 1;
10167 			break;
10168 		}
10169 
10170 		if (type[i] == NULL) {
10171 			if ((type[i] = xmlNewNode(NULL, (xmlChar *)"type")) ==
10172 			    NULL)
10173 				uu_die(emsg_create_xml);
10174 
10175 			safe_setprop(type[i], name_attr, t);
10176 		}
10177 		if (strcmp(p, active_attr) == 0) {
10178 			if (set_attr_from_prop(exp_prop, type[i],
10179 			    active_attr) != 0) {
10180 				err = 1;
10181 				break;
10182 			}
10183 			continue;
10184 		}
10185 		/*
10186 		 * We export the parameter
10187 		 */
10188 		export_parameter(exp_prop, p, &eelts[i]);
10189 	}
10190 
10191 	if (ret == -1)
10192 		scfdie();
10193 
10194 	if (err == 1) {
10195 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10196 			xmlFree(type[i]);
10197 		free(type);
10198 
10199 		export_pg(pg, elts, SCE_ALL_VALUES);
10200 
10201 		return;
10202 	} else {
10203 		for (i = 0; i < URI_SCHEME_NUM; ++i)
10204 			if (type[i] != NULL) {
10205 				(void) xmlAddChildList(type[i],
10206 				    eelts[i].paramval);
10207 				(void) xmlAddChildList(type[i],
10208 				    eelts[i].parameter);
10209 				(void) xmlAddSibling(event, type[i]);
10210 			}
10211 	}
10212 	free(type);
10213 
10214 	if (elts->notify_params == NULL)
10215 		elts->notify_params = n;
10216 	else
10217 		(void) xmlAddSibling(elts->notify_params, n);
10218 }
10219 
10220 /*
10221  * Process the general property group for an instance.
10222  */
10223 static void
10224 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
10225     struct entity_elts *elts)
10226 {
10227 	uint8_t enabled;
10228 	struct pg_elts pgelts;
10229 	int ret;
10230 
10231 	/* enabled */
10232 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
10233 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
10234 	    prop_get_val(exp_prop, exp_val) == 0) {
10235 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
10236 			scfdie();
10237 	} else {
10238 		enabled = 0;
10239 	}
10240 
10241 	safe_setprop(inode, enabled_attr, enabled ? true : false);
10242 
10243 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
10244 		scfdie();
10245 
10246 	(void) memset(&pgelts, 0, sizeof (pgelts));
10247 
10248 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
10249 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
10250 			scfdie();
10251 
10252 		if (strcmp(exp_str, scf_property_enabled) == 0) {
10253 			continue;
10254 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
10255 			xmlNodePtr rnode, sfnode;
10256 
10257 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
10258 			if (rnode == NULL)
10259 				uu_die(emsg_create_xml);
10260 
10261 			sfnode = xmlNewChild(rnode, NULL,
10262 			    (xmlChar *)"service_fmri", NULL);
10263 			if (sfnode == NULL)
10264 				uu_die(emsg_create_xml);
10265 
10266 			if (set_attr_from_prop(exp_prop, sfnode,
10267 			    value_attr) == 0) {
10268 				elts->restarter = rnode;
10269 				continue;
10270 			}
10271 
10272 			xmlFreeNode(rnode);
10273 		}
10274 
10275 		export_property(exp_prop, exp_str, &pgelts, SCE_ALL_VALUES);
10276 	}
10277 	if (ret == -1)
10278 		scfdie();
10279 
10280 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
10281 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
10282 		    elts);
10283 }
10284 
10285 /*
10286  * Put an instance element for the given instance into selts.
10287  */
10288 static void
10289 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
10290 {
10291 	xmlNodePtr n;
10292 	boolean_t isdefault;
10293 	struct entity_elts elts;
10294 	struct template_elts template_elts;
10295 	int ret;
10296 
10297 	n = xmlNewNode(NULL, (xmlChar *)"instance");
10298 	if (n == NULL)
10299 		uu_die(emsg_create_xml);
10300 
10301 	/* name */
10302 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
10303 		scfdie();
10304 	safe_setprop(n, name_attr, exp_str);
10305 	isdefault = strcmp(exp_str, "default") == 0;
10306 
10307 	/* check existance of general pg (since general/enabled is required) */
10308 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
10309 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10310 			scfdie();
10311 
10312 		if (g_verbose) {
10313 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
10314 				scfdie();
10315 
10316 			warn(gettext("Instance %s has no general property "
10317 			    "group; it will be marked disabled.\n"), exp_str);
10318 		}
10319 
10320 		safe_setprop(n, enabled_attr, false);
10321 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
10322 	    strcmp(exp_str, scf_group_framework) != 0) {
10323 		if (g_verbose) {
10324 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
10325 				scfdie();
10326 
10327 			warn(gettext("Property group %s is not of type "
10328 			    "framework; the instance will be marked "
10329 			    "disabled.\n"), exp_str);
10330 		}
10331 
10332 		safe_setprop(n, enabled_attr, false);
10333 	}
10334 
10335 	/* property groups */
10336 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
10337 		scfdie();
10338 
10339 	(void) memset(&elts, 0, sizeof (elts));
10340 	(void) memset(&template_elts, 0, sizeof (template_elts));
10341 
10342 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10343 		uint32_t pgflags;
10344 
10345 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10346 			scfdie();
10347 
10348 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10349 			continue;
10350 
10351 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10352 			scfdie();
10353 
10354 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10355 			export_dependency(exp_pg, &elts);
10356 			continue;
10357 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10358 			export_method(exp_pg, &elts);
10359 			continue;
10360 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10361 			if (scf_pg_get_name(exp_pg, exp_str,
10362 			    max_scf_name_len + 1) < 0)
10363 				scfdie();
10364 
10365 			if (strcmp(exp_str, scf_pg_general) == 0) {
10366 				export_inst_general(exp_pg, n, &elts);
10367 				continue;
10368 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10369 			    0) {
10370 				export_method_context(exp_pg, &elts);
10371 				continue;
10372 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10373 				export_dependents(exp_pg, &elts);
10374 				continue;
10375 			}
10376 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10377 			export_template(exp_pg, &elts, &template_elts);
10378 			continue;
10379 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10380 			export_notify_params(exp_pg, &elts);
10381 			continue;
10382 		}
10383 
10384 		/* Ordinary pg. */
10385 		export_pg(exp_pg, &elts, flags);
10386 	}
10387 	if (ret == -1)
10388 		scfdie();
10389 
10390 	if (template_elts.common_name != NULL) {
10391 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10392 		(void) xmlAddChild(elts.template, template_elts.common_name);
10393 		(void) xmlAddChild(elts.template, template_elts.description);
10394 		(void) xmlAddChild(elts.template, template_elts.documentation);
10395 	} else {
10396 		xmlFreeNode(template_elts.description);
10397 		xmlFreeNode(template_elts.documentation);
10398 	}
10399 
10400 	if (isdefault && elts.restarter == NULL &&
10401 	    elts.dependencies == NULL && elts.method_context == NULL &&
10402 	    elts.exec_methods == NULL && elts.notify_params == NULL &&
10403 	    elts.property_groups == NULL && elts.template == NULL) {
10404 		xmlChar *eval;
10405 
10406 		/* This is a default instance */
10407 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
10408 
10409 		xmlFreeNode(n);
10410 
10411 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
10412 		if (n == NULL)
10413 			uu_die(emsg_create_xml);
10414 
10415 		safe_setprop(n, enabled_attr, (char *)eval);
10416 		xmlFree(eval);
10417 
10418 		selts->create_default_instance = n;
10419 	} else {
10420 		/* Assemble the children in order. */
10421 		(void) xmlAddChild(n, elts.restarter);
10422 		(void) xmlAddChildList(n, elts.dependencies);
10423 		(void) xmlAddChildList(n, elts.dependents);
10424 		(void) xmlAddChild(n, elts.method_context);
10425 		(void) xmlAddChildList(n, elts.exec_methods);
10426 		(void) xmlAddChildList(n, elts.notify_params);
10427 		(void) xmlAddChildList(n, elts.property_groups);
10428 		(void) xmlAddChild(n, elts.template);
10429 
10430 		if (selts->instances == NULL)
10431 			selts->instances = n;
10432 		else
10433 			(void) xmlAddSibling(selts->instances, n);
10434 	}
10435 }
10436 
10437 /*
10438  * Return a service element for the given service.
10439  */
10440 static xmlNodePtr
10441 export_service(scf_service_t *svc, int flags)
10442 {
10443 	xmlNodePtr snode;
10444 	struct entity_elts elts;
10445 	struct template_elts template_elts;
10446 	int ret;
10447 
10448 	snode = xmlNewNode(NULL, (xmlChar *)"service");
10449 	if (snode == NULL)
10450 		uu_die(emsg_create_xml);
10451 
10452 	/* Get & set name attribute */
10453 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
10454 		scfdie();
10455 	safe_setprop(snode, name_attr, exp_str);
10456 
10457 	safe_setprop(snode, type_attr, "service");
10458 	safe_setprop(snode, "version", "0");
10459 
10460 	/* Acquire child elements. */
10461 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
10462 		scfdie();
10463 
10464 	(void) memset(&elts, 0, sizeof (elts));
10465 	(void) memset(&template_elts, 0, sizeof (template_elts));
10466 
10467 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
10468 		uint32_t pgflags;
10469 
10470 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
10471 			scfdie();
10472 
10473 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
10474 			continue;
10475 
10476 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
10477 			scfdie();
10478 
10479 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
10480 			export_dependency(exp_pg, &elts);
10481 			continue;
10482 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
10483 			export_method(exp_pg, &elts);
10484 			continue;
10485 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
10486 			if (scf_pg_get_name(exp_pg, exp_str,
10487 			    max_scf_name_len + 1) < 0)
10488 				scfdie();
10489 
10490 			if (strcmp(exp_str, scf_pg_general) == 0) {
10491 				export_svc_general(exp_pg, &elts);
10492 				continue;
10493 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
10494 			    0) {
10495 				export_method_context(exp_pg, &elts);
10496 				continue;
10497 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
10498 				export_dependents(exp_pg, &elts);
10499 				continue;
10500 			} else if (strcmp(exp_str, SCF_PG_MANIFESTFILES) == 0) {
10501 				continue;
10502 			}
10503 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
10504 			export_template(exp_pg, &elts, &template_elts);
10505 			continue;
10506 		} else if (strcmp(exp_str, SCF_NOTIFY_PARAMS_PG_TYPE) == 0) {
10507 			export_notify_params(exp_pg, &elts);
10508 			continue;
10509 		}
10510 
10511 		export_pg(exp_pg, &elts, flags);
10512 	}
10513 	if (ret == -1)
10514 		scfdie();
10515 
10516 	if (template_elts.common_name != NULL) {
10517 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
10518 		(void) xmlAddChild(elts.template, template_elts.common_name);
10519 		(void) xmlAddChild(elts.template, template_elts.description);
10520 		(void) xmlAddChild(elts.template, template_elts.documentation);
10521 	} else {
10522 		xmlFreeNode(template_elts.description);
10523 		xmlFreeNode(template_elts.documentation);
10524 	}
10525 
10526 	/* Iterate instances */
10527 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
10528 		scfdie();
10529 
10530 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
10531 		export_instance(exp_inst, &elts, flags);
10532 	if (ret == -1)
10533 		scfdie();
10534 
10535 	/* Now add all of the accumulated elements in order. */
10536 	(void) xmlAddChild(snode, elts.create_default_instance);
10537 	(void) xmlAddChild(snode, elts.single_instance);
10538 	(void) xmlAddChild(snode, elts.restarter);
10539 	(void) xmlAddChildList(snode, elts.dependencies);
10540 	(void) xmlAddChildList(snode, elts.dependents);
10541 	(void) xmlAddChild(snode, elts.method_context);
10542 	(void) xmlAddChildList(snode, elts.exec_methods);
10543 	(void) xmlAddChildList(snode, elts.notify_params);
10544 	(void) xmlAddChildList(snode, elts.property_groups);
10545 	(void) xmlAddChildList(snode, elts.instances);
10546 	(void) xmlAddChild(snode, elts.stability);
10547 	(void) xmlAddChild(snode, elts.template);
10548 
10549 	return (snode);
10550 }
10551 
10552 static int
10553 export_callback(void *data, scf_walkinfo_t *wip)
10554 {
10555 	FILE *f;
10556 	xmlDocPtr doc;
10557 	xmlNodePtr sb;
10558 	int result;
10559 	struct export_args *argsp = (struct export_args *)data;
10560 
10561 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
10562 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10563 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10564 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10565 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10566 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10567 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10568 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10569 		scfdie();
10570 
10571 	exp_str_sz = max_scf_len + 1;
10572 	exp_str = safe_malloc(exp_str_sz);
10573 
10574 	if (argsp->filename != NULL) {
10575 		errno = 0;
10576 		f = fopen(argsp->filename, "wb");
10577 		if (f == NULL) {
10578 			if (errno == 0)
10579 				uu_die(gettext("Could not open \"%s\": no free "
10580 				    "stdio streams.\n"), argsp->filename);
10581 			else
10582 				uu_die(gettext("Could not open \"%s\""),
10583 				    argsp->filename);
10584 		}
10585 	} else
10586 		f = stdout;
10587 
10588 	doc = xmlNewDoc((xmlChar *)"1.0");
10589 	if (doc == NULL)
10590 		uu_die(gettext("Could not create XML document.\n"));
10591 
10592 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10593 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10594 		uu_die(emsg_create_xml);
10595 
10596 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10597 	if (sb == NULL)
10598 		uu_die(emsg_create_xml);
10599 	safe_setprop(sb, type_attr, "manifest");
10600 	safe_setprop(sb, name_attr, "export");
10601 	(void) xmlAddSibling(doc->children, sb);
10602 
10603 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
10604 
10605 	result = write_service_bundle(doc, f);
10606 
10607 	free(exp_str);
10608 	scf_iter_destroy(exp_val_iter);
10609 	scf_iter_destroy(exp_prop_iter);
10610 	scf_iter_destroy(exp_pg_iter);
10611 	scf_iter_destroy(exp_inst_iter);
10612 	scf_value_destroy(exp_val);
10613 	scf_property_destroy(exp_prop);
10614 	scf_pg_destroy(exp_pg);
10615 	scf_instance_destroy(exp_inst);
10616 
10617 	xmlFreeDoc(doc);
10618 
10619 	if (f != stdout)
10620 		(void) fclose(f);
10621 
10622 	return (result);
10623 }
10624 
10625 /*
10626  * Get the service named by fmri, build an XML tree which represents it, and
10627  * dump it into filename (or stdout if filename is NULL).
10628  */
10629 int
10630 lscf_service_export(char *fmri, const char *filename, int flags)
10631 {
10632 	struct export_args args;
10633 	char *fmridup;
10634 	const char *scope, *svc, *inst;
10635 	size_t cblen = 3 * max_scf_name_len;
10636 	char *canonbuf = alloca(cblen);
10637 	int ret, err;
10638 
10639 	lscf_prep_hndl();
10640 
10641 	bzero(&args, sizeof (args));
10642 	args.filename = filename;
10643 	args.flags = flags;
10644 
10645 	/*
10646 	 * If some poor user has passed an exact instance FMRI, of the sort
10647 	 * one might cut and paste from svcs(1) or an error message, warn
10648 	 * and chop off the instance instead of failing.
10649 	 */
10650 	fmridup = alloca(strlen(fmri) + 1);
10651 	(void) strcpy(fmridup, fmri);
10652 	if (strncmp(fmridup, SCF_FMRI_SVC_PREFIX,
10653 	    sizeof (SCF_FMRI_SVC_PREFIX) -1) == 0 &&
10654 	    scf_parse_svc_fmri(fmridup, &scope, &svc, &inst, NULL, NULL) == 0 &&
10655 	    inst != NULL) {
10656 		(void) strlcpy(canonbuf, "svc:/", cblen);
10657 		if (strcmp(scope, SCF_FMRI_LOCAL_SCOPE) != 0) {
10658 			(void) strlcat(canonbuf, "/", cblen);
10659 			(void) strlcat(canonbuf, scope, cblen);
10660 		}
10661 		(void) strlcat(canonbuf, svc, cblen);
10662 		fmri = canonbuf;
10663 
10664 		warn(gettext("Only services may be exported; ignoring "
10665 		    "instance portion of argument.\n"));
10666 	}
10667 
10668 	err = 0;
10669 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10670 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10671 	    &args, &err, semerr)) != 0) {
10672 		if (ret != -1)
10673 			semerr(gettext("Failed to walk instances: %s\n"),
10674 			    scf_strerror(ret));
10675 		return (-1);
10676 	}
10677 
10678 	/*
10679 	 * Error message has already been printed.
10680 	 */
10681 	if (err != 0)
10682 		return (-1);
10683 
10684 	return (0);
10685 }
10686 
10687 
10688 /*
10689  * Archive
10690  */
10691 
10692 static xmlNodePtr
10693 make_archive(int flags)
10694 {
10695 	xmlNodePtr sb;
10696 	scf_scope_t *scope;
10697 	scf_service_t *svc;
10698 	scf_iter_t *iter;
10699 	int r;
10700 
10701 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10702 	    (svc = scf_service_create(g_hndl)) == NULL ||
10703 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10704 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10705 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10706 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10707 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10708 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10709 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10710 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10711 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10712 		scfdie();
10713 
10714 	exp_str_sz = max_scf_len + 1;
10715 	exp_str = safe_malloc(exp_str_sz);
10716 
10717 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10718 	if (sb == NULL)
10719 		uu_die(emsg_create_xml);
10720 	safe_setprop(sb, type_attr, "archive");
10721 	safe_setprop(sb, name_attr, "none");
10722 
10723 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10724 		scfdie();
10725 	if (scf_iter_scope_services(iter, scope) != 0)
10726 		scfdie();
10727 
10728 	for (;;) {
10729 		r = scf_iter_next_service(iter, svc);
10730 		if (r == 0)
10731 			break;
10732 		if (r != 1)
10733 			scfdie();
10734 
10735 		if (scf_service_get_name(svc, exp_str,
10736 		    max_scf_name_len + 1) < 0)
10737 			scfdie();
10738 
10739 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10740 			continue;
10741 
10742 		(void) xmlAddChild(sb, export_service(svc, flags));
10743 	}
10744 
10745 	free(exp_str);
10746 
10747 	scf_iter_destroy(exp_val_iter);
10748 	scf_iter_destroy(exp_prop_iter);
10749 	scf_iter_destroy(exp_pg_iter);
10750 	scf_iter_destroy(exp_inst_iter);
10751 	scf_value_destroy(exp_val);
10752 	scf_property_destroy(exp_prop);
10753 	scf_pg_destroy(exp_pg);
10754 	scf_instance_destroy(exp_inst);
10755 	scf_iter_destroy(iter);
10756 	scf_service_destroy(svc);
10757 	scf_scope_destroy(scope);
10758 
10759 	return (sb);
10760 }
10761 
10762 int
10763 lscf_archive(const char *filename, int flags)
10764 {
10765 	FILE *f;
10766 	xmlDocPtr doc;
10767 	int result;
10768 
10769 	lscf_prep_hndl();
10770 
10771 	if (filename != NULL) {
10772 		errno = 0;
10773 		f = fopen(filename, "wb");
10774 		if (f == NULL) {
10775 			if (errno == 0)
10776 				uu_die(gettext("Could not open \"%s\": no free "
10777 				    "stdio streams.\n"), filename);
10778 			else
10779 				uu_die(gettext("Could not open \"%s\""),
10780 				    filename);
10781 		}
10782 	} else
10783 		f = stdout;
10784 
10785 	doc = xmlNewDoc((xmlChar *)"1.0");
10786 	if (doc == NULL)
10787 		uu_die(gettext("Could not create XML document.\n"));
10788 
10789 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10790 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10791 		uu_die(emsg_create_xml);
10792 
10793 	(void) xmlAddSibling(doc->children, make_archive(flags));
10794 
10795 	result = write_service_bundle(doc, f);
10796 
10797 	xmlFreeDoc(doc);
10798 
10799 	if (f != stdout)
10800 		(void) fclose(f);
10801 
10802 	return (result);
10803 }
10804 
10805 
10806 /*
10807  * "Extract" a profile.
10808  */
10809 int
10810 lscf_profile_extract(const char *filename)
10811 {
10812 	FILE *f;
10813 	xmlDocPtr doc;
10814 	xmlNodePtr sb, snode, inode;
10815 	scf_scope_t *scope;
10816 	scf_service_t *svc;
10817 	scf_instance_t *inst;
10818 	scf_propertygroup_t *pg;
10819 	scf_property_t *prop;
10820 	scf_value_t *val;
10821 	scf_iter_t *siter, *iiter;
10822 	int r, s;
10823 	char *namebuf;
10824 	uint8_t b;
10825 	int result;
10826 
10827 	lscf_prep_hndl();
10828 
10829 	if (filename != NULL) {
10830 		errno = 0;
10831 		f = fopen(filename, "wb");
10832 		if (f == NULL) {
10833 			if (errno == 0)
10834 				uu_die(gettext("Could not open \"%s\": no "
10835 				    "free stdio streams.\n"), filename);
10836 			else
10837 				uu_die(gettext("Could not open \"%s\""),
10838 				    filename);
10839 		}
10840 	} else
10841 		f = stdout;
10842 
10843 	doc = xmlNewDoc((xmlChar *)"1.0");
10844 	if (doc == NULL)
10845 		uu_die(gettext("Could not create XML document.\n"));
10846 
10847 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10848 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10849 		uu_die(emsg_create_xml);
10850 
10851 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10852 	if (sb == NULL)
10853 		uu_die(emsg_create_xml);
10854 	safe_setprop(sb, type_attr, "profile");
10855 	safe_setprop(sb, name_attr, "extract");
10856 	(void) xmlAddSibling(doc->children, sb);
10857 
10858 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10859 	    (svc = scf_service_create(g_hndl)) == NULL ||
10860 	    (inst = scf_instance_create(g_hndl)) == NULL ||
10861 	    (pg = scf_pg_create(g_hndl)) == NULL ||
10862 	    (prop = scf_property_create(g_hndl)) == NULL ||
10863 	    (val = scf_value_create(g_hndl)) == NULL ||
10864 	    (siter = scf_iter_create(g_hndl)) == NULL ||
10865 	    (iiter = scf_iter_create(g_hndl)) == NULL)
10866 		scfdie();
10867 
10868 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
10869 		scfdie();
10870 
10871 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
10872 		scfdie();
10873 
10874 	namebuf = safe_malloc(max_scf_name_len + 1);
10875 
10876 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
10877 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
10878 			scfdie();
10879 
10880 		snode = xmlNewNode(NULL, (xmlChar *)"service");
10881 		if (snode == NULL)
10882 			uu_die(emsg_create_xml);
10883 
10884 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
10885 		    0)
10886 			scfdie();
10887 
10888 		safe_setprop(snode, name_attr, namebuf);
10889 
10890 		safe_setprop(snode, type_attr, "service");
10891 		safe_setprop(snode, "version", "0");
10892 
10893 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
10894 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
10895 			    SCF_SUCCESS) {
10896 				if (scf_error() != SCF_ERROR_NOT_FOUND)
10897 					scfdie();
10898 
10899 				if (g_verbose) {
10900 					ssize_t len;
10901 					char *fmri;
10902 
10903 					len =
10904 					    scf_instance_to_fmri(inst, NULL, 0);
10905 					if (len < 0)
10906 						scfdie();
10907 
10908 					fmri = safe_malloc(len + 1);
10909 
10910 					if (scf_instance_to_fmri(inst, fmri,
10911 					    len + 1) < 0)
10912 						scfdie();
10913 
10914 					warn("Instance %s has no \"%s\" "
10915 					    "property group.\n", fmri,
10916 					    scf_pg_general);
10917 
10918 					free(fmri);
10919 				}
10920 
10921 				continue;
10922 			}
10923 
10924 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
10925 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
10926 			    prop_get_val(prop, val) != 0)
10927 				continue;
10928 
10929 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
10930 			    NULL);
10931 			if (inode == NULL)
10932 				uu_die(emsg_create_xml);
10933 
10934 			if (scf_instance_get_name(inst, namebuf,
10935 			    max_scf_name_len + 1) < 0)
10936 				scfdie();
10937 
10938 			safe_setprop(inode, name_attr, namebuf);
10939 
10940 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
10941 				scfdie();
10942 
10943 			safe_setprop(inode, enabled_attr, b ? true : false);
10944 		}
10945 		if (s < 0)
10946 			scfdie();
10947 
10948 		if (snode->children != NULL)
10949 			(void) xmlAddChild(sb, snode);
10950 		else
10951 			xmlFreeNode(snode);
10952 	}
10953 	if (r < 0)
10954 		scfdie();
10955 
10956 	free(namebuf);
10957 
10958 	result = write_service_bundle(doc, f);
10959 
10960 	xmlFreeDoc(doc);
10961 
10962 	if (f != stdout)
10963 		(void) fclose(f);
10964 
10965 	return (result);
10966 }
10967 
10968 
10969 /*
10970  * Entity manipulation commands
10971  */
10972 
10973 /*
10974  * Entity selection.  If no entity is selected, then the current scope is in
10975  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
10976  * only cur_inst is NULL, and when an instance is selected, none are NULL.
10977  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
10978  * cur_inst will be non-NULL.
10979  */
10980 
10981 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
10982 static int
10983 select_inst(const char *name)
10984 {
10985 	scf_instance_t *inst;
10986 	scf_error_t err;
10987 
10988 	assert(cur_svc != NULL);
10989 
10990 	inst = scf_instance_create(g_hndl);
10991 	if (inst == NULL)
10992 		scfdie();
10993 
10994 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10995 		cur_inst = inst;
10996 		return (0);
10997 	}
10998 
10999 	err = scf_error();
11000 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11001 		scfdie();
11002 
11003 	scf_instance_destroy(inst);
11004 	return (1);
11005 }
11006 
11007 /* Returns as above. */
11008 static int
11009 select_svc(const char *name)
11010 {
11011 	scf_service_t *svc;
11012 	scf_error_t err;
11013 
11014 	assert(cur_scope != NULL);
11015 
11016 	svc = scf_service_create(g_hndl);
11017 	if (svc == NULL)
11018 		scfdie();
11019 
11020 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
11021 		cur_svc = svc;
11022 		return (0);
11023 	}
11024 
11025 	err = scf_error();
11026 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11027 		scfdie();
11028 
11029 	scf_service_destroy(svc);
11030 	return (1);
11031 }
11032 
11033 /* ARGSUSED */
11034 static int
11035 select_callback(void *unused, scf_walkinfo_t *wip)
11036 {
11037 	scf_instance_t *inst;
11038 	scf_service_t *svc;
11039 	scf_scope_t *scope;
11040 
11041 	if (wip->inst != NULL) {
11042 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11043 		    (svc = scf_service_create(g_hndl)) == NULL ||
11044 		    (inst = scf_instance_create(g_hndl)) == NULL)
11045 			scfdie();
11046 
11047 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11048 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11049 			scfdie();
11050 	} else {
11051 		assert(wip->svc != NULL);
11052 
11053 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11054 		    (svc = scf_service_create(g_hndl)) == NULL)
11055 			scfdie();
11056 
11057 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11058 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11059 			scfdie();
11060 
11061 		inst = NULL;
11062 	}
11063 
11064 	/* Clear out the current selection */
11065 	assert(cur_scope != NULL);
11066 	scf_scope_destroy(cur_scope);
11067 	scf_service_destroy(cur_svc);
11068 	scf_instance_destroy(cur_inst);
11069 
11070 	cur_scope = scope;
11071 	cur_svc = svc;
11072 	cur_inst = inst;
11073 
11074 	return (0);
11075 }
11076 
11077 static int
11078 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11079 {
11080 	char **fmri = fmri_p;
11081 
11082 	*fmri = strdup(wip->fmri);
11083 	if (*fmri == NULL)
11084 		uu_die(gettext("Out of memory.\n"));
11085 
11086 	return (0);
11087 }
11088 
11089 /*
11090  * validate [fmri]
11091  * Perform the validation of an FMRI instance.
11092  */
11093 void
11094 lscf_validate_fmri(const char *fmri)
11095 {
11096 	int ret = 0;
11097 	size_t inst_sz;
11098 	char *inst_fmri = NULL;
11099 	scf_tmpl_errors_t *errs = NULL;
11100 	char *snapbuf = NULL;
11101 
11102 	lscf_prep_hndl();
11103 
11104 	if (fmri == NULL) {
11105 		inst_sz = max_scf_fmri_len + 1;
11106 		inst_fmri = safe_malloc(inst_sz);
11107 
11108 		if (cur_snap != NULL) {
11109 			snapbuf = safe_malloc(max_scf_name_len + 1);
11110 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11111 			    max_scf_name_len + 1) < 0)
11112 				scfdie();
11113 		}
11114 		if (cur_inst == NULL) {
11115 			semerr(gettext("No instance selected\n"));
11116 			goto cleanup;
11117 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11118 		    inst_sz) >= inst_sz) {
11119 			/* sanity check. Should never get here */
11120 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11121 			    __FILE__, __LINE__);
11122 		}
11123 	} else {
11124 		scf_error_t scf_err;
11125 		int err = 0;
11126 
11127 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11128 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11129 			uu_warn("Failed to walk instances: %s\n",
11130 			    scf_strerror(scf_err));
11131 			goto cleanup;
11132 		}
11133 		if (err != 0) {
11134 			/* error message displayed by scf_walk_fmri */
11135 			goto cleanup;
11136 		}
11137 	}
11138 
11139 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11140 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11141 	if (ret == -1) {
11142 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11143 			warn(gettext("Template data for %s is invalid. "
11144 			    "Consider reverting to a previous snapshot or "
11145 			    "restoring original configuration.\n"), inst_fmri);
11146 		} else {
11147 			uu_warn("%s: %s\n",
11148 			    gettext("Error validating the instance"),
11149 			    scf_strerror(scf_error()));
11150 		}
11151 	} else if (ret == 1 && errs != NULL) {
11152 		scf_tmpl_error_t *err = NULL;
11153 		char *msg;
11154 		size_t len = 256;	/* initial error buffer size */
11155 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11156 		    SCF_TMPL_STRERROR_HUMAN : 0;
11157 
11158 		msg = safe_malloc(len);
11159 
11160 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11161 			int ret;
11162 
11163 			if ((ret = scf_tmpl_strerror(err, msg, len,
11164 			    flag)) >= len) {
11165 				len = ret + 1;
11166 				msg = realloc(msg, len);
11167 				if (msg == NULL)
11168 					uu_die(gettext(
11169 					    "Out of memory.\n"));
11170 				(void) scf_tmpl_strerror(err, msg, len,
11171 				    flag);
11172 			}
11173 			(void) fprintf(stderr, "%s\n", msg);
11174 		}
11175 		if (msg != NULL)
11176 			free(msg);
11177 	}
11178 	if (errs != NULL)
11179 		scf_tmpl_errors_destroy(errs);
11180 
11181 cleanup:
11182 	free(inst_fmri);
11183 	free(snapbuf);
11184 }
11185 
11186 static void
11187 lscf_validate_file(const char *filename)
11188 {
11189 	tmpl_errors_t *errs;
11190 
11191 	bundle_t *b = internal_bundle_new();
11192 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11193 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11194 			tmpl_errors_print(stderr, errs, "");
11195 			semerr(gettext("Validation failed.\n"));
11196 		}
11197 		tmpl_errors_destroy(errs);
11198 	}
11199 	(void) internal_bundle_free(b);
11200 }
11201 
11202 /*
11203  * validate [fmri|file]
11204  */
11205 void
11206 lscf_validate(const char *arg)
11207 {
11208 	const char *str;
11209 
11210 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11211 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11212 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11213 		lscf_validate_file(str);
11214 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11215 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11216 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11217 		lscf_validate_fmri(str);
11218 	} else if (access(arg, R_OK | F_OK) == 0) {
11219 		lscf_validate_file(arg);
11220 	} else {
11221 		lscf_validate_fmri(arg);
11222 	}
11223 }
11224 
11225 void
11226 lscf_select(const char *fmri)
11227 {
11228 	int ret, err;
11229 
11230 	lscf_prep_hndl();
11231 
11232 	if (cur_snap != NULL) {
11233 		struct snaplevel *elt;
11234 		char *buf;
11235 
11236 		/* Error unless name is that of the next level. */
11237 		elt = uu_list_next(cur_levels, cur_elt);
11238 		if (elt == NULL) {
11239 			semerr(gettext("No children.\n"));
11240 			return;
11241 		}
11242 
11243 		buf = safe_malloc(max_scf_name_len + 1);
11244 
11245 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11246 		    max_scf_name_len + 1) < 0)
11247 			scfdie();
11248 
11249 		if (strcmp(buf, fmri) != 0) {
11250 			semerr(gettext("No such child.\n"));
11251 			free(buf);
11252 			return;
11253 		}
11254 
11255 		free(buf);
11256 
11257 		cur_elt = elt;
11258 		cur_level = elt->sl;
11259 		return;
11260 	}
11261 
11262 	/*
11263 	 * Special case for 'svc:', which takes the user to the scope level.
11264 	 */
11265 	if (strcmp(fmri, "svc:") == 0) {
11266 		scf_instance_destroy(cur_inst);
11267 		scf_service_destroy(cur_svc);
11268 		cur_inst = NULL;
11269 		cur_svc = NULL;
11270 		return;
11271 	}
11272 
11273 	/*
11274 	 * Special case for ':properties'.  This appears as part of 'list' but
11275 	 * can't be selected.  Give a more helpful error message in this case.
11276 	 */
11277 	if (strcmp(fmri, ":properties") == 0) {
11278 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11279 		    "to list properties.\n"));
11280 		return;
11281 	}
11282 
11283 	/*
11284 	 * First try the argument as relative to the current selection.
11285 	 */
11286 	if (cur_inst != NULL) {
11287 		/* EMPTY */;
11288 	} else if (cur_svc != NULL) {
11289 		if (select_inst(fmri) != 1)
11290 			return;
11291 	} else {
11292 		if (select_svc(fmri) != 1)
11293 			return;
11294 	}
11295 
11296 	err = 0;
11297 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11298 	    select_callback, NULL, &err, semerr)) != 0) {
11299 		semerr(gettext("Failed to walk instances: %s\n"),
11300 		    scf_strerror(ret));
11301 	}
11302 }
11303 
11304 void
11305 lscf_unselect(void)
11306 {
11307 	lscf_prep_hndl();
11308 
11309 	if (cur_snap != NULL) {
11310 		struct snaplevel *elt;
11311 
11312 		elt = uu_list_prev(cur_levels, cur_elt);
11313 		if (elt == NULL) {
11314 			semerr(gettext("No parent levels.\n"));
11315 		} else {
11316 			cur_elt = elt;
11317 			cur_level = elt->sl;
11318 		}
11319 	} else if (cur_inst != NULL) {
11320 		scf_instance_destroy(cur_inst);
11321 		cur_inst = NULL;
11322 	} else if (cur_svc != NULL) {
11323 		scf_service_destroy(cur_svc);
11324 		cur_svc = NULL;
11325 	} else {
11326 		semerr(gettext("Cannot unselect at scope level.\n"));
11327 	}
11328 }
11329 
11330 /*
11331  * Return the FMRI of the current selection, for the prompt.
11332  */
11333 void
11334 lscf_get_selection_str(char *buf, size_t bufsz)
11335 {
11336 	char *cp;
11337 	ssize_t fmrilen, szret;
11338 	boolean_t deleted = B_FALSE;
11339 
11340 	if (g_hndl == NULL) {
11341 		(void) strlcpy(buf, "svc:", bufsz);
11342 		return;
11343 	}
11344 
11345 	if (cur_level != NULL) {
11346 		assert(cur_snap != NULL);
11347 
11348 		/* [ snapshot ] FMRI [: instance ] */
11349 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11350 		    + 2 + max_scf_name_len + 1 + 1);
11351 
11352 		buf[0] = '[';
11353 
11354 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11355 		    max_scf_name_len + 1);
11356 		if (szret < 0) {
11357 			if (scf_error() != SCF_ERROR_DELETED)
11358 				scfdie();
11359 
11360 			goto snap_deleted;
11361 		}
11362 
11363 		(void) strcat(buf, "]svc:/");
11364 
11365 		cp = strchr(buf, '\0');
11366 
11367 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11368 		    max_scf_name_len + 1);
11369 		if (szret < 0) {
11370 			if (scf_error() != SCF_ERROR_DELETED)
11371 				scfdie();
11372 
11373 			goto snap_deleted;
11374 		}
11375 
11376 		cp = strchr(cp, '\0');
11377 
11378 		if (snaplevel_is_instance(cur_level)) {
11379 			*cp++ = ':';
11380 
11381 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11382 			    max_scf_name_len + 1) < 0) {
11383 				if (scf_error() != SCF_ERROR_DELETED)
11384 					scfdie();
11385 
11386 				goto snap_deleted;
11387 			}
11388 		} else {
11389 			*cp++ = '[';
11390 			*cp++ = ':';
11391 
11392 			if (scf_instance_get_name(cur_inst, cp,
11393 			    max_scf_name_len + 1) < 0) {
11394 				if (scf_error() != SCF_ERROR_DELETED)
11395 					scfdie();
11396 
11397 				goto snap_deleted;
11398 			}
11399 
11400 			(void) strcat(buf, "]");
11401 		}
11402 
11403 		return;
11404 
11405 snap_deleted:
11406 		deleted = B_TRUE;
11407 		free(buf);
11408 		unselect_cursnap();
11409 	}
11410 
11411 	assert(cur_snap == NULL);
11412 
11413 	if (cur_inst != NULL) {
11414 		assert(cur_svc != NULL);
11415 		assert(cur_scope != NULL);
11416 
11417 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11418 		if (fmrilen >= 0) {
11419 			assert(fmrilen < bufsz);
11420 			if (deleted)
11421 				warn(emsg_deleted);
11422 			return;
11423 		}
11424 
11425 		if (scf_error() != SCF_ERROR_DELETED)
11426 			scfdie();
11427 
11428 		deleted = B_TRUE;
11429 
11430 		scf_instance_destroy(cur_inst);
11431 		cur_inst = NULL;
11432 	}
11433 
11434 	if (cur_svc != NULL) {
11435 		assert(cur_scope != NULL);
11436 
11437 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11438 		if (szret >= 0) {
11439 			assert(szret < bufsz);
11440 			if (deleted)
11441 				warn(emsg_deleted);
11442 			return;
11443 		}
11444 
11445 		if (scf_error() != SCF_ERROR_DELETED)
11446 			scfdie();
11447 
11448 		deleted = B_TRUE;
11449 		scf_service_destroy(cur_svc);
11450 		cur_svc = NULL;
11451 	}
11452 
11453 	assert(cur_scope != NULL);
11454 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11455 
11456 	if (fmrilen < 0)
11457 		scfdie();
11458 
11459 	assert(fmrilen < bufsz);
11460 	if (deleted)
11461 		warn(emsg_deleted);
11462 }
11463 
11464 /*
11465  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11466  * :statistics) are listed for the current selection.
11467  */
11468 void
11469 lscf_list(const char *pattern)
11470 {
11471 	scf_iter_t *iter;
11472 	char *buf;
11473 	int ret;
11474 
11475 	lscf_prep_hndl();
11476 
11477 	if (cur_level != NULL) {
11478 		struct snaplevel *elt;
11479 
11480 		(void) fputs(COLON_NAMESPACES, stdout);
11481 
11482 		elt = uu_list_next(cur_levels, cur_elt);
11483 		if (elt == NULL)
11484 			return;
11485 
11486 		/*
11487 		 * For now, we know that the next level is an instance.  But
11488 		 * if we ever have multiple scopes, this could be complicated.
11489 		 */
11490 		buf = safe_malloc(max_scf_name_len + 1);
11491 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11492 		    max_scf_name_len + 1) >= 0) {
11493 			(void) puts(buf);
11494 		} else {
11495 			if (scf_error() != SCF_ERROR_DELETED)
11496 				scfdie();
11497 		}
11498 
11499 		free(buf);
11500 
11501 		return;
11502 	}
11503 
11504 	if (cur_inst != NULL) {
11505 		(void) fputs(COLON_NAMESPACES, stdout);
11506 		return;
11507 	}
11508 
11509 	iter = scf_iter_create(g_hndl);
11510 	if (iter == NULL)
11511 		scfdie();
11512 
11513 	buf = safe_malloc(max_scf_name_len + 1);
11514 
11515 	if (cur_svc != NULL) {
11516 		/* List the instances in this service. */
11517 		scf_instance_t *inst;
11518 
11519 		inst = scf_instance_create(g_hndl);
11520 		if (inst == NULL)
11521 			scfdie();
11522 
11523 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11524 			safe_printf(COLON_NAMESPACES);
11525 
11526 			for (;;) {
11527 				ret = scf_iter_next_instance(iter, inst);
11528 				if (ret == 0)
11529 					break;
11530 				if (ret != 1) {
11531 					if (scf_error() != SCF_ERROR_DELETED)
11532 						scfdie();
11533 
11534 					break;
11535 				}
11536 
11537 				if (scf_instance_get_name(inst, buf,
11538 				    max_scf_name_len + 1) >= 0) {
11539 					if (pattern == NULL ||
11540 					    fnmatch(pattern, buf, 0) == 0)
11541 						(void) puts(buf);
11542 				} else {
11543 					if (scf_error() != SCF_ERROR_DELETED)
11544 						scfdie();
11545 				}
11546 			}
11547 		} else {
11548 			if (scf_error() != SCF_ERROR_DELETED)
11549 				scfdie();
11550 		}
11551 
11552 		scf_instance_destroy(inst);
11553 	} else {
11554 		/* List the services in this scope. */
11555 		scf_service_t *svc;
11556 
11557 		assert(cur_scope != NULL);
11558 
11559 		svc = scf_service_create(g_hndl);
11560 		if (svc == NULL)
11561 			scfdie();
11562 
11563 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11564 			scfdie();
11565 
11566 		for (;;) {
11567 			ret = scf_iter_next_service(iter, svc);
11568 			if (ret == 0)
11569 				break;
11570 			if (ret != 1)
11571 				scfdie();
11572 
11573 			if (scf_service_get_name(svc, buf,
11574 			    max_scf_name_len + 1) >= 0) {
11575 				if (pattern == NULL ||
11576 				    fnmatch(pattern, buf, 0) == 0)
11577 					safe_printf("%s\n", buf);
11578 			} else {
11579 				if (scf_error() != SCF_ERROR_DELETED)
11580 					scfdie();
11581 			}
11582 		}
11583 
11584 		scf_service_destroy(svc);
11585 	}
11586 
11587 	free(buf);
11588 	scf_iter_destroy(iter);
11589 }
11590 
11591 /*
11592  * Entity addition.  Creates an empty entity in the current selection.
11593  */
11594 void
11595 lscf_add(const char *name)
11596 {
11597 	lscf_prep_hndl();
11598 
11599 	if (cur_snap != NULL) {
11600 		semerr(emsg_cant_modify_snapshots);
11601 	} else if (cur_inst != NULL) {
11602 		semerr(gettext("Cannot add entities to an instance.\n"));
11603 	} else if (cur_svc != NULL) {
11604 
11605 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11606 		    SCF_SUCCESS) {
11607 			switch (scf_error()) {
11608 			case SCF_ERROR_INVALID_ARGUMENT:
11609 				semerr(gettext("Invalid name.\n"));
11610 				break;
11611 
11612 			case SCF_ERROR_EXISTS:
11613 				semerr(gettext("Instance already exists.\n"));
11614 				break;
11615 
11616 			case SCF_ERROR_PERMISSION_DENIED:
11617 				semerr(emsg_permission_denied);
11618 				break;
11619 
11620 			default:
11621 				scfdie();
11622 			}
11623 		}
11624 	} else {
11625 		assert(cur_scope != NULL);
11626 
11627 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11628 		    SCF_SUCCESS) {
11629 			switch (scf_error()) {
11630 			case SCF_ERROR_INVALID_ARGUMENT:
11631 				semerr(gettext("Invalid name.\n"));
11632 				break;
11633 
11634 			case SCF_ERROR_EXISTS:
11635 				semerr(gettext("Service already exists.\n"));
11636 				break;
11637 
11638 			case SCF_ERROR_PERMISSION_DENIED:
11639 				semerr(emsg_permission_denied);
11640 				break;
11641 
11642 			case SCF_ERROR_BACKEND_READONLY:
11643 				semerr(emsg_read_only);
11644 				break;
11645 
11646 			default:
11647 				scfdie();
11648 			}
11649 		}
11650 	}
11651 }
11652 
11653 /* return 1 if the entity has no persistent pgs, else return 0 */
11654 static int
11655 entity_has_no_pgs(void *ent, int isservice)
11656 {
11657 	scf_iter_t *iter = NULL;
11658 	scf_propertygroup_t *pg = NULL;
11659 	uint32_t flags;
11660 	int err;
11661 	int ret = 1;
11662 
11663 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11664 	    (pg = scf_pg_create(g_hndl)) == NULL)
11665 		scfdie();
11666 
11667 	if (isservice) {
11668 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11669 			scfdie();
11670 	} else {
11671 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11672 			scfdie();
11673 	}
11674 
11675 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11676 		if (scf_pg_get_flags(pg, &flags) != 0)
11677 			scfdie();
11678 
11679 		/* skip nonpersistent pgs */
11680 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11681 			continue;
11682 
11683 		ret = 0;
11684 		break;
11685 	}
11686 
11687 	if (err == -1)
11688 		scfdie();
11689 
11690 	scf_pg_destroy(pg);
11691 	scf_iter_destroy(iter);
11692 
11693 	return (ret);
11694 }
11695 
11696 /* return 1 if the service has no instances, else return 0 */
11697 static int
11698 svc_has_no_insts(scf_service_t *svc)
11699 {
11700 	scf_instance_t *inst;
11701 	scf_iter_t *iter;
11702 	int r;
11703 	int ret = 1;
11704 
11705 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11706 	    (iter = scf_iter_create(g_hndl)) == NULL)
11707 		scfdie();
11708 
11709 	if (scf_iter_service_instances(iter, svc) != 0)
11710 		scfdie();
11711 
11712 	r = scf_iter_next_instance(iter, inst);
11713 	if (r == 1) {
11714 		ret = 0;
11715 	} else if (r == 0) {
11716 		ret = 1;
11717 	} else if (r == -1) {
11718 		scfdie();
11719 	} else {
11720 		bad_error("scf_iter_next_instance", r);
11721 	}
11722 
11723 	scf_iter_destroy(iter);
11724 	scf_instance_destroy(inst);
11725 
11726 	return (ret);
11727 }
11728 
11729 /*
11730  * Entity deletion.
11731  */
11732 
11733 /*
11734  * Delete the property group <fmri>/:properties/<name>.  Returns
11735  * SCF_ERROR_NONE on success (or if the entity is not found),
11736  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11737  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11738  * denied.
11739  */
11740 static scf_error_t
11741 delete_dependency_pg(const char *fmri, const char *name)
11742 {
11743 	void *entity = NULL;
11744 	int isservice;
11745 	scf_propertygroup_t *pg = NULL;
11746 	scf_error_t result;
11747 	char *pgty;
11748 	scf_service_t *svc = NULL;
11749 	scf_instance_t *inst = NULL;
11750 	scf_iter_t *iter = NULL;
11751 	char *name_buf = NULL;
11752 
11753 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11754 	switch (result) {
11755 	case SCF_ERROR_NONE:
11756 		break;
11757 
11758 	case SCF_ERROR_NO_MEMORY:
11759 		uu_die(gettext("Out of memory.\n"));
11760 		/* NOTREACHED */
11761 
11762 	case SCF_ERROR_INVALID_ARGUMENT:
11763 	case SCF_ERROR_CONSTRAINT_VIOLATED:
11764 		return (SCF_ERROR_INVALID_ARGUMENT);
11765 
11766 	case SCF_ERROR_NOT_FOUND:
11767 		result = SCF_ERROR_NONE;
11768 		goto out;
11769 
11770 	default:
11771 		bad_error("fmri_to_entity", result);
11772 	}
11773 
11774 	pg = scf_pg_create(g_hndl);
11775 	if (pg == NULL)
11776 		scfdie();
11777 
11778 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
11779 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11780 			scfdie();
11781 
11782 		result = SCF_ERROR_NONE;
11783 		goto out;
11784 	}
11785 
11786 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11787 
11788 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11789 		scfdie();
11790 
11791 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
11792 		result = SCF_ERROR_TYPE_MISMATCH;
11793 		free(pgty);
11794 		goto out;
11795 	}
11796 
11797 	free(pgty);
11798 
11799 	if (scf_pg_delete(pg) != 0) {
11800 		result = scf_error();
11801 		if (result != SCF_ERROR_PERMISSION_DENIED)
11802 			scfdie();
11803 		goto out;
11804 	}
11805 
11806 	/*
11807 	 * We have to handle the case where we've just deleted the last
11808 	 * property group of a "dummy" entity (instance or service).
11809 	 * A "dummy" entity is an entity only present to hold an
11810 	 * external dependency.
11811 	 * So, in the case we deleted the last property group then we
11812 	 * can also delete the entity. If the entity is an instance then
11813 	 * we must verify if this was the last instance for the service
11814 	 * and if it is, we can also delete the service if it doesn't
11815 	 * have any property group either.
11816 	 */
11817 
11818 	result = SCF_ERROR_NONE;
11819 
11820 	if (isservice) {
11821 		svc = (scf_service_t *)entity;
11822 
11823 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
11824 		    (iter = scf_iter_create(g_hndl)) == NULL)
11825 			scfdie();
11826 
11827 		name_buf = safe_malloc(max_scf_name_len + 1);
11828 	} else {
11829 		inst = (scf_instance_t *)entity;
11830 	}
11831 
11832 	/*
11833 	 * If the entity is an instance and we've just deleted its last
11834 	 * property group then we should delete it.
11835 	 */
11836 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
11837 		/* find the service before deleting the inst. - needed later */
11838 		if ((svc = scf_service_create(g_hndl)) == NULL)
11839 			scfdie();
11840 
11841 		if (scf_instance_get_parent(inst, svc) != 0)
11842 			scfdie();
11843 
11844 		/* delete the instance */
11845 		if (scf_instance_delete(inst) != 0) {
11846 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11847 				scfdie();
11848 
11849 			result = SCF_ERROR_PERMISSION_DENIED;
11850 			goto out;
11851 		}
11852 		/* no need to refresh the instance */
11853 		inst = NULL;
11854 	}
11855 
11856 	/*
11857 	 * If the service has no more instances and pgs or we just deleted the
11858 	 * last instance and the service doesn't have anymore propery groups
11859 	 * then the service should be deleted.
11860 	 */
11861 	if (svc != NULL &&
11862 	    svc_has_no_insts(svc) &&
11863 	    entity_has_no_pgs((void *)svc, 1)) {
11864 		if (scf_service_delete(svc) == 0) {
11865 			if (isservice) {
11866 				/* no need to refresh the service */
11867 				svc = NULL;
11868 			}
11869 
11870 			goto out;
11871 		}
11872 
11873 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11874 			scfdie();
11875 
11876 		result = SCF_ERROR_PERMISSION_DENIED;
11877 	}
11878 
11879 	/* if the entity has not been deleted, refresh it */
11880 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
11881 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
11882 		    name_buf);
11883 	}
11884 
11885 out:
11886 	if (isservice && (inst != NULL && iter != NULL)) {
11887 		free(name_buf);
11888 		scf_iter_destroy(iter);
11889 		scf_instance_destroy(inst);
11890 	}
11891 
11892 	if (!isservice && svc != NULL) {
11893 		scf_service_destroy(svc);
11894 	}
11895 
11896 	scf_pg_destroy(pg);
11897 	if (entity != NULL)
11898 		entity_destroy(entity, isservice);
11899 
11900 	return (result);
11901 }
11902 
11903 static int
11904 delete_dependents(scf_propertygroup_t *pg)
11905 {
11906 	char *pgty, *name, *fmri;
11907 	scf_property_t *prop;
11908 	scf_value_t *val;
11909 	scf_iter_t *iter;
11910 	int r;
11911 	scf_error_t err;
11912 
11913 	/* Verify that the pg has the correct type. */
11914 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11915 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11916 		scfdie();
11917 
11918 	if (strcmp(pgty, scf_group_framework) != 0) {
11919 		if (g_verbose) {
11920 			fmri = safe_malloc(max_scf_fmri_len + 1);
11921 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
11922 				scfdie();
11923 
11924 			warn(gettext("Property group %s is not of expected "
11925 			    "type %s.\n"), fmri, scf_group_framework);
11926 
11927 			free(fmri);
11928 		}
11929 
11930 		free(pgty);
11931 		return (-1);
11932 	}
11933 
11934 	free(pgty);
11935 
11936 	/* map delete_dependency_pg onto the properties. */
11937 	if ((prop = scf_property_create(g_hndl)) == NULL ||
11938 	    (val = scf_value_create(g_hndl)) == NULL ||
11939 	    (iter = scf_iter_create(g_hndl)) == NULL)
11940 		scfdie();
11941 
11942 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
11943 		scfdie();
11944 
11945 	name = safe_malloc(max_scf_name_len + 1);
11946 	fmri = safe_malloc(max_scf_fmri_len + 2);
11947 
11948 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
11949 		scf_type_t ty;
11950 
11951 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
11952 			scfdie();
11953 
11954 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11955 			scfdie();
11956 
11957 		if ((ty != SCF_TYPE_ASTRING &&
11958 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
11959 		    prop_get_val(prop, val) != 0)
11960 			continue;
11961 
11962 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
11963 			scfdie();
11964 
11965 		err = delete_dependency_pg(fmri, name);
11966 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
11967 			if (scf_property_to_fmri(prop, fmri,
11968 			    max_scf_fmri_len + 2) < 0)
11969 				scfdie();
11970 
11971 			warn(gettext("Value of %s is not a valid FMRI.\n"),
11972 			    fmri);
11973 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
11974 			warn(gettext("Property group \"%s\" of entity \"%s\" "
11975 			    "does not have dependency type.\n"), name, fmri);
11976 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
11977 			warn(gettext("Could not delete property group \"%s\" "
11978 			    "of entity \"%s\" (permission denied).\n"), name,
11979 			    fmri);
11980 		}
11981 	}
11982 	if (r == -1)
11983 		scfdie();
11984 
11985 	scf_value_destroy(val);
11986 	scf_property_destroy(prop);
11987 
11988 	return (0);
11989 }
11990 
11991 /*
11992  * Returns 1 if the instance may be running, and 0 otherwise.
11993  */
11994 static int
11995 inst_is_running(scf_instance_t *inst)
11996 {
11997 	scf_propertygroup_t *pg;
11998 	scf_property_t *prop;
11999 	scf_value_t *val;
12000 	char buf[MAX_SCF_STATE_STRING_SZ];
12001 	int ret = 0;
12002 	ssize_t szret;
12003 
12004 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12005 	    (prop = scf_property_create(g_hndl)) == NULL ||
12006 	    (val = scf_value_create(g_hndl)) == NULL)
12007 		scfdie();
12008 
12009 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
12010 		if (scf_error() != SCF_ERROR_NOT_FOUND)
12011 			scfdie();
12012 		goto out;
12013 	}
12014 
12015 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
12016 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
12017 	    prop_get_val(prop, val) != 0)
12018 		goto out;
12019 
12020 	szret = scf_value_get_astring(val, buf, sizeof (buf));
12021 	assert(szret >= 0);
12022 
12023 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
12024 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
12025 
12026 out:
12027 	scf_value_destroy(val);
12028 	scf_property_destroy(prop);
12029 	scf_pg_destroy(pg);
12030 	return (ret);
12031 }
12032 
12033 static uint8_t
12034 pg_is_external_dependency(scf_propertygroup_t *pg)
12035 {
12036 	char *type;
12037 	scf_value_t *val;
12038 	scf_property_t *prop;
12039 	uint8_t b = B_FALSE;
12040 
12041 	type = safe_malloc(max_scf_pg_type_len + 1);
12042 
12043 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12044 		scfdie();
12045 
12046 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12047 	    (val = scf_value_create(g_hndl)) == NULL)
12048 		scfdie();
12049 
12050 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12051 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12052 			if (scf_property_get_value(prop, val) != 0)
12053 				scfdie();
12054 			if (scf_value_get_boolean(val, &b) != 0)
12055 				scfdie();
12056 		}
12057 	}
12058 
12059 	free(type);
12060 	(void) scf_value_destroy(val);
12061 	(void) scf_property_destroy(prop);
12062 
12063 	return (b);
12064 }
12065 
12066 #define	DELETE_FAILURE			-1
12067 #define	DELETE_SUCCESS_NOEXTDEPS	0
12068 #define	DELETE_SUCCESS_EXTDEPS		1
12069 
12070 /*
12071  * lscf_instance_delete() deletes an instance.  Before calling
12072  * scf_instance_delete(), though, we make sure the instance isn't
12073  * running and delete dependencies in other entities which the instance
12074  * declared as "dependents".  If there are dependencies which were
12075  * created for other entities, then instead of deleting the instance we
12076  * make it "empty" by deleting all other property groups and all
12077  * snapshots.
12078  *
12079  * lscf_instance_delete() verifies that there is no external dependency pgs
12080  * before suppressing the instance. If there is, then we must not remove them
12081  * now in case the instance is re-created otherwise the dependencies would be
12082  * lost. The external dependency pgs will be removed if the dependencies are
12083  * removed.
12084  *
12085  * Returns:
12086  *  DELETE_FAILURE		on failure
12087  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12088  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12089  */
12090 static int
12091 lscf_instance_delete(scf_instance_t *inst, int force)
12092 {
12093 	scf_propertygroup_t *pg;
12094 	scf_snapshot_t *snap;
12095 	scf_iter_t *iter;
12096 	int err;
12097 	int external = 0;
12098 
12099 	/* If we're not forcing and the instance is running, refuse. */
12100 	if (!force && inst_is_running(inst)) {
12101 		char *fmri;
12102 
12103 		fmri = safe_malloc(max_scf_fmri_len + 1);
12104 
12105 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12106 			scfdie();
12107 
12108 		semerr(gettext("Instance %s may be running.  "
12109 		    "Use delete -f if it is not.\n"), fmri);
12110 
12111 		free(fmri);
12112 		return (DELETE_FAILURE);
12113 	}
12114 
12115 	pg = scf_pg_create(g_hndl);
12116 	if (pg == NULL)
12117 		scfdie();
12118 
12119 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12120 		(void) delete_dependents(pg);
12121 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12122 		scfdie();
12123 
12124 	scf_pg_destroy(pg);
12125 
12126 	/*
12127 	 * If the instance has some external dependencies then we must
12128 	 * keep them in case the instance is reimported otherwise the
12129 	 * dependencies would be lost on reimport.
12130 	 */
12131 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12132 	    (pg = scf_pg_create(g_hndl)) == NULL)
12133 		scfdie();
12134 
12135 	if (scf_iter_instance_pgs(iter, inst) < 0)
12136 		scfdie();
12137 
12138 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12139 		if (pg_is_external_dependency(pg)) {
12140 			external = 1;
12141 			continue;
12142 		}
12143 
12144 		if (scf_pg_delete(pg) != 0) {
12145 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12146 				scfdie();
12147 			else {
12148 				semerr(emsg_permission_denied);
12149 
12150 				(void) scf_iter_destroy(iter);
12151 				(void) scf_pg_destroy(pg);
12152 				return (DELETE_FAILURE);
12153 			}
12154 		}
12155 	}
12156 
12157 	if (err == -1)
12158 		scfdie();
12159 
12160 	(void) scf_iter_destroy(iter);
12161 	(void) scf_pg_destroy(pg);
12162 
12163 	if (external) {
12164 		/*
12165 		 * All the pgs have been deleted for the instance except
12166 		 * the ones holding the external dependencies.
12167 		 * For the job to be complete, we must also delete the
12168 		 * snapshots associated with the instance.
12169 		 */
12170 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12171 		    NULL)
12172 			scfdie();
12173 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12174 			scfdie();
12175 
12176 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12177 			scfdie();
12178 
12179 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12180 			if (_scf_snapshot_delete(snap) != 0) {
12181 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12182 					scfdie();
12183 
12184 				semerr(emsg_permission_denied);
12185 
12186 				(void) scf_iter_destroy(iter);
12187 				(void) scf_snapshot_destroy(snap);
12188 				return (DELETE_FAILURE);
12189 			}
12190 		}
12191 
12192 		if (err == -1)
12193 			scfdie();
12194 
12195 		(void) scf_iter_destroy(iter);
12196 		(void) scf_snapshot_destroy(snap);
12197 		return (DELETE_SUCCESS_EXTDEPS);
12198 	}
12199 
12200 	if (scf_instance_delete(inst) != 0) {
12201 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12202 			scfdie();
12203 
12204 		semerr(emsg_permission_denied);
12205 
12206 		return (DELETE_FAILURE);
12207 	}
12208 
12209 	return (DELETE_SUCCESS_NOEXTDEPS);
12210 }
12211 
12212 /*
12213  * lscf_service_delete() deletes a service.  Before calling
12214  * scf_service_delete(), though, we call lscf_instance_delete() for
12215  * each of the instances and delete dependencies in other entities
12216  * which were created as "dependents" of this service.  If there are
12217  * dependencies which were created for other entities, then we delete
12218  * all other property groups in the service and leave it as "empty".
12219  *
12220  * lscf_service_delete() verifies that there is no external dependency
12221  * pgs at the instance & service level before suppressing the service.
12222  * If there is, then we must not remove them now in case the service
12223  * is re-imported otherwise the dependencies would be lost. The external
12224  * dependency pgs will be removed if the dependencies are removed.
12225  *
12226  * Returns:
12227  *   DELETE_FAILURE		on failure
12228  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12229  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12230  */
12231 static int
12232 lscf_service_delete(scf_service_t *svc, int force)
12233 {
12234 	int r;
12235 	scf_instance_t *inst;
12236 	scf_propertygroup_t *pg;
12237 	scf_iter_t *iter;
12238 	int ret;
12239 	int external = 0;
12240 
12241 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12242 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12243 	    (iter = scf_iter_create(g_hndl)) == NULL)
12244 		scfdie();
12245 
12246 	if (scf_iter_service_instances(iter, svc) != 0)
12247 		scfdie();
12248 
12249 	for (r = scf_iter_next_instance(iter, inst);
12250 	    r == 1;
12251 	    r = scf_iter_next_instance(iter, inst)) {
12252 
12253 		ret = lscf_instance_delete(inst, force);
12254 		if (ret == DELETE_FAILURE) {
12255 			scf_iter_destroy(iter);
12256 			scf_pg_destroy(pg);
12257 			scf_instance_destroy(inst);
12258 			return (DELETE_FAILURE);
12259 		}
12260 
12261 		/*
12262 		 * Record the fact that there is some external dependencies
12263 		 * at the instance level.
12264 		 */
12265 		if (ret == DELETE_SUCCESS_EXTDEPS)
12266 			external |= 1;
12267 	}
12268 
12269 	if (r != 0)
12270 		scfdie();
12271 
12272 	/* Delete dependency property groups in dependent services. */
12273 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12274 		(void) delete_dependents(pg);
12275 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12276 		scfdie();
12277 
12278 	scf_iter_destroy(iter);
12279 	scf_pg_destroy(pg);
12280 	scf_instance_destroy(inst);
12281 
12282 	/*
12283 	 * If the service has some external dependencies then we don't
12284 	 * want to remove them in case the service is re-imported.
12285 	 */
12286 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12287 	    (iter = scf_iter_create(g_hndl)) == NULL)
12288 		scfdie();
12289 
12290 	if (scf_iter_service_pgs(iter, svc) < 0)
12291 		scfdie();
12292 
12293 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12294 		if (pg_is_external_dependency(pg)) {
12295 			external |= 2;
12296 			continue;
12297 		}
12298 
12299 		if (scf_pg_delete(pg) != 0) {
12300 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12301 				scfdie();
12302 			else {
12303 				semerr(emsg_permission_denied);
12304 
12305 				(void) scf_iter_destroy(iter);
12306 				(void) scf_pg_destroy(pg);
12307 				return (DELETE_FAILURE);
12308 			}
12309 		}
12310 	}
12311 
12312 	if (r == -1)
12313 		scfdie();
12314 
12315 	(void) scf_iter_destroy(iter);
12316 	(void) scf_pg_destroy(pg);
12317 
12318 	if (external != 0)
12319 		return (DELETE_SUCCESS_EXTDEPS);
12320 
12321 	if (scf_service_delete(svc) == 0)
12322 		return (DELETE_SUCCESS_NOEXTDEPS);
12323 
12324 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12325 		scfdie();
12326 
12327 	semerr(emsg_permission_denied);
12328 	return (DELETE_FAILURE);
12329 }
12330 
12331 static int
12332 delete_callback(void *data, scf_walkinfo_t *wip)
12333 {
12334 	int force = (int)data;
12335 
12336 	if (wip->inst != NULL)
12337 		(void) lscf_instance_delete(wip->inst, force);
12338 	else
12339 		(void) lscf_service_delete(wip->svc, force);
12340 
12341 	return (0);
12342 }
12343 
12344 void
12345 lscf_delete(const char *fmri, int force)
12346 {
12347 	scf_service_t *svc;
12348 	scf_instance_t *inst;
12349 	int ret;
12350 
12351 	lscf_prep_hndl();
12352 
12353 	if (cur_snap != NULL) {
12354 		if (!snaplevel_is_instance(cur_level)) {
12355 			char *buf;
12356 
12357 			buf = safe_malloc(max_scf_name_len + 1);
12358 			if (scf_instance_get_name(cur_inst, buf,
12359 			    max_scf_name_len + 1) >= 0) {
12360 				if (strcmp(buf, fmri) == 0) {
12361 					semerr(emsg_cant_modify_snapshots);
12362 					free(buf);
12363 					return;
12364 				}
12365 			} else if (scf_error() != SCF_ERROR_DELETED) {
12366 				scfdie();
12367 			}
12368 			free(buf);
12369 		}
12370 	} else if (cur_inst != NULL) {
12371 		/* EMPTY */;
12372 	} else if (cur_svc != NULL) {
12373 		inst = scf_instance_create(g_hndl);
12374 		if (inst == NULL)
12375 			scfdie();
12376 
12377 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12378 		    SCF_SUCCESS) {
12379 			(void) lscf_instance_delete(inst, force);
12380 			scf_instance_destroy(inst);
12381 			return;
12382 		}
12383 
12384 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12385 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12386 			scfdie();
12387 
12388 		scf_instance_destroy(inst);
12389 	} else {
12390 		assert(cur_scope != NULL);
12391 
12392 		svc = scf_service_create(g_hndl);
12393 		if (svc == NULL)
12394 			scfdie();
12395 
12396 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12397 		    SCF_SUCCESS) {
12398 			(void) lscf_service_delete(svc, force);
12399 			scf_service_destroy(svc);
12400 			return;
12401 		}
12402 
12403 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12404 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12405 			scfdie();
12406 
12407 		scf_service_destroy(svc);
12408 	}
12409 
12410 	/*
12411 	 * Match FMRI to entity.
12412 	 */
12413 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12414 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12415 		semerr(gettext("Failed to walk instances: %s\n"),
12416 		    scf_strerror(ret));
12417 	}
12418 }
12419 
12420 
12421 
12422 /*
12423  * :properties commands.  These all end with "pg" or "prop" and generally
12424  * operate on the currently selected entity.
12425  */
12426 
12427 /*
12428  * Property listing.  List the property groups, properties, their types and
12429  * their values for the currently selected entity.
12430  */
12431 static void
12432 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12433 {
12434 	char *buf;
12435 	uint32_t flags;
12436 
12437 	buf = safe_malloc(max_scf_pg_type_len + 1);
12438 
12439 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12440 		scfdie();
12441 
12442 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12443 		scfdie();
12444 
12445 	safe_printf("%-*s  %s", namewidth, name, buf);
12446 
12447 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12448 		safe_printf("\tNONPERSISTENT");
12449 
12450 	safe_printf("\n");
12451 
12452 	free(buf);
12453 }
12454 
12455 static boolean_t
12456 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12457 {
12458 	if (scf_property_get_value(prop, val) == 0) {
12459 		return (B_FALSE);
12460 	} else {
12461 		switch (scf_error()) {
12462 		case SCF_ERROR_NOT_FOUND:
12463 			return (B_FALSE);
12464 		case SCF_ERROR_PERMISSION_DENIED:
12465 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12466 			return (B_TRUE);
12467 		default:
12468 			scfdie();
12469 			/*NOTREACHED*/
12470 		}
12471 	}
12472 }
12473 
12474 static void
12475 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12476 {
12477 	scf_iter_t *iter;
12478 	scf_value_t *val;
12479 	const char *type;
12480 	int multiple_strings = 0;
12481 	int ret;
12482 
12483 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12484 	    (val = scf_value_create(g_hndl)) == NULL)
12485 		scfdie();
12486 
12487 	type = prop_to_typestr(prop);
12488 	assert(type != NULL);
12489 
12490 	safe_printf("%-*s  %-7s ", len, name, type);
12491 
12492 	if (prop_has_multiple_values(prop, val) &&
12493 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12494 	    scf_value_type(val) == SCF_TYPE_USTRING))
12495 		multiple_strings = 1;
12496 
12497 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12498 		scfdie();
12499 
12500 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12501 		char *buf;
12502 		ssize_t vlen, szret;
12503 
12504 		vlen = scf_value_get_as_string(val, NULL, 0);
12505 		if (vlen < 0)
12506 			scfdie();
12507 
12508 		buf = safe_malloc(vlen + 1);
12509 
12510 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12511 		if (szret < 0)
12512 			scfdie();
12513 		assert(szret <= vlen);
12514 
12515 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12516 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12517 			safe_printf(" \"");
12518 			(void) quote_and_print(buf, stdout, 0);
12519 			(void) putchar('"');
12520 			if (ferror(stdout)) {
12521 				(void) putchar('\n');
12522 				uu_die(gettext("Error writing to stdout.\n"));
12523 			}
12524 		} else {
12525 			safe_printf(" %s", buf);
12526 		}
12527 
12528 		free(buf);
12529 	}
12530 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12531 		scfdie();
12532 
12533 	if (putchar('\n') != '\n')
12534 		uu_die(gettext("Could not output newline"));
12535 }
12536 
12537 /*
12538  * Outputs template property group info for the describe subcommand.
12539  * If 'templates' == 2, verbose output is printed in the format expected
12540  * for describe -v, which includes all templates fields.  If pg is
12541  * not NULL, we're describing the template data, not an existing property
12542  * group, and formatting should be appropriate for describe -t.
12543  */
12544 static void
12545 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12546 {
12547 	char *buf;
12548 	uint8_t required;
12549 	scf_property_t *stability_prop;
12550 	scf_value_t *stability_val;
12551 
12552 	if (templates == 0)
12553 		return;
12554 
12555 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12556 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12557 		scfdie();
12558 
12559 	if (templates == 2 && pg != NULL) {
12560 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12561 		    stability_prop) == 0) {
12562 			if (prop_check_type(stability_prop,
12563 			    SCF_TYPE_ASTRING) == 0 &&
12564 			    prop_get_val(stability_prop, stability_val) == 0) {
12565 				char *stability;
12566 
12567 				stability = safe_malloc(max_scf_value_len + 1);
12568 
12569 				if (scf_value_get_astring(stability_val,
12570 				    stability, max_scf_value_len + 1) == -1 &&
12571 				    scf_error() != SCF_ERROR_NOT_FOUND)
12572 					scfdie();
12573 
12574 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12575 				    gettext("stability"), stability);
12576 
12577 				free(stability);
12578 			}
12579 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12580 			scfdie();
12581 	}
12582 
12583 	scf_property_destroy(stability_prop);
12584 	scf_value_destroy(stability_val);
12585 
12586 	if (pgt == NULL)
12587 		return;
12588 
12589 	if (pg == NULL || templates == 2) {
12590 		/* print type info only if scf_tmpl_pg_name succeeds */
12591 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12592 			if (pg != NULL)
12593 				safe_printf("%s", TMPL_INDENT);
12594 			safe_printf("%s: ", gettext("name"));
12595 			safe_printf("%s\n", buf);
12596 			free(buf);
12597 		}
12598 
12599 		/* print type info only if scf_tmpl_pg_type succeeds */
12600 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12601 			if (pg != NULL)
12602 				safe_printf("%s", TMPL_INDENT);
12603 			safe_printf("%s: ", gettext("type"));
12604 			safe_printf("%s\n", buf);
12605 			free(buf);
12606 		}
12607 	}
12608 
12609 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12610 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12611 		    required ? "true" : "false");
12612 
12613 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12614 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12615 		    buf);
12616 		free(buf);
12617 	}
12618 
12619 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12620 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12621 		    buf);
12622 		free(buf);
12623 	}
12624 
12625 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12626 		if (templates == 2)
12627 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12628 			    gettext("description"), buf);
12629 		else
12630 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12631 		free(buf);
12632 	}
12633 
12634 }
12635 
12636 /*
12637  * With as_value set to true, indent as appropriate for the value level.
12638  * If false, indent to appropriate level for inclusion in constraint
12639  * or choice printout.
12640  */
12641 static void
12642 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12643     int as_value)
12644 {
12645 	char *buf;
12646 
12647 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12648 		if (as_value == 0)
12649 			safe_printf("%s", TMPL_CHOICE_INDENT);
12650 		else
12651 			safe_printf("%s", TMPL_INDENT);
12652 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12653 		free(buf);
12654 	}
12655 
12656 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12657 		if (as_value == 0)
12658 			safe_printf("%s", TMPL_CHOICE_INDENT);
12659 		else
12660 			safe_printf("%s", TMPL_INDENT);
12661 		safe_printf("%s: %s\n", gettext("value description"), buf);
12662 		free(buf);
12663 	}
12664 }
12665 
12666 static void
12667 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12668 {
12669 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12670 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12671 	safe_printf("%s\n", val_buf);
12672 
12673 	print_template_value_details(prt, val_buf, 1);
12674 }
12675 
12676 static void
12677 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12678 {
12679 	int i, printed = 0;
12680 	scf_values_t values;
12681 	scf_count_ranges_t c_ranges;
12682 	scf_int_ranges_t i_ranges;
12683 
12684 	printed = 0;
12685 	i = 0;
12686 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12687 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12688 		    gettext("value constraints"));
12689 		printed++;
12690 		for (i = 0; i < values.value_count; ++i) {
12691 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12692 			    gettext("value name"), values.values_as_strings[i]);
12693 			if (verbose == 1)
12694 				print_template_value_details(prt,
12695 				    values.values_as_strings[i], 0);
12696 		}
12697 
12698 		scf_values_destroy(&values);
12699 	}
12700 
12701 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12702 		if (printed++ == 0)
12703 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12704 			    gettext("value constraints"));
12705 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12706 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12707 			    gettext("range"), c_ranges.scr_min[i],
12708 			    c_ranges.scr_max[i]);
12709 		}
12710 		scf_count_ranges_destroy(&c_ranges);
12711 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12712 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12713 		if (printed++ == 0)
12714 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12715 			    gettext("value constraints"));
12716 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12717 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12718 			    gettext("range"), i_ranges.sir_min[i],
12719 			    i_ranges.sir_max[i]);
12720 		}
12721 		scf_int_ranges_destroy(&i_ranges);
12722 	}
12723 }
12724 
12725 static void
12726 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12727 {
12728 	int i = 0, printed = 0;
12729 	scf_values_t values;
12730 	scf_count_ranges_t c_ranges;
12731 	scf_int_ranges_t i_ranges;
12732 
12733 	printed = 0;
12734 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12735 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12736 		    gettext("value constraints"));
12737 		printed++;
12738 		for (i = 0; i < values.value_count; i++) {
12739 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12740 			    gettext("value name"), values.values_as_strings[i]);
12741 			if (verbose == 1)
12742 				print_template_value_details(prt,
12743 				    values.values_as_strings[i], 0);
12744 		}
12745 
12746 		scf_values_destroy(&values);
12747 	}
12748 
12749 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12750 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12751 			if (printed++ == 0)
12752 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12753 				    gettext("value choices"));
12754 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12755 			    gettext("range"), c_ranges.scr_min[i],
12756 			    c_ranges.scr_max[i]);
12757 		}
12758 		scf_count_ranges_destroy(&c_ranges);
12759 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12760 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12761 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12762 			if (printed++ == 0)
12763 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12764 				    gettext("value choices"));
12765 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12766 			    gettext("range"), i_ranges.sir_min[i],
12767 			    i_ranges.sir_max[i]);
12768 		}
12769 		scf_int_ranges_destroy(&i_ranges);
12770 	}
12771 }
12772 
12773 static void
12774 list_values_by_template(scf_prop_tmpl_t *prt)
12775 {
12776 	print_template_constraints(prt, 1);
12777 	print_template_choices(prt, 1);
12778 }
12779 
12780 static void
12781 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
12782 {
12783 	char *val_buf;
12784 	scf_iter_t *iter;
12785 	scf_value_t *val;
12786 	int ret;
12787 
12788 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12789 	    (val = scf_value_create(g_hndl)) == NULL)
12790 		scfdie();
12791 
12792 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12793 		scfdie();
12794 
12795 	val_buf = safe_malloc(max_scf_value_len + 1);
12796 
12797 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12798 		if (scf_value_get_as_string(val, val_buf,
12799 		    max_scf_value_len + 1) < 0)
12800 			scfdie();
12801 
12802 		print_template_value(prt, val_buf);
12803 	}
12804 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12805 		scfdie();
12806 	free(val_buf);
12807 
12808 	print_template_constraints(prt, 0);
12809 	print_template_choices(prt, 0);
12810 
12811 }
12812 
12813 /*
12814  * Outputs property info for the describe subcommand
12815  * Verbose output if templates == 2, -v option of svccfg describe
12816  * Displays template data if prop is not NULL, -t option of svccfg describe
12817  */
12818 static void
12819 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
12820 {
12821 	char *buf;
12822 	uint8_t u_buf;
12823 	int i;
12824 	uint64_t min, max;
12825 	scf_values_t values;
12826 
12827 	if (prt == NULL || templates == 0)
12828 		return;
12829 
12830 	if (prop == NULL) {
12831 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
12832 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
12833 			safe_printf("%s\n", buf);
12834 			free(buf);
12835 		} else
12836 			safe_printf("(%s)\n", gettext("any"));
12837 	}
12838 
12839 	if (prop == NULL || templates == 2) {
12840 		if (prop != NULL)
12841 			safe_printf("%s", TMPL_INDENT);
12842 		else
12843 			safe_printf("%s", TMPL_VALUE_INDENT);
12844 		safe_printf("%s: ", gettext("type"));
12845 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
12846 			safe_printf("%s\n", buf);
12847 			free(buf);
12848 		} else
12849 			safe_printf("(%s)\n", gettext("any"));
12850 	}
12851 
12852 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
12853 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12854 		    u_buf ? "true" : "false");
12855 
12856 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
12857 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12858 		    buf);
12859 		free(buf);
12860 	}
12861 
12862 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
12863 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
12864 		    buf);
12865 		free(buf);
12866 	}
12867 
12868 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
12869 		safe_printf("%s%s\n", TMPL_INDENT, buf);
12870 		free(buf);
12871 	}
12872 
12873 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
12874 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
12875 		    scf_tmpl_visibility_to_string(u_buf));
12876 
12877 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
12878 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12879 		    gettext("minimum number of values"), min);
12880 		if (max == ULLONG_MAX) {
12881 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12882 			    gettext("maximum number of values"),
12883 			    gettext("unlimited"));
12884 		} else {
12885 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12886 			    gettext("maximum number of values"), max);
12887 		}
12888 	}
12889 
12890 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
12891 		for (i = 0; i < values.value_count; i++) {
12892 			if (i == 0) {
12893 				safe_printf("%s%s:", TMPL_INDENT,
12894 				    gettext("internal separators"));
12895 			}
12896 			safe_printf(" \"%s\"", values.values_as_strings[i]);
12897 		}
12898 		safe_printf("\n");
12899 	}
12900 
12901 	if (templates != 2)
12902 		return;
12903 
12904 	if (prop != NULL)
12905 		list_values_tmpl(prt, prop);
12906 	else
12907 		list_values_by_template(prt);
12908 }
12909 
12910 static char *
12911 read_astring(scf_propertygroup_t *pg, const char *prop_name)
12912 {
12913 	char *rv;
12914 
12915 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
12916 	if (rv == NULL) {
12917 		switch (scf_error()) {
12918 		case SCF_ERROR_NOT_FOUND:
12919 			break;
12920 		default:
12921 			scfdie();
12922 		}
12923 	}
12924 	return (rv);
12925 }
12926 
12927 static void
12928 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
12929 {
12930 	size_t doc_len;
12931 	size_t man_len;
12932 	char *pg_name;
12933 	char *text = NULL;
12934 	int rv;
12935 
12936 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
12937 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
12938 	pg_name = safe_malloc(max_scf_name_len + 1);
12939 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
12940 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
12941 			scfdie();
12942 		}
12943 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
12944 			/* Display doc_link and and uri */
12945 			safe_printf("%s%s:\n", TMPL_INDENT,
12946 			    gettext("doc_link"));
12947 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
12948 			if (text != NULL) {
12949 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12950 				    TMPL_INDENT, gettext("name"), text);
12951 				uu_free(text);
12952 			}
12953 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
12954 			if (text != NULL) {
12955 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
12956 				    gettext("uri"), text);
12957 				uu_free(text);
12958 			}
12959 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
12960 		    man_len) == 0) {
12961 			/* Display manpage title, section and path */
12962 			safe_printf("%s%s:\n", TMPL_INDENT,
12963 			    gettext("manpage"));
12964 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
12965 			if (text != NULL) {
12966 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12967 				    TMPL_INDENT, gettext("title"), text);
12968 				uu_free(text);
12969 			}
12970 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
12971 			if (text != NULL) {
12972 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12973 				    TMPL_INDENT, gettext("section"), text);
12974 				uu_free(text);
12975 			}
12976 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
12977 			if (text != NULL) {
12978 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12979 				    TMPL_INDENT, gettext("manpath"), text);
12980 				uu_free(text);
12981 			}
12982 		}
12983 	}
12984 	if (rv == -1)
12985 		scfdie();
12986 
12987 done:
12988 	free(pg_name);
12989 }
12990 
12991 static void
12992 list_entity_tmpl(int templates)
12993 {
12994 	char *common_name = NULL;
12995 	char *description = NULL;
12996 	char *locale = NULL;
12997 	scf_iter_t *iter;
12998 	scf_propertygroup_t *pg;
12999 	scf_property_t *prop;
13000 	int r;
13001 	scf_value_t *val;
13002 
13003 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13004 	    (prop = scf_property_create(g_hndl)) == NULL ||
13005 	    (val = scf_value_create(g_hndl)) == NULL ||
13006 	    (iter = scf_iter_create(g_hndl)) == NULL)
13007 		scfdie();
13008 
13009 	locale = setlocale(LC_MESSAGES, NULL);
13010 
13011 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
13012 		common_name = safe_malloc(max_scf_value_len + 1);
13013 
13014 		/* Try both the current locale and the "C" locale. */
13015 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
13016 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
13017 		    scf_pg_get_property(pg, "C", prop) == 0)) {
13018 			if (prop_get_val(prop, val) == 0 &&
13019 			    scf_value_get_ustring(val, common_name,
13020 			    max_scf_value_len + 1) != -1) {
13021 				safe_printf("%s%s: %s\n", TMPL_INDENT,
13022 				    gettext("common name"), common_name);
13023 			}
13024 		}
13025 	}
13026 
13027 	/*
13028 	 * Do description, manpages, and doc links if templates == 2.
13029 	 */
13030 	if (templates == 2) {
13031 		/* Get the description. */
13032 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13033 			description = safe_malloc(max_scf_value_len + 1);
13034 
13035 			/* Try both the current locale and the "C" locale. */
13036 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
13037 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
13038 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13039 				if (prop_get_val(prop, val) == 0 &&
13040 				    scf_value_get_ustring(val, description,
13041 				    max_scf_value_len + 1) != -1) {
13042 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13043 					    gettext("description"),
13044 					    description);
13045 				}
13046 			}
13047 		}
13048 
13049 		/* Process doc_link & manpage elements. */
13050 		if (cur_level != NULL) {
13051 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13052 			    SCF_GROUP_TEMPLATE);
13053 		} else if (cur_inst != NULL) {
13054 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13055 			    SCF_GROUP_TEMPLATE);
13056 		} else {
13057 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13058 			    SCF_GROUP_TEMPLATE);
13059 		}
13060 		if (r == 0) {
13061 			display_documentation(iter, pg);
13062 		}
13063 	}
13064 
13065 	free(common_name);
13066 	free(description);
13067 	scf_pg_destroy(pg);
13068 	scf_property_destroy(prop);
13069 	scf_value_destroy(val);
13070 	scf_iter_destroy(iter);
13071 }
13072 
13073 static void
13074 listtmpl(const char *pattern, int templates)
13075 {
13076 	scf_pg_tmpl_t *pgt;
13077 	scf_prop_tmpl_t *prt;
13078 	char *snapbuf = NULL;
13079 	char *fmribuf;
13080 	char *pg_name = NULL, *prop_name = NULL;
13081 	ssize_t prop_name_size;
13082 	char *qual_prop_name;
13083 	char *search_name;
13084 	int listed = 0;
13085 
13086 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13087 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13088 		scfdie();
13089 
13090 	fmribuf = safe_malloc(max_scf_name_len + 1);
13091 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13092 
13093 	if (cur_snap != NULL) {
13094 		snapbuf = safe_malloc(max_scf_name_len + 1);
13095 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13096 		    max_scf_name_len + 1) < 0)
13097 			scfdie();
13098 	}
13099 
13100 	if (cur_inst != NULL) {
13101 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13102 		    max_scf_name_len + 1) < 0)
13103 			scfdie();
13104 	} else if (cur_svc != NULL) {
13105 		if (scf_service_to_fmri(cur_svc, fmribuf,
13106 		    max_scf_name_len + 1) < 0)
13107 			scfdie();
13108 	} else
13109 		abort();
13110 
13111 	/* If pattern is specified, we want to list only those items. */
13112 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13113 		listed = 0;
13114 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13115 		    fnmatch(pattern, pg_name, 0) == 0)) {
13116 			list_pg_tmpl(pgt, NULL, templates);
13117 			listed++;
13118 		}
13119 
13120 		scf_tmpl_prop_reset(prt);
13121 
13122 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13123 			search_name = NULL;
13124 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13125 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13126 				if (snprintf(qual_prop_name,
13127 				    max_scf_name_len + 1, "%s/%s",
13128 				    pg_name, prop_name) >=
13129 				    max_scf_name_len + 1) {
13130 					prop_name_size = -1;
13131 				} else {
13132 					search_name = qual_prop_name;
13133 				}
13134 			}
13135 			if (listed > 0 || pattern == NULL ||
13136 			    (prop_name_size > 0 &&
13137 			    fnmatch(pattern, search_name,
13138 			    FNM_PATHNAME) == 0))
13139 				list_prop_tmpl(prt, NULL, templates);
13140 			if (prop_name != NULL) {
13141 				free(prop_name);
13142 				prop_name = NULL;
13143 			}
13144 		}
13145 		if (pg_name != NULL) {
13146 			free(pg_name);
13147 			pg_name = NULL;
13148 		}
13149 	}
13150 
13151 	scf_tmpl_prop_destroy(prt);
13152 	scf_tmpl_pg_destroy(pgt);
13153 	free(snapbuf);
13154 	free(fmribuf);
13155 	free(qual_prop_name);
13156 }
13157 
13158 static void
13159 listprop(const char *pattern, int only_pgs, int templates)
13160 {
13161 	scf_propertygroup_t *pg;
13162 	scf_property_t *prop;
13163 	scf_iter_t *iter, *piter;
13164 	char *pgnbuf, *prnbuf, *ppnbuf;
13165 	scf_pg_tmpl_t *pgt, *pgtp;
13166 	scf_prop_tmpl_t *prt;
13167 
13168 	void **objects;
13169 	char **names;
13170 	void **tmpls;
13171 	int allocd, i;
13172 
13173 	int ret;
13174 	ssize_t pgnlen, prnlen, szret;
13175 	size_t max_len = 0;
13176 
13177 	if (cur_svc == NULL && cur_inst == NULL) {
13178 		semerr(emsg_entity_not_selected);
13179 		return;
13180 	}
13181 
13182 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13183 	    (prop = scf_property_create(g_hndl)) == NULL ||
13184 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13185 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13186 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13187 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13188 		scfdie();
13189 
13190 	prnbuf = safe_malloc(max_scf_name_len + 1);
13191 
13192 	if (cur_level != NULL)
13193 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13194 	else if (cur_inst != NULL)
13195 		ret = scf_iter_instance_pgs(iter, cur_inst);
13196 	else
13197 		ret = scf_iter_service_pgs(iter, cur_svc);
13198 	if (ret != 0) {
13199 		return;
13200 	}
13201 
13202 	/*
13203 	 * We want to only list items which match pattern, and we want the
13204 	 * second column to line up, so during the first pass we'll save
13205 	 * matching items, their names, and their templates in objects,
13206 	 * names, and tmpls, computing the maximum name length as we go,
13207 	 * and then we'll print them out.
13208 	 *
13209 	 * Note: We always keep an extra slot available so the array can be
13210 	 * NULL-terminated.
13211 	 */
13212 	i = 0;
13213 	allocd = 1;
13214 	objects = safe_malloc(sizeof (*objects));
13215 	names = safe_malloc(sizeof (*names));
13216 	tmpls = safe_malloc(sizeof (*tmpls));
13217 
13218 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13219 		int new_pg = 0;
13220 		int print_props = 0;
13221 		pgtp = NULL;
13222 
13223 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13224 		if (pgnlen < 0)
13225 			scfdie();
13226 
13227 		pgnbuf = safe_malloc(pgnlen + 1);
13228 
13229 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13230 		if (szret < 0)
13231 			scfdie();
13232 		assert(szret <= pgnlen);
13233 
13234 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13235 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13236 				scfdie();
13237 			pgtp = NULL;
13238 		} else {
13239 			pgtp = pgt;
13240 		}
13241 
13242 		if (pattern == NULL ||
13243 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13244 			if (i+1 >= allocd) {
13245 				allocd *= 2;
13246 				objects = realloc(objects,
13247 				    sizeof (*objects) * allocd);
13248 				names =
13249 				    realloc(names, sizeof (*names) * allocd);
13250 				tmpls = realloc(tmpls,
13251 				    sizeof (*tmpls) * allocd);
13252 				if (objects == NULL || names == NULL ||
13253 				    tmpls == NULL)
13254 					uu_die(gettext("Out of memory"));
13255 			}
13256 			objects[i] = pg;
13257 			names[i] = pgnbuf;
13258 
13259 			if (pgtp == NULL)
13260 				tmpls[i] = NULL;
13261 			else
13262 				tmpls[i] = pgt;
13263 
13264 			++i;
13265 
13266 			if (pgnlen > max_len)
13267 				max_len = pgnlen;
13268 
13269 			new_pg = 1;
13270 			print_props = 1;
13271 		}
13272 
13273 		if (only_pgs) {
13274 			if (new_pg) {
13275 				pg = scf_pg_create(g_hndl);
13276 				if (pg == NULL)
13277 					scfdie();
13278 				pgt = scf_tmpl_pg_create(g_hndl);
13279 				if (pgt == NULL)
13280 					scfdie();
13281 			} else
13282 				free(pgnbuf);
13283 
13284 			continue;
13285 		}
13286 
13287 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13288 			scfdie();
13289 
13290 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13291 			prnlen = scf_property_get_name(prop, prnbuf,
13292 			    max_scf_name_len + 1);
13293 			if (prnlen < 0)
13294 				scfdie();
13295 
13296 			/* Will prepend the property group name and a slash. */
13297 			prnlen += pgnlen + 1;
13298 
13299 			ppnbuf = safe_malloc(prnlen + 1);
13300 
13301 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13302 			    prnbuf) < 0)
13303 				uu_die("snprintf");
13304 
13305 			if (pattern == NULL || print_props == 1 ||
13306 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13307 				if (i+1 >= allocd) {
13308 					allocd *= 2;
13309 					objects = realloc(objects,
13310 					    sizeof (*objects) * allocd);
13311 					names = realloc(names,
13312 					    sizeof (*names) * allocd);
13313 					tmpls = realloc(tmpls,
13314 					    sizeof (*tmpls) * allocd);
13315 					if (objects == NULL || names == NULL ||
13316 					    tmpls == NULL)
13317 						uu_die(gettext(
13318 						    "Out of memory"));
13319 				}
13320 
13321 				objects[i] = prop;
13322 				names[i] = ppnbuf;
13323 
13324 				if (pgtp != NULL) {
13325 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13326 					    prt, 0) < 0) {
13327 						if (scf_error() !=
13328 						    SCF_ERROR_NOT_FOUND)
13329 							scfdie();
13330 						tmpls[i] = NULL;
13331 					} else {
13332 						tmpls[i] = prt;
13333 					}
13334 				} else {
13335 					tmpls[i] = NULL;
13336 				}
13337 
13338 				++i;
13339 
13340 				if (prnlen > max_len)
13341 					max_len = prnlen;
13342 
13343 				prop = scf_property_create(g_hndl);
13344 				prt = scf_tmpl_prop_create(g_hndl);
13345 			} else {
13346 				free(ppnbuf);
13347 			}
13348 		}
13349 
13350 		if (new_pg) {
13351 			pg = scf_pg_create(g_hndl);
13352 			if (pg == NULL)
13353 				scfdie();
13354 			pgt = scf_tmpl_pg_create(g_hndl);
13355 			if (pgt == NULL)
13356 				scfdie();
13357 		} else
13358 			free(pgnbuf);
13359 	}
13360 	if (ret != 0)
13361 		scfdie();
13362 
13363 	objects[i] = NULL;
13364 
13365 	scf_pg_destroy(pg);
13366 	scf_tmpl_pg_destroy(pgt);
13367 	scf_property_destroy(prop);
13368 	scf_tmpl_prop_destroy(prt);
13369 
13370 	for (i = 0; objects[i] != NULL; ++i) {
13371 		if (strchr(names[i], '/') == NULL) {
13372 			/* property group */
13373 			pg = (scf_propertygroup_t *)objects[i];
13374 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13375 			list_pg_info(pg, names[i], max_len);
13376 			list_pg_tmpl(pgt, pg, templates);
13377 			free(names[i]);
13378 			scf_pg_destroy(pg);
13379 			if (pgt != NULL)
13380 				scf_tmpl_pg_destroy(pgt);
13381 		} else {
13382 			/* property */
13383 			prop = (scf_property_t *)objects[i];
13384 			prt = (scf_prop_tmpl_t *)tmpls[i];
13385 			list_prop_info(prop, names[i], max_len);
13386 			list_prop_tmpl(prt, prop, templates);
13387 			free(names[i]);
13388 			scf_property_destroy(prop);
13389 			if (prt != NULL)
13390 				scf_tmpl_prop_destroy(prt);
13391 		}
13392 	}
13393 
13394 	free(names);
13395 	free(objects);
13396 	free(tmpls);
13397 }
13398 
13399 void
13400 lscf_listpg(const char *pattern)
13401 {
13402 	lscf_prep_hndl();
13403 
13404 	listprop(pattern, 1, 0);
13405 }
13406 
13407 /*
13408  * Property group and property creation, setting, and deletion.  setprop (and
13409  * its alias, addprop) can either create a property group of a given type, or
13410  * it can create or set a property to a given type and list of values.
13411  */
13412 void
13413 lscf_addpg(const char *name, const char *type, const char *flags)
13414 {
13415 	scf_propertygroup_t *pg;
13416 	int ret;
13417 	uint32_t flgs = 0;
13418 	const char *cp;
13419 
13420 
13421 	lscf_prep_hndl();
13422 
13423 	if (cur_snap != NULL) {
13424 		semerr(emsg_cant_modify_snapshots);
13425 		return;
13426 	}
13427 
13428 	if (cur_inst == NULL && cur_svc == NULL) {
13429 		semerr(emsg_entity_not_selected);
13430 		return;
13431 	}
13432 
13433 	if (flags != NULL) {
13434 		for (cp = flags; *cp != '\0'; ++cp) {
13435 			switch (*cp) {
13436 			case 'P':
13437 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13438 				break;
13439 
13440 			case 'p':
13441 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13442 				break;
13443 
13444 			default:
13445 				semerr(gettext("Invalid property group flag "
13446 				    "%c."), *cp);
13447 				return;
13448 			}
13449 		}
13450 	}
13451 
13452 	pg = scf_pg_create(g_hndl);
13453 	if (pg == NULL)
13454 		scfdie();
13455 
13456 	if (cur_inst != NULL)
13457 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13458 	else
13459 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13460 
13461 	if (ret != SCF_SUCCESS) {
13462 		switch (scf_error()) {
13463 		case SCF_ERROR_INVALID_ARGUMENT:
13464 			semerr(gettext("Name, type, or flags are invalid.\n"));
13465 			break;
13466 
13467 		case SCF_ERROR_EXISTS:
13468 			semerr(gettext("Property group already exists.\n"));
13469 			break;
13470 
13471 		case SCF_ERROR_PERMISSION_DENIED:
13472 			semerr(emsg_permission_denied);
13473 			break;
13474 
13475 		case SCF_ERROR_BACKEND_ACCESS:
13476 			semerr(gettext("Backend refused access.\n"));
13477 			break;
13478 
13479 		default:
13480 			scfdie();
13481 		}
13482 	}
13483 
13484 	scf_pg_destroy(pg);
13485 
13486 	private_refresh();
13487 }
13488 
13489 void
13490 lscf_delpg(char *name)
13491 {
13492 	lscf_prep_hndl();
13493 
13494 	if (cur_snap != NULL) {
13495 		semerr(emsg_cant_modify_snapshots);
13496 		return;
13497 	}
13498 
13499 	if (cur_inst == NULL && cur_svc == NULL) {
13500 		semerr(emsg_entity_not_selected);
13501 		return;
13502 	}
13503 
13504 	if (strchr(name, '/') != NULL) {
13505 		semerr(emsg_invalid_pg_name, name);
13506 		return;
13507 	}
13508 
13509 	lscf_delprop(name);
13510 }
13511 
13512 /*
13513  * scf_delhash() is used to remove the property group related to the
13514  * hash entry for a specific manifest in the repository. pgname will be
13515  * constructed from the location of the manifest file. If deathrow isn't 0,
13516  * manifest file doesn't need to exist (manifest string will be used as
13517  * an absolute path).
13518  */
13519 void
13520 lscf_delhash(char *manifest, int deathrow)
13521 {
13522 	char *pgname;
13523 
13524 	if (cur_snap != NULL ||
13525 	    cur_inst != NULL || cur_svc != NULL) {
13526 		warn(gettext("error, an entity is selected\n"));
13527 		return;
13528 	}
13529 
13530 	/* select smf/manifest */
13531 	lscf_select(HASH_SVC);
13532 	/*
13533 	 * Translate the manifest file name to property name. In the deathrow
13534 	 * case, the manifest file does not need to exist.
13535 	 */
13536 	pgname = mhash_filename_to_propname(manifest,
13537 	    deathrow ? B_TRUE : B_FALSE);
13538 	if (pgname == NULL) {
13539 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13540 		return;
13541 	}
13542 	/* delete the hash property name */
13543 	lscf_delpg(pgname);
13544 }
13545 
13546 void
13547 lscf_listprop(const char *pattern)
13548 {
13549 	lscf_prep_hndl();
13550 
13551 	listprop(pattern, 0, 0);
13552 }
13553 
13554 int
13555 lscf_setprop(const char *pgname, const char *type, const char *value,
13556     const uu_list_t *values)
13557 {
13558 	scf_type_t ty, current_ty;
13559 	scf_service_t *svc;
13560 	scf_propertygroup_t *pg, *parent_pg;
13561 	scf_property_t *prop, *parent_prop;
13562 	scf_pg_tmpl_t *pgt;
13563 	scf_prop_tmpl_t *prt;
13564 	int ret, result = 0;
13565 	scf_transaction_t *tx;
13566 	scf_transaction_entry_t *e;
13567 	scf_value_t *v;
13568 	uu_list_walk_t *walk;
13569 	string_list_t *sp;
13570 	char *propname;
13571 	int req_quotes = 0;
13572 
13573 	lscf_prep_hndl();
13574 
13575 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13576 	    (svc = scf_service_create(g_hndl)) == NULL ||
13577 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13578 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13579 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13580 	    (prop = scf_property_create(g_hndl)) == NULL ||
13581 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13582 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13583 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13584 		scfdie();
13585 
13586 	if (cur_snap != NULL) {
13587 		semerr(emsg_cant_modify_snapshots);
13588 		goto fail;
13589 	}
13590 
13591 	if (cur_inst == NULL && cur_svc == NULL) {
13592 		semerr(emsg_entity_not_selected);
13593 		goto fail;
13594 	}
13595 
13596 	propname = strchr(pgname, '/');
13597 	if (propname == NULL) {
13598 		semerr(gettext("Property names must contain a `/'.\n"));
13599 		goto fail;
13600 	}
13601 
13602 	*propname = '\0';
13603 	++propname;
13604 
13605 	if (type != NULL) {
13606 		ty = string_to_type(type);
13607 		if (ty == SCF_TYPE_INVALID) {
13608 			semerr(gettext("Unknown type \"%s\".\n"), type);
13609 			goto fail;
13610 		}
13611 	}
13612 
13613 	if (cur_inst != NULL)
13614 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13615 	else
13616 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13617 	if (ret != SCF_SUCCESS) {
13618 		switch (scf_error()) {
13619 		case SCF_ERROR_NOT_FOUND:
13620 			semerr(emsg_no_such_pg, pgname);
13621 			goto fail;
13622 
13623 		case SCF_ERROR_INVALID_ARGUMENT:
13624 			semerr(emsg_invalid_pg_name, pgname);
13625 			goto fail;
13626 
13627 		default:
13628 			scfdie();
13629 			break;
13630 		}
13631 	}
13632 
13633 	do {
13634 		if (scf_pg_update(pg) == -1)
13635 			scfdie();
13636 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13637 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13638 				scfdie();
13639 
13640 			semerr(emsg_permission_denied);
13641 			goto fail;
13642 		}
13643 
13644 		ret = scf_pg_get_property(pg, propname, prop);
13645 		if (ret == SCF_SUCCESS) {
13646 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13647 				scfdie();
13648 
13649 			if (type == NULL)
13650 				ty = current_ty;
13651 			if (scf_transaction_property_change_type(tx, e,
13652 			    propname, ty) == -1)
13653 				scfdie();
13654 
13655 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13656 			/* Infer the type, if possible. */
13657 			if (type == NULL) {
13658 				/*
13659 				 * First check if we're an instance and the
13660 				 * property is set on the service.
13661 				 */
13662 				if (cur_inst != NULL &&
13663 				    scf_instance_get_parent(cur_inst,
13664 				    svc) == 0 &&
13665 				    scf_service_get_pg(cur_svc, pgname,
13666 				    parent_pg) == 0 &&
13667 				    scf_pg_get_property(parent_pg, propname,
13668 				    parent_prop) == 0 &&
13669 				    scf_property_type(parent_prop,
13670 				    &current_ty) == 0) {
13671 					ty = current_ty;
13672 
13673 				/* Then check for a type set in a template. */
13674 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13675 				    0) == 0 &&
13676 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13677 				    0) == 0 &&
13678 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13679 					ty = current_ty;
13680 
13681 				/* If type can't be inferred, fail. */
13682 				} else {
13683 					semerr(gettext("Type required for new "
13684 					    "properties.\n"));
13685 					goto fail;
13686 				}
13687 			}
13688 			if (scf_transaction_property_new(tx, e, propname,
13689 			    ty) == -1)
13690 				scfdie();
13691 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13692 			semerr(emsg_invalid_prop_name, propname);
13693 			goto fail;
13694 		} else {
13695 			scfdie();
13696 		}
13697 
13698 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13699 			req_quotes = 1;
13700 
13701 		if (value != NULL) {
13702 			v = string_to_value(value, ty, 0);
13703 
13704 			if (v == NULL)
13705 				goto fail;
13706 
13707 			ret = scf_entry_add_value(e, v);
13708 			assert(ret == SCF_SUCCESS);
13709 		} else {
13710 			assert(values != NULL);
13711 
13712 			walk = uu_list_walk_start((uu_list_t *)values,
13713 			    UU_DEFAULT);
13714 			if (walk == NULL)
13715 				uu_die(gettext("Could not walk list"));
13716 
13717 			for (sp = uu_list_walk_next(walk); sp != NULL;
13718 			    sp = uu_list_walk_next(walk)) {
13719 				v = string_to_value(sp->str, ty, req_quotes);
13720 
13721 				if (v == NULL) {
13722 					scf_entry_destroy_children(e);
13723 					goto fail;
13724 				}
13725 
13726 				ret = scf_entry_add_value(e, v);
13727 				assert(ret == SCF_SUCCESS);
13728 			}
13729 			uu_list_walk_end(walk);
13730 		}
13731 		result = scf_transaction_commit(tx);
13732 
13733 		scf_transaction_reset(tx);
13734 		scf_entry_destroy_children(e);
13735 	} while (result == 0);
13736 
13737 	if (result < 0) {
13738 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13739 			scfdie();
13740 
13741 		semerr(emsg_permission_denied);
13742 		goto fail;
13743 	}
13744 
13745 	ret = 0;
13746 
13747 	private_refresh();
13748 
13749 	goto cleanup;
13750 
13751 fail:
13752 	ret = -1;
13753 
13754 cleanup:
13755 	scf_transaction_destroy(tx);
13756 	scf_entry_destroy(e);
13757 	scf_service_destroy(svc);
13758 	scf_pg_destroy(parent_pg);
13759 	scf_pg_destroy(pg);
13760 	scf_property_destroy(parent_prop);
13761 	scf_property_destroy(prop);
13762 	scf_tmpl_pg_destroy(pgt);
13763 	scf_tmpl_prop_destroy(prt);
13764 
13765 	return (ret);
13766 }
13767 
13768 void
13769 lscf_delprop(char *pgn)
13770 {
13771 	char *slash, *pn;
13772 	scf_propertygroup_t *pg;
13773 	scf_transaction_t *tx;
13774 	scf_transaction_entry_t *e;
13775 	int ret;
13776 
13777 
13778 	lscf_prep_hndl();
13779 
13780 	if (cur_snap != NULL) {
13781 		semerr(emsg_cant_modify_snapshots);
13782 		return;
13783 	}
13784 
13785 	if (cur_inst == NULL && cur_svc == NULL) {
13786 		semerr(emsg_entity_not_selected);
13787 		return;
13788 	}
13789 
13790 	pg = scf_pg_create(g_hndl);
13791 	if (pg == NULL)
13792 		scfdie();
13793 
13794 	slash = strchr(pgn, '/');
13795 	if (slash == NULL) {
13796 		pn = NULL;
13797 	} else {
13798 		*slash = '\0';
13799 		pn = slash + 1;
13800 	}
13801 
13802 	if (cur_inst != NULL)
13803 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
13804 	else
13805 		ret = scf_service_get_pg(cur_svc, pgn, pg);
13806 	if (ret != SCF_SUCCESS) {
13807 		switch (scf_error()) {
13808 		case SCF_ERROR_NOT_FOUND:
13809 			semerr(emsg_no_such_pg, pgn);
13810 			break;
13811 
13812 		case SCF_ERROR_INVALID_ARGUMENT:
13813 			semerr(emsg_invalid_pg_name, pgn);
13814 			break;
13815 
13816 		default:
13817 			scfdie();
13818 		}
13819 
13820 		scf_pg_destroy(pg);
13821 
13822 		return;
13823 	}
13824 
13825 	if (pn == NULL) {
13826 		/* Try to delete the property group. */
13827 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
13828 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13829 				scfdie();
13830 
13831 			semerr(emsg_permission_denied);
13832 		} else {
13833 			private_refresh();
13834 		}
13835 
13836 		scf_pg_destroy(pg);
13837 		return;
13838 	}
13839 
13840 	e = scf_entry_create(g_hndl);
13841 	tx = scf_transaction_create(g_hndl);
13842 
13843 	do {
13844 		if (scf_pg_update(pg) == -1)
13845 			scfdie();
13846 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13847 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13848 				scfdie();
13849 
13850 			semerr(emsg_permission_denied);
13851 			break;
13852 		}
13853 
13854 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
13855 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
13856 				semerr(gettext("No such property %s/%s.\n"),
13857 				    pgn, pn);
13858 				break;
13859 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13860 				semerr(emsg_invalid_prop_name, pn);
13861 				break;
13862 			} else {
13863 				scfdie();
13864 			}
13865 		}
13866 
13867 		ret = scf_transaction_commit(tx);
13868 
13869 		if (ret == 0)
13870 			scf_transaction_reset(tx);
13871 	} while (ret == 0);
13872 
13873 	if (ret < 0) {
13874 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13875 			scfdie();
13876 
13877 		semerr(emsg_permission_denied);
13878 	} else {
13879 		private_refresh();
13880 	}
13881 
13882 	scf_transaction_destroy(tx);
13883 	scf_entry_destroy(e);
13884 	scf_pg_destroy(pg);
13885 }
13886 
13887 /*
13888  * Property editing.
13889  */
13890 
13891 static int
13892 write_edit_script(FILE *strm)
13893 {
13894 	char *fmribuf;
13895 	ssize_t fmrilen;
13896 
13897 	scf_propertygroup_t *pg;
13898 	scf_property_t *prop;
13899 	scf_value_t *val;
13900 	scf_type_t ty;
13901 	int ret, result = 0;
13902 	scf_iter_t *iter, *piter, *viter;
13903 	char *buf, *tybuf, *pname;
13904 	const char *emsg_write_error;
13905 
13906 
13907 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
13908 
13909 
13910 	/* select fmri */
13911 	if (cur_inst != NULL) {
13912 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
13913 		if (fmrilen < 0)
13914 			scfdie();
13915 		fmribuf = safe_malloc(fmrilen + 1);
13916 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
13917 			scfdie();
13918 	} else {
13919 		assert(cur_svc != NULL);
13920 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
13921 		if (fmrilen < 0)
13922 			scfdie();
13923 		fmribuf = safe_malloc(fmrilen + 1);
13924 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
13925 			scfdie();
13926 	}
13927 
13928 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
13929 		warn(emsg_write_error, strerror(errno));
13930 		free(fmribuf);
13931 		return (-1);
13932 	}
13933 
13934 	free(fmribuf);
13935 
13936 
13937 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13938 	    (prop = scf_property_create(g_hndl)) == NULL ||
13939 	    (val = scf_value_create(g_hndl)) == NULL ||
13940 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13941 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13942 	    (viter = scf_iter_create(g_hndl)) == NULL)
13943 		scfdie();
13944 
13945 	buf = safe_malloc(max_scf_name_len + 1);
13946 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
13947 	pname = safe_malloc(max_scf_name_len + 1);
13948 
13949 	if (cur_inst != NULL)
13950 		ret = scf_iter_instance_pgs(iter, cur_inst);
13951 	else
13952 		ret = scf_iter_service_pgs(iter, cur_svc);
13953 	if (ret != SCF_SUCCESS)
13954 		scfdie();
13955 
13956 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13957 		int ret2;
13958 
13959 		/*
13960 		 * # delprop pg
13961 		 * # addpg pg type
13962 		 */
13963 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
13964 			scfdie();
13965 
13966 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
13967 			scfdie();
13968 
13969 		if (fprintf(strm, "# Property group \"%s\"\n"
13970 		    "# delprop %s\n"
13971 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
13972 			warn(emsg_write_error, strerror(errno));
13973 			result = -1;
13974 			goto out;
13975 		}
13976 
13977 		/* # setprop pg/prop = (values) */
13978 
13979 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13980 			scfdie();
13981 
13982 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
13983 			int first = 1;
13984 			int ret3;
13985 			int multiple;
13986 			int is_str;
13987 			scf_type_t bty;
13988 
13989 			if (scf_property_get_name(prop, pname,
13990 			    max_scf_name_len + 1) < 0)
13991 				scfdie();
13992 
13993 			if (scf_property_type(prop, &ty) != 0)
13994 				scfdie();
13995 
13996 			multiple = prop_has_multiple_values(prop, val);
13997 
13998 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13999 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
14000 			    < 0) {
14001 				warn(emsg_write_error, strerror(errno));
14002 				result = -1;
14003 				goto out;
14004 			}
14005 
14006 			(void) scf_type_base_type(ty, &bty);
14007 			is_str = (bty == SCF_TYPE_ASTRING);
14008 
14009 			if (scf_iter_property_values(viter, prop) !=
14010 			    SCF_SUCCESS)
14011 				scfdie();
14012 
14013 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
14014 				char *buf;
14015 				ssize_t buflen;
14016 
14017 				buflen = scf_value_get_as_string(val, NULL, 0);
14018 				if (buflen < 0)
14019 					scfdie();
14020 
14021 				buf = safe_malloc(buflen + 1);
14022 
14023 				if (scf_value_get_as_string(val, buf,
14024 				    buflen + 1) < 0)
14025 					scfdie();
14026 
14027 				if (first)
14028 					first = 0;
14029 				else {
14030 					if (putc(' ', strm) != ' ') {
14031 						warn(emsg_write_error,
14032 						    strerror(errno));
14033 						result = -1;
14034 						goto out;
14035 					}
14036 				}
14037 
14038 				if ((is_str && multiple) ||
14039 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14040 					(void) putc('"', strm);
14041 					(void) quote_and_print(buf, strm, 1);
14042 					(void) putc('"', strm);
14043 
14044 					if (ferror(strm)) {
14045 						warn(emsg_write_error,
14046 						    strerror(errno));
14047 						result = -1;
14048 						goto out;
14049 					}
14050 				} else {
14051 					if (fprintf(strm, "%s", buf) < 0) {
14052 						warn(emsg_write_error,
14053 						    strerror(errno));
14054 						result = -1;
14055 						goto out;
14056 					}
14057 				}
14058 
14059 				free(buf);
14060 			}
14061 			if (ret3 < 0 &&
14062 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14063 				scfdie();
14064 
14065 			/* Write closing paren if mult-value property */
14066 			if ((multiple && putc(')', strm) == EOF) ||
14067 
14068 			    /* Write final newline */
14069 			    fputc('\n', strm) == EOF) {
14070 				warn(emsg_write_error, strerror(errno));
14071 				result = -1;
14072 				goto out;
14073 			}
14074 		}
14075 		if (ret2 < 0)
14076 			scfdie();
14077 
14078 		if (fputc('\n', strm) == EOF) {
14079 			warn(emsg_write_error, strerror(errno));
14080 			result = -1;
14081 			goto out;
14082 		}
14083 	}
14084 	if (ret < 0)
14085 		scfdie();
14086 
14087 out:
14088 	free(pname);
14089 	free(tybuf);
14090 	free(buf);
14091 	scf_iter_destroy(viter);
14092 	scf_iter_destroy(piter);
14093 	scf_iter_destroy(iter);
14094 	scf_value_destroy(val);
14095 	scf_property_destroy(prop);
14096 	scf_pg_destroy(pg);
14097 
14098 	if (result == 0) {
14099 		if (fflush(strm) != 0) {
14100 			warn(emsg_write_error, strerror(errno));
14101 			return (-1);
14102 		}
14103 	}
14104 
14105 	return (result);
14106 }
14107 
14108 int
14109 lscf_editprop()
14110 {
14111 	char *buf, *editor;
14112 	size_t bufsz;
14113 	int tmpfd;
14114 	char tempname[] = TEMP_FILE_PATTERN;
14115 
14116 	lscf_prep_hndl();
14117 
14118 	if (cur_snap != NULL) {
14119 		semerr(emsg_cant_modify_snapshots);
14120 		return (-1);
14121 	}
14122 
14123 	if (cur_svc == NULL && cur_inst == NULL) {
14124 		semerr(emsg_entity_not_selected);
14125 		return (-1);
14126 	}
14127 
14128 	tmpfd = mkstemp(tempname);
14129 	if (tmpfd == -1) {
14130 		semerr(gettext("Could not create temporary file.\n"));
14131 		return (-1);
14132 	}
14133 
14134 	(void) strcpy(tempfilename, tempname);
14135 
14136 	tempfile = fdopen(tmpfd, "r+");
14137 	if (tempfile == NULL) {
14138 		warn(gettext("Could not create temporary file.\n"));
14139 		if (close(tmpfd) == -1)
14140 			warn(gettext("Could not close temporary file: %s.\n"),
14141 			    strerror(errno));
14142 
14143 		remove_tempfile();
14144 
14145 		return (-1);
14146 	}
14147 
14148 	if (write_edit_script(tempfile) == -1) {
14149 		remove_tempfile();
14150 		return (-1);
14151 	}
14152 
14153 	editor = getenv("EDITOR");
14154 	if (editor == NULL)
14155 		editor = "vi";
14156 
14157 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14158 	buf = safe_malloc(bufsz);
14159 
14160 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14161 		uu_die(gettext("Error creating editor command"));
14162 
14163 	if (system(buf) == -1) {
14164 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14165 		    strerror(errno));
14166 		free(buf);
14167 		remove_tempfile();
14168 		return (-1);
14169 	}
14170 
14171 	free(buf);
14172 
14173 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14174 
14175 	remove_tempfile();
14176 
14177 	return (0);
14178 }
14179 
14180 static void
14181 add_string(uu_list_t *strlist, const char *str)
14182 {
14183 	string_list_t *elem;
14184 	elem = safe_malloc(sizeof (*elem));
14185 	uu_list_node_init(elem, &elem->node, string_pool);
14186 	elem->str = safe_strdup(str);
14187 	if (uu_list_append(strlist, elem) != 0)
14188 		uu_die(gettext("libuutil error: %s\n"),
14189 		    uu_strerror(uu_error()));
14190 }
14191 
14192 static int
14193 remove_string(uu_list_t *strlist, const char *str)
14194 {
14195 	uu_list_walk_t	*elems;
14196 	string_list_t	*sp;
14197 
14198 	/*
14199 	 * Find the element that needs to be removed.
14200 	 */
14201 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14202 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14203 		if (strcmp(sp->str, str) == 0)
14204 			break;
14205 	}
14206 	uu_list_walk_end(elems);
14207 
14208 	/*
14209 	 * Returning 1 here as the value was not found, this
14210 	 * might not be an error.  Leave it to the caller to
14211 	 * decide.
14212 	 */
14213 	if (sp == NULL) {
14214 		return (1);
14215 	}
14216 
14217 	uu_list_remove(strlist, sp);
14218 
14219 	free(sp->str);
14220 	free(sp);
14221 
14222 	return (0);
14223 }
14224 
14225 /*
14226  * Get all property values that don't match the given glob pattern,
14227  * if a pattern is specified.
14228  */
14229 static void
14230 get_prop_values(scf_property_t *prop, uu_list_t *values,
14231     const char *pattern)
14232 {
14233 	scf_iter_t *iter;
14234 	scf_value_t *val;
14235 	int ret;
14236 
14237 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14238 	    (val = scf_value_create(g_hndl)) == NULL)
14239 		scfdie();
14240 
14241 	if (scf_iter_property_values(iter, prop) != 0)
14242 		scfdie();
14243 
14244 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14245 		char *buf;
14246 		ssize_t vlen, szret;
14247 
14248 		vlen = scf_value_get_as_string(val, NULL, 0);
14249 		if (vlen < 0)
14250 			scfdie();
14251 
14252 		buf = safe_malloc(vlen + 1);
14253 
14254 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14255 		if (szret < 0)
14256 			scfdie();
14257 		assert(szret <= vlen);
14258 
14259 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14260 			add_string(values, buf);
14261 
14262 		free(buf);
14263 	}
14264 
14265 	if (ret == -1)
14266 		scfdie();
14267 
14268 	scf_value_destroy(val);
14269 	scf_iter_destroy(iter);
14270 }
14271 
14272 static int
14273 lscf_setpropvalue(const char *pgname, const char *type,
14274     const char *arg, int isadd, int isnotfoundok)
14275 {
14276 	scf_type_t ty;
14277 	scf_propertygroup_t *pg;
14278 	scf_property_t *prop;
14279 	int ret, result = 0;
14280 	scf_transaction_t *tx;
14281 	scf_transaction_entry_t *e;
14282 	scf_value_t *v;
14283 	string_list_t *sp;
14284 	char *propname;
14285 	uu_list_t *values;
14286 	uu_list_walk_t *walk;
14287 	void *cookie = NULL;
14288 	char *pattern = NULL;
14289 
14290 	lscf_prep_hndl();
14291 
14292 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14293 		uu_die(gettext("Could not create property list: %s\n"),
14294 		    uu_strerror(uu_error()));
14295 
14296 	if (!isadd)
14297 		pattern = safe_strdup(arg);
14298 
14299 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14300 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14301 	    (prop = scf_property_create(g_hndl)) == NULL ||
14302 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14303 		scfdie();
14304 
14305 	if (cur_snap != NULL) {
14306 		semerr(emsg_cant_modify_snapshots);
14307 		goto fail;
14308 	}
14309 
14310 	if (cur_inst == NULL && cur_svc == NULL) {
14311 		semerr(emsg_entity_not_selected);
14312 		goto fail;
14313 	}
14314 
14315 	propname = strchr(pgname, '/');
14316 	if (propname == NULL) {
14317 		semerr(gettext("Property names must contain a `/'.\n"));
14318 		goto fail;
14319 	}
14320 
14321 	*propname = '\0';
14322 	++propname;
14323 
14324 	if (type != NULL) {
14325 		ty = string_to_type(type);
14326 		if (ty == SCF_TYPE_INVALID) {
14327 			semerr(gettext("Unknown type \"%s\".\n"), type);
14328 			goto fail;
14329 		}
14330 	}
14331 
14332 	if (cur_inst != NULL)
14333 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14334 	else
14335 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14336 	if (ret != 0) {
14337 		switch (scf_error()) {
14338 		case SCF_ERROR_NOT_FOUND:
14339 			if (isnotfoundok) {
14340 				result = 0;
14341 			} else {
14342 				semerr(emsg_no_such_pg, pgname);
14343 				result = -1;
14344 			}
14345 			goto out;
14346 
14347 		case SCF_ERROR_INVALID_ARGUMENT:
14348 			semerr(emsg_invalid_pg_name, pgname);
14349 			goto fail;
14350 
14351 		default:
14352 			scfdie();
14353 		}
14354 	}
14355 
14356 	do {
14357 		if (scf_pg_update(pg) == -1)
14358 			scfdie();
14359 		if (scf_transaction_start(tx, pg) != 0) {
14360 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14361 				scfdie();
14362 
14363 			semerr(emsg_permission_denied);
14364 			goto fail;
14365 		}
14366 
14367 		ret = scf_pg_get_property(pg, propname, prop);
14368 		if (ret == 0) {
14369 			scf_type_t ptype;
14370 			char *pat = pattern;
14371 
14372 			if (scf_property_type(prop, &ptype) != 0)
14373 				scfdie();
14374 
14375 			if (isadd) {
14376 				if (type != NULL && ptype != ty) {
14377 					semerr(gettext("Property \"%s\" is not "
14378 					    "of type \"%s\".\n"), propname,
14379 					    type);
14380 					goto fail;
14381 				}
14382 
14383 				pat = NULL;
14384 			} else {
14385 				size_t len = strlen(pat);
14386 				if (len > 0 && pat[len - 1] == '\"')
14387 					pat[len - 1] = '\0';
14388 				if (len > 0 && pat[0] == '\"')
14389 					pat++;
14390 			}
14391 
14392 			ty = ptype;
14393 
14394 			get_prop_values(prop, values, pat);
14395 
14396 			if (isadd)
14397 				add_string(values, arg);
14398 
14399 			if (scf_transaction_property_change(tx, e,
14400 			    propname, ty) == -1)
14401 				scfdie();
14402 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14403 			if (isadd) {
14404 				if (type == NULL) {
14405 					semerr(gettext("Type required "
14406 					    "for new properties.\n"));
14407 					goto fail;
14408 				}
14409 
14410 				add_string(values, arg);
14411 
14412 				if (scf_transaction_property_new(tx, e,
14413 				    propname, ty) == -1)
14414 					scfdie();
14415 			} else if (isnotfoundok) {
14416 				result = 0;
14417 				goto out;
14418 			} else {
14419 				semerr(gettext("No such property %s/%s.\n"),
14420 				    pgname, propname);
14421 				result = -1;
14422 				goto out;
14423 			}
14424 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14425 			semerr(emsg_invalid_prop_name, propname);
14426 			goto fail;
14427 		} else {
14428 			scfdie();
14429 		}
14430 
14431 		walk = uu_list_walk_start(values, UU_DEFAULT);
14432 		if (walk == NULL)
14433 			uu_die(gettext("Could not walk property list.\n"));
14434 
14435 		for (sp = uu_list_walk_next(walk); sp != NULL;
14436 		    sp = uu_list_walk_next(walk)) {
14437 			v = string_to_value(sp->str, ty, 0);
14438 
14439 			if (v == NULL) {
14440 				scf_entry_destroy_children(e);
14441 				goto fail;
14442 			}
14443 			ret = scf_entry_add_value(e, v);
14444 			assert(ret == 0);
14445 		}
14446 		uu_list_walk_end(walk);
14447 
14448 		result = scf_transaction_commit(tx);
14449 
14450 		scf_transaction_reset(tx);
14451 		scf_entry_destroy_children(e);
14452 	} while (result == 0);
14453 
14454 	if (result < 0) {
14455 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14456 			scfdie();
14457 
14458 		semerr(emsg_permission_denied);
14459 		goto fail;
14460 	}
14461 
14462 	result = 0;
14463 
14464 	private_refresh();
14465 
14466 out:
14467 	scf_transaction_destroy(tx);
14468 	scf_entry_destroy(e);
14469 	scf_pg_destroy(pg);
14470 	scf_property_destroy(prop);
14471 	free(pattern);
14472 
14473 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14474 		free(sp->str);
14475 		free(sp);
14476 	}
14477 
14478 	uu_list_destroy(values);
14479 
14480 	return (result);
14481 
14482 fail:
14483 	result = -1;
14484 	goto out;
14485 }
14486 
14487 int
14488 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14489 {
14490 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14491 }
14492 
14493 int
14494 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14495 {
14496 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14497 }
14498 
14499 /*
14500  * Look for a standard start method, first in the instance (if any),
14501  * then the service.
14502  */
14503 static const char *
14504 start_method_name(int *in_instance)
14505 {
14506 	scf_propertygroup_t *pg;
14507 	char **p;
14508 	int ret;
14509 	scf_instance_t *inst = cur_inst;
14510 
14511 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14512 		scfdie();
14513 
14514 again:
14515 	for (p = start_method_names; *p != NULL; p++) {
14516 		if (inst != NULL)
14517 			ret = scf_instance_get_pg(inst, *p, pg);
14518 		else
14519 			ret = scf_service_get_pg(cur_svc, *p, pg);
14520 
14521 		if (ret == 0) {
14522 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14523 			char *buf = safe_malloc(bufsz);
14524 
14525 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14526 				free(buf);
14527 				continue;
14528 			}
14529 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14530 				free(buf);
14531 				continue;
14532 			}
14533 
14534 			free(buf);
14535 			*in_instance = (inst != NULL);
14536 			scf_pg_destroy(pg);
14537 			return (*p);
14538 		}
14539 
14540 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14541 			continue;
14542 
14543 		scfdie();
14544 	}
14545 
14546 	if (inst != NULL) {
14547 		inst = NULL;
14548 		goto again;
14549 	}
14550 
14551 	scf_pg_destroy(pg);
14552 	return (NULL);
14553 }
14554 
14555 static int
14556 addpg(const char *name, const char *type)
14557 {
14558 	scf_propertygroup_t *pg;
14559 	int ret;
14560 
14561 	pg = scf_pg_create(g_hndl);
14562 	if (pg == NULL)
14563 		scfdie();
14564 
14565 	if (cur_inst != NULL)
14566 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14567 	else
14568 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14569 
14570 	if (ret != 0) {
14571 		switch (scf_error()) {
14572 		case SCF_ERROR_EXISTS:
14573 			ret = 0;
14574 			break;
14575 
14576 		case SCF_ERROR_PERMISSION_DENIED:
14577 			semerr(emsg_permission_denied);
14578 			break;
14579 
14580 		default:
14581 			scfdie();
14582 		}
14583 	}
14584 
14585 	scf_pg_destroy(pg);
14586 	return (ret);
14587 }
14588 
14589 int
14590 lscf_setenv(uu_list_t *args, int isunset)
14591 {
14592 	int ret = 0;
14593 	size_t i;
14594 	int argc;
14595 	char **argv = NULL;
14596 	string_list_t *slp;
14597 	char *pattern;
14598 	char *prop;
14599 	int do_service = 0;
14600 	int do_instance = 0;
14601 	const char *method = NULL;
14602 	const char *name = NULL;
14603 	const char *value = NULL;
14604 	scf_instance_t *saved_cur_inst = cur_inst;
14605 
14606 	lscf_prep_hndl();
14607 
14608 	argc = uu_list_numnodes(args);
14609 	if (argc < 1)
14610 		goto usage;
14611 
14612 	argv = calloc(argc + 1, sizeof (char *));
14613 	if (argv == NULL)
14614 		uu_die(gettext("Out of memory.\n"));
14615 
14616 	for (slp = uu_list_first(args), i = 0;
14617 	    slp != NULL;
14618 	    slp = uu_list_next(args, slp), ++i)
14619 		argv[i] = slp->str;
14620 
14621 	argv[i] = NULL;
14622 
14623 	opterr = 0;
14624 	optind = 0;
14625 	for (;;) {
14626 		ret = getopt(argc, argv, "sim:");
14627 		if (ret == -1)
14628 			break;
14629 
14630 		switch (ret) {
14631 		case 's':
14632 			do_service = 1;
14633 			cur_inst = NULL;
14634 			break;
14635 
14636 		case 'i':
14637 			do_instance = 1;
14638 			break;
14639 
14640 		case 'm':
14641 			method = optarg;
14642 			break;
14643 
14644 		case '?':
14645 			goto usage;
14646 
14647 		default:
14648 			bad_error("getopt", ret);
14649 		}
14650 	}
14651 
14652 	argc -= optind;
14653 	if ((do_service && do_instance) ||
14654 	    (isunset && argc != 1) ||
14655 	    (!isunset && argc != 2))
14656 		goto usage;
14657 
14658 	name = argv[optind];
14659 	if (!isunset)
14660 		value = argv[optind + 1];
14661 
14662 	if (cur_snap != NULL) {
14663 		semerr(emsg_cant_modify_snapshots);
14664 		ret = -1;
14665 		goto out;
14666 	}
14667 
14668 	if (cur_inst == NULL && cur_svc == NULL) {
14669 		semerr(emsg_entity_not_selected);
14670 		ret = -1;
14671 		goto out;
14672 	}
14673 
14674 	if (do_instance && cur_inst == NULL) {
14675 		semerr(gettext("No instance is selected.\n"));
14676 		ret = -1;
14677 		goto out;
14678 	}
14679 
14680 	if (do_service && cur_svc == NULL) {
14681 		semerr(gettext("No service is selected.\n"));
14682 		ret = -1;
14683 		goto out;
14684 	}
14685 
14686 	if (method == NULL) {
14687 		if (do_instance || do_service) {
14688 			method = "method_context";
14689 			if (!isunset) {
14690 				ret = addpg("method_context",
14691 				    SCF_GROUP_FRAMEWORK);
14692 				if (ret != 0)
14693 					goto out;
14694 			}
14695 		} else {
14696 			int in_instance;
14697 			method = start_method_name(&in_instance);
14698 			if (method == NULL) {
14699 				semerr(gettext(
14700 				    "Couldn't find start method; please "
14701 				    "specify a method with '-m'.\n"));
14702 				ret = -1;
14703 				goto out;
14704 			}
14705 			if (!in_instance)
14706 				cur_inst = NULL;
14707 		}
14708 	} else {
14709 		scf_propertygroup_t *pg;
14710 		size_t bufsz;
14711 		char *buf;
14712 		int ret;
14713 
14714 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14715 			scfdie();
14716 
14717 		if (cur_inst != NULL)
14718 			ret = scf_instance_get_pg(cur_inst, method, pg);
14719 		else
14720 			ret = scf_service_get_pg(cur_svc, method, pg);
14721 
14722 		if (ret != 0) {
14723 			scf_pg_destroy(pg);
14724 			switch (scf_error()) {
14725 			case SCF_ERROR_NOT_FOUND:
14726 				semerr(gettext("Couldn't find the method "
14727 				    "\"%s\".\n"), method);
14728 				goto out;
14729 
14730 			case SCF_ERROR_INVALID_ARGUMENT:
14731 				semerr(gettext("Invalid method name \"%s\".\n"),
14732 				    method);
14733 				goto out;
14734 
14735 			default:
14736 				scfdie();
14737 			}
14738 		}
14739 
14740 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
14741 		buf = safe_malloc(bufsz);
14742 
14743 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14744 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
14745 			semerr(gettext("Property group \"%s\" is not of type "
14746 			    "\"method\".\n"), method);
14747 			ret = -1;
14748 			free(buf);
14749 			scf_pg_destroy(pg);
14750 			goto out;
14751 		}
14752 
14753 		free(buf);
14754 		scf_pg_destroy(pg);
14755 	}
14756 
14757 	prop = uu_msprintf("%s/environment", method);
14758 	pattern = uu_msprintf("%s=*", name);
14759 
14760 	if (prop == NULL || pattern == NULL)
14761 		uu_die(gettext("Out of memory.\n"));
14762 
14763 	ret = lscf_delpropvalue(prop, pattern, !isunset);
14764 
14765 	if (ret == 0 && !isunset) {
14766 		uu_free(pattern);
14767 		uu_free(prop);
14768 		prop = uu_msprintf("%s/environment", method);
14769 		pattern = uu_msprintf("%s=%s", name, value);
14770 		if (prop == NULL || pattern == NULL)
14771 			uu_die(gettext("Out of memory.\n"));
14772 		ret = lscf_addpropvalue(prop, "astring:", pattern);
14773 	}
14774 	uu_free(pattern);
14775 	uu_free(prop);
14776 
14777 out:
14778 	cur_inst = saved_cur_inst;
14779 
14780 	free(argv);
14781 	return (ret);
14782 usage:
14783 	ret = -2;
14784 	goto out;
14785 }
14786 
14787 /*
14788  * Snapshot commands
14789  */
14790 
14791 void
14792 lscf_listsnap()
14793 {
14794 	scf_snapshot_t *snap;
14795 	scf_iter_t *iter;
14796 	char *nb;
14797 	int r;
14798 
14799 	lscf_prep_hndl();
14800 
14801 	if (cur_inst == NULL) {
14802 		semerr(gettext("Instance not selected.\n"));
14803 		return;
14804 	}
14805 
14806 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14807 	    (iter = scf_iter_create(g_hndl)) == NULL)
14808 		scfdie();
14809 
14810 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
14811 		scfdie();
14812 
14813 	nb = safe_malloc(max_scf_name_len + 1);
14814 
14815 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
14816 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
14817 			scfdie();
14818 
14819 		(void) puts(nb);
14820 	}
14821 	if (r < 0)
14822 		scfdie();
14823 
14824 	free(nb);
14825 	scf_iter_destroy(iter);
14826 	scf_snapshot_destroy(snap);
14827 }
14828 
14829 void
14830 lscf_selectsnap(const char *name)
14831 {
14832 	scf_snapshot_t *snap;
14833 	scf_snaplevel_t *level;
14834 
14835 	lscf_prep_hndl();
14836 
14837 	if (cur_inst == NULL) {
14838 		semerr(gettext("Instance not selected.\n"));
14839 		return;
14840 	}
14841 
14842 	if (cur_snap != NULL) {
14843 		if (name != NULL) {
14844 			char *cur_snap_name;
14845 			boolean_t nochange;
14846 
14847 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
14848 
14849 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
14850 			    max_scf_name_len + 1) < 0)
14851 				scfdie();
14852 
14853 			nochange = strcmp(name, cur_snap_name) == 0;
14854 
14855 			free(cur_snap_name);
14856 
14857 			if (nochange)
14858 				return;
14859 		}
14860 
14861 		unselect_cursnap();
14862 	}
14863 
14864 	if (name == NULL)
14865 		return;
14866 
14867 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14868 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
14869 		scfdie();
14870 
14871 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
14872 	    SCF_SUCCESS) {
14873 		switch (scf_error()) {
14874 		case SCF_ERROR_INVALID_ARGUMENT:
14875 			semerr(gettext("Invalid name \"%s\".\n"), name);
14876 			break;
14877 
14878 		case SCF_ERROR_NOT_FOUND:
14879 			semerr(gettext("No such snapshot \"%s\".\n"), name);
14880 			break;
14881 
14882 		default:
14883 			scfdie();
14884 		}
14885 
14886 		scf_snaplevel_destroy(level);
14887 		scf_snapshot_destroy(snap);
14888 		return;
14889 	}
14890 
14891 	/* Load the snaplevels into our list. */
14892 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
14893 	if (cur_levels == NULL)
14894 		uu_die(gettext("Could not create list: %s\n"),
14895 		    uu_strerror(uu_error()));
14896 
14897 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14898 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14899 			scfdie();
14900 
14901 		semerr(gettext("Snapshot has no snaplevels.\n"));
14902 
14903 		scf_snaplevel_destroy(level);
14904 		scf_snapshot_destroy(snap);
14905 		return;
14906 	}
14907 
14908 	cur_snap = snap;
14909 
14910 	for (;;) {
14911 		cur_elt = safe_malloc(sizeof (*cur_elt));
14912 		uu_list_node_init(cur_elt, &cur_elt->list_node,
14913 		    snaplevel_pool);
14914 		cur_elt->sl = level;
14915 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
14916 			uu_die(gettext("libuutil error: %s\n"),
14917 			    uu_strerror(uu_error()));
14918 
14919 		level = scf_snaplevel_create(g_hndl);
14920 		if (level == NULL)
14921 			scfdie();
14922 
14923 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
14924 		    level) != SCF_SUCCESS) {
14925 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14926 				scfdie();
14927 
14928 			scf_snaplevel_destroy(level);
14929 			break;
14930 		}
14931 	}
14932 
14933 	cur_elt = uu_list_last(cur_levels);
14934 	cur_level = cur_elt->sl;
14935 }
14936 
14937 /*
14938  * Copies the properties & values in src to dst.  Assumes src won't change.
14939  * Returns -1 if permission is denied, -2 if another transaction interrupts,
14940  * and 0 on success.
14941  *
14942  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
14943  * property, if it is copied and has type boolean.  (See comment in
14944  * lscf_revert()).
14945  */
14946 static int
14947 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
14948     uint8_t enabled)
14949 {
14950 	scf_transaction_t *tx;
14951 	scf_iter_t *iter, *viter;
14952 	scf_property_t *prop;
14953 	scf_value_t *v;
14954 	char *nbuf;
14955 	int r;
14956 
14957 	tx = scf_transaction_create(g_hndl);
14958 	if (tx == NULL)
14959 		scfdie();
14960 
14961 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
14962 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14963 			scfdie();
14964 
14965 		scf_transaction_destroy(tx);
14966 
14967 		return (-1);
14968 	}
14969 
14970 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14971 	    (prop = scf_property_create(g_hndl)) == NULL ||
14972 	    (viter = scf_iter_create(g_hndl)) == NULL)
14973 		scfdie();
14974 
14975 	nbuf = safe_malloc(max_scf_name_len + 1);
14976 
14977 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
14978 		scfdie();
14979 
14980 	for (;;) {
14981 		scf_transaction_entry_t *e;
14982 		scf_type_t ty;
14983 
14984 		r = scf_iter_next_property(iter, prop);
14985 		if (r == -1)
14986 			scfdie();
14987 		if (r == 0)
14988 			break;
14989 
14990 		e = scf_entry_create(g_hndl);
14991 		if (e == NULL)
14992 			scfdie();
14993 
14994 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14995 			scfdie();
14996 
14997 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14998 			scfdie();
14999 
15000 		if (scf_transaction_property_new(tx, e, nbuf,
15001 		    ty) != SCF_SUCCESS)
15002 			scfdie();
15003 
15004 		if ((enabled == 0 || enabled == 1) &&
15005 		    strcmp(nbuf, scf_property_enabled) == 0 &&
15006 		    ty == SCF_TYPE_BOOLEAN) {
15007 			v = scf_value_create(g_hndl);
15008 			if (v == NULL)
15009 				scfdie();
15010 
15011 			scf_value_set_boolean(v, enabled);
15012 
15013 			if (scf_entry_add_value(e, v) != 0)
15014 				scfdie();
15015 		} else {
15016 			if (scf_iter_property_values(viter, prop) != 0)
15017 				scfdie();
15018 
15019 			for (;;) {
15020 				v = scf_value_create(g_hndl);
15021 				if (v == NULL)
15022 					scfdie();
15023 
15024 				r = scf_iter_next_value(viter, v);
15025 				if (r == -1)
15026 					scfdie();
15027 				if (r == 0) {
15028 					scf_value_destroy(v);
15029 					break;
15030 				}
15031 
15032 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15033 					scfdie();
15034 			}
15035 		}
15036 	}
15037 
15038 	free(nbuf);
15039 	scf_iter_destroy(viter);
15040 	scf_property_destroy(prop);
15041 	scf_iter_destroy(iter);
15042 
15043 	r = scf_transaction_commit(tx);
15044 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15045 		scfdie();
15046 
15047 	scf_transaction_destroy_children(tx);
15048 	scf_transaction_destroy(tx);
15049 
15050 	switch (r) {
15051 	case 1:		return (0);
15052 	case 0:		return (-2);
15053 	case -1:	return (-1);
15054 
15055 	default:
15056 		abort();
15057 	}
15058 
15059 	/* NOTREACHED */
15060 }
15061 
15062 void
15063 lscf_revert(const char *snapname)
15064 {
15065 	scf_snapshot_t *snap, *prev;
15066 	scf_snaplevel_t *level, *nlevel;
15067 	scf_iter_t *iter;
15068 	scf_propertygroup_t *pg, *npg;
15069 	scf_property_t *prop;
15070 	scf_value_t *val;
15071 	char *nbuf, *tbuf;
15072 	uint8_t enabled;
15073 
15074 	lscf_prep_hndl();
15075 
15076 	if (cur_inst == NULL) {
15077 		semerr(gettext("Instance not selected.\n"));
15078 		return;
15079 	}
15080 
15081 	if (snapname != NULL) {
15082 		snap = scf_snapshot_create(g_hndl);
15083 		if (snap == NULL)
15084 			scfdie();
15085 
15086 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15087 		    SCF_SUCCESS) {
15088 			switch (scf_error()) {
15089 			case SCF_ERROR_INVALID_ARGUMENT:
15090 				semerr(gettext("Invalid snapshot name "
15091 				    "\"%s\".\n"), snapname);
15092 				break;
15093 
15094 			case SCF_ERROR_NOT_FOUND:
15095 				semerr(gettext("No such snapshot.\n"));
15096 				break;
15097 
15098 			default:
15099 				scfdie();
15100 			}
15101 
15102 			scf_snapshot_destroy(snap);
15103 			return;
15104 		}
15105 	} else {
15106 		if (cur_snap != NULL) {
15107 			snap = cur_snap;
15108 		} else {
15109 			semerr(gettext("No snapshot selected.\n"));
15110 			return;
15111 		}
15112 	}
15113 
15114 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15115 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15116 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15117 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15118 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15119 	    (prop = scf_property_create(g_hndl)) == NULL ||
15120 	    (val = scf_value_create(g_hndl)) == NULL)
15121 		scfdie();
15122 
15123 	nbuf = safe_malloc(max_scf_name_len + 1);
15124 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15125 
15126 	/* Take the "previous" snapshot before we blow away the properties. */
15127 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15128 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15129 			scfdie();
15130 	} else {
15131 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15132 			scfdie();
15133 
15134 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15135 			scfdie();
15136 	}
15137 
15138 	/* Save general/enabled, since we're probably going to replace it. */
15139 	enabled = 2;
15140 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15141 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15142 	    scf_property_get_value(prop, val) == 0)
15143 		(void) scf_value_get_boolean(val, &enabled);
15144 
15145 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15146 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15147 			scfdie();
15148 
15149 		goto out;
15150 	}
15151 
15152 	for (;;) {
15153 		boolean_t isinst;
15154 		uint32_t flags;
15155 		int r;
15156 
15157 		/* Clear the properties from the corresponding entity. */
15158 		isinst = snaplevel_is_instance(level);
15159 
15160 		if (!isinst)
15161 			r = scf_iter_service_pgs(iter, cur_svc);
15162 		else
15163 			r = scf_iter_instance_pgs(iter, cur_inst);
15164 		if (r != SCF_SUCCESS)
15165 			scfdie();
15166 
15167 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15168 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15169 				scfdie();
15170 
15171 			/* Skip nonpersistent pgs. */
15172 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15173 				continue;
15174 
15175 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15176 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15177 					scfdie();
15178 
15179 				semerr(emsg_permission_denied);
15180 				goto out;
15181 			}
15182 		}
15183 		if (r == -1)
15184 			scfdie();
15185 
15186 		/* Copy the properties to the corresponding entity. */
15187 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15188 			scfdie();
15189 
15190 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15191 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15192 				scfdie();
15193 
15194 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15195 			    0)
15196 				scfdie();
15197 
15198 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15199 				scfdie();
15200 
15201 			if (!isinst)
15202 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15203 				    flags, npg);
15204 			else
15205 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15206 				    flags, npg);
15207 			if (r != SCF_SUCCESS) {
15208 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15209 					scfdie();
15210 
15211 				semerr(emsg_permission_denied);
15212 				goto out;
15213 			}
15214 
15215 			if ((enabled == 0 || enabled == 1) &&
15216 			    strcmp(nbuf, scf_pg_general) == 0)
15217 				r = pg_copy(pg, npg, enabled);
15218 			else
15219 				r = pg_copy(pg, npg, 2);
15220 
15221 			switch (r) {
15222 			case 0:
15223 				break;
15224 
15225 			case -1:
15226 				semerr(emsg_permission_denied);
15227 				goto out;
15228 
15229 			case -2:
15230 				semerr(gettext(
15231 				    "Interrupted by another change.\n"));
15232 				goto out;
15233 
15234 			default:
15235 				abort();
15236 			}
15237 		}
15238 		if (r == -1)
15239 			scfdie();
15240 
15241 		/* Get next level. */
15242 		nlevel = scf_snaplevel_create(g_hndl);
15243 		if (nlevel == NULL)
15244 			scfdie();
15245 
15246 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15247 		    SCF_SUCCESS) {
15248 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15249 				scfdie();
15250 
15251 			scf_snaplevel_destroy(nlevel);
15252 			break;
15253 		}
15254 
15255 		scf_snaplevel_destroy(level);
15256 		level = nlevel;
15257 	}
15258 
15259 	if (snapname == NULL) {
15260 		lscf_selectsnap(NULL);
15261 		snap = NULL;		/* cur_snap has been destroyed */
15262 	}
15263 
15264 out:
15265 	free(tbuf);
15266 	free(nbuf);
15267 	scf_value_destroy(val);
15268 	scf_property_destroy(prop);
15269 	scf_pg_destroy(npg);
15270 	scf_pg_destroy(pg);
15271 	scf_iter_destroy(iter);
15272 	scf_snaplevel_destroy(level);
15273 	scf_snapshot_destroy(prev);
15274 	if (snap != cur_snap)
15275 		scf_snapshot_destroy(snap);
15276 }
15277 
15278 void
15279 lscf_refresh(void)
15280 {
15281 	ssize_t fmrilen;
15282 	size_t bufsz;
15283 	char *fmribuf;
15284 	int r;
15285 
15286 	lscf_prep_hndl();
15287 
15288 	if (cur_inst == NULL) {
15289 		semerr(gettext("Instance not selected.\n"));
15290 		return;
15291 	}
15292 
15293 	bufsz = max_scf_fmri_len + 1;
15294 	fmribuf = safe_malloc(bufsz);
15295 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15296 	if (fmrilen < 0) {
15297 		free(fmribuf);
15298 		if (scf_error() != SCF_ERROR_DELETED)
15299 			scfdie();
15300 		scf_instance_destroy(cur_inst);
15301 		cur_inst = NULL;
15302 		warn(emsg_deleted);
15303 		return;
15304 	}
15305 	assert(fmrilen < bufsz);
15306 
15307 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15308 	switch (r) {
15309 	case 0:
15310 		break;
15311 
15312 	case ECONNABORTED:
15313 		warn(gettext("Could not refresh %s "
15314 		    "(repository connection broken).\n"), fmribuf);
15315 		break;
15316 
15317 	case ECANCELED:
15318 		warn(emsg_deleted);
15319 		break;
15320 
15321 	case EPERM:
15322 		warn(gettext("Could not refresh %s "
15323 		    "(permission denied).\n"), fmribuf);
15324 		break;
15325 
15326 	case ENOSPC:
15327 		warn(gettext("Could not refresh %s "
15328 		    "(repository server out of resources).\n"),
15329 		    fmribuf);
15330 		break;
15331 
15332 	case EACCES:
15333 	default:
15334 		bad_error("refresh_entity", scf_error());
15335 	}
15336 
15337 	free(fmribuf);
15338 }
15339 
15340 /*
15341  * describe [-v] [-t] [pg/prop]
15342  */
15343 int
15344 lscf_describe(uu_list_t *args, int hasargs)
15345 {
15346 	int ret = 0;
15347 	size_t i;
15348 	int argc;
15349 	char **argv = NULL;
15350 	string_list_t *slp;
15351 	int do_verbose = 0;
15352 	int do_templates = 0;
15353 	char *pattern = NULL;
15354 
15355 	lscf_prep_hndl();
15356 
15357 	if (hasargs != 0)  {
15358 		argc = uu_list_numnodes(args);
15359 		if (argc < 1)
15360 			goto usage;
15361 
15362 		argv = calloc(argc + 1, sizeof (char *));
15363 		if (argv == NULL)
15364 			uu_die(gettext("Out of memory.\n"));
15365 
15366 		for (slp = uu_list_first(args), i = 0;
15367 		    slp != NULL;
15368 		    slp = uu_list_next(args, slp), ++i)
15369 			argv[i] = slp->str;
15370 
15371 		argv[i] = NULL;
15372 
15373 		/*
15374 		 * We start optind = 0 because our list of arguments
15375 		 * starts at argv[0]
15376 		 */
15377 		optind = 0;
15378 		opterr = 0;
15379 		for (;;) {
15380 			ret = getopt(argc, argv, "vt");
15381 			if (ret == -1)
15382 				break;
15383 
15384 			switch (ret) {
15385 			case 'v':
15386 				do_verbose = 1;
15387 				break;
15388 
15389 			case 't':
15390 				do_templates = 1;
15391 				break;
15392 
15393 			case '?':
15394 				goto usage;
15395 
15396 			default:
15397 				bad_error("getopt", ret);
15398 			}
15399 		}
15400 
15401 		pattern = argv[optind];
15402 	}
15403 
15404 	if (cur_inst == NULL && cur_svc == NULL) {
15405 		semerr(emsg_entity_not_selected);
15406 		ret = -1;
15407 		goto out;
15408 	}
15409 
15410 	/*
15411 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15412 	 * output if their last parameter is set to 2.  Less information is
15413 	 * produced if the parameter is set to 1.
15414 	 */
15415 	if (pattern == NULL) {
15416 		if (do_verbose == 1)
15417 			list_entity_tmpl(2);
15418 		else
15419 			list_entity_tmpl(1);
15420 	}
15421 
15422 	if (do_templates == 0) {
15423 		if (do_verbose == 1)
15424 			listprop(pattern, 0, 2);
15425 		else
15426 			listprop(pattern, 0, 1);
15427 	} else {
15428 		if (do_verbose == 1)
15429 			listtmpl(pattern, 2);
15430 		else
15431 			listtmpl(pattern, 1);
15432 	}
15433 
15434 	ret = 0;
15435 out:
15436 	if (argv != NULL)
15437 		free(argv);
15438 	return (ret);
15439 usage:
15440 	ret = -2;
15441 	goto out;
15442 }
15443 
15444 #define	PARAM_ACTIVE	((const char *) "active")
15445 #define	PARAM_INACTIVE	((const char *) "inactive")
15446 #define	PARAM_SMTP_TO	((const char *) "to")
15447 
15448 /*
15449  * tokenize()
15450  * Breaks down the string according to the tokens passed.
15451  * Caller is responsible for freeing array of pointers returned.
15452  * Returns NULL on failure
15453  */
15454 char **
15455 tokenize(char *str, const char *sep)
15456 {
15457 	char *token, *lasts;
15458 	char **buf;
15459 	int n = 0;	/* number of elements */
15460 	int size = 8;	/* size of the array (initial) */
15461 
15462 	buf = safe_malloc(size * sizeof (char *));
15463 
15464 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15465 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15466 		if (n + 1 >= size) {
15467 			size *= 2;
15468 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15469 			    NULL) {
15470 				uu_die(gettext("Out of memory"));
15471 			}
15472 		}
15473 		buf[n] = token;
15474 	}
15475 	/* NULL terminate the pointer array */
15476 	buf[n] = NULL;
15477 
15478 	return (buf);
15479 }
15480 
15481 int32_t
15482 check_tokens(char **p)
15483 {
15484 	int32_t smf = 0;
15485 	int32_t fma = 0;
15486 
15487 	while (*p) {
15488 		int32_t t = string_to_tset(*p);
15489 
15490 		if (t == 0) {
15491 			if (is_fma_token(*p) == 0)
15492 				return (INVALID_TOKENS);
15493 			fma = 1; /* this token is an fma event */
15494 		} else {
15495 			smf |= t;
15496 		}
15497 
15498 		if (smf != 0 && fma == 1)
15499 			return (MIXED_TOKENS);
15500 		++p;
15501 	}
15502 
15503 	if (smf > 0)
15504 		return (smf);
15505 	else if (fma == 1)
15506 		return (FMA_TOKENS);
15507 
15508 	return (INVALID_TOKENS);
15509 }
15510 
15511 static int
15512 get_selection_str(char *fmri, size_t sz)
15513 {
15514 	if (g_hndl == NULL) {
15515 		semerr(emsg_entity_not_selected);
15516 		return (-1);
15517 	} else if (cur_level != NULL) {
15518 		semerr(emsg_invalid_for_snapshot);
15519 		return (-1);
15520 	} else {
15521 		lscf_get_selection_str(fmri, sz);
15522 	}
15523 
15524 	return (0);
15525 }
15526 
15527 void
15528 lscf_delnotify(const char *set, int global)
15529 {
15530 	char *str = strdup(set);
15531 	char **pgs;
15532 	char **p;
15533 	int32_t tset;
15534 	char *fmri = NULL;
15535 
15536 	if (str == NULL)
15537 		uu_die(gettext("Out of memory.\n"));
15538 
15539 	pgs = tokenize(str, ",");
15540 
15541 	if ((tset = check_tokens(pgs)) > 0) {
15542 		size_t sz = max_scf_fmri_len + 1;
15543 
15544 		fmri = safe_malloc(sz);
15545 		if (global) {
15546 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15547 		} else if (get_selection_str(fmri, sz) != 0) {
15548 			goto out;
15549 		}
15550 
15551 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15552 		    tset) != SCF_SUCCESS) {
15553 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15554 			    scf_strerror(scf_error()));
15555 		}
15556 	} else if (tset == FMA_TOKENS) {
15557 		if (global) {
15558 			semerr(gettext("Can't use option '-g' with FMA event "
15559 			    "definitions\n"));
15560 			goto out;
15561 		}
15562 
15563 		for (p = pgs; *p; ++p) {
15564 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15565 			    SCF_SUCCESS) {
15566 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15567 				    scf_strerror(scf_error()));
15568 				goto out;
15569 			}
15570 		}
15571 	} else if (tset == MIXED_TOKENS) {
15572 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15573 		goto out;
15574 	} else {
15575 		uu_die(gettext("Invalid input.\n"));
15576 	}
15577 
15578 out:
15579 	free(fmri);
15580 	free(pgs);
15581 	free(str);
15582 }
15583 
15584 void
15585 lscf_listnotify(const char *set, int global)
15586 {
15587 	char *str = safe_strdup(set);
15588 	char **pgs;
15589 	char **p;
15590 	int32_t tset;
15591 	nvlist_t *nvl;
15592 	char *fmri = NULL;
15593 
15594 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15595 		uu_die(gettext("Out of memory.\n"));
15596 
15597 	pgs = tokenize(str, ",");
15598 
15599 	if ((tset = check_tokens(pgs)) > 0) {
15600 		size_t sz = max_scf_fmri_len + 1;
15601 
15602 		fmri = safe_malloc(sz);
15603 		if (global) {
15604 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15605 		} else if (get_selection_str(fmri, sz) != 0) {
15606 			goto out;
15607 		}
15608 
15609 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15610 		    SCF_SUCCESS) {
15611 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15612 			    scf_error() != SCF_ERROR_DELETED)
15613 				uu_warn(gettext(
15614 				    "Failed listnotify: %s\n"),
15615 				    scf_strerror(scf_error()));
15616 			goto out;
15617 		}
15618 
15619 		listnotify_print(nvl, NULL);
15620 	} else if (tset == FMA_TOKENS) {
15621 		if (global) {
15622 			semerr(gettext("Can't use option '-g' with FMA event "
15623 			    "definitions\n"));
15624 			goto out;
15625 		}
15626 
15627 		for (p = pgs; *p; ++p) {
15628 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15629 			    SCF_SUCCESS) {
15630 				/*
15631 				 * if the preferences have just been deleted
15632 				 * or does not exist, just skip.
15633 				 */
15634 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15635 				    scf_error() == SCF_ERROR_DELETED)
15636 					continue;
15637 				uu_warn(gettext(
15638 				    "Failed listnotify: %s\n"),
15639 				    scf_strerror(scf_error()));
15640 				goto out;
15641 			}
15642 			listnotify_print(nvl, re_tag(*p));
15643 		}
15644 	} else if (tset == MIXED_TOKENS) {
15645 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15646 		goto out;
15647 	} else {
15648 		semerr(gettext("Invalid input.\n"));
15649 	}
15650 
15651 out:
15652 	nvlist_free(nvl);
15653 	free(fmri);
15654 	free(pgs);
15655 	free(str);
15656 }
15657 
15658 static char *
15659 strip_quotes_and_blanks(char *s)
15660 {
15661 	char *start = s;
15662 	char *end = strrchr(s, '\"');
15663 
15664 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15665 		start = s + 1;
15666 		while (isblank(*start))
15667 			start++;
15668 		while (isblank(*(end - 1)) && end > start) {
15669 			end--;
15670 		}
15671 		*end = '\0';
15672 	}
15673 
15674 	return (start);
15675 }
15676 
15677 static int
15678 set_active(nvlist_t *mech, const char *hier_part)
15679 {
15680 	boolean_t b;
15681 
15682 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15683 		b = B_TRUE;
15684 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15685 		b = B_FALSE;
15686 	} else {
15687 		return (-1);
15688 	}
15689 
15690 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15691 		uu_die(gettext("Out of memory.\n"));
15692 
15693 	return (0);
15694 }
15695 
15696 static int
15697 add_snmp_params(nvlist_t *mech, char *hier_part)
15698 {
15699 	return (set_active(mech, hier_part));
15700 }
15701 
15702 static int
15703 add_syslog_params(nvlist_t *mech, char *hier_part)
15704 {
15705 	return (set_active(mech, hier_part));
15706 }
15707 
15708 /*
15709  * add_mailto_paramas()
15710  * parse the hier_part of mailto URI
15711  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15712  * or mailto:{[active]|inactive}
15713  */
15714 static int
15715 add_mailto_params(nvlist_t *mech, char *hier_part)
15716 {
15717 	const char *tok = "?&";
15718 	char *p;
15719 	char *lasts;
15720 	char *param;
15721 	char *val;
15722 
15723 	/*
15724 	 * If the notification parametes are in the form of
15725 	 *
15726 	 *   malito:{[active]|inactive}
15727 	 *
15728 	 * we set the property accordingly and return.
15729 	 * Otherwise, we make the notification type active and
15730 	 * process the hier_part.
15731 	 */
15732 	if (set_active(mech, hier_part) == 0)
15733 		return (0);
15734 	else if (set_active(mech, PARAM_ACTIVE) != 0)
15735 		return (-1);
15736 
15737 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15738 		/*
15739 		 * sanity check: we only get here if hier_part = "", but
15740 		 * that's handled by set_active
15741 		 */
15742 		uu_die("strtok_r");
15743 	}
15744 
15745 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15746 		uu_die(gettext("Out of memory.\n"));
15747 
15748 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
15749 		if ((param = strtok_r(p, "=", &val)) != NULL)
15750 			if (nvlist_add_string(mech, param, val) != 0)
15751 				uu_die(gettext("Out of memory.\n"));
15752 
15753 	return (0);
15754 }
15755 
15756 static int
15757 uri_split(char *uri, char **scheme, char **hier_part)
15758 {
15759 	int r = -1;
15760 
15761 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
15762 	    *hier_part == NULL) {
15763 		semerr(gettext("'%s' is not an URI\n"), uri);
15764 		return (r);
15765 	}
15766 
15767 	if ((r = check_uri_scheme(*scheme)) < 0) {
15768 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
15769 		return (r);
15770 	}
15771 
15772 	return (r);
15773 }
15774 
15775 static int
15776 process_uri(nvlist_t *params, char *uri)
15777 {
15778 	char *scheme;
15779 	char *hier_part;
15780 	nvlist_t *mech;
15781 	int index;
15782 	int r;
15783 
15784 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
15785 		return (-1);
15786 
15787 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
15788 		uu_die(gettext("Out of memory.\n"));
15789 
15790 	switch (index) {
15791 	case 0:
15792 		/* error messages displayed by called function */
15793 		r = add_mailto_params(mech, hier_part);
15794 		break;
15795 
15796 	case 1:
15797 		if ((r = add_snmp_params(mech, hier_part)) != 0)
15798 			semerr(gettext("Not valid parameters: '%s'\n"),
15799 			    hier_part);
15800 		break;
15801 
15802 	case 2:
15803 		if ((r = add_syslog_params(mech, hier_part)) != 0)
15804 			semerr(gettext("Not valid parameters: '%s'\n"),
15805 			    hier_part);
15806 		break;
15807 
15808 	default:
15809 		r = -1;
15810 	}
15811 
15812 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
15813 	    mech) != 0)
15814 		uu_die(gettext("Out of memory.\n"));
15815 
15816 	nvlist_free(mech);
15817 	return (r);
15818 }
15819 
15820 static int
15821 set_params(nvlist_t *params, char **p)
15822 {
15823 	char *uri;
15824 
15825 	if (p == NULL)
15826 		/* sanity check */
15827 		uu_die("set_params");
15828 
15829 	while (*p) {
15830 		uri = strip_quotes_and_blanks(*p);
15831 		if (process_uri(params, uri) != 0)
15832 			return (-1);
15833 
15834 		++p;
15835 	}
15836 
15837 	return (0);
15838 }
15839 
15840 static int
15841 setnotify(const char *e, char **p, int global)
15842 {
15843 	char *str = safe_strdup(e);
15844 	char **events;
15845 	int32_t tset;
15846 	int r = -1;
15847 	nvlist_t *nvl, *params;
15848 	char *fmri = NULL;
15849 
15850 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
15851 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
15852 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
15853 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
15854 		uu_die(gettext("Out of memory.\n"));
15855 
15856 	events = tokenize(str, ",");
15857 
15858 	if ((tset = check_tokens(events)) > 0) {
15859 		/* SMF state transitions parameters */
15860 		size_t sz = max_scf_fmri_len + 1;
15861 
15862 		fmri = safe_malloc(sz);
15863 		if (global) {
15864 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15865 		} else if (get_selection_str(fmri, sz) != 0) {
15866 			goto out;
15867 		}
15868 
15869 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
15870 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
15871 			uu_die(gettext("Out of memory.\n"));
15872 
15873 		if ((r = set_params(params, p)) == 0) {
15874 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
15875 			    params) != 0)
15876 				uu_die(gettext("Out of memory.\n"));
15877 
15878 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
15879 			    nvl) != SCF_SUCCESS) {
15880 				r = -1;
15881 				uu_warn(gettext(
15882 				    "Failed smf_notify_set_params(3SCF): %s\n"),
15883 				    scf_strerror(scf_error()));
15884 			}
15885 		}
15886 	} else if (tset == FMA_TOKENS) {
15887 		/* FMA event parameters */
15888 		if (global) {
15889 			semerr(gettext("Can't use option '-g' with FMA event "
15890 			    "definitions\n"));
15891 			goto out;
15892 		}
15893 
15894 		if ((r = set_params(params, p)) != 0)
15895 			goto out;
15896 
15897 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
15898 			uu_die(gettext("Out of memory.\n"));
15899 
15900 		while (*events) {
15901 			if (smf_notify_set_params(de_tag(*events), nvl) !=
15902 			    SCF_SUCCESS)
15903 				uu_warn(gettext(
15904 				    "Failed smf_notify_set_params(3SCF) for "
15905 				    "event %s: %s\n"), *events,
15906 				    scf_strerror(scf_error()));
15907 			events++;
15908 		}
15909 	} else if (tset == MIXED_TOKENS) {
15910 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15911 	} else {
15912 		/* Sanity check */
15913 		uu_die(gettext("Invalid input.\n"));
15914 	}
15915 
15916 out:
15917 	nvlist_free(nvl);
15918 	nvlist_free(params);
15919 	free(fmri);
15920 	free(str);
15921 
15922 	return (r);
15923 }
15924 
15925 int
15926 lscf_setnotify(uu_list_t *args)
15927 {
15928 	int argc;
15929 	char **argv = NULL;
15930 	string_list_t *slp;
15931 	int global;
15932 	char *events;
15933 	char **p;
15934 	int i;
15935 	int ret;
15936 
15937 	if ((argc = uu_list_numnodes(args)) < 2)
15938 		goto usage;
15939 
15940 	argv = calloc(argc + 1, sizeof (char *));
15941 	if (argv == NULL)
15942 		uu_die(gettext("Out of memory.\n"));
15943 
15944 	for (slp = uu_list_first(args), i = 0;
15945 	    slp != NULL;
15946 	    slp = uu_list_next(args, slp), ++i)
15947 		argv[i] = slp->str;
15948 
15949 	argv[i] = NULL;
15950 
15951 	if (strcmp(argv[0], "-g") == 0) {
15952 		global = 1;
15953 		events = argv[1];
15954 		p = argv + 2;
15955 	} else {
15956 		global = 0;
15957 		events = argv[0];
15958 		p = argv + 1;
15959 	}
15960 
15961 	ret = setnotify(events, p, global);
15962 
15963 out:
15964 	free(argv);
15965 	return (ret);
15966 
15967 usage:
15968 	ret = -2;
15969 	goto out;
15970 }
15971 
15972 /*
15973  * Creates a list of instance name strings associated with a service. If
15974  * wohandcrafted flag is set, get only instances that have a last-import
15975  * snapshot, instances that were imported via svccfg.
15976  */
15977 static uu_list_t *
15978 create_instance_list(scf_service_t *svc, int wohandcrafted)
15979 {
15980 	scf_snapshot_t  *snap = NULL;
15981 	scf_instance_t  *inst;
15982 	scf_iter_t	*inst_iter;
15983 	uu_list_t	*instances;
15984 	char		*instname;
15985 	int		r;
15986 
15987 	inst_iter = scf_iter_create(g_hndl);
15988 	inst = scf_instance_create(g_hndl);
15989 	if (inst_iter == NULL || inst == NULL) {
15990 		uu_warn(gettext("Could not create instance or iterator\n"));
15991 		scfdie();
15992 	}
15993 
15994 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
15995 		return (instances);
15996 
15997 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
15998 		switch (scf_error()) {
15999 		case SCF_ERROR_CONNECTION_BROKEN:
16000 		case SCF_ERROR_DELETED:
16001 			uu_list_destroy(instances);
16002 			instances = NULL;
16003 			goto out;
16004 
16005 		case SCF_ERROR_HANDLE_MISMATCH:
16006 		case SCF_ERROR_NOT_BOUND:
16007 		case SCF_ERROR_NOT_SET:
16008 		default:
16009 			bad_error("scf_iter_service_instances", scf_error());
16010 		}
16011 	}
16012 
16013 	instname = safe_malloc(max_scf_name_len + 1);
16014 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
16015 		if (r == -1) {
16016 			(void) uu_warn(gettext("Unable to iterate through "
16017 			    "instances to create instance list : %s\n"),
16018 			    scf_strerror(scf_error()));
16019 
16020 			uu_list_destroy(instances);
16021 			instances = NULL;
16022 			goto out;
16023 		}
16024 
16025 		/*
16026 		 * If the instance does not have a last-import snapshot
16027 		 * then do not add it to the list as it is a hand-crafted
16028 		 * instance that should not be managed.
16029 		 */
16030 		if (wohandcrafted) {
16031 			if (snap == NULL &&
16032 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
16033 				uu_warn(gettext("Unable to create snapshot "
16034 				    "entity\n"));
16035 				scfdie();
16036 			}
16037 
16038 			if (scf_instance_get_snapshot(inst,
16039 			    snap_lastimport, snap) != 0) {
16040 				switch (scf_error()) {
16041 				case SCF_ERROR_NOT_FOUND :
16042 				case SCF_ERROR_DELETED:
16043 					continue;
16044 
16045 				case SCF_ERROR_CONNECTION_BROKEN:
16046 					uu_list_destroy(instances);
16047 					instances = NULL;
16048 					goto out;
16049 
16050 				case SCF_ERROR_HANDLE_MISMATCH:
16051 				case SCF_ERROR_NOT_BOUND:
16052 				case SCF_ERROR_NOT_SET:
16053 				default:
16054 					bad_error("scf_iter_service_instances",
16055 					    scf_error());
16056 				}
16057 			}
16058 		}
16059 
16060 		if (scf_instance_get_name(inst, instname,
16061 		    max_scf_name_len + 1) < 0) {
16062 			switch (scf_error()) {
16063 			case SCF_ERROR_NOT_FOUND :
16064 				continue;
16065 
16066 			case SCF_ERROR_CONNECTION_BROKEN:
16067 			case SCF_ERROR_DELETED:
16068 				uu_list_destroy(instances);
16069 				instances = NULL;
16070 				goto out;
16071 
16072 			case SCF_ERROR_HANDLE_MISMATCH:
16073 			case SCF_ERROR_NOT_BOUND:
16074 			case SCF_ERROR_NOT_SET:
16075 			default:
16076 				bad_error("scf_iter_service_instances",
16077 				    scf_error());
16078 			}
16079 		}
16080 
16081 		add_string(instances, instname);
16082 	}
16083 
16084 out:
16085 	if (snap)
16086 		scf_snapshot_destroy(snap);
16087 
16088 	scf_instance_destroy(inst);
16089 	scf_iter_destroy(inst_iter);
16090 	free(instname);
16091 	return (instances);
16092 }
16093 
16094 /*
16095  * disable an instance but wait for the instance to
16096  * move out of the running state.
16097  *
16098  * Returns 0 : if the instance did not disable
16099  * Returns non-zero : if the instance disabled.
16100  *
16101  */
16102 static int
16103 disable_instance(scf_instance_t *instance)
16104 {
16105 	char	*fmribuf;
16106 	int	enabled = 10000;
16107 
16108 	if (inst_is_running(instance)) {
16109 		fmribuf = safe_malloc(max_scf_name_len + 1);
16110 		if (scf_instance_to_fmri(instance, fmribuf,
16111 		    max_scf_name_len + 1) < 0) {
16112 			free(fmribuf);
16113 			return (0);
16114 		}
16115 
16116 		/*
16117 		 * If the instance cannot be disabled then return
16118 		 * failure to disable and let the caller decide
16119 		 * if that is of importance.
16120 		 */
16121 		if (smf_disable_instance(fmribuf, 0) != 0) {
16122 			free(fmribuf);
16123 			return (0);
16124 		}
16125 
16126 		while (enabled) {
16127 			if (!inst_is_running(instance))
16128 				break;
16129 
16130 			(void) poll(NULL, 0, 5);
16131 			enabled = enabled - 5;
16132 		}
16133 
16134 		free(fmribuf);
16135 	}
16136 
16137 	return (enabled);
16138 }
16139 
16140 /*
16141  * Function to compare two service_manifest structures.
16142  */
16143 /* ARGSUSED2 */
16144 static int
16145 service_manifest_compare(const void *left, const void *right, void *unused)
16146 {
16147 	service_manifest_t *l = (service_manifest_t *)left;
16148 	service_manifest_t *r = (service_manifest_t *)right;
16149 	int rc;
16150 
16151 	rc = strcmp(l->servicename, r->servicename);
16152 
16153 	return (rc);
16154 }
16155 
16156 /*
16157  * Look for the provided service in the service to manifest
16158  * tree.  If the service exists, and a manifest was provided
16159  * then add the manifest to that service.  If the service
16160  * does not exist, then add the service and manifest to the
16161  * list.
16162  *
16163  * If the manifest is NULL, return the element if found.  If
16164  * the service is not found return NULL.
16165  */
16166 service_manifest_t *
16167 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16168 {
16169 	service_manifest_t	elem;
16170 	service_manifest_t	*fnelem;
16171 	uu_avl_index_t		marker;
16172 
16173 	elem.servicename = svnbuf;
16174 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16175 
16176 	if (mfst) {
16177 		if (fnelem) {
16178 			add_string(fnelem->mfstlist, strdup(mfst));
16179 		} else {
16180 			fnelem = safe_malloc(sizeof (*fnelem));
16181 			fnelem->servicename = safe_strdup(svnbuf);
16182 			if ((fnelem->mfstlist =
16183 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16184 				uu_die(gettext("Could not create property "
16185 				    "list: %s\n"), uu_strerror(uu_error()));
16186 
16187 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16188 
16189 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16190 		}
16191 	}
16192 
16193 	return (fnelem);
16194 }
16195 
16196 /*
16197  * Create the service to manifest avl tree.
16198  *
16199  * Walk each of the manifests currently installed in the supported
16200  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16201  * each of the manifests, inventory the services and add them to
16202  * the tree.
16203  *
16204  * Code that calls this function should make sure fileystem/minimal is online,
16205  * /var is available, since this function walks the /var/svc/manifest directory.
16206  */
16207 static void
16208 create_manifest_tree(void)
16209 {
16210 	manifest_info_t **entry;
16211 	manifest_info_t **manifests;
16212 	uu_list_walk_t	*svcs;
16213 	bundle_t	*b;
16214 	entity_t	*mfsvc;
16215 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16216 	int		c, status;
16217 
16218 	if (service_manifest_pool)
16219 		return;
16220 
16221 	/*
16222 	 * Create the list pool for the service manifest list
16223 	 */
16224 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16225 	    sizeof (service_manifest_t),
16226 	    offsetof(service_manifest_t, svcmfst_node),
16227 	    service_manifest_compare, UU_DEFAULT);
16228 	if (service_manifest_pool == NULL)
16229 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16230 		    uu_strerror(uu_error()));
16231 
16232 	/*
16233 	 * Create the list
16234 	 */
16235 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16236 	    UU_DEFAULT);
16237 	if (service_manifest_tree == NULL)
16238 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16239 		    uu_strerror(uu_error()));
16240 
16241 	/*
16242 	 * Walk the manifests adding the service(s) from each manifest.
16243 	 *
16244 	 * If a service already exists add the manifest to the manifest
16245 	 * list for that service.  This covers the case of a service that
16246 	 * is supported by multiple manifest files.
16247 	 */
16248 	for (c = 0; dirs[c]; c++) {
16249 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16250 		if (status < 0) {
16251 			uu_warn(gettext("file tree walk of %s encountered "
16252 			    "error %s\n"), dirs[c], strerror(errno));
16253 
16254 			uu_avl_destroy(service_manifest_tree);
16255 			service_manifest_tree = NULL;
16256 			return;
16257 		}
16258 
16259 		/*
16260 		 * If a manifest that was in the list is not found
16261 		 * then skip and go to the next manifest file.
16262 		 */
16263 		if (manifests != NULL) {
16264 			for (entry = manifests; *entry != NULL; entry++) {
16265 				b = internal_bundle_new();
16266 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16267 				    SVCCFG_OP_IMPORT) != 0) {
16268 					internal_bundle_free(b);
16269 					continue;
16270 				}
16271 
16272 				svcs = uu_list_walk_start(b->sc_bundle_services,
16273 				    0);
16274 				if (svcs == NULL) {
16275 					internal_bundle_free(b);
16276 					continue;
16277 				}
16278 
16279 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16280 				    NULL) {
16281 					/* Add manifest to service */
16282 					(void) find_add_svc_mfst(mfsvc->sc_name,
16283 					    (*entry)->mi_path);
16284 				}
16285 
16286 				uu_list_walk_end(svcs);
16287 				internal_bundle_free(b);
16288 			}
16289 
16290 			free_manifest_array(manifests);
16291 		}
16292 	}
16293 }
16294 
16295 /*
16296  * Check the manifest history file to see
16297  * if the service was ever installed from
16298  * one of the supported directories.
16299  *
16300  * Return Values :
16301  * 	-1 - if there's error reading manifest history file
16302  *	 1 - if the service is not found
16303  *	 0 - if the service is found
16304  */
16305 static int
16306 check_mfst_history(const char *svcname)
16307 {
16308 	struct stat	st;
16309 	caddr_t		mfsthist_start;
16310 	char		*svnbuf;
16311 	int		fd;
16312 	int		r = 1;
16313 
16314 	fd = open(MFSTHISTFILE, O_RDONLY);
16315 	if (fd == -1) {
16316 		uu_warn(gettext("Unable to open the history file\n"));
16317 		return (-1);
16318 	}
16319 
16320 	if (fstat(fd, &st) == -1) {
16321 		uu_warn(gettext("Unable to stat the history file\n"));
16322 		return (-1);
16323 	}
16324 
16325 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16326 	    MAP_PRIVATE, fd, 0);
16327 
16328 	(void) close(fd);
16329 	if (mfsthist_start == MAP_FAILED ||
16330 	    *(mfsthist_start + st.st_size) != '\0') {
16331 		(void) munmap(mfsthist_start, st.st_size);
16332 		return (-1);
16333 	}
16334 
16335 	/*
16336 	 * The manifest history file is a space delimited list
16337 	 * of service and instance to manifest linkage.  Adding
16338 	 * a space to the end of the service name so to get only
16339 	 * the service that is being searched for.
16340 	 */
16341 	svnbuf = uu_msprintf("%s ", svcname);
16342 	if (svnbuf == NULL)
16343 		uu_die(gettext("Out of memory"));
16344 
16345 	if (strstr(mfsthist_start, svnbuf) != NULL)
16346 		r = 0;
16347 
16348 	(void) munmap(mfsthist_start, st.st_size);
16349 	uu_free(svnbuf);
16350 	return (r);
16351 }
16352 
16353 /*
16354  * Take down each of the instances in the service
16355  * and remove them, then delete the service.
16356  */
16357 static void
16358 teardown_service(scf_service_t *svc, const char *svnbuf)
16359 {
16360 	scf_instance_t	*instance;
16361 	scf_iter_t	*iter;
16362 	int		r;
16363 
16364 	safe_printf(gettext("Delete service %s as there are no "
16365 	    "supporting manifests\n"), svnbuf);
16366 
16367 	instance = scf_instance_create(g_hndl);
16368 	iter = scf_iter_create(g_hndl);
16369 	if (iter == NULL || instance == NULL) {
16370 		uu_warn(gettext("Unable to create supporting entities to "
16371 		    "teardown the service\n"));
16372 		uu_warn(gettext("scf error is : %s\n"),
16373 		    scf_strerror(scf_error()));
16374 		scfdie();
16375 	}
16376 
16377 	if (scf_iter_service_instances(iter, svc) != 0) {
16378 		switch (scf_error()) {
16379 		case SCF_ERROR_CONNECTION_BROKEN:
16380 		case SCF_ERROR_DELETED:
16381 			goto out;
16382 
16383 		case SCF_ERROR_HANDLE_MISMATCH:
16384 		case SCF_ERROR_NOT_BOUND:
16385 		case SCF_ERROR_NOT_SET:
16386 		default:
16387 			bad_error("scf_iter_service_instances",
16388 			    scf_error());
16389 		}
16390 	}
16391 
16392 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16393 		if (r == -1) {
16394 			uu_warn(gettext("Error - %s\n"),
16395 			    scf_strerror(scf_error()));
16396 			goto out;
16397 		}
16398 
16399 		(void) disable_instance(instance);
16400 	}
16401 
16402 	/*
16403 	 * Delete the service... forcing the deletion in case
16404 	 * any of the instances did not disable.
16405 	 */
16406 	(void) lscf_service_delete(svc, 1);
16407 out:
16408 	scf_instance_destroy(instance);
16409 	scf_iter_destroy(iter);
16410 }
16411 
16412 /*
16413  * Get the list of instances supported by the manifest
16414  * file.
16415  *
16416  * Return 0 if there are no instances.
16417  *
16418  * Return -1 if there are errors attempting to collect instances.
16419  *
16420  * Return the count of instances found if there are no errors.
16421  *
16422  */
16423 static int
16424 check_instance_support(char *mfstfile, const char *svcname,
16425     uu_list_t *instances)
16426 {
16427 	uu_list_walk_t	*svcs, *insts;
16428 	uu_list_t	*ilist;
16429 	bundle_t	*b;
16430 	entity_t	*mfsvc, *mfinst;
16431 	const char	*svcn;
16432 	int		rminstcnt = 0;
16433 
16434 
16435 	b = internal_bundle_new();
16436 
16437 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16438 		/*
16439 		 * Unable to process the manifest file for
16440 		 * instance support, so just return as
16441 		 * don't want to remove instances that could
16442 		 * not be accounted for that might exist here.
16443 		 */
16444 		internal_bundle_free(b);
16445 		return (0);
16446 	}
16447 
16448 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16449 	if (svcs == NULL) {
16450 		internal_bundle_free(b);
16451 		return (0);
16452 	}
16453 
16454 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16455 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16456 
16457 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16458 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16459 			break;
16460 	}
16461 	uu_list_walk_end(svcs);
16462 
16463 	if (mfsvc == NULL) {
16464 		internal_bundle_free(b);
16465 		return (-1);
16466 	}
16467 
16468 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16469 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16470 		internal_bundle_free(b);
16471 		return (0);
16472 	}
16473 
16474 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16475 		/*
16476 		 * Remove the instance from the instances list.
16477 		 * The unaccounted for instances will be removed
16478 		 * from the service once all manifests are
16479 		 * processed.
16480 		 */
16481 		(void) remove_string(instances,
16482 		    mfinst->sc_name);
16483 		rminstcnt++;
16484 	}
16485 
16486 	uu_list_walk_end(insts);
16487 	internal_bundle_free(b);
16488 
16489 	return (rminstcnt);
16490 }
16491 
16492 /*
16493  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16494  * 'false' to indicate there's no manifest file(s) found for the service.
16495  */
16496 static void
16497 svc_add_no_support(scf_service_t *svc)
16498 {
16499 	char	*pname;
16500 
16501 	/* Add no support */
16502 	cur_svc = svc;
16503 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16504 		return;
16505 
16506 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16507 	if (pname == NULL)
16508 		uu_die(gettext("Out of memory.\n"));
16509 
16510 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16511 
16512 	uu_free(pname);
16513 	cur_svc = NULL;
16514 }
16515 
16516 /*
16517  * This function handles all upgrade scenarios for a service that doesn't have
16518  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16519  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16520  * manifest(s) mapping. Manifests under supported directories are inventoried
16521  * and a property is added for each file that delivers configuration to the
16522  * service.  A service that has no corresponding manifest files (deleted) are
16523  * removed from repository.
16524  *
16525  * Unsupported services:
16526  *
16527  * A service is considered unsupported if there is no corresponding manifest
16528  * in the supported directories for that service and the service isn't in the
16529  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16530  * services and instances that were delivered by Solaris before the introduction
16531  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16532  * the path to the manifest file that defined the service or instance.
16533  *
16534  * Another type of unsupported services is 'handcrafted' services,
16535  * programmatically created services or services created by dependent entries
16536  * in other manifests. A handcrafted service is identified by its lack of any
16537  * instance containing last-import snapshot which is created during svccfg
16538  * import.
16539  *
16540  * This function sets a flag for unsupported services by setting services'
16541  * SCF_PG_MANIFESTFILES/support property to false.
16542  */
16543 static void
16544 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16545 {
16546 	service_manifest_t	*elem;
16547 	uu_list_walk_t		*mfwalk;
16548 	string_list_t		*mfile;
16549 	uu_list_t		*instances;
16550 	const char		*sname;
16551 	char			*pname;
16552 	int			r;
16553 
16554 	/*
16555 	 * Since there's no guarantee manifests under /var are available during
16556 	 * early import, don't perform any upgrade during early import.
16557 	 */
16558 	if (IGNORE_VAR)
16559 		return;
16560 
16561 	if (service_manifest_tree == NULL) {
16562 		create_manifest_tree();
16563 	}
16564 
16565 	/*
16566 	 * Find service's supporting manifest(s) after
16567 	 * stripping off the svc:/ prefix that is part
16568 	 * of the fmri that is not used in the service
16569 	 * manifest bundle list.
16570 	 */
16571 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16572 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16573 	elem = find_add_svc_mfst(sname, NULL);
16574 	if (elem == NULL) {
16575 
16576 		/*
16577 		 * A handcrafted service, one that has no instance containing
16578 		 * last-import snapshot, should get unsupported flag.
16579 		 */
16580 		instances = create_instance_list(svc, 1);
16581 		if (instances == NULL) {
16582 			uu_warn(gettext("Unable to create instance list %s\n"),
16583 			    svcname);
16584 			return;
16585 		}
16586 
16587 		if (uu_list_numnodes(instances) == 0) {
16588 			svc_add_no_support(svc);
16589 			return;
16590 		}
16591 
16592 		/*
16593 		 * If the service is in the history file, and its supporting
16594 		 * manifests are not found, we can safely delete the service
16595 		 * because its manifests are removed from the system.
16596 		 *
16597 		 * Services not found in the history file are not delivered by
16598 		 * Solaris and/or delivered outside supported directories, set
16599 		 * unsupported flag for these services.
16600 		 */
16601 		r = check_mfst_history(svcname);
16602 		if (r == -1)
16603 			return;
16604 
16605 		if (r) {
16606 			/* Set unsupported flag for service  */
16607 			svc_add_no_support(svc);
16608 		} else {
16609 			/* Delete the service */
16610 			teardown_service(svc, svcname);
16611 		}
16612 
16613 		return;
16614 	}
16615 
16616 	/*
16617 	 * Walk through the list of manifests and add them
16618 	 * to the service.
16619 	 *
16620 	 * Create a manifestfiles pg and add the property.
16621 	 */
16622 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16623 	if (mfwalk == NULL)
16624 		return;
16625 
16626 	cur_svc = svc;
16627 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16628 	if (r != 0) {
16629 		cur_svc = NULL;
16630 		return;
16631 	}
16632 
16633 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16634 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16635 		    mhash_filename_to_propname(mfile->str, 0));
16636 		if (pname == NULL)
16637 			uu_die(gettext("Out of memory.\n"));
16638 
16639 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16640 		uu_free(pname);
16641 	}
16642 	uu_list_walk_end(mfwalk);
16643 
16644 	cur_svc = NULL;
16645 }
16646 
16647 /*
16648  * Take a service and process the manifest file entires to see if
16649  * there is continued support for the service and instances.  If
16650  * not cleanup as appropriate.
16651  *
16652  * If a service does not have a manifest files entry flag it for
16653  * upgrade and return.
16654  *
16655  * For each manifestfiles property check if the manifest file is
16656  * under the supported /lib/svc/manifest or /var/svc/manifest path
16657  * and if not then return immediately as this service is not supported
16658  * by the cleanup mechanism and should be ignored.
16659  *
16660  * For each manifest file that is supported, check to see if the
16661  * file exists.  If not then remove the manifest file property
16662  * from the service and the smf/manifest hash table.  If the manifest
16663  * file exists then verify that it supports the instances that are
16664  * part of the service.
16665  *
16666  * Once all manifest files have been accounted for remove any instances
16667  * that are no longer supported in the service.
16668  *
16669  * Return values :
16670  * 0 - Successfully processed the service
16671  * non-zero - failed to process the service
16672  *
16673  * On most errors, will just return to wait and get the next service,
16674  * unless in case of unable to create the needed structures which is
16675  * most likely a fatal error that is not going to be recoverable.
16676  */
16677 int
16678 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16679 {
16680 	struct mpg_mfile	*mpntov;
16681 	struct mpg_mfile	**mpvarry = NULL;
16682 	scf_service_t		*svc;
16683 	scf_propertygroup_t	*mpg;
16684 	scf_property_t		*mp;
16685 	scf_value_t		*mv;
16686 	scf_iter_t		*mi;
16687 	scf_instance_t		*instance;
16688 	uu_list_walk_t		*insts;
16689 	uu_list_t		*instances = NULL;
16690 	boolean_t		activity = (boolean_t)act;
16691 	char			*mpnbuf;
16692 	char			*mpvbuf;
16693 	char			*pgpropbuf;
16694 	int			mfstcnt, rminstct, instct, mfstmax;
16695 	int			index;
16696 	int			r = 0;
16697 
16698 	assert(g_hndl != NULL);
16699 	assert(wip->svc != NULL);
16700 	assert(wip->fmri != NULL);
16701 
16702 	svc = wip->svc;
16703 
16704 	mpg = scf_pg_create(g_hndl);
16705 	mp = scf_property_create(g_hndl);
16706 	mi = scf_iter_create(g_hndl);
16707 	mv = scf_value_create(g_hndl);
16708 	instance = scf_instance_create(g_hndl);
16709 
16710 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16711 	    instance == NULL) {
16712 		uu_warn(gettext("Unable to create the supporting entities\n"));
16713 		uu_warn(gettext("scf error is : %s\n"),
16714 		    scf_strerror(scf_error()));
16715 		scfdie();
16716 	}
16717 
16718 	/*
16719 	 * Get the manifestfiles property group to be parsed for
16720 	 * files existence.
16721 	 */
16722 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16723 		switch (scf_error()) {
16724 		case SCF_ERROR_NOT_FOUND:
16725 			upgrade_svc_mfst_connection(svc, wip->fmri);
16726 			break;
16727 		case SCF_ERROR_DELETED:
16728 		case SCF_ERROR_CONNECTION_BROKEN:
16729 			goto out;
16730 
16731 		case SCF_ERROR_HANDLE_MISMATCH:
16732 		case SCF_ERROR_NOT_BOUND:
16733 		case SCF_ERROR_NOT_SET:
16734 		default:
16735 			bad_error("scf_iter_pg_properties",
16736 			    scf_error());
16737 		}
16738 
16739 		goto out;
16740 	}
16741 
16742 	/*
16743 	 * Iterate through each of the manifestfiles properties
16744 	 * to determine what manifestfiles are available.
16745 	 *
16746 	 * If a manifest file is supported then increment the
16747 	 * count and therefore the service is safe.
16748 	 */
16749 	if (scf_iter_pg_properties(mi, mpg) != 0) {
16750 		switch (scf_error()) {
16751 		case SCF_ERROR_DELETED:
16752 		case SCF_ERROR_CONNECTION_BROKEN:
16753 			goto out;
16754 
16755 		case SCF_ERROR_HANDLE_MISMATCH:
16756 		case SCF_ERROR_NOT_BOUND:
16757 		case SCF_ERROR_NOT_SET:
16758 		default:
16759 			bad_error("scf_iter_pg_properties",
16760 			    scf_error());
16761 		}
16762 	}
16763 
16764 	mfstcnt = 0;
16765 	mfstmax = MFSTFILE_MAX;
16766 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
16767 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
16768 		if (r == -1)
16769 			bad_error(gettext("Unable to iterate through "
16770 			    "manifestfiles properties : %s"),
16771 			    scf_error());
16772 
16773 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
16774 		mpnbuf = safe_malloc(max_scf_name_len + 1);
16775 		mpvbuf = safe_malloc(max_scf_value_len + 1);
16776 		mpntov->mpg = mpnbuf;
16777 		mpntov->mfile = mpvbuf;
16778 		mpntov->access = 1;
16779 		if (scf_property_get_name(mp, mpnbuf,
16780 		    max_scf_name_len + 1) < 0) {
16781 			uu_warn(gettext("Unable to get manifest file "
16782 			    "property : %s\n"),
16783 			    scf_strerror(scf_error()));
16784 
16785 			switch (scf_error()) {
16786 			case SCF_ERROR_DELETED:
16787 			case SCF_ERROR_CONNECTION_BROKEN:
16788 				r = scferror2errno(scf_error());
16789 				goto out_free;
16790 
16791 			case SCF_ERROR_HANDLE_MISMATCH:
16792 			case SCF_ERROR_NOT_BOUND:
16793 			case SCF_ERROR_NOT_SET:
16794 			default:
16795 				bad_error("scf_iter_pg_properties",
16796 				    scf_error());
16797 			}
16798 		}
16799 
16800 		/*
16801 		 * The support property is a boolean value that indicates
16802 		 * if the service is supported for manifest file deletion.
16803 		 * Currently at this time there is no code that sets this
16804 		 * value to true.  So while we could just let this be caught
16805 		 * by the support check below, in the future this by be set
16806 		 * to true and require processing.  So for that, go ahead
16807 		 * and check here, and just return if false.  Otherwise,
16808 		 * fall through expecting that other support checks will
16809 		 * handle the entries.
16810 		 */
16811 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
16812 			uint8_t	support;
16813 
16814 			if (scf_property_get_value(mp, mv) != 0 ||
16815 			    scf_value_get_boolean(mv, &support) != 0) {
16816 				uu_warn(gettext("Unable to get the manifest "
16817 				    "support value: %s\n"),
16818 				    scf_strerror(scf_error()));
16819 
16820 				switch (scf_error()) {
16821 				case SCF_ERROR_DELETED:
16822 				case SCF_ERROR_CONNECTION_BROKEN:
16823 					r = scferror2errno(scf_error());
16824 					goto out_free;
16825 
16826 				case SCF_ERROR_HANDLE_MISMATCH:
16827 				case SCF_ERROR_NOT_BOUND:
16828 				case SCF_ERROR_NOT_SET:
16829 				default:
16830 					bad_error("scf_iter_pg_properties",
16831 					    scf_error());
16832 				}
16833 			}
16834 
16835 			if (support == B_FALSE)
16836 				goto out_free;
16837 		}
16838 
16839 		/*
16840 		 * Anything with a manifest outside of the supported
16841 		 * directories, immediately bail out because that makes
16842 		 * this service non-supported.  We don't even want
16843 		 * to do instance processing in this case because the
16844 		 * instances could be part of the non-supported manifest.
16845 		 */
16846 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
16847 			/*
16848 			 * Manifest is not in /lib/svc, so we need to
16849 			 * consider the /var/svc case.
16850 			 */
16851 			if (strncmp(mpnbuf, VARSVC_PR,
16852 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
16853 				/*
16854 				 * Either the manifest is not in /var/svc or
16855 				 * /var is not yet mounted.  We ignore the
16856 				 * manifest either because it is not in a
16857 				 * standard location or because we cannot
16858 				 * currently access the manifest.
16859 				 */
16860 				goto out_free;
16861 			}
16862 		}
16863 
16864 		/*
16865 		 * Get the value to of the manifest file for this entry
16866 		 * for access verification and instance support
16867 		 * verification if it still exists.
16868 		 *
16869 		 * During Early Manifest Import if the manifest is in
16870 		 * /var/svc then it may not yet be available for checking
16871 		 * so we must determine if /var/svc is available.  If not
16872 		 * then defer until Late Manifest Import to cleanup.
16873 		 */
16874 		if (scf_property_get_value(mp, mv) != 0) {
16875 			uu_warn(gettext("Unable to get the manifest file "
16876 			    "value: %s\n"),
16877 			    scf_strerror(scf_error()));
16878 
16879 			switch (scf_error()) {
16880 			case SCF_ERROR_DELETED:
16881 			case SCF_ERROR_CONNECTION_BROKEN:
16882 				r = scferror2errno(scf_error());
16883 				goto out_free;
16884 
16885 			case SCF_ERROR_HANDLE_MISMATCH:
16886 			case SCF_ERROR_NOT_BOUND:
16887 			case SCF_ERROR_NOT_SET:
16888 			default:
16889 				bad_error("scf_property_get_value",
16890 				    scf_error());
16891 			}
16892 		}
16893 
16894 		if (scf_value_get_astring(mv, mpvbuf,
16895 		    max_scf_value_len + 1) < 0) {
16896 			uu_warn(gettext("Unable to get the manifest "
16897 			    "file : %s\n"),
16898 			    scf_strerror(scf_error()));
16899 
16900 			switch (scf_error()) {
16901 			case SCF_ERROR_DELETED:
16902 			case SCF_ERROR_CONNECTION_BROKEN:
16903 				r = scferror2errno(scf_error());
16904 				goto out_free;
16905 
16906 			case SCF_ERROR_HANDLE_MISMATCH:
16907 			case SCF_ERROR_NOT_BOUND:
16908 			case SCF_ERROR_NOT_SET:
16909 			default:
16910 				bad_error("scf_value_get_astring",
16911 				    scf_error());
16912 			}
16913 		}
16914 
16915 		mpvarry[mfstcnt] = mpntov;
16916 		mfstcnt++;
16917 
16918 		/*
16919 		 * Check for the need to reallocate array
16920 		 */
16921 		if (mfstcnt >= (mfstmax - 1)) {
16922 			struct mpg_mfile **newmpvarry;
16923 
16924 			mfstmax = mfstmax * 2;
16925 			newmpvarry = realloc(mpvarry,
16926 			    sizeof (struct mpg_mfile *) * mfstmax);
16927 
16928 			if (newmpvarry == NULL)
16929 				goto out_free;
16930 
16931 			mpvarry = newmpvarry;
16932 		}
16933 
16934 		mpvarry[mfstcnt] = NULL;
16935 	}
16936 
16937 	for (index = 0; mpvarry[index]; index++) {
16938 		mpntov = mpvarry[index];
16939 
16940 		/*
16941 		 * Check to see if the manifestfile is accessable, if so hand
16942 		 * this service and manifestfile off to be processed for
16943 		 * instance support.
16944 		 */
16945 		mpnbuf = mpntov->mpg;
16946 		mpvbuf = mpntov->mfile;
16947 		if (access(mpvbuf, F_OK) != 0) {
16948 			mpntov->access = 0;
16949 			activity++;
16950 			mfstcnt--;
16951 			/* Remove the entry from the service */
16952 			cur_svc = svc;
16953 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16954 			    mpnbuf);
16955 			if (pgpropbuf == NULL)
16956 				uu_die(gettext("Out of memory.\n"));
16957 
16958 			lscf_delprop(pgpropbuf);
16959 			cur_svc = NULL;
16960 
16961 			uu_free(pgpropbuf);
16962 		}
16963 	}
16964 
16965 	/*
16966 	 * If mfstcnt is 0, none of the manifests that supported the service
16967 	 * existed so remove the service.
16968 	 */
16969 	if (mfstcnt == 0) {
16970 		teardown_service(svc, wip->fmri);
16971 
16972 		goto out_free;
16973 	}
16974 
16975 	if (activity) {
16976 		int	nosvcsupport = 0;
16977 
16978 		/*
16979 		 * If the list of service instances is NULL then
16980 		 * create the list.
16981 		 */
16982 		instances = create_instance_list(svc, 1);
16983 		if (instances == NULL) {
16984 			uu_warn(gettext("Unable to create instance list %s\n"),
16985 			    wip->fmri);
16986 			goto out_free;
16987 		}
16988 
16989 		rminstct = uu_list_numnodes(instances);
16990 		instct = rminstct;
16991 
16992 		for (index = 0; mpvarry[index]; index++) {
16993 			mpntov = mpvarry[index];
16994 			if (mpntov->access == 0)
16995 				continue;
16996 
16997 			mpnbuf = mpntov->mpg;
16998 			mpvbuf = mpntov->mfile;
16999 			r = check_instance_support(mpvbuf, wip->fmri,
17000 			    instances);
17001 			if (r == -1) {
17002 				nosvcsupport++;
17003 			} else {
17004 				rminstct -= r;
17005 			}
17006 		}
17007 
17008 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
17009 			teardown_service(svc, wip->fmri);
17010 
17011 			goto out_free;
17012 		}
17013 	}
17014 
17015 	/*
17016 	 * If there are instances left on the instance list, then
17017 	 * we must remove them.
17018 	 */
17019 	if (instances != NULL && uu_list_numnodes(instances)) {
17020 		string_list_t *sp;
17021 
17022 		insts = uu_list_walk_start(instances, 0);
17023 		while ((sp = uu_list_walk_next(insts)) != NULL) {
17024 			/*
17025 			 * Remove the instance from the instances list.
17026 			 */
17027 			safe_printf(gettext("Delete instance %s from "
17028 			    "service %s\n"), sp->str, wip->fmri);
17029 			if (scf_service_get_instance(svc, sp->str,
17030 			    instance) != SCF_SUCCESS) {
17031 				(void) uu_warn("scf_error - %s\n",
17032 				    scf_strerror(scf_error()));
17033 
17034 				continue;
17035 			}
17036 
17037 			(void) disable_instance(instance);
17038 
17039 			(void) lscf_instance_delete(instance, 1);
17040 		}
17041 		scf_instance_destroy(instance);
17042 		uu_list_walk_end(insts);
17043 	}
17044 
17045 out_free:
17046 	if (mpvarry) {
17047 		struct mpg_mfile *fmpntov;
17048 
17049 		for (index = 0; mpvarry[index]; index++) {
17050 			fmpntov  = mpvarry[index];
17051 			if (fmpntov->mpg == mpnbuf)
17052 				mpnbuf = NULL;
17053 			free(fmpntov->mpg);
17054 
17055 			if (fmpntov->mfile == mpvbuf)
17056 				mpvbuf = NULL;
17057 			free(fmpntov->mfile);
17058 
17059 			if (fmpntov == mpntov)
17060 				mpntov = NULL;
17061 			free(fmpntov);
17062 		}
17063 		if (mpnbuf)
17064 			free(mpnbuf);
17065 		if (mpvbuf)
17066 			free(mpvbuf);
17067 		if (mpntov)
17068 			free(mpntov);
17069 
17070 		free(mpvarry);
17071 	}
17072 out:
17073 	scf_pg_destroy(mpg);
17074 	scf_property_destroy(mp);
17075 	scf_iter_destroy(mi);
17076 	scf_value_destroy(mv);
17077 
17078 	return (0);
17079 }
17080 
17081 /*
17082  * Take the service and search for the manifestfiles property
17083  * in each of the property groups.  If the manifest file
17084  * associated with the property does not exist then remove
17085  * the property group.
17086  */
17087 int
17088 lscf_hash_cleanup()
17089 {
17090 	scf_service_t		*svc;
17091 	scf_scope_t		*scope;
17092 	scf_propertygroup_t	*pg;
17093 	scf_property_t		*prop;
17094 	scf_value_t		*val;
17095 	scf_iter_t		*iter;
17096 	char			*pgname = NULL;
17097 	char			*mfile = NULL;
17098 	int			r;
17099 
17100 	svc = scf_service_create(g_hndl);
17101 	scope = scf_scope_create(g_hndl);
17102 	pg = scf_pg_create(g_hndl);
17103 	prop = scf_property_create(g_hndl);
17104 	val = scf_value_create(g_hndl);
17105 	iter = scf_iter_create(g_hndl);
17106 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17107 	    svc == NULL || scope == NULL) {
17108 		uu_warn(gettext("Unable to create a property group, or "
17109 		    "property\n"));
17110 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17111 		    "pg is not NULL");
17112 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17113 		    "prop is not NULL");
17114 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17115 		    "val is not NULL");
17116 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17117 		    "iter is not NULL");
17118 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17119 		    "svc is not NULL");
17120 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17121 		    "scope is not NULL");
17122 		uu_warn(gettext("scf error is : %s\n"),
17123 		    scf_strerror(scf_error()));
17124 		scfdie();
17125 	}
17126 
17127 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17128 		switch (scf_error()) {
17129 		case SCF_ERROR_CONNECTION_BROKEN:
17130 		case SCF_ERROR_NOT_FOUND:
17131 			goto out;
17132 
17133 		case SCF_ERROR_HANDLE_MISMATCH:
17134 		case SCF_ERROR_NOT_BOUND:
17135 		case SCF_ERROR_INVALID_ARGUMENT:
17136 		default:
17137 			bad_error("scf_handle_get_scope", scf_error());
17138 		}
17139 	}
17140 
17141 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17142 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17143 		    HASH_SVC);
17144 		goto out;
17145 	}
17146 
17147 	pgname = safe_malloc(max_scf_name_len + 1);
17148 	mfile = safe_malloc(max_scf_value_len + 1);
17149 
17150 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17151 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17152 		    scf_strerror(scf_error()));
17153 		goto out;
17154 	}
17155 
17156 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17157 		if (r == -1)
17158 			goto out;
17159 
17160 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17161 			switch (scf_error()) {
17162 			case SCF_ERROR_DELETED:
17163 				return (ENODEV);
17164 
17165 			case SCF_ERROR_CONNECTION_BROKEN:
17166 				return (ECONNABORTED);
17167 
17168 			case SCF_ERROR_NOT_SET:
17169 			case SCF_ERROR_NOT_BOUND:
17170 			default:
17171 				bad_error("scf_pg_get_name", scf_error());
17172 			}
17173 		}
17174 		if (IGNORE_VAR) {
17175 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17176 				continue;
17177 		}
17178 
17179 		/*
17180 		 * If unable to get the property continue as this is an
17181 		 * entry that has no location to check against.
17182 		 */
17183 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17184 			continue;
17185 		}
17186 
17187 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17188 			uu_warn(gettext("Unable to get value from %s\n"),
17189 			    pgname);
17190 
17191 			switch (scf_error()) {
17192 			case SCF_ERROR_DELETED:
17193 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17194 			case SCF_ERROR_NOT_FOUND:
17195 			case SCF_ERROR_NOT_SET:
17196 				continue;
17197 
17198 			case SCF_ERROR_CONNECTION_BROKEN:
17199 				r = scferror2errno(scf_error());
17200 				goto out;
17201 
17202 			case SCF_ERROR_HANDLE_MISMATCH:
17203 			case SCF_ERROR_NOT_BOUND:
17204 			default:
17205 				bad_error("scf_property_get_value",
17206 				    scf_error());
17207 			}
17208 		}
17209 
17210 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17211 		    == -1) {
17212 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17213 			    pgname, scf_strerror(scf_error()));
17214 
17215 			switch (scf_error()) {
17216 			case SCF_ERROR_NOT_SET:
17217 			case SCF_ERROR_TYPE_MISMATCH:
17218 				continue;
17219 
17220 			default:
17221 				bad_error("scf_value_get_astring", scf_error());
17222 			}
17223 		}
17224 
17225 		if (access(mfile, F_OK) == 0)
17226 			continue;
17227 
17228 		(void) scf_pg_delete(pg);
17229 	}
17230 
17231 out:
17232 	scf_scope_destroy(scope);
17233 	scf_service_destroy(svc);
17234 	scf_pg_destroy(pg);
17235 	scf_property_destroy(prop);
17236 	scf_value_destroy(val);
17237 	scf_iter_destroy(iter);
17238 	free(pgname);
17239 	free(mfile);
17240 
17241 	return (0);
17242 }
17243 
17244 #ifndef NATIVE_BUILD
17245 /* ARGSUSED */
17246 CPL_MATCH_FN(complete_select)
17247 {
17248 	const char *arg0, *arg1, *arg1end;
17249 	int word_start, err = 0, r;
17250 	size_t len;
17251 	char *buf;
17252 
17253 	lscf_prep_hndl();
17254 
17255 	arg0 = line + strspn(line, " \t");
17256 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17257 
17258 	arg1 = arg0 + sizeof ("select") - 1;
17259 	arg1 += strspn(arg1, " \t");
17260 	word_start = arg1 - line;
17261 
17262 	arg1end = arg1 + strcspn(arg1, " \t");
17263 	if (arg1end < line + word_end)
17264 		return (0);
17265 
17266 	len = line + word_end - arg1;
17267 
17268 	buf = safe_malloc(max_scf_name_len + 1);
17269 
17270 	if (cur_snap != NULL) {
17271 		return (0);
17272 	} else if (cur_inst != NULL) {
17273 		return (0);
17274 	} else if (cur_svc != NULL) {
17275 		scf_instance_t *inst;
17276 		scf_iter_t *iter;
17277 
17278 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17279 		    (iter = scf_iter_create(g_hndl)) == NULL)
17280 			scfdie();
17281 
17282 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17283 			scfdie();
17284 
17285 		for (;;) {
17286 			r = scf_iter_next_instance(iter, inst);
17287 			if (r == 0)
17288 				break;
17289 			if (r != 1)
17290 				scfdie();
17291 
17292 			if (scf_instance_get_name(inst, buf,
17293 			    max_scf_name_len + 1) < 0)
17294 				scfdie();
17295 
17296 			if (strncmp(buf, arg1, len) == 0) {
17297 				err = cpl_add_completion(cpl, line, word_start,
17298 				    word_end, buf + len, "", " ");
17299 				if (err != 0)
17300 					break;
17301 			}
17302 		}
17303 
17304 		scf_iter_destroy(iter);
17305 		scf_instance_destroy(inst);
17306 
17307 		return (err);
17308 	} else {
17309 		scf_service_t *svc;
17310 		scf_iter_t *iter;
17311 
17312 		assert(cur_scope != NULL);
17313 
17314 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17315 		    (iter = scf_iter_create(g_hndl)) == NULL)
17316 			scfdie();
17317 
17318 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17319 			scfdie();
17320 
17321 		for (;;) {
17322 			r = scf_iter_next_service(iter, svc);
17323 			if (r == 0)
17324 				break;
17325 			if (r != 1)
17326 				scfdie();
17327 
17328 			if (scf_service_get_name(svc, buf,
17329 			    max_scf_name_len + 1) < 0)
17330 				scfdie();
17331 
17332 			if (strncmp(buf, arg1, len) == 0) {
17333 				err = cpl_add_completion(cpl, line, word_start,
17334 				    word_end, buf + len, "", " ");
17335 				if (err != 0)
17336 					break;
17337 			}
17338 		}
17339 
17340 		scf_iter_destroy(iter);
17341 		scf_service_destroy(svc);
17342 
17343 		return (err);
17344 	}
17345 }
17346 
17347 /* ARGSUSED */
17348 CPL_MATCH_FN(complete_command)
17349 {
17350 	uint32_t scope = 0;
17351 
17352 	if (cur_snap != NULL)
17353 		scope = CS_SNAP;
17354 	else if (cur_inst != NULL)
17355 		scope = CS_INST;
17356 	else if (cur_svc != NULL)
17357 		scope = CS_SVC;
17358 	else
17359 		scope = CS_SCOPE;
17360 
17361 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17362 }
17363 #endif	/* NATIVE_BUILD */
17364