xref: /illumos-gate/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision 1ed6b69a5ca1ca3ee5e9a4931f74e2237c7e1c9f)
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 	int ret, err;
10634 
10635 	lscf_prep_hndl();
10636 
10637 	bzero(&args, sizeof (args));
10638 	args.filename = filename;
10639 	args.flags = flags;
10640 
10641 	err = 0;
10642 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
10643 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
10644 	    &args, &err, semerr)) != 0) {
10645 		if (ret != -1)
10646 			semerr(gettext("Failed to walk instances: %s\n"),
10647 			    scf_strerror(ret));
10648 		return (-1);
10649 	}
10650 
10651 	/*
10652 	 * Error message has already been printed.
10653 	 */
10654 	if (err != 0)
10655 		return (-1);
10656 
10657 	return (0);
10658 }
10659 
10660 
10661 /*
10662  * Archive
10663  */
10664 
10665 static xmlNodePtr
10666 make_archive(int flags)
10667 {
10668 	xmlNodePtr sb;
10669 	scf_scope_t *scope;
10670 	scf_service_t *svc;
10671 	scf_iter_t *iter;
10672 	int r;
10673 
10674 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10675 	    (svc = scf_service_create(g_hndl)) == NULL ||
10676 	    (iter = scf_iter_create(g_hndl)) == NULL ||
10677 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
10678 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
10679 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
10680 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
10681 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
10682 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
10683 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
10684 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
10685 		scfdie();
10686 
10687 	exp_str_sz = max_scf_len + 1;
10688 	exp_str = safe_malloc(exp_str_sz);
10689 
10690 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10691 	if (sb == NULL)
10692 		uu_die(emsg_create_xml);
10693 	safe_setprop(sb, type_attr, "archive");
10694 	safe_setprop(sb, name_attr, "none");
10695 
10696 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
10697 		scfdie();
10698 	if (scf_iter_scope_services(iter, scope) != 0)
10699 		scfdie();
10700 
10701 	for (;;) {
10702 		r = scf_iter_next_service(iter, svc);
10703 		if (r == 0)
10704 			break;
10705 		if (r != 1)
10706 			scfdie();
10707 
10708 		if (scf_service_get_name(svc, exp_str,
10709 		    max_scf_name_len + 1) < 0)
10710 			scfdie();
10711 
10712 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
10713 			continue;
10714 
10715 		(void) xmlAddChild(sb, export_service(svc, flags));
10716 	}
10717 
10718 	free(exp_str);
10719 
10720 	scf_iter_destroy(exp_val_iter);
10721 	scf_iter_destroy(exp_prop_iter);
10722 	scf_iter_destroy(exp_pg_iter);
10723 	scf_iter_destroy(exp_inst_iter);
10724 	scf_value_destroy(exp_val);
10725 	scf_property_destroy(exp_prop);
10726 	scf_pg_destroy(exp_pg);
10727 	scf_instance_destroy(exp_inst);
10728 	scf_iter_destroy(iter);
10729 	scf_service_destroy(svc);
10730 	scf_scope_destroy(scope);
10731 
10732 	return (sb);
10733 }
10734 
10735 int
10736 lscf_archive(const char *filename, int flags)
10737 {
10738 	FILE *f;
10739 	xmlDocPtr doc;
10740 	int result;
10741 
10742 	lscf_prep_hndl();
10743 
10744 	if (filename != NULL) {
10745 		errno = 0;
10746 		f = fopen(filename, "wb");
10747 		if (f == NULL) {
10748 			if (errno == 0)
10749 				uu_die(gettext("Could not open \"%s\": no free "
10750 				    "stdio streams.\n"), filename);
10751 			else
10752 				uu_die(gettext("Could not open \"%s\""),
10753 				    filename);
10754 		}
10755 	} else
10756 		f = stdout;
10757 
10758 	doc = xmlNewDoc((xmlChar *)"1.0");
10759 	if (doc == NULL)
10760 		uu_die(gettext("Could not create XML document.\n"));
10761 
10762 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10763 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10764 		uu_die(emsg_create_xml);
10765 
10766 	(void) xmlAddSibling(doc->children, make_archive(flags));
10767 
10768 	result = write_service_bundle(doc, f);
10769 
10770 	xmlFreeDoc(doc);
10771 
10772 	if (f != stdout)
10773 		(void) fclose(f);
10774 
10775 	return (result);
10776 }
10777 
10778 
10779 /*
10780  * "Extract" a profile.
10781  */
10782 int
10783 lscf_profile_extract(const char *filename)
10784 {
10785 	FILE *f;
10786 	xmlDocPtr doc;
10787 	xmlNodePtr sb, snode, inode;
10788 	scf_scope_t *scope;
10789 	scf_service_t *svc;
10790 	scf_instance_t *inst;
10791 	scf_propertygroup_t *pg;
10792 	scf_property_t *prop;
10793 	scf_value_t *val;
10794 	scf_iter_t *siter, *iiter;
10795 	int r, s;
10796 	char *namebuf;
10797 	uint8_t b;
10798 	int result;
10799 
10800 	lscf_prep_hndl();
10801 
10802 	if (filename != NULL) {
10803 		errno = 0;
10804 		f = fopen(filename, "wb");
10805 		if (f == NULL) {
10806 			if (errno == 0)
10807 				uu_die(gettext("Could not open \"%s\": no "
10808 				    "free stdio streams.\n"), filename);
10809 			else
10810 				uu_die(gettext("Could not open \"%s\""),
10811 				    filename);
10812 		}
10813 	} else
10814 		f = stdout;
10815 
10816 	doc = xmlNewDoc((xmlChar *)"1.0");
10817 	if (doc == NULL)
10818 		uu_die(gettext("Could not create XML document.\n"));
10819 
10820 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
10821 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
10822 		uu_die(emsg_create_xml);
10823 
10824 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
10825 	if (sb == NULL)
10826 		uu_die(emsg_create_xml);
10827 	safe_setprop(sb, type_attr, "profile");
10828 	safe_setprop(sb, name_attr, "extract");
10829 	(void) xmlAddSibling(doc->children, sb);
10830 
10831 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
10832 	    (svc = scf_service_create(g_hndl)) == NULL ||
10833 	    (inst = scf_instance_create(g_hndl)) == NULL ||
10834 	    (pg = scf_pg_create(g_hndl)) == NULL ||
10835 	    (prop = scf_property_create(g_hndl)) == NULL ||
10836 	    (val = scf_value_create(g_hndl)) == NULL ||
10837 	    (siter = scf_iter_create(g_hndl)) == NULL ||
10838 	    (iiter = scf_iter_create(g_hndl)) == NULL)
10839 		scfdie();
10840 
10841 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
10842 		scfdie();
10843 
10844 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
10845 		scfdie();
10846 
10847 	namebuf = safe_malloc(max_scf_name_len + 1);
10848 
10849 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
10850 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
10851 			scfdie();
10852 
10853 		snode = xmlNewNode(NULL, (xmlChar *)"service");
10854 		if (snode == NULL)
10855 			uu_die(emsg_create_xml);
10856 
10857 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
10858 		    0)
10859 			scfdie();
10860 
10861 		safe_setprop(snode, name_attr, namebuf);
10862 
10863 		safe_setprop(snode, type_attr, "service");
10864 		safe_setprop(snode, "version", "0");
10865 
10866 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
10867 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
10868 			    SCF_SUCCESS) {
10869 				if (scf_error() != SCF_ERROR_NOT_FOUND)
10870 					scfdie();
10871 
10872 				if (g_verbose) {
10873 					ssize_t len;
10874 					char *fmri;
10875 
10876 					len =
10877 					    scf_instance_to_fmri(inst, NULL, 0);
10878 					if (len < 0)
10879 						scfdie();
10880 
10881 					fmri = safe_malloc(len + 1);
10882 
10883 					if (scf_instance_to_fmri(inst, fmri,
10884 					    len + 1) < 0)
10885 						scfdie();
10886 
10887 					warn("Instance %s has no \"%s\" "
10888 					    "property group.\n", fmri,
10889 					    scf_pg_general);
10890 
10891 					free(fmri);
10892 				}
10893 
10894 				continue;
10895 			}
10896 
10897 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
10898 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
10899 			    prop_get_val(prop, val) != 0)
10900 				continue;
10901 
10902 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
10903 			    NULL);
10904 			if (inode == NULL)
10905 				uu_die(emsg_create_xml);
10906 
10907 			if (scf_instance_get_name(inst, namebuf,
10908 			    max_scf_name_len + 1) < 0)
10909 				scfdie();
10910 
10911 			safe_setprop(inode, name_attr, namebuf);
10912 
10913 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
10914 				scfdie();
10915 
10916 			safe_setprop(inode, enabled_attr, b ? true : false);
10917 		}
10918 		if (s < 0)
10919 			scfdie();
10920 
10921 		if (snode->children != NULL)
10922 			(void) xmlAddChild(sb, snode);
10923 		else
10924 			xmlFreeNode(snode);
10925 	}
10926 	if (r < 0)
10927 		scfdie();
10928 
10929 	free(namebuf);
10930 
10931 	result = write_service_bundle(doc, f);
10932 
10933 	xmlFreeDoc(doc);
10934 
10935 	if (f != stdout)
10936 		(void) fclose(f);
10937 
10938 	return (result);
10939 }
10940 
10941 
10942 /*
10943  * Entity manipulation commands
10944  */
10945 
10946 /*
10947  * Entity selection.  If no entity is selected, then the current scope is in
10948  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
10949  * only cur_inst is NULL, and when an instance is selected, none are NULL.
10950  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
10951  * cur_inst will be non-NULL.
10952  */
10953 
10954 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
10955 static int
10956 select_inst(const char *name)
10957 {
10958 	scf_instance_t *inst;
10959 	scf_error_t err;
10960 
10961 	assert(cur_svc != NULL);
10962 
10963 	inst = scf_instance_create(g_hndl);
10964 	if (inst == NULL)
10965 		scfdie();
10966 
10967 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
10968 		cur_inst = inst;
10969 		return (0);
10970 	}
10971 
10972 	err = scf_error();
10973 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
10974 		scfdie();
10975 
10976 	scf_instance_destroy(inst);
10977 	return (1);
10978 }
10979 
10980 /* Returns as above. */
10981 static int
10982 select_svc(const char *name)
10983 {
10984 	scf_service_t *svc;
10985 	scf_error_t err;
10986 
10987 	assert(cur_scope != NULL);
10988 
10989 	svc = scf_service_create(g_hndl);
10990 	if (svc == NULL)
10991 		scfdie();
10992 
10993 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
10994 		cur_svc = svc;
10995 		return (0);
10996 	}
10997 
10998 	err = scf_error();
10999 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
11000 		scfdie();
11001 
11002 	scf_service_destroy(svc);
11003 	return (1);
11004 }
11005 
11006 /* ARGSUSED */
11007 static int
11008 select_callback(void *unused, scf_walkinfo_t *wip)
11009 {
11010 	scf_instance_t *inst;
11011 	scf_service_t *svc;
11012 	scf_scope_t *scope;
11013 
11014 	if (wip->inst != NULL) {
11015 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11016 		    (svc = scf_service_create(g_hndl)) == NULL ||
11017 		    (inst = scf_instance_create(g_hndl)) == NULL)
11018 			scfdie();
11019 
11020 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11021 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11022 			scfdie();
11023 	} else {
11024 		assert(wip->svc != NULL);
11025 
11026 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
11027 		    (svc = scf_service_create(g_hndl)) == NULL)
11028 			scfdie();
11029 
11030 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
11031 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
11032 			scfdie();
11033 
11034 		inst = NULL;
11035 	}
11036 
11037 	/* Clear out the current selection */
11038 	assert(cur_scope != NULL);
11039 	scf_scope_destroy(cur_scope);
11040 	scf_service_destroy(cur_svc);
11041 	scf_instance_destroy(cur_inst);
11042 
11043 	cur_scope = scope;
11044 	cur_svc = svc;
11045 	cur_inst = inst;
11046 
11047 	return (0);
11048 }
11049 
11050 static int
11051 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
11052 {
11053 	char **fmri = fmri_p;
11054 
11055 	*fmri = strdup(wip->fmri);
11056 	if (*fmri == NULL)
11057 		uu_die(gettext("Out of memory.\n"));
11058 
11059 	return (0);
11060 }
11061 
11062 /*
11063  * validate [fmri]
11064  * Perform the validation of an FMRI instance.
11065  */
11066 void
11067 lscf_validate_fmri(const char *fmri)
11068 {
11069 	int ret = 0;
11070 	size_t inst_sz;
11071 	char *inst_fmri = NULL;
11072 	scf_tmpl_errors_t *errs = NULL;
11073 	char *snapbuf = NULL;
11074 
11075 	lscf_prep_hndl();
11076 
11077 	if (fmri == NULL) {
11078 		inst_sz = max_scf_fmri_len + 1;
11079 		inst_fmri = safe_malloc(inst_sz);
11080 
11081 		if (cur_snap != NULL) {
11082 			snapbuf = safe_malloc(max_scf_name_len + 1);
11083 			if (scf_snapshot_get_name(cur_snap, snapbuf,
11084 			    max_scf_name_len + 1) < 0)
11085 				scfdie();
11086 		}
11087 		if (cur_inst == NULL) {
11088 			semerr(gettext("No instance selected\n"));
11089 			goto cleanup;
11090 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
11091 		    inst_sz) >= inst_sz) {
11092 			/* sanity check. Should never get here */
11093 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
11094 			    __FILE__, __LINE__);
11095 		}
11096 	} else {
11097 		scf_error_t scf_err;
11098 		int err = 0;
11099 
11100 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
11101 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
11102 			uu_warn("Failed to walk instances: %s\n",
11103 			    scf_strerror(scf_err));
11104 			goto cleanup;
11105 		}
11106 		if (err != 0) {
11107 			/* error message displayed by scf_walk_fmri */
11108 			goto cleanup;
11109 		}
11110 	}
11111 
11112 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
11113 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
11114 	if (ret == -1) {
11115 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
11116 			warn(gettext("Template data for %s is invalid. "
11117 			    "Consider reverting to a previous snapshot or "
11118 			    "restoring original configuration.\n"), inst_fmri);
11119 		} else {
11120 			uu_warn("%s: %s\n",
11121 			    gettext("Error validating the instance"),
11122 			    scf_strerror(scf_error()));
11123 		}
11124 	} else if (ret == 1 && errs != NULL) {
11125 		scf_tmpl_error_t *err = NULL;
11126 		char *msg;
11127 		size_t len = 256;	/* initial error buffer size */
11128 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
11129 		    SCF_TMPL_STRERROR_HUMAN : 0;
11130 
11131 		msg = safe_malloc(len);
11132 
11133 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
11134 			int ret;
11135 
11136 			if ((ret = scf_tmpl_strerror(err, msg, len,
11137 			    flag)) >= len) {
11138 				len = ret + 1;
11139 				msg = realloc(msg, len);
11140 				if (msg == NULL)
11141 					uu_die(gettext(
11142 					    "Out of memory.\n"));
11143 				(void) scf_tmpl_strerror(err, msg, len,
11144 				    flag);
11145 			}
11146 			(void) fprintf(stderr, "%s\n", msg);
11147 		}
11148 		if (msg != NULL)
11149 			free(msg);
11150 	}
11151 	if (errs != NULL)
11152 		scf_tmpl_errors_destroy(errs);
11153 
11154 cleanup:
11155 	free(inst_fmri);
11156 	free(snapbuf);
11157 }
11158 
11159 static void
11160 lscf_validate_file(const char *filename)
11161 {
11162 	tmpl_errors_t *errs;
11163 
11164 	bundle_t *b = internal_bundle_new();
11165 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
11166 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
11167 			tmpl_errors_print(stderr, errs, "");
11168 			semerr(gettext("Validation failed.\n"));
11169 		}
11170 		tmpl_errors_destroy(errs);
11171 	}
11172 	(void) internal_bundle_free(b);
11173 }
11174 
11175 /*
11176  * validate [fmri|file]
11177  */
11178 void
11179 lscf_validate(const char *arg)
11180 {
11181 	const char *str;
11182 
11183 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
11184 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
11185 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
11186 		lscf_validate_file(str);
11187 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
11188 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
11189 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
11190 		lscf_validate_fmri(str);
11191 	} else if (access(arg, R_OK | F_OK) == 0) {
11192 		lscf_validate_file(arg);
11193 	} else {
11194 		lscf_validate_fmri(arg);
11195 	}
11196 }
11197 
11198 void
11199 lscf_select(const char *fmri)
11200 {
11201 	int ret, err;
11202 
11203 	lscf_prep_hndl();
11204 
11205 	if (cur_snap != NULL) {
11206 		struct snaplevel *elt;
11207 		char *buf;
11208 
11209 		/* Error unless name is that of the next level. */
11210 		elt = uu_list_next(cur_levels, cur_elt);
11211 		if (elt == NULL) {
11212 			semerr(gettext("No children.\n"));
11213 			return;
11214 		}
11215 
11216 		buf = safe_malloc(max_scf_name_len + 1);
11217 
11218 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11219 		    max_scf_name_len + 1) < 0)
11220 			scfdie();
11221 
11222 		if (strcmp(buf, fmri) != 0) {
11223 			semerr(gettext("No such child.\n"));
11224 			free(buf);
11225 			return;
11226 		}
11227 
11228 		free(buf);
11229 
11230 		cur_elt = elt;
11231 		cur_level = elt->sl;
11232 		return;
11233 	}
11234 
11235 	/*
11236 	 * Special case for 'svc:', which takes the user to the scope level.
11237 	 */
11238 	if (strcmp(fmri, "svc:") == 0) {
11239 		scf_instance_destroy(cur_inst);
11240 		scf_service_destroy(cur_svc);
11241 		cur_inst = NULL;
11242 		cur_svc = NULL;
11243 		return;
11244 	}
11245 
11246 	/*
11247 	 * Special case for ':properties'.  This appears as part of 'list' but
11248 	 * can't be selected.  Give a more helpful error message in this case.
11249 	 */
11250 	if (strcmp(fmri, ":properties") == 0) {
11251 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
11252 		    "to list properties.\n"));
11253 		return;
11254 	}
11255 
11256 	/*
11257 	 * First try the argument as relative to the current selection.
11258 	 */
11259 	if (cur_inst != NULL) {
11260 		/* EMPTY */;
11261 	} else if (cur_svc != NULL) {
11262 		if (select_inst(fmri) != 1)
11263 			return;
11264 	} else {
11265 		if (select_svc(fmri) != 1)
11266 			return;
11267 	}
11268 
11269 	err = 0;
11270 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
11271 	    select_callback, NULL, &err, semerr)) != 0) {
11272 		semerr(gettext("Failed to walk instances: %s\n"),
11273 		    scf_strerror(ret));
11274 	}
11275 }
11276 
11277 void
11278 lscf_unselect(void)
11279 {
11280 	lscf_prep_hndl();
11281 
11282 	if (cur_snap != NULL) {
11283 		struct snaplevel *elt;
11284 
11285 		elt = uu_list_prev(cur_levels, cur_elt);
11286 		if (elt == NULL) {
11287 			semerr(gettext("No parent levels.\n"));
11288 		} else {
11289 			cur_elt = elt;
11290 			cur_level = elt->sl;
11291 		}
11292 	} else if (cur_inst != NULL) {
11293 		scf_instance_destroy(cur_inst);
11294 		cur_inst = NULL;
11295 	} else if (cur_svc != NULL) {
11296 		scf_service_destroy(cur_svc);
11297 		cur_svc = NULL;
11298 	} else {
11299 		semerr(gettext("Cannot unselect at scope level.\n"));
11300 	}
11301 }
11302 
11303 /*
11304  * Return the FMRI of the current selection, for the prompt.
11305  */
11306 void
11307 lscf_get_selection_str(char *buf, size_t bufsz)
11308 {
11309 	char *cp;
11310 	ssize_t fmrilen, szret;
11311 	boolean_t deleted = B_FALSE;
11312 
11313 	if (g_hndl == NULL) {
11314 		(void) strlcpy(buf, "svc:", bufsz);
11315 		return;
11316 	}
11317 
11318 	if (cur_level != NULL) {
11319 		assert(cur_snap != NULL);
11320 
11321 		/* [ snapshot ] FMRI [: instance ] */
11322 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
11323 		    + 2 + max_scf_name_len + 1 + 1);
11324 
11325 		buf[0] = '[';
11326 
11327 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
11328 		    max_scf_name_len + 1);
11329 		if (szret < 0) {
11330 			if (scf_error() != SCF_ERROR_DELETED)
11331 				scfdie();
11332 
11333 			goto snap_deleted;
11334 		}
11335 
11336 		(void) strcat(buf, "]svc:/");
11337 
11338 		cp = strchr(buf, '\0');
11339 
11340 		szret = scf_snaplevel_get_service_name(cur_level, cp,
11341 		    max_scf_name_len + 1);
11342 		if (szret < 0) {
11343 			if (scf_error() != SCF_ERROR_DELETED)
11344 				scfdie();
11345 
11346 			goto snap_deleted;
11347 		}
11348 
11349 		cp = strchr(cp, '\0');
11350 
11351 		if (snaplevel_is_instance(cur_level)) {
11352 			*cp++ = ':';
11353 
11354 			if (scf_snaplevel_get_instance_name(cur_level, cp,
11355 			    max_scf_name_len + 1) < 0) {
11356 				if (scf_error() != SCF_ERROR_DELETED)
11357 					scfdie();
11358 
11359 				goto snap_deleted;
11360 			}
11361 		} else {
11362 			*cp++ = '[';
11363 			*cp++ = ':';
11364 
11365 			if (scf_instance_get_name(cur_inst, cp,
11366 			    max_scf_name_len + 1) < 0) {
11367 				if (scf_error() != SCF_ERROR_DELETED)
11368 					scfdie();
11369 
11370 				goto snap_deleted;
11371 			}
11372 
11373 			(void) strcat(buf, "]");
11374 		}
11375 
11376 		return;
11377 
11378 snap_deleted:
11379 		deleted = B_TRUE;
11380 		free(buf);
11381 		unselect_cursnap();
11382 	}
11383 
11384 	assert(cur_snap == NULL);
11385 
11386 	if (cur_inst != NULL) {
11387 		assert(cur_svc != NULL);
11388 		assert(cur_scope != NULL);
11389 
11390 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
11391 		if (fmrilen >= 0) {
11392 			assert(fmrilen < bufsz);
11393 			if (deleted)
11394 				warn(emsg_deleted);
11395 			return;
11396 		}
11397 
11398 		if (scf_error() != SCF_ERROR_DELETED)
11399 			scfdie();
11400 
11401 		deleted = B_TRUE;
11402 
11403 		scf_instance_destroy(cur_inst);
11404 		cur_inst = NULL;
11405 	}
11406 
11407 	if (cur_svc != NULL) {
11408 		assert(cur_scope != NULL);
11409 
11410 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
11411 		if (szret >= 0) {
11412 			assert(szret < bufsz);
11413 			if (deleted)
11414 				warn(emsg_deleted);
11415 			return;
11416 		}
11417 
11418 		if (scf_error() != SCF_ERROR_DELETED)
11419 			scfdie();
11420 
11421 		deleted = B_TRUE;
11422 		scf_service_destroy(cur_svc);
11423 		cur_svc = NULL;
11424 	}
11425 
11426 	assert(cur_scope != NULL);
11427 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
11428 
11429 	if (fmrilen < 0)
11430 		scfdie();
11431 
11432 	assert(fmrilen < bufsz);
11433 	if (deleted)
11434 		warn(emsg_deleted);
11435 }
11436 
11437 /*
11438  * Entity listing.  Entities and colon namespaces (e.g., :properties and
11439  * :statistics) are listed for the current selection.
11440  */
11441 void
11442 lscf_list(const char *pattern)
11443 {
11444 	scf_iter_t *iter;
11445 	char *buf;
11446 	int ret;
11447 
11448 	lscf_prep_hndl();
11449 
11450 	if (cur_level != NULL) {
11451 		struct snaplevel *elt;
11452 
11453 		(void) fputs(COLON_NAMESPACES, stdout);
11454 
11455 		elt = uu_list_next(cur_levels, cur_elt);
11456 		if (elt == NULL)
11457 			return;
11458 
11459 		/*
11460 		 * For now, we know that the next level is an instance.  But
11461 		 * if we ever have multiple scopes, this could be complicated.
11462 		 */
11463 		buf = safe_malloc(max_scf_name_len + 1);
11464 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
11465 		    max_scf_name_len + 1) >= 0) {
11466 			(void) puts(buf);
11467 		} else {
11468 			if (scf_error() != SCF_ERROR_DELETED)
11469 				scfdie();
11470 		}
11471 
11472 		free(buf);
11473 
11474 		return;
11475 	}
11476 
11477 	if (cur_inst != NULL) {
11478 		(void) fputs(COLON_NAMESPACES, stdout);
11479 		return;
11480 	}
11481 
11482 	iter = scf_iter_create(g_hndl);
11483 	if (iter == NULL)
11484 		scfdie();
11485 
11486 	buf = safe_malloc(max_scf_name_len + 1);
11487 
11488 	if (cur_svc != NULL) {
11489 		/* List the instances in this service. */
11490 		scf_instance_t *inst;
11491 
11492 		inst = scf_instance_create(g_hndl);
11493 		if (inst == NULL)
11494 			scfdie();
11495 
11496 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
11497 			safe_printf(COLON_NAMESPACES);
11498 
11499 			for (;;) {
11500 				ret = scf_iter_next_instance(iter, inst);
11501 				if (ret == 0)
11502 					break;
11503 				if (ret != 1) {
11504 					if (scf_error() != SCF_ERROR_DELETED)
11505 						scfdie();
11506 
11507 					break;
11508 				}
11509 
11510 				if (scf_instance_get_name(inst, buf,
11511 				    max_scf_name_len + 1) >= 0) {
11512 					if (pattern == NULL ||
11513 					    fnmatch(pattern, buf, 0) == 0)
11514 						(void) puts(buf);
11515 				} else {
11516 					if (scf_error() != SCF_ERROR_DELETED)
11517 						scfdie();
11518 				}
11519 			}
11520 		} else {
11521 			if (scf_error() != SCF_ERROR_DELETED)
11522 				scfdie();
11523 		}
11524 
11525 		scf_instance_destroy(inst);
11526 	} else {
11527 		/* List the services in this scope. */
11528 		scf_service_t *svc;
11529 
11530 		assert(cur_scope != NULL);
11531 
11532 		svc = scf_service_create(g_hndl);
11533 		if (svc == NULL)
11534 			scfdie();
11535 
11536 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
11537 			scfdie();
11538 
11539 		for (;;) {
11540 			ret = scf_iter_next_service(iter, svc);
11541 			if (ret == 0)
11542 				break;
11543 			if (ret != 1)
11544 				scfdie();
11545 
11546 			if (scf_service_get_name(svc, buf,
11547 			    max_scf_name_len + 1) >= 0) {
11548 				if (pattern == NULL ||
11549 				    fnmatch(pattern, buf, 0) == 0)
11550 					safe_printf("%s\n", buf);
11551 			} else {
11552 				if (scf_error() != SCF_ERROR_DELETED)
11553 					scfdie();
11554 			}
11555 		}
11556 
11557 		scf_service_destroy(svc);
11558 	}
11559 
11560 	free(buf);
11561 	scf_iter_destroy(iter);
11562 }
11563 
11564 /*
11565  * Entity addition.  Creates an empty entity in the current selection.
11566  */
11567 void
11568 lscf_add(const char *name)
11569 {
11570 	lscf_prep_hndl();
11571 
11572 	if (cur_snap != NULL) {
11573 		semerr(emsg_cant_modify_snapshots);
11574 	} else if (cur_inst != NULL) {
11575 		semerr(gettext("Cannot add entities to an instance.\n"));
11576 	} else if (cur_svc != NULL) {
11577 
11578 		if (scf_service_add_instance(cur_svc, name, NULL) !=
11579 		    SCF_SUCCESS) {
11580 			switch (scf_error()) {
11581 			case SCF_ERROR_INVALID_ARGUMENT:
11582 				semerr(gettext("Invalid name.\n"));
11583 				break;
11584 
11585 			case SCF_ERROR_EXISTS:
11586 				semerr(gettext("Instance already exists.\n"));
11587 				break;
11588 
11589 			case SCF_ERROR_PERMISSION_DENIED:
11590 				semerr(emsg_permission_denied);
11591 				break;
11592 
11593 			default:
11594 				scfdie();
11595 			}
11596 		}
11597 	} else {
11598 		assert(cur_scope != NULL);
11599 
11600 		if (scf_scope_add_service(cur_scope, name, NULL) !=
11601 		    SCF_SUCCESS) {
11602 			switch (scf_error()) {
11603 			case SCF_ERROR_INVALID_ARGUMENT:
11604 				semerr(gettext("Invalid name.\n"));
11605 				break;
11606 
11607 			case SCF_ERROR_EXISTS:
11608 				semerr(gettext("Service already exists.\n"));
11609 				break;
11610 
11611 			case SCF_ERROR_PERMISSION_DENIED:
11612 				semerr(emsg_permission_denied);
11613 				break;
11614 
11615 			case SCF_ERROR_BACKEND_READONLY:
11616 				semerr(emsg_read_only);
11617 				break;
11618 
11619 			default:
11620 				scfdie();
11621 			}
11622 		}
11623 	}
11624 }
11625 
11626 /* return 1 if the entity has no persistent pgs, else return 0 */
11627 static int
11628 entity_has_no_pgs(void *ent, int isservice)
11629 {
11630 	scf_iter_t *iter = NULL;
11631 	scf_propertygroup_t *pg = NULL;
11632 	uint32_t flags;
11633 	int err;
11634 	int ret = 1;
11635 
11636 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11637 	    (pg = scf_pg_create(g_hndl)) == NULL)
11638 		scfdie();
11639 
11640 	if (isservice) {
11641 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
11642 			scfdie();
11643 	} else {
11644 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
11645 			scfdie();
11646 	}
11647 
11648 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
11649 		if (scf_pg_get_flags(pg, &flags) != 0)
11650 			scfdie();
11651 
11652 		/* skip nonpersistent pgs */
11653 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
11654 			continue;
11655 
11656 		ret = 0;
11657 		break;
11658 	}
11659 
11660 	if (err == -1)
11661 		scfdie();
11662 
11663 	scf_pg_destroy(pg);
11664 	scf_iter_destroy(iter);
11665 
11666 	return (ret);
11667 }
11668 
11669 /* return 1 if the service has no instances, else return 0 */
11670 static int
11671 svc_has_no_insts(scf_service_t *svc)
11672 {
11673 	scf_instance_t *inst;
11674 	scf_iter_t *iter;
11675 	int r;
11676 	int ret = 1;
11677 
11678 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
11679 	    (iter = scf_iter_create(g_hndl)) == NULL)
11680 		scfdie();
11681 
11682 	if (scf_iter_service_instances(iter, svc) != 0)
11683 		scfdie();
11684 
11685 	r = scf_iter_next_instance(iter, inst);
11686 	if (r == 1) {
11687 		ret = 0;
11688 	} else if (r == 0) {
11689 		ret = 1;
11690 	} else if (r == -1) {
11691 		scfdie();
11692 	} else {
11693 		bad_error("scf_iter_next_instance", r);
11694 	}
11695 
11696 	scf_iter_destroy(iter);
11697 	scf_instance_destroy(inst);
11698 
11699 	return (ret);
11700 }
11701 
11702 /*
11703  * Entity deletion.
11704  */
11705 
11706 /*
11707  * Delete the property group <fmri>/:properties/<name>.  Returns
11708  * SCF_ERROR_NONE on success (or if the entity is not found),
11709  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
11710  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
11711  * denied.
11712  */
11713 static scf_error_t
11714 delete_dependency_pg(const char *fmri, const char *name)
11715 {
11716 	void *entity = NULL;
11717 	int isservice;
11718 	scf_propertygroup_t *pg = NULL;
11719 	scf_error_t result;
11720 	char *pgty;
11721 	scf_service_t *svc = NULL;
11722 	scf_instance_t *inst = NULL;
11723 	scf_iter_t *iter = NULL;
11724 	char *name_buf = NULL;
11725 
11726 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
11727 	switch (result) {
11728 	case SCF_ERROR_NONE:
11729 		break;
11730 
11731 	case SCF_ERROR_NO_MEMORY:
11732 		uu_die(gettext("Out of memory.\n"));
11733 		/* NOTREACHED */
11734 
11735 	case SCF_ERROR_INVALID_ARGUMENT:
11736 	case SCF_ERROR_CONSTRAINT_VIOLATED:
11737 		return (SCF_ERROR_INVALID_ARGUMENT);
11738 
11739 	case SCF_ERROR_NOT_FOUND:
11740 		result = SCF_ERROR_NONE;
11741 		goto out;
11742 
11743 	default:
11744 		bad_error("fmri_to_entity", result);
11745 	}
11746 
11747 	pg = scf_pg_create(g_hndl);
11748 	if (pg == NULL)
11749 		scfdie();
11750 
11751 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
11752 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11753 			scfdie();
11754 
11755 		result = SCF_ERROR_NONE;
11756 		goto out;
11757 	}
11758 
11759 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11760 
11761 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11762 		scfdie();
11763 
11764 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
11765 		result = SCF_ERROR_TYPE_MISMATCH;
11766 		free(pgty);
11767 		goto out;
11768 	}
11769 
11770 	free(pgty);
11771 
11772 	if (scf_pg_delete(pg) != 0) {
11773 		result = scf_error();
11774 		if (result != SCF_ERROR_PERMISSION_DENIED)
11775 			scfdie();
11776 		goto out;
11777 	}
11778 
11779 	/*
11780 	 * We have to handle the case where we've just deleted the last
11781 	 * property group of a "dummy" entity (instance or service).
11782 	 * A "dummy" entity is an entity only present to hold an
11783 	 * external dependency.
11784 	 * So, in the case we deleted the last property group then we
11785 	 * can also delete the entity. If the entity is an instance then
11786 	 * we must verify if this was the last instance for the service
11787 	 * and if it is, we can also delete the service if it doesn't
11788 	 * have any property group either.
11789 	 */
11790 
11791 	result = SCF_ERROR_NONE;
11792 
11793 	if (isservice) {
11794 		svc = (scf_service_t *)entity;
11795 
11796 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
11797 		    (iter = scf_iter_create(g_hndl)) == NULL)
11798 			scfdie();
11799 
11800 		name_buf = safe_malloc(max_scf_name_len + 1);
11801 	} else {
11802 		inst = (scf_instance_t *)entity;
11803 	}
11804 
11805 	/*
11806 	 * If the entity is an instance and we've just deleted its last
11807 	 * property group then we should delete it.
11808 	 */
11809 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
11810 		/* find the service before deleting the inst. - needed later */
11811 		if ((svc = scf_service_create(g_hndl)) == NULL)
11812 			scfdie();
11813 
11814 		if (scf_instance_get_parent(inst, svc) != 0)
11815 			scfdie();
11816 
11817 		/* delete the instance */
11818 		if (scf_instance_delete(inst) != 0) {
11819 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11820 				scfdie();
11821 
11822 			result = SCF_ERROR_PERMISSION_DENIED;
11823 			goto out;
11824 		}
11825 		/* no need to refresh the instance */
11826 		inst = NULL;
11827 	}
11828 
11829 	/*
11830 	 * If the service has no more instances and pgs or we just deleted the
11831 	 * last instance and the service doesn't have anymore propery groups
11832 	 * then the service should be deleted.
11833 	 */
11834 	if (svc != NULL &&
11835 	    svc_has_no_insts(svc) &&
11836 	    entity_has_no_pgs((void *)svc, 1)) {
11837 		if (scf_service_delete(svc) == 0) {
11838 			if (isservice) {
11839 				/* no need to refresh the service */
11840 				svc = NULL;
11841 			}
11842 
11843 			goto out;
11844 		}
11845 
11846 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
11847 			scfdie();
11848 
11849 		result = SCF_ERROR_PERMISSION_DENIED;
11850 	}
11851 
11852 	/* if the entity has not been deleted, refresh it */
11853 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
11854 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
11855 		    name_buf);
11856 	}
11857 
11858 out:
11859 	if (isservice && (inst != NULL && iter != NULL)) {
11860 		free(name_buf);
11861 		scf_iter_destroy(iter);
11862 		scf_instance_destroy(inst);
11863 	}
11864 
11865 	if (!isservice && svc != NULL) {
11866 		scf_service_destroy(svc);
11867 	}
11868 
11869 	scf_pg_destroy(pg);
11870 	if (entity != NULL)
11871 		entity_destroy(entity, isservice);
11872 
11873 	return (result);
11874 }
11875 
11876 static int
11877 delete_dependents(scf_propertygroup_t *pg)
11878 {
11879 	char *pgty, *name, *fmri;
11880 	scf_property_t *prop;
11881 	scf_value_t *val;
11882 	scf_iter_t *iter;
11883 	int r;
11884 	scf_error_t err;
11885 
11886 	/* Verify that the pg has the correct type. */
11887 	pgty = safe_malloc(max_scf_pg_type_len + 1);
11888 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
11889 		scfdie();
11890 
11891 	if (strcmp(pgty, scf_group_framework) != 0) {
11892 		if (g_verbose) {
11893 			fmri = safe_malloc(max_scf_fmri_len + 1);
11894 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
11895 				scfdie();
11896 
11897 			warn(gettext("Property group %s is not of expected "
11898 			    "type %s.\n"), fmri, scf_group_framework);
11899 
11900 			free(fmri);
11901 		}
11902 
11903 		free(pgty);
11904 		return (-1);
11905 	}
11906 
11907 	free(pgty);
11908 
11909 	/* map delete_dependency_pg onto the properties. */
11910 	if ((prop = scf_property_create(g_hndl)) == NULL ||
11911 	    (val = scf_value_create(g_hndl)) == NULL ||
11912 	    (iter = scf_iter_create(g_hndl)) == NULL)
11913 		scfdie();
11914 
11915 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
11916 		scfdie();
11917 
11918 	name = safe_malloc(max_scf_name_len + 1);
11919 	fmri = safe_malloc(max_scf_fmri_len + 2);
11920 
11921 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
11922 		scf_type_t ty;
11923 
11924 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
11925 			scfdie();
11926 
11927 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
11928 			scfdie();
11929 
11930 		if ((ty != SCF_TYPE_ASTRING &&
11931 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
11932 		    prop_get_val(prop, val) != 0)
11933 			continue;
11934 
11935 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
11936 			scfdie();
11937 
11938 		err = delete_dependency_pg(fmri, name);
11939 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
11940 			if (scf_property_to_fmri(prop, fmri,
11941 			    max_scf_fmri_len + 2) < 0)
11942 				scfdie();
11943 
11944 			warn(gettext("Value of %s is not a valid FMRI.\n"),
11945 			    fmri);
11946 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
11947 			warn(gettext("Property group \"%s\" of entity \"%s\" "
11948 			    "does not have dependency type.\n"), name, fmri);
11949 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
11950 			warn(gettext("Could not delete property group \"%s\" "
11951 			    "of entity \"%s\" (permission denied).\n"), name,
11952 			    fmri);
11953 		}
11954 	}
11955 	if (r == -1)
11956 		scfdie();
11957 
11958 	scf_value_destroy(val);
11959 	scf_property_destroy(prop);
11960 
11961 	return (0);
11962 }
11963 
11964 /*
11965  * Returns 1 if the instance may be running, and 0 otherwise.
11966  */
11967 static int
11968 inst_is_running(scf_instance_t *inst)
11969 {
11970 	scf_propertygroup_t *pg;
11971 	scf_property_t *prop;
11972 	scf_value_t *val;
11973 	char buf[MAX_SCF_STATE_STRING_SZ];
11974 	int ret = 0;
11975 	ssize_t szret;
11976 
11977 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11978 	    (prop = scf_property_create(g_hndl)) == NULL ||
11979 	    (val = scf_value_create(g_hndl)) == NULL)
11980 		scfdie();
11981 
11982 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
11983 		if (scf_error() != SCF_ERROR_NOT_FOUND)
11984 			scfdie();
11985 		goto out;
11986 	}
11987 
11988 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
11989 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
11990 	    prop_get_val(prop, val) != 0)
11991 		goto out;
11992 
11993 	szret = scf_value_get_astring(val, buf, sizeof (buf));
11994 	assert(szret >= 0);
11995 
11996 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
11997 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
11998 
11999 out:
12000 	scf_value_destroy(val);
12001 	scf_property_destroy(prop);
12002 	scf_pg_destroy(pg);
12003 	return (ret);
12004 }
12005 
12006 static uint8_t
12007 pg_is_external_dependency(scf_propertygroup_t *pg)
12008 {
12009 	char *type;
12010 	scf_value_t *val;
12011 	scf_property_t *prop;
12012 	uint8_t b = B_FALSE;
12013 
12014 	type = safe_malloc(max_scf_pg_type_len + 1);
12015 
12016 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
12017 		scfdie();
12018 
12019 	if ((prop = scf_property_create(g_hndl)) == NULL ||
12020 	    (val = scf_value_create(g_hndl)) == NULL)
12021 		scfdie();
12022 
12023 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
12024 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
12025 			if (scf_property_get_value(prop, val) != 0)
12026 				scfdie();
12027 			if (scf_value_get_boolean(val, &b) != 0)
12028 				scfdie();
12029 		}
12030 	}
12031 
12032 	free(type);
12033 	(void) scf_value_destroy(val);
12034 	(void) scf_property_destroy(prop);
12035 
12036 	return (b);
12037 }
12038 
12039 #define	DELETE_FAILURE			-1
12040 #define	DELETE_SUCCESS_NOEXTDEPS	0
12041 #define	DELETE_SUCCESS_EXTDEPS		1
12042 
12043 /*
12044  * lscf_instance_delete() deletes an instance.  Before calling
12045  * scf_instance_delete(), though, we make sure the instance isn't
12046  * running and delete dependencies in other entities which the instance
12047  * declared as "dependents".  If there are dependencies which were
12048  * created for other entities, then instead of deleting the instance we
12049  * make it "empty" by deleting all other property groups and all
12050  * snapshots.
12051  *
12052  * lscf_instance_delete() verifies that there is no external dependency pgs
12053  * before suppressing the instance. If there is, then we must not remove them
12054  * now in case the instance is re-created otherwise the dependencies would be
12055  * lost. The external dependency pgs will be removed if the dependencies are
12056  * removed.
12057  *
12058  * Returns:
12059  *  DELETE_FAILURE		on failure
12060  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12061  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12062  */
12063 static int
12064 lscf_instance_delete(scf_instance_t *inst, int force)
12065 {
12066 	scf_propertygroup_t *pg;
12067 	scf_snapshot_t *snap;
12068 	scf_iter_t *iter;
12069 	int err;
12070 	int external = 0;
12071 
12072 	/* If we're not forcing and the instance is running, refuse. */
12073 	if (!force && inst_is_running(inst)) {
12074 		char *fmri;
12075 
12076 		fmri = safe_malloc(max_scf_fmri_len + 1);
12077 
12078 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
12079 			scfdie();
12080 
12081 		semerr(gettext("Instance %s may be running.  "
12082 		    "Use delete -f if it is not.\n"), fmri);
12083 
12084 		free(fmri);
12085 		return (DELETE_FAILURE);
12086 	}
12087 
12088 	pg = scf_pg_create(g_hndl);
12089 	if (pg == NULL)
12090 		scfdie();
12091 
12092 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
12093 		(void) delete_dependents(pg);
12094 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12095 		scfdie();
12096 
12097 	scf_pg_destroy(pg);
12098 
12099 	/*
12100 	 * If the instance has some external dependencies then we must
12101 	 * keep them in case the instance is reimported otherwise the
12102 	 * dependencies would be lost on reimport.
12103 	 */
12104 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12105 	    (pg = scf_pg_create(g_hndl)) == NULL)
12106 		scfdie();
12107 
12108 	if (scf_iter_instance_pgs(iter, inst) < 0)
12109 		scfdie();
12110 
12111 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
12112 		if (pg_is_external_dependency(pg)) {
12113 			external = 1;
12114 			continue;
12115 		}
12116 
12117 		if (scf_pg_delete(pg) != 0) {
12118 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12119 				scfdie();
12120 			else {
12121 				semerr(emsg_permission_denied);
12122 
12123 				(void) scf_iter_destroy(iter);
12124 				(void) scf_pg_destroy(pg);
12125 				return (DELETE_FAILURE);
12126 			}
12127 		}
12128 	}
12129 
12130 	if (err == -1)
12131 		scfdie();
12132 
12133 	(void) scf_iter_destroy(iter);
12134 	(void) scf_pg_destroy(pg);
12135 
12136 	if (external) {
12137 		/*
12138 		 * All the pgs have been deleted for the instance except
12139 		 * the ones holding the external dependencies.
12140 		 * For the job to be complete, we must also delete the
12141 		 * snapshots associated with the instance.
12142 		 */
12143 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
12144 		    NULL)
12145 			scfdie();
12146 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
12147 			scfdie();
12148 
12149 		if (scf_iter_instance_snapshots(iter, inst) == -1)
12150 			scfdie();
12151 
12152 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
12153 			if (_scf_snapshot_delete(snap) != 0) {
12154 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12155 					scfdie();
12156 
12157 				semerr(emsg_permission_denied);
12158 
12159 				(void) scf_iter_destroy(iter);
12160 				(void) scf_snapshot_destroy(snap);
12161 				return (DELETE_FAILURE);
12162 			}
12163 		}
12164 
12165 		if (err == -1)
12166 			scfdie();
12167 
12168 		(void) scf_iter_destroy(iter);
12169 		(void) scf_snapshot_destroy(snap);
12170 		return (DELETE_SUCCESS_EXTDEPS);
12171 	}
12172 
12173 	if (scf_instance_delete(inst) != 0) {
12174 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12175 			scfdie();
12176 
12177 		semerr(emsg_permission_denied);
12178 
12179 		return (DELETE_FAILURE);
12180 	}
12181 
12182 	return (DELETE_SUCCESS_NOEXTDEPS);
12183 }
12184 
12185 /*
12186  * lscf_service_delete() deletes a service.  Before calling
12187  * scf_service_delete(), though, we call lscf_instance_delete() for
12188  * each of the instances and delete dependencies in other entities
12189  * which were created as "dependents" of this service.  If there are
12190  * dependencies which were created for other entities, then we delete
12191  * all other property groups in the service and leave it as "empty".
12192  *
12193  * lscf_service_delete() verifies that there is no external dependency
12194  * pgs at the instance & service level before suppressing the service.
12195  * If there is, then we must not remove them now in case the service
12196  * is re-imported otherwise the dependencies would be lost. The external
12197  * dependency pgs will be removed if the dependencies are removed.
12198  *
12199  * Returns:
12200  *   DELETE_FAILURE		on failure
12201  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
12202  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
12203  */
12204 static int
12205 lscf_service_delete(scf_service_t *svc, int force)
12206 {
12207 	int r;
12208 	scf_instance_t *inst;
12209 	scf_propertygroup_t *pg;
12210 	scf_iter_t *iter;
12211 	int ret;
12212 	int external = 0;
12213 
12214 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
12215 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12216 	    (iter = scf_iter_create(g_hndl)) == NULL)
12217 		scfdie();
12218 
12219 	if (scf_iter_service_instances(iter, svc) != 0)
12220 		scfdie();
12221 
12222 	for (r = scf_iter_next_instance(iter, inst);
12223 	    r == 1;
12224 	    r = scf_iter_next_instance(iter, inst)) {
12225 
12226 		ret = lscf_instance_delete(inst, force);
12227 		if (ret == DELETE_FAILURE) {
12228 			scf_iter_destroy(iter);
12229 			scf_pg_destroy(pg);
12230 			scf_instance_destroy(inst);
12231 			return (DELETE_FAILURE);
12232 		}
12233 
12234 		/*
12235 		 * Record the fact that there is some external dependencies
12236 		 * at the instance level.
12237 		 */
12238 		if (ret == DELETE_SUCCESS_EXTDEPS)
12239 			external |= 1;
12240 	}
12241 
12242 	if (r != 0)
12243 		scfdie();
12244 
12245 	/* Delete dependency property groups in dependent services. */
12246 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
12247 		(void) delete_dependents(pg);
12248 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
12249 		scfdie();
12250 
12251 	scf_iter_destroy(iter);
12252 	scf_pg_destroy(pg);
12253 	scf_instance_destroy(inst);
12254 
12255 	/*
12256 	 * If the service has some external dependencies then we don't
12257 	 * want to remove them in case the service is re-imported.
12258 	 */
12259 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12260 	    (iter = scf_iter_create(g_hndl)) == NULL)
12261 		scfdie();
12262 
12263 	if (scf_iter_service_pgs(iter, svc) < 0)
12264 		scfdie();
12265 
12266 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
12267 		if (pg_is_external_dependency(pg)) {
12268 			external |= 2;
12269 			continue;
12270 		}
12271 
12272 		if (scf_pg_delete(pg) != 0) {
12273 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12274 				scfdie();
12275 			else {
12276 				semerr(emsg_permission_denied);
12277 
12278 				(void) scf_iter_destroy(iter);
12279 				(void) scf_pg_destroy(pg);
12280 				return (DELETE_FAILURE);
12281 			}
12282 		}
12283 	}
12284 
12285 	if (r == -1)
12286 		scfdie();
12287 
12288 	(void) scf_iter_destroy(iter);
12289 	(void) scf_pg_destroy(pg);
12290 
12291 	if (external != 0)
12292 		return (DELETE_SUCCESS_EXTDEPS);
12293 
12294 	if (scf_service_delete(svc) == 0)
12295 		return (DELETE_SUCCESS_NOEXTDEPS);
12296 
12297 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12298 		scfdie();
12299 
12300 	semerr(emsg_permission_denied);
12301 	return (DELETE_FAILURE);
12302 }
12303 
12304 static int
12305 delete_callback(void *data, scf_walkinfo_t *wip)
12306 {
12307 	int force = (int)data;
12308 
12309 	if (wip->inst != NULL)
12310 		(void) lscf_instance_delete(wip->inst, force);
12311 	else
12312 		(void) lscf_service_delete(wip->svc, force);
12313 
12314 	return (0);
12315 }
12316 
12317 void
12318 lscf_delete(const char *fmri, int force)
12319 {
12320 	scf_service_t *svc;
12321 	scf_instance_t *inst;
12322 	int ret;
12323 
12324 	lscf_prep_hndl();
12325 
12326 	if (cur_snap != NULL) {
12327 		if (!snaplevel_is_instance(cur_level)) {
12328 			char *buf;
12329 
12330 			buf = safe_malloc(max_scf_name_len + 1);
12331 			if (scf_instance_get_name(cur_inst, buf,
12332 			    max_scf_name_len + 1) >= 0) {
12333 				if (strcmp(buf, fmri) == 0) {
12334 					semerr(emsg_cant_modify_snapshots);
12335 					free(buf);
12336 					return;
12337 				}
12338 			} else if (scf_error() != SCF_ERROR_DELETED) {
12339 				scfdie();
12340 			}
12341 			free(buf);
12342 		}
12343 	} else if (cur_inst != NULL) {
12344 		/* EMPTY */;
12345 	} else if (cur_svc != NULL) {
12346 		inst = scf_instance_create(g_hndl);
12347 		if (inst == NULL)
12348 			scfdie();
12349 
12350 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
12351 		    SCF_SUCCESS) {
12352 			(void) lscf_instance_delete(inst, force);
12353 			scf_instance_destroy(inst);
12354 			return;
12355 		}
12356 
12357 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12358 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12359 			scfdie();
12360 
12361 		scf_instance_destroy(inst);
12362 	} else {
12363 		assert(cur_scope != NULL);
12364 
12365 		svc = scf_service_create(g_hndl);
12366 		if (svc == NULL)
12367 			scfdie();
12368 
12369 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
12370 		    SCF_SUCCESS) {
12371 			(void) lscf_service_delete(svc, force);
12372 			scf_service_destroy(svc);
12373 			return;
12374 		}
12375 
12376 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
12377 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
12378 			scfdie();
12379 
12380 		scf_service_destroy(svc);
12381 	}
12382 
12383 	/*
12384 	 * Match FMRI to entity.
12385 	 */
12386 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
12387 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
12388 		semerr(gettext("Failed to walk instances: %s\n"),
12389 		    scf_strerror(ret));
12390 	}
12391 }
12392 
12393 
12394 
12395 /*
12396  * :properties commands.  These all end with "pg" or "prop" and generally
12397  * operate on the currently selected entity.
12398  */
12399 
12400 /*
12401  * Property listing.  List the property groups, properties, their types and
12402  * their values for the currently selected entity.
12403  */
12404 static void
12405 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
12406 {
12407 	char *buf;
12408 	uint32_t flags;
12409 
12410 	buf = safe_malloc(max_scf_pg_type_len + 1);
12411 
12412 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
12413 		scfdie();
12414 
12415 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
12416 		scfdie();
12417 
12418 	safe_printf("%-*s  %s", namewidth, name, buf);
12419 
12420 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
12421 		safe_printf("\tNONPERSISTENT");
12422 
12423 	safe_printf("\n");
12424 
12425 	free(buf);
12426 }
12427 
12428 static boolean_t
12429 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
12430 {
12431 	if (scf_property_get_value(prop, val) == 0) {
12432 		return (B_FALSE);
12433 	} else {
12434 		switch (scf_error()) {
12435 		case SCF_ERROR_NOT_FOUND:
12436 			return (B_FALSE);
12437 		case SCF_ERROR_PERMISSION_DENIED:
12438 		case SCF_ERROR_CONSTRAINT_VIOLATED:
12439 			return (B_TRUE);
12440 		default:
12441 			scfdie();
12442 			/*NOTREACHED*/
12443 		}
12444 	}
12445 }
12446 
12447 static void
12448 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
12449 {
12450 	scf_iter_t *iter;
12451 	scf_value_t *val;
12452 	const char *type;
12453 	int multiple_strings = 0;
12454 	int ret;
12455 
12456 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12457 	    (val = scf_value_create(g_hndl)) == NULL)
12458 		scfdie();
12459 
12460 	type = prop_to_typestr(prop);
12461 	assert(type != NULL);
12462 
12463 	safe_printf("%-*s  %-7s ", len, name, type);
12464 
12465 	if (prop_has_multiple_values(prop, val) &&
12466 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
12467 	    scf_value_type(val) == SCF_TYPE_USTRING))
12468 		multiple_strings = 1;
12469 
12470 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12471 		scfdie();
12472 
12473 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12474 		char *buf;
12475 		ssize_t vlen, szret;
12476 
12477 		vlen = scf_value_get_as_string(val, NULL, 0);
12478 		if (vlen < 0)
12479 			scfdie();
12480 
12481 		buf = safe_malloc(vlen + 1);
12482 
12483 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12484 		if (szret < 0)
12485 			scfdie();
12486 		assert(szret <= vlen);
12487 
12488 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12489 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
12490 			safe_printf(" \"");
12491 			(void) quote_and_print(buf, stdout, 0);
12492 			(void) putchar('"');
12493 			if (ferror(stdout)) {
12494 				(void) putchar('\n');
12495 				uu_die(gettext("Error writing to stdout.\n"));
12496 			}
12497 		} else {
12498 			safe_printf(" %s", buf);
12499 		}
12500 
12501 		free(buf);
12502 	}
12503 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12504 		scfdie();
12505 
12506 	if (putchar('\n') != '\n')
12507 		uu_die(gettext("Could not output newline"));
12508 }
12509 
12510 /*
12511  * Outputs template property group info for the describe subcommand.
12512  * If 'templates' == 2, verbose output is printed in the format expected
12513  * for describe -v, which includes all templates fields.  If pg is
12514  * not NULL, we're describing the template data, not an existing property
12515  * group, and formatting should be appropriate for describe -t.
12516  */
12517 static void
12518 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
12519 {
12520 	char *buf;
12521 	uint8_t required;
12522 	scf_property_t *stability_prop;
12523 	scf_value_t *stability_val;
12524 
12525 	if (templates == 0)
12526 		return;
12527 
12528 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
12529 	    (stability_val = scf_value_create(g_hndl)) == NULL)
12530 		scfdie();
12531 
12532 	if (templates == 2 && pg != NULL) {
12533 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
12534 		    stability_prop) == 0) {
12535 			if (prop_check_type(stability_prop,
12536 			    SCF_TYPE_ASTRING) == 0 &&
12537 			    prop_get_val(stability_prop, stability_val) == 0) {
12538 				char *stability;
12539 
12540 				stability = safe_malloc(max_scf_value_len + 1);
12541 
12542 				if (scf_value_get_astring(stability_val,
12543 				    stability, max_scf_value_len + 1) == -1 &&
12544 				    scf_error() != SCF_ERROR_NOT_FOUND)
12545 					scfdie();
12546 
12547 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12548 				    gettext("stability"), stability);
12549 
12550 				free(stability);
12551 			}
12552 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
12553 			scfdie();
12554 	}
12555 
12556 	scf_property_destroy(stability_prop);
12557 	scf_value_destroy(stability_val);
12558 
12559 	if (pgt == NULL)
12560 		return;
12561 
12562 	if (pg == NULL || templates == 2) {
12563 		/* print type info only if scf_tmpl_pg_name succeeds */
12564 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
12565 			if (pg != NULL)
12566 				safe_printf("%s", TMPL_INDENT);
12567 			safe_printf("%s: ", gettext("name"));
12568 			safe_printf("%s\n", buf);
12569 			free(buf);
12570 		}
12571 
12572 		/* print type info only if scf_tmpl_pg_type succeeds */
12573 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
12574 			if (pg != NULL)
12575 				safe_printf("%s", TMPL_INDENT);
12576 			safe_printf("%s: ", gettext("type"));
12577 			safe_printf("%s\n", buf);
12578 			free(buf);
12579 		}
12580 	}
12581 
12582 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
12583 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12584 		    required ? "true" : "false");
12585 
12586 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
12587 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
12588 		    buf);
12589 		free(buf);
12590 	}
12591 
12592 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
12593 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12594 		    buf);
12595 		free(buf);
12596 	}
12597 
12598 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
12599 		if (templates == 2)
12600 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12601 			    gettext("description"), buf);
12602 		else
12603 			safe_printf("%s%s\n", TMPL_INDENT, buf);
12604 		free(buf);
12605 	}
12606 
12607 }
12608 
12609 /*
12610  * With as_value set to true, indent as appropriate for the value level.
12611  * If false, indent to appropriate level for inclusion in constraint
12612  * or choice printout.
12613  */
12614 static void
12615 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
12616     int as_value)
12617 {
12618 	char *buf;
12619 
12620 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
12621 		if (as_value == 0)
12622 			safe_printf("%s", TMPL_CHOICE_INDENT);
12623 		else
12624 			safe_printf("%s", TMPL_INDENT);
12625 		safe_printf("%s: %s\n", gettext("value common name"), buf);
12626 		free(buf);
12627 	}
12628 
12629 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
12630 		if (as_value == 0)
12631 			safe_printf("%s", TMPL_CHOICE_INDENT);
12632 		else
12633 			safe_printf("%s", TMPL_INDENT);
12634 		safe_printf("%s: %s\n", gettext("value description"), buf);
12635 		free(buf);
12636 	}
12637 }
12638 
12639 static void
12640 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
12641 {
12642 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
12643 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
12644 	safe_printf("%s\n", val_buf);
12645 
12646 	print_template_value_details(prt, val_buf, 1);
12647 }
12648 
12649 static void
12650 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
12651 {
12652 	int i, printed = 0;
12653 	scf_values_t values;
12654 	scf_count_ranges_t c_ranges;
12655 	scf_int_ranges_t i_ranges;
12656 
12657 	printed = 0;
12658 	i = 0;
12659 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
12660 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12661 		    gettext("value constraints"));
12662 		printed++;
12663 		for (i = 0; i < values.value_count; ++i) {
12664 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12665 			    gettext("value name"), values.values_as_strings[i]);
12666 			if (verbose == 1)
12667 				print_template_value_details(prt,
12668 				    values.values_as_strings[i], 0);
12669 		}
12670 
12671 		scf_values_destroy(&values);
12672 	}
12673 
12674 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
12675 		if (printed++ == 0)
12676 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12677 			    gettext("value constraints"));
12678 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12679 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12680 			    gettext("range"), c_ranges.scr_min[i],
12681 			    c_ranges.scr_max[i]);
12682 		}
12683 		scf_count_ranges_destroy(&c_ranges);
12684 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12685 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
12686 		if (printed++ == 0)
12687 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12688 			    gettext("value constraints"));
12689 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12690 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12691 			    gettext("range"), i_ranges.sir_min[i],
12692 			    i_ranges.sir_max[i]);
12693 		}
12694 		scf_int_ranges_destroy(&i_ranges);
12695 	}
12696 }
12697 
12698 static void
12699 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
12700 {
12701 	int i = 0, printed = 0;
12702 	scf_values_t values;
12703 	scf_count_ranges_t c_ranges;
12704 	scf_int_ranges_t i_ranges;
12705 
12706 	printed = 0;
12707 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
12708 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12709 		    gettext("value constraints"));
12710 		printed++;
12711 		for (i = 0; i < values.value_count; i++) {
12712 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12713 			    gettext("value name"), values.values_as_strings[i]);
12714 			if (verbose == 1)
12715 				print_template_value_details(prt,
12716 				    values.values_as_strings[i], 0);
12717 		}
12718 
12719 		scf_values_destroy(&values);
12720 	}
12721 
12722 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
12723 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
12724 			if (printed++ == 0)
12725 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12726 				    gettext("value choices"));
12727 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
12728 			    gettext("range"), c_ranges.scr_min[i],
12729 			    c_ranges.scr_max[i]);
12730 		}
12731 		scf_count_ranges_destroy(&c_ranges);
12732 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
12733 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
12734 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
12735 			if (printed++ == 0)
12736 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
12737 				    gettext("value choices"));
12738 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
12739 			    gettext("range"), i_ranges.sir_min[i],
12740 			    i_ranges.sir_max[i]);
12741 		}
12742 		scf_int_ranges_destroy(&i_ranges);
12743 	}
12744 }
12745 
12746 static void
12747 list_values_by_template(scf_prop_tmpl_t *prt)
12748 {
12749 	print_template_constraints(prt, 1);
12750 	print_template_choices(prt, 1);
12751 }
12752 
12753 static void
12754 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
12755 {
12756 	char *val_buf;
12757 	scf_iter_t *iter;
12758 	scf_value_t *val;
12759 	int ret;
12760 
12761 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12762 	    (val = scf_value_create(g_hndl)) == NULL)
12763 		scfdie();
12764 
12765 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
12766 		scfdie();
12767 
12768 	val_buf = safe_malloc(max_scf_value_len + 1);
12769 
12770 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12771 		if (scf_value_get_as_string(val, val_buf,
12772 		    max_scf_value_len + 1) < 0)
12773 			scfdie();
12774 
12775 		print_template_value(prt, val_buf);
12776 	}
12777 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
12778 		scfdie();
12779 	free(val_buf);
12780 
12781 	print_template_constraints(prt, 0);
12782 	print_template_choices(prt, 0);
12783 
12784 }
12785 
12786 /*
12787  * Outputs property info for the describe subcommand
12788  * Verbose output if templates == 2, -v option of svccfg describe
12789  * Displays template data if prop is not NULL, -t option of svccfg describe
12790  */
12791 static void
12792 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
12793 {
12794 	char *buf;
12795 	uint8_t u_buf;
12796 	int i;
12797 	uint64_t min, max;
12798 	scf_values_t values;
12799 
12800 	if (prt == NULL || templates == 0)
12801 		return;
12802 
12803 	if (prop == NULL) {
12804 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
12805 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
12806 			safe_printf("%s\n", buf);
12807 			free(buf);
12808 		} else
12809 			safe_printf("(%s)\n", gettext("any"));
12810 	}
12811 
12812 	if (prop == NULL || templates == 2) {
12813 		if (prop != NULL)
12814 			safe_printf("%s", TMPL_INDENT);
12815 		else
12816 			safe_printf("%s", TMPL_VALUE_INDENT);
12817 		safe_printf("%s: ", gettext("type"));
12818 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
12819 			safe_printf("%s\n", buf);
12820 			free(buf);
12821 		} else
12822 			safe_printf("(%s)\n", gettext("any"));
12823 	}
12824 
12825 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
12826 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
12827 		    u_buf ? "true" : "false");
12828 
12829 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
12830 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
12831 		    buf);
12832 		free(buf);
12833 	}
12834 
12835 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
12836 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
12837 		    buf);
12838 		free(buf);
12839 	}
12840 
12841 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
12842 		safe_printf("%s%s\n", TMPL_INDENT, buf);
12843 		free(buf);
12844 	}
12845 
12846 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
12847 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
12848 		    scf_tmpl_visibility_to_string(u_buf));
12849 
12850 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
12851 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12852 		    gettext("minimum number of values"), min);
12853 		if (max == ULLONG_MAX) {
12854 			safe_printf("%s%s: %s\n", TMPL_INDENT,
12855 			    gettext("maximum number of values"),
12856 			    gettext("unlimited"));
12857 		} else {
12858 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
12859 			    gettext("maximum number of values"), max);
12860 		}
12861 	}
12862 
12863 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
12864 		for (i = 0; i < values.value_count; i++) {
12865 			if (i == 0) {
12866 				safe_printf("%s%s:", TMPL_INDENT,
12867 				    gettext("internal separators"));
12868 			}
12869 			safe_printf(" \"%s\"", values.values_as_strings[i]);
12870 		}
12871 		safe_printf("\n");
12872 	}
12873 
12874 	if (templates != 2)
12875 		return;
12876 
12877 	if (prop != NULL)
12878 		list_values_tmpl(prt, prop);
12879 	else
12880 		list_values_by_template(prt);
12881 }
12882 
12883 static char *
12884 read_astring(scf_propertygroup_t *pg, const char *prop_name)
12885 {
12886 	char *rv;
12887 
12888 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
12889 	if (rv == NULL) {
12890 		switch (scf_error()) {
12891 		case SCF_ERROR_NOT_FOUND:
12892 			break;
12893 		default:
12894 			scfdie();
12895 		}
12896 	}
12897 	return (rv);
12898 }
12899 
12900 static void
12901 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
12902 {
12903 	size_t doc_len;
12904 	size_t man_len;
12905 	char *pg_name;
12906 	char *text = NULL;
12907 	int rv;
12908 
12909 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
12910 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
12911 	pg_name = safe_malloc(max_scf_name_len + 1);
12912 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
12913 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
12914 			scfdie();
12915 		}
12916 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
12917 			/* Display doc_link and and uri */
12918 			safe_printf("%s%s:\n", TMPL_INDENT,
12919 			    gettext("doc_link"));
12920 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
12921 			if (text != NULL) {
12922 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12923 				    TMPL_INDENT, gettext("name"), text);
12924 				uu_free(text);
12925 			}
12926 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
12927 			if (text != NULL) {
12928 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
12929 				    gettext("uri"), text);
12930 				uu_free(text);
12931 			}
12932 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
12933 		    man_len) == 0) {
12934 			/* Display manpage title, section and path */
12935 			safe_printf("%s%s:\n", TMPL_INDENT,
12936 			    gettext("manpage"));
12937 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
12938 			if (text != NULL) {
12939 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12940 				    TMPL_INDENT, gettext("title"), text);
12941 				uu_free(text);
12942 			}
12943 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
12944 			if (text != NULL) {
12945 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12946 				    TMPL_INDENT, gettext("section"), text);
12947 				uu_free(text);
12948 			}
12949 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
12950 			if (text != NULL) {
12951 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
12952 				    TMPL_INDENT, gettext("manpath"), text);
12953 				uu_free(text);
12954 			}
12955 		}
12956 	}
12957 	if (rv == -1)
12958 		scfdie();
12959 
12960 done:
12961 	free(pg_name);
12962 }
12963 
12964 static void
12965 list_entity_tmpl(int templates)
12966 {
12967 	char *common_name = NULL;
12968 	char *description = NULL;
12969 	char *locale = NULL;
12970 	scf_iter_t *iter;
12971 	scf_propertygroup_t *pg;
12972 	scf_property_t *prop;
12973 	int r;
12974 	scf_value_t *val;
12975 
12976 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12977 	    (prop = scf_property_create(g_hndl)) == NULL ||
12978 	    (val = scf_value_create(g_hndl)) == NULL ||
12979 	    (iter = scf_iter_create(g_hndl)) == NULL)
12980 		scfdie();
12981 
12982 	locale = setlocale(LC_MESSAGES, NULL);
12983 
12984 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
12985 		common_name = safe_malloc(max_scf_value_len + 1);
12986 
12987 		/* Try both the current locale and the "C" locale. */
12988 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
12989 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
12990 		    scf_pg_get_property(pg, "C", prop) == 0)) {
12991 			if (prop_get_val(prop, val) == 0 &&
12992 			    scf_value_get_ustring(val, common_name,
12993 			    max_scf_value_len + 1) != -1) {
12994 				safe_printf("%s%s: %s\n", TMPL_INDENT,
12995 				    gettext("common name"), common_name);
12996 			}
12997 		}
12998 	}
12999 
13000 	/*
13001 	 * Do description, manpages, and doc links if templates == 2.
13002 	 */
13003 	if (templates == 2) {
13004 		/* Get the description. */
13005 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
13006 			description = safe_malloc(max_scf_value_len + 1);
13007 
13008 			/* Try both the current locale and the "C" locale. */
13009 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
13010 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
13011 			    scf_pg_get_property(pg, "C", prop) == 0)) {
13012 				if (prop_get_val(prop, val) == 0 &&
13013 				    scf_value_get_ustring(val, description,
13014 				    max_scf_value_len + 1) != -1) {
13015 					safe_printf("%s%s: %s\n", TMPL_INDENT,
13016 					    gettext("description"),
13017 					    description);
13018 				}
13019 			}
13020 		}
13021 
13022 		/* Process doc_link & manpage elements. */
13023 		if (cur_level != NULL) {
13024 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
13025 			    SCF_GROUP_TEMPLATE);
13026 		} else if (cur_inst != NULL) {
13027 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
13028 			    SCF_GROUP_TEMPLATE);
13029 		} else {
13030 			r = scf_iter_service_pgs_typed(iter, cur_svc,
13031 			    SCF_GROUP_TEMPLATE);
13032 		}
13033 		if (r == 0) {
13034 			display_documentation(iter, pg);
13035 		}
13036 	}
13037 
13038 	free(common_name);
13039 	free(description);
13040 	scf_pg_destroy(pg);
13041 	scf_property_destroy(prop);
13042 	scf_value_destroy(val);
13043 	scf_iter_destroy(iter);
13044 }
13045 
13046 static void
13047 listtmpl(const char *pattern, int templates)
13048 {
13049 	scf_pg_tmpl_t *pgt;
13050 	scf_prop_tmpl_t *prt;
13051 	char *snapbuf = NULL;
13052 	char *fmribuf;
13053 	char *pg_name = NULL, *prop_name = NULL;
13054 	ssize_t prop_name_size;
13055 	char *qual_prop_name;
13056 	char *search_name;
13057 	int listed = 0;
13058 
13059 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13060 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
13061 		scfdie();
13062 
13063 	fmribuf = safe_malloc(max_scf_name_len + 1);
13064 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
13065 
13066 	if (cur_snap != NULL) {
13067 		snapbuf = safe_malloc(max_scf_name_len + 1);
13068 		if (scf_snapshot_get_name(cur_snap, snapbuf,
13069 		    max_scf_name_len + 1) < 0)
13070 			scfdie();
13071 	}
13072 
13073 	if (cur_inst != NULL) {
13074 		if (scf_instance_to_fmri(cur_inst, fmribuf,
13075 		    max_scf_name_len + 1) < 0)
13076 			scfdie();
13077 	} else if (cur_svc != NULL) {
13078 		if (scf_service_to_fmri(cur_svc, fmribuf,
13079 		    max_scf_name_len + 1) < 0)
13080 			scfdie();
13081 	} else
13082 		abort();
13083 
13084 	/* If pattern is specified, we want to list only those items. */
13085 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, 0) == 1) {
13086 		listed = 0;
13087 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
13088 		    fnmatch(pattern, pg_name, 0) == 0)) {
13089 			list_pg_tmpl(pgt, NULL, templates);
13090 			listed++;
13091 		}
13092 
13093 		scf_tmpl_prop_reset(prt);
13094 
13095 		while (scf_tmpl_iter_props(pgt, prt, 0) == 0) {
13096 			search_name = NULL;
13097 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
13098 			if ((prop_name_size > 0) && (pg_name != NULL)) {
13099 				if (snprintf(qual_prop_name,
13100 				    max_scf_name_len + 1, "%s/%s",
13101 				    pg_name, prop_name) >=
13102 				    max_scf_name_len + 1) {
13103 					prop_name_size = -1;
13104 				} else {
13105 					search_name = qual_prop_name;
13106 				}
13107 			}
13108 			if (listed > 0 || pattern == NULL ||
13109 			    (prop_name_size > 0 &&
13110 			    fnmatch(pattern, search_name,
13111 			    FNM_PATHNAME) == 0))
13112 				list_prop_tmpl(prt, NULL, templates);
13113 			if (prop_name != NULL) {
13114 				free(prop_name);
13115 				prop_name = NULL;
13116 			}
13117 		}
13118 		if (pg_name != NULL) {
13119 			free(pg_name);
13120 			pg_name = NULL;
13121 		}
13122 	}
13123 
13124 	scf_tmpl_prop_destroy(prt);
13125 	scf_tmpl_pg_destroy(pgt);
13126 	free(snapbuf);
13127 	free(fmribuf);
13128 	free(qual_prop_name);
13129 }
13130 
13131 static void
13132 listprop(const char *pattern, int only_pgs, int templates)
13133 {
13134 	scf_propertygroup_t *pg;
13135 	scf_property_t *prop;
13136 	scf_iter_t *iter, *piter;
13137 	char *pgnbuf, *prnbuf, *ppnbuf;
13138 	scf_pg_tmpl_t *pgt, *pgtp;
13139 	scf_prop_tmpl_t *prt;
13140 
13141 	void **objects;
13142 	char **names;
13143 	void **tmpls;
13144 	int allocd, i;
13145 
13146 	int ret;
13147 	ssize_t pgnlen, prnlen, szret;
13148 	size_t max_len = 0;
13149 
13150 	if (cur_svc == NULL && cur_inst == NULL) {
13151 		semerr(emsg_entity_not_selected);
13152 		return;
13153 	}
13154 
13155 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13156 	    (prop = scf_property_create(g_hndl)) == NULL ||
13157 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13158 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13159 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13160 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
13161 		scfdie();
13162 
13163 	prnbuf = safe_malloc(max_scf_name_len + 1);
13164 
13165 	if (cur_level != NULL)
13166 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
13167 	else if (cur_inst != NULL)
13168 		ret = scf_iter_instance_pgs(iter, cur_inst);
13169 	else
13170 		ret = scf_iter_service_pgs(iter, cur_svc);
13171 	if (ret != 0) {
13172 		return;
13173 	}
13174 
13175 	/*
13176 	 * We want to only list items which match pattern, and we want the
13177 	 * second column to line up, so during the first pass we'll save
13178 	 * matching items, their names, and their templates in objects,
13179 	 * names, and tmpls, computing the maximum name length as we go,
13180 	 * and then we'll print them out.
13181 	 *
13182 	 * Note: We always keep an extra slot available so the array can be
13183 	 * NULL-terminated.
13184 	 */
13185 	i = 0;
13186 	allocd = 1;
13187 	objects = safe_malloc(sizeof (*objects));
13188 	names = safe_malloc(sizeof (*names));
13189 	tmpls = safe_malloc(sizeof (*tmpls));
13190 
13191 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13192 		int new_pg = 0;
13193 		int print_props = 0;
13194 		pgtp = NULL;
13195 
13196 		pgnlen = scf_pg_get_name(pg, NULL, 0);
13197 		if (pgnlen < 0)
13198 			scfdie();
13199 
13200 		pgnbuf = safe_malloc(pgnlen + 1);
13201 
13202 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
13203 		if (szret < 0)
13204 			scfdie();
13205 		assert(szret <= pgnlen);
13206 
13207 		if (scf_tmpl_get_by_pg(pg, pgt, 0) == -1) {
13208 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13209 				scfdie();
13210 			pgtp = NULL;
13211 		} else {
13212 			pgtp = pgt;
13213 		}
13214 
13215 		if (pattern == NULL ||
13216 		    fnmatch(pattern, pgnbuf, 0) == 0) {
13217 			if (i+1 >= allocd) {
13218 				allocd *= 2;
13219 				objects = realloc(objects,
13220 				    sizeof (*objects) * allocd);
13221 				names =
13222 				    realloc(names, sizeof (*names) * allocd);
13223 				tmpls = realloc(tmpls,
13224 				    sizeof (*tmpls) * allocd);
13225 				if (objects == NULL || names == NULL ||
13226 				    tmpls == NULL)
13227 					uu_die(gettext("Out of memory"));
13228 			}
13229 			objects[i] = pg;
13230 			names[i] = pgnbuf;
13231 
13232 			if (pgtp == NULL)
13233 				tmpls[i] = NULL;
13234 			else
13235 				tmpls[i] = pgt;
13236 
13237 			++i;
13238 
13239 			if (pgnlen > max_len)
13240 				max_len = pgnlen;
13241 
13242 			new_pg = 1;
13243 			print_props = 1;
13244 		}
13245 
13246 		if (only_pgs) {
13247 			if (new_pg) {
13248 				pg = scf_pg_create(g_hndl);
13249 				if (pg == NULL)
13250 					scfdie();
13251 				pgt = scf_tmpl_pg_create(g_hndl);
13252 				if (pgt == NULL)
13253 					scfdie();
13254 			} else
13255 				free(pgnbuf);
13256 
13257 			continue;
13258 		}
13259 
13260 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13261 			scfdie();
13262 
13263 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
13264 			prnlen = scf_property_get_name(prop, prnbuf,
13265 			    max_scf_name_len + 1);
13266 			if (prnlen < 0)
13267 				scfdie();
13268 
13269 			/* Will prepend the property group name and a slash. */
13270 			prnlen += pgnlen + 1;
13271 
13272 			ppnbuf = safe_malloc(prnlen + 1);
13273 
13274 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
13275 			    prnbuf) < 0)
13276 				uu_die("snprintf");
13277 
13278 			if (pattern == NULL || print_props == 1 ||
13279 			    fnmatch(pattern, ppnbuf, 0) == 0) {
13280 				if (i+1 >= allocd) {
13281 					allocd *= 2;
13282 					objects = realloc(objects,
13283 					    sizeof (*objects) * allocd);
13284 					names = realloc(names,
13285 					    sizeof (*names) * allocd);
13286 					tmpls = realloc(tmpls,
13287 					    sizeof (*tmpls) * allocd);
13288 					if (objects == NULL || names == NULL ||
13289 					    tmpls == NULL)
13290 						uu_die(gettext(
13291 						    "Out of memory"));
13292 				}
13293 
13294 				objects[i] = prop;
13295 				names[i] = ppnbuf;
13296 
13297 				if (pgtp != NULL) {
13298 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
13299 					    prt, 0) < 0) {
13300 						if (scf_error() !=
13301 						    SCF_ERROR_NOT_FOUND)
13302 							scfdie();
13303 						tmpls[i] = NULL;
13304 					} else {
13305 						tmpls[i] = prt;
13306 					}
13307 				} else {
13308 					tmpls[i] = NULL;
13309 				}
13310 
13311 				++i;
13312 
13313 				if (prnlen > max_len)
13314 					max_len = prnlen;
13315 
13316 				prop = scf_property_create(g_hndl);
13317 				prt = scf_tmpl_prop_create(g_hndl);
13318 			} else {
13319 				free(ppnbuf);
13320 			}
13321 		}
13322 
13323 		if (new_pg) {
13324 			pg = scf_pg_create(g_hndl);
13325 			if (pg == NULL)
13326 				scfdie();
13327 			pgt = scf_tmpl_pg_create(g_hndl);
13328 			if (pgt == NULL)
13329 				scfdie();
13330 		} else
13331 			free(pgnbuf);
13332 	}
13333 	if (ret != 0)
13334 		scfdie();
13335 
13336 	objects[i] = NULL;
13337 
13338 	scf_pg_destroy(pg);
13339 	scf_tmpl_pg_destroy(pgt);
13340 	scf_property_destroy(prop);
13341 	scf_tmpl_prop_destroy(prt);
13342 
13343 	for (i = 0; objects[i] != NULL; ++i) {
13344 		if (strchr(names[i], '/') == NULL) {
13345 			/* property group */
13346 			pg = (scf_propertygroup_t *)objects[i];
13347 			pgt = (scf_pg_tmpl_t *)tmpls[i];
13348 			list_pg_info(pg, names[i], max_len);
13349 			list_pg_tmpl(pgt, pg, templates);
13350 			free(names[i]);
13351 			scf_pg_destroy(pg);
13352 			if (pgt != NULL)
13353 				scf_tmpl_pg_destroy(pgt);
13354 		} else {
13355 			/* property */
13356 			prop = (scf_property_t *)objects[i];
13357 			prt = (scf_prop_tmpl_t *)tmpls[i];
13358 			list_prop_info(prop, names[i], max_len);
13359 			list_prop_tmpl(prt, prop, templates);
13360 			free(names[i]);
13361 			scf_property_destroy(prop);
13362 			if (prt != NULL)
13363 				scf_tmpl_prop_destroy(prt);
13364 		}
13365 	}
13366 
13367 	free(names);
13368 	free(objects);
13369 	free(tmpls);
13370 }
13371 
13372 void
13373 lscf_listpg(const char *pattern)
13374 {
13375 	lscf_prep_hndl();
13376 
13377 	listprop(pattern, 1, 0);
13378 }
13379 
13380 /*
13381  * Property group and property creation, setting, and deletion.  setprop (and
13382  * its alias, addprop) can either create a property group of a given type, or
13383  * it can create or set a property to a given type and list of values.
13384  */
13385 void
13386 lscf_addpg(const char *name, const char *type, const char *flags)
13387 {
13388 	scf_propertygroup_t *pg;
13389 	int ret;
13390 	uint32_t flgs = 0;
13391 	const char *cp;
13392 
13393 
13394 	lscf_prep_hndl();
13395 
13396 	if (cur_snap != NULL) {
13397 		semerr(emsg_cant_modify_snapshots);
13398 		return;
13399 	}
13400 
13401 	if (cur_inst == NULL && cur_svc == NULL) {
13402 		semerr(emsg_entity_not_selected);
13403 		return;
13404 	}
13405 
13406 	if (flags != NULL) {
13407 		for (cp = flags; *cp != '\0'; ++cp) {
13408 			switch (*cp) {
13409 			case 'P':
13410 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
13411 				break;
13412 
13413 			case 'p':
13414 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
13415 				break;
13416 
13417 			default:
13418 				semerr(gettext("Invalid property group flag "
13419 				    "%c."), *cp);
13420 				return;
13421 			}
13422 		}
13423 	}
13424 
13425 	pg = scf_pg_create(g_hndl);
13426 	if (pg == NULL)
13427 		scfdie();
13428 
13429 	if (cur_inst != NULL)
13430 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
13431 	else
13432 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
13433 
13434 	if (ret != SCF_SUCCESS) {
13435 		switch (scf_error()) {
13436 		case SCF_ERROR_INVALID_ARGUMENT:
13437 			semerr(gettext("Name, type, or flags are invalid.\n"));
13438 			break;
13439 
13440 		case SCF_ERROR_EXISTS:
13441 			semerr(gettext("Property group already exists.\n"));
13442 			break;
13443 
13444 		case SCF_ERROR_PERMISSION_DENIED:
13445 			semerr(emsg_permission_denied);
13446 			break;
13447 
13448 		case SCF_ERROR_BACKEND_ACCESS:
13449 			semerr(gettext("Backend refused access.\n"));
13450 			break;
13451 
13452 		default:
13453 			scfdie();
13454 		}
13455 	}
13456 
13457 	scf_pg_destroy(pg);
13458 
13459 	private_refresh();
13460 }
13461 
13462 void
13463 lscf_delpg(char *name)
13464 {
13465 	lscf_prep_hndl();
13466 
13467 	if (cur_snap != NULL) {
13468 		semerr(emsg_cant_modify_snapshots);
13469 		return;
13470 	}
13471 
13472 	if (cur_inst == NULL && cur_svc == NULL) {
13473 		semerr(emsg_entity_not_selected);
13474 		return;
13475 	}
13476 
13477 	if (strchr(name, '/') != NULL) {
13478 		semerr(emsg_invalid_pg_name, name);
13479 		return;
13480 	}
13481 
13482 	lscf_delprop(name);
13483 }
13484 
13485 /*
13486  * scf_delhash() is used to remove the property group related to the
13487  * hash entry for a specific manifest in the repository. pgname will be
13488  * constructed from the location of the manifest file. If deathrow isn't 0,
13489  * manifest file doesn't need to exist (manifest string will be used as
13490  * an absolute path).
13491  */
13492 void
13493 lscf_delhash(char *manifest, int deathrow)
13494 {
13495 	char *pgname;
13496 
13497 	if (cur_snap != NULL ||
13498 	    cur_inst != NULL || cur_svc != NULL) {
13499 		warn(gettext("error, an entity is selected\n"));
13500 		return;
13501 	}
13502 
13503 	/* select smf/manifest */
13504 	lscf_select(HASH_SVC);
13505 	/*
13506 	 * Translate the manifest file name to property name. In the deathrow
13507 	 * case, the manifest file does not need to exist.
13508 	 */
13509 	pgname = mhash_filename_to_propname(manifest,
13510 	    deathrow ? B_TRUE : B_FALSE);
13511 	if (pgname == NULL) {
13512 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
13513 		return;
13514 	}
13515 	/* delete the hash property name */
13516 	lscf_delpg(pgname);
13517 }
13518 
13519 void
13520 lscf_listprop(const char *pattern)
13521 {
13522 	lscf_prep_hndl();
13523 
13524 	listprop(pattern, 0, 0);
13525 }
13526 
13527 int
13528 lscf_setprop(const char *pgname, const char *type, const char *value,
13529     const uu_list_t *values)
13530 {
13531 	scf_type_t ty, current_ty;
13532 	scf_service_t *svc;
13533 	scf_propertygroup_t *pg, *parent_pg;
13534 	scf_property_t *prop, *parent_prop;
13535 	scf_pg_tmpl_t *pgt;
13536 	scf_prop_tmpl_t *prt;
13537 	int ret, result = 0;
13538 	scf_transaction_t *tx;
13539 	scf_transaction_entry_t *e;
13540 	scf_value_t *v;
13541 	uu_list_walk_t *walk;
13542 	string_list_t *sp;
13543 	char *propname;
13544 	int req_quotes = 0;
13545 
13546 	lscf_prep_hndl();
13547 
13548 	if ((e = scf_entry_create(g_hndl)) == NULL ||
13549 	    (svc = scf_service_create(g_hndl)) == NULL ||
13550 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
13551 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13552 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
13553 	    (prop = scf_property_create(g_hndl)) == NULL ||
13554 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
13555 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
13556 	    (tx = scf_transaction_create(g_hndl)) == NULL)
13557 		scfdie();
13558 
13559 	if (cur_snap != NULL) {
13560 		semerr(emsg_cant_modify_snapshots);
13561 		goto fail;
13562 	}
13563 
13564 	if (cur_inst == NULL && cur_svc == NULL) {
13565 		semerr(emsg_entity_not_selected);
13566 		goto fail;
13567 	}
13568 
13569 	propname = strchr(pgname, '/');
13570 	if (propname == NULL) {
13571 		semerr(gettext("Property names must contain a `/'.\n"));
13572 		goto fail;
13573 	}
13574 
13575 	*propname = '\0';
13576 	++propname;
13577 
13578 	if (type != NULL) {
13579 		ty = string_to_type(type);
13580 		if (ty == SCF_TYPE_INVALID) {
13581 			semerr(gettext("Unknown type \"%s\".\n"), type);
13582 			goto fail;
13583 		}
13584 	}
13585 
13586 	if (cur_inst != NULL)
13587 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
13588 	else
13589 		ret = scf_service_get_pg(cur_svc, pgname, pg);
13590 	if (ret != SCF_SUCCESS) {
13591 		switch (scf_error()) {
13592 		case SCF_ERROR_NOT_FOUND:
13593 			semerr(emsg_no_such_pg, pgname);
13594 			goto fail;
13595 
13596 		case SCF_ERROR_INVALID_ARGUMENT:
13597 			semerr(emsg_invalid_pg_name, pgname);
13598 			goto fail;
13599 
13600 		default:
13601 			scfdie();
13602 			break;
13603 		}
13604 	}
13605 
13606 	do {
13607 		if (scf_pg_update(pg) == -1)
13608 			scfdie();
13609 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13610 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13611 				scfdie();
13612 
13613 			semerr(emsg_permission_denied);
13614 			goto fail;
13615 		}
13616 
13617 		ret = scf_pg_get_property(pg, propname, prop);
13618 		if (ret == SCF_SUCCESS) {
13619 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
13620 				scfdie();
13621 
13622 			if (type == NULL)
13623 				ty = current_ty;
13624 			if (scf_transaction_property_change_type(tx, e,
13625 			    propname, ty) == -1)
13626 				scfdie();
13627 
13628 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
13629 			/* Infer the type, if possible. */
13630 			if (type == NULL) {
13631 				/*
13632 				 * First check if we're an instance and the
13633 				 * property is set on the service.
13634 				 */
13635 				if (cur_inst != NULL &&
13636 				    scf_instance_get_parent(cur_inst,
13637 				    svc) == 0 &&
13638 				    scf_service_get_pg(cur_svc, pgname,
13639 				    parent_pg) == 0 &&
13640 				    scf_pg_get_property(parent_pg, propname,
13641 				    parent_prop) == 0 &&
13642 				    scf_property_type(parent_prop,
13643 				    &current_ty) == 0) {
13644 					ty = current_ty;
13645 
13646 				/* Then check for a type set in a template. */
13647 				} else if (scf_tmpl_get_by_pg(pg, pgt,
13648 				    0) == 0 &&
13649 				    scf_tmpl_get_by_prop(pgt, propname, prt,
13650 				    0) == 0 &&
13651 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
13652 					ty = current_ty;
13653 
13654 				/* If type can't be inferred, fail. */
13655 				} else {
13656 					semerr(gettext("Type required for new "
13657 					    "properties.\n"));
13658 					goto fail;
13659 				}
13660 			}
13661 			if (scf_transaction_property_new(tx, e, propname,
13662 			    ty) == -1)
13663 				scfdie();
13664 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13665 			semerr(emsg_invalid_prop_name, propname);
13666 			goto fail;
13667 		} else {
13668 			scfdie();
13669 		}
13670 
13671 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
13672 			req_quotes = 1;
13673 
13674 		if (value != NULL) {
13675 			v = string_to_value(value, ty, 0);
13676 
13677 			if (v == NULL)
13678 				goto fail;
13679 
13680 			ret = scf_entry_add_value(e, v);
13681 			assert(ret == SCF_SUCCESS);
13682 		} else {
13683 			assert(values != NULL);
13684 
13685 			walk = uu_list_walk_start((uu_list_t *)values,
13686 			    UU_DEFAULT);
13687 			if (walk == NULL)
13688 				uu_die(gettext("Could not walk list"));
13689 
13690 			for (sp = uu_list_walk_next(walk); sp != NULL;
13691 			    sp = uu_list_walk_next(walk)) {
13692 				v = string_to_value(sp->str, ty, req_quotes);
13693 
13694 				if (v == NULL) {
13695 					scf_entry_destroy_children(e);
13696 					goto fail;
13697 				}
13698 
13699 				ret = scf_entry_add_value(e, v);
13700 				assert(ret == SCF_SUCCESS);
13701 			}
13702 			uu_list_walk_end(walk);
13703 		}
13704 		result = scf_transaction_commit(tx);
13705 
13706 		scf_transaction_reset(tx);
13707 		scf_entry_destroy_children(e);
13708 	} while (result == 0);
13709 
13710 	if (result < 0) {
13711 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13712 			scfdie();
13713 
13714 		semerr(emsg_permission_denied);
13715 		goto fail;
13716 	}
13717 
13718 	ret = 0;
13719 
13720 	private_refresh();
13721 
13722 	goto cleanup;
13723 
13724 fail:
13725 	ret = -1;
13726 
13727 cleanup:
13728 	scf_transaction_destroy(tx);
13729 	scf_entry_destroy(e);
13730 	scf_service_destroy(svc);
13731 	scf_pg_destroy(parent_pg);
13732 	scf_pg_destroy(pg);
13733 	scf_property_destroy(parent_prop);
13734 	scf_property_destroy(prop);
13735 	scf_tmpl_pg_destroy(pgt);
13736 	scf_tmpl_prop_destroy(prt);
13737 
13738 	return (ret);
13739 }
13740 
13741 void
13742 lscf_delprop(char *pgn)
13743 {
13744 	char *slash, *pn;
13745 	scf_propertygroup_t *pg;
13746 	scf_transaction_t *tx;
13747 	scf_transaction_entry_t *e;
13748 	int ret;
13749 
13750 
13751 	lscf_prep_hndl();
13752 
13753 	if (cur_snap != NULL) {
13754 		semerr(emsg_cant_modify_snapshots);
13755 		return;
13756 	}
13757 
13758 	if (cur_inst == NULL && cur_svc == NULL) {
13759 		semerr(emsg_entity_not_selected);
13760 		return;
13761 	}
13762 
13763 	pg = scf_pg_create(g_hndl);
13764 	if (pg == NULL)
13765 		scfdie();
13766 
13767 	slash = strchr(pgn, '/');
13768 	if (slash == NULL) {
13769 		pn = NULL;
13770 	} else {
13771 		*slash = '\0';
13772 		pn = slash + 1;
13773 	}
13774 
13775 	if (cur_inst != NULL)
13776 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
13777 	else
13778 		ret = scf_service_get_pg(cur_svc, pgn, pg);
13779 	if (ret != SCF_SUCCESS) {
13780 		switch (scf_error()) {
13781 		case SCF_ERROR_NOT_FOUND:
13782 			semerr(emsg_no_such_pg, pgn);
13783 			break;
13784 
13785 		case SCF_ERROR_INVALID_ARGUMENT:
13786 			semerr(emsg_invalid_pg_name, pgn);
13787 			break;
13788 
13789 		default:
13790 			scfdie();
13791 		}
13792 
13793 		scf_pg_destroy(pg);
13794 
13795 		return;
13796 	}
13797 
13798 	if (pn == NULL) {
13799 		/* Try to delete the property group. */
13800 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
13801 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13802 				scfdie();
13803 
13804 			semerr(emsg_permission_denied);
13805 		} else {
13806 			private_refresh();
13807 		}
13808 
13809 		scf_pg_destroy(pg);
13810 		return;
13811 	}
13812 
13813 	e = scf_entry_create(g_hndl);
13814 	tx = scf_transaction_create(g_hndl);
13815 
13816 	do {
13817 		if (scf_pg_update(pg) == -1)
13818 			scfdie();
13819 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
13820 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13821 				scfdie();
13822 
13823 			semerr(emsg_permission_denied);
13824 			break;
13825 		}
13826 
13827 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
13828 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
13829 				semerr(gettext("No such property %s/%s.\n"),
13830 				    pgn, pn);
13831 				break;
13832 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
13833 				semerr(emsg_invalid_prop_name, pn);
13834 				break;
13835 			} else {
13836 				scfdie();
13837 			}
13838 		}
13839 
13840 		ret = scf_transaction_commit(tx);
13841 
13842 		if (ret == 0)
13843 			scf_transaction_reset(tx);
13844 	} while (ret == 0);
13845 
13846 	if (ret < 0) {
13847 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13848 			scfdie();
13849 
13850 		semerr(emsg_permission_denied);
13851 	} else {
13852 		private_refresh();
13853 	}
13854 
13855 	scf_transaction_destroy(tx);
13856 	scf_entry_destroy(e);
13857 	scf_pg_destroy(pg);
13858 }
13859 
13860 /*
13861  * Property editing.
13862  */
13863 
13864 static int
13865 write_edit_script(FILE *strm)
13866 {
13867 	char *fmribuf;
13868 	ssize_t fmrilen;
13869 
13870 	scf_propertygroup_t *pg;
13871 	scf_property_t *prop;
13872 	scf_value_t *val;
13873 	scf_type_t ty;
13874 	int ret, result = 0;
13875 	scf_iter_t *iter, *piter, *viter;
13876 	char *buf, *tybuf, *pname;
13877 	const char *emsg_write_error;
13878 
13879 
13880 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
13881 
13882 
13883 	/* select fmri */
13884 	if (cur_inst != NULL) {
13885 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
13886 		if (fmrilen < 0)
13887 			scfdie();
13888 		fmribuf = safe_malloc(fmrilen + 1);
13889 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
13890 			scfdie();
13891 	} else {
13892 		assert(cur_svc != NULL);
13893 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
13894 		if (fmrilen < 0)
13895 			scfdie();
13896 		fmribuf = safe_malloc(fmrilen + 1);
13897 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
13898 			scfdie();
13899 	}
13900 
13901 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
13902 		warn(emsg_write_error, strerror(errno));
13903 		free(fmribuf);
13904 		return (-1);
13905 	}
13906 
13907 	free(fmribuf);
13908 
13909 
13910 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
13911 	    (prop = scf_property_create(g_hndl)) == NULL ||
13912 	    (val = scf_value_create(g_hndl)) == NULL ||
13913 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13914 	    (piter = scf_iter_create(g_hndl)) == NULL ||
13915 	    (viter = scf_iter_create(g_hndl)) == NULL)
13916 		scfdie();
13917 
13918 	buf = safe_malloc(max_scf_name_len + 1);
13919 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
13920 	pname = safe_malloc(max_scf_name_len + 1);
13921 
13922 	if (cur_inst != NULL)
13923 		ret = scf_iter_instance_pgs(iter, cur_inst);
13924 	else
13925 		ret = scf_iter_service_pgs(iter, cur_svc);
13926 	if (ret != SCF_SUCCESS)
13927 		scfdie();
13928 
13929 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
13930 		int ret2;
13931 
13932 		/*
13933 		 * # delprop pg
13934 		 * # addpg pg type
13935 		 */
13936 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
13937 			scfdie();
13938 
13939 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
13940 			scfdie();
13941 
13942 		if (fprintf(strm, "# Property group \"%s\"\n"
13943 		    "# delprop %s\n"
13944 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
13945 			warn(emsg_write_error, strerror(errno));
13946 			result = -1;
13947 			goto out;
13948 		}
13949 
13950 		/* # setprop pg/prop = (values) */
13951 
13952 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
13953 			scfdie();
13954 
13955 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
13956 			int first = 1;
13957 			int ret3;
13958 			int multiple;
13959 			int is_str;
13960 			scf_type_t bty;
13961 
13962 			if (scf_property_get_name(prop, pname,
13963 			    max_scf_name_len + 1) < 0)
13964 				scfdie();
13965 
13966 			if (scf_property_type(prop, &ty) != 0)
13967 				scfdie();
13968 
13969 			multiple = prop_has_multiple_values(prop, val);
13970 
13971 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
13972 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
13973 			    < 0) {
13974 				warn(emsg_write_error, strerror(errno));
13975 				result = -1;
13976 				goto out;
13977 			}
13978 
13979 			(void) scf_type_base_type(ty, &bty);
13980 			is_str = (bty == SCF_TYPE_ASTRING);
13981 
13982 			if (scf_iter_property_values(viter, prop) !=
13983 			    SCF_SUCCESS)
13984 				scfdie();
13985 
13986 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
13987 				char *buf;
13988 				ssize_t buflen;
13989 
13990 				buflen = scf_value_get_as_string(val, NULL, 0);
13991 				if (buflen < 0)
13992 					scfdie();
13993 
13994 				buf = safe_malloc(buflen + 1);
13995 
13996 				if (scf_value_get_as_string(val, buf,
13997 				    buflen + 1) < 0)
13998 					scfdie();
13999 
14000 				if (first)
14001 					first = 0;
14002 				else {
14003 					if (putc(' ', strm) != ' ') {
14004 						warn(emsg_write_error,
14005 						    strerror(errno));
14006 						result = -1;
14007 						goto out;
14008 					}
14009 				}
14010 
14011 				if ((is_str && multiple) ||
14012 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
14013 					(void) putc('"', strm);
14014 					(void) quote_and_print(buf, strm, 1);
14015 					(void) putc('"', strm);
14016 
14017 					if (ferror(strm)) {
14018 						warn(emsg_write_error,
14019 						    strerror(errno));
14020 						result = -1;
14021 						goto out;
14022 					}
14023 				} else {
14024 					if (fprintf(strm, "%s", buf) < 0) {
14025 						warn(emsg_write_error,
14026 						    strerror(errno));
14027 						result = -1;
14028 						goto out;
14029 					}
14030 				}
14031 
14032 				free(buf);
14033 			}
14034 			if (ret3 < 0 &&
14035 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
14036 				scfdie();
14037 
14038 			/* Write closing paren if mult-value property */
14039 			if ((multiple && putc(')', strm) == EOF) ||
14040 
14041 			    /* Write final newline */
14042 			    fputc('\n', strm) == EOF) {
14043 				warn(emsg_write_error, strerror(errno));
14044 				result = -1;
14045 				goto out;
14046 			}
14047 		}
14048 		if (ret2 < 0)
14049 			scfdie();
14050 
14051 		if (fputc('\n', strm) == EOF) {
14052 			warn(emsg_write_error, strerror(errno));
14053 			result = -1;
14054 			goto out;
14055 		}
14056 	}
14057 	if (ret < 0)
14058 		scfdie();
14059 
14060 out:
14061 	free(pname);
14062 	free(tybuf);
14063 	free(buf);
14064 	scf_iter_destroy(viter);
14065 	scf_iter_destroy(piter);
14066 	scf_iter_destroy(iter);
14067 	scf_value_destroy(val);
14068 	scf_property_destroy(prop);
14069 	scf_pg_destroy(pg);
14070 
14071 	if (result == 0) {
14072 		if (fflush(strm) != 0) {
14073 			warn(emsg_write_error, strerror(errno));
14074 			return (-1);
14075 		}
14076 	}
14077 
14078 	return (result);
14079 }
14080 
14081 int
14082 lscf_editprop()
14083 {
14084 	char *buf, *editor;
14085 	size_t bufsz;
14086 	int tmpfd;
14087 	char tempname[] = TEMP_FILE_PATTERN;
14088 
14089 	lscf_prep_hndl();
14090 
14091 	if (cur_snap != NULL) {
14092 		semerr(emsg_cant_modify_snapshots);
14093 		return (-1);
14094 	}
14095 
14096 	if (cur_svc == NULL && cur_inst == NULL) {
14097 		semerr(emsg_entity_not_selected);
14098 		return (-1);
14099 	}
14100 
14101 	tmpfd = mkstemp(tempname);
14102 	if (tmpfd == -1) {
14103 		semerr(gettext("Could not create temporary file.\n"));
14104 		return (-1);
14105 	}
14106 
14107 	(void) strcpy(tempfilename, tempname);
14108 
14109 	tempfile = fdopen(tmpfd, "r+");
14110 	if (tempfile == NULL) {
14111 		warn(gettext("Could not create temporary file.\n"));
14112 		if (close(tmpfd) == -1)
14113 			warn(gettext("Could not close temporary file: %s.\n"),
14114 			    strerror(errno));
14115 
14116 		remove_tempfile();
14117 
14118 		return (-1);
14119 	}
14120 
14121 	if (write_edit_script(tempfile) == -1) {
14122 		remove_tempfile();
14123 		return (-1);
14124 	}
14125 
14126 	editor = getenv("EDITOR");
14127 	if (editor == NULL)
14128 		editor = "vi";
14129 
14130 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
14131 	buf = safe_malloc(bufsz);
14132 
14133 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
14134 		uu_die(gettext("Error creating editor command"));
14135 
14136 	if (system(buf) == -1) {
14137 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
14138 		    strerror(errno));
14139 		free(buf);
14140 		remove_tempfile();
14141 		return (-1);
14142 	}
14143 
14144 	free(buf);
14145 
14146 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
14147 
14148 	remove_tempfile();
14149 
14150 	return (0);
14151 }
14152 
14153 static void
14154 add_string(uu_list_t *strlist, const char *str)
14155 {
14156 	string_list_t *elem;
14157 	elem = safe_malloc(sizeof (*elem));
14158 	uu_list_node_init(elem, &elem->node, string_pool);
14159 	elem->str = safe_strdup(str);
14160 	if (uu_list_append(strlist, elem) != 0)
14161 		uu_die(gettext("libuutil error: %s\n"),
14162 		    uu_strerror(uu_error()));
14163 }
14164 
14165 static int
14166 remove_string(uu_list_t *strlist, const char *str)
14167 {
14168 	uu_list_walk_t	*elems;
14169 	string_list_t	*sp;
14170 
14171 	/*
14172 	 * Find the element that needs to be removed.
14173 	 */
14174 	elems = uu_list_walk_start(strlist, UU_DEFAULT);
14175 	while ((sp = uu_list_walk_next(elems)) != NULL) {
14176 		if (strcmp(sp->str, str) == 0)
14177 			break;
14178 	}
14179 	uu_list_walk_end(elems);
14180 
14181 	/*
14182 	 * Returning 1 here as the value was not found, this
14183 	 * might not be an error.  Leave it to the caller to
14184 	 * decide.
14185 	 */
14186 	if (sp == NULL) {
14187 		return (1);
14188 	}
14189 
14190 	uu_list_remove(strlist, sp);
14191 
14192 	free(sp->str);
14193 	free(sp);
14194 
14195 	return (0);
14196 }
14197 
14198 /*
14199  * Get all property values that don't match the given glob pattern,
14200  * if a pattern is specified.
14201  */
14202 static void
14203 get_prop_values(scf_property_t *prop, uu_list_t *values,
14204     const char *pattern)
14205 {
14206 	scf_iter_t *iter;
14207 	scf_value_t *val;
14208 	int ret;
14209 
14210 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14211 	    (val = scf_value_create(g_hndl)) == NULL)
14212 		scfdie();
14213 
14214 	if (scf_iter_property_values(iter, prop) != 0)
14215 		scfdie();
14216 
14217 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
14218 		char *buf;
14219 		ssize_t vlen, szret;
14220 
14221 		vlen = scf_value_get_as_string(val, NULL, 0);
14222 		if (vlen < 0)
14223 			scfdie();
14224 
14225 		buf = safe_malloc(vlen + 1);
14226 
14227 		szret = scf_value_get_as_string(val, buf, vlen + 1);
14228 		if (szret < 0)
14229 			scfdie();
14230 		assert(szret <= vlen);
14231 
14232 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
14233 			add_string(values, buf);
14234 
14235 		free(buf);
14236 	}
14237 
14238 	if (ret == -1)
14239 		scfdie();
14240 
14241 	scf_value_destroy(val);
14242 	scf_iter_destroy(iter);
14243 }
14244 
14245 static int
14246 lscf_setpropvalue(const char *pgname, const char *type,
14247     const char *arg, int isadd, int isnotfoundok)
14248 {
14249 	scf_type_t ty;
14250 	scf_propertygroup_t *pg;
14251 	scf_property_t *prop;
14252 	int ret, result = 0;
14253 	scf_transaction_t *tx;
14254 	scf_transaction_entry_t *e;
14255 	scf_value_t *v;
14256 	string_list_t *sp;
14257 	char *propname;
14258 	uu_list_t *values;
14259 	uu_list_walk_t *walk;
14260 	void *cookie = NULL;
14261 	char *pattern = NULL;
14262 
14263 	lscf_prep_hndl();
14264 
14265 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
14266 		uu_die(gettext("Could not create property list: %s\n"),
14267 		    uu_strerror(uu_error()));
14268 
14269 	if (!isadd)
14270 		pattern = safe_strdup(arg);
14271 
14272 	if ((e = scf_entry_create(g_hndl)) == NULL ||
14273 	    (pg = scf_pg_create(g_hndl)) == NULL ||
14274 	    (prop = scf_property_create(g_hndl)) == NULL ||
14275 	    (tx = scf_transaction_create(g_hndl)) == NULL)
14276 		scfdie();
14277 
14278 	if (cur_snap != NULL) {
14279 		semerr(emsg_cant_modify_snapshots);
14280 		goto fail;
14281 	}
14282 
14283 	if (cur_inst == NULL && cur_svc == NULL) {
14284 		semerr(emsg_entity_not_selected);
14285 		goto fail;
14286 	}
14287 
14288 	propname = strchr(pgname, '/');
14289 	if (propname == NULL) {
14290 		semerr(gettext("Property names must contain a `/'.\n"));
14291 		goto fail;
14292 	}
14293 
14294 	*propname = '\0';
14295 	++propname;
14296 
14297 	if (type != NULL) {
14298 		ty = string_to_type(type);
14299 		if (ty == SCF_TYPE_INVALID) {
14300 			semerr(gettext("Unknown type \"%s\".\n"), type);
14301 			goto fail;
14302 		}
14303 	}
14304 
14305 	if (cur_inst != NULL)
14306 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
14307 	else
14308 		ret = scf_service_get_pg(cur_svc, pgname, pg);
14309 	if (ret != 0) {
14310 		switch (scf_error()) {
14311 		case SCF_ERROR_NOT_FOUND:
14312 			if (isnotfoundok) {
14313 				result = 0;
14314 			} else {
14315 				semerr(emsg_no_such_pg, pgname);
14316 				result = -1;
14317 			}
14318 			goto out;
14319 
14320 		case SCF_ERROR_INVALID_ARGUMENT:
14321 			semerr(emsg_invalid_pg_name, pgname);
14322 			goto fail;
14323 
14324 		default:
14325 			scfdie();
14326 		}
14327 	}
14328 
14329 	do {
14330 		if (scf_pg_update(pg) == -1)
14331 			scfdie();
14332 		if (scf_transaction_start(tx, pg) != 0) {
14333 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14334 				scfdie();
14335 
14336 			semerr(emsg_permission_denied);
14337 			goto fail;
14338 		}
14339 
14340 		ret = scf_pg_get_property(pg, propname, prop);
14341 		if (ret == 0) {
14342 			scf_type_t ptype;
14343 			char *pat = pattern;
14344 
14345 			if (scf_property_type(prop, &ptype) != 0)
14346 				scfdie();
14347 
14348 			if (isadd) {
14349 				if (type != NULL && ptype != ty) {
14350 					semerr(gettext("Property \"%s\" is not "
14351 					    "of type \"%s\".\n"), propname,
14352 					    type);
14353 					goto fail;
14354 				}
14355 
14356 				pat = NULL;
14357 			} else {
14358 				size_t len = strlen(pat);
14359 				if (len > 0 && pat[len - 1] == '\"')
14360 					pat[len - 1] = '\0';
14361 				if (len > 0 && pat[0] == '\"')
14362 					pat++;
14363 			}
14364 
14365 			ty = ptype;
14366 
14367 			get_prop_values(prop, values, pat);
14368 
14369 			if (isadd)
14370 				add_string(values, arg);
14371 
14372 			if (scf_transaction_property_change(tx, e,
14373 			    propname, ty) == -1)
14374 				scfdie();
14375 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
14376 			if (isadd) {
14377 				if (type == NULL) {
14378 					semerr(gettext("Type required "
14379 					    "for new properties.\n"));
14380 					goto fail;
14381 				}
14382 
14383 				add_string(values, arg);
14384 
14385 				if (scf_transaction_property_new(tx, e,
14386 				    propname, ty) == -1)
14387 					scfdie();
14388 			} else if (isnotfoundok) {
14389 				result = 0;
14390 				goto out;
14391 			} else {
14392 				semerr(gettext("No such property %s/%s.\n"),
14393 				    pgname, propname);
14394 				result = -1;
14395 				goto out;
14396 			}
14397 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
14398 			semerr(emsg_invalid_prop_name, propname);
14399 			goto fail;
14400 		} else {
14401 			scfdie();
14402 		}
14403 
14404 		walk = uu_list_walk_start(values, UU_DEFAULT);
14405 		if (walk == NULL)
14406 			uu_die(gettext("Could not walk property list.\n"));
14407 
14408 		for (sp = uu_list_walk_next(walk); sp != NULL;
14409 		    sp = uu_list_walk_next(walk)) {
14410 			v = string_to_value(sp->str, ty, 0);
14411 
14412 			if (v == NULL) {
14413 				scf_entry_destroy_children(e);
14414 				goto fail;
14415 			}
14416 			ret = scf_entry_add_value(e, v);
14417 			assert(ret == 0);
14418 		}
14419 		uu_list_walk_end(walk);
14420 
14421 		result = scf_transaction_commit(tx);
14422 
14423 		scf_transaction_reset(tx);
14424 		scf_entry_destroy_children(e);
14425 	} while (result == 0);
14426 
14427 	if (result < 0) {
14428 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14429 			scfdie();
14430 
14431 		semerr(emsg_permission_denied);
14432 		goto fail;
14433 	}
14434 
14435 	result = 0;
14436 
14437 	private_refresh();
14438 
14439 out:
14440 	scf_transaction_destroy(tx);
14441 	scf_entry_destroy(e);
14442 	scf_pg_destroy(pg);
14443 	scf_property_destroy(prop);
14444 	free(pattern);
14445 
14446 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
14447 		free(sp->str);
14448 		free(sp);
14449 	}
14450 
14451 	uu_list_destroy(values);
14452 
14453 	return (result);
14454 
14455 fail:
14456 	result = -1;
14457 	goto out;
14458 }
14459 
14460 int
14461 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
14462 {
14463 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
14464 }
14465 
14466 int
14467 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
14468 {
14469 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
14470 }
14471 
14472 /*
14473  * Look for a standard start method, first in the instance (if any),
14474  * then the service.
14475  */
14476 static const char *
14477 start_method_name(int *in_instance)
14478 {
14479 	scf_propertygroup_t *pg;
14480 	char **p;
14481 	int ret;
14482 	scf_instance_t *inst = cur_inst;
14483 
14484 	if ((pg = scf_pg_create(g_hndl)) == NULL)
14485 		scfdie();
14486 
14487 again:
14488 	for (p = start_method_names; *p != NULL; p++) {
14489 		if (inst != NULL)
14490 			ret = scf_instance_get_pg(inst, *p, pg);
14491 		else
14492 			ret = scf_service_get_pg(cur_svc, *p, pg);
14493 
14494 		if (ret == 0) {
14495 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
14496 			char *buf = safe_malloc(bufsz);
14497 
14498 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
14499 				free(buf);
14500 				continue;
14501 			}
14502 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
14503 				free(buf);
14504 				continue;
14505 			}
14506 
14507 			free(buf);
14508 			*in_instance = (inst != NULL);
14509 			scf_pg_destroy(pg);
14510 			return (*p);
14511 		}
14512 
14513 		if (scf_error() == SCF_ERROR_NOT_FOUND)
14514 			continue;
14515 
14516 		scfdie();
14517 	}
14518 
14519 	if (inst != NULL) {
14520 		inst = NULL;
14521 		goto again;
14522 	}
14523 
14524 	scf_pg_destroy(pg);
14525 	return (NULL);
14526 }
14527 
14528 static int
14529 addpg(const char *name, const char *type)
14530 {
14531 	scf_propertygroup_t *pg;
14532 	int ret;
14533 
14534 	pg = scf_pg_create(g_hndl);
14535 	if (pg == NULL)
14536 		scfdie();
14537 
14538 	if (cur_inst != NULL)
14539 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
14540 	else
14541 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
14542 
14543 	if (ret != 0) {
14544 		switch (scf_error()) {
14545 		case SCF_ERROR_EXISTS:
14546 			ret = 0;
14547 			break;
14548 
14549 		case SCF_ERROR_PERMISSION_DENIED:
14550 			semerr(emsg_permission_denied);
14551 			break;
14552 
14553 		default:
14554 			scfdie();
14555 		}
14556 	}
14557 
14558 	scf_pg_destroy(pg);
14559 	return (ret);
14560 }
14561 
14562 int
14563 lscf_setenv(uu_list_t *args, int isunset)
14564 {
14565 	int ret = 0;
14566 	size_t i;
14567 	int argc;
14568 	char **argv = NULL;
14569 	string_list_t *slp;
14570 	char *pattern;
14571 	char *prop;
14572 	int do_service = 0;
14573 	int do_instance = 0;
14574 	const char *method = NULL;
14575 	const char *name = NULL;
14576 	const char *value = NULL;
14577 	scf_instance_t *saved_cur_inst = cur_inst;
14578 
14579 	lscf_prep_hndl();
14580 
14581 	argc = uu_list_numnodes(args);
14582 	if (argc < 1)
14583 		goto usage;
14584 
14585 	argv = calloc(argc + 1, sizeof (char *));
14586 	if (argv == NULL)
14587 		uu_die(gettext("Out of memory.\n"));
14588 
14589 	for (slp = uu_list_first(args), i = 0;
14590 	    slp != NULL;
14591 	    slp = uu_list_next(args, slp), ++i)
14592 		argv[i] = slp->str;
14593 
14594 	argv[i] = NULL;
14595 
14596 	opterr = 0;
14597 	optind = 0;
14598 	for (;;) {
14599 		ret = getopt(argc, argv, "sim:");
14600 		if (ret == -1)
14601 			break;
14602 
14603 		switch (ret) {
14604 		case 's':
14605 			do_service = 1;
14606 			cur_inst = NULL;
14607 			break;
14608 
14609 		case 'i':
14610 			do_instance = 1;
14611 			break;
14612 
14613 		case 'm':
14614 			method = optarg;
14615 			break;
14616 
14617 		case '?':
14618 			goto usage;
14619 
14620 		default:
14621 			bad_error("getopt", ret);
14622 		}
14623 	}
14624 
14625 	argc -= optind;
14626 	if ((do_service && do_instance) ||
14627 	    (isunset && argc != 1) ||
14628 	    (!isunset && argc != 2))
14629 		goto usage;
14630 
14631 	name = argv[optind];
14632 	if (!isunset)
14633 		value = argv[optind + 1];
14634 
14635 	if (cur_snap != NULL) {
14636 		semerr(emsg_cant_modify_snapshots);
14637 		ret = -1;
14638 		goto out;
14639 	}
14640 
14641 	if (cur_inst == NULL && cur_svc == NULL) {
14642 		semerr(emsg_entity_not_selected);
14643 		ret = -1;
14644 		goto out;
14645 	}
14646 
14647 	if (do_instance && cur_inst == NULL) {
14648 		semerr(gettext("No instance is selected.\n"));
14649 		ret = -1;
14650 		goto out;
14651 	}
14652 
14653 	if (do_service && cur_svc == NULL) {
14654 		semerr(gettext("No service is selected.\n"));
14655 		ret = -1;
14656 		goto out;
14657 	}
14658 
14659 	if (method == NULL) {
14660 		if (do_instance || do_service) {
14661 			method = "method_context";
14662 			if (!isunset) {
14663 				ret = addpg("method_context",
14664 				    SCF_GROUP_FRAMEWORK);
14665 				if (ret != 0)
14666 					goto out;
14667 			}
14668 		} else {
14669 			int in_instance;
14670 			method = start_method_name(&in_instance);
14671 			if (method == NULL) {
14672 				semerr(gettext(
14673 				    "Couldn't find start method; please "
14674 				    "specify a method with '-m'.\n"));
14675 				ret = -1;
14676 				goto out;
14677 			}
14678 			if (!in_instance)
14679 				cur_inst = NULL;
14680 		}
14681 	} else {
14682 		scf_propertygroup_t *pg;
14683 		size_t bufsz;
14684 		char *buf;
14685 		int ret;
14686 
14687 		if ((pg = scf_pg_create(g_hndl)) == NULL)
14688 			scfdie();
14689 
14690 		if (cur_inst != NULL)
14691 			ret = scf_instance_get_pg(cur_inst, method, pg);
14692 		else
14693 			ret = scf_service_get_pg(cur_svc, method, pg);
14694 
14695 		if (ret != 0) {
14696 			scf_pg_destroy(pg);
14697 			switch (scf_error()) {
14698 			case SCF_ERROR_NOT_FOUND:
14699 				semerr(gettext("Couldn't find the method "
14700 				    "\"%s\".\n"), method);
14701 				goto out;
14702 
14703 			case SCF_ERROR_INVALID_ARGUMENT:
14704 				semerr(gettext("Invalid method name \"%s\".\n"),
14705 				    method);
14706 				goto out;
14707 
14708 			default:
14709 				scfdie();
14710 			}
14711 		}
14712 
14713 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
14714 		buf = safe_malloc(bufsz);
14715 
14716 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
14717 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
14718 			semerr(gettext("Property group \"%s\" is not of type "
14719 			    "\"method\".\n"), method);
14720 			ret = -1;
14721 			free(buf);
14722 			scf_pg_destroy(pg);
14723 			goto out;
14724 		}
14725 
14726 		free(buf);
14727 		scf_pg_destroy(pg);
14728 	}
14729 
14730 	prop = uu_msprintf("%s/environment", method);
14731 	pattern = uu_msprintf("%s=*", name);
14732 
14733 	if (prop == NULL || pattern == NULL)
14734 		uu_die(gettext("Out of memory.\n"));
14735 
14736 	ret = lscf_delpropvalue(prop, pattern, !isunset);
14737 
14738 	if (ret == 0 && !isunset) {
14739 		uu_free(pattern);
14740 		uu_free(prop);
14741 		prop = uu_msprintf("%s/environment", method);
14742 		pattern = uu_msprintf("%s=%s", name, value);
14743 		if (prop == NULL || pattern == NULL)
14744 			uu_die(gettext("Out of memory.\n"));
14745 		ret = lscf_addpropvalue(prop, "astring:", pattern);
14746 	}
14747 	uu_free(pattern);
14748 	uu_free(prop);
14749 
14750 out:
14751 	cur_inst = saved_cur_inst;
14752 
14753 	free(argv);
14754 	return (ret);
14755 usage:
14756 	ret = -2;
14757 	goto out;
14758 }
14759 
14760 /*
14761  * Snapshot commands
14762  */
14763 
14764 void
14765 lscf_listsnap()
14766 {
14767 	scf_snapshot_t *snap;
14768 	scf_iter_t *iter;
14769 	char *nb;
14770 	int r;
14771 
14772 	lscf_prep_hndl();
14773 
14774 	if (cur_inst == NULL) {
14775 		semerr(gettext("Instance not selected.\n"));
14776 		return;
14777 	}
14778 
14779 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14780 	    (iter = scf_iter_create(g_hndl)) == NULL)
14781 		scfdie();
14782 
14783 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
14784 		scfdie();
14785 
14786 	nb = safe_malloc(max_scf_name_len + 1);
14787 
14788 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
14789 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
14790 			scfdie();
14791 
14792 		(void) puts(nb);
14793 	}
14794 	if (r < 0)
14795 		scfdie();
14796 
14797 	free(nb);
14798 	scf_iter_destroy(iter);
14799 	scf_snapshot_destroy(snap);
14800 }
14801 
14802 void
14803 lscf_selectsnap(const char *name)
14804 {
14805 	scf_snapshot_t *snap;
14806 	scf_snaplevel_t *level;
14807 
14808 	lscf_prep_hndl();
14809 
14810 	if (cur_inst == NULL) {
14811 		semerr(gettext("Instance not selected.\n"));
14812 		return;
14813 	}
14814 
14815 	if (cur_snap != NULL) {
14816 		if (name != NULL) {
14817 			char *cur_snap_name;
14818 			boolean_t nochange;
14819 
14820 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
14821 
14822 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
14823 			    max_scf_name_len + 1) < 0)
14824 				scfdie();
14825 
14826 			nochange = strcmp(name, cur_snap_name) == 0;
14827 
14828 			free(cur_snap_name);
14829 
14830 			if (nochange)
14831 				return;
14832 		}
14833 
14834 		unselect_cursnap();
14835 	}
14836 
14837 	if (name == NULL)
14838 		return;
14839 
14840 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
14841 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
14842 		scfdie();
14843 
14844 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
14845 	    SCF_SUCCESS) {
14846 		switch (scf_error()) {
14847 		case SCF_ERROR_INVALID_ARGUMENT:
14848 			semerr(gettext("Invalid name \"%s\".\n"), name);
14849 			break;
14850 
14851 		case SCF_ERROR_NOT_FOUND:
14852 			semerr(gettext("No such snapshot \"%s\".\n"), name);
14853 			break;
14854 
14855 		default:
14856 			scfdie();
14857 		}
14858 
14859 		scf_snaplevel_destroy(level);
14860 		scf_snapshot_destroy(snap);
14861 		return;
14862 	}
14863 
14864 	/* Load the snaplevels into our list. */
14865 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
14866 	if (cur_levels == NULL)
14867 		uu_die(gettext("Could not create list: %s\n"),
14868 		    uu_strerror(uu_error()));
14869 
14870 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
14871 		if (scf_error() != SCF_ERROR_NOT_FOUND)
14872 			scfdie();
14873 
14874 		semerr(gettext("Snapshot has no snaplevels.\n"));
14875 
14876 		scf_snaplevel_destroy(level);
14877 		scf_snapshot_destroy(snap);
14878 		return;
14879 	}
14880 
14881 	cur_snap = snap;
14882 
14883 	for (;;) {
14884 		cur_elt = safe_malloc(sizeof (*cur_elt));
14885 		uu_list_node_init(cur_elt, &cur_elt->list_node,
14886 		    snaplevel_pool);
14887 		cur_elt->sl = level;
14888 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
14889 			uu_die(gettext("libuutil error: %s\n"),
14890 			    uu_strerror(uu_error()));
14891 
14892 		level = scf_snaplevel_create(g_hndl);
14893 		if (level == NULL)
14894 			scfdie();
14895 
14896 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
14897 		    level) != SCF_SUCCESS) {
14898 			if (scf_error() != SCF_ERROR_NOT_FOUND)
14899 				scfdie();
14900 
14901 			scf_snaplevel_destroy(level);
14902 			break;
14903 		}
14904 	}
14905 
14906 	cur_elt = uu_list_last(cur_levels);
14907 	cur_level = cur_elt->sl;
14908 }
14909 
14910 /*
14911  * Copies the properties & values in src to dst.  Assumes src won't change.
14912  * Returns -1 if permission is denied, -2 if another transaction interrupts,
14913  * and 0 on success.
14914  *
14915  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
14916  * property, if it is copied and has type boolean.  (See comment in
14917  * lscf_revert()).
14918  */
14919 static int
14920 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
14921     uint8_t enabled)
14922 {
14923 	scf_transaction_t *tx;
14924 	scf_iter_t *iter, *viter;
14925 	scf_property_t *prop;
14926 	scf_value_t *v;
14927 	char *nbuf;
14928 	int r;
14929 
14930 	tx = scf_transaction_create(g_hndl);
14931 	if (tx == NULL)
14932 		scfdie();
14933 
14934 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
14935 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
14936 			scfdie();
14937 
14938 		scf_transaction_destroy(tx);
14939 
14940 		return (-1);
14941 	}
14942 
14943 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
14944 	    (prop = scf_property_create(g_hndl)) == NULL ||
14945 	    (viter = scf_iter_create(g_hndl)) == NULL)
14946 		scfdie();
14947 
14948 	nbuf = safe_malloc(max_scf_name_len + 1);
14949 
14950 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
14951 		scfdie();
14952 
14953 	for (;;) {
14954 		scf_transaction_entry_t *e;
14955 		scf_type_t ty;
14956 
14957 		r = scf_iter_next_property(iter, prop);
14958 		if (r == -1)
14959 			scfdie();
14960 		if (r == 0)
14961 			break;
14962 
14963 		e = scf_entry_create(g_hndl);
14964 		if (e == NULL)
14965 			scfdie();
14966 
14967 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
14968 			scfdie();
14969 
14970 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
14971 			scfdie();
14972 
14973 		if (scf_transaction_property_new(tx, e, nbuf,
14974 		    ty) != SCF_SUCCESS)
14975 			scfdie();
14976 
14977 		if ((enabled == 0 || enabled == 1) &&
14978 		    strcmp(nbuf, scf_property_enabled) == 0 &&
14979 		    ty == SCF_TYPE_BOOLEAN) {
14980 			v = scf_value_create(g_hndl);
14981 			if (v == NULL)
14982 				scfdie();
14983 
14984 			scf_value_set_boolean(v, enabled);
14985 
14986 			if (scf_entry_add_value(e, v) != 0)
14987 				scfdie();
14988 		} else {
14989 			if (scf_iter_property_values(viter, prop) != 0)
14990 				scfdie();
14991 
14992 			for (;;) {
14993 				v = scf_value_create(g_hndl);
14994 				if (v == NULL)
14995 					scfdie();
14996 
14997 				r = scf_iter_next_value(viter, v);
14998 				if (r == -1)
14999 					scfdie();
15000 				if (r == 0) {
15001 					scf_value_destroy(v);
15002 					break;
15003 				}
15004 
15005 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
15006 					scfdie();
15007 			}
15008 		}
15009 	}
15010 
15011 	free(nbuf);
15012 	scf_iter_destroy(viter);
15013 	scf_property_destroy(prop);
15014 	scf_iter_destroy(iter);
15015 
15016 	r = scf_transaction_commit(tx);
15017 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
15018 		scfdie();
15019 
15020 	scf_transaction_destroy_children(tx);
15021 	scf_transaction_destroy(tx);
15022 
15023 	switch (r) {
15024 	case 1:		return (0);
15025 	case 0:		return (-2);
15026 	case -1:	return (-1);
15027 
15028 	default:
15029 		abort();
15030 	}
15031 
15032 	/* NOTREACHED */
15033 }
15034 
15035 void
15036 lscf_revert(const char *snapname)
15037 {
15038 	scf_snapshot_t *snap, *prev;
15039 	scf_snaplevel_t *level, *nlevel;
15040 	scf_iter_t *iter;
15041 	scf_propertygroup_t *pg, *npg;
15042 	scf_property_t *prop;
15043 	scf_value_t *val;
15044 	char *nbuf, *tbuf;
15045 	uint8_t enabled;
15046 
15047 	lscf_prep_hndl();
15048 
15049 	if (cur_inst == NULL) {
15050 		semerr(gettext("Instance not selected.\n"));
15051 		return;
15052 	}
15053 
15054 	if (snapname != NULL) {
15055 		snap = scf_snapshot_create(g_hndl);
15056 		if (snap == NULL)
15057 			scfdie();
15058 
15059 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
15060 		    SCF_SUCCESS) {
15061 			switch (scf_error()) {
15062 			case SCF_ERROR_INVALID_ARGUMENT:
15063 				semerr(gettext("Invalid snapshot name "
15064 				    "\"%s\".\n"), snapname);
15065 				break;
15066 
15067 			case SCF_ERROR_NOT_FOUND:
15068 				semerr(gettext("No such snapshot.\n"));
15069 				break;
15070 
15071 			default:
15072 				scfdie();
15073 			}
15074 
15075 			scf_snapshot_destroy(snap);
15076 			return;
15077 		}
15078 	} else {
15079 		if (cur_snap != NULL) {
15080 			snap = cur_snap;
15081 		} else {
15082 			semerr(gettext("No snapshot selected.\n"));
15083 			return;
15084 		}
15085 	}
15086 
15087 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
15088 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
15089 	    (iter = scf_iter_create(g_hndl)) == NULL ||
15090 	    (pg = scf_pg_create(g_hndl)) == NULL ||
15091 	    (npg = scf_pg_create(g_hndl)) == NULL ||
15092 	    (prop = scf_property_create(g_hndl)) == NULL ||
15093 	    (val = scf_value_create(g_hndl)) == NULL)
15094 		scfdie();
15095 
15096 	nbuf = safe_malloc(max_scf_name_len + 1);
15097 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
15098 
15099 	/* Take the "previous" snapshot before we blow away the properties. */
15100 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
15101 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
15102 			scfdie();
15103 	} else {
15104 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15105 			scfdie();
15106 
15107 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
15108 			scfdie();
15109 	}
15110 
15111 	/* Save general/enabled, since we're probably going to replace it. */
15112 	enabled = 2;
15113 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
15114 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
15115 	    scf_property_get_value(prop, val) == 0)
15116 		(void) scf_value_get_boolean(val, &enabled);
15117 
15118 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
15119 		if (scf_error() != SCF_ERROR_NOT_FOUND)
15120 			scfdie();
15121 
15122 		goto out;
15123 	}
15124 
15125 	for (;;) {
15126 		boolean_t isinst;
15127 		uint32_t flags;
15128 		int r;
15129 
15130 		/* Clear the properties from the corresponding entity. */
15131 		isinst = snaplevel_is_instance(level);
15132 
15133 		if (!isinst)
15134 			r = scf_iter_service_pgs(iter, cur_svc);
15135 		else
15136 			r = scf_iter_instance_pgs(iter, cur_inst);
15137 		if (r != SCF_SUCCESS)
15138 			scfdie();
15139 
15140 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15141 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15142 				scfdie();
15143 
15144 			/* Skip nonpersistent pgs. */
15145 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
15146 				continue;
15147 
15148 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
15149 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15150 					scfdie();
15151 
15152 				semerr(emsg_permission_denied);
15153 				goto out;
15154 			}
15155 		}
15156 		if (r == -1)
15157 			scfdie();
15158 
15159 		/* Copy the properties to the corresponding entity. */
15160 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
15161 			scfdie();
15162 
15163 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
15164 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
15165 				scfdie();
15166 
15167 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
15168 			    0)
15169 				scfdie();
15170 
15171 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
15172 				scfdie();
15173 
15174 			if (!isinst)
15175 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
15176 				    flags, npg);
15177 			else
15178 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
15179 				    flags, npg);
15180 			if (r != SCF_SUCCESS) {
15181 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
15182 					scfdie();
15183 
15184 				semerr(emsg_permission_denied);
15185 				goto out;
15186 			}
15187 
15188 			if ((enabled == 0 || enabled == 1) &&
15189 			    strcmp(nbuf, scf_pg_general) == 0)
15190 				r = pg_copy(pg, npg, enabled);
15191 			else
15192 				r = pg_copy(pg, npg, 2);
15193 
15194 			switch (r) {
15195 			case 0:
15196 				break;
15197 
15198 			case -1:
15199 				semerr(emsg_permission_denied);
15200 				goto out;
15201 
15202 			case -2:
15203 				semerr(gettext(
15204 				    "Interrupted by another change.\n"));
15205 				goto out;
15206 
15207 			default:
15208 				abort();
15209 			}
15210 		}
15211 		if (r == -1)
15212 			scfdie();
15213 
15214 		/* Get next level. */
15215 		nlevel = scf_snaplevel_create(g_hndl);
15216 		if (nlevel == NULL)
15217 			scfdie();
15218 
15219 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
15220 		    SCF_SUCCESS) {
15221 			if (scf_error() != SCF_ERROR_NOT_FOUND)
15222 				scfdie();
15223 
15224 			scf_snaplevel_destroy(nlevel);
15225 			break;
15226 		}
15227 
15228 		scf_snaplevel_destroy(level);
15229 		level = nlevel;
15230 	}
15231 
15232 	if (snapname == NULL) {
15233 		lscf_selectsnap(NULL);
15234 		snap = NULL;		/* cur_snap has been destroyed */
15235 	}
15236 
15237 out:
15238 	free(tbuf);
15239 	free(nbuf);
15240 	scf_value_destroy(val);
15241 	scf_property_destroy(prop);
15242 	scf_pg_destroy(npg);
15243 	scf_pg_destroy(pg);
15244 	scf_iter_destroy(iter);
15245 	scf_snaplevel_destroy(level);
15246 	scf_snapshot_destroy(prev);
15247 	if (snap != cur_snap)
15248 		scf_snapshot_destroy(snap);
15249 }
15250 
15251 void
15252 lscf_refresh(void)
15253 {
15254 	ssize_t fmrilen;
15255 	size_t bufsz;
15256 	char *fmribuf;
15257 	int r;
15258 
15259 	lscf_prep_hndl();
15260 
15261 	if (cur_inst == NULL) {
15262 		semerr(gettext("Instance not selected.\n"));
15263 		return;
15264 	}
15265 
15266 	bufsz = max_scf_fmri_len + 1;
15267 	fmribuf = safe_malloc(bufsz);
15268 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
15269 	if (fmrilen < 0) {
15270 		free(fmribuf);
15271 		if (scf_error() != SCF_ERROR_DELETED)
15272 			scfdie();
15273 		scf_instance_destroy(cur_inst);
15274 		cur_inst = NULL;
15275 		warn(emsg_deleted);
15276 		return;
15277 	}
15278 	assert(fmrilen < bufsz);
15279 
15280 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
15281 	switch (r) {
15282 	case 0:
15283 		break;
15284 
15285 	case ECONNABORTED:
15286 		warn(gettext("Could not refresh %s "
15287 		    "(repository connection broken).\n"), fmribuf);
15288 		break;
15289 
15290 	case ECANCELED:
15291 		warn(emsg_deleted);
15292 		break;
15293 
15294 	case EPERM:
15295 		warn(gettext("Could not refresh %s "
15296 		    "(permission denied).\n"), fmribuf);
15297 		break;
15298 
15299 	case ENOSPC:
15300 		warn(gettext("Could not refresh %s "
15301 		    "(repository server out of resources).\n"),
15302 		    fmribuf);
15303 		break;
15304 
15305 	case EACCES:
15306 	default:
15307 		bad_error("refresh_entity", scf_error());
15308 	}
15309 
15310 	free(fmribuf);
15311 }
15312 
15313 /*
15314  * describe [-v] [-t] [pg/prop]
15315  */
15316 int
15317 lscf_describe(uu_list_t *args, int hasargs)
15318 {
15319 	int ret = 0;
15320 	size_t i;
15321 	int argc;
15322 	char **argv = NULL;
15323 	string_list_t *slp;
15324 	int do_verbose = 0;
15325 	int do_templates = 0;
15326 	char *pattern = NULL;
15327 
15328 	lscf_prep_hndl();
15329 
15330 	if (hasargs != 0)  {
15331 		argc = uu_list_numnodes(args);
15332 		if (argc < 1)
15333 			goto usage;
15334 
15335 		argv = calloc(argc + 1, sizeof (char *));
15336 		if (argv == NULL)
15337 			uu_die(gettext("Out of memory.\n"));
15338 
15339 		for (slp = uu_list_first(args), i = 0;
15340 		    slp != NULL;
15341 		    slp = uu_list_next(args, slp), ++i)
15342 			argv[i] = slp->str;
15343 
15344 		argv[i] = NULL;
15345 
15346 		/*
15347 		 * We start optind = 0 because our list of arguments
15348 		 * starts at argv[0]
15349 		 */
15350 		optind = 0;
15351 		opterr = 0;
15352 		for (;;) {
15353 			ret = getopt(argc, argv, "vt");
15354 			if (ret == -1)
15355 				break;
15356 
15357 			switch (ret) {
15358 			case 'v':
15359 				do_verbose = 1;
15360 				break;
15361 
15362 			case 't':
15363 				do_templates = 1;
15364 				break;
15365 
15366 			case '?':
15367 				goto usage;
15368 
15369 			default:
15370 				bad_error("getopt", ret);
15371 			}
15372 		}
15373 
15374 		pattern = argv[optind];
15375 	}
15376 
15377 	if (cur_inst == NULL && cur_svc == NULL) {
15378 		semerr(emsg_entity_not_selected);
15379 		ret = -1;
15380 		goto out;
15381 	}
15382 
15383 	/*
15384 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
15385 	 * output if their last parameter is set to 2.  Less information is
15386 	 * produced if the parameter is set to 1.
15387 	 */
15388 	if (pattern == NULL) {
15389 		if (do_verbose == 1)
15390 			list_entity_tmpl(2);
15391 		else
15392 			list_entity_tmpl(1);
15393 	}
15394 
15395 	if (do_templates == 0) {
15396 		if (do_verbose == 1)
15397 			listprop(pattern, 0, 2);
15398 		else
15399 			listprop(pattern, 0, 1);
15400 	} else {
15401 		if (do_verbose == 1)
15402 			listtmpl(pattern, 2);
15403 		else
15404 			listtmpl(pattern, 1);
15405 	}
15406 
15407 	ret = 0;
15408 out:
15409 	if (argv != NULL)
15410 		free(argv);
15411 	return (ret);
15412 usage:
15413 	ret = -2;
15414 	goto out;
15415 }
15416 
15417 #define	PARAM_ACTIVE	((const char *) "active")
15418 #define	PARAM_INACTIVE	((const char *) "inactive")
15419 #define	PARAM_SMTP_TO	((const char *) "to")
15420 
15421 /*
15422  * tokenize()
15423  * Breaks down the string according to the tokens passed.
15424  * Caller is responsible for freeing array of pointers returned.
15425  * Returns NULL on failure
15426  */
15427 char **
15428 tokenize(char *str, const char *sep)
15429 {
15430 	char *token, *lasts;
15431 	char **buf;
15432 	int n = 0;	/* number of elements */
15433 	int size = 8;	/* size of the array (initial) */
15434 
15435 	buf = safe_malloc(size * sizeof (char *));
15436 
15437 	for (token = strtok_r(str, sep, &lasts); token != NULL;
15438 	    token = strtok_r(NULL, sep, &lasts), ++n) {
15439 		if (n + 1 >= size) {
15440 			size *= 2;
15441 			if ((buf = realloc(buf, size * sizeof (char *))) ==
15442 			    NULL) {
15443 				uu_die(gettext("Out of memory"));
15444 			}
15445 		}
15446 		buf[n] = token;
15447 	}
15448 	/* NULL terminate the pointer array */
15449 	buf[n] = NULL;
15450 
15451 	return (buf);
15452 }
15453 
15454 int32_t
15455 check_tokens(char **p)
15456 {
15457 	int32_t smf = 0;
15458 	int32_t fma = 0;
15459 
15460 	while (*p) {
15461 		int32_t t = string_to_tset(*p);
15462 
15463 		if (t == 0) {
15464 			if (is_fma_token(*p) == 0)
15465 				return (INVALID_TOKENS);
15466 			fma = 1; /* this token is an fma event */
15467 		} else {
15468 			smf |= t;
15469 		}
15470 
15471 		if (smf != 0 && fma == 1)
15472 			return (MIXED_TOKENS);
15473 		++p;
15474 	}
15475 
15476 	if (smf > 0)
15477 		return (smf);
15478 	else if (fma == 1)
15479 		return (FMA_TOKENS);
15480 
15481 	return (INVALID_TOKENS);
15482 }
15483 
15484 static int
15485 get_selection_str(char *fmri, size_t sz)
15486 {
15487 	if (g_hndl == NULL) {
15488 		semerr(emsg_entity_not_selected);
15489 		return (-1);
15490 	} else if (cur_level != NULL) {
15491 		semerr(emsg_invalid_for_snapshot);
15492 		return (-1);
15493 	} else {
15494 		lscf_get_selection_str(fmri, sz);
15495 	}
15496 
15497 	return (0);
15498 }
15499 
15500 void
15501 lscf_delnotify(const char *set, int global)
15502 {
15503 	char *str = strdup(set);
15504 	char **pgs;
15505 	char **p;
15506 	int32_t tset;
15507 	char *fmri = NULL;
15508 
15509 	if (str == NULL)
15510 		uu_die(gettext("Out of memory.\n"));
15511 
15512 	pgs = tokenize(str, ",");
15513 
15514 	if ((tset = check_tokens(pgs)) > 0) {
15515 		size_t sz = max_scf_fmri_len + 1;
15516 
15517 		fmri = safe_malloc(sz);
15518 		if (global) {
15519 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15520 		} else if (get_selection_str(fmri, sz) != 0) {
15521 			goto out;
15522 		}
15523 
15524 		if (smf_notify_del_params(SCF_SVC_TRANSITION_CLASS, fmri,
15525 		    tset) != SCF_SUCCESS) {
15526 			uu_warn(gettext("Failed smf_notify_del_params: %s\n"),
15527 			    scf_strerror(scf_error()));
15528 		}
15529 	} else if (tset == FMA_TOKENS) {
15530 		if (global) {
15531 			semerr(gettext("Can't use option '-g' with FMA event "
15532 			    "definitions\n"));
15533 			goto out;
15534 		}
15535 
15536 		for (p = pgs; *p; ++p) {
15537 			if (smf_notify_del_params(de_tag(*p), NULL, 0) !=
15538 			    SCF_SUCCESS) {
15539 				uu_warn(gettext("Failed for \"%s\": %s\n"), *p,
15540 				    scf_strerror(scf_error()));
15541 				goto out;
15542 			}
15543 		}
15544 	} else if (tset == MIXED_TOKENS) {
15545 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15546 		goto out;
15547 	} else {
15548 		uu_die(gettext("Invalid input.\n"));
15549 	}
15550 
15551 out:
15552 	free(fmri);
15553 	free(pgs);
15554 	free(str);
15555 }
15556 
15557 void
15558 lscf_listnotify(const char *set, int global)
15559 {
15560 	char *str = safe_strdup(set);
15561 	char **pgs;
15562 	char **p;
15563 	int32_t tset;
15564 	nvlist_t *nvl;
15565 	char *fmri = NULL;
15566 
15567 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
15568 		uu_die(gettext("Out of memory.\n"));
15569 
15570 	pgs = tokenize(str, ",");
15571 
15572 	if ((tset = check_tokens(pgs)) > 0) {
15573 		size_t sz = max_scf_fmri_len + 1;
15574 
15575 		fmri = safe_malloc(sz);
15576 		if (global) {
15577 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15578 		} else if (get_selection_str(fmri, sz) != 0) {
15579 			goto out;
15580 		}
15581 
15582 		if (_scf_get_svc_notify_params(fmri, nvl, tset, 1, 1) !=
15583 		    SCF_SUCCESS) {
15584 			if (scf_error() != SCF_ERROR_NOT_FOUND &&
15585 			    scf_error() != SCF_ERROR_DELETED)
15586 				uu_warn(gettext(
15587 				    "Failed listnotify: %s\n"),
15588 				    scf_strerror(scf_error()));
15589 			goto out;
15590 		}
15591 
15592 		listnotify_print(nvl, NULL);
15593 	} else if (tset == FMA_TOKENS) {
15594 		if (global) {
15595 			semerr(gettext("Can't use option '-g' with FMA event "
15596 			    "definitions\n"));
15597 			goto out;
15598 		}
15599 
15600 		for (p = pgs; *p; ++p) {
15601 			if (_scf_get_fma_notify_params(de_tag(*p), nvl, 1) !=
15602 			    SCF_SUCCESS) {
15603 				/*
15604 				 * if the preferences have just been deleted
15605 				 * or does not exist, just skip.
15606 				 */
15607 				if (scf_error() == SCF_ERROR_NOT_FOUND ||
15608 				    scf_error() == SCF_ERROR_DELETED)
15609 					continue;
15610 				uu_warn(gettext(
15611 				    "Failed listnotify: %s\n"),
15612 				    scf_strerror(scf_error()));
15613 				goto out;
15614 			}
15615 			listnotify_print(nvl, re_tag(*p));
15616 		}
15617 	} else if (tset == MIXED_TOKENS) {
15618 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15619 		goto out;
15620 	} else {
15621 		semerr(gettext("Invalid input.\n"));
15622 	}
15623 
15624 out:
15625 	nvlist_free(nvl);
15626 	free(fmri);
15627 	free(pgs);
15628 	free(str);
15629 }
15630 
15631 static char *
15632 strip_quotes_and_blanks(char *s)
15633 {
15634 	char *start = s;
15635 	char *end = strrchr(s, '\"');
15636 
15637 	if (s[0] == '\"' && end != NULL && *(end + 1) == '\0') {
15638 		start = s + 1;
15639 		while (isblank(*start))
15640 			start++;
15641 		while (isblank(*(end - 1)) && end > start) {
15642 			end--;
15643 		}
15644 		*end = '\0';
15645 	}
15646 
15647 	return (start);
15648 }
15649 
15650 static int
15651 set_active(nvlist_t *mech, const char *hier_part)
15652 {
15653 	boolean_t b;
15654 
15655 	if (*hier_part == '\0' || strcmp(hier_part, PARAM_ACTIVE) == 0) {
15656 		b = B_TRUE;
15657 	} else if (strcmp(hier_part, PARAM_INACTIVE) == 0) {
15658 		b = B_FALSE;
15659 	} else {
15660 		return (-1);
15661 	}
15662 
15663 	if (nvlist_add_boolean_value(mech, PARAM_ACTIVE, b) != 0)
15664 		uu_die(gettext("Out of memory.\n"));
15665 
15666 	return (0);
15667 }
15668 
15669 static int
15670 add_snmp_params(nvlist_t *mech, char *hier_part)
15671 {
15672 	return (set_active(mech, hier_part));
15673 }
15674 
15675 static int
15676 add_syslog_params(nvlist_t *mech, char *hier_part)
15677 {
15678 	return (set_active(mech, hier_part));
15679 }
15680 
15681 /*
15682  * add_mailto_paramas()
15683  * parse the hier_part of mailto URI
15684  * mailto:<addr>[?<header1>=<value1>[&<header2>=<value2>]]
15685  * or mailto:{[active]|inactive}
15686  */
15687 static int
15688 add_mailto_params(nvlist_t *mech, char *hier_part)
15689 {
15690 	const char *tok = "?&";
15691 	char *p;
15692 	char *lasts;
15693 	char *param;
15694 	char *val;
15695 
15696 	/*
15697 	 * If the notification parametes are in the form of
15698 	 *
15699 	 *   malito:{[active]|inactive}
15700 	 *
15701 	 * we set the property accordingly and return.
15702 	 * Otherwise, we make the notification type active and
15703 	 * process the hier_part.
15704 	 */
15705 	if (set_active(mech, hier_part) == 0)
15706 		return (0);
15707 	else if (set_active(mech, PARAM_ACTIVE) != 0)
15708 		return (-1);
15709 
15710 	if ((p = strtok_r(hier_part, tok, &lasts)) == NULL) {
15711 		/*
15712 		 * sanity check: we only get here if hier_part = "", but
15713 		 * that's handled by set_active
15714 		 */
15715 		uu_die("strtok_r");
15716 	}
15717 
15718 	if (nvlist_add_string(mech, PARAM_SMTP_TO, p) != 0)
15719 		uu_die(gettext("Out of memory.\n"));
15720 
15721 	while ((p = strtok_r(NULL, tok, &lasts)) != NULL)
15722 		if ((param = strtok_r(p, "=", &val)) != NULL)
15723 			if (nvlist_add_string(mech, param, val) != 0)
15724 				uu_die(gettext("Out of memory.\n"));
15725 
15726 	return (0);
15727 }
15728 
15729 static int
15730 uri_split(char *uri, char **scheme, char **hier_part)
15731 {
15732 	int r = -1;
15733 
15734 	if ((*scheme = strtok_r(uri, ":", hier_part)) == NULL ||
15735 	    *hier_part == NULL) {
15736 		semerr(gettext("'%s' is not an URI\n"), uri);
15737 		return (r);
15738 	}
15739 
15740 	if ((r = check_uri_scheme(*scheme)) < 0) {
15741 		semerr(gettext("Unkown URI scheme: %s\n"), *scheme);
15742 		return (r);
15743 	}
15744 
15745 	return (r);
15746 }
15747 
15748 static int
15749 process_uri(nvlist_t *params, char *uri)
15750 {
15751 	char *scheme;
15752 	char *hier_part;
15753 	nvlist_t *mech;
15754 	int index;
15755 	int r;
15756 
15757 	if ((index = uri_split(uri, &scheme, &hier_part)) < 0)
15758 		return (-1);
15759 
15760 	if (nvlist_alloc(&mech, NV_UNIQUE_NAME, 0) != 0)
15761 		uu_die(gettext("Out of memory.\n"));
15762 
15763 	switch (index) {
15764 	case 0:
15765 		/* error messages displayed by called function */
15766 		r = add_mailto_params(mech, hier_part);
15767 		break;
15768 
15769 	case 1:
15770 		if ((r = add_snmp_params(mech, hier_part)) != 0)
15771 			semerr(gettext("Not valid parameters: '%s'\n"),
15772 			    hier_part);
15773 		break;
15774 
15775 	case 2:
15776 		if ((r = add_syslog_params(mech, hier_part)) != 0)
15777 			semerr(gettext("Not valid parameters: '%s'\n"),
15778 			    hier_part);
15779 		break;
15780 
15781 	default:
15782 		r = -1;
15783 	}
15784 
15785 	if (r == 0 && nvlist_add_nvlist(params, uri_scheme[index].protocol,
15786 	    mech) != 0)
15787 		uu_die(gettext("Out of memory.\n"));
15788 
15789 	nvlist_free(mech);
15790 	return (r);
15791 }
15792 
15793 static int
15794 set_params(nvlist_t *params, char **p)
15795 {
15796 	char *uri;
15797 
15798 	if (p == NULL)
15799 		/* sanity check */
15800 		uu_die("set_params");
15801 
15802 	while (*p) {
15803 		uri = strip_quotes_and_blanks(*p);
15804 		if (process_uri(params, uri) != 0)
15805 			return (-1);
15806 
15807 		++p;
15808 	}
15809 
15810 	return (0);
15811 }
15812 
15813 static int
15814 setnotify(const char *e, char **p, int global)
15815 {
15816 	char *str = safe_strdup(e);
15817 	char **events;
15818 	int32_t tset;
15819 	int r = -1;
15820 	nvlist_t *nvl, *params;
15821 	char *fmri = NULL;
15822 
15823 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0 ||
15824 	    nvlist_alloc(&params, NV_UNIQUE_NAME, 0) != 0 ||
15825 	    nvlist_add_uint32(nvl, SCF_NOTIFY_NAME_VERSION,
15826 	    SCF_NOTIFY_PARAMS_VERSION) != 0)
15827 		uu_die(gettext("Out of memory.\n"));
15828 
15829 	events = tokenize(str, ",");
15830 
15831 	if ((tset = check_tokens(events)) > 0) {
15832 		/* SMF state transitions parameters */
15833 		size_t sz = max_scf_fmri_len + 1;
15834 
15835 		fmri = safe_malloc(sz);
15836 		if (global) {
15837 			(void) strlcpy(fmri, SCF_INSTANCE_GLOBAL, sz);
15838 		} else if (get_selection_str(fmri, sz) != 0) {
15839 			goto out;
15840 		}
15841 
15842 		if (nvlist_add_string(nvl, SCF_NOTIFY_NAME_FMRI, fmri) != 0 ||
15843 		    nvlist_add_int32(nvl, SCF_NOTIFY_NAME_TSET, tset) != 0)
15844 			uu_die(gettext("Out of memory.\n"));
15845 
15846 		if ((r = set_params(params, p)) == 0) {
15847 			if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS,
15848 			    params) != 0)
15849 				uu_die(gettext("Out of memory.\n"));
15850 
15851 			if (smf_notify_set_params(SCF_SVC_TRANSITION_CLASS,
15852 			    nvl) != SCF_SUCCESS) {
15853 				r = -1;
15854 				uu_warn(gettext(
15855 				    "Failed smf_notify_set_params(3SCF): %s\n"),
15856 				    scf_strerror(scf_error()));
15857 			}
15858 		}
15859 	} else if (tset == FMA_TOKENS) {
15860 		/* FMA event parameters */
15861 		if (global) {
15862 			semerr(gettext("Can't use option '-g' with FMA event "
15863 			    "definitions\n"));
15864 			goto out;
15865 		}
15866 
15867 		if ((r = set_params(params, p)) != 0)
15868 			goto out;
15869 
15870 		if (nvlist_add_nvlist(nvl, SCF_NOTIFY_PARAMS, params) != 0)
15871 			uu_die(gettext("Out of memory.\n"));
15872 
15873 		while (*events) {
15874 			if (smf_notify_set_params(de_tag(*events), nvl) !=
15875 			    SCF_SUCCESS)
15876 				uu_warn(gettext(
15877 				    "Failed smf_notify_set_params(3SCF) for "
15878 				    "event %s: %s\n"), *events,
15879 				    scf_strerror(scf_error()));
15880 			events++;
15881 		}
15882 	} else if (tset == MIXED_TOKENS) {
15883 		semerr(gettext("Can't mix SMF and FMA event definitions\n"));
15884 	} else {
15885 		/* Sanity check */
15886 		uu_die(gettext("Invalid input.\n"));
15887 	}
15888 
15889 out:
15890 	nvlist_free(nvl);
15891 	nvlist_free(params);
15892 	free(fmri);
15893 	free(str);
15894 
15895 	return (r);
15896 }
15897 
15898 int
15899 lscf_setnotify(uu_list_t *args)
15900 {
15901 	int argc;
15902 	char **argv = NULL;
15903 	string_list_t *slp;
15904 	int global;
15905 	char *events;
15906 	char **p;
15907 	int i;
15908 	int ret;
15909 
15910 	if ((argc = uu_list_numnodes(args)) < 2)
15911 		goto usage;
15912 
15913 	argv = calloc(argc + 1, sizeof (char *));
15914 	if (argv == NULL)
15915 		uu_die(gettext("Out of memory.\n"));
15916 
15917 	for (slp = uu_list_first(args), i = 0;
15918 	    slp != NULL;
15919 	    slp = uu_list_next(args, slp), ++i)
15920 		argv[i] = slp->str;
15921 
15922 	argv[i] = NULL;
15923 
15924 	if (strcmp(argv[0], "-g") == 0) {
15925 		global = 1;
15926 		events = argv[1];
15927 		p = argv + 2;
15928 	} else {
15929 		global = 0;
15930 		events = argv[0];
15931 		p = argv + 1;
15932 	}
15933 
15934 	ret = setnotify(events, p, global);
15935 
15936 out:
15937 	free(argv);
15938 	return (ret);
15939 
15940 usage:
15941 	ret = -2;
15942 	goto out;
15943 }
15944 
15945 /*
15946  * Creates a list of instance name strings associated with a service. If
15947  * wohandcrafted flag is set, get only instances that have a last-import
15948  * snapshot, instances that were imported via svccfg.
15949  */
15950 static uu_list_t *
15951 create_instance_list(scf_service_t *svc, int wohandcrafted)
15952 {
15953 	scf_snapshot_t  *snap = NULL;
15954 	scf_instance_t  *inst;
15955 	scf_iter_t	*inst_iter;
15956 	uu_list_t	*instances;
15957 	char		*instname;
15958 	int		r;
15959 
15960 	inst_iter = scf_iter_create(g_hndl);
15961 	inst = scf_instance_create(g_hndl);
15962 	if (inst_iter == NULL || inst == NULL) {
15963 		uu_warn(gettext("Could not create instance or iterator\n"));
15964 		scfdie();
15965 	}
15966 
15967 	if ((instances = uu_list_create(string_pool, NULL, 0)) == NULL)
15968 		return (instances);
15969 
15970 	if (scf_iter_service_instances(inst_iter, svc) != 0) {
15971 		switch (scf_error()) {
15972 		case SCF_ERROR_CONNECTION_BROKEN:
15973 		case SCF_ERROR_DELETED:
15974 			uu_list_destroy(instances);
15975 			instances = NULL;
15976 			goto out;
15977 
15978 		case SCF_ERROR_HANDLE_MISMATCH:
15979 		case SCF_ERROR_NOT_BOUND:
15980 		case SCF_ERROR_NOT_SET:
15981 		default:
15982 			bad_error("scf_iter_service_instances", scf_error());
15983 		}
15984 	}
15985 
15986 	instname = safe_malloc(max_scf_name_len + 1);
15987 	while ((r = scf_iter_next_instance(inst_iter, inst)) != 0) {
15988 		if (r == -1) {
15989 			(void) uu_warn(gettext("Unable to iterate through "
15990 			    "instances to create instance list : %s\n"),
15991 			    scf_strerror(scf_error()));
15992 
15993 			uu_list_destroy(instances);
15994 			instances = NULL;
15995 			goto out;
15996 		}
15997 
15998 		/*
15999 		 * If the instance does not have a last-import snapshot
16000 		 * then do not add it to the list as it is a hand-crafted
16001 		 * instance that should not be managed.
16002 		 */
16003 		if (wohandcrafted) {
16004 			if (snap == NULL &&
16005 			    (snap = scf_snapshot_create(g_hndl)) == NULL) {
16006 				uu_warn(gettext("Unable to create snapshot "
16007 				    "entity\n"));
16008 				scfdie();
16009 			}
16010 
16011 			if (scf_instance_get_snapshot(inst,
16012 			    snap_lastimport, snap) != 0) {
16013 				switch (scf_error()) {
16014 				case SCF_ERROR_NOT_FOUND :
16015 				case SCF_ERROR_DELETED:
16016 					continue;
16017 
16018 				case SCF_ERROR_CONNECTION_BROKEN:
16019 					uu_list_destroy(instances);
16020 					instances = NULL;
16021 					goto out;
16022 
16023 				case SCF_ERROR_HANDLE_MISMATCH:
16024 				case SCF_ERROR_NOT_BOUND:
16025 				case SCF_ERROR_NOT_SET:
16026 				default:
16027 					bad_error("scf_iter_service_instances",
16028 					    scf_error());
16029 				}
16030 			}
16031 		}
16032 
16033 		if (scf_instance_get_name(inst, instname,
16034 		    max_scf_name_len + 1) < 0) {
16035 			switch (scf_error()) {
16036 			case SCF_ERROR_NOT_FOUND :
16037 				continue;
16038 
16039 			case SCF_ERROR_CONNECTION_BROKEN:
16040 			case SCF_ERROR_DELETED:
16041 				uu_list_destroy(instances);
16042 				instances = NULL;
16043 				goto out;
16044 
16045 			case SCF_ERROR_HANDLE_MISMATCH:
16046 			case SCF_ERROR_NOT_BOUND:
16047 			case SCF_ERROR_NOT_SET:
16048 			default:
16049 				bad_error("scf_iter_service_instances",
16050 				    scf_error());
16051 			}
16052 		}
16053 
16054 		add_string(instances, instname);
16055 	}
16056 
16057 out:
16058 	if (snap)
16059 		scf_snapshot_destroy(snap);
16060 
16061 	scf_instance_destroy(inst);
16062 	scf_iter_destroy(inst_iter);
16063 	free(instname);
16064 	return (instances);
16065 }
16066 
16067 /*
16068  * disable an instance but wait for the instance to
16069  * move out of the running state.
16070  *
16071  * Returns 0 : if the instance did not disable
16072  * Returns non-zero : if the instance disabled.
16073  *
16074  */
16075 static int
16076 disable_instance(scf_instance_t *instance)
16077 {
16078 	char	*fmribuf;
16079 	int	enabled = 10000;
16080 
16081 	if (inst_is_running(instance)) {
16082 		fmribuf = safe_malloc(max_scf_name_len + 1);
16083 		if (scf_instance_to_fmri(instance, fmribuf,
16084 		    max_scf_name_len + 1) < 0) {
16085 			free(fmribuf);
16086 			return (0);
16087 		}
16088 
16089 		/*
16090 		 * If the instance cannot be disabled then return
16091 		 * failure to disable and let the caller decide
16092 		 * if that is of importance.
16093 		 */
16094 		if (smf_disable_instance(fmribuf, 0) != 0) {
16095 			free(fmribuf);
16096 			return (0);
16097 		}
16098 
16099 		while (enabled) {
16100 			if (!inst_is_running(instance))
16101 				break;
16102 
16103 			(void) poll(NULL, 0, 5);
16104 			enabled = enabled - 5;
16105 		}
16106 
16107 		free(fmribuf);
16108 	}
16109 
16110 	return (enabled);
16111 }
16112 
16113 /*
16114  * Function to compare two service_manifest structures.
16115  */
16116 /* ARGSUSED2 */
16117 static int
16118 service_manifest_compare(const void *left, const void *right, void *unused)
16119 {
16120 	service_manifest_t *l = (service_manifest_t *)left;
16121 	service_manifest_t *r = (service_manifest_t *)right;
16122 	int rc;
16123 
16124 	rc = strcmp(l->servicename, r->servicename);
16125 
16126 	return (rc);
16127 }
16128 
16129 /*
16130  * Look for the provided service in the service to manifest
16131  * tree.  If the service exists, and a manifest was provided
16132  * then add the manifest to that service.  If the service
16133  * does not exist, then add the service and manifest to the
16134  * list.
16135  *
16136  * If the manifest is NULL, return the element if found.  If
16137  * the service is not found return NULL.
16138  */
16139 service_manifest_t *
16140 find_add_svc_mfst(const char *svnbuf, const char *mfst)
16141 {
16142 	service_manifest_t	elem;
16143 	service_manifest_t	*fnelem;
16144 	uu_avl_index_t		marker;
16145 
16146 	elem.servicename = svnbuf;
16147 	fnelem = uu_avl_find(service_manifest_tree, &elem, NULL, &marker);
16148 
16149 	if (mfst) {
16150 		if (fnelem) {
16151 			add_string(fnelem->mfstlist, strdup(mfst));
16152 		} else {
16153 			fnelem = safe_malloc(sizeof (*fnelem));
16154 			fnelem->servicename = safe_strdup(svnbuf);
16155 			if ((fnelem->mfstlist =
16156 			    uu_list_create(string_pool, NULL, 0)) == NULL)
16157 				uu_die(gettext("Could not create property "
16158 				    "list: %s\n"), uu_strerror(uu_error()));
16159 
16160 			add_string(fnelem->mfstlist, safe_strdup(mfst));
16161 
16162 			uu_avl_insert(service_manifest_tree, fnelem, marker);
16163 		}
16164 	}
16165 
16166 	return (fnelem);
16167 }
16168 
16169 /*
16170  * Create the service to manifest avl tree.
16171  *
16172  * Walk each of the manifests currently installed in the supported
16173  * directories, /lib/svc/manifests and /var/svc/manifests.  For
16174  * each of the manifests, inventory the services and add them to
16175  * the tree.
16176  *
16177  * Code that calls this function should make sure fileystem/minimal is online,
16178  * /var is available, since this function walks the /var/svc/manifest directory.
16179  */
16180 static void
16181 create_manifest_tree(void)
16182 {
16183 	manifest_info_t **entry;
16184 	manifest_info_t **manifests;
16185 	uu_list_walk_t	*svcs;
16186 	bundle_t	*b;
16187 	entity_t	*mfsvc;
16188 	char		*dirs[] = {LIBSVC_DIR, VARSVC_DIR, NULL};
16189 	int		c, status;
16190 
16191 	if (service_manifest_pool)
16192 		return;
16193 
16194 	/*
16195 	 * Create the list pool for the service manifest list
16196 	 */
16197 	service_manifest_pool = uu_avl_pool_create("service_manifest",
16198 	    sizeof (service_manifest_t),
16199 	    offsetof(service_manifest_t, svcmfst_node),
16200 	    service_manifest_compare, UU_DEFAULT);
16201 	if (service_manifest_pool == NULL)
16202 		uu_die(gettext("service_manifest pool creation failed: %s\n"),
16203 		    uu_strerror(uu_error()));
16204 
16205 	/*
16206 	 * Create the list
16207 	 */
16208 	service_manifest_tree = uu_avl_create(service_manifest_pool, NULL,
16209 	    UU_DEFAULT);
16210 	if (service_manifest_tree == NULL)
16211 		uu_die(gettext("service_manifest tree creation failed: %s\n"),
16212 		    uu_strerror(uu_error()));
16213 
16214 	/*
16215 	 * Walk the manifests adding the service(s) from each manifest.
16216 	 *
16217 	 * If a service already exists add the manifest to the manifest
16218 	 * list for that service.  This covers the case of a service that
16219 	 * is supported by multiple manifest files.
16220 	 */
16221 	for (c = 0; dirs[c]; c++) {
16222 		status = find_manifests(g_hndl, dirs[c], &manifests, CHECKEXT);
16223 		if (status < 0) {
16224 			uu_warn(gettext("file tree walk of %s encountered "
16225 			    "error %s\n"), dirs[c], strerror(errno));
16226 
16227 			uu_avl_destroy(service_manifest_tree);
16228 			service_manifest_tree = NULL;
16229 			return;
16230 		}
16231 
16232 		/*
16233 		 * If a manifest that was in the list is not found
16234 		 * then skip and go to the next manifest file.
16235 		 */
16236 		if (manifests != NULL) {
16237 			for (entry = manifests; *entry != NULL; entry++) {
16238 				b = internal_bundle_new();
16239 				if (lxml_get_bundle_file(b, (*entry)->mi_path,
16240 				    SVCCFG_OP_IMPORT) != 0) {
16241 					internal_bundle_free(b);
16242 					continue;
16243 				}
16244 
16245 				svcs = uu_list_walk_start(b->sc_bundle_services,
16246 				    0);
16247 				if (svcs == NULL) {
16248 					internal_bundle_free(b);
16249 					continue;
16250 				}
16251 
16252 				while ((mfsvc = uu_list_walk_next(svcs)) !=
16253 				    NULL) {
16254 					/* Add manifest to service */
16255 					(void) find_add_svc_mfst(mfsvc->sc_name,
16256 					    (*entry)->mi_path);
16257 				}
16258 
16259 				uu_list_walk_end(svcs);
16260 				internal_bundle_free(b);
16261 			}
16262 
16263 			free_manifest_array(manifests);
16264 		}
16265 	}
16266 }
16267 
16268 /*
16269  * Check the manifest history file to see
16270  * if the service was ever installed from
16271  * one of the supported directories.
16272  *
16273  * Return Values :
16274  * 	-1 - if there's error reading manifest history file
16275  *	 1 - if the service is not found
16276  *	 0 - if the service is found
16277  */
16278 static int
16279 check_mfst_history(const char *svcname)
16280 {
16281 	struct stat	st;
16282 	caddr_t		mfsthist_start;
16283 	char		*svnbuf;
16284 	int		fd;
16285 	int		r = 1;
16286 
16287 	fd = open(MFSTHISTFILE, O_RDONLY);
16288 	if (fd == -1) {
16289 		uu_warn(gettext("Unable to open the history file\n"));
16290 		return (-1);
16291 	}
16292 
16293 	if (fstat(fd, &st) == -1) {
16294 		uu_warn(gettext("Unable to stat the history file\n"));
16295 		return (-1);
16296 	}
16297 
16298 	mfsthist_start = mmap(0, st.st_size, PROT_READ,
16299 	    MAP_PRIVATE, fd, 0);
16300 
16301 	(void) close(fd);
16302 	if (mfsthist_start == MAP_FAILED ||
16303 	    *(mfsthist_start + st.st_size) != '\0') {
16304 		(void) munmap(mfsthist_start, st.st_size);
16305 		return (-1);
16306 	}
16307 
16308 	/*
16309 	 * The manifest history file is a space delimited list
16310 	 * of service and instance to manifest linkage.  Adding
16311 	 * a space to the end of the service name so to get only
16312 	 * the service that is being searched for.
16313 	 */
16314 	svnbuf = uu_msprintf("%s ", svcname);
16315 	if (svnbuf == NULL)
16316 		uu_die(gettext("Out of memory"));
16317 
16318 	if (strstr(mfsthist_start, svnbuf) != NULL)
16319 		r = 0;
16320 
16321 	(void) munmap(mfsthist_start, st.st_size);
16322 	uu_free(svnbuf);
16323 	return (r);
16324 }
16325 
16326 /*
16327  * Take down each of the instances in the service
16328  * and remove them, then delete the service.
16329  */
16330 static void
16331 teardown_service(scf_service_t *svc, const char *svnbuf)
16332 {
16333 	scf_instance_t	*instance;
16334 	scf_iter_t	*iter;
16335 	int		r;
16336 
16337 	safe_printf(gettext("Delete service %s as there are no "
16338 	    "supporting manifests\n"), svnbuf);
16339 
16340 	instance = scf_instance_create(g_hndl);
16341 	iter = scf_iter_create(g_hndl);
16342 	if (iter == NULL || instance == NULL) {
16343 		uu_warn(gettext("Unable to create supporting entities to "
16344 		    "teardown the service\n"));
16345 		uu_warn(gettext("scf error is : %s\n"),
16346 		    scf_strerror(scf_error()));
16347 		scfdie();
16348 	}
16349 
16350 	if (scf_iter_service_instances(iter, svc) != 0) {
16351 		switch (scf_error()) {
16352 		case SCF_ERROR_CONNECTION_BROKEN:
16353 		case SCF_ERROR_DELETED:
16354 			goto out;
16355 
16356 		case SCF_ERROR_HANDLE_MISMATCH:
16357 		case SCF_ERROR_NOT_BOUND:
16358 		case SCF_ERROR_NOT_SET:
16359 		default:
16360 			bad_error("scf_iter_service_instances",
16361 			    scf_error());
16362 		}
16363 	}
16364 
16365 	while ((r = scf_iter_next_instance(iter, instance)) != 0) {
16366 		if (r == -1) {
16367 			uu_warn(gettext("Error - %s\n"),
16368 			    scf_strerror(scf_error()));
16369 			goto out;
16370 		}
16371 
16372 		(void) disable_instance(instance);
16373 	}
16374 
16375 	/*
16376 	 * Delete the service... forcing the deletion in case
16377 	 * any of the instances did not disable.
16378 	 */
16379 	(void) lscf_service_delete(svc, 1);
16380 out:
16381 	scf_instance_destroy(instance);
16382 	scf_iter_destroy(iter);
16383 }
16384 
16385 /*
16386  * Get the list of instances supported by the manifest
16387  * file.
16388  *
16389  * Return 0 if there are no instances.
16390  *
16391  * Return -1 if there are errors attempting to collect instances.
16392  *
16393  * Return the count of instances found if there are no errors.
16394  *
16395  */
16396 static int
16397 check_instance_support(char *mfstfile, const char *svcname,
16398     uu_list_t *instances)
16399 {
16400 	uu_list_walk_t	*svcs, *insts;
16401 	uu_list_t	*ilist;
16402 	bundle_t	*b;
16403 	entity_t	*mfsvc, *mfinst;
16404 	const char	*svcn;
16405 	int		rminstcnt = 0;
16406 
16407 
16408 	b = internal_bundle_new();
16409 
16410 	if (lxml_get_bundle_file(b, mfstfile, SVCCFG_OP_IMPORT) != 0) {
16411 		/*
16412 		 * Unable to process the manifest file for
16413 		 * instance support, so just return as
16414 		 * don't want to remove instances that could
16415 		 * not be accounted for that might exist here.
16416 		 */
16417 		internal_bundle_free(b);
16418 		return (0);
16419 	}
16420 
16421 	svcs = uu_list_walk_start(b->sc_bundle_services, 0);
16422 	if (svcs == NULL) {
16423 		internal_bundle_free(b);
16424 		return (0);
16425 	}
16426 
16427 	svcn = svcname + (sizeof (SCF_FMRI_SVC_PREFIX) - 1) +
16428 	    (sizeof (SCF_FMRI_SERVICE_PREFIX) - 1);
16429 
16430 	while ((mfsvc = uu_list_walk_next(svcs)) != NULL) {
16431 		if (strcmp(mfsvc->sc_name, svcn) == 0)
16432 			break;
16433 	}
16434 	uu_list_walk_end(svcs);
16435 
16436 	if (mfsvc == NULL) {
16437 		internal_bundle_free(b);
16438 		return (-1);
16439 	}
16440 
16441 	ilist = mfsvc->sc_u.sc_service.sc_service_instances;
16442 	if ((insts = uu_list_walk_start(ilist, 0)) == NULL) {
16443 		internal_bundle_free(b);
16444 		return (0);
16445 	}
16446 
16447 	while ((mfinst = uu_list_walk_next(insts)) != NULL) {
16448 		/*
16449 		 * Remove the instance from the instances list.
16450 		 * The unaccounted for instances will be removed
16451 		 * from the service once all manifests are
16452 		 * processed.
16453 		 */
16454 		(void) remove_string(instances,
16455 		    mfinst->sc_name);
16456 		rminstcnt++;
16457 	}
16458 
16459 	uu_list_walk_end(insts);
16460 	internal_bundle_free(b);
16461 
16462 	return (rminstcnt);
16463 }
16464 
16465 /*
16466  * For the given service, set its SCF_PG_MANIFESTFILES/SUPPORT property to
16467  * 'false' to indicate there's no manifest file(s) found for the service.
16468  */
16469 static void
16470 svc_add_no_support(scf_service_t *svc)
16471 {
16472 	char	*pname;
16473 
16474 	/* Add no support */
16475 	cur_svc = svc;
16476 	if (addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK))
16477 		return;
16478 
16479 	pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES, SUPPORTPROP);
16480 	if (pname == NULL)
16481 		uu_die(gettext("Out of memory.\n"));
16482 
16483 	(void) lscf_addpropvalue(pname, "boolean:", "0");
16484 
16485 	uu_free(pname);
16486 	cur_svc = NULL;
16487 }
16488 
16489 /*
16490  * This function handles all upgrade scenarios for a service that doesn't have
16491  * SCF_PG_MANIFESTFILES pg. The function creates and populates
16492  * SCF_PG_MANIFESTFILES pg for the given service to keep track of service to
16493  * manifest(s) mapping. Manifests under supported directories are inventoried
16494  * and a property is added for each file that delivers configuration to the
16495  * service.  A service that has no corresponding manifest files (deleted) are
16496  * removed from repository.
16497  *
16498  * Unsupported services:
16499  *
16500  * A service is considered unsupported if there is no corresponding manifest
16501  * in the supported directories for that service and the service isn't in the
16502  * history file list.  The history file, MFSTHISTFILE, contains a list of all
16503  * services and instances that were delivered by Solaris before the introduction
16504  * of the SCF_PG_MANIFESTFILES property group.  The history file also contains
16505  * the path to the manifest file that defined the service or instance.
16506  *
16507  * Another type of unsupported services is 'handcrafted' services,
16508  * programmatically created services or services created by dependent entries
16509  * in other manifests. A handcrafted service is identified by its lack of any
16510  * instance containing last-import snapshot which is created during svccfg
16511  * import.
16512  *
16513  * This function sets a flag for unsupported services by setting services'
16514  * SCF_PG_MANIFESTFILES/support property to false.
16515  */
16516 static void
16517 upgrade_svc_mfst_connection(scf_service_t *svc, const char *svcname)
16518 {
16519 	service_manifest_t	*elem;
16520 	uu_list_walk_t		*mfwalk;
16521 	string_list_t		*mfile;
16522 	uu_list_t		*instances;
16523 	const char		*sname;
16524 	char			*pname;
16525 	int			r;
16526 
16527 	/*
16528 	 * Since there's no guarantee manifests under /var are available during
16529 	 * early import, don't perform any upgrade during early import.
16530 	 */
16531 	if (IGNORE_VAR)
16532 		return;
16533 
16534 	if (service_manifest_tree == NULL) {
16535 		create_manifest_tree();
16536 	}
16537 
16538 	/*
16539 	 * Find service's supporting manifest(s) after
16540 	 * stripping off the svc:/ prefix that is part
16541 	 * of the fmri that is not used in the service
16542 	 * manifest bundle list.
16543 	 */
16544 	sname = svcname + strlen(SCF_FMRI_SVC_PREFIX) +
16545 	    strlen(SCF_FMRI_SERVICE_PREFIX);
16546 	elem = find_add_svc_mfst(sname, NULL);
16547 	if (elem == NULL) {
16548 
16549 		/*
16550 		 * A handcrafted service, one that has no instance containing
16551 		 * last-import snapshot, should get unsupported flag.
16552 		 */
16553 		instances = create_instance_list(svc, 1);
16554 		if (instances == NULL) {
16555 			uu_warn(gettext("Unable to create instance list %s\n"),
16556 			    svcname);
16557 			return;
16558 		}
16559 
16560 		if (uu_list_numnodes(instances) == 0) {
16561 			svc_add_no_support(svc);
16562 			return;
16563 		}
16564 
16565 		/*
16566 		 * If the service is in the history file, and its supporting
16567 		 * manifests are not found, we can safely delete the service
16568 		 * because its manifests are removed from the system.
16569 		 *
16570 		 * Services not found in the history file are not delivered by
16571 		 * Solaris and/or delivered outside supported directories, set
16572 		 * unsupported flag for these services.
16573 		 */
16574 		r = check_mfst_history(svcname);
16575 		if (r == -1)
16576 			return;
16577 
16578 		if (r) {
16579 			/* Set unsupported flag for service  */
16580 			svc_add_no_support(svc);
16581 		} else {
16582 			/* Delete the service */
16583 			teardown_service(svc, svcname);
16584 		}
16585 
16586 		return;
16587 	}
16588 
16589 	/*
16590 	 * Walk through the list of manifests and add them
16591 	 * to the service.
16592 	 *
16593 	 * Create a manifestfiles pg and add the property.
16594 	 */
16595 	mfwalk = uu_list_walk_start(elem->mfstlist, 0);
16596 	if (mfwalk == NULL)
16597 		return;
16598 
16599 	cur_svc = svc;
16600 	r = addpg(SCF_PG_MANIFESTFILES, SCF_GROUP_FRAMEWORK);
16601 	if (r != 0) {
16602 		cur_svc = NULL;
16603 		return;
16604 	}
16605 
16606 	while ((mfile = uu_list_walk_next(mfwalk)) != NULL) {
16607 		pname = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16608 		    mhash_filename_to_propname(mfile->str, 0));
16609 		if (pname == NULL)
16610 			uu_die(gettext("Out of memory.\n"));
16611 
16612 		(void) lscf_addpropvalue(pname, "astring:", mfile->str);
16613 		uu_free(pname);
16614 	}
16615 	uu_list_walk_end(mfwalk);
16616 
16617 	cur_svc = NULL;
16618 }
16619 
16620 /*
16621  * Take a service and process the manifest file entires to see if
16622  * there is continued support for the service and instances.  If
16623  * not cleanup as appropriate.
16624  *
16625  * If a service does not have a manifest files entry flag it for
16626  * upgrade and return.
16627  *
16628  * For each manifestfiles property check if the manifest file is
16629  * under the supported /lib/svc/manifest or /var/svc/manifest path
16630  * and if not then return immediately as this service is not supported
16631  * by the cleanup mechanism and should be ignored.
16632  *
16633  * For each manifest file that is supported, check to see if the
16634  * file exists.  If not then remove the manifest file property
16635  * from the service and the smf/manifest hash table.  If the manifest
16636  * file exists then verify that it supports the instances that are
16637  * part of the service.
16638  *
16639  * Once all manifest files have been accounted for remove any instances
16640  * that are no longer supported in the service.
16641  *
16642  * Return values :
16643  * 0 - Successfully processed the service
16644  * non-zero - failed to process the service
16645  *
16646  * On most errors, will just return to wait and get the next service,
16647  * unless in case of unable to create the needed structures which is
16648  * most likely a fatal error that is not going to be recoverable.
16649  */
16650 int
16651 lscf_service_cleanup(void *act, scf_walkinfo_t *wip)
16652 {
16653 	struct mpg_mfile	*mpntov;
16654 	struct mpg_mfile	**mpvarry = NULL;
16655 	scf_service_t		*svc;
16656 	scf_propertygroup_t	*mpg;
16657 	scf_property_t		*mp;
16658 	scf_value_t		*mv;
16659 	scf_iter_t		*mi;
16660 	scf_instance_t		*instance;
16661 	uu_list_walk_t		*insts;
16662 	uu_list_t		*instances = NULL;
16663 	boolean_t		activity = (boolean_t)act;
16664 	char			*mpnbuf;
16665 	char			*mpvbuf;
16666 	char			*pgpropbuf;
16667 	int			mfstcnt, rminstct, instct, mfstmax;
16668 	int			index;
16669 	int			r = 0;
16670 
16671 	assert(g_hndl != NULL);
16672 	assert(wip->svc != NULL);
16673 	assert(wip->fmri != NULL);
16674 
16675 	svc = wip->svc;
16676 
16677 	mpg = scf_pg_create(g_hndl);
16678 	mp = scf_property_create(g_hndl);
16679 	mi = scf_iter_create(g_hndl);
16680 	mv = scf_value_create(g_hndl);
16681 	instance = scf_instance_create(g_hndl);
16682 
16683 	if (mpg == NULL || mp == NULL || mi == NULL || mv == NULL ||
16684 	    instance == NULL) {
16685 		uu_warn(gettext("Unable to create the supporting entities\n"));
16686 		uu_warn(gettext("scf error is : %s\n"),
16687 		    scf_strerror(scf_error()));
16688 		scfdie();
16689 	}
16690 
16691 	/*
16692 	 * Get the manifestfiles property group to be parsed for
16693 	 * files existence.
16694 	 */
16695 	if (scf_service_get_pg(svc, SCF_PG_MANIFESTFILES, mpg) != SCF_SUCCESS) {
16696 		switch (scf_error()) {
16697 		case SCF_ERROR_NOT_FOUND:
16698 			upgrade_svc_mfst_connection(svc, wip->fmri);
16699 			break;
16700 		case SCF_ERROR_DELETED:
16701 		case SCF_ERROR_CONNECTION_BROKEN:
16702 			goto out;
16703 
16704 		case SCF_ERROR_HANDLE_MISMATCH:
16705 		case SCF_ERROR_NOT_BOUND:
16706 		case SCF_ERROR_NOT_SET:
16707 		default:
16708 			bad_error("scf_iter_pg_properties",
16709 			    scf_error());
16710 		}
16711 
16712 		goto out;
16713 	}
16714 
16715 	/*
16716 	 * Iterate through each of the manifestfiles properties
16717 	 * to determine what manifestfiles are available.
16718 	 *
16719 	 * If a manifest file is supported then increment the
16720 	 * count and therefore the service is safe.
16721 	 */
16722 	if (scf_iter_pg_properties(mi, mpg) != 0) {
16723 		switch (scf_error()) {
16724 		case SCF_ERROR_DELETED:
16725 		case SCF_ERROR_CONNECTION_BROKEN:
16726 			goto out;
16727 
16728 		case SCF_ERROR_HANDLE_MISMATCH:
16729 		case SCF_ERROR_NOT_BOUND:
16730 		case SCF_ERROR_NOT_SET:
16731 		default:
16732 			bad_error("scf_iter_pg_properties",
16733 			    scf_error());
16734 		}
16735 	}
16736 
16737 	mfstcnt = 0;
16738 	mfstmax = MFSTFILE_MAX;
16739 	mpvarry = safe_malloc(sizeof (struct mpg_file *) * MFSTFILE_MAX);
16740 	while ((r = scf_iter_next_property(mi, mp)) != 0) {
16741 		if (r == -1)
16742 			bad_error(gettext("Unable to iterate through "
16743 			    "manifestfiles properties : %s"),
16744 			    scf_error());
16745 
16746 		mpntov = safe_malloc(sizeof (struct mpg_mfile));
16747 		mpnbuf = safe_malloc(max_scf_name_len + 1);
16748 		mpvbuf = safe_malloc(max_scf_value_len + 1);
16749 		mpntov->mpg = mpnbuf;
16750 		mpntov->mfile = mpvbuf;
16751 		mpntov->access = 1;
16752 		if (scf_property_get_name(mp, mpnbuf,
16753 		    max_scf_name_len + 1) < 0) {
16754 			uu_warn(gettext("Unable to get manifest file "
16755 			    "property : %s\n"),
16756 			    scf_strerror(scf_error()));
16757 
16758 			switch (scf_error()) {
16759 			case SCF_ERROR_DELETED:
16760 			case SCF_ERROR_CONNECTION_BROKEN:
16761 				r = scferror2errno(scf_error());
16762 				goto out_free;
16763 
16764 			case SCF_ERROR_HANDLE_MISMATCH:
16765 			case SCF_ERROR_NOT_BOUND:
16766 			case SCF_ERROR_NOT_SET:
16767 			default:
16768 				bad_error("scf_iter_pg_properties",
16769 				    scf_error());
16770 			}
16771 		}
16772 
16773 		/*
16774 		 * The support property is a boolean value that indicates
16775 		 * if the service is supported for manifest file deletion.
16776 		 * Currently at this time there is no code that sets this
16777 		 * value to true.  So while we could just let this be caught
16778 		 * by the support check below, in the future this by be set
16779 		 * to true and require processing.  So for that, go ahead
16780 		 * and check here, and just return if false.  Otherwise,
16781 		 * fall through expecting that other support checks will
16782 		 * handle the entries.
16783 		 */
16784 		if (strcmp(mpnbuf, SUPPORTPROP) == 0) {
16785 			uint8_t	support;
16786 
16787 			if (scf_property_get_value(mp, mv) != 0 ||
16788 			    scf_value_get_boolean(mv, &support) != 0) {
16789 				uu_warn(gettext("Unable to get the manifest "
16790 				    "support value: %s\n"),
16791 				    scf_strerror(scf_error()));
16792 
16793 				switch (scf_error()) {
16794 				case SCF_ERROR_DELETED:
16795 				case SCF_ERROR_CONNECTION_BROKEN:
16796 					r = scferror2errno(scf_error());
16797 					goto out_free;
16798 
16799 				case SCF_ERROR_HANDLE_MISMATCH:
16800 				case SCF_ERROR_NOT_BOUND:
16801 				case SCF_ERROR_NOT_SET:
16802 				default:
16803 					bad_error("scf_iter_pg_properties",
16804 					    scf_error());
16805 				}
16806 			}
16807 
16808 			if (support == B_FALSE)
16809 				goto out_free;
16810 		}
16811 
16812 		/*
16813 		 * Anything with a manifest outside of the supported
16814 		 * directories, immediately bail out because that makes
16815 		 * this service non-supported.  We don't even want
16816 		 * to do instance processing in this case because the
16817 		 * instances could be part of the non-supported manifest.
16818 		 */
16819 		if (strncmp(mpnbuf, LIBSVC_PR, strlen(LIBSVC_PR)) != 0) {
16820 			/*
16821 			 * Manifest is not in /lib/svc, so we need to
16822 			 * consider the /var/svc case.
16823 			 */
16824 			if (strncmp(mpnbuf, VARSVC_PR,
16825 			    strlen(VARSVC_PR)) != 0 || IGNORE_VAR) {
16826 				/*
16827 				 * Either the manifest is not in /var/svc or
16828 				 * /var is not yet mounted.  We ignore the
16829 				 * manifest either because it is not in a
16830 				 * standard location or because we cannot
16831 				 * currently access the manifest.
16832 				 */
16833 				goto out_free;
16834 			}
16835 		}
16836 
16837 		/*
16838 		 * Get the value to of the manifest file for this entry
16839 		 * for access verification and instance support
16840 		 * verification if it still exists.
16841 		 *
16842 		 * During Early Manifest Import if the manifest is in
16843 		 * /var/svc then it may not yet be available for checking
16844 		 * so we must determine if /var/svc is available.  If not
16845 		 * then defer until Late Manifest Import to cleanup.
16846 		 */
16847 		if (scf_property_get_value(mp, mv) != 0) {
16848 			uu_warn(gettext("Unable to get the manifest file "
16849 			    "value: %s\n"),
16850 			    scf_strerror(scf_error()));
16851 
16852 			switch (scf_error()) {
16853 			case SCF_ERROR_DELETED:
16854 			case SCF_ERROR_CONNECTION_BROKEN:
16855 				r = scferror2errno(scf_error());
16856 				goto out_free;
16857 
16858 			case SCF_ERROR_HANDLE_MISMATCH:
16859 			case SCF_ERROR_NOT_BOUND:
16860 			case SCF_ERROR_NOT_SET:
16861 			default:
16862 				bad_error("scf_property_get_value",
16863 				    scf_error());
16864 			}
16865 		}
16866 
16867 		if (scf_value_get_astring(mv, mpvbuf,
16868 		    max_scf_value_len + 1) < 0) {
16869 			uu_warn(gettext("Unable to get the manifest "
16870 			    "file : %s\n"),
16871 			    scf_strerror(scf_error()));
16872 
16873 			switch (scf_error()) {
16874 			case SCF_ERROR_DELETED:
16875 			case SCF_ERROR_CONNECTION_BROKEN:
16876 				r = scferror2errno(scf_error());
16877 				goto out_free;
16878 
16879 			case SCF_ERROR_HANDLE_MISMATCH:
16880 			case SCF_ERROR_NOT_BOUND:
16881 			case SCF_ERROR_NOT_SET:
16882 			default:
16883 				bad_error("scf_value_get_astring",
16884 				    scf_error());
16885 			}
16886 		}
16887 
16888 		mpvarry[mfstcnt] = mpntov;
16889 		mfstcnt++;
16890 
16891 		/*
16892 		 * Check for the need to reallocate array
16893 		 */
16894 		if (mfstcnt >= (mfstmax - 1)) {
16895 			struct mpg_mfile **newmpvarry;
16896 
16897 			mfstmax = mfstmax * 2;
16898 			newmpvarry = realloc(mpvarry,
16899 			    sizeof (struct mpg_mfile *) * mfstmax);
16900 
16901 			if (newmpvarry == NULL)
16902 				goto out_free;
16903 
16904 			mpvarry = newmpvarry;
16905 		}
16906 
16907 		mpvarry[mfstcnt] = NULL;
16908 	}
16909 
16910 	for (index = 0; mpvarry[index]; index++) {
16911 		mpntov = mpvarry[index];
16912 
16913 		/*
16914 		 * Check to see if the manifestfile is accessable, if so hand
16915 		 * this service and manifestfile off to be processed for
16916 		 * instance support.
16917 		 */
16918 		mpnbuf = mpntov->mpg;
16919 		mpvbuf = mpntov->mfile;
16920 		if (access(mpvbuf, F_OK) != 0) {
16921 			mpntov->access = 0;
16922 			activity++;
16923 			mfstcnt--;
16924 			/* Remove the entry from the service */
16925 			cur_svc = svc;
16926 			pgpropbuf = uu_msprintf("%s/%s", SCF_PG_MANIFESTFILES,
16927 			    mpnbuf);
16928 			if (pgpropbuf == NULL)
16929 				uu_die(gettext("Out of memory.\n"));
16930 
16931 			lscf_delprop(pgpropbuf);
16932 			cur_svc = NULL;
16933 
16934 			uu_free(pgpropbuf);
16935 		}
16936 	}
16937 
16938 	/*
16939 	 * If mfstcnt is 0, none of the manifests that supported the service
16940 	 * existed so remove the service.
16941 	 */
16942 	if (mfstcnt == 0) {
16943 		teardown_service(svc, wip->fmri);
16944 
16945 		goto out_free;
16946 	}
16947 
16948 	if (activity) {
16949 		int	nosvcsupport = 0;
16950 
16951 		/*
16952 		 * If the list of service instances is NULL then
16953 		 * create the list.
16954 		 */
16955 		instances = create_instance_list(svc, 1);
16956 		if (instances == NULL) {
16957 			uu_warn(gettext("Unable to create instance list %s\n"),
16958 			    wip->fmri);
16959 			goto out_free;
16960 		}
16961 
16962 		rminstct = uu_list_numnodes(instances);
16963 		instct = rminstct;
16964 
16965 		for (index = 0; mpvarry[index]; index++) {
16966 			mpntov = mpvarry[index];
16967 			if (mpntov->access == 0)
16968 				continue;
16969 
16970 			mpnbuf = mpntov->mpg;
16971 			mpvbuf = mpntov->mfile;
16972 			r = check_instance_support(mpvbuf, wip->fmri,
16973 			    instances);
16974 			if (r == -1) {
16975 				nosvcsupport++;
16976 			} else {
16977 				rminstct -= r;
16978 			}
16979 		}
16980 
16981 		if (instct && instct == rminstct && nosvcsupport == mfstcnt) {
16982 			teardown_service(svc, wip->fmri);
16983 
16984 			goto out_free;
16985 		}
16986 	}
16987 
16988 	/*
16989 	 * If there are instances left on the instance list, then
16990 	 * we must remove them.
16991 	 */
16992 	if (instances != NULL && uu_list_numnodes(instances)) {
16993 		string_list_t *sp;
16994 
16995 		insts = uu_list_walk_start(instances, 0);
16996 		while ((sp = uu_list_walk_next(insts)) != NULL) {
16997 			/*
16998 			 * Remove the instance from the instances list.
16999 			 */
17000 			safe_printf(gettext("Delete instance %s from "
17001 			    "service %s\n"), sp->str, wip->fmri);
17002 			if (scf_service_get_instance(svc, sp->str,
17003 			    instance) != SCF_SUCCESS) {
17004 				(void) uu_warn("scf_error - %s\n",
17005 				    scf_strerror(scf_error()));
17006 
17007 				continue;
17008 			}
17009 
17010 			(void) disable_instance(instance);
17011 
17012 			(void) lscf_instance_delete(instance, 1);
17013 		}
17014 		scf_instance_destroy(instance);
17015 		uu_list_walk_end(insts);
17016 	}
17017 
17018 out_free:
17019 	if (mpvarry) {
17020 		struct mpg_mfile *fmpntov;
17021 
17022 		for (index = 0; mpvarry[index]; index++) {
17023 			fmpntov  = mpvarry[index];
17024 			if (fmpntov->mpg == mpnbuf)
17025 				mpnbuf = NULL;
17026 			free(fmpntov->mpg);
17027 
17028 			if (fmpntov->mfile == mpvbuf)
17029 				mpvbuf = NULL;
17030 			free(fmpntov->mfile);
17031 
17032 			if (fmpntov == mpntov)
17033 				mpntov = NULL;
17034 			free(fmpntov);
17035 		}
17036 		if (mpnbuf)
17037 			free(mpnbuf);
17038 		if (mpvbuf)
17039 			free(mpvbuf);
17040 		if (mpntov)
17041 			free(mpntov);
17042 
17043 		free(mpvarry);
17044 	}
17045 out:
17046 	scf_pg_destroy(mpg);
17047 	scf_property_destroy(mp);
17048 	scf_iter_destroy(mi);
17049 	scf_value_destroy(mv);
17050 
17051 	return (0);
17052 }
17053 
17054 /*
17055  * Take the service and search for the manifestfiles property
17056  * in each of the property groups.  If the manifest file
17057  * associated with the property does not exist then remove
17058  * the property group.
17059  */
17060 int
17061 lscf_hash_cleanup()
17062 {
17063 	scf_service_t		*svc;
17064 	scf_scope_t		*scope;
17065 	scf_propertygroup_t	*pg;
17066 	scf_property_t		*prop;
17067 	scf_value_t		*val;
17068 	scf_iter_t		*iter;
17069 	char			*pgname = NULL;
17070 	char			*mfile = NULL;
17071 	int			r;
17072 
17073 	svc = scf_service_create(g_hndl);
17074 	scope = scf_scope_create(g_hndl);
17075 	pg = scf_pg_create(g_hndl);
17076 	prop = scf_property_create(g_hndl);
17077 	val = scf_value_create(g_hndl);
17078 	iter = scf_iter_create(g_hndl);
17079 	if (pg == NULL || prop == NULL || val == NULL || iter == NULL ||
17080 	    svc == NULL || scope == NULL) {
17081 		uu_warn(gettext("Unable to create a property group, or "
17082 		    "property\n"));
17083 		uu_warn("%s\n", pg == NULL ? "pg is NULL" :
17084 		    "pg is not NULL");
17085 		uu_warn("%s\n", prop == NULL ? "prop is NULL" :
17086 		    "prop is not NULL");
17087 		uu_warn("%s\n", val == NULL ? "val is NULL" :
17088 		    "val is not NULL");
17089 		uu_warn("%s\n", iter == NULL ? "iter is NULL" :
17090 		    "iter is not NULL");
17091 		uu_warn("%s\n", svc == NULL ? "svc is NULL" :
17092 		    "svc is not NULL");
17093 		uu_warn("%s\n", scope == NULL ? "scope is NULL" :
17094 		    "scope is not NULL");
17095 		uu_warn(gettext("scf error is : %s\n"),
17096 		    scf_strerror(scf_error()));
17097 		scfdie();
17098 	}
17099 
17100 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0) {
17101 		switch (scf_error()) {
17102 		case SCF_ERROR_CONNECTION_BROKEN:
17103 		case SCF_ERROR_NOT_FOUND:
17104 			goto out;
17105 
17106 		case SCF_ERROR_HANDLE_MISMATCH:
17107 		case SCF_ERROR_NOT_BOUND:
17108 		case SCF_ERROR_INVALID_ARGUMENT:
17109 		default:
17110 			bad_error("scf_handle_get_scope", scf_error());
17111 		}
17112 	}
17113 
17114 	if (scf_scope_get_service(scope, HASH_SVC, svc) != 0) {
17115 		uu_warn(gettext("Unable to process the hash service, %s\n"),
17116 		    HASH_SVC);
17117 		goto out;
17118 	}
17119 
17120 	pgname = safe_malloc(max_scf_name_len + 1);
17121 	mfile = safe_malloc(max_scf_value_len + 1);
17122 
17123 	if (scf_iter_service_pgs(iter, svc) != SCF_SUCCESS) {
17124 		uu_warn(gettext("Unable to cleanup smf hash table : %s\n"),
17125 		    scf_strerror(scf_error()));
17126 		goto out;
17127 	}
17128 
17129 	while ((r = scf_iter_next_pg(iter, pg)) != 0) {
17130 		if (r == -1)
17131 			goto out;
17132 
17133 		if (scf_pg_get_name(pg, pgname, max_scf_name_len + 1) < 0) {
17134 			switch (scf_error()) {
17135 			case SCF_ERROR_DELETED:
17136 				return (ENODEV);
17137 
17138 			case SCF_ERROR_CONNECTION_BROKEN:
17139 				return (ECONNABORTED);
17140 
17141 			case SCF_ERROR_NOT_SET:
17142 			case SCF_ERROR_NOT_BOUND:
17143 			default:
17144 				bad_error("scf_pg_get_name", scf_error());
17145 			}
17146 		}
17147 		if (IGNORE_VAR) {
17148 			if (strncmp(pgname, VARSVC_PR, strlen(VARSVC_PR)) == 0)
17149 				continue;
17150 		}
17151 
17152 		/*
17153 		 * If unable to get the property continue as this is an
17154 		 * entry that has no location to check against.
17155 		 */
17156 		if (scf_pg_get_property(pg, MFSTFILEPR, prop) != SCF_SUCCESS) {
17157 			continue;
17158 		}
17159 
17160 		if (scf_property_get_value(prop, val) != SCF_SUCCESS) {
17161 			uu_warn(gettext("Unable to get value from %s\n"),
17162 			    pgname);
17163 
17164 			switch (scf_error()) {
17165 			case SCF_ERROR_DELETED:
17166 			case SCF_ERROR_CONSTRAINT_VIOLATED:
17167 			case SCF_ERROR_NOT_FOUND:
17168 			case SCF_ERROR_NOT_SET:
17169 				continue;
17170 
17171 			case SCF_ERROR_CONNECTION_BROKEN:
17172 				r = scferror2errno(scf_error());
17173 				goto out;
17174 
17175 			case SCF_ERROR_HANDLE_MISMATCH:
17176 			case SCF_ERROR_NOT_BOUND:
17177 			default:
17178 				bad_error("scf_property_get_value",
17179 				    scf_error());
17180 			}
17181 		}
17182 
17183 		if (scf_value_get_astring(val, mfile, max_scf_value_len + 1)
17184 		    == -1) {
17185 			uu_warn(gettext("Unable to get astring from %s : %s\n"),
17186 			    pgname, scf_strerror(scf_error()));
17187 
17188 			switch (scf_error()) {
17189 			case SCF_ERROR_NOT_SET:
17190 			case SCF_ERROR_TYPE_MISMATCH:
17191 				continue;
17192 
17193 			default:
17194 				bad_error("scf_value_get_astring", scf_error());
17195 			}
17196 		}
17197 
17198 		if (access(mfile, F_OK) == 0)
17199 			continue;
17200 
17201 		(void) scf_pg_delete(pg);
17202 	}
17203 
17204 out:
17205 	scf_scope_destroy(scope);
17206 	scf_service_destroy(svc);
17207 	scf_pg_destroy(pg);
17208 	scf_property_destroy(prop);
17209 	scf_value_destroy(val);
17210 	scf_iter_destroy(iter);
17211 	free(pgname);
17212 	free(mfile);
17213 
17214 	return (0);
17215 }
17216 
17217 #ifndef NATIVE_BUILD
17218 /* ARGSUSED */
17219 CPL_MATCH_FN(complete_select)
17220 {
17221 	const char *arg0, *arg1, *arg1end;
17222 	int word_start, err = 0, r;
17223 	size_t len;
17224 	char *buf;
17225 
17226 	lscf_prep_hndl();
17227 
17228 	arg0 = line + strspn(line, " \t");
17229 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
17230 
17231 	arg1 = arg0 + sizeof ("select") - 1;
17232 	arg1 += strspn(arg1, " \t");
17233 	word_start = arg1 - line;
17234 
17235 	arg1end = arg1 + strcspn(arg1, " \t");
17236 	if (arg1end < line + word_end)
17237 		return (0);
17238 
17239 	len = line + word_end - arg1;
17240 
17241 	buf = safe_malloc(max_scf_name_len + 1);
17242 
17243 	if (cur_snap != NULL) {
17244 		return (0);
17245 	} else if (cur_inst != NULL) {
17246 		return (0);
17247 	} else if (cur_svc != NULL) {
17248 		scf_instance_t *inst;
17249 		scf_iter_t *iter;
17250 
17251 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
17252 		    (iter = scf_iter_create(g_hndl)) == NULL)
17253 			scfdie();
17254 
17255 		if (scf_iter_service_instances(iter, cur_svc) != 0)
17256 			scfdie();
17257 
17258 		for (;;) {
17259 			r = scf_iter_next_instance(iter, inst);
17260 			if (r == 0)
17261 				break;
17262 			if (r != 1)
17263 				scfdie();
17264 
17265 			if (scf_instance_get_name(inst, buf,
17266 			    max_scf_name_len + 1) < 0)
17267 				scfdie();
17268 
17269 			if (strncmp(buf, arg1, len) == 0) {
17270 				err = cpl_add_completion(cpl, line, word_start,
17271 				    word_end, buf + len, "", " ");
17272 				if (err != 0)
17273 					break;
17274 			}
17275 		}
17276 
17277 		scf_iter_destroy(iter);
17278 		scf_instance_destroy(inst);
17279 
17280 		return (err);
17281 	} else {
17282 		scf_service_t *svc;
17283 		scf_iter_t *iter;
17284 
17285 		assert(cur_scope != NULL);
17286 
17287 		if ((svc = scf_service_create(g_hndl)) == NULL ||
17288 		    (iter = scf_iter_create(g_hndl)) == NULL)
17289 			scfdie();
17290 
17291 		if (scf_iter_scope_services(iter, cur_scope) != 0)
17292 			scfdie();
17293 
17294 		for (;;) {
17295 			r = scf_iter_next_service(iter, svc);
17296 			if (r == 0)
17297 				break;
17298 			if (r != 1)
17299 				scfdie();
17300 
17301 			if (scf_service_get_name(svc, buf,
17302 			    max_scf_name_len + 1) < 0)
17303 				scfdie();
17304 
17305 			if (strncmp(buf, arg1, len) == 0) {
17306 				err = cpl_add_completion(cpl, line, word_start,
17307 				    word_end, buf + len, "", " ");
17308 				if (err != 0)
17309 					break;
17310 			}
17311 		}
17312 
17313 		scf_iter_destroy(iter);
17314 		scf_service_destroy(svc);
17315 
17316 		return (err);
17317 	}
17318 }
17319 
17320 /* ARGSUSED */
17321 CPL_MATCH_FN(complete_command)
17322 {
17323 	uint32_t scope = 0;
17324 
17325 	if (cur_snap != NULL)
17326 		scope = CS_SNAP;
17327 	else if (cur_inst != NULL)
17328 		scope = CS_INST;
17329 	else if (cur_svc != NULL)
17330 		scope = CS_SVC;
17331 	else
17332 		scope = CS_SCOPE;
17333 
17334 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
17335 }
17336 #endif	/* NATIVE_BUILD */
17337