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