xref: /titanic_52/usr/src/cmd/svc/svccfg/svccfg_libscf.c (revision ff0e937b36dcde1a47ff7b00aa76a491c0dc07a8)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
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 <libscf.h>
38 #include <libscf_priv.h>
39 #include <libtecla.h>
40 #include <libuutil.h>
41 #include <limits.h>
42 #include <locale.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <strings.h>
46 #include <unistd.h>
47 #include <wait.h>
48 
49 #include <libxml/tree.h>
50 
51 #include "svccfg.h"
52 #include "manifest_hash.h"
53 
54 /* The colon namespaces in each entity (each followed by a newline). */
55 #define	COLON_NAMESPACES	":properties\n"
56 
57 #define	TEMP_FILE_PATTERN	"/tmp/svccfg-XXXXXX"
58 
59 /* These are characters which the lexer requires to be in double-quotes. */
60 #define	CHARS_TO_QUOTE		" \t\n\\>=\"()"
61 
62 #define	HASH_SIZE		16
63 #define	HASH_SVC		"smf/manifest"
64 #define	HASH_PG_TYPE		"framework"
65 #define	HASH_PG_FLAGS		0
66 #define	HASH_PROP		"md5sum"
67 
68 /*
69  * Indentation used in the output of the describe subcommand.
70  */
71 #define	TMPL_VALUE_INDENT	"  "
72 #define	TMPL_INDENT		"    "
73 #define	TMPL_INDENT_2X		"        "
74 #define	TMPL_CHOICE_INDENT	"      "
75 
76 /*
77  * These are the classes of elements which may appear as children of service
78  * or instance elements in XML manifests.
79  */
80 struct entity_elts {
81 	xmlNodePtr	create_default_instance;
82 	xmlNodePtr	single_instance;
83 	xmlNodePtr	restarter;
84 	xmlNodePtr	dependencies;
85 	xmlNodePtr	dependents;
86 	xmlNodePtr	method_context;
87 	xmlNodePtr	exec_methods;
88 	xmlNodePtr	property_groups;
89 	xmlNodePtr	instances;
90 	xmlNodePtr	stability;
91 	xmlNodePtr	template;
92 };
93 
94 /*
95  * Likewise for property_group elements.
96  */
97 struct pg_elts {
98 	xmlNodePtr	stability;
99 	xmlNodePtr	propvals;
100 	xmlNodePtr	properties;
101 };
102 
103 /*
104  * Likewise for template elements.
105  */
106 struct template_elts {
107 	xmlNodePtr	common_name;
108 	xmlNodePtr	description;
109 	xmlNodePtr	documentation;
110 };
111 
112 /*
113  * This structure is for snaplevel lists.  They are convenient because libscf
114  * only allows traversing snaplevels in one direction.
115  */
116 struct snaplevel {
117 	uu_list_node_t	list_node;
118 	scf_snaplevel_t	*sl;
119 };
120 
121 /*
122  * This is used for communication between lscf_service_export and
123  * export_callback.
124  */
125 struct export_args {
126 	const char	*filename;
127 	int 		flags;
128 };
129 
130 const char * const scf_pg_general = SCF_PG_GENERAL;
131 const char * const scf_group_framework = SCF_GROUP_FRAMEWORK;
132 const char * const scf_property_enabled = SCF_PROPERTY_ENABLED;
133 const char * const scf_property_external = "external";
134 
135 const char * const snap_initial = "initial";
136 const char * const snap_lastimport = "last-import";
137 const char * const snap_previous = "previous";
138 const char * const snap_running = "running";
139 
140 scf_handle_t *g_hndl = NULL;	/* only valid after lscf_prep_hndl() */
141 
142 ssize_t max_scf_fmri_len;
143 ssize_t max_scf_name_len;
144 ssize_t max_scf_pg_type_len;
145 ssize_t max_scf_value_len;
146 static size_t max_scf_len;
147 
148 static scf_scope_t *cur_scope;
149 static scf_service_t *cur_svc = NULL;
150 static scf_instance_t *cur_inst = NULL;
151 static scf_snapshot_t *cur_snap = NULL;
152 static scf_snaplevel_t *cur_level = NULL;
153 
154 static uu_list_pool_t *snaplevel_pool;
155 /* cur_levels is the snaplevels of cur_snap, from least specific to most. */
156 static uu_list_t *cur_levels;
157 static struct snaplevel *cur_elt;		/* cur_elt->sl == cur_level */
158 
159 static FILE *tempfile = NULL;
160 static char tempfilename[sizeof (TEMP_FILE_PATTERN)] = "";
161 
162 static const char *emsg_entity_not_selected;
163 static const char *emsg_permission_denied;
164 static const char *emsg_create_xml;
165 static const char *emsg_cant_modify_snapshots;
166 static const char *emsg_read_only;
167 static const char *emsg_deleted;
168 static const char *emsg_invalid_pg_name;
169 static const char *emsg_invalid_prop_name;
170 static const char *emsg_no_such_pg;
171 static const char *emsg_fmri_invalid_pg_name;
172 static const char *emsg_fmri_invalid_pg_name_type;
173 static const char *emsg_pg_added;
174 static const char *emsg_pg_changed;
175 static const char *emsg_pg_deleted;
176 static const char *emsg_pg_mod_perm;
177 static const char *emsg_pg_add_perm;
178 static const char *emsg_pg_del_perm;
179 static const char *emsg_snap_perm;
180 static const char *emsg_dpt_dangling;
181 static const char *emsg_dpt_no_dep;
182 
183 static int li_only;
184 static int no_refresh = 0;
185 
186 /* import globals, to minimize allocations */
187 static scf_scope_t *imp_scope = NULL;
188 static scf_service_t *imp_svc = NULL, *imp_tsvc = NULL;
189 static scf_instance_t *imp_inst = NULL, *imp_tinst = NULL;
190 static scf_snapshot_t *imp_snap = NULL, *imp_lisnap = NULL, *imp_tlisnap = NULL;
191 static scf_snapshot_t *imp_rsnap = NULL;
192 static scf_snaplevel_t *imp_snpl = NULL, *imp_rsnpl = NULL;
193 static scf_propertygroup_t *imp_pg = NULL, *imp_pg2 = NULL;
194 static scf_property_t *imp_prop = NULL;
195 static scf_iter_t *imp_iter = NULL;
196 static scf_iter_t *imp_rpg_iter = NULL;
197 static scf_iter_t *imp_up_iter = NULL;
198 static scf_transaction_t *imp_tx = NULL;	/* always reset this */
199 static char *imp_str = NULL;
200 static size_t imp_str_sz;
201 static char *imp_tsname = NULL;
202 static char *imp_fe1 = NULL;		/* for fmri_equal() */
203 static char *imp_fe2 = NULL;
204 static uu_list_t *imp_deleted_dpts = NULL;	/* pgroup_t's to refresh */
205 
206 /* upgrade_dependents() globals */
207 static scf_instance_t *ud_inst = NULL;
208 static scf_snaplevel_t *ud_snpl = NULL;
209 static scf_propertygroup_t *ud_pg = NULL;
210 static scf_propertygroup_t *ud_cur_depts_pg = NULL;
211 static scf_propertygroup_t *ud_run_dpts_pg = NULL;
212 static int ud_run_dpts_pg_set = 0;
213 static scf_property_t *ud_prop = NULL;
214 static scf_property_t *ud_dpt_prop = NULL;
215 static scf_value_t *ud_val = NULL;
216 static scf_iter_t *ud_iter = NULL, *ud_iter2 = NULL;
217 static scf_transaction_t *ud_tx = NULL;
218 static char *ud_ctarg = NULL;
219 static char *ud_oldtarg = NULL;
220 static char *ud_name = NULL;
221 
222 /* export globals */
223 static scf_instance_t *exp_inst;
224 static scf_propertygroup_t *exp_pg;
225 static scf_property_t *exp_prop;
226 static scf_value_t *exp_val;
227 static scf_iter_t *exp_inst_iter, *exp_pg_iter, *exp_prop_iter, *exp_val_iter;
228 static char *exp_str;
229 static size_t exp_str_sz;
230 
231 static void scfdie_lineno(int lineno) __NORETURN;
232 
233 static char *start_method_names[] = {
234 	"start",
235 	"inetd_start",
236 	NULL
237 };
238 
239 static void
240 safe_printf(const char *fmt, ...)
241 {
242 	va_list va;
243 
244 	va_start(va, fmt);
245 	if (vprintf(fmt, va) < 0)
246 		uu_die(gettext("Error writing to stdout"));
247 	va_end(va);
248 }
249 
250 /*
251  * For unexpected libscf errors.
252  */
253 #ifdef NDEBUG
254 
255 static void scfdie(void) __NORETURN;
256 
257 static void
258 scfdie(void)
259 {
260 	scf_error_t err = scf_error();
261 
262 	if (err == SCF_ERROR_CONNECTION_BROKEN)
263 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
264 
265 	uu_die(gettext("Unexpected fatal libscf error: %s.  Exiting.\n"),
266 	    scf_strerror(err));
267 }
268 
269 #else
270 
271 #define	scfdie()	scfdie_lineno(__LINE__)
272 
273 static void
274 scfdie_lineno(int lineno)
275 {
276 	scf_error_t err = scf_error();
277 
278 	if (err == SCF_ERROR_CONNECTION_BROKEN)
279 		uu_die(gettext("Repository connection broken.  Exiting.\n"));
280 
281 	uu_die(gettext("Unexpected libscf error on line %d of " __FILE__
282 	    ": %s.\n"), lineno, scf_strerror(err));
283 }
284 
285 #endif
286 
287 static void
288 scfwarn(void)
289 {
290 	warn(gettext("Unexpected libscf error: %s.\n"),
291 	    scf_strerror(scf_error()));
292 }
293 
294 /*
295  * Clear a field of a structure.
296  */
297 static int
298 clear_int(void *a, void *b)
299 {
300 	/* LINTED */
301 	*(int *)((char *)a + (size_t)b) = 0;
302 
303 	return (UU_WALK_NEXT);
304 }
305 
306 static int
307 scferror2errno(scf_error_t err)
308 {
309 	switch (err) {
310 	case SCF_ERROR_BACKEND_ACCESS:
311 		return (EACCES);
312 
313 	case SCF_ERROR_BACKEND_READONLY:
314 		return (EROFS);
315 
316 	case SCF_ERROR_CONNECTION_BROKEN:
317 		return (ECONNABORTED);
318 
319 	case SCF_ERROR_CONSTRAINT_VIOLATED:
320 	case SCF_ERROR_INVALID_ARGUMENT:
321 		return (EINVAL);
322 
323 	case SCF_ERROR_DELETED:
324 		return (ECANCELED);
325 
326 	case SCF_ERROR_EXISTS:
327 		return (EEXIST);
328 
329 	case SCF_ERROR_NO_MEMORY:
330 		return (ENOMEM);
331 
332 	case SCF_ERROR_NO_RESOURCES:
333 		return (ENOSPC);
334 
335 	case SCF_ERROR_NOT_FOUND:
336 		return (ENOENT);
337 
338 	case SCF_ERROR_PERMISSION_DENIED:
339 		return (EPERM);
340 
341 	default:
342 #ifndef NDEBUG
343 		(void) fprintf(stderr, "%s:%d: Unknown libscf error %d.\n",
344 		    __FILE__, __LINE__, err);
345 #else
346 		(void) fprintf(stderr, "Unknown libscf error %d.\n", err);
347 #endif
348 		abort();
349 		/* NOTREACHED */
350 	}
351 }
352 
353 static int
354 entity_get_pg(void *ent, int issvc, const char *name,
355     scf_propertygroup_t *pg)
356 {
357 	if (issvc)
358 		return (scf_service_get_pg(ent, name, pg));
359 	else
360 		return (scf_instance_get_pg(ent, name, pg));
361 }
362 
363 static void
364 entity_destroy(void *ent, int issvc)
365 {
366 	if (issvc)
367 		scf_service_destroy(ent);
368 	else
369 		scf_instance_destroy(ent);
370 }
371 
372 static int
373 get_pg(const char *pg_name, scf_propertygroup_t *pg)
374 {
375 	int ret;
376 
377 	if (cur_level != NULL)
378 		ret = scf_snaplevel_get_pg(cur_level, pg_name, pg);
379 	else if (cur_inst != NULL)
380 		ret = scf_instance_get_pg(cur_inst, pg_name, pg);
381 	else
382 		ret = scf_service_get_pg(cur_svc, pg_name, pg);
383 
384 	return (ret);
385 }
386 
387 /*
388  * Find a snaplevel in a snapshot.  If get_svc is true, find the service
389  * snaplevel.  Otherwise find the instance snaplevel.
390  *
391  * Returns
392  *   0 - success
393  *   ECONNABORTED - repository connection broken
394  *   ECANCELED - instance containing snap was deleted
395  *   ENOENT - snap has no snaplevels
396  *	    - requested snaplevel not found
397  */
398 static int
399 get_snaplevel(scf_snapshot_t *snap, int get_svc, scf_snaplevel_t *snpl)
400 {
401 	if (scf_snapshot_get_base_snaplevel(snap, snpl) != 0) {
402 		switch (scf_error()) {
403 		case SCF_ERROR_CONNECTION_BROKEN:
404 		case SCF_ERROR_DELETED:
405 		case SCF_ERROR_NOT_FOUND:
406 			return (scferror2errno(scf_error()));
407 
408 		case SCF_ERROR_HANDLE_MISMATCH:
409 		case SCF_ERROR_NOT_BOUND:
410 		case SCF_ERROR_NOT_SET:
411 		default:
412 			bad_error("scf_snapshot_get_base_snaplevel",
413 			    scf_error());
414 		}
415 	}
416 
417 	for (;;) {
418 		ssize_t ssz;
419 
420 		ssz = scf_snaplevel_get_instance_name(snpl, NULL, 0);
421 		if (ssz >= 0) {
422 			if (!get_svc)
423 				return (0);
424 		} else {
425 			switch (scf_error()) {
426 			case SCF_ERROR_CONSTRAINT_VIOLATED:
427 				if (get_svc)
428 					return (0);
429 				break;
430 
431 			case SCF_ERROR_DELETED:
432 			case SCF_ERROR_CONNECTION_BROKEN:
433 				return (scferror2errno(scf_error()));
434 
435 			case SCF_ERROR_NOT_SET:
436 			case SCF_ERROR_NOT_BOUND:
437 			default:
438 				bad_error("scf_snaplevel_get_instance_name",
439 				    scf_error());
440 			}
441 		}
442 
443 		if (scf_snaplevel_get_next_snaplevel(snpl, snpl) != 0) {
444 			switch (scf_error()) {
445 			case SCF_ERROR_NOT_FOUND:
446 			case SCF_ERROR_CONNECTION_BROKEN:
447 			case SCF_ERROR_DELETED:
448 				return (scferror2errno(scf_error()));
449 
450 			case SCF_ERROR_HANDLE_MISMATCH:
451 			case SCF_ERROR_NOT_BOUND:
452 			case SCF_ERROR_NOT_SET:
453 			case SCF_ERROR_INVALID_ARGUMENT:
454 			default:
455 				bad_error("scf_snaplevel_get_next_snaplevel",
456 				    scf_error());
457 			}
458 		}
459 	}
460 }
461 
462 /*
463  * If issvc is 0, take ent to be a pointer to an scf_instance_t.  If it has
464  * a running snapshot, and that snapshot has an instance snaplevel, set pg to
465  * the property group named name in it.  If it doesn't have a running
466  * snapshot, set pg to the instance's current property group named name.
467  *
468  * If issvc is nonzero, take ent to be a pointer to an scf_service_t, and walk
469  * its instances.  If one has a running snapshot with a service snaplevel, set
470  * pg to the property group named name in it.  If no such snaplevel could be
471  * found, set pg to the service's current property group named name.
472  *
473  * iter, inst, snap, and snpl are required scratch objects.
474  *
475  * Returns
476  *   0 - success
477  *   ECONNABORTED - repository connection broken
478  *   ECANCELED - ent was deleted
479  *   ENOENT - no such property group
480  *   EINVAL - name is an invalid property group name
481  *   EBADF - found running snapshot is missing a snaplevel
482  */
483 static int
484 entity_get_running_pg(void *ent, int issvc, const char *name,
485     scf_propertygroup_t *pg, scf_iter_t *iter, scf_instance_t *inst,
486     scf_snapshot_t *snap, scf_snaplevel_t *snpl)
487 {
488 	int r;
489 
490 	if (issvc) {
491 		/* Search for an instance with a running snapshot. */
492 		if (scf_iter_service_instances(iter, ent) != 0) {
493 			switch (scf_error()) {
494 			case SCF_ERROR_DELETED:
495 			case SCF_ERROR_CONNECTION_BROKEN:
496 				return (scferror2errno(scf_error()));
497 
498 			case SCF_ERROR_NOT_SET:
499 			case SCF_ERROR_NOT_BOUND:
500 			case SCF_ERROR_HANDLE_MISMATCH:
501 			default:
502 				bad_error("scf_iter_service_instances",
503 				    scf_error());
504 			}
505 		}
506 
507 		for (;;) {
508 			r = scf_iter_next_instance(iter, inst);
509 			if (r == 0) {
510 				if (scf_service_get_pg(ent, name, pg) == 0)
511 					return (0);
512 
513 				switch (scf_error()) {
514 				case SCF_ERROR_DELETED:
515 				case SCF_ERROR_NOT_FOUND:
516 				case SCF_ERROR_INVALID_ARGUMENT:
517 				case SCF_ERROR_CONNECTION_BROKEN:
518 					return (scferror2errno(scf_error()));
519 
520 				case SCF_ERROR_NOT_BOUND:
521 				case SCF_ERROR_HANDLE_MISMATCH:
522 				case SCF_ERROR_NOT_SET:
523 				default:
524 					bad_error("scf_service_get_pg",
525 					    scf_error());
526 				}
527 			}
528 			if (r != 1) {
529 				switch (scf_error()) {
530 				case SCF_ERROR_DELETED:
531 				case SCF_ERROR_CONNECTION_BROKEN:
532 					return (scferror2errno(scf_error()));
533 
534 				case SCF_ERROR_INVALID_ARGUMENT:
535 				case SCF_ERROR_NOT_SET:
536 				case SCF_ERROR_NOT_BOUND:
537 				case SCF_ERROR_HANDLE_MISMATCH:
538 				default:
539 					bad_error("scf_iter_next_instance",
540 					    scf_error());
541 				}
542 			}
543 
544 			if (scf_instance_get_snapshot(inst, snap_running,
545 			    snap) == 0)
546 				break;
547 
548 			switch (scf_error()) {
549 			case SCF_ERROR_NOT_FOUND:
550 			case SCF_ERROR_DELETED:
551 				continue;
552 
553 			case SCF_ERROR_CONNECTION_BROKEN:
554 				return (ECONNABORTED);
555 
556 			case SCF_ERROR_HANDLE_MISMATCH:
557 			case SCF_ERROR_INVALID_ARGUMENT:
558 			case SCF_ERROR_NOT_SET:
559 			case SCF_ERROR_NOT_BOUND:
560 			default:
561 				bad_error("scf_instance_get_snapshot",
562 				    scf_error());
563 			}
564 		}
565 	} else {
566 		if (scf_instance_get_snapshot(ent, snap_running, snap) != 0) {
567 			switch (scf_error()) {
568 			case SCF_ERROR_NOT_FOUND:
569 				break;
570 
571 			case SCF_ERROR_DELETED:
572 			case SCF_ERROR_CONNECTION_BROKEN:
573 				return (scferror2errno(scf_error()));
574 
575 			case SCF_ERROR_NOT_BOUND:
576 			case SCF_ERROR_HANDLE_MISMATCH:
577 			case SCF_ERROR_INVALID_ARGUMENT:
578 			case SCF_ERROR_NOT_SET:
579 			default:
580 				bad_error("scf_instance_get_snapshot",
581 				    scf_error());
582 			}
583 
584 			if (scf_instance_get_pg(ent, name, pg) == 0)
585 				return (0);
586 
587 			switch (scf_error()) {
588 			case SCF_ERROR_DELETED:
589 			case SCF_ERROR_NOT_FOUND:
590 			case SCF_ERROR_INVALID_ARGUMENT:
591 			case SCF_ERROR_CONNECTION_BROKEN:
592 				return (scferror2errno(scf_error()));
593 
594 			case SCF_ERROR_NOT_BOUND:
595 			case SCF_ERROR_HANDLE_MISMATCH:
596 			case SCF_ERROR_NOT_SET:
597 			default:
598 				bad_error("scf_instance_get_pg", scf_error());
599 			}
600 		}
601 	}
602 
603 	r = get_snaplevel(snap, issvc, snpl);
604 	switch (r) {
605 	case 0:
606 		break;
607 
608 	case ECONNABORTED:
609 	case ECANCELED:
610 		return (r);
611 
612 	case ENOENT:
613 		return (EBADF);
614 
615 	default:
616 		bad_error("get_snaplevel", r);
617 	}
618 
619 	if (scf_snaplevel_get_pg(snpl, name, pg) == 0)
620 		return (0);
621 
622 	switch (scf_error()) {
623 	case SCF_ERROR_DELETED:
624 	case SCF_ERROR_INVALID_ARGUMENT:
625 	case SCF_ERROR_CONNECTION_BROKEN:
626 	case SCF_ERROR_NOT_FOUND:
627 		return (scferror2errno(scf_error()));
628 
629 	case SCF_ERROR_NOT_BOUND:
630 	case SCF_ERROR_HANDLE_MISMATCH:
631 	case SCF_ERROR_NOT_SET:
632 	default:
633 		bad_error("scf_snaplevel_get_pg", scf_error());
634 		/* NOTREACHED */
635 	}
636 }
637 
638 
639 /*
640  * To be registered with atexit().
641  */
642 static void
643 remove_tempfile(void)
644 {
645 	int ret;
646 
647 	if (tempfile != NULL) {
648 		if (fclose(tempfile) == EOF)
649 			warn(gettext("Could not close temporary file"));
650 		tempfile = NULL;
651 	}
652 
653 	if (tempfilename[0] != '\0') {
654 		do {
655 			ret = remove(tempfilename);
656 		} while (ret == -1 && errno == EINTR);
657 		if (ret == -1)
658 			warn(gettext("Could not remove temporary file"));
659 		tempfilename[0] = '\0';
660 	}
661 }
662 
663 /*
664  * Launch private svc.configd(1M) for manipulating alternate repositories.
665  */
666 static void
667 start_private_repository(engine_state_t *est)
668 {
669 	int fd, stat;
670 	struct door_info info;
671 	pid_t pid;
672 
673 	/*
674 	 * 1.  Create a temporary file for the door.
675 	 */
676 	if (est->sc_repo_doorname != NULL)
677 		free((void *)est->sc_repo_doorname);
678 
679 	est->sc_repo_doorname = tempnam(est->sc_repo_doordir, "scfdr");
680 	if (est->sc_repo_doorname == NULL)
681 		uu_die(gettext("Could not acquire temporary filename"));
682 
683 	fd = open(est->sc_repo_doorname, O_CREAT | O_EXCL | O_RDWR, 0600);
684 	if (fd < 0)
685 		uu_die(gettext("Could not create temporary file for "
686 		    "repository server"));
687 
688 	(void) close(fd);
689 
690 	/*
691 	 * 2.  Launch a configd with that door, using the specified
692 	 * repository.
693 	 */
694 	if ((est->sc_repo_pid = fork()) == 0) {
695 		(void) execlp(est->sc_repo_server, est->sc_repo_server, "-p",
696 		    "-d", est->sc_repo_doorname, "-r", est->sc_repo_filename,
697 		    NULL);
698 		uu_die(gettext("Could not execute %s"), est->sc_repo_server);
699 	} else if (est->sc_repo_pid == -1)
700 		uu_die(gettext("Attempt to fork failed"));
701 
702 	do {
703 		pid = waitpid(est->sc_repo_pid, &stat, 0);
704 	} while (pid == -1 && errno == EINTR);
705 
706 	if (pid == -1)
707 		uu_die(gettext("Could not waitpid() for repository server"));
708 
709 	if (!WIFEXITED(stat)) {
710 		uu_die(gettext("Repository server failed (status %d).\n"),
711 		    stat);
712 	} else if (WEXITSTATUS(stat) != 0) {
713 		uu_die(gettext("Repository server failed (exit %d).\n"),
714 		    WEXITSTATUS(stat));
715 	}
716 
717 	/*
718 	 * See if it was successful by checking if the door is a door.
719 	 */
720 
721 	fd = open(est->sc_repo_doorname, O_RDWR);
722 	if (fd < 0)
723 		uu_die(gettext("Could not open door \"%s\""),
724 		    est->sc_repo_doorname);
725 
726 	if (door_info(fd, &info) < 0)
727 		uu_die(gettext("Unexpected door_info() error"));
728 
729 	if (close(fd) == -1)
730 		warn(gettext("Could not close repository door"),
731 		    strerror(errno));
732 
733 	est->sc_repo_pid = info.di_target;
734 }
735 
736 void
737 lscf_cleanup(void)
738 {
739 	/*
740 	 * In the case where we've launched a private svc.configd(1M)
741 	 * instance, we must terminate our child and remove the temporary
742 	 * rendezvous point.
743 	 */
744 	if (est->sc_repo_pid > 0) {
745 		(void) kill(est->sc_repo_pid, SIGTERM);
746 		(void) waitpid(est->sc_repo_pid, NULL, 0);
747 		(void) unlink(est->sc_repo_doorname);
748 
749 		est->sc_repo_pid = 0;
750 	}
751 }
752 
753 void
754 unselect_cursnap(void)
755 {
756 	void *cookie;
757 
758 	cur_level = NULL;
759 
760 	cookie = NULL;
761 	while ((cur_elt = uu_list_teardown(cur_levels, &cookie)) != NULL) {
762 		scf_snaplevel_destroy(cur_elt->sl);
763 		free(cur_elt);
764 	}
765 
766 	scf_snapshot_destroy(cur_snap);
767 	cur_snap = NULL;
768 }
769 
770 void
771 lscf_prep_hndl(void)
772 {
773 	if (g_hndl != NULL)
774 		return;
775 
776 	g_hndl = scf_handle_create(SCF_VERSION);
777 	if (g_hndl == NULL)
778 		scfdie();
779 
780 	if (est->sc_repo_filename != NULL)
781 		start_private_repository(est);
782 
783 	if (est->sc_repo_doorname != NULL) {
784 		scf_value_t *repo_value;
785 		int ret;
786 
787 		repo_value = scf_value_create(g_hndl);
788 		if (repo_value == NULL)
789 			scfdie();
790 
791 		ret = scf_value_set_astring(repo_value, est->sc_repo_doorname);
792 		assert(ret == SCF_SUCCESS);
793 
794 		if (scf_handle_decorate(g_hndl, "door_path", repo_value) !=
795 		    SCF_SUCCESS)
796 			scfdie();
797 
798 		scf_value_destroy(repo_value);
799 	}
800 
801 	if (scf_handle_bind(g_hndl) != 0)
802 		uu_die(gettext("Could not connect to repository server: %s.\n"),
803 		    scf_strerror(scf_error()));
804 
805 	cur_scope = scf_scope_create(g_hndl);
806 	if (cur_scope == NULL)
807 		scfdie();
808 
809 	if (scf_handle_get_local_scope(g_hndl, cur_scope) != 0)
810 		scfdie();
811 }
812 
813 static void
814 repository_teardown(void)
815 {
816 	if (g_hndl != NULL) {
817 		if (cur_snap != NULL)
818 			unselect_cursnap();
819 		scf_instance_destroy(cur_inst);
820 		scf_service_destroy(cur_svc);
821 		scf_scope_destroy(cur_scope);
822 		scf_handle_destroy(g_hndl);
823 		cur_inst = NULL;
824 		cur_svc = NULL;
825 		cur_scope = NULL;
826 		g_hndl = NULL;
827 		lscf_cleanup();
828 	}
829 }
830 
831 void
832 lscf_set_repository(const char *repfile, int force)
833 {
834 	repository_teardown();
835 
836 	if (est->sc_repo_filename != NULL) {
837 		free((void *)est->sc_repo_filename);
838 		est->sc_repo_filename = NULL;
839 	}
840 
841 	if ((force == 0) && (access(repfile, R_OK) != 0)) {
842 		/*
843 		 * Repository file does not exist
844 		 * or has no read permission.
845 		 */
846 		warn(gettext("Cannot access \"%s\": %s\n"),
847 		    repfile, strerror(errno));
848 	} else {
849 		est->sc_repo_filename = safe_strdup(repfile);
850 	}
851 
852 	lscf_prep_hndl();
853 }
854 
855 void
856 lscf_init()
857 {
858 	if ((max_scf_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH)) < 0 ||
859 	    (max_scf_name_len = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) < 0 ||
860 	    (max_scf_pg_type_len = scf_limit(SCF_LIMIT_MAX_PG_TYPE_LENGTH)) <
861 	    0 ||
862 	    (max_scf_value_len = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH)) < 0)
863 		scfdie();
864 
865 	max_scf_len = max_scf_fmri_len;
866 	if (max_scf_name_len > max_scf_len)
867 		max_scf_len = max_scf_name_len;
868 	if (max_scf_pg_type_len > max_scf_len)
869 		max_scf_len = max_scf_pg_type_len;
870 	if (max_scf_value_len > max_scf_len)
871 		max_scf_len = max_scf_value_len;
872 
873 	if (atexit(remove_tempfile) != 0)
874 		uu_die(gettext("Could not register atexit() function"));
875 
876 	emsg_entity_not_selected = gettext("An entity is not selected.\n");
877 	emsg_permission_denied = gettext("Permission denied.\n");
878 	emsg_create_xml = gettext("Could not create XML node.\n");
879 	emsg_cant_modify_snapshots = gettext("Cannot modify snapshots.\n");
880 	emsg_read_only = gettext("Backend read-only.\n");
881 	emsg_deleted = gettext("Current selection has been deleted.\n");
882 	emsg_invalid_pg_name =
883 	    gettext("Invalid property group name \"%s\".\n");
884 	emsg_invalid_prop_name = gettext("Invalid property name \"%s\".\n");
885 	emsg_no_such_pg = gettext("No such property group \"%s\".\n");
886 	emsg_fmri_invalid_pg_name = gettext("Service %s has property group "
887 	    "with invalid name \"%s\".\n");
888 	emsg_fmri_invalid_pg_name_type = gettext("Service %s has property "
889 	    "group with invalid name \"%s\" or type \"%s\".\n");
890 	emsg_pg_added = gettext("%s changed unexpectedly "
891 	    "(property group \"%s\" added).\n");
892 	emsg_pg_changed = gettext("%s changed unexpectedly "
893 	    "(property group \"%s\" changed).\n");
894 	emsg_pg_deleted = gettext("%s changed unexpectedly "
895 	    "(property group \"%s\" or an ancestor was deleted).\n");
896 	emsg_pg_mod_perm = gettext("Could not modify property group \"%s\" "
897 	    "in %s (permission denied).\n");
898 	emsg_pg_add_perm = gettext("Could not create property group \"%s\" "
899 	    "in %s (permission denied).\n");
900 	emsg_pg_del_perm = gettext("Could not delete property group \"%s\" "
901 	    "in %s (permission denied).\n");
902 	emsg_snap_perm = gettext("Could not take \"%s\" snapshot of %s "
903 	    "(permission denied).\n");
904 	emsg_dpt_dangling = gettext("Conflict upgrading %s (not importing "
905 	    "new dependent \"%s\" because it already exists).  Warning: The "
906 	    "current dependent's target (%s) does not exist.\n");
907 	emsg_dpt_no_dep = gettext("Conflict upgrading %s (not importing new "
908 	    "dependent \"%s\" because it already exists).  Warning: The "
909 	    "current dependent's target (%s) does not have a dependency named "
910 	    "\"%s\" as expected.\n");
911 
912 	string_pool = uu_list_pool_create("strings", sizeof (string_list_t),
913 	    offsetof(string_list_t, node), NULL, 0);
914 	snaplevel_pool = uu_list_pool_create("snaplevels",
915 	    sizeof (struct snaplevel), offsetof(struct snaplevel, list_node),
916 	    NULL, 0);
917 }
918 
919 
920 static const char *
921 prop_to_typestr(const scf_property_t *prop)
922 {
923 	scf_type_t ty;
924 
925 	if (scf_property_type(prop, &ty) != SCF_SUCCESS)
926 		scfdie();
927 
928 	return (scf_type_to_string(ty));
929 }
930 
931 static scf_type_t
932 string_to_type(const char *type)
933 {
934 	size_t len = strlen(type);
935 	char *buf;
936 
937 	if (len == 0 || type[len - 1] != ':')
938 		return (SCF_TYPE_INVALID);
939 
940 	buf = (char *)alloca(len + 1);
941 	(void) strlcpy(buf, type, len + 1);
942 	buf[len - 1] = 0;
943 
944 	return (scf_string_to_type(buf));
945 }
946 
947 static scf_value_t *
948 string_to_value(const char *str, scf_type_t ty, boolean_t require_quotes)
949 {
950 	scf_value_t *v;
951 	char *dup, *nstr;
952 	size_t len;
953 
954 	v = scf_value_create(g_hndl);
955 	if (v == NULL)
956 		scfdie();
957 
958 	len = strlen(str);
959 	if (require_quotes &&
960 	    (len < 2 || str[0] != '\"' || str[len - 1] != '\"')) {
961 		semerr(gettext("Multiple string values or string values "
962 		    "with spaces must be quoted with '\"'.\n"));
963 		scf_value_destroy(v);
964 		return (NULL);
965 	}
966 
967 	nstr = dup = safe_strdup(str);
968 	if (dup[0] == '\"') {
969 		/*
970 		 * Strip out the first and the last quote.
971 		 */
972 		dup[len - 1] = '\0';
973 		nstr = dup + 1;
974 	}
975 
976 	if (scf_value_set_from_string(v, ty, (const char *)nstr) != 0) {
977 		assert(scf_error() == SCF_ERROR_INVALID_ARGUMENT);
978 		semerr(gettext("Invalid \"%s\" value \"%s\".\n"),
979 		    scf_type_to_string(ty), nstr);
980 		scf_value_destroy(v);
981 		v = NULL;
982 	}
983 	free(dup);
984 	return (v);
985 }
986 
987 /*
988  * Print str to strm, quoting double-quotes and backslashes with backslashes.
989  * Optionally append a comment prefix ('#') to newlines ('\n').
990  */
991 static int
992 quote_and_print(const char *str, FILE *strm, int commentnl)
993 {
994 	const char *cp;
995 
996 	for (cp = str; *cp != '\0'; ++cp) {
997 		if (*cp == '"' || *cp == '\\')
998 			(void) putc('\\', strm);
999 
1000 		(void) putc(*cp, strm);
1001 
1002 		if (commentnl && *cp == '\n') {
1003 			(void) putc('#', strm);
1004 		}
1005 	}
1006 
1007 	return (ferror(strm));
1008 }
1009 
1010 /*
1011  * These wrappers around lowlevel functions provide consistent error checking
1012  * and warnings.
1013  */
1014 static int
1015 pg_get_prop(scf_propertygroup_t *pg, const char *propname, scf_property_t *prop)
1016 {
1017 	if (scf_pg_get_property(pg, propname, prop) == SCF_SUCCESS)
1018 		return (0);
1019 
1020 	if (scf_error() != SCF_ERROR_NOT_FOUND)
1021 		scfdie();
1022 
1023 	if (g_verbose) {
1024 		ssize_t len;
1025 		char *fmri;
1026 
1027 		len = scf_pg_to_fmri(pg, NULL, 0);
1028 		if (len < 0)
1029 			scfdie();
1030 
1031 		fmri = safe_malloc(len + 1);
1032 
1033 		if (scf_pg_to_fmri(pg, fmri, len + 1) < 0)
1034 			scfdie();
1035 
1036 		warn(gettext("Expected property %s of property group %s is "
1037 		    "missing.\n"), propname, fmri);
1038 
1039 		free(fmri);
1040 	}
1041 
1042 	return (-1);
1043 }
1044 
1045 static int
1046 prop_check_type(scf_property_t *prop, scf_type_t ty)
1047 {
1048 	scf_type_t pty;
1049 
1050 	if (scf_property_type(prop, &pty) != SCF_SUCCESS)
1051 		scfdie();
1052 
1053 	if (ty == pty)
1054 		return (0);
1055 
1056 	if (g_verbose) {
1057 		ssize_t len;
1058 		char *fmri;
1059 		const char *tystr;
1060 
1061 		len = scf_property_to_fmri(prop, NULL, 0);
1062 		if (len < 0)
1063 			scfdie();
1064 
1065 		fmri = safe_malloc(len + 1);
1066 
1067 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1068 			scfdie();
1069 
1070 		tystr = scf_type_to_string(ty);
1071 		if (tystr == NULL)
1072 			tystr = "?";
1073 
1074 		warn(gettext("Property %s is not of expected type %s.\n"),
1075 		    fmri, tystr);
1076 
1077 		free(fmri);
1078 	}
1079 
1080 	return (-1);
1081 }
1082 
1083 static int
1084 prop_get_val(scf_property_t *prop, scf_value_t *val)
1085 {
1086 	scf_error_t err;
1087 
1088 	if (scf_property_get_value(prop, val) == SCF_SUCCESS)
1089 		return (0);
1090 
1091 	err = scf_error();
1092 
1093 	if (err != SCF_ERROR_NOT_FOUND &&
1094 	    err != SCF_ERROR_CONSTRAINT_VIOLATED &&
1095 	    err != SCF_ERROR_PERMISSION_DENIED)
1096 		scfdie();
1097 
1098 	if (g_verbose) {
1099 		ssize_t len;
1100 		char *fmri, *emsg;
1101 
1102 		len = scf_property_to_fmri(prop, NULL, 0);
1103 		if (len < 0)
1104 			scfdie();
1105 
1106 		fmri = safe_malloc(len + 1);
1107 
1108 		if (scf_property_to_fmri(prop, fmri, len + 1) < 0)
1109 			scfdie();
1110 
1111 		if (err == SCF_ERROR_NOT_FOUND)
1112 			emsg = gettext("Property %s has no values; expected "
1113 			    "one.\n");
1114 		else if (err == SCF_ERROR_CONSTRAINT_VIOLATED)
1115 			emsg = gettext("Property %s has multiple values; "
1116 			    "expected one.\n");
1117 		else
1118 			emsg = gettext("No permission to read property %s.\n");
1119 
1120 		warn(emsg, fmri);
1121 
1122 		free(fmri);
1123 	}
1124 
1125 	return (-1);
1126 }
1127 
1128 
1129 static boolean_t
1130 snaplevel_is_instance(const scf_snaplevel_t *level)
1131 {
1132 	if (scf_snaplevel_get_instance_name(level, NULL, 0) < 0) {
1133 		if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED)
1134 			scfdie();
1135 		return (0);
1136 	} else {
1137 		return (1);
1138 	}
1139 }
1140 
1141 /*
1142  * Decode FMRI into a service or instance, and put the result in *ep.  If
1143  * memory cannot be allocated, return SCF_ERROR_NO_MEMORY.  If the FMRI is
1144  * invalid, return SCF_ERROR_INVALID_ARGUMENT.  If the FMRI does not specify
1145  * an entity, return SCF_ERROR_CONSTRAINT_VIOLATED.  If the entity cannot be
1146  * found, return SCF_ERROR_NOT_FOUND.  Otherwise return SCF_ERROR_NONE, point
1147  * *ep to a valid scf_service_t or scf_instance_t, and set *isservice to
1148  * whether *ep is a service.
1149  */
1150 static scf_error_t
1151 fmri_to_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservice)
1152 {
1153 	char *fmri_copy;
1154 	const char *sstr, *istr, *pgstr;
1155 	scf_service_t *svc;
1156 	scf_instance_t *inst;
1157 
1158 	fmri_copy = strdup(fmri);
1159 	if (fmri_copy == NULL)
1160 		return (SCF_ERROR_NO_MEMORY);
1161 
1162 	if (scf_parse_svc_fmri(fmri_copy, NULL, &sstr, &istr, &pgstr, NULL) !=
1163 	    SCF_SUCCESS) {
1164 		free(fmri_copy);
1165 		return (SCF_ERROR_INVALID_ARGUMENT);
1166 	}
1167 
1168 	free(fmri_copy);
1169 
1170 	if (sstr == NULL || pgstr != NULL)
1171 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1172 
1173 	if (istr == NULL) {
1174 		svc = scf_service_create(h);
1175 		if (svc == NULL)
1176 			return (SCF_ERROR_NO_MEMORY);
1177 
1178 		if (scf_handle_decode_fmri(h, fmri, NULL, svc, NULL, NULL, NULL,
1179 		    SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1180 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1181 				scfdie();
1182 
1183 			return (SCF_ERROR_NOT_FOUND);
1184 		}
1185 
1186 		*ep = svc;
1187 		*isservice = 1;
1188 	} else {
1189 		inst = scf_instance_create(h);
1190 		if (inst == NULL)
1191 			return (SCF_ERROR_NO_MEMORY);
1192 
1193 		if (scf_handle_decode_fmri(h, fmri, NULL, NULL, inst, NULL,
1194 		    NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS) {
1195 			if (scf_error() != SCF_ERROR_NOT_FOUND)
1196 				scfdie();
1197 
1198 			return (SCF_ERROR_NOT_FOUND);
1199 		}
1200 
1201 		*ep = inst;
1202 		*isservice = 0;
1203 	}
1204 
1205 	return (SCF_ERROR_NONE);
1206 }
1207 
1208 /*
1209  * Create the entity named by fmri.  Place a pointer to its libscf handle in
1210  * *ep, and set or clear *isservicep if it is a service or an instance.
1211  * Returns
1212  *   SCF_ERROR_NONE - success
1213  *   SCF_ERROR_NO_MEMORY - scf_*_create() failed
1214  *   SCF_ERROR_INVALID_ARGUMENT - fmri is invalid
1215  *   SCF_ERROR_CONSTRAINT_VIOLATED - fmri is not a service or instance
1216  *   SCF_ERROR_NOT_FOUND - no such scope
1217  *   SCF_ERROR_PERMISSION_DENIED
1218  *   SCF_ERROR_BACKEND_READONLY
1219  *   SCF_ERROR_BACKEND_ACCESS
1220  */
1221 static scf_error_t
1222 create_entity(scf_handle_t *h, const char *fmri, void **ep, int *isservicep)
1223 {
1224 	char *fmri_copy;
1225 	const char *scstr, *sstr, *istr, *pgstr;
1226 	scf_scope_t *scope = NULL;
1227 	scf_service_t *svc = NULL;
1228 	scf_instance_t *inst = NULL;
1229 	scf_error_t scfe;
1230 
1231 	fmri_copy = safe_strdup(fmri);
1232 
1233 	if (scf_parse_svc_fmri(fmri_copy, &scstr, &sstr, &istr, &pgstr, NULL) !=
1234 	    0) {
1235 		free(fmri_copy);
1236 		return (SCF_ERROR_INVALID_ARGUMENT);
1237 	}
1238 
1239 	if (scstr == NULL || sstr == NULL || pgstr != NULL) {
1240 		free(fmri_copy);
1241 		return (SCF_ERROR_CONSTRAINT_VIOLATED);
1242 	}
1243 
1244 	*ep = NULL;
1245 
1246 	if ((scope = scf_scope_create(h)) == NULL ||
1247 	    (svc = scf_service_create(h)) == NULL ||
1248 	    (inst = scf_instance_create(h)) == NULL) {
1249 		scfe = SCF_ERROR_NO_MEMORY;
1250 		goto out;
1251 	}
1252 
1253 get_scope:
1254 	if (scf_handle_get_scope(h, scstr, scope) != 0) {
1255 		switch (scf_error()) {
1256 		case SCF_ERROR_CONNECTION_BROKEN:
1257 			scfdie();
1258 			/* NOTREACHED */
1259 
1260 		case SCF_ERROR_NOT_FOUND:
1261 			scfe = SCF_ERROR_NOT_FOUND;
1262 			goto out;
1263 
1264 		case SCF_ERROR_HANDLE_MISMATCH:
1265 		case SCF_ERROR_NOT_BOUND:
1266 		case SCF_ERROR_INVALID_ARGUMENT:
1267 		default:
1268 			bad_error("scf_handle_get_scope", scf_error());
1269 		}
1270 	}
1271 
1272 get_svc:
1273 	if (scf_scope_get_service(scope, sstr, svc) != 0) {
1274 		switch (scf_error()) {
1275 		case SCF_ERROR_CONNECTION_BROKEN:
1276 			scfdie();
1277 			/* NOTREACHED */
1278 
1279 		case SCF_ERROR_DELETED:
1280 			goto get_scope;
1281 
1282 		case SCF_ERROR_NOT_FOUND:
1283 			break;
1284 
1285 		case SCF_ERROR_HANDLE_MISMATCH:
1286 		case SCF_ERROR_INVALID_ARGUMENT:
1287 		case SCF_ERROR_NOT_BOUND:
1288 		case SCF_ERROR_NOT_SET:
1289 		default:
1290 			bad_error("scf_scope_get_service", scf_error());
1291 		}
1292 
1293 		if (scf_scope_add_service(scope, sstr, svc) != 0) {
1294 			switch (scf_error()) {
1295 			case SCF_ERROR_CONNECTION_BROKEN:
1296 				scfdie();
1297 				/* NOTREACHED */
1298 
1299 			case SCF_ERROR_DELETED:
1300 				goto get_scope;
1301 
1302 			case SCF_ERROR_PERMISSION_DENIED:
1303 			case SCF_ERROR_BACKEND_READONLY:
1304 			case SCF_ERROR_BACKEND_ACCESS:
1305 				scfe = scf_error();
1306 				goto out;
1307 
1308 			case SCF_ERROR_HANDLE_MISMATCH:
1309 			case SCF_ERROR_INVALID_ARGUMENT:
1310 			case SCF_ERROR_NOT_BOUND:
1311 			case SCF_ERROR_NOT_SET:
1312 			default:
1313 				bad_error("scf_scope_get_service", scf_error());
1314 			}
1315 		}
1316 	}
1317 
1318 	if (istr == NULL) {
1319 		scfe = SCF_ERROR_NONE;
1320 		*ep = svc;
1321 		*isservicep = 1;
1322 		goto out;
1323 	}
1324 
1325 get_inst:
1326 	if (scf_service_get_instance(svc, istr, inst) != 0) {
1327 		switch (scf_error()) {
1328 		case SCF_ERROR_CONNECTION_BROKEN:
1329 			scfdie();
1330 			/* NOTREACHED */
1331 
1332 		case SCF_ERROR_DELETED:
1333 			goto get_svc;
1334 
1335 		case SCF_ERROR_NOT_FOUND:
1336 			break;
1337 
1338 		case SCF_ERROR_HANDLE_MISMATCH:
1339 		case SCF_ERROR_INVALID_ARGUMENT:
1340 		case SCF_ERROR_NOT_BOUND:
1341 		case SCF_ERROR_NOT_SET:
1342 		default:
1343 			bad_error("scf_service_get_instance", scf_error());
1344 		}
1345 
1346 		if (scf_service_add_instance(svc, istr, inst) != 0) {
1347 			switch (scf_error()) {
1348 			case SCF_ERROR_CONNECTION_BROKEN:
1349 				scfdie();
1350 				/* NOTREACHED */
1351 
1352 			case SCF_ERROR_DELETED:
1353 				goto get_svc;
1354 
1355 			case SCF_ERROR_PERMISSION_DENIED:
1356 			case SCF_ERROR_BACKEND_READONLY:
1357 			case SCF_ERROR_BACKEND_ACCESS:
1358 				scfe = scf_error();
1359 				goto out;
1360 
1361 			case SCF_ERROR_HANDLE_MISMATCH:
1362 			case SCF_ERROR_INVALID_ARGUMENT:
1363 			case SCF_ERROR_NOT_BOUND:
1364 			case SCF_ERROR_NOT_SET:
1365 			default:
1366 				bad_error("scf_service_add_instance",
1367 				    scf_error());
1368 			}
1369 		}
1370 	}
1371 
1372 	scfe = SCF_ERROR_NONE;
1373 	*ep = inst;
1374 	*isservicep = 0;
1375 
1376 out:
1377 	if (*ep != inst)
1378 		scf_instance_destroy(inst);
1379 	if (*ep != svc)
1380 		scf_service_destroy(svc);
1381 	scf_scope_destroy(scope);
1382 	free(fmri_copy);
1383 	return (scfe);
1384 }
1385 
1386 /*
1387  * Create or update a snapshot of inst.  snap is a required scratch object.
1388  *
1389  * Returns
1390  *   0 - success
1391  *   ECONNABORTED - repository connection broken
1392  *   EPERM - permission denied
1393  *   ENOSPC - configd is out of resources
1394  *   ECANCELED - inst was deleted
1395  *   -1 - unknown libscf error (message printed)
1396  */
1397 static int
1398 take_snap(scf_instance_t *inst, const char *name, scf_snapshot_t *snap)
1399 {
1400 again:
1401 	if (scf_instance_get_snapshot(inst, name, snap) == 0) {
1402 		if (_scf_snapshot_take_attach(inst, snap) != 0) {
1403 			switch (scf_error()) {
1404 			case SCF_ERROR_CONNECTION_BROKEN:
1405 			case SCF_ERROR_PERMISSION_DENIED:
1406 			case SCF_ERROR_NO_RESOURCES:
1407 				return (scferror2errno(scf_error()));
1408 
1409 			case SCF_ERROR_NOT_SET:
1410 			case SCF_ERROR_INVALID_ARGUMENT:
1411 			default:
1412 				bad_error("_scf_snapshot_take_attach",
1413 				    scf_error());
1414 			}
1415 		}
1416 	} else {
1417 		switch (scf_error()) {
1418 		case SCF_ERROR_NOT_FOUND:
1419 			break;
1420 
1421 		case SCF_ERROR_DELETED:
1422 		case SCF_ERROR_CONNECTION_BROKEN:
1423 			return (scferror2errno(scf_error()));
1424 
1425 		case SCF_ERROR_HANDLE_MISMATCH:
1426 		case SCF_ERROR_NOT_BOUND:
1427 		case SCF_ERROR_INVALID_ARGUMENT:
1428 		case SCF_ERROR_NOT_SET:
1429 		default:
1430 			bad_error("scf_instance_get_snapshot", scf_error());
1431 		}
1432 
1433 		if (_scf_snapshot_take_new(inst, name, snap) != 0) {
1434 			switch (scf_error()) {
1435 			case SCF_ERROR_EXISTS:
1436 				goto again;
1437 
1438 			case SCF_ERROR_CONNECTION_BROKEN:
1439 			case SCF_ERROR_NO_RESOURCES:
1440 			case SCF_ERROR_PERMISSION_DENIED:
1441 				return (scferror2errno(scf_error()));
1442 
1443 			default:
1444 				scfwarn();
1445 				return (-1);
1446 
1447 			case SCF_ERROR_NOT_SET:
1448 			case SCF_ERROR_INTERNAL:
1449 			case SCF_ERROR_INVALID_ARGUMENT:
1450 			case SCF_ERROR_HANDLE_MISMATCH:
1451 				bad_error("_scf_snapshot_take_new",
1452 				    scf_error());
1453 			}
1454 		}
1455 	}
1456 
1457 	return (0);
1458 }
1459 
1460 static int
1461 refresh_running_snapshot(void *entity) {
1462 	scf_snapshot_t *snap;
1463 	int r;
1464 
1465 	if ((snap = scf_snapshot_create(g_hndl)) == NULL)
1466 		scfdie();
1467 	r = take_snap(entity, snap_running, snap);
1468 	scf_snapshot_destroy(snap);
1469 
1470 	return (r);
1471 }
1472 
1473 /*
1474  * Refresh entity.  If isservice is zero, take entity to be an scf_instance_t *.
1475  * Otherwise take entity to be an scf_service_t * and refresh all of its child
1476  * instances.  fmri is used for messages.  inst, iter, and name_buf are used
1477  * for scratch space.  Returns
1478  *   0 - success
1479  *   ECONNABORTED - repository connection broken
1480  *   ECANCELED - entity was deleted
1481  *   EACCES - backend denied access
1482  *   EPERM - permission denied
1483  *   ENOSPC - repository server out of resources
1484  *   -1 - _smf_refresh_instance_i() failed.  scf_error() should be set.
1485  */
1486 static int
1487 refresh_entity(int isservice, void *entity, const char *fmri,
1488     scf_instance_t *inst, scf_iter_t *iter, char *name_buf)
1489 {
1490 	scf_error_t scfe;
1491 	int r;
1492 
1493 	if (!isservice) {
1494 		if (est->sc_repo_filename == NULL) {
1495 			if (_smf_refresh_instance_i(entity) == 0) {
1496 				if (g_verbose)
1497 					warn(gettext("Refreshed %s.\n"), fmri);
1498 				return (0);
1499 			}
1500 
1501 			switch (scf_error()) {
1502 			case SCF_ERROR_BACKEND_ACCESS:
1503 				return (EACCES);
1504 
1505 			case SCF_ERROR_PERMISSION_DENIED:
1506 				return (EPERM);
1507 
1508 			default:
1509 				return (-1);
1510 			}
1511 		} else {
1512 			r = refresh_running_snapshot(entity);
1513 			switch (r) {
1514 			case 0:
1515 				break;
1516 
1517 			case ECONNABORTED:
1518 			case ECANCELED:
1519 			case EPERM:
1520 			case ENOSPC:
1521 				break;
1522 
1523 			default:
1524 				bad_error("refresh_running_snapshot",
1525 				    scf_error());
1526 			}
1527 
1528 			return (r);
1529 		}
1530 	}
1531 
1532 	if (scf_iter_service_instances(iter, entity) != 0) {
1533 		switch (scf_error()) {
1534 		case SCF_ERROR_CONNECTION_BROKEN:
1535 			return (ECONNABORTED);
1536 
1537 		case SCF_ERROR_DELETED:
1538 			return (ECANCELED);
1539 
1540 		case SCF_ERROR_HANDLE_MISMATCH:
1541 		case SCF_ERROR_NOT_BOUND:
1542 		case SCF_ERROR_NOT_SET:
1543 		default:
1544 			bad_error("scf_iter_service_instances", scf_error());
1545 		}
1546 	}
1547 
1548 	for (;;) {
1549 		r = scf_iter_next_instance(iter, inst);
1550 		if (r == 0)
1551 			break;
1552 		if (r != 1) {
1553 			switch (scf_error()) {
1554 			case SCF_ERROR_CONNECTION_BROKEN:
1555 				return (ECONNABORTED);
1556 
1557 			case SCF_ERROR_DELETED:
1558 				return (ECANCELED);
1559 
1560 			case SCF_ERROR_HANDLE_MISMATCH:
1561 			case SCF_ERROR_NOT_BOUND:
1562 			case SCF_ERROR_NOT_SET:
1563 			case SCF_ERROR_INVALID_ARGUMENT:
1564 			default:
1565 				bad_error("scf_iter_next_instance",
1566 				    scf_error());
1567 			}
1568 		}
1569 
1570 		if (est->sc_repo_filename != NULL) {
1571 			r = refresh_running_snapshot(inst);
1572 			switch (r) {
1573 			case 0:
1574 				continue;
1575 
1576 			case ECONNABORTED:
1577 			case ECANCELED:
1578 			case EPERM:
1579 			case ENOSPC:
1580 				break;
1581 			default:
1582 				bad_error("refresh_running_snapshot",
1583 				    scf_error());
1584 			}
1585 
1586 			return (r);
1587 
1588 		}
1589 
1590 		if (_smf_refresh_instance_i(inst) == 0) {
1591 			if (g_verbose) {
1592 				if (scf_instance_get_name(inst, name_buf,
1593 				    max_scf_name_len + 1) < 0)
1594 					(void) strcpy(name_buf, "?");
1595 
1596 				warn(gettext("Refreshed %s:%s.\n"),
1597 				    fmri, name_buf);
1598 			}
1599 		} else {
1600 			if (scf_error() != SCF_ERROR_BACKEND_ACCESS ||
1601 			    g_verbose) {
1602 				scfe = scf_error();
1603 
1604 				if (scf_instance_to_fmri(inst, name_buf,
1605 				    max_scf_name_len + 1) < 0)
1606 					(void) strcpy(name_buf, "?");
1607 
1608 				warn(gettext(
1609 				    "Refresh of %s:%s failed: %s.\n"), fmri,
1610 				    name_buf, scf_strerror(scfe));
1611 			}
1612 		}
1613 	}
1614 
1615 	return (0);
1616 }
1617 
1618 static void
1619 private_refresh(void)
1620 {
1621 	scf_instance_t *pinst = NULL;
1622 	scf_iter_t *piter = NULL;
1623 	ssize_t fmrilen;
1624 	size_t bufsz;
1625 	char *fmribuf;
1626 	void *ent;
1627 	int issvc;
1628 	int r;
1629 
1630 	if (est->sc_repo_filename == NULL)
1631 		return;
1632 
1633 	assert(cur_svc != NULL);
1634 
1635 	bufsz = max_scf_fmri_len + 1;
1636 	fmribuf = safe_malloc(bufsz);
1637 	if (cur_inst) {
1638 		issvc = 0;
1639 		ent = cur_inst;
1640 		fmrilen = scf_instance_to_fmri(ent, fmribuf, bufsz);
1641 	} else {
1642 		issvc = 1;
1643 		ent = cur_svc;
1644 		fmrilen = scf_service_to_fmri(ent, fmribuf, bufsz);
1645 		if ((pinst = scf_instance_create(g_hndl)) == NULL)
1646 			scfdie();
1647 
1648 		if ((piter = scf_iter_create(g_hndl)) == NULL)
1649 			scfdie();
1650 	}
1651 	if (fmrilen < 0) {
1652 		free(fmribuf);
1653 		if (scf_error() != SCF_ERROR_DELETED)
1654 			scfdie();
1655 
1656 		warn(emsg_deleted);
1657 		return;
1658 	}
1659 	assert(fmrilen < bufsz);
1660 
1661 	r = refresh_entity(issvc, ent, fmribuf, pinst, piter, NULL);
1662 	switch (r) {
1663 	case 0:
1664 		break;
1665 
1666 	case ECONNABORTED:
1667 		warn(gettext("Could not refresh %s "
1668 		    "(repository connection broken).\n"), fmribuf);
1669 		break;
1670 
1671 	case ECANCELED:
1672 		warn(emsg_deleted);
1673 		break;
1674 
1675 	case EPERM:
1676 		warn(gettext("Could not refresh %s "
1677 		    "(permission denied).\n"), fmribuf);
1678 		break;
1679 
1680 	case ENOSPC:
1681 		warn(gettext("Could not refresh %s "
1682 		    "(repository server out of resources).\n"),
1683 		    fmribuf);
1684 		break;
1685 
1686 	case EACCES:
1687 	default:
1688 		bad_error("refresh_entity", scf_error());
1689 	}
1690 
1691 	if (issvc) {
1692 		scf_instance_destroy(pinst);
1693 		scf_iter_destroy(piter);
1694 	}
1695 
1696 	free(fmribuf);
1697 }
1698 
1699 
1700 static int
1701 stash_scferror_err(scf_callback_t *cbp, scf_error_t err)
1702 {
1703 	cbp->sc_err = scferror2errno(err);
1704 	return (UU_WALK_ERROR);
1705 }
1706 
1707 static int
1708 stash_scferror(scf_callback_t *cbp)
1709 {
1710 	return (stash_scferror_err(cbp, scf_error()));
1711 }
1712 
1713 /*
1714  * Import.  These functions import a bundle into the repository.
1715  */
1716 
1717 /*
1718  * Add a transaction entry to lcbdata->sc_trans for this property_t.  Uses
1719  * sc_handle, sc_trans, and sc_flags (SCI_NOENABLED) in lcbdata.  On success,
1720  * returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1721  * lcbdata->sc_err to
1722  *   ENOMEM - out of memory
1723  *   ECONNABORTED - repository connection broken
1724  *   ECANCELED - sc_trans's property group was deleted
1725  *   EINVAL - p's name is invalid (error printed)
1726  *	    - p has an invalid value (error printed)
1727  */
1728 static int
1729 lscf_property_import(void *v, void *pvt)
1730 {
1731 	property_t *p = v;
1732 	scf_callback_t *lcbdata = pvt;
1733 	value_t *vp;
1734 	scf_transaction_t *trans = lcbdata->sc_trans;
1735 	scf_transaction_entry_t *entr;
1736 	scf_value_t *val;
1737 	scf_type_t tp;
1738 
1739 	if ((lcbdata->sc_flags & SCI_NOENABLED ||
1740 	    lcbdata->sc_flags & SCI_DELAYENABLE) &&
1741 	    strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) == 0) {
1742 		lcbdata->sc_enable = p;
1743 		return (UU_WALK_NEXT);
1744 	}
1745 
1746 	entr = scf_entry_create(lcbdata->sc_handle);
1747 	if (entr == NULL) {
1748 		switch (scf_error()) {
1749 		case SCF_ERROR_NO_MEMORY:
1750 			return (stash_scferror(lcbdata));
1751 
1752 		case SCF_ERROR_INVALID_ARGUMENT:
1753 		default:
1754 			bad_error("scf_entry_create", scf_error());
1755 		}
1756 	}
1757 
1758 	tp = p->sc_value_type;
1759 
1760 	if (scf_transaction_property_new(trans, entr,
1761 	    p->sc_property_name, tp) != 0) {
1762 		switch (scf_error()) {
1763 		case SCF_ERROR_INVALID_ARGUMENT:
1764 			semerr(emsg_invalid_prop_name, p->sc_property_name);
1765 			scf_entry_destroy(entr);
1766 			return (stash_scferror(lcbdata));
1767 
1768 		case SCF_ERROR_EXISTS:
1769 			break;
1770 
1771 		case SCF_ERROR_DELETED:
1772 		case SCF_ERROR_CONNECTION_BROKEN:
1773 			scf_entry_destroy(entr);
1774 			return (stash_scferror(lcbdata));
1775 
1776 		case SCF_ERROR_NOT_BOUND:
1777 		case SCF_ERROR_HANDLE_MISMATCH:
1778 		case SCF_ERROR_NOT_SET:
1779 		default:
1780 			bad_error("scf_transaction_property_new", scf_error());
1781 		}
1782 
1783 		if (scf_transaction_property_change_type(trans, entr,
1784 		    p->sc_property_name, tp) != 0) {
1785 			switch (scf_error()) {
1786 			case SCF_ERROR_DELETED:
1787 			case SCF_ERROR_CONNECTION_BROKEN:
1788 				scf_entry_destroy(entr);
1789 				return (stash_scferror(lcbdata));
1790 
1791 			case SCF_ERROR_INVALID_ARGUMENT:
1792 				semerr(emsg_invalid_prop_name,
1793 				    p->sc_property_name);
1794 				scf_entry_destroy(entr);
1795 				return (stash_scferror(lcbdata));
1796 
1797 			case SCF_ERROR_NOT_FOUND:
1798 			case SCF_ERROR_NOT_SET:
1799 			case SCF_ERROR_HANDLE_MISMATCH:
1800 			case SCF_ERROR_NOT_BOUND:
1801 			default:
1802 				bad_error(
1803 				    "scf_transaction_property_change_type",
1804 				    scf_error());
1805 			}
1806 		}
1807 	}
1808 
1809 	for (vp = uu_list_first(p->sc_property_values);
1810 	    vp != NULL;
1811 	    vp = uu_list_next(p->sc_property_values, vp)) {
1812 		val = scf_value_create(g_hndl);
1813 		if (val == NULL) {
1814 			switch (scf_error()) {
1815 			case SCF_ERROR_NO_MEMORY:
1816 				return (stash_scferror(lcbdata));
1817 
1818 			case SCF_ERROR_INVALID_ARGUMENT:
1819 			default:
1820 				bad_error("scf_value_create", scf_error());
1821 			}
1822 		}
1823 
1824 		switch (tp) {
1825 		case SCF_TYPE_BOOLEAN:
1826 			scf_value_set_boolean(val, vp->sc_u.sc_count);
1827 			break;
1828 		case SCF_TYPE_COUNT:
1829 			scf_value_set_count(val, vp->sc_u.sc_count);
1830 			break;
1831 		case SCF_TYPE_INTEGER:
1832 			scf_value_set_integer(val, vp->sc_u.sc_integer);
1833 			break;
1834 		default:
1835 			assert(vp->sc_u.sc_string != NULL);
1836 			if (scf_value_set_from_string(val, tp,
1837 			    vp->sc_u.sc_string) != 0) {
1838 				if (scf_error() != SCF_ERROR_INVALID_ARGUMENT)
1839 					bad_error("scf_value_set_from_string",
1840 					    scf_error());
1841 
1842 				warn(gettext("Value \"%s\" is not a valid "
1843 				    "%s.\n"), vp->sc_u.sc_string,
1844 				    scf_type_to_string(tp));
1845 				scf_value_destroy(val);
1846 				return (stash_scferror(lcbdata));
1847 			}
1848 			break;
1849 		}
1850 
1851 		if (scf_entry_add_value(entr, val) != 0)
1852 			bad_error("scf_entry_add_value", scf_error());
1853 	}
1854 
1855 	return (UU_WALK_NEXT);
1856 }
1857 
1858 /*
1859  * Import a pgroup_t into the repository.  Uses sc_handle, sc_parent,
1860  * sc_service, sc_flags (SCI_GENERALLAST, SCI_FORCE, & SCI_KEEP),
1861  * sc_source_fmri, and sc_target_fmri in lcbdata, and uses imp_pg and imp_tx.
1862  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
1863  * lcbdata->sc_err to
1864  *   ECONNABORTED - repository connection broken
1865  *   ENOMEM - out of memory
1866  *   ENOSPC - svc.configd is out of resources
1867  *   ECANCELED - sc_parent was deleted
1868  *   EPERM - could not create property group (permission denied) (error printed)
1869  *	   - could not modify property group (permission denied) (error printed)
1870  *	   - could not delete property group (permission denied) (error	printed)
1871  *   EROFS - could not create property group (repository is read-only)
1872  *	   - could not delete property group (repository is read-only)
1873  *   EACCES - could not create property group (backend access denied)
1874  *	    - could not delete property group (backend access denied)
1875  *   EEXIST - could not create property group (already exists)
1876  *   EINVAL - invalid property group name (error printed)
1877  *	    - invalid property name (error printed)
1878  *	    - invalid value (error printed)
1879  *   EBUSY - new property group deleted (error printed)
1880  *	   - new property group changed (error printed)
1881  *	   - property group added (error printed)
1882  *	   - property group deleted (error printed)
1883  */
1884 static int
1885 entity_pgroup_import(void *v, void *pvt)
1886 {
1887 	pgroup_t *p = v;
1888 	scf_callback_t cbdata;
1889 	scf_callback_t *lcbdata = pvt;
1890 	void *ent = lcbdata->sc_parent;
1891 	int issvc = lcbdata->sc_service;
1892 	int r;
1893 
1894 	const char * const pg_changed = gettext("%s changed unexpectedly "
1895 	    "(new property group \"%s\" changed).\n");
1896 
1897 	/* Never import deleted property groups. */
1898 	if (p->sc_pgroup_delete)
1899 		return (UU_WALK_NEXT);
1900 
1901 	if (!issvc && (lcbdata->sc_flags & SCI_GENERALLAST) &&
1902 	    strcmp(p->sc_pgroup_name, SCF_PG_GENERAL) == 0) {
1903 		lcbdata->sc_general = p;
1904 		return (UU_WALK_NEXT);
1905 	}
1906 
1907 add_pg:
1908 	if (issvc)
1909 		r = scf_service_add_pg(ent, p->sc_pgroup_name,
1910 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1911 	else
1912 		r = scf_instance_add_pg(ent, p->sc_pgroup_name,
1913 		    p->sc_pgroup_type, p->sc_pgroup_flags, imp_pg);
1914 	if (r != 0) {
1915 		switch (scf_error()) {
1916 		case SCF_ERROR_DELETED:
1917 		case SCF_ERROR_CONNECTION_BROKEN:
1918 		case SCF_ERROR_BACKEND_READONLY:
1919 		case SCF_ERROR_BACKEND_ACCESS:
1920 		case SCF_ERROR_NO_RESOURCES:
1921 			return (stash_scferror(lcbdata));
1922 
1923 		case SCF_ERROR_EXISTS:
1924 			if (lcbdata->sc_flags & SCI_FORCE)
1925 				break;
1926 			return (stash_scferror(lcbdata));
1927 
1928 		case SCF_ERROR_INVALID_ARGUMENT:
1929 			warn(emsg_fmri_invalid_pg_name_type,
1930 			    lcbdata->sc_source_fmri,
1931 			    p->sc_pgroup_name, p->sc_pgroup_type);
1932 			return (stash_scferror(lcbdata));
1933 
1934 		case SCF_ERROR_PERMISSION_DENIED:
1935 			warn(emsg_pg_add_perm, p->sc_pgroup_name,
1936 			    lcbdata->sc_target_fmri);
1937 			return (stash_scferror(lcbdata));
1938 
1939 		case SCF_ERROR_NOT_BOUND:
1940 		case SCF_ERROR_HANDLE_MISMATCH:
1941 		case SCF_ERROR_NOT_SET:
1942 		default:
1943 			bad_error("scf_service_add_pg", scf_error());
1944 		}
1945 
1946 		if (entity_get_pg(ent, issvc, p->sc_pgroup_name, imp_pg) != 0) {
1947 			switch (scf_error()) {
1948 			case SCF_ERROR_CONNECTION_BROKEN:
1949 			case SCF_ERROR_DELETED:
1950 				return (stash_scferror(lcbdata));
1951 
1952 			case SCF_ERROR_INVALID_ARGUMENT:
1953 				warn(emsg_fmri_invalid_pg_name,
1954 				    lcbdata->sc_source_fmri,
1955 				    p->sc_pgroup_name);
1956 				return (stash_scferror(lcbdata));
1957 
1958 			case SCF_ERROR_NOT_FOUND:
1959 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
1960 				    p->sc_pgroup_name);
1961 				lcbdata->sc_err = EBUSY;
1962 				return (UU_WALK_ERROR);
1963 
1964 			case SCF_ERROR_NOT_BOUND:
1965 			case SCF_ERROR_HANDLE_MISMATCH:
1966 			case SCF_ERROR_NOT_SET:
1967 			default:
1968 				bad_error("entity_get_pg", scf_error());
1969 			}
1970 		}
1971 
1972 		if (lcbdata->sc_flags & SCI_KEEP)
1973 			goto props;
1974 
1975 		if (scf_pg_delete(imp_pg) != 0) {
1976 			switch (scf_error()) {
1977 			case SCF_ERROR_DELETED:
1978 				warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
1979 				    p->sc_pgroup_name);
1980 				lcbdata->sc_err = EBUSY;
1981 				return (UU_WALK_ERROR);
1982 
1983 			case SCF_ERROR_PERMISSION_DENIED:
1984 				warn(emsg_pg_del_perm, p->sc_pgroup_name,
1985 				    lcbdata->sc_target_fmri);
1986 				return (stash_scferror(lcbdata));
1987 
1988 			case SCF_ERROR_BACKEND_READONLY:
1989 			case SCF_ERROR_BACKEND_ACCESS:
1990 			case SCF_ERROR_CONNECTION_BROKEN:
1991 				return (stash_scferror(lcbdata));
1992 
1993 			case SCF_ERROR_NOT_SET:
1994 			default:
1995 				bad_error("scf_pg_delete", scf_error());
1996 			}
1997 		}
1998 
1999 		goto add_pg;
2000 	}
2001 
2002 props:
2003 
2004 	/*
2005 	 * Add properties to property group, if any.
2006 	 */
2007 	cbdata.sc_handle = lcbdata->sc_handle;
2008 	cbdata.sc_parent = imp_pg;
2009 	cbdata.sc_flags = lcbdata->sc_flags;
2010 	cbdata.sc_trans = imp_tx;
2011 	cbdata.sc_enable = NULL;
2012 
2013 	if (scf_transaction_start(imp_tx, imp_pg) != 0) {
2014 		switch (scf_error()) {
2015 		case SCF_ERROR_BACKEND_ACCESS:
2016 		case SCF_ERROR_BACKEND_READONLY:
2017 		case SCF_ERROR_CONNECTION_BROKEN:
2018 			return (stash_scferror(lcbdata));
2019 
2020 		case SCF_ERROR_DELETED:
2021 			warn(pg_changed, lcbdata->sc_target_fmri,
2022 			    p->sc_pgroup_name);
2023 			lcbdata->sc_err = EBUSY;
2024 			return (UU_WALK_ERROR);
2025 
2026 		case SCF_ERROR_PERMISSION_DENIED:
2027 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2028 			    lcbdata->sc_target_fmri);
2029 			return (stash_scferror(lcbdata));
2030 
2031 		case SCF_ERROR_NOT_BOUND:
2032 		case SCF_ERROR_NOT_SET:
2033 		case SCF_ERROR_IN_USE:
2034 		case SCF_ERROR_HANDLE_MISMATCH:
2035 		default:
2036 			bad_error("scf_transaction_start", scf_error());
2037 		}
2038 	}
2039 
2040 	if (uu_list_walk(p->sc_pgroup_props, lscf_property_import, &cbdata,
2041 	    UU_DEFAULT) != 0) {
2042 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2043 			bad_error("uu_list_walk", uu_error());
2044 		scf_transaction_reset(imp_tx);
2045 
2046 		lcbdata->sc_err = cbdata.sc_err;
2047 		if (cbdata.sc_err == ECANCELED) {
2048 			warn(pg_changed, lcbdata->sc_target_fmri,
2049 			    p->sc_pgroup_name);
2050 			lcbdata->sc_err = EBUSY;
2051 		}
2052 		return (UU_WALK_ERROR);
2053 	}
2054 
2055 	if ((lcbdata->sc_flags & SCI_DELAYENABLE) && cbdata.sc_enable) {
2056 		cbdata.sc_flags = cbdata.sc_flags & (~SCI_DELAYENABLE);
2057 
2058 		/*
2059 		 * take the snapshot running snapshot then
2060 		 * import the stored general/enable property
2061 		 */
2062 		r = take_snap(ent, snap_running, imp_rsnap);
2063 		switch (r) {
2064 		case 0:
2065 			break;
2066 
2067 		case ECONNABORTED:
2068 			warn(gettext("Could not take %s snapshot on import "
2069 			    "(repository connection broken).\n"),
2070 			    snap_running);
2071 			lcbdata->sc_err = r;
2072 			return (UU_WALK_ERROR);
2073 		case ECANCELED:
2074 			warn(emsg_deleted);
2075 			lcbdata->sc_err = r;
2076 			return (UU_WALK_ERROR);
2077 
2078 		case EPERM:
2079 			warn(gettext("Could not take %s snapshot "
2080 			    "(permission denied).\n"), snap_running);
2081 			lcbdata->sc_err = r;
2082 			return (UU_WALK_ERROR);
2083 
2084 		case ENOSPC:
2085 			warn(gettext("Could not take %s snapshot"
2086 			    "(repository server out of resources).\n"),
2087 			    snap_running);
2088 			lcbdata->sc_err = r;
2089 			return (UU_WALK_ERROR);
2090 
2091 		default:
2092 			bad_error("take_snap", r);
2093 		}
2094 
2095 		r = lscf_property_import(cbdata.sc_enable, &cbdata);
2096 		if (r != UU_WALK_NEXT) {
2097 			if (r != UU_WALK_ERROR)
2098 				bad_error("lscf_property_import", r);
2099 			return (EINVAL);
2100 		}
2101 	}
2102 
2103 	r = scf_transaction_commit(imp_tx);
2104 	switch (r) {
2105 	case 1:
2106 		r = UU_WALK_NEXT;
2107 		break;
2108 
2109 	case 0:
2110 		warn(pg_changed, lcbdata->sc_target_fmri, p->sc_pgroup_name);
2111 		lcbdata->sc_err = EBUSY;
2112 		r = UU_WALK_ERROR;
2113 		break;
2114 
2115 	case -1:
2116 		switch (scf_error()) {
2117 		case SCF_ERROR_BACKEND_READONLY:
2118 		case SCF_ERROR_BACKEND_ACCESS:
2119 		case SCF_ERROR_CONNECTION_BROKEN:
2120 		case SCF_ERROR_NO_RESOURCES:
2121 			r = stash_scferror(lcbdata);
2122 			break;
2123 
2124 		case SCF_ERROR_DELETED:
2125 			warn(emsg_pg_deleted, lcbdata->sc_target_fmri,
2126 			    p->sc_pgroup_name);
2127 			lcbdata->sc_err = EBUSY;
2128 			r = UU_WALK_ERROR;
2129 			break;
2130 
2131 		case SCF_ERROR_PERMISSION_DENIED:
2132 			warn(emsg_pg_mod_perm, p->sc_pgroup_name,
2133 			    lcbdata->sc_target_fmri);
2134 			r = stash_scferror(lcbdata);
2135 			break;
2136 
2137 		case SCF_ERROR_NOT_SET:
2138 		case SCF_ERROR_INVALID_ARGUMENT:
2139 		case SCF_ERROR_NOT_BOUND:
2140 		default:
2141 			bad_error("scf_transaction_commit", scf_error());
2142 		}
2143 
2144 	default:
2145 		bad_error("scf_transaction_commit", r);
2146 	}
2147 
2148 	scf_transaction_destroy_children(imp_tx);
2149 
2150 	return (r);
2151 }
2152 
2153 /*
2154  * Returns
2155  *   0 - success
2156  *   ECONNABORTED - repository connection broken
2157  *   ENOMEM - out of memory
2158  *   ENOSPC - svc.configd is out of resources
2159  *   ECANCELED - inst was deleted
2160  *   EPERM - could not create property group (permission denied) (error printed)
2161  *	   - could not modify property group (permission denied) (error printed)
2162  *   EROFS - could not create property group (repository is read-only)
2163  *   EACCES - could not create property group (backend access denied)
2164  *   EEXIST - could not create property group (already exists)
2165  *   EINVAL - invalid property group name (error printed)
2166  *	    - invalid property name (error printed)
2167  *	    - invalid value (error printed)
2168  *   EBUSY - new property group changed (error printed)
2169  */
2170 static int
2171 lscf_import_instance_pgs(scf_instance_t *inst, const char *target_fmri,
2172     const entity_t *iinst, int flags)
2173 {
2174 	scf_callback_t cbdata;
2175 
2176 	cbdata.sc_handle = scf_instance_handle(inst);
2177 	cbdata.sc_parent = inst;
2178 	cbdata.sc_service = 0;
2179 	cbdata.sc_general = NULL;
2180 	cbdata.sc_enable = NULL;
2181 	cbdata.sc_flags = flags;
2182 	cbdata.sc_source_fmri = iinst->sc_fmri;
2183 	cbdata.sc_target_fmri = target_fmri;
2184 
2185 	if (uu_list_walk(iinst->sc_pgroups, entity_pgroup_import, &cbdata,
2186 	    UU_DEFAULT) != 0) {
2187 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
2188 			bad_error("uu_list_walk", uu_error());
2189 
2190 		return (cbdata.sc_err);
2191 	}
2192 
2193 	if ((flags & SCI_GENERALLAST) && cbdata.sc_general) {
2194 		cbdata.sc_flags = flags & (~SCI_GENERALLAST);
2195 		/*
2196 		 * If importing with the SCI_NOENABLED flag then
2197 		 * skip the delay, but if not then add the delay
2198 		 * of the enable property.
2199 		 */
2200 		if (!(cbdata.sc_flags & SCI_NOENABLED)) {
2201 			cbdata.sc_flags |= SCI_DELAYENABLE;
2202 		}
2203 
2204 		if (entity_pgroup_import(cbdata.sc_general, &cbdata)
2205 		    != UU_WALK_NEXT)
2206 			return (cbdata.sc_err);
2207 	}
2208 
2209 	return (0);
2210 }
2211 
2212 /*
2213  * Report the reasons why we can't upgrade pg2 to pg1.
2214  */
2215 static void
2216 report_pg_diffs(const pgroup_t *pg1, const pgroup_t *pg2, const char *fmri,
2217     int new)
2218 {
2219 	property_t *p1, *p2;
2220 
2221 	assert(strcmp(pg1->sc_pgroup_name, pg2->sc_pgroup_name) == 0);
2222 
2223 	if (!pg_attrs_equal(pg1, pg2, fmri, new))
2224 		return;
2225 
2226 	for (p1 = uu_list_first(pg1->sc_pgroup_props);
2227 	    p1 != NULL;
2228 	    p1 = uu_list_next(pg1->sc_pgroup_props, p1)) {
2229 		p2 = uu_list_find(pg2->sc_pgroup_props, p1, NULL, NULL);
2230 		if (p2 != NULL) {
2231 			(void) prop_equal(p1, p2, fmri, pg1->sc_pgroup_name,
2232 			    new);
2233 			continue;
2234 		}
2235 
2236 		if (new)
2237 			warn(gettext("Conflict upgrading %s (new property "
2238 			    "group \"%s\" is missing property \"%s\").\n"),
2239 			    fmri, pg1->sc_pgroup_name, p1->sc_property_name);
2240 		else
2241 			warn(gettext("Conflict upgrading %s (property "
2242 			    "\"%s/%s\" is missing).\n"), fmri,
2243 			    pg1->sc_pgroup_name, p1->sc_property_name);
2244 	}
2245 
2246 	/*
2247 	 * Since pg1 should be from the manifest, any properties in pg2 which
2248 	 * aren't in pg1 shouldn't be reported as conflicts.
2249 	 */
2250 }
2251 
2252 /*
2253  * Add transaction entries to tx which will upgrade cur's pg according to old
2254  * & new.
2255  *
2256  * Returns
2257  *   0 - success
2258  *   EINVAL - new has a property with an invalid name or value (message emitted)
2259  *   ENOMEM - out of memory
2260  */
2261 static int
2262 add_upgrade_entries(scf_transaction_t *tx, pgroup_t *old, pgroup_t *new,
2263     pgroup_t *cur, int speak, const char *fmri)
2264 {
2265 	property_t *p, *new_p, *cur_p;
2266 	scf_transaction_entry_t *e;
2267 	int r;
2268 	int is_general;
2269 	int is_protected;
2270 
2271 	if (uu_list_walk(new->sc_pgroup_props, clear_int,
2272 	    (void *)offsetof(property_t, sc_seen), UU_DEFAULT) != 0)
2273 		bad_error("uu_list_walk", uu_error());
2274 
2275 	is_general = strcmp(old->sc_pgroup_name, SCF_PG_GENERAL) == 0;
2276 
2277 	for (p = uu_list_first(old->sc_pgroup_props);
2278 	    p != NULL;
2279 	    p = uu_list_next(old->sc_pgroup_props, p)) {
2280 		/* p is a property in the old property group. */
2281 
2282 		/* Protect live properties. */
2283 		is_protected = 0;
2284 		if (is_general) {
2285 			if (strcmp(p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2286 			    0 ||
2287 			    strcmp(p->sc_property_name,
2288 			    SCF_PROPERTY_RESTARTER) == 0)
2289 				is_protected = 1;
2290 		}
2291 
2292 		/* Look for the same property in the new properties. */
2293 		new_p = uu_list_find(new->sc_pgroup_props, p, NULL, NULL);
2294 		if (new_p != NULL) {
2295 			new_p->sc_seen = 1;
2296 
2297 			/*
2298 			 * If the new property is the same as the old, don't do
2299 			 * anything (leave any user customizations).
2300 			 */
2301 			if (prop_equal(p, new_p, NULL, NULL, 0))
2302 				continue;
2303 
2304 			if (new_p->sc_property_override)
2305 				goto upgrade;
2306 		}
2307 
2308 		cur_p = uu_list_find(cur->sc_pgroup_props, p, NULL, NULL);
2309 		if (cur_p == NULL) {
2310 			/*
2311 			 * p has been deleted from the repository.  If we were
2312 			 * going to delete it anyway, do nothing.  Otherwise
2313 			 * report a conflict.
2314 			 */
2315 			if (new_p == NULL)
2316 				continue;
2317 
2318 			if (is_protected)
2319 				continue;
2320 
2321 			warn(gettext("Conflict upgrading %s "
2322 			    "(property \"%s/%s\" is missing).\n"), fmri,
2323 			    old->sc_pgroup_name, p->sc_property_name);
2324 			continue;
2325 		}
2326 
2327 		if (!prop_equal(p, cur_p, NULL, NULL, 0)) {
2328 			/*
2329 			 * Conflict.  Don't warn if the property is already the
2330 			 * way we want it, though.
2331 			 */
2332 			if (is_protected)
2333 				continue;
2334 
2335 			if (new_p == NULL)
2336 				(void) prop_equal(p, cur_p, fmri,
2337 				    old->sc_pgroup_name, 0);
2338 			else
2339 				(void) prop_equal(cur_p, new_p, fmri,
2340 				    old->sc_pgroup_name, 0);
2341 			continue;
2342 		}
2343 
2344 		if (is_protected) {
2345 			if (speak)
2346 				warn(gettext("%s: Refusing to upgrade "
2347 				    "\"%s/%s\" (live property).\n"), fmri,
2348 				    old->sc_pgroup_name, p->sc_property_name);
2349 			continue;
2350 		}
2351 
2352 upgrade:
2353 		/* p hasn't been customized in the repository.  Upgrade it. */
2354 		if (new_p == NULL) {
2355 			/* p was deleted.  Delete from cur if unchanged. */
2356 			if (speak)
2357 				warn(gettext(
2358 				    "%s: Deleting property \"%s/%s\".\n"),
2359 				    fmri, old->sc_pgroup_name,
2360 				    p->sc_property_name);
2361 
2362 			e = scf_entry_create(g_hndl);
2363 			if (e == NULL)
2364 				return (ENOMEM);
2365 
2366 			if (scf_transaction_property_delete(tx, e,
2367 			    p->sc_property_name) != 0) {
2368 				switch (scf_error()) {
2369 				case SCF_ERROR_DELETED:
2370 					scf_entry_destroy(e);
2371 					return (ECANCELED);
2372 
2373 				case SCF_ERROR_CONNECTION_BROKEN:
2374 					scf_entry_destroy(e);
2375 					return (ECONNABORTED);
2376 
2377 				case SCF_ERROR_NOT_FOUND:
2378 					/*
2379 					 * This can happen if cur is from the
2380 					 * running snapshot (and it differs
2381 					 * from the live properties).
2382 					 */
2383 					scf_entry_destroy(e);
2384 					break;
2385 
2386 				case SCF_ERROR_HANDLE_MISMATCH:
2387 				case SCF_ERROR_NOT_BOUND:
2388 				case SCF_ERROR_NOT_SET:
2389 				case SCF_ERROR_INVALID_ARGUMENT:
2390 				default:
2391 					bad_error(
2392 					    "scf_transaction_property_delete",
2393 					    scf_error());
2394 				}
2395 			}
2396 		} else {
2397 			scf_callback_t ctx;
2398 
2399 			if (speak)
2400 				warn(gettext(
2401 				    "%s: Upgrading property \"%s/%s\".\n"),
2402 				    fmri, old->sc_pgroup_name,
2403 				    p->sc_property_name);
2404 
2405 			ctx.sc_handle = g_hndl;
2406 			ctx.sc_trans = tx;
2407 			ctx.sc_flags = 0;
2408 
2409 			r = lscf_property_import(new_p, &ctx);
2410 			if (r != UU_WALK_NEXT) {
2411 				if (r != UU_WALK_ERROR)
2412 					bad_error("lscf_property_import", r);
2413 				return (EINVAL);
2414 			}
2415 		}
2416 	}
2417 
2418 	/* Go over the properties which were added. */
2419 	for (new_p = uu_list_first(new->sc_pgroup_props);
2420 	    new_p != NULL;
2421 	    new_p = uu_list_next(new->sc_pgroup_props, new_p)) {
2422 		if (new_p->sc_seen)
2423 			continue;
2424 
2425 		/* This is a new property. */
2426 		cur_p = uu_list_find(cur->sc_pgroup_props, new_p, NULL, NULL);
2427 		if (cur_p == NULL) {
2428 			scf_callback_t ctx;
2429 
2430 			ctx.sc_handle = g_hndl;
2431 			ctx.sc_trans = tx;
2432 			ctx.sc_flags = 0;
2433 
2434 			r = lscf_property_import(new_p, &ctx);
2435 			if (r != UU_WALK_NEXT) {
2436 				if (r != UU_WALK_ERROR)
2437 					bad_error("lscf_property_import", r);
2438 				return (EINVAL);
2439 			}
2440 			continue;
2441 		}
2442 
2443 		/*
2444 		 * Report a conflict if the new property differs from the
2445 		 * current one.  Unless it's general/enabled, since that's
2446 		 * never in the last-import snapshot.
2447 		 */
2448 		if (strcmp(new_p->sc_property_name, SCF_PROPERTY_ENABLED) ==
2449 		    0 &&
2450 		    strcmp(cur->sc_pgroup_name, SCF_PG_GENERAL) == 0)
2451 			continue;
2452 
2453 		(void) prop_equal(cur_p, new_p, fmri, old->sc_pgroup_name, 1);
2454 	}
2455 
2456 	return (0);
2457 }
2458 
2459 /*
2460  * Upgrade pg according to old & new.
2461  *
2462  * Returns
2463  *   0 - success
2464  *   ECONNABORTED - repository connection broken
2465  *   ENOMEM - out of memory
2466  *   ENOSPC - svc.configd is out of resources
2467  *   ECANCELED - pg was deleted
2468  *   EPERM - couldn't modify pg (permission denied)
2469  *   EROFS - couldn't modify pg (backend read-only)
2470  *   EACCES - couldn't modify pg (backend access denied)
2471  *   EINVAL - new has a property with invalid name or value (error printed)
2472  *   EBUSY - pg changed unexpectedly
2473  */
2474 static int
2475 upgrade_pg(scf_propertygroup_t *pg, pgroup_t *cur, pgroup_t *old,
2476     pgroup_t *new, int speak, const char *fmri)
2477 {
2478 	int r;
2479 
2480 	if (scf_transaction_start(imp_tx, pg) != 0) {
2481 		switch (scf_error()) {
2482 		case SCF_ERROR_CONNECTION_BROKEN:
2483 		case SCF_ERROR_DELETED:
2484 		case SCF_ERROR_PERMISSION_DENIED:
2485 		case SCF_ERROR_BACKEND_READONLY:
2486 		case SCF_ERROR_BACKEND_ACCESS:
2487 			return (scferror2errno(scf_error()));
2488 
2489 		case SCF_ERROR_HANDLE_MISMATCH:
2490 		case SCF_ERROR_IN_USE:
2491 		case SCF_ERROR_NOT_BOUND:
2492 		case SCF_ERROR_NOT_SET:
2493 		default:
2494 			bad_error("scf_transaction_start", scf_error());
2495 		}
2496 	}
2497 
2498 	r = add_upgrade_entries(imp_tx, old, new, cur, speak, fmri);
2499 	switch (r) {
2500 	case 0:
2501 		break;
2502 
2503 	case EINVAL:
2504 	case ENOMEM:
2505 		scf_transaction_destroy_children(imp_tx);
2506 		return (r);
2507 
2508 	default:
2509 		bad_error("add_upgrade_entries", r);
2510 	}
2511 
2512 	r = scf_transaction_commit(imp_tx);
2513 
2514 	scf_transaction_destroy_children(imp_tx);
2515 
2516 	switch (r) {
2517 	case 1:
2518 		break;
2519 
2520 	case 0:
2521 		return (EBUSY);
2522 
2523 	case -1:
2524 		switch (scf_error()) {
2525 		case SCF_ERROR_CONNECTION_BROKEN:
2526 		case SCF_ERROR_NO_RESOURCES:
2527 		case SCF_ERROR_PERMISSION_DENIED:
2528 		case SCF_ERROR_BACKEND_READONLY:
2529 		case SCF_ERROR_BACKEND_ACCESS:
2530 		case SCF_ERROR_DELETED:
2531 			return (scferror2errno(scf_error()));
2532 
2533 		case SCF_ERROR_NOT_BOUND:
2534 		case SCF_ERROR_INVALID_ARGUMENT:
2535 		case SCF_ERROR_NOT_SET:
2536 		default:
2537 			bad_error("scf_transaction_commit", scf_error());
2538 		}
2539 
2540 	default:
2541 		bad_error("scf_transaction_commit", r);
2542 	}
2543 
2544 	return (0);
2545 }
2546 
2547 /*
2548  * Compares two entity FMRIs.  Returns
2549  *
2550  *   1 - equal
2551  *   0 - not equal
2552  *   -1 - f1 is invalid or not an entity
2553  *   -2 - f2 is invalid or not an entity
2554  */
2555 static int
2556 fmri_equal(const char *f1, const char *f2)
2557 {
2558 	int r;
2559 	const char *s1, *i1, *pg1;
2560 	const char *s2, *i2, *pg2;
2561 
2562 	if (strlcpy(imp_fe1, f1, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2563 		return (-1);
2564 	if (scf_parse_svc_fmri(imp_fe1, NULL, &s1, &i1, &pg1, NULL) != 0)
2565 		return (-1);
2566 
2567 	if (s1 == NULL || pg1 != NULL)
2568 		return (-1);
2569 
2570 	if (strlcpy(imp_fe2, f2, max_scf_fmri_len + 1) >= max_scf_fmri_len + 1)
2571 		return (-2);
2572 	if (scf_parse_svc_fmri(imp_fe2, NULL, &s2, &i2, &pg2, NULL) != 0)
2573 		return (-2);
2574 
2575 	if (s2 == NULL || pg2 != NULL)
2576 		return (-2);
2577 
2578 	r = strcmp(s1, s2);
2579 	if (r != 0)
2580 		return (0);
2581 
2582 	if (i1 == NULL && i2 == NULL)
2583 		return (1);
2584 
2585 	if (i1 == NULL || i2 == NULL)
2586 		return (0);
2587 
2588 	return (strcmp(i1, i2) == 0);
2589 }
2590 
2591 /*
2592  * Import a dependent by creating a dependency property group in the dependent
2593  * entity.  If lcbdata->sc_trans is set, assume it's been started on the
2594  * dependents pg, and add an entry to create a new property for this
2595  * dependent.  Uses sc_handle, sc_trans, and sc_fmri in lcbdata.
2596  *
2597  * On success, returns UU_WALK_NEXT.  On error, returns UU_WALK_ERROR and sets
2598  * lcbdata->sc_err to
2599  *   ECONNABORTED - repository connection broken
2600  *   ENOMEM - out of memory
2601  *   ENOSPC - configd is out of resources
2602  *   EINVAL - target is invalid (error printed)
2603  *	    - target is not an entity (error printed)
2604  *	    - dependent has invalid name (error printed)
2605  *	    - invalid property name (error printed)
2606  *	    - invalid value (error printed)
2607  *	    - scope of target does not exist (error printed)
2608  *   EPERM - couldn't create target (permission denied) (error printed)
2609  *	   - couldn't create dependency pg (permission denied) (error printed)
2610  *	   - couldn't modify dependency pg (permission denied) (error printed)
2611  *   EROFS - couldn't create target (repository read-only)
2612  *	   - couldn't create dependency pg (repository read-only)
2613  *   EACCES - couldn't create target (backend access denied)
2614  *	    - couldn't create dependency pg (backend access denied)
2615  *   ECANCELED - sc_trans's pg was deleted
2616  *   EALREADY - property for dependent already exists in sc_trans's pg
2617  *   EEXIST - dependency pg already exists in target (error printed)
2618  *   EBUSY - target deleted (error printed)
2619  *         - property group changed during import (error printed)
2620  */
2621 static int
2622 lscf_dependent_import(void *a1, void *pvt)
2623 {
2624 	pgroup_t *pgrp = a1;
2625 	scf_callback_t *lcbdata = pvt;
2626 
2627 	int isservice;
2628 	int ret;
2629 	scf_transaction_entry_t *e;
2630 	scf_value_t *val;
2631 	scf_callback_t dependent_cbdata;
2632 	scf_error_t scfe;
2633 
2634 	/*
2635 	 * Decode the FMRI into dependent_cbdata->sc_parent.  Do it here so if
2636 	 * it's invalid, we fail before modifying the repository.
2637 	 */
2638 	scfe = fmri_to_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2639 	    &dependent_cbdata.sc_parent, &isservice);
2640 	switch (scfe) {
2641 	case SCF_ERROR_NONE:
2642 		break;
2643 
2644 	case SCF_ERROR_NO_MEMORY:
2645 		return (stash_scferror_err(lcbdata, scfe));
2646 
2647 	case SCF_ERROR_INVALID_ARGUMENT:
2648 		semerr(gettext("The FMRI for the \"%s\" dependent is "
2649 		    "invalid.\n"), pgrp->sc_pgroup_name);
2650 		return (stash_scferror_err(lcbdata, scfe));
2651 
2652 	case SCF_ERROR_CONSTRAINT_VIOLATED:
2653 		semerr(gettext("The FMRI \"%s\" for the \"%s\" dependent "
2654 		    "specifies neither a service nor an instance.\n"),
2655 		    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2656 		return (stash_scferror_err(lcbdata, scfe));
2657 
2658 	case SCF_ERROR_NOT_FOUND:
2659 		scfe = create_entity(lcbdata->sc_handle, pgrp->sc_pgroup_fmri,
2660 		    &dependent_cbdata.sc_parent, &isservice);
2661 		switch (scfe) {
2662 		case SCF_ERROR_NONE:
2663 			break;
2664 
2665 		case SCF_ERROR_NO_MEMORY:
2666 		case SCF_ERROR_BACKEND_READONLY:
2667 		case SCF_ERROR_BACKEND_ACCESS:
2668 			return (stash_scferror_err(lcbdata, scfe));
2669 
2670 		case SCF_ERROR_NOT_FOUND:
2671 			semerr(gettext("The scope in FMRI \"%s\" for the "
2672 			    "\"%s\" dependent does not exist.\n"),
2673 			    pgrp->sc_pgroup_fmri, pgrp->sc_pgroup_name);
2674 			lcbdata->sc_err = EINVAL;
2675 			return (UU_WALK_ERROR);
2676 
2677 		case SCF_ERROR_PERMISSION_DENIED:
2678 			warn(gettext(
2679 			    "Could not create %s (permission denied).\n"),
2680 			    pgrp->sc_pgroup_fmri);
2681 			return (stash_scferror_err(lcbdata, scfe));
2682 
2683 		case SCF_ERROR_INVALID_ARGUMENT:
2684 		case SCF_ERROR_CONSTRAINT_VIOLATED:
2685 		default:
2686 			bad_error("create_entity", scfe);
2687 		}
2688 		break;
2689 
2690 	default:
2691 		bad_error("fmri_to_entity", scfe);
2692 	}
2693 
2694 	if (lcbdata->sc_trans != NULL) {
2695 		e = scf_entry_create(lcbdata->sc_handle);
2696 		if (e == NULL) {
2697 			if (scf_error() != SCF_ERROR_NO_MEMORY)
2698 				bad_error("scf_entry_create", scf_error());
2699 
2700 			entity_destroy(dependent_cbdata.sc_parent, isservice);
2701 			return (stash_scferror(lcbdata));
2702 		}
2703 
2704 		if (scf_transaction_property_new(lcbdata->sc_trans, e,
2705 		    pgrp->sc_pgroup_name, SCF_TYPE_FMRI) != 0) {
2706 			switch (scf_error()) {
2707 			case SCF_ERROR_INVALID_ARGUMENT:
2708 				warn(gettext("Dependent of %s has invalid name "
2709 				    "\"%s\".\n"), pgrp->sc_parent->sc_fmri,
2710 				    pgrp->sc_pgroup_name);
2711 				/* FALLTHROUGH */
2712 
2713 			case SCF_ERROR_DELETED:
2714 			case SCF_ERROR_CONNECTION_BROKEN:
2715 				scf_entry_destroy(e);
2716 				entity_destroy(dependent_cbdata.sc_parent,
2717 				    isservice);
2718 				return (stash_scferror(lcbdata));
2719 
2720 			case SCF_ERROR_EXISTS:
2721 				scf_entry_destroy(e);
2722 				entity_destroy(dependent_cbdata.sc_parent,
2723 				    isservice);
2724 				lcbdata->sc_err = EALREADY;
2725 				return (UU_WALK_ERROR);
2726 
2727 			case SCF_ERROR_NOT_BOUND:
2728 			case SCF_ERROR_HANDLE_MISMATCH:
2729 			case SCF_ERROR_NOT_SET:
2730 			default:
2731 				bad_error("scf_transaction_property_new",
2732 				    scf_error());
2733 			}
2734 		}
2735 
2736 		val = scf_value_create(lcbdata->sc_handle);
2737 		if (val == NULL) {
2738 			if (scf_error() != SCF_ERROR_NO_MEMORY)
2739 				bad_error("scf_value_create", scf_error());
2740 
2741 			entity_destroy(dependent_cbdata.sc_parent, isservice);
2742 			return (stash_scferror(lcbdata));
2743 		}
2744 
2745 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
2746 		    pgrp->sc_pgroup_fmri) != 0)
2747 			/* invalid should have been caught above */
2748 			bad_error("scf_value_set_from_string", scf_error());
2749 
2750 		if (scf_entry_add_value(e, val) != 0)
2751 			bad_error("scf_entry_add_value", scf_error());
2752 	}
2753 
2754 	/* Add the property group to the target entity. */
2755 
2756 	dependent_cbdata.sc_handle = lcbdata->sc_handle;
2757 	dependent_cbdata.sc_flags = 0;
2758 	dependent_cbdata.sc_source_fmri = lcbdata->sc_source_fmri;
2759 	dependent_cbdata.sc_target_fmri = pgrp->sc_pgroup_fmri;
2760 
2761 	ret = entity_pgroup_import(pgrp, &dependent_cbdata);
2762 
2763 	entity_destroy(dependent_cbdata.sc_parent, isservice);
2764 
2765 	if (ret == UU_WALK_NEXT)
2766 		return (ret);
2767 
2768 	if (ret != UU_WALK_ERROR)
2769 		bad_error("entity_pgroup_import", ret);
2770 
2771 	switch (dependent_cbdata.sc_err) {
2772 	case ECANCELED:
2773 		warn(gettext("%s deleted unexpectedly.\n"),
2774 		    pgrp->sc_pgroup_fmri);
2775 		lcbdata->sc_err = EBUSY;
2776 		break;
2777 
2778 	case EEXIST:
2779 		warn(gettext("Could not create \"%s\" dependency in %s "
2780 		    "(already exists).\n"), pgrp->sc_pgroup_name,
2781 		    pgrp->sc_pgroup_fmri);
2782 		/* FALLTHROUGH */
2783 
2784 	default:
2785 		lcbdata->sc_err = dependent_cbdata.sc_err;
2786 	}
2787 
2788 	return (UU_WALK_ERROR);
2789 }
2790 
2791 static int upgrade_dependent(const scf_property_t *, const entity_t *,
2792     const scf_snaplevel_t *, scf_transaction_t *);
2793 static int handle_dependent_conflict(const entity_t *, const scf_property_t *,
2794     const pgroup_t *);
2795 
2796 /*
2797  * Upgrade uncustomized dependents of ent to those specified in ient.  Read
2798  * the current dependent targets from running (the snaplevel of a running
2799  * snapshot which corresponds to ient) if not NULL (ent, an scf_service_t * or
2800  * scf_instance_t * according to ient, otherwise).  Draw the ancestral
2801  * dependent targets and dependency properties from li_dpts_pg (the
2802  * "dependents" property group in snpl) and snpl (the snaplevel which
2803  * corresponds to ent in a last-import snapshot).  If li_dpts_pg is NULL, then
2804  * snpl doesn't have a "dependents" property group, and any dependents in ient
2805  * are new.
2806  *
2807  * Returns
2808  *   0 - success
2809  *   ECONNABORTED - repository connection broken
2810  *   ENOMEM - out of memory
2811  *   ENOSPC - configd is out of resources
2812  *   ECANCELED - ent was deleted
2813  *   ENODEV - the entity containing li_dpts_pg was deleted
2814  *   EPERM - could not modify dependents pg (permission denied) (error printed)
2815  *	   - couldn't upgrade dependent (permission denied) (error printed)
2816  *	   - couldn't create dependent (permission denied) (error printed)
2817  *   EROFS - could not modify dependents pg (repository read-only)
2818  *	   - couldn't upgrade dependent (repository read-only)
2819  *	   - couldn't create dependent (repository read-only)
2820  *   EACCES - could not modify dependents pg (backend access denied)
2821  *	    - could not upgrade dependent (backend access denied)
2822  *	    - could not create dependent (backend access denied)
2823  *   EBUSY - "dependents" pg of ent added, changed, or deleted (error printed)
2824  *	   - dependent target deleted (error printed)
2825  *	   - dependent pg changed (error printed)
2826  *   EINVAL - new dependent is invalid (error printed)
2827  *   EBADF - snpl is corrupt (error printed)
2828  *	   - snpl has corrupt pg (error printed)
2829  *	   - dependency pg in target is corrupt (error printed)
2830  *	   - target has corrupt snapshot (error printed)
2831  *   EEXIST - dependency pg already existed in target service (error printed)
2832  */
2833 static int
2834 upgrade_dependents(const scf_propertygroup_t *li_dpts_pg,
2835     const scf_snaplevel_t *snpl, const entity_t *ient,
2836     const scf_snaplevel_t *running, void *ent)
2837 {
2838 	pgroup_t *new_dpt_pgroup;
2839 	scf_callback_t cbdata;
2840 	int r, unseen, tx_started = 0;
2841 	int have_cur_depts;
2842 
2843 	const char * const dependents = "dependents";
2844 
2845 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
2846 
2847 	if (li_dpts_pg == NULL && uu_list_numnodes(ient->sc_dependents) == 0)
2848 		/* Nothing to do. */
2849 		return (0);
2850 
2851 	/* Fetch the current version of the "dependents" property group. */
2852 	have_cur_depts = 1;
2853 	if (entity_get_pg(ent, issvc, dependents, ud_cur_depts_pg) != 0) {
2854 		switch (scf_error()) {
2855 		case SCF_ERROR_NOT_FOUND:
2856 			break;
2857 
2858 		case SCF_ERROR_DELETED:
2859 		case SCF_ERROR_CONNECTION_BROKEN:
2860 			return (scferror2errno(scf_error()));
2861 
2862 		case SCF_ERROR_NOT_SET:
2863 		case SCF_ERROR_INVALID_ARGUMENT:
2864 		case SCF_ERROR_HANDLE_MISMATCH:
2865 		case SCF_ERROR_NOT_BOUND:
2866 		default:
2867 			bad_error("entity_get_pg", scf_error());
2868 		}
2869 
2870 		have_cur_depts = 0;
2871 	}
2872 
2873 	/* Fetch the running version of the "dependents" property group. */
2874 	ud_run_dpts_pg_set = 0;
2875 	if (running != NULL)
2876 		r = scf_snaplevel_get_pg(running, dependents, ud_run_dpts_pg);
2877 	else
2878 		r = entity_get_pg(ent, issvc, dependents, ud_run_dpts_pg);
2879 	if (r == 0) {
2880 		ud_run_dpts_pg_set = 1;
2881 	} else {
2882 		switch (scf_error()) {
2883 		case SCF_ERROR_NOT_FOUND:
2884 			break;
2885 
2886 		case SCF_ERROR_DELETED:
2887 		case SCF_ERROR_CONNECTION_BROKEN:
2888 			return (scferror2errno(scf_error()));
2889 
2890 		case SCF_ERROR_NOT_SET:
2891 		case SCF_ERROR_INVALID_ARGUMENT:
2892 		case SCF_ERROR_HANDLE_MISMATCH:
2893 		case SCF_ERROR_NOT_BOUND:
2894 		default:
2895 			bad_error(running ? "scf_snaplevel_get_pg" :
2896 			    "entity_get_pg", scf_error());
2897 		}
2898 	}
2899 
2900 	/*
2901 	 * Clear the seen fields of the dependents, so we can tell which ones
2902 	 * are new.
2903 	 */
2904 	if (uu_list_walk(ient->sc_dependents, clear_int,
2905 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
2906 		bad_error("uu_list_walk", uu_error());
2907 
2908 	if (li_dpts_pg != NULL) {
2909 		/*
2910 		 * Each property in li_dpts_pg represents a dependent tag in
2911 		 * the old manifest.  For each, call upgrade_dependent(),
2912 		 * which will change ud_cur_depts_pg or dependencies in other
2913 		 * services as appropriate.  Note (a) that changes to
2914 		 * ud_cur_depts_pg are accumulated in ud_tx so they can all be
2915 		 * made en masse, and (b) it's ok if the entity doesn't have
2916 		 * a current version of the "dependents" property group,
2917 		 * because we'll just consider all dependents as customized
2918 		 * (by being deleted).
2919 		 */
2920 
2921 		if (scf_iter_pg_properties(ud_iter, li_dpts_pg) != 0) {
2922 			switch (scf_error()) {
2923 			case SCF_ERROR_DELETED:
2924 				return (ENODEV);
2925 
2926 			case SCF_ERROR_CONNECTION_BROKEN:
2927 				return (ECONNABORTED);
2928 
2929 			case SCF_ERROR_HANDLE_MISMATCH:
2930 			case SCF_ERROR_NOT_BOUND:
2931 			case SCF_ERROR_NOT_SET:
2932 			default:
2933 				bad_error("scf_iter_pg_properties",
2934 				    scf_error());
2935 			}
2936 		}
2937 
2938 		if (have_cur_depts &&
2939 		    scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
2940 			switch (scf_error()) {
2941 			case SCF_ERROR_BACKEND_ACCESS:
2942 			case SCF_ERROR_BACKEND_READONLY:
2943 			case SCF_ERROR_CONNECTION_BROKEN:
2944 				return (scferror2errno(scf_error()));
2945 
2946 			case SCF_ERROR_DELETED:
2947 				warn(emsg_pg_deleted, ient->sc_fmri,
2948 				    dependents);
2949 				return (EBUSY);
2950 
2951 			case SCF_ERROR_PERMISSION_DENIED:
2952 				warn(emsg_pg_mod_perm, dependents,
2953 				    ient->sc_fmri);
2954 				return (scferror2errno(scf_error()));
2955 
2956 			case SCF_ERROR_HANDLE_MISMATCH:
2957 			case SCF_ERROR_IN_USE:
2958 			case SCF_ERROR_NOT_BOUND:
2959 			case SCF_ERROR_NOT_SET:
2960 			default:
2961 				bad_error("scf_transaction_start", scf_error());
2962 			}
2963 		}
2964 		tx_started = have_cur_depts;
2965 
2966 		for (;;) {
2967 			r = scf_iter_next_property(ud_iter, ud_dpt_prop);
2968 			if (r == 0)
2969 				break;
2970 			if (r == 1) {
2971 				r = upgrade_dependent(ud_dpt_prop, ient, snpl,
2972 				    tx_started ? ud_tx : NULL);
2973 				switch (r) {
2974 				case 0:
2975 					continue;
2976 
2977 				case ECONNABORTED:
2978 				case ENOMEM:
2979 				case ENOSPC:
2980 				case EBADF:
2981 				case EBUSY:
2982 				case EINVAL:
2983 				case EPERM:
2984 				case EROFS:
2985 				case EACCES:
2986 				case EEXIST:
2987 					break;
2988 
2989 				case ECANCELED:
2990 					r = ENODEV;
2991 					break;
2992 
2993 				default:
2994 					bad_error("upgrade_dependent", r);
2995 				}
2996 
2997 				if (tx_started)
2998 					scf_transaction_destroy_children(ud_tx);
2999 				return (r);
3000 			}
3001 			if (r != -1)
3002 				bad_error("scf_iter_next_property", r);
3003 
3004 			switch (scf_error()) {
3005 			case SCF_ERROR_DELETED:
3006 				r = ENODEV;
3007 				break;
3008 
3009 			case SCF_ERROR_CONNECTION_BROKEN:
3010 				r = ECONNABORTED;
3011 				break;
3012 
3013 			case SCF_ERROR_NOT_SET:
3014 			case SCF_ERROR_INVALID_ARGUMENT:
3015 			case SCF_ERROR_NOT_BOUND:
3016 			case SCF_ERROR_HANDLE_MISMATCH:
3017 			default:
3018 				bad_error("scf_iter_next_property",
3019 				    scf_error());
3020 			}
3021 
3022 			if (tx_started)
3023 				scf_transaction_destroy_children(ud_tx);
3024 			return (r);
3025 		}
3026 	}
3027 
3028 	/* import unseen dependents */
3029 	unseen = 0;
3030 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3031 	    new_dpt_pgroup != NULL;
3032 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3033 	    new_dpt_pgroup)) {
3034 		if (!new_dpt_pgroup->sc_pgroup_seen) {
3035 			unseen = 1;
3036 			break;
3037 		}
3038 	}
3039 
3040 	/* If there are none, exit early. */
3041 	if (unseen == 0)
3042 		goto commit;
3043 
3044 	/* Set up for lscf_dependent_import() */
3045 	cbdata.sc_handle = g_hndl;
3046 	cbdata.sc_parent = ent;
3047 	cbdata.sc_service = issvc;
3048 	cbdata.sc_flags = 0;
3049 
3050 	if (!have_cur_depts) {
3051 		/*
3052 		 * We have new dependents to import, so we need a "dependents"
3053 		 * property group.
3054 		 */
3055 		if (issvc)
3056 			r = scf_service_add_pg(ent, dependents,
3057 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3058 		else
3059 			r = scf_instance_add_pg(ent, dependents,
3060 			    SCF_GROUP_FRAMEWORK, 0, ud_cur_depts_pg);
3061 		if (r != 0) {
3062 			switch (scf_error()) {
3063 			case SCF_ERROR_DELETED:
3064 			case SCF_ERROR_CONNECTION_BROKEN:
3065 			case SCF_ERROR_BACKEND_READONLY:
3066 			case SCF_ERROR_BACKEND_ACCESS:
3067 			case SCF_ERROR_NO_RESOURCES:
3068 				return (scferror2errno(scf_error()));
3069 
3070 			case SCF_ERROR_EXISTS:
3071 				warn(emsg_pg_added, ient->sc_fmri, dependents);
3072 				return (EBUSY);
3073 
3074 			case SCF_ERROR_PERMISSION_DENIED:
3075 				warn(emsg_pg_add_perm, dependents,
3076 				    ient->sc_fmri);
3077 				return (scferror2errno(scf_error()));
3078 
3079 			case SCF_ERROR_NOT_BOUND:
3080 			case SCF_ERROR_HANDLE_MISMATCH:
3081 			case SCF_ERROR_INVALID_ARGUMENT:
3082 			case SCF_ERROR_NOT_SET:
3083 			default:
3084 				bad_error("scf_service_add_pg", scf_error());
3085 			}
3086 		}
3087 	}
3088 
3089 	cbdata.sc_trans = ud_tx;
3090 
3091 	if (!tx_started && scf_transaction_start(ud_tx, ud_cur_depts_pg) != 0) {
3092 		switch (scf_error()) {
3093 		case SCF_ERROR_CONNECTION_BROKEN:
3094 		case SCF_ERROR_BACKEND_ACCESS:
3095 		case SCF_ERROR_BACKEND_READONLY:
3096 			return (scferror2errno(scf_error()));
3097 
3098 		case SCF_ERROR_DELETED:
3099 			warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3100 			return (EBUSY);
3101 
3102 		case SCF_ERROR_PERMISSION_DENIED:
3103 			warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3104 			return (scferror2errno(scf_error()));
3105 
3106 		case SCF_ERROR_HANDLE_MISMATCH:
3107 		case SCF_ERROR_IN_USE:
3108 		case SCF_ERROR_NOT_BOUND:
3109 		case SCF_ERROR_NOT_SET:
3110 		default:
3111 			bad_error("scf_transaction_start", scf_error());
3112 		}
3113 	}
3114 	tx_started = 1;
3115 
3116 	for (new_dpt_pgroup = uu_list_first(ient->sc_dependents);
3117 	    new_dpt_pgroup != NULL;
3118 	    new_dpt_pgroup = uu_list_next(ient->sc_dependents,
3119 	    new_dpt_pgroup)) {
3120 		if (new_dpt_pgroup->sc_pgroup_seen)
3121 			continue;
3122 
3123 		if (ud_run_dpts_pg_set) {
3124 			/*
3125 			 * If the dependent is already there, then we have
3126 			 * a conflict.
3127 			 */
3128 			if (scf_pg_get_property(ud_run_dpts_pg,
3129 			    new_dpt_pgroup->sc_pgroup_name, ud_prop) == 0) {
3130 				r = handle_dependent_conflict(ient, ud_prop,
3131 				    new_dpt_pgroup);
3132 				switch (r) {
3133 				case 0:
3134 					continue;
3135 
3136 				case ECONNABORTED:
3137 				case ENOMEM:
3138 				case EBUSY:
3139 				case EBADF:
3140 				case EINVAL:
3141 					scf_transaction_destroy_children(ud_tx);
3142 					return (r);
3143 
3144 				default:
3145 					bad_error("handle_dependent_conflict",
3146 					    r);
3147 				}
3148 			} else {
3149 				switch (scf_error()) {
3150 				case SCF_ERROR_NOT_FOUND:
3151 					break;
3152 
3153 				case SCF_ERROR_INVALID_ARGUMENT:
3154 					warn(emsg_fmri_invalid_pg_name,
3155 					    ient->sc_fmri,
3156 					    new_dpt_pgroup->sc_pgroup_name);
3157 					scf_transaction_destroy_children(ud_tx);
3158 					return (EINVAL);
3159 
3160 				case SCF_ERROR_DELETED:
3161 					warn(emsg_pg_deleted, ient->sc_fmri,
3162 					    new_dpt_pgroup->sc_pgroup_name);
3163 					scf_transaction_destroy_children(ud_tx);
3164 					return (EBUSY);
3165 
3166 				case SCF_ERROR_CONNECTION_BROKEN:
3167 					scf_transaction_destroy_children(ud_tx);
3168 					return (ECONNABORTED);
3169 
3170 				case SCF_ERROR_NOT_BOUND:
3171 				case SCF_ERROR_HANDLE_MISMATCH:
3172 				case SCF_ERROR_NOT_SET:
3173 				default:
3174 					bad_error("scf_pg_get_property",
3175 					    scf_error());
3176 				}
3177 			}
3178 		}
3179 
3180 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
3181 		if (r != UU_WALK_NEXT) {
3182 			if (r != UU_WALK_ERROR)
3183 				bad_error("lscf_dependent_import", r);
3184 
3185 			if (cbdata.sc_err == EALREADY) {
3186 				/* Collisions were handled preemptively. */
3187 				bad_error("lscf_dependent_import",
3188 				    cbdata.sc_err);
3189 			}
3190 
3191 			scf_transaction_destroy_children(ud_tx);
3192 			return (cbdata.sc_err);
3193 		}
3194 	}
3195 
3196 commit:
3197 	if (!tx_started)
3198 		return (0);
3199 
3200 	r = scf_transaction_commit(ud_tx);
3201 
3202 	scf_transaction_destroy_children(ud_tx);
3203 
3204 	switch (r) {
3205 	case 1:
3206 		return (0);
3207 
3208 	case 0:
3209 		warn(emsg_pg_changed, ient->sc_fmri, dependents);
3210 		return (EBUSY);
3211 
3212 	case -1:
3213 		break;
3214 
3215 	default:
3216 		bad_error("scf_transaction_commit", r);
3217 	}
3218 
3219 	switch (scf_error()) {
3220 	case SCF_ERROR_CONNECTION_BROKEN:
3221 	case SCF_ERROR_BACKEND_READONLY:
3222 	case SCF_ERROR_BACKEND_ACCESS:
3223 	case SCF_ERROR_NO_RESOURCES:
3224 		return (scferror2errno(scf_error()));
3225 
3226 	case SCF_ERROR_DELETED:
3227 		warn(emsg_pg_deleted, ient->sc_fmri, dependents);
3228 		return (EBUSY);
3229 
3230 	case SCF_ERROR_PERMISSION_DENIED:
3231 		warn(emsg_pg_mod_perm, dependents, ient->sc_fmri);
3232 		return (scferror2errno(scf_error()));
3233 
3234 	case SCF_ERROR_NOT_BOUND:
3235 	case SCF_ERROR_INVALID_ARGUMENT:
3236 	case SCF_ERROR_NOT_SET:
3237 	default:
3238 		bad_error("scf_transaction_destroy", scf_error());
3239 		/* NOTREACHED */
3240 	}
3241 }
3242 
3243 /*
3244  * prop is taken to be a property in the "dependents" property group of snpl,
3245  * which is taken to be the snaplevel of a last-import snapshot corresponding
3246  * to ient.  If prop is a valid dependents property, upgrade the dependent it
3247  * represents according to the repository & ient.  If ud_run_dpts_pg_set is
3248  * true, then ud_run_dpts_pg is taken to be the "dependents" property group
3249  * of the entity ient represents (possibly in the running snapshot).  If it
3250  * needs to be changed, an entry will be added to tx, if not NULL.
3251  *
3252  * Returns
3253  *   0 - success
3254  *   ECONNABORTED - repository connection broken
3255  *   ENOMEM - out of memory
3256  *   ENOSPC - configd was out of resources
3257  *   ECANCELED - snpl's entity was deleted
3258  *   EINVAL - dependent target is invalid (error printed)
3259  *	    - dependent is invalid (error printed)
3260  *   EBADF - snpl is corrupt (error printed)
3261  *	   - snpl has corrupt pg (error printed)
3262  *	   - dependency pg in target is corrupt (error printed)
3263  *	   - running snapshot in dependent is missing snaplevel (error printed)
3264  *   EPERM - couldn't delete dependency pg (permission denied) (error printed)
3265  *	   - couldn't create dependent (permission denied) (error printed)
3266  *	   - couldn't modify dependent pg (permission denied) (error printed)
3267  *   EROFS - couldn't delete dependency pg (repository read-only)
3268  *	   - couldn't create dependent (repository read-only)
3269  *   EACCES - couldn't delete dependency pg (backend access denied)
3270  *	    - couldn't create dependent (backend access denied)
3271  *   EBUSY - ud_run_dpts_pg was deleted (error printed)
3272  *	   - tx's pg was deleted (error printed)
3273  *	   - dependent pg was changed or deleted (error printed)
3274  *   EEXIST - dependency pg already exists in new target (error printed)
3275  */
3276 static int
3277 upgrade_dependent(const scf_property_t *prop, const entity_t *ient,
3278     const scf_snaplevel_t *snpl, scf_transaction_t *tx)
3279 {
3280 	pgroup_t pgrp;
3281 	scf_type_t ty;
3282 	pgroup_t *new_dpt_pgroup;
3283 	pgroup_t *old_dpt_pgroup = NULL;
3284 	pgroup_t *current_pg;
3285 	scf_callback_t cbdata;
3286 	int tissvc;
3287 	void *target_ent;
3288 	scf_error_t serr;
3289 	int r;
3290 	scf_transaction_entry_t *ent;
3291 
3292 	const char * const cf_inval = gettext("Conflict upgrading %s "
3293 	    "(dependent \"%s\" has invalid dependents property).\n");
3294 	const char * const cf_missing = gettext("Conflict upgrading %s "
3295 	    "(dependent \"%s\" is missing).\n");
3296 	const char * const cf_newdpg = gettext("Conflict upgrading %s "
3297 	    "(dependent \"%s\" has new dependency property group).\n");
3298 	const char * const cf_newtarg = gettext("Conflict upgrading %s "
3299 	    "(dependent \"%s\" has new target).\n");
3300 	const char * const li_corrupt =
3301 	    gettext("%s: \"last-import\" snapshot is corrupt.\n");
3302 	const char * const upgrading =
3303 	    gettext("%s: Upgrading dependent \"%s\".\n");
3304 	const char * const r_no_lvl = gettext("%s: \"running\" snapshot is "
3305 	    "corrupt (missing snaplevel).\n");
3306 
3307 	if (scf_property_type(prop, &ty) != 0) {
3308 		switch (scf_error()) {
3309 		case SCF_ERROR_DELETED:
3310 		case SCF_ERROR_CONNECTION_BROKEN:
3311 			return (scferror2errno(scf_error()));
3312 
3313 		case SCF_ERROR_NOT_BOUND:
3314 		case SCF_ERROR_NOT_SET:
3315 		default:
3316 			bad_error("scf_property_type", scf_error());
3317 		}
3318 	}
3319 
3320 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3321 		warn(li_corrupt, ient->sc_fmri);
3322 		return (EBADF);
3323 	}
3324 
3325 	/*
3326 	 * prop represents a dependent in the old manifest.  It is named after
3327 	 * the dependent.
3328 	 */
3329 	if (scf_property_get_name(prop, ud_name, max_scf_name_len + 1) < 0) {
3330 		switch (scf_error()) {
3331 		case SCF_ERROR_DELETED:
3332 		case SCF_ERROR_CONNECTION_BROKEN:
3333 			return (scferror2errno(scf_error()));
3334 
3335 		case SCF_ERROR_NOT_BOUND:
3336 		case SCF_ERROR_NOT_SET:
3337 		default:
3338 			bad_error("scf_property_get_name", scf_error());
3339 		}
3340 	}
3341 
3342 	/* See if it's in the new manifest. */
3343 	pgrp.sc_pgroup_name = ud_name;
3344 	new_dpt_pgroup =
3345 	    uu_list_find(ient->sc_dependents, &pgrp, NULL, UU_DEFAULT);
3346 
3347 	/* If it's not, delete it... if it hasn't been customized. */
3348 	if (new_dpt_pgroup == NULL) {
3349 		pgroup_t *dpt;
3350 
3351 		if (!ud_run_dpts_pg_set)
3352 			return (0);
3353 
3354 		if (scf_property_get_value(prop, ud_val) != 0) {
3355 			switch (scf_error()) {
3356 			case SCF_ERROR_NOT_FOUND:
3357 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3358 				warn(li_corrupt, ient->sc_fmri);
3359 				return (EBADF);
3360 
3361 			case SCF_ERROR_DELETED:
3362 			case SCF_ERROR_CONNECTION_BROKEN:
3363 				return (scferror2errno(scf_error()));
3364 
3365 			case SCF_ERROR_HANDLE_MISMATCH:
3366 			case SCF_ERROR_NOT_BOUND:
3367 			case SCF_ERROR_NOT_SET:
3368 			case SCF_ERROR_PERMISSION_DENIED:
3369 			default:
3370 				bad_error("scf_property_get_value",
3371 				    scf_error());
3372 			}
3373 		}
3374 
3375 		if (scf_value_get_as_string(ud_val, ud_oldtarg,
3376 		    max_scf_value_len + 1) < 0)
3377 			bad_error("scf_value_get_as_string", scf_error());
3378 
3379 		if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) !=
3380 		    0) {
3381 			switch (scf_error()) {
3382 			case SCF_ERROR_NOT_FOUND:
3383 				return (0);
3384 
3385 			case SCF_ERROR_CONNECTION_BROKEN:
3386 				return (scferror2errno(scf_error()));
3387 
3388 			case SCF_ERROR_DELETED:
3389 				warn(emsg_pg_deleted, ient->sc_fmri,
3390 				    "dependents");
3391 				return (EBUSY);
3392 
3393 			case SCF_ERROR_INVALID_ARGUMENT:
3394 			case SCF_ERROR_NOT_BOUND:
3395 			case SCF_ERROR_HANDLE_MISMATCH:
3396 			case SCF_ERROR_NOT_SET:
3397 			default:
3398 				bad_error("scf_pg_get_property", scf_error());
3399 			}
3400 		}
3401 		if (scf_property_get_value(ud_prop, ud_val) != 0) {
3402 			switch (scf_error()) {
3403 			case SCF_ERROR_NOT_FOUND:
3404 			case SCF_ERROR_CONSTRAINT_VIOLATED:
3405 				warn(cf_inval, ient->sc_fmri, ud_name);
3406 				return (0);
3407 
3408 			case SCF_ERROR_DELETED:
3409 			case SCF_ERROR_CONNECTION_BROKEN:
3410 				return (scferror2errno(scf_error()));
3411 
3412 			case SCF_ERROR_HANDLE_MISMATCH:
3413 			case SCF_ERROR_NOT_BOUND:
3414 			case SCF_ERROR_NOT_SET:
3415 			case SCF_ERROR_PERMISSION_DENIED:
3416 			default:
3417 				bad_error("scf_property_get_value",
3418 				    scf_error());
3419 			}
3420 		}
3421 
3422 		ty = scf_value_type(ud_val);
3423 		assert(ty != SCF_TYPE_INVALID);
3424 		if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3425 			warn(cf_inval, ient->sc_fmri, ud_name);
3426 			return (0);
3427 		}
3428 
3429 		if (scf_value_get_as_string(ud_val, ud_ctarg,
3430 		    max_scf_value_len + 1) < 0)
3431 			bad_error("scf_value_get_as_string", scf_error());
3432 
3433 		r = fmri_equal(ud_ctarg, ud_oldtarg);
3434 		switch (r) {
3435 		case 1:
3436 			break;
3437 
3438 		case 0:
3439 		case -1:	/* warn? */
3440 			warn(cf_newtarg, ient->sc_fmri, ud_name);
3441 			return (0);
3442 
3443 		case -2:
3444 			warn(li_corrupt, ient->sc_fmri);
3445 			return (EBADF);
3446 
3447 		default:
3448 			bad_error("fmri_equal", r);
3449 		}
3450 
3451 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3452 			switch (scf_error()) {
3453 			case SCF_ERROR_NOT_FOUND:
3454 				warn(li_corrupt, ient->sc_fmri);
3455 				return (EBADF);
3456 
3457 			case SCF_ERROR_DELETED:
3458 			case SCF_ERROR_CONNECTION_BROKEN:
3459 				return (scferror2errno(scf_error()));
3460 
3461 			case SCF_ERROR_NOT_BOUND:
3462 			case SCF_ERROR_HANDLE_MISMATCH:
3463 			case SCF_ERROR_INVALID_ARGUMENT:
3464 			case SCF_ERROR_NOT_SET:
3465 			default:
3466 				bad_error("scf_snaplevel_get_pg", scf_error());
3467 			}
3468 		}
3469 
3470 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3471 		    snap_lastimport);
3472 		switch (r) {
3473 		case 0:
3474 			break;
3475 
3476 		case ECANCELED:
3477 		case ECONNABORTED:
3478 		case ENOMEM:
3479 		case EBADF:
3480 			return (r);
3481 
3482 		case EACCES:
3483 		default:
3484 			bad_error("load_pg", r);
3485 		}
3486 
3487 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3488 		switch (serr) {
3489 		case SCF_ERROR_NONE:
3490 			break;
3491 
3492 		case SCF_ERROR_NO_MEMORY:
3493 			internal_pgroup_free(old_dpt_pgroup);
3494 			return (ENOMEM);
3495 
3496 		case SCF_ERROR_NOT_FOUND:
3497 			internal_pgroup_free(old_dpt_pgroup);
3498 			goto delprop;
3499 
3500 		case SCF_ERROR_CONSTRAINT_VIOLATED:	/* caught above */
3501 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
3502 		default:
3503 			bad_error("fmri_to_entity", serr);
3504 		}
3505 
3506 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
3507 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
3508 		switch (r) {
3509 		case 0:
3510 			break;
3511 
3512 		case ECONNABORTED:
3513 			internal_pgroup_free(old_dpt_pgroup);
3514 			return (r);
3515 
3516 		case ECANCELED:
3517 		case ENOENT:
3518 			internal_pgroup_free(old_dpt_pgroup);
3519 			goto delprop;
3520 
3521 		case EBADF:
3522 			warn(r_no_lvl, ud_ctarg);
3523 			internal_pgroup_free(old_dpt_pgroup);
3524 			return (r);
3525 
3526 		case EINVAL:
3527 		default:
3528 			bad_error("entity_get_running_pg", r);
3529 		}
3530 
3531 		/* load it */
3532 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
3533 		switch (r) {
3534 		case 0:
3535 			break;
3536 
3537 		case ECANCELED:
3538 			internal_pgroup_free(old_dpt_pgroup);
3539 			goto delprop;
3540 
3541 		case ECONNABORTED:
3542 		case ENOMEM:
3543 		case EBADF:
3544 			internal_pgroup_free(old_dpt_pgroup);
3545 			return (r);
3546 
3547 		case EACCES:
3548 		default:
3549 			bad_error("load_pg", r);
3550 		}
3551 
3552 		/* compare property groups */
3553 		if (!pg_equal(old_dpt_pgroup, current_pg)) {
3554 			warn(cf_newdpg, ient->sc_fmri, ud_name);
3555 			internal_pgroup_free(old_dpt_pgroup);
3556 			internal_pgroup_free(current_pg);
3557 			return (0);
3558 		}
3559 
3560 		internal_pgroup_free(old_dpt_pgroup);
3561 		internal_pgroup_free(current_pg);
3562 
3563 		if (g_verbose)
3564 			warn(gettext("%s: Deleting dependent \"%s\".\n"),
3565 			    ient->sc_fmri, ud_name);
3566 
3567 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
3568 			switch (scf_error()) {
3569 			case SCF_ERROR_NOT_FOUND:
3570 			case SCF_ERROR_DELETED:
3571 				internal_pgroup_free(old_dpt_pgroup);
3572 				goto delprop;
3573 
3574 			case SCF_ERROR_CONNECTION_BROKEN:
3575 				internal_pgroup_free(old_dpt_pgroup);
3576 				return (ECONNABORTED);
3577 
3578 			case SCF_ERROR_NOT_SET:
3579 			case SCF_ERROR_INVALID_ARGUMENT:
3580 			case SCF_ERROR_HANDLE_MISMATCH:
3581 			case SCF_ERROR_NOT_BOUND:
3582 			default:
3583 				bad_error("entity_get_pg", scf_error());
3584 			}
3585 		}
3586 
3587 		if (scf_pg_delete(ud_pg) != 0) {
3588 			switch (scf_error()) {
3589 			case SCF_ERROR_DELETED:
3590 				break;
3591 
3592 			case SCF_ERROR_CONNECTION_BROKEN:
3593 			case SCF_ERROR_BACKEND_READONLY:
3594 			case SCF_ERROR_BACKEND_ACCESS:
3595 				return (scferror2errno(scf_error()));
3596 
3597 			case SCF_ERROR_PERMISSION_DENIED:
3598 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
3599 				return (scferror2errno(scf_error()));
3600 
3601 			case SCF_ERROR_NOT_SET:
3602 			default:
3603 				bad_error("scf_pg_delete", scf_error());
3604 			}
3605 		}
3606 
3607 		/*
3608 		 * This service was changed, so it must be refreshed.  But
3609 		 * since it's not mentioned in the new manifest, we have to
3610 		 * record its FMRI here for use later.  We record the name
3611 		 * & the entity (via sc_parent) in case we need to print error
3612 		 * messages during the refresh.
3613 		 */
3614 		dpt = internal_pgroup_new();
3615 		if (dpt == NULL)
3616 			return (ENOMEM);
3617 		dpt->sc_pgroup_name = strdup(ud_name);
3618 		dpt->sc_pgroup_fmri = strdup(ud_ctarg);
3619 		if (dpt->sc_pgroup_name == NULL || dpt->sc_pgroup_fmri == NULL)
3620 			return (ENOMEM);
3621 		dpt->sc_parent = (entity_t *)ient;
3622 		if (uu_list_insert_after(imp_deleted_dpts, NULL, dpt) != 0)
3623 			uu_die(gettext("libuutil error: %s\n"),
3624 			    uu_strerror(uu_error()));
3625 
3626 delprop:
3627 		if (tx == NULL)
3628 			return (0);
3629 
3630 		ent = scf_entry_create(g_hndl);
3631 		if (ent == NULL)
3632 			return (ENOMEM);
3633 
3634 		if (scf_transaction_property_delete(tx, ent, ud_name) != 0) {
3635 			scf_entry_destroy(ent);
3636 			switch (scf_error()) {
3637 			case SCF_ERROR_DELETED:
3638 				warn(emsg_pg_deleted, ient->sc_fmri,
3639 				    "dependents");
3640 				return (EBUSY);
3641 
3642 			case SCF_ERROR_CONNECTION_BROKEN:
3643 				return (scferror2errno(scf_error()));
3644 
3645 			case SCF_ERROR_NOT_FOUND:
3646 				break;
3647 
3648 			case SCF_ERROR_HANDLE_MISMATCH:
3649 			case SCF_ERROR_NOT_BOUND:
3650 			case SCF_ERROR_INVALID_ARGUMENT:
3651 			case SCF_ERROR_NOT_SET:
3652 			default:
3653 				bad_error("scf_transaction_property_delete",
3654 				    scf_error());
3655 			}
3656 		}
3657 
3658 		return (0);
3659 	}
3660 
3661 	new_dpt_pgroup->sc_pgroup_seen = 1;
3662 
3663 	/*
3664 	 * Decide whether the dependent has changed in the manifest.
3665 	 */
3666 	/* Compare the target. */
3667 	if (scf_property_get_value(prop, ud_val) != 0) {
3668 		switch (scf_error()) {
3669 		case SCF_ERROR_NOT_FOUND:
3670 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3671 			warn(li_corrupt, ient->sc_fmri);
3672 			return (EBADF);
3673 
3674 		case SCF_ERROR_DELETED:
3675 		case SCF_ERROR_CONNECTION_BROKEN:
3676 			return (scferror2errno(scf_error()));
3677 
3678 		case SCF_ERROR_HANDLE_MISMATCH:
3679 		case SCF_ERROR_NOT_BOUND:
3680 		case SCF_ERROR_NOT_SET:
3681 		case SCF_ERROR_PERMISSION_DENIED:
3682 		default:
3683 			bad_error("scf_property_get_value", scf_error());
3684 		}
3685 	}
3686 
3687 	if (scf_value_get_as_string(ud_val, ud_oldtarg, max_scf_value_len + 1) <
3688 	    0)
3689 		bad_error("scf_value_get_as_string", scf_error());
3690 
3691 	r = fmri_equal(ud_oldtarg, new_dpt_pgroup->sc_pgroup_fmri);
3692 	switch (r) {
3693 	case 0:
3694 		break;
3695 
3696 	case 1:
3697 		/* Compare the dependency pgs. */
3698 		if (scf_snaplevel_get_pg(snpl, ud_name, ud_pg) != 0) {
3699 			switch (scf_error()) {
3700 			case SCF_ERROR_NOT_FOUND:
3701 				warn(li_corrupt, ient->sc_fmri);
3702 				return (EBADF);
3703 
3704 			case SCF_ERROR_DELETED:
3705 			case SCF_ERROR_CONNECTION_BROKEN:
3706 				return (scferror2errno(scf_error()));
3707 
3708 			case SCF_ERROR_NOT_BOUND:
3709 			case SCF_ERROR_HANDLE_MISMATCH:
3710 			case SCF_ERROR_INVALID_ARGUMENT:
3711 			case SCF_ERROR_NOT_SET:
3712 			default:
3713 				bad_error("scf_snaplevel_get_pg", scf_error());
3714 			}
3715 		}
3716 
3717 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3718 		    snap_lastimport);
3719 		switch (r) {
3720 		case 0:
3721 			break;
3722 
3723 		case ECANCELED:
3724 		case ECONNABORTED:
3725 		case ENOMEM:
3726 		case EBADF:
3727 			return (r);
3728 
3729 		case EACCES:
3730 		default:
3731 			bad_error("load_pg", r);
3732 		}
3733 
3734 		if (pg_equal(old_dpt_pgroup, new_dpt_pgroup)) {
3735 			/* no change, leave customizations */
3736 			internal_pgroup_free(old_dpt_pgroup);
3737 			return (0);
3738 		}
3739 		break;
3740 
3741 	case -1:
3742 		warn(li_corrupt, ient->sc_fmri);
3743 		return (EBADF);
3744 
3745 	case -2:
3746 		warn(gettext("Dependent \"%s\" has invalid target \"%s\".\n"),
3747 		    ud_name, new_dpt_pgroup->sc_pgroup_fmri);
3748 		return (EINVAL);
3749 
3750 	default:
3751 		bad_error("fmri_equal", r);
3752 	}
3753 
3754 	/*
3755 	 * The dependent has changed in the manifest.  Upgrade the current
3756 	 * properties if they haven't been customized.
3757 	 */
3758 
3759 	/*
3760 	 * If new_dpt_pgroup->sc_override, then act as though the property
3761 	 * group hasn't been customized.
3762 	 */
3763 	if (new_dpt_pgroup->sc_pgroup_override)
3764 		goto nocust;
3765 
3766 	if (!ud_run_dpts_pg_set) {
3767 		warn(cf_missing, ient->sc_fmri, ud_name);
3768 		r = 0;
3769 		goto out;
3770 	} else if (scf_pg_get_property(ud_run_dpts_pg, ud_name, ud_prop) != 0) {
3771 		switch (scf_error()) {
3772 		case SCF_ERROR_NOT_FOUND:
3773 			warn(cf_missing, ient->sc_fmri, ud_name);
3774 			r = 0;
3775 			goto out;
3776 
3777 		case SCF_ERROR_CONNECTION_BROKEN:
3778 			r = scferror2errno(scf_error());
3779 			goto out;
3780 
3781 		case SCF_ERROR_DELETED:
3782 			warn(emsg_pg_deleted, ient->sc_fmri, "dependents");
3783 			r = EBUSY;
3784 			goto out;
3785 
3786 		case SCF_ERROR_INVALID_ARGUMENT:
3787 		case SCF_ERROR_NOT_BOUND:
3788 		case SCF_ERROR_HANDLE_MISMATCH:
3789 		case SCF_ERROR_NOT_SET:
3790 		default:
3791 			bad_error("scf_pg_get_property", scf_error());
3792 		}
3793 	}
3794 
3795 	if (scf_property_get_value(ud_prop, ud_val) != 0) {
3796 		switch (scf_error()) {
3797 		case SCF_ERROR_NOT_FOUND:
3798 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3799 			warn(cf_inval, ient->sc_fmri, ud_name);
3800 			r = 0;
3801 			goto out;
3802 
3803 		case SCF_ERROR_DELETED:
3804 		case SCF_ERROR_CONNECTION_BROKEN:
3805 			r = scferror2errno(scf_error());
3806 			goto out;
3807 
3808 		case SCF_ERROR_HANDLE_MISMATCH:
3809 		case SCF_ERROR_NOT_BOUND:
3810 		case SCF_ERROR_NOT_SET:
3811 		case SCF_ERROR_PERMISSION_DENIED:
3812 		default:
3813 			bad_error("scf_property_get_value", scf_error());
3814 		}
3815 	}
3816 
3817 	ty = scf_value_type(ud_val);
3818 	assert(ty != SCF_TYPE_INVALID);
3819 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
3820 		warn(cf_inval, ient->sc_fmri, ud_name);
3821 		r = 0;
3822 		goto out;
3823 	}
3824 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
3825 	    0)
3826 		bad_error("scf_value_get_as_string", scf_error());
3827 
3828 	r = fmri_equal(ud_ctarg, ud_oldtarg);
3829 	if (r == -1) {
3830 		warn(cf_inval, ient->sc_fmri, ud_name);
3831 		r = 0;
3832 		goto out;
3833 	} else if (r == -2) {
3834 		warn(li_corrupt, ient->sc_fmri);
3835 		r = EBADF;
3836 		goto out;
3837 	} else if (r == 0) {
3838 		/*
3839 		 * Target has been changed.  Only abort now if it's been
3840 		 * changed to something other than what's in the manifest.
3841 		 */
3842 		r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
3843 		if (r == -1) {
3844 			warn(cf_inval, ient->sc_fmri, ud_name);
3845 			r = 0;
3846 			goto out;
3847 		} else if (r == 0) {
3848 			warn(cf_newtarg, ient->sc_fmri, ud_name);
3849 			r = 0;
3850 			goto out;
3851 		} else if (r != 1) {
3852 			/* invalid sc_pgroup_fmri caught above */
3853 			bad_error("fmri_equal", r);
3854 		}
3855 
3856 		/*
3857 		 * Fetch the current dependency pg.  If it's what the manifest
3858 		 * says, then no problem.
3859 		 */
3860 		serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3861 		switch (serr) {
3862 		case SCF_ERROR_NONE:
3863 			break;
3864 
3865 		case SCF_ERROR_NOT_FOUND:
3866 			warn(cf_missing, ient->sc_fmri, ud_name);
3867 			r = 0;
3868 			goto out;
3869 
3870 		case SCF_ERROR_NO_MEMORY:
3871 			r = ENOMEM;
3872 			goto out;
3873 
3874 		case SCF_ERROR_CONSTRAINT_VIOLATED:
3875 		case SCF_ERROR_INVALID_ARGUMENT:
3876 		default:
3877 			bad_error("fmri_to_entity", serr);
3878 		}
3879 
3880 		r = entity_get_running_pg(target_ent, tissvc, ud_name,
3881 		    ud_pg, ud_iter2, ud_inst, imp_snap, ud_snpl);
3882 		switch (r) {
3883 		case 0:
3884 			break;
3885 
3886 		case ECONNABORTED:
3887 			goto out;
3888 
3889 		case ECANCELED:
3890 		case ENOENT:
3891 			warn(cf_missing, ient->sc_fmri, ud_name);
3892 			r = 0;
3893 			goto out;
3894 
3895 		case EBADF:
3896 			warn(r_no_lvl, ud_ctarg);
3897 			goto out;
3898 
3899 		case EINVAL:
3900 		default:
3901 			bad_error("entity_get_running_pg", r);
3902 		}
3903 
3904 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
3905 		switch (r) {
3906 		case 0:
3907 			break;
3908 
3909 		case ECANCELED:
3910 			warn(cf_missing, ient->sc_fmri, ud_name);
3911 			r = 0;
3912 			goto out;
3913 
3914 		case ECONNABORTED:
3915 		case ENOMEM:
3916 		case EBADF:
3917 			goto out;
3918 
3919 		case EACCES:
3920 		default:
3921 			bad_error("load_pg", r);
3922 		}
3923 
3924 		if (!pg_equal(current_pg, new_dpt_pgroup))
3925 			warn(cf_newdpg, ient->sc_fmri, ud_name);
3926 		internal_pgroup_free(current_pg);
3927 		r = 0;
3928 		goto out;
3929 	} else if (r != 1) {
3930 		bad_error("fmri_equal", r);
3931 	}
3932 
3933 nocust:
3934 	/*
3935 	 * Target has not been customized.  Check the dependency property
3936 	 * group.
3937 	 */
3938 
3939 	if (old_dpt_pgroup == NULL) {
3940 		if (scf_snaplevel_get_pg(snpl, new_dpt_pgroup->sc_pgroup_name,
3941 		    ud_pg) != 0) {
3942 			switch (scf_error()) {
3943 			case SCF_ERROR_NOT_FOUND:
3944 				warn(li_corrupt, ient->sc_fmri);
3945 				return (EBADF);
3946 
3947 			case SCF_ERROR_DELETED:
3948 			case SCF_ERROR_CONNECTION_BROKEN:
3949 				return (scferror2errno(scf_error()));
3950 
3951 			case SCF_ERROR_NOT_BOUND:
3952 			case SCF_ERROR_HANDLE_MISMATCH:
3953 			case SCF_ERROR_INVALID_ARGUMENT:
3954 			case SCF_ERROR_NOT_SET:
3955 			default:
3956 				bad_error("scf_snaplevel_get_pg", scf_error());
3957 			}
3958 		}
3959 
3960 		r = load_pg(ud_pg, &old_dpt_pgroup, ient->sc_fmri,
3961 		    snap_lastimport);
3962 		switch (r) {
3963 		case 0:
3964 			break;
3965 
3966 		case ECANCELED:
3967 		case ECONNABORTED:
3968 		case ENOMEM:
3969 		case EBADF:
3970 			return (r);
3971 
3972 		case EACCES:
3973 		default:
3974 			bad_error("load_pg", r);
3975 		}
3976 	}
3977 
3978 	serr = fmri_to_entity(g_hndl, ud_ctarg, &target_ent, &tissvc);
3979 	switch (serr) {
3980 	case SCF_ERROR_NONE:
3981 		break;
3982 
3983 	case SCF_ERROR_NOT_FOUND:
3984 		warn(cf_missing, ient->sc_fmri, ud_name);
3985 		r = 0;
3986 		goto out;
3987 
3988 	case SCF_ERROR_NO_MEMORY:
3989 		r = ENOMEM;
3990 		goto out;
3991 
3992 	case SCF_ERROR_CONSTRAINT_VIOLATED:
3993 	case SCF_ERROR_INVALID_ARGUMENT:
3994 	default:
3995 		bad_error("fmri_to_entity", serr);
3996 	}
3997 
3998 	r = entity_get_running_pg(target_ent, tissvc, ud_name, ud_pg,
3999 	    ud_iter2, ud_inst, imp_snap, ud_snpl);
4000 	switch (r) {
4001 	case 0:
4002 		break;
4003 
4004 	case ECONNABORTED:
4005 		goto out;
4006 
4007 	case ECANCELED:
4008 	case ENOENT:
4009 		warn(cf_missing, ient->sc_fmri, ud_name);
4010 		r = 0;
4011 		goto out;
4012 
4013 	case EBADF:
4014 		warn(r_no_lvl, ud_ctarg);
4015 		goto out;
4016 
4017 	case EINVAL:
4018 	default:
4019 		bad_error("entity_get_running_pg", r);
4020 	}
4021 
4022 	r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4023 	switch (r) {
4024 	case 0:
4025 		break;
4026 
4027 	case ECANCELED:
4028 		warn(cf_missing, ient->sc_fmri, ud_name);
4029 		goto out;
4030 
4031 	case ECONNABORTED:
4032 	case ENOMEM:
4033 	case EBADF:
4034 		goto out;
4035 
4036 	case EACCES:
4037 	default:
4038 		bad_error("load_pg", r);
4039 	}
4040 
4041 	if (!pg_equal(current_pg, old_dpt_pgroup)) {
4042 		if (!pg_equal(current_pg, new_dpt_pgroup))
4043 			warn(cf_newdpg, ient->sc_fmri, ud_name);
4044 		internal_pgroup_free(current_pg);
4045 		r = 0;
4046 		goto out;
4047 	}
4048 
4049 	/* Uncustomized.  Upgrade. */
4050 
4051 	r = fmri_equal(new_dpt_pgroup->sc_pgroup_fmri, ud_oldtarg);
4052 	switch (r) {
4053 	case 1:
4054 		if (pg_equal(current_pg, new_dpt_pgroup)) {
4055 			/* Already upgraded. */
4056 			internal_pgroup_free(current_pg);
4057 			r = 0;
4058 			goto out;
4059 		}
4060 
4061 		internal_pgroup_free(current_pg);
4062 
4063 		/* upgrade current_pg */
4064 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4065 			switch (scf_error()) {
4066 			case SCF_ERROR_CONNECTION_BROKEN:
4067 				r = scferror2errno(scf_error());
4068 				goto out;
4069 
4070 			case SCF_ERROR_DELETED:
4071 				warn(cf_missing, ient->sc_fmri, ud_name);
4072 				r = 0;
4073 				goto out;
4074 
4075 			case SCF_ERROR_NOT_FOUND:
4076 				break;
4077 
4078 			case SCF_ERROR_INVALID_ARGUMENT:
4079 			case SCF_ERROR_NOT_BOUND:
4080 			case SCF_ERROR_NOT_SET:
4081 			case SCF_ERROR_HANDLE_MISMATCH:
4082 			default:
4083 				bad_error("entity_get_pg", scf_error());
4084 			}
4085 
4086 			if (tissvc)
4087 				r = scf_service_add_pg(target_ent, ud_name,
4088 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4089 			else
4090 				r = scf_instance_add_pg(target_ent, ud_name,
4091 				    SCF_GROUP_DEPENDENCY, 0, ud_pg);
4092 			if (r != 0) {
4093 				switch (scf_error()) {
4094 				case SCF_ERROR_CONNECTION_BROKEN:
4095 				case SCF_ERROR_NO_RESOURCES:
4096 				case SCF_ERROR_BACKEND_READONLY:
4097 				case SCF_ERROR_BACKEND_ACCESS:
4098 					r = scferror2errno(scf_error());
4099 					goto out;
4100 
4101 				case SCF_ERROR_DELETED:
4102 					warn(cf_missing, ient->sc_fmri,
4103 					    ud_name);
4104 					r = 0;
4105 					goto out;
4106 
4107 				case SCF_ERROR_PERMISSION_DENIED:
4108 					warn(emsg_pg_deleted, ud_ctarg,
4109 					    ud_name);
4110 					r = EPERM;
4111 					goto out;
4112 
4113 				case SCF_ERROR_EXISTS:
4114 					warn(emsg_pg_added, ud_ctarg, ud_name);
4115 					r = EBUSY;
4116 					goto out;
4117 
4118 				case SCF_ERROR_NOT_BOUND:
4119 				case SCF_ERROR_HANDLE_MISMATCH:
4120 				case SCF_ERROR_INVALID_ARGUMENT:
4121 				case SCF_ERROR_NOT_SET:
4122 				default:
4123 					bad_error("entity_add_pg", scf_error());
4124 				}
4125 			}
4126 		}
4127 
4128 		r = load_pg(ud_pg, &current_pg, ud_ctarg, NULL);
4129 		switch (r) {
4130 		case 0:
4131 			break;
4132 
4133 		case ECANCELED:
4134 			warn(cf_missing, ient->sc_fmri, ud_name);
4135 			goto out;
4136 
4137 		case ECONNABORTED:
4138 		case ENOMEM:
4139 		case EBADF:
4140 			goto out;
4141 
4142 		case EACCES:
4143 		default:
4144 			bad_error("load_pg", r);
4145 		}
4146 
4147 		if (g_verbose)
4148 			warn(upgrading, ient->sc_fmri, ud_name);
4149 
4150 		r = upgrade_pg(ud_pg, current_pg, old_dpt_pgroup,
4151 		    new_dpt_pgroup, 0, ient->sc_fmri);
4152 		switch (r) {
4153 		case 0:
4154 			break;
4155 
4156 		case ECANCELED:
4157 			warn(emsg_pg_deleted, ud_ctarg, ud_name);
4158 			r = EBUSY;
4159 			goto out;
4160 
4161 		case EPERM:
4162 			warn(emsg_pg_mod_perm, ud_name, ud_ctarg);
4163 			goto out;
4164 
4165 		case EBUSY:
4166 			warn(emsg_pg_changed, ud_ctarg, ud_name);
4167 			goto out;
4168 
4169 		case ECONNABORTED:
4170 		case ENOMEM:
4171 		case ENOSPC:
4172 		case EROFS:
4173 		case EACCES:
4174 		case EINVAL:
4175 			goto out;
4176 
4177 		default:
4178 			bad_error("upgrade_pg", r);
4179 		}
4180 		break;
4181 
4182 	case 0: {
4183 		scf_transaction_entry_t *ent;
4184 		scf_value_t *val;
4185 
4186 		internal_pgroup_free(current_pg);
4187 
4188 		/* delete old pg */
4189 		if (g_verbose)
4190 			warn(upgrading, ient->sc_fmri, ud_name);
4191 
4192 		if (entity_get_pg(target_ent, tissvc, ud_name, ud_pg) != 0) {
4193 			switch (scf_error()) {
4194 			case SCF_ERROR_CONNECTION_BROKEN:
4195 				r = scferror2errno(scf_error());
4196 				goto out;
4197 
4198 			case SCF_ERROR_DELETED:
4199 				warn(cf_missing, ient->sc_fmri, ud_name);
4200 				r = 0;
4201 				goto out;
4202 
4203 			case SCF_ERROR_NOT_FOUND:
4204 				break;
4205 
4206 			case SCF_ERROR_INVALID_ARGUMENT:
4207 			case SCF_ERROR_NOT_BOUND:
4208 			case SCF_ERROR_NOT_SET:
4209 			case SCF_ERROR_HANDLE_MISMATCH:
4210 			default:
4211 				bad_error("entity_get_pg", scf_error());
4212 			}
4213 		} else if (scf_pg_delete(ud_pg) != 0) {
4214 			switch (scf_error()) {
4215 			case SCF_ERROR_DELETED:
4216 				break;
4217 
4218 			case SCF_ERROR_CONNECTION_BROKEN:
4219 			case SCF_ERROR_BACKEND_READONLY:
4220 			case SCF_ERROR_BACKEND_ACCESS:
4221 				r = scferror2errno(scf_error());
4222 				goto out;
4223 
4224 			case SCF_ERROR_PERMISSION_DENIED:
4225 				warn(emsg_pg_del_perm, ud_name, ient->sc_fmri);
4226 				r = scferror2errno(scf_error());
4227 				goto out;
4228 
4229 			case SCF_ERROR_NOT_SET:
4230 			default:
4231 				bad_error("scf_pg_delete", scf_error());
4232 			}
4233 		}
4234 
4235 		/* import new one */
4236 		cbdata.sc_handle = g_hndl;
4237 		cbdata.sc_trans = NULL;		/* handled below */
4238 
4239 		r = lscf_dependent_import(new_dpt_pgroup, &cbdata);
4240 		if (r != UU_WALK_NEXT) {
4241 			if (r != UU_WALK_ERROR)
4242 				bad_error("lscf_dependent_import", r);
4243 
4244 			r = cbdata.sc_err;
4245 			goto out;
4246 		}
4247 
4248 		if (tx == NULL)
4249 			break;
4250 
4251 		if ((ent = scf_entry_create(g_hndl)) == NULL ||
4252 		    (val = scf_value_create(g_hndl)) == NULL) {
4253 			if (scf_error() == SCF_ERROR_NO_MEMORY)
4254 				return (ENOMEM);
4255 
4256 			bad_error("scf_entry_create", scf_error());
4257 		}
4258 
4259 		if (scf_transaction_property_change_type(tx, ent, ud_name,
4260 		    SCF_TYPE_FMRI) != 0) {
4261 			switch (scf_error()) {
4262 			case SCF_ERROR_CONNECTION_BROKEN:
4263 				r = scferror2errno(scf_error());
4264 				goto out;
4265 
4266 			case SCF_ERROR_DELETED:
4267 				warn(emsg_pg_deleted, ient->sc_fmri,
4268 				    "dependents");
4269 				r = EBUSY;
4270 				goto out;
4271 
4272 			case SCF_ERROR_NOT_FOUND:
4273 				break;
4274 
4275 			case SCF_ERROR_NOT_BOUND:
4276 			case SCF_ERROR_HANDLE_MISMATCH:
4277 			case SCF_ERROR_INVALID_ARGUMENT:
4278 			case SCF_ERROR_NOT_SET:
4279 			default:
4280 				bad_error("scf_transaction_property_"
4281 				    "change_type", scf_error());
4282 			}
4283 
4284 			if (scf_transaction_property_new(tx, ent, ud_name,
4285 			    SCF_TYPE_FMRI) != 0) {
4286 				switch (scf_error()) {
4287 				case SCF_ERROR_CONNECTION_BROKEN:
4288 					r = scferror2errno(scf_error());
4289 					goto out;
4290 
4291 				case SCF_ERROR_DELETED:
4292 					warn(emsg_pg_deleted, ient->sc_fmri,
4293 					    "dependents");
4294 					r = EBUSY;
4295 					goto out;
4296 
4297 				case SCF_ERROR_EXISTS:
4298 					warn(emsg_pg_changed, ient->sc_fmri,
4299 					    "dependents");
4300 					r = EBUSY;
4301 					goto out;
4302 
4303 				case SCF_ERROR_INVALID_ARGUMENT:
4304 				case SCF_ERROR_HANDLE_MISMATCH:
4305 				case SCF_ERROR_NOT_BOUND:
4306 				case SCF_ERROR_NOT_SET:
4307 				default:
4308 					bad_error("scf_transaction_property_"
4309 					    "new", scf_error());
4310 				}
4311 			}
4312 		}
4313 
4314 		if (scf_value_set_from_string(val, SCF_TYPE_FMRI,
4315 		    new_dpt_pgroup->sc_pgroup_fmri) != 0)
4316 			/* invalid sc_pgroup_fmri caught above */
4317 			bad_error("scf_value_set_from_string",
4318 			    scf_error());
4319 
4320 		if (scf_entry_add_value(ent, val) != 0)
4321 			bad_error("scf_entry_add_value", scf_error());
4322 		break;
4323 	}
4324 
4325 	case -2:
4326 		warn(li_corrupt, ient->sc_fmri);
4327 		internal_pgroup_free(current_pg);
4328 		r = EBADF;
4329 		goto out;
4330 
4331 	case -1:
4332 	default:
4333 		/* invalid sc_pgroup_fmri caught above */
4334 		bad_error("fmri_equal", r);
4335 	}
4336 
4337 	r = 0;
4338 
4339 out:
4340 	if (old_dpt_pgroup != NULL)
4341 		internal_pgroup_free(old_dpt_pgroup);
4342 
4343 	return (r);
4344 }
4345 
4346 /*
4347  * new_dpt_pgroup was in the manifest but not the last-import snapshot, so we
4348  * would import it, except it seems to exist in the service anyway.  Compare
4349  * the existent dependent with the one we would import, and report any
4350  * differences (if there are none, be silent).  prop is the property which
4351  * represents the existent dependent (in the dependents property group) in the
4352  * entity corresponding to ient.
4353  *
4354  * Returns
4355  *   0 - success (Sort of.  At least, we can continue importing.)
4356  *   ECONNABORTED - repository connection broken
4357  *   EBUSY - ancestor of prop was deleted (error printed)
4358  *   ENOMEM - out of memory
4359  *   EBADF - corrupt property group (error printed)
4360  *   EINVAL - new_dpt_pgroup has invalid target (error printed)
4361  */
4362 static int
4363 handle_dependent_conflict(const entity_t * const ient,
4364     const scf_property_t * const prop, const pgroup_t * const new_dpt_pgroup)
4365 {
4366 	int r;
4367 	scf_type_t ty;
4368 	scf_error_t scfe;
4369 	void *tptr;
4370 	int tissvc;
4371 	pgroup_t *pgroup;
4372 
4373 	if (scf_property_get_value(prop, ud_val) != 0) {
4374 		switch (scf_error()) {
4375 		case SCF_ERROR_CONNECTION_BROKEN:
4376 			return (scferror2errno(scf_error()));
4377 
4378 		case SCF_ERROR_DELETED:
4379 			warn(emsg_pg_deleted, ient->sc_fmri,
4380 			    new_dpt_pgroup->sc_pgroup_name);
4381 			return (EBUSY);
4382 
4383 		case SCF_ERROR_CONSTRAINT_VIOLATED:
4384 		case SCF_ERROR_NOT_FOUND:
4385 			warn(gettext("Conflict upgrading %s (not importing "
4386 			    "dependent \"%s\" because it already exists.)  "
4387 			    "Warning: The \"%s/%2$s\" property has more or "
4388 			    "fewer than one value)).\n"), ient->sc_fmri,
4389 			    new_dpt_pgroup->sc_pgroup_name, "dependents");
4390 			return (0);
4391 
4392 		case SCF_ERROR_HANDLE_MISMATCH:
4393 		case SCF_ERROR_NOT_BOUND:
4394 		case SCF_ERROR_NOT_SET:
4395 		case SCF_ERROR_PERMISSION_DENIED:
4396 		default:
4397 			bad_error("scf_property_get_value",
4398 			    scf_error());
4399 		}
4400 	}
4401 
4402 	ty = scf_value_type(ud_val);
4403 	assert(ty != SCF_TYPE_INVALID);
4404 	if (!(ty == SCF_TYPE_FMRI || ty == SCF_TYPE_ASTRING)) {
4405 		warn(gettext("Conflict upgrading %s (not importing dependent "
4406 		    "\"%s\" because it already exists).  Warning: The "
4407 		    "\"%s/%s\" property has unexpected type \"%s\")).\n"),
4408 		    ient->sc_fmri, new_dpt_pgroup->sc_pgroup_name,
4409 		    scf_type_to_string(ty), "dependents");
4410 		return (0);
4411 	}
4412 
4413 	if (scf_value_get_as_string(ud_val, ud_ctarg, max_scf_value_len + 1) <
4414 	    0)
4415 		bad_error("scf_value_get_as_string", scf_error());
4416 
4417 	r = fmri_equal(ud_ctarg, new_dpt_pgroup->sc_pgroup_fmri);
4418 	switch (r) {
4419 	case 0:
4420 		warn(gettext("Conflict upgrading %s (not importing dependent "
4421 		    "\"%s\" (target \"%s\") because it already exists with "
4422 		    "target \"%s\").\n"), ient->sc_fmri,
4423 		    new_dpt_pgroup->sc_pgroup_name,
4424 		    new_dpt_pgroup->sc_pgroup_fmri, ud_ctarg);
4425 		return (0);
4426 
4427 	case 1:
4428 		break;
4429 
4430 	case -1:
4431 		warn(gettext("Conflict upgrading %s (not importing dependent "
4432 		    "\"%s\" because it already exists).  Warning: The current "
4433 		    "dependent's target (%s) is invalid.\n"), ient->sc_fmri,
4434 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4435 		return (0);
4436 
4437 	case -2:
4438 		warn(gettext("Dependent \"%s\" of %s has invalid target "
4439 		    "\"%s\".\n"), new_dpt_pgroup->sc_pgroup_name, ient->sc_fmri,
4440 		    new_dpt_pgroup->sc_pgroup_fmri);
4441 		return (EINVAL);
4442 
4443 	default:
4444 		bad_error("fmri_equal", r);
4445 	}
4446 
4447 	/* compare dependency pgs in target */
4448 	scfe = fmri_to_entity(g_hndl, ud_ctarg, &tptr, &tissvc);
4449 	switch (scfe) {
4450 	case SCF_ERROR_NONE:
4451 		break;
4452 
4453 	case SCF_ERROR_NO_MEMORY:
4454 		return (ENOMEM);
4455 
4456 	case SCF_ERROR_NOT_FOUND:
4457 		warn(emsg_dpt_dangling, ient->sc_fmri,
4458 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4459 		return (0);
4460 
4461 	case SCF_ERROR_CONSTRAINT_VIOLATED:
4462 	case SCF_ERROR_INVALID_ARGUMENT:
4463 	default:
4464 		bad_error("fmri_to_entity", scfe);
4465 	}
4466 
4467 	r = entity_get_running_pg(tptr, tissvc, new_dpt_pgroup->sc_pgroup_name,
4468 	    ud_pg, ud_iter, ud_inst, imp_snap, ud_snpl);
4469 	switch (r) {
4470 	case 0:
4471 		break;
4472 
4473 	case ECONNABORTED:
4474 		return (r);
4475 
4476 	case ECANCELED:
4477 		warn(emsg_dpt_dangling, ient->sc_fmri,
4478 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg);
4479 		return (0);
4480 
4481 	case EBADF:
4482 		if (tissvc)
4483 			warn(gettext("%s has an instance with a \"%s\" "
4484 			    "snapshot which is missing a snaplevel.\n"),
4485 			    ud_ctarg, "running");
4486 		else
4487 			warn(gettext("%s has a \"%s\" snapshot which is "
4488 			    "missing a snaplevel.\n"), ud_ctarg, "running");
4489 		/* FALLTHROUGH */
4490 
4491 	case ENOENT:
4492 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4493 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4494 		    new_dpt_pgroup->sc_pgroup_name);
4495 		return (0);
4496 
4497 	case EINVAL:
4498 	default:
4499 		bad_error("entity_get_running_pg", r);
4500 	}
4501 
4502 	pgroup = internal_pgroup_new();
4503 	if (pgroup == NULL)
4504 		return (ENOMEM);
4505 
4506 	r = load_pg(ud_pg, &pgroup, ud_ctarg, NULL);
4507 	switch (r) {
4508 	case 0:
4509 		break;
4510 
4511 	case ECONNABORTED:
4512 	case EBADF:
4513 	case ENOMEM:
4514 		internal_pgroup_free(pgroup);
4515 		return (r);
4516 
4517 	case ECANCELED:
4518 		warn(emsg_dpt_no_dep, ient->sc_fmri,
4519 		    new_dpt_pgroup->sc_pgroup_name, ud_ctarg,
4520 		    new_dpt_pgroup->sc_pgroup_name);
4521 		internal_pgroup_free(pgroup);
4522 		return (0);
4523 
4524 	case EACCES:
4525 	default:
4526 		bad_error("load_pg", r);
4527 	}
4528 
4529 	/* report differences */
4530 	report_pg_diffs(new_dpt_pgroup, pgroup, ud_ctarg, 1);
4531 	internal_pgroup_free(pgroup);
4532 	return (0);
4533 }
4534 
4535 /*
4536  * lipg is a property group in the last-import snapshot of ent, which is an
4537  * scf_service_t or an scf_instance_t (according to ient).  If lipg is not in
4538  * ient's pgroups, delete it from ent if it hasn't been customized.  If it is
4539  * in ents's property groups, compare and upgrade ent appropriately.
4540  *
4541  * Returns
4542  *   0 - success
4543  *   ECONNABORTED - repository connection broken
4544  *   ENOMEM - out of memory
4545  *   ENOSPC - configd is out of resources
4546  *   EINVAL - ient has invalid dependent (error printed)
4547  *	    - ient has invalid pgroup_t (error printed)
4548  *   ECANCELED - ent has been deleted
4549  *   ENODEV - entity containing lipg has been deleted
4550  *	    - entity containing running has been deleted
4551  *   EPERM - could not delete pg (permission denied) (error printed)
4552  *	   - couldn't upgrade dependents (permission denied) (error printed)
4553  *	   - couldn't import pg (permission denied) (error printed)
4554  *	   - couldn't upgrade pg (permission denied) (error printed)
4555  *   EROFS - could not delete pg (repository read-only)
4556  *	   - couldn't upgrade dependents (repository read-only)
4557  *	   - couldn't import pg (repository read-only)
4558  *	   - couldn't upgrade pg (repository read-only)
4559  *   EACCES - could not delete pg (backend access denied)
4560  *	    - couldn't upgrade dependents (backend access denied)
4561  *	    - couldn't import pg (backend access denied)
4562  *	    - couldn't upgrade pg (backend access denied)
4563  *	    - couldn't read property (backend access denied)
4564  *   EBUSY - property group was added (error printed)
4565  *	   - property group was deleted (error printed)
4566  *	   - property group changed (error printed)
4567  *	   - "dependents" pg was added, changed, or deleted (error printed)
4568  *	   - dependent target deleted (error printed)
4569  *	   - dependent pg changed (error printed)
4570  *   EBADF - imp_snpl is corrupt (error printed)
4571  *	   - ent has bad pg (error printed)
4572  *   EEXIST - dependent collision in target service (error printed)
4573  */
4574 static int
4575 process_old_pg(const scf_propertygroup_t *lipg, entity_t *ient, void *ent,
4576     const scf_snaplevel_t *running)
4577 {
4578 	int r;
4579 	pgroup_t *mpg, *lipg_i, *curpg_i, pgrp;
4580 	scf_callback_t cbdata;
4581 
4582 	const char * const cf_pg_missing =
4583 	    gettext("Conflict upgrading %s (property group %s is missing)\n");
4584 	const char * const deleting =
4585 	    gettext("%s: Deleting property group \"%s\".\n");
4586 
4587 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
4588 
4589 	/* Skip dependent property groups. */
4590 	if (scf_pg_get_type(lipg, imp_str, imp_str_sz) < 0) {
4591 		switch (scf_error()) {
4592 		case SCF_ERROR_DELETED:
4593 			return (ENODEV);
4594 
4595 		case SCF_ERROR_CONNECTION_BROKEN:
4596 			return (ECONNABORTED);
4597 
4598 		case SCF_ERROR_NOT_SET:
4599 		case SCF_ERROR_NOT_BOUND:
4600 		default:
4601 			bad_error("scf_pg_get_type", scf_error());
4602 		}
4603 	}
4604 
4605 	if (strcmp(imp_str, SCF_GROUP_DEPENDENCY) == 0) {
4606 		if (scf_pg_get_property(lipg, "external", NULL) == 0)
4607 			return (0);
4608 
4609 		switch (scf_error()) {
4610 		case SCF_ERROR_NOT_FOUND:
4611 			break;
4612 
4613 		case SCF_ERROR_CONNECTION_BROKEN:
4614 			return (ECONNABORTED);
4615 
4616 		case SCF_ERROR_DELETED:
4617 			return (ENODEV);
4618 
4619 		case SCF_ERROR_INVALID_ARGUMENT:
4620 		case SCF_ERROR_NOT_BOUND:
4621 		case SCF_ERROR_HANDLE_MISMATCH:
4622 		case SCF_ERROR_NOT_SET:
4623 		default:
4624 			bad_error("scf_pg_get_property", scf_error());
4625 		}
4626 	}
4627 
4628 	/* lookup pg in new properties */
4629 	if (scf_pg_get_name(lipg, imp_str, imp_str_sz) < 0) {
4630 		switch (scf_error()) {
4631 		case SCF_ERROR_DELETED:
4632 			return (ENODEV);
4633 
4634 		case SCF_ERROR_CONNECTION_BROKEN:
4635 			return (ECONNABORTED);
4636 
4637 		case SCF_ERROR_NOT_SET:
4638 		case SCF_ERROR_NOT_BOUND:
4639 		default:
4640 			bad_error("scf_pg_get_name", scf_error());
4641 		}
4642 	}
4643 
4644 	pgrp.sc_pgroup_name = imp_str;
4645 	mpg = uu_list_find(ient->sc_pgroups, &pgrp, NULL, NULL);
4646 
4647 	if (mpg != NULL)
4648 		mpg->sc_pgroup_seen = 1;
4649 
4650 	/* Special handling for dependents */
4651 	if (strcmp(imp_str, "dependents") == 0)
4652 		return (upgrade_dependents(lipg, imp_snpl, ient, running, ent));
4653 
4654 	if (mpg == NULL || mpg->sc_pgroup_delete) {
4655 		/* property group was deleted from manifest */
4656 		if (entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4657 			switch (scf_error()) {
4658 			case SCF_ERROR_NOT_FOUND:
4659 				return (0);
4660 
4661 			case SCF_ERROR_DELETED:
4662 			case SCF_ERROR_CONNECTION_BROKEN:
4663 				return (scferror2errno(scf_error()));
4664 
4665 			case SCF_ERROR_INVALID_ARGUMENT:
4666 			case SCF_ERROR_HANDLE_MISMATCH:
4667 			case SCF_ERROR_NOT_BOUND:
4668 			case SCF_ERROR_NOT_SET:
4669 			default:
4670 				bad_error("entity_get_pg", scf_error());
4671 			}
4672 		}
4673 
4674 		if (mpg != NULL && mpg->sc_pgroup_delete) {
4675 			if (g_verbose)
4676 				warn(deleting, ient->sc_fmri, imp_str);
4677 			if (scf_pg_delete(imp_pg2) == 0)
4678 				return (0);
4679 
4680 			switch (scf_error()) {
4681 			case SCF_ERROR_DELETED:
4682 				return (0);
4683 
4684 			case SCF_ERROR_CONNECTION_BROKEN:
4685 			case SCF_ERROR_BACKEND_READONLY:
4686 			case SCF_ERROR_BACKEND_ACCESS:
4687 				return (scferror2errno(scf_error()));
4688 
4689 			case SCF_ERROR_PERMISSION_DENIED:
4690 				warn(emsg_pg_del_perm, imp_str, ient->sc_fmri);
4691 				return (scferror2errno(scf_error()));
4692 
4693 			case SCF_ERROR_NOT_SET:
4694 			default:
4695 				bad_error("scf_pg_delete", scf_error());
4696 			}
4697 		}
4698 
4699 		r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4700 		switch (r) {
4701 		case 0:
4702 			break;
4703 
4704 		case ECANCELED:
4705 			return (ENODEV);
4706 
4707 		case ECONNABORTED:
4708 		case ENOMEM:
4709 		case EBADF:
4710 		case EACCES:
4711 			return (r);
4712 
4713 		default:
4714 			bad_error("load_pg", r);
4715 		}
4716 
4717 		r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
4718 		switch (r) {
4719 		case 0:
4720 			break;
4721 
4722 		case ECANCELED:
4723 		case ECONNABORTED:
4724 		case ENOMEM:
4725 		case EBADF:
4726 		case EACCES:
4727 			internal_pgroup_free(lipg_i);
4728 			return (r);
4729 
4730 		default:
4731 			bad_error("load_pg", r);
4732 		}
4733 
4734 		if (pg_equal(lipg_i, curpg_i)) {
4735 			if (g_verbose)
4736 				warn(deleting, ient->sc_fmri, imp_str);
4737 			if (scf_pg_delete(imp_pg2) != 0) {
4738 				switch (scf_error()) {
4739 				case SCF_ERROR_DELETED:
4740 					break;
4741 
4742 				case SCF_ERROR_CONNECTION_BROKEN:
4743 					internal_pgroup_free(lipg_i);
4744 					internal_pgroup_free(curpg_i);
4745 					return (ECONNABORTED);
4746 
4747 				case SCF_ERROR_NOT_SET:
4748 				case SCF_ERROR_NOT_BOUND:
4749 				default:
4750 					bad_error("scf_pg_delete", scf_error());
4751 				}
4752 			}
4753 		} else {
4754 			report_pg_diffs(lipg_i, curpg_i, ient->sc_fmri, 0);
4755 		}
4756 
4757 		internal_pgroup_free(lipg_i);
4758 		internal_pgroup_free(curpg_i);
4759 
4760 		return (0);
4761 	}
4762 
4763 	/*
4764 	 * Only dependent pgs can have override set, and we skipped those
4765 	 * above.
4766 	 */
4767 	assert(!mpg->sc_pgroup_override);
4768 
4769 	/* compare */
4770 	r = load_pg(lipg, &lipg_i, ient->sc_fmri, snap_lastimport);
4771 	switch (r) {
4772 	case 0:
4773 		break;
4774 
4775 	case ECANCELED:
4776 		return (ENODEV);
4777 
4778 	case ECONNABORTED:
4779 	case EBADF:
4780 	case ENOMEM:
4781 	case EACCES:
4782 		return (r);
4783 
4784 	default:
4785 		bad_error("load_pg", r);
4786 	}
4787 
4788 	if (pg_equal(mpg, lipg_i)) {
4789 		/* The manifest pg has not changed.  Move on. */
4790 		r = 0;
4791 		goto out;
4792 	}
4793 
4794 	/* upgrade current properties according to lipg & mpg */
4795 	if (running != NULL)
4796 		r = scf_snaplevel_get_pg(running, imp_str, imp_pg2);
4797 	else
4798 		r = entity_get_pg(ent, issvc, imp_str, imp_pg2);
4799 	if (r != 0) {
4800 		switch (scf_error()) {
4801 		case SCF_ERROR_CONNECTION_BROKEN:
4802 			r = scferror2errno(scf_error());
4803 			goto out;
4804 
4805 		case SCF_ERROR_DELETED:
4806 			if (running != NULL)
4807 				r = ENODEV;
4808 			else
4809 				r = ECANCELED;
4810 			goto out;
4811 
4812 		case SCF_ERROR_NOT_FOUND:
4813 			break;
4814 
4815 		case SCF_ERROR_INVALID_ARGUMENT:
4816 		case SCF_ERROR_HANDLE_MISMATCH:
4817 		case SCF_ERROR_NOT_BOUND:
4818 		case SCF_ERROR_NOT_SET:
4819 		default:
4820 			bad_error("entity_get_pg", scf_error());
4821 		}
4822 
4823 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
4824 
4825 		r = 0;
4826 		goto out;
4827 	}
4828 
4829 	r = load_pg_attrs(imp_pg2, &curpg_i);
4830 	switch (r) {
4831 	case 0:
4832 		break;
4833 
4834 	case ECANCELED:
4835 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
4836 		r = 0;
4837 		goto out;
4838 
4839 	case ECONNABORTED:
4840 	case ENOMEM:
4841 		goto out;
4842 
4843 	default:
4844 		bad_error("load_pg_attrs", r);
4845 	}
4846 
4847 	if (!pg_attrs_equal(lipg_i, curpg_i, NULL, 0)) {
4848 		(void) pg_attrs_equal(curpg_i, mpg, ient->sc_fmri, 0);
4849 		internal_pgroup_free(curpg_i);
4850 		r = 0;
4851 		goto out;
4852 	}
4853 
4854 	internal_pgroup_free(curpg_i);
4855 
4856 	r = load_pg(imp_pg2, &curpg_i, ient->sc_fmri, NULL);
4857 	switch (r) {
4858 	case 0:
4859 		break;
4860 
4861 	case ECANCELED:
4862 		warn(cf_pg_missing, ient->sc_fmri, imp_str);
4863 		r = 0;
4864 		goto out;
4865 
4866 	case ECONNABORTED:
4867 	case EBADF:
4868 	case ENOMEM:
4869 	case EACCES:
4870 		goto out;
4871 
4872 	default:
4873 		bad_error("load_pg", r);
4874 	}
4875 
4876 	if (pg_equal(lipg_i, curpg_i) &&
4877 	    !pg_attrs_equal(lipg_i, mpg, NULL, 0)) {
4878 		int do_delete = 1;
4879 
4880 		if (g_verbose)
4881 			warn(gettext("%s: Upgrading property group \"%s\".\n"),
4882 			    ient->sc_fmri, mpg->sc_pgroup_name);
4883 
4884 		internal_pgroup_free(curpg_i);
4885 
4886 		if (running != NULL &&
4887 		    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4888 			switch (scf_error()) {
4889 			case SCF_ERROR_DELETED:
4890 				r = ECANCELED;
4891 				goto out;
4892 
4893 			case SCF_ERROR_NOT_FOUND:
4894 				do_delete = 0;
4895 				break;
4896 
4897 			case SCF_ERROR_CONNECTION_BROKEN:
4898 				r = scferror2errno(scf_error());
4899 				goto out;
4900 
4901 			case SCF_ERROR_HANDLE_MISMATCH:
4902 			case SCF_ERROR_INVALID_ARGUMENT:
4903 			case SCF_ERROR_NOT_SET:
4904 			case SCF_ERROR_NOT_BOUND:
4905 			default:
4906 				bad_error("entity_get_pg", scf_error());
4907 			}
4908 		}
4909 
4910 		if (do_delete && scf_pg_delete(imp_pg2) != 0) {
4911 			switch (scf_error()) {
4912 			case SCF_ERROR_DELETED:
4913 				break;
4914 
4915 			case SCF_ERROR_CONNECTION_BROKEN:
4916 			case SCF_ERROR_BACKEND_READONLY:
4917 			case SCF_ERROR_BACKEND_ACCESS:
4918 				r = scferror2errno(scf_error());
4919 				goto out;
4920 
4921 			case SCF_ERROR_PERMISSION_DENIED:
4922 				warn(emsg_pg_del_perm, mpg->sc_pgroup_name,
4923 				    ient->sc_fmri);
4924 				r = scferror2errno(scf_error());
4925 				goto out;
4926 
4927 			case SCF_ERROR_NOT_SET:
4928 			case SCF_ERROR_NOT_BOUND:
4929 			default:
4930 				bad_error("scf_pg_delete", scf_error());
4931 			}
4932 		}
4933 
4934 		cbdata.sc_handle = g_hndl;
4935 		cbdata.sc_parent = ent;
4936 		cbdata.sc_service = issvc;
4937 		cbdata.sc_flags = 0;
4938 		cbdata.sc_source_fmri = ient->sc_fmri;
4939 		cbdata.sc_target_fmri = ient->sc_fmri;
4940 
4941 		r = entity_pgroup_import(mpg, &cbdata);
4942 		switch (r) {
4943 		case UU_WALK_NEXT:
4944 			r = 0;
4945 			goto out;
4946 
4947 		case UU_WALK_ERROR:
4948 			if (cbdata.sc_err == EEXIST) {
4949 				warn(emsg_pg_added, ient->sc_fmri,
4950 				    mpg->sc_pgroup_name);
4951 				r = EBUSY;
4952 			} else {
4953 				r = cbdata.sc_err;
4954 			}
4955 			goto out;
4956 
4957 		default:
4958 			bad_error("entity_pgroup_import", r);
4959 		}
4960 	}
4961 
4962 	if (running != NULL &&
4963 	    entity_get_pg(ent, issvc, imp_str, imp_pg2) != 0) {
4964 		switch (scf_error()) {
4965 		case SCF_ERROR_CONNECTION_BROKEN:
4966 		case SCF_ERROR_DELETED:
4967 			r = scferror2errno(scf_error());
4968 			goto out;
4969 
4970 		case SCF_ERROR_NOT_FOUND:
4971 			break;
4972 
4973 		case SCF_ERROR_HANDLE_MISMATCH:
4974 		case SCF_ERROR_INVALID_ARGUMENT:
4975 		case SCF_ERROR_NOT_SET:
4976 		case SCF_ERROR_NOT_BOUND:
4977 		default:
4978 			bad_error("entity_get_pg", scf_error());
4979 		}
4980 
4981 		cbdata.sc_handle = g_hndl;
4982 		cbdata.sc_parent = ent;
4983 		cbdata.sc_service = issvc;
4984 		cbdata.sc_flags = SCI_FORCE;
4985 		cbdata.sc_source_fmri = ient->sc_fmri;
4986 		cbdata.sc_target_fmri = ient->sc_fmri;
4987 
4988 		r = entity_pgroup_import(mpg, &cbdata);
4989 		switch (r) {
4990 		case UU_WALK_NEXT:
4991 			r = 0;
4992 			goto out;
4993 
4994 		case UU_WALK_ERROR:
4995 			if (cbdata.sc_err == EEXIST) {
4996 				warn(emsg_pg_added, ient->sc_fmri,
4997 				    mpg->sc_pgroup_name);
4998 				r = EBUSY;
4999 			} else {
5000 				r = cbdata.sc_err;
5001 			}
5002 			goto out;
5003 
5004 		default:
5005 			bad_error("entity_pgroup_import", r);
5006 		}
5007 	}
5008 
5009 	r = upgrade_pg(imp_pg2, curpg_i, lipg_i, mpg, g_verbose, ient->sc_fmri);
5010 	internal_pgroup_free(curpg_i);
5011 	switch (r) {
5012 	case 0:
5013 		ient->sc_import_state = IMPORT_PROP_BEGUN;
5014 		break;
5015 
5016 	case ECANCELED:
5017 		warn(emsg_pg_deleted, ient->sc_fmri, mpg->sc_pgroup_name);
5018 		r = EBUSY;
5019 		break;
5020 
5021 	case EPERM:
5022 		warn(emsg_pg_mod_perm, mpg->sc_pgroup_name, ient->sc_fmri);
5023 		break;
5024 
5025 	case EBUSY:
5026 		warn(emsg_pg_changed, ient->sc_fmri, mpg->sc_pgroup_name);
5027 		break;
5028 
5029 	case ECONNABORTED:
5030 	case ENOMEM:
5031 	case ENOSPC:
5032 	case EROFS:
5033 	case EACCES:
5034 	case EINVAL:
5035 		break;
5036 
5037 	default:
5038 		bad_error("upgrade_pg", r);
5039 	}
5040 
5041 out:
5042 	internal_pgroup_free(lipg_i);
5043 	return (r);
5044 }
5045 
5046 /*
5047  * Upgrade the properties of ent according to snpl & ient.
5048  *
5049  * Returns
5050  *   0 - success
5051  *   ECONNABORTED - repository connection broken
5052  *   ENOMEM - out of memory
5053  *   ENOSPC - configd is out of resources
5054  *   ECANCELED - ent was deleted
5055  *   ENODEV - entity containing snpl was deleted
5056  *	    - entity containing running was deleted
5057  *   EBADF - imp_snpl is corrupt (error printed)
5058  *	   - ent has corrupt pg (error printed)
5059  *	   - dependent has corrupt pg (error printed)
5060  *	   - dependent target has a corrupt snapshot (error printed)
5061  *   EBUSY - pg was added, changed, or deleted (error printed)
5062  *	   - dependent target was deleted (error printed)
5063  *	   - dependent pg changed (error printed)
5064  *   EINVAL - invalid property group name (error printed)
5065  *	    - invalid property name (error printed)
5066  *	    - invalid value (error printed)
5067  *	    - ient has invalid pgroup or dependent (error printed)
5068  *   EPERM - could not create property group (permission denied) (error printed)
5069  *	   - could not modify property group (permission denied) (error printed)
5070  *	   - couldn't delete, upgrade, or import pg or dependent (error printed)
5071  *   EROFS - could not create property group (repository read-only)
5072  *	   - couldn't delete, upgrade, or import pg or dependent
5073  *   EACCES - could not create property group (backend access denied)
5074  *	    - couldn't delete, upgrade, or import pg or dependent
5075  *   EEXIST - dependent collision in target service (error printed)
5076  */
5077 static int
5078 upgrade_props(void *ent, scf_snaplevel_t *running, scf_snaplevel_t *snpl,
5079     entity_t *ient)
5080 {
5081 	pgroup_t *pg, *rpg;
5082 	int r;
5083 	uu_list_t *pgs = ient->sc_pgroups;
5084 
5085 	const int issvc = (ient->sc_etype == SVCCFG_SERVICE_OBJECT);
5086 
5087 	/* clear sc_sceen for pgs */
5088 	if (uu_list_walk(pgs, clear_int,
5089 	    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) != 0)
5090 		bad_error("uu_list_walk", uu_error());
5091 
5092 	if (scf_iter_snaplevel_pgs(imp_up_iter, snpl) != 0) {
5093 		switch (scf_error()) {
5094 		case SCF_ERROR_DELETED:
5095 			return (ENODEV);
5096 
5097 		case SCF_ERROR_CONNECTION_BROKEN:
5098 			return (ECONNABORTED);
5099 
5100 		case SCF_ERROR_NOT_SET:
5101 		case SCF_ERROR_NOT_BOUND:
5102 		case SCF_ERROR_HANDLE_MISMATCH:
5103 		default:
5104 			bad_error("scf_iter_snaplevel_pgs", scf_error());
5105 		}
5106 	}
5107 
5108 	for (;;) {
5109 		r = scf_iter_next_pg(imp_up_iter, imp_pg);
5110 		if (r == 0)
5111 			break;
5112 		if (r == 1) {
5113 			r = process_old_pg(imp_pg, ient, ent, running);
5114 			switch (r) {
5115 			case 0:
5116 				break;
5117 
5118 			case ECONNABORTED:
5119 			case ENOMEM:
5120 			case ENOSPC:
5121 			case ECANCELED:
5122 			case ENODEV:
5123 			case EPERM:
5124 			case EROFS:
5125 			case EACCES:
5126 			case EBADF:
5127 			case EBUSY:
5128 			case EINVAL:
5129 			case EEXIST:
5130 				return (r);
5131 
5132 			default:
5133 				bad_error("process_old_pg", r);
5134 			}
5135 			continue;
5136 		}
5137 		if (r != -1)
5138 			bad_error("scf_iter_next_pg", r);
5139 
5140 		switch (scf_error()) {
5141 		case SCF_ERROR_DELETED:
5142 			return (ENODEV);
5143 
5144 		case SCF_ERROR_CONNECTION_BROKEN:
5145 			return (ECONNABORTED);
5146 
5147 		case SCF_ERROR_HANDLE_MISMATCH:
5148 		case SCF_ERROR_NOT_BOUND:
5149 		case SCF_ERROR_NOT_SET:
5150 		case SCF_ERROR_INVALID_ARGUMENT:
5151 		default:
5152 			bad_error("scf_iter_next_pg", scf_error());
5153 		}
5154 	}
5155 
5156 	for (pg = uu_list_first(pgs); pg != NULL; pg = uu_list_next(pgs, pg)) {
5157 		if (pg->sc_pgroup_seen)
5158 			continue;
5159 
5160 		/* pg is new */
5161 
5162 		if (strcmp(pg->sc_pgroup_name, "dependents") == 0) {
5163 			r = upgrade_dependents(NULL, imp_snpl, ient, running,
5164 			    ent);
5165 			switch (r) {
5166 			case 0:
5167 				break;
5168 
5169 			case ECONNABORTED:
5170 			case ENOMEM:
5171 			case ENOSPC:
5172 			case ECANCELED:
5173 			case ENODEV:
5174 			case EBADF:
5175 			case EBUSY:
5176 			case EINVAL:
5177 			case EPERM:
5178 			case EROFS:
5179 			case EACCES:
5180 			case EEXIST:
5181 				return (r);
5182 
5183 			default:
5184 				bad_error("upgrade_dependents", r);
5185 			}
5186 			continue;
5187 		}
5188 
5189 		if (running != NULL)
5190 			r = scf_snaplevel_get_pg(running, pg->sc_pgroup_name,
5191 			    imp_pg);
5192 		else
5193 			r = entity_get_pg(ent, issvc, pg->sc_pgroup_name,
5194 			    imp_pg);
5195 		if (r != 0) {
5196 			scf_callback_t cbdata;
5197 
5198 			switch (scf_error()) {
5199 			case SCF_ERROR_NOT_FOUND:
5200 				break;
5201 
5202 			case SCF_ERROR_CONNECTION_BROKEN:
5203 				return (scferror2errno(scf_error()));
5204 
5205 			case SCF_ERROR_DELETED:
5206 				if (running != NULL)
5207 					return (ENODEV);
5208 				else
5209 					return (scferror2errno(scf_error()));
5210 
5211 			case SCF_ERROR_INVALID_ARGUMENT:
5212 				warn(emsg_fmri_invalid_pg_name, ient->sc_fmri,
5213 				    pg->sc_pgroup_name);
5214 				return (EINVAL);
5215 
5216 			case SCF_ERROR_NOT_SET:
5217 			case SCF_ERROR_HANDLE_MISMATCH:
5218 			case SCF_ERROR_NOT_BOUND:
5219 			default:
5220 				bad_error("entity_get_pg", scf_error());
5221 			}
5222 
5223 			/* User doesn't have pg, so import it. */
5224 
5225 			cbdata.sc_handle = g_hndl;
5226 			cbdata.sc_parent = ent;
5227 			cbdata.sc_service = issvc;
5228 			cbdata.sc_flags = SCI_FORCE;
5229 			cbdata.sc_source_fmri = ient->sc_fmri;
5230 			cbdata.sc_target_fmri = ient->sc_fmri;
5231 
5232 			r = entity_pgroup_import(pg, &cbdata);
5233 			switch (r) {
5234 			case UU_WALK_NEXT:
5235 				ient->sc_import_state = IMPORT_PROP_BEGUN;
5236 				continue;
5237 
5238 			case UU_WALK_ERROR:
5239 				if (cbdata.sc_err == EEXIST) {
5240 					warn(emsg_pg_added, ient->sc_fmri,
5241 					    pg->sc_pgroup_name);
5242 					return (EBUSY);
5243 				}
5244 				return (cbdata.sc_err);
5245 
5246 			default:
5247 				bad_error("entity_pgroup_import", r);
5248 			}
5249 		}
5250 
5251 		/* report differences between pg & current */
5252 		r = load_pg(imp_pg, &rpg, ient->sc_fmri, NULL);
5253 		switch (r) {
5254 		case 0:
5255 			break;
5256 
5257 		case ECANCELED:
5258 			warn(emsg_pg_deleted, ient->sc_fmri,
5259 			    pg->sc_pgroup_name);
5260 			return (EBUSY);
5261 
5262 		case ECONNABORTED:
5263 		case EBADF:
5264 		case ENOMEM:
5265 		case EACCES:
5266 			return (r);
5267 
5268 		default:
5269 			bad_error("load_pg", r);
5270 		}
5271 		report_pg_diffs(pg, rpg, ient->sc_fmri, 1);
5272 		internal_pgroup_free(rpg);
5273 		rpg = NULL;
5274 	}
5275 
5276 	return (0);
5277 }
5278 
5279 /*
5280  * Import an instance.  If it doesn't exist, create it.  If it has
5281  * a last-import snapshot, upgrade its properties.  Finish by updating its
5282  * last-import snapshot.  If it doesn't have a last-import snapshot then it
5283  * could have been created for a dependent tag in another manifest.  Import the
5284  * new properties.  If there's a conflict, don't override, like now?
5285  *
5286  * On success, returns UU_WALK_NEXT.  On error returns UU_WALK_ERROR and sets
5287  * lcbdata->sc_err to
5288  *   ECONNABORTED - repository connection broken
5289  *   ENOMEM - out of memory
5290  *   ENOSPC - svc.configd is out of resources
5291  *   EEXIST - dependency collision in dependent service (error printed)
5292  *   EPERM - couldn't create temporary instance (permission denied)
5293  *	   - couldn't import into temporary instance (permission denied)
5294  *	   - couldn't take snapshot (permission denied)
5295  *	   - couldn't upgrade properties (permission denied)
5296  *	   - couldn't import properties (permission denied)
5297  *	   - couldn't import dependents (permission denied)
5298  *   EROFS - couldn't create temporary instance (repository read-only)
5299  *	   - couldn't import into temporary instance (repository read-only)
5300  *	   - couldn't upgrade properties (repository read-only)
5301  *	   - couldn't import properties (repository read-only)
5302  *	   - couldn't import dependents (repository read-only)
5303  *   EACCES - couldn't create temporary instance (backend access denied)
5304  *	    - couldn't import into temporary instance (backend access denied)
5305  *	    - couldn't upgrade properties (backend access denied)
5306  *	    - couldn't import properties (backend access denied)
5307  *	    - couldn't import dependents (backend access denied)
5308  *   EINVAL - invalid instance name (error printed)
5309  *	    - invalid pgroup_t's (error printed)
5310  *	    - invalid dependents (error printed)
5311  *   EBUSY - temporary service deleted (error printed)
5312  *	   - temporary instance deleted (error printed)
5313  *	   - temporary instance changed (error printed)
5314  *	   - temporary instance already exists (error printed)
5315  *	   - instance deleted (error printed)
5316  *   EBADF - instance has corrupt last-import snapshot (error printed)
5317  *	   - instance is corrupt (error printed)
5318  *	   - dependent has corrupt pg (error printed)
5319  *	   - dependent target has a corrupt snapshot (error printed)
5320  *   -1 - unknown libscf error (error printed)
5321  */
5322 static int
5323 lscf_instance_import(void *v, void *pvt)
5324 {
5325 	entity_t *inst = v;
5326 	scf_callback_t ctx;
5327 	scf_callback_t *lcbdata = pvt;
5328 	scf_service_t *rsvc = lcbdata->sc_parent;
5329 	int r;
5330 	scf_snaplevel_t *running;
5331 	int flags = lcbdata->sc_flags;
5332 
5333 	const char * const emsg_tdel =
5334 	    gettext("Temporary instance svc:/%s:%s was deleted.\n");
5335 	const char * const emsg_tchg = gettext("Temporary instance svc:/%s:%s "
5336 	    "changed unexpectedly.\n");
5337 	const char * const emsg_del = gettext("%s changed unexpectedly "
5338 	    "(instance \"%s\" was deleted.)\n");
5339 	const char * const emsg_badsnap = gettext(
5340 	    "\"%s\" snapshot of %s is corrupt (missing a snaplevel).\n");
5341 
5342 	/*
5343 	 * prepare last-import snapshot:
5344 	 * create temporary instance (service was precreated)
5345 	 * populate with properties from bundle
5346 	 * take snapshot
5347 	 */
5348 	if (scf_service_add_instance(imp_tsvc, inst->sc_name, imp_tinst) != 0) {
5349 		switch (scf_error()) {
5350 		case SCF_ERROR_CONNECTION_BROKEN:
5351 		case SCF_ERROR_NO_RESOURCES:
5352 		case SCF_ERROR_BACKEND_READONLY:
5353 		case SCF_ERROR_BACKEND_ACCESS:
5354 			return (stash_scferror(lcbdata));
5355 
5356 		case SCF_ERROR_EXISTS:
5357 			warn(gettext("Temporary service svc:/%s "
5358 			    "changed unexpectedly (instance \"%s\" added).\n"),
5359 			    imp_tsname, inst->sc_name);
5360 			lcbdata->sc_err = EBUSY;
5361 			return (UU_WALK_ERROR);
5362 
5363 		case SCF_ERROR_DELETED:
5364 			warn(gettext("Temporary service svc:/%s "
5365 			    "was deleted unexpectedly.\n"), imp_tsname);
5366 			lcbdata->sc_err = EBUSY;
5367 			return (UU_WALK_ERROR);
5368 
5369 		case SCF_ERROR_INVALID_ARGUMENT:
5370 			warn(gettext("Invalid instance name \"%s\".\n"),
5371 			    inst->sc_name);
5372 			return (stash_scferror(lcbdata));
5373 
5374 		case SCF_ERROR_PERMISSION_DENIED:
5375 			warn(gettext("Could not create temporary instance "
5376 			    "\"%s\" in svc:/%s (permission denied).\n"),
5377 			    inst->sc_name, imp_tsname);
5378 			return (stash_scferror(lcbdata));
5379 
5380 		case SCF_ERROR_HANDLE_MISMATCH:
5381 		case SCF_ERROR_NOT_BOUND:
5382 		case SCF_ERROR_NOT_SET:
5383 		default:
5384 			bad_error("scf_service_add_instance", scf_error());
5385 		}
5386 	}
5387 
5388 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5389 	    inst->sc_name);
5390 	if (r < 0)
5391 		bad_error("snprintf", errno);
5392 
5393 	r = lscf_import_instance_pgs(imp_tinst, imp_str, inst,
5394 	    lcbdata->sc_flags | SCI_NOENABLED);
5395 	switch (r) {
5396 	case 0:
5397 		break;
5398 
5399 	case ECANCELED:
5400 		warn(emsg_tdel, imp_tsname, inst->sc_name);
5401 		lcbdata->sc_err = EBUSY;
5402 		r = UU_WALK_ERROR;
5403 		goto deltemp;
5404 
5405 	case EEXIST:
5406 		warn(emsg_tchg, imp_tsname, inst->sc_name);
5407 		lcbdata->sc_err = EBUSY;
5408 		r = UU_WALK_ERROR;
5409 		goto deltemp;
5410 
5411 	case ECONNABORTED:
5412 		goto connaborted;
5413 
5414 	case ENOMEM:
5415 	case ENOSPC:
5416 	case EPERM:
5417 	case EROFS:
5418 	case EACCES:
5419 	case EINVAL:
5420 	case EBUSY:
5421 		lcbdata->sc_err = r;
5422 		r = UU_WALK_ERROR;
5423 		goto deltemp;
5424 
5425 	default:
5426 		bad_error("lscf_import_instance_pgs", r);
5427 	}
5428 
5429 	r = snprintf(imp_str, imp_str_sz, "svc:/%s:%s", imp_tsname,
5430 	    inst->sc_name);
5431 	if (r < 0)
5432 		bad_error("snprintf", errno);
5433 
5434 	ctx.sc_handle = lcbdata->sc_handle;
5435 	ctx.sc_parent = imp_tinst;
5436 	ctx.sc_service = 0;
5437 	ctx.sc_source_fmri = inst->sc_fmri;
5438 	ctx.sc_target_fmri = imp_str;
5439 	if (uu_list_walk(inst->sc_dependents, entity_pgroup_import, &ctx,
5440 	    UU_DEFAULT) != 0) {
5441 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5442 			bad_error("uu_list_walk", uu_error());
5443 
5444 		switch (ctx.sc_err) {
5445 		case ECONNABORTED:
5446 			goto connaborted;
5447 
5448 		case ECANCELED:
5449 			warn(emsg_tdel, imp_tsname, inst->sc_name);
5450 			lcbdata->sc_err = EBUSY;
5451 			break;
5452 
5453 		case EEXIST:
5454 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5455 			lcbdata->sc_err = EBUSY;
5456 			break;
5457 
5458 		default:
5459 			lcbdata->sc_err = ctx.sc_err;
5460 		}
5461 		r = UU_WALK_ERROR;
5462 		goto deltemp;
5463 	}
5464 
5465 	if (_scf_snapshot_take_new_named(imp_tinst, inst->sc_parent->sc_name,
5466 	    inst->sc_name, snap_lastimport, imp_tlisnap) != 0) {
5467 		switch (scf_error()) {
5468 		case SCF_ERROR_CONNECTION_BROKEN:
5469 			goto connaborted;
5470 
5471 		case SCF_ERROR_NO_RESOURCES:
5472 			r = stash_scferror(lcbdata);
5473 			goto deltemp;
5474 
5475 		case SCF_ERROR_EXISTS:
5476 			warn(emsg_tchg, imp_tsname, inst->sc_name);
5477 			lcbdata->sc_err = EBUSY;
5478 			r = UU_WALK_ERROR;
5479 			goto deltemp;
5480 
5481 		case SCF_ERROR_PERMISSION_DENIED:
5482 			warn(gettext("Could not take \"%s\" snapshot of %s "
5483 			    "(permission denied).\n"), snap_lastimport,
5484 			    imp_str);
5485 			r = stash_scferror(lcbdata);
5486 			goto deltemp;
5487 
5488 		default:
5489 			scfwarn();
5490 			lcbdata->sc_err = -1;
5491 			r = UU_WALK_ERROR;
5492 			goto deltemp;
5493 
5494 		case SCF_ERROR_HANDLE_MISMATCH:
5495 		case SCF_ERROR_INVALID_ARGUMENT:
5496 		case SCF_ERROR_NOT_SET:
5497 			bad_error("_scf_snapshot_take_new_named", scf_error());
5498 		}
5499 	}
5500 
5501 	if (lcbdata->sc_flags & SCI_FRESH)
5502 		goto fresh;
5503 
5504 	if (scf_service_get_instance(rsvc, inst->sc_name, imp_inst) == 0) {
5505 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
5506 		    imp_lisnap) != 0) {
5507 			switch (scf_error()) {
5508 			case SCF_ERROR_DELETED:
5509 				warn(emsg_del, inst->sc_parent->sc_fmri,
5510 				    inst->sc_name);
5511 				lcbdata->sc_err = EBUSY;
5512 				r = UU_WALK_ERROR;
5513 				goto deltemp;
5514 
5515 			case SCF_ERROR_NOT_FOUND:
5516 				flags |= SCI_FORCE;
5517 				goto nosnap;
5518 
5519 			case SCF_ERROR_CONNECTION_BROKEN:
5520 				goto connaborted;
5521 
5522 			case SCF_ERROR_INVALID_ARGUMENT:
5523 			case SCF_ERROR_HANDLE_MISMATCH:
5524 			case SCF_ERROR_NOT_BOUND:
5525 			case SCF_ERROR_NOT_SET:
5526 			default:
5527 				bad_error("scf_instance_get_snapshot",
5528 				    scf_error());
5529 			}
5530 		}
5531 
5532 		/* upgrade */
5533 
5534 		/*
5535 		 * compare new properties with last-import properties
5536 		 * upgrade current properties
5537 		 */
5538 		/* clear sc_sceen for pgs */
5539 		if (uu_list_walk(inst->sc_pgroups, clear_int,
5540 		    (void *)offsetof(pgroup_t, sc_pgroup_seen), UU_DEFAULT) !=
5541 		    0)
5542 			bad_error("uu_list_walk", uu_error());
5543 
5544 		r = get_snaplevel(imp_lisnap, 0, imp_snpl);
5545 		switch (r) {
5546 		case 0:
5547 			break;
5548 
5549 		case ECONNABORTED:
5550 			goto connaborted;
5551 
5552 		case ECANCELED:
5553 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5554 			lcbdata->sc_err = EBUSY;
5555 			r = UU_WALK_ERROR;
5556 			goto deltemp;
5557 
5558 		case ENOENT:
5559 			warn(emsg_badsnap, snap_lastimport, inst->sc_fmri);
5560 			lcbdata->sc_err = EBADF;
5561 			r = UU_WALK_ERROR;
5562 			goto deltemp;
5563 
5564 		default:
5565 			bad_error("get_snaplevel", r);
5566 		}
5567 
5568 		if (scf_instance_get_snapshot(imp_inst, snap_running,
5569 		    imp_rsnap) != 0) {
5570 			switch (scf_error()) {
5571 			case SCF_ERROR_DELETED:
5572 				warn(emsg_del, inst->sc_parent->sc_fmri,
5573 				    inst->sc_name);
5574 				lcbdata->sc_err = EBUSY;
5575 				r = UU_WALK_ERROR;
5576 				goto deltemp;
5577 
5578 			case SCF_ERROR_NOT_FOUND:
5579 				break;
5580 
5581 			case SCF_ERROR_CONNECTION_BROKEN:
5582 				goto connaborted;
5583 
5584 			case SCF_ERROR_INVALID_ARGUMENT:
5585 			case SCF_ERROR_HANDLE_MISMATCH:
5586 			case SCF_ERROR_NOT_BOUND:
5587 			case SCF_ERROR_NOT_SET:
5588 			default:
5589 				bad_error("scf_instance_get_snapshot",
5590 				    scf_error());
5591 			}
5592 
5593 			running = NULL;
5594 		} else {
5595 			r = get_snaplevel(imp_rsnap, 0, imp_rsnpl);
5596 			switch (r) {
5597 			case 0:
5598 				running = imp_rsnpl;
5599 				break;
5600 
5601 			case ECONNABORTED:
5602 				goto connaborted;
5603 
5604 			case ECANCELED:
5605 				warn(emsg_del, inst->sc_parent->sc_fmri,
5606 				    inst->sc_name);
5607 				lcbdata->sc_err = EBUSY;
5608 				r = UU_WALK_ERROR;
5609 				goto deltemp;
5610 
5611 			case ENOENT:
5612 				warn(emsg_badsnap, snap_running, inst->sc_fmri);
5613 				lcbdata->sc_err = EBADF;
5614 				r = UU_WALK_ERROR;
5615 				goto deltemp;
5616 
5617 			default:
5618 				bad_error("get_snaplevel", r);
5619 			}
5620 		}
5621 
5622 		r = upgrade_props(imp_inst, running, imp_snpl, inst);
5623 		switch (r) {
5624 		case 0:
5625 			break;
5626 
5627 		case ECANCELED:
5628 		case ENODEV:
5629 			warn(emsg_del, inst->sc_parent->sc_fmri, inst->sc_name);
5630 			lcbdata->sc_err = EBUSY;
5631 			r = UU_WALK_ERROR;
5632 			goto deltemp;
5633 
5634 		case ECONNABORTED:
5635 			goto connaborted;
5636 
5637 		case ENOMEM:
5638 		case ENOSPC:
5639 		case EBADF:
5640 		case EBUSY:
5641 		case EINVAL:
5642 		case EPERM:
5643 		case EROFS:
5644 		case EACCES:
5645 		case EEXIST:
5646 			lcbdata->sc_err = r;
5647 			r = UU_WALK_ERROR;
5648 			goto deltemp;
5649 
5650 		default:
5651 			bad_error("upgrade_props", r);
5652 		}
5653 
5654 		inst->sc_import_state = IMPORT_PROP_DONE;
5655 	} else {
5656 		switch (scf_error()) {
5657 		case SCF_ERROR_CONNECTION_BROKEN:
5658 			goto connaborted;
5659 
5660 		case SCF_ERROR_NOT_FOUND:
5661 			break;
5662 
5663 		case SCF_ERROR_INVALID_ARGUMENT:	/* caught above */
5664 		case SCF_ERROR_HANDLE_MISMATCH:
5665 		case SCF_ERROR_NOT_BOUND:
5666 		case SCF_ERROR_NOT_SET:
5667 		default:
5668 			bad_error("scf_service_get_instance", scf_error());
5669 		}
5670 
5671 fresh:
5672 		/* create instance */
5673 		if (scf_service_add_instance(rsvc, inst->sc_name,
5674 		    imp_inst) != 0) {
5675 			switch (scf_error()) {
5676 			case SCF_ERROR_CONNECTION_BROKEN:
5677 				goto connaborted;
5678 
5679 			case SCF_ERROR_NO_RESOURCES:
5680 			case SCF_ERROR_BACKEND_READONLY:
5681 			case SCF_ERROR_BACKEND_ACCESS:
5682 				r = stash_scferror(lcbdata);
5683 				goto deltemp;
5684 
5685 			case SCF_ERROR_EXISTS:
5686 				warn(gettext("%s changed unexpectedly "
5687 				    "(instance \"%s\" added).\n"),
5688 				    inst->sc_parent->sc_fmri, inst->sc_name);
5689 				lcbdata->sc_err = EBUSY;
5690 				r = UU_WALK_ERROR;
5691 				goto deltemp;
5692 
5693 			case SCF_ERROR_PERMISSION_DENIED:
5694 				warn(gettext("Could not create \"%s\" instance "
5695 				    "in %s (permission denied).\n"),
5696 				    inst->sc_name, inst->sc_parent->sc_fmri);
5697 				r = stash_scferror(lcbdata);
5698 				goto deltemp;
5699 
5700 			case SCF_ERROR_INVALID_ARGUMENT:  /* caught above */
5701 			case SCF_ERROR_HANDLE_MISMATCH:
5702 			case SCF_ERROR_NOT_BOUND:
5703 			case SCF_ERROR_NOT_SET:
5704 			default:
5705 				bad_error("scf_service_add_instance",
5706 				    scf_error());
5707 			}
5708 		}
5709 
5710 nosnap:
5711 		/*
5712 		 * Create a last-import snapshot to serve as an attachment
5713 		 * point for the real one from the temporary instance.  Since
5714 		 * the contents is irrelevant, take it now, while the instance
5715 		 * is empty, to minimize svc.configd's work.
5716 		 */
5717 		if (_scf_snapshot_take_new(imp_inst, snap_lastimport,
5718 		    imp_lisnap) != 0) {
5719 			switch (scf_error()) {
5720 			case SCF_ERROR_CONNECTION_BROKEN:
5721 				goto connaborted;
5722 
5723 			case SCF_ERROR_NO_RESOURCES:
5724 				r = stash_scferror(lcbdata);
5725 				goto deltemp;
5726 
5727 			case SCF_ERROR_EXISTS:
5728 				warn(gettext("%s changed unexpectedly "
5729 				    "(snapshot \"%s\" added).\n"),
5730 				    inst->sc_fmri, snap_lastimport);
5731 				lcbdata->sc_err = EBUSY;
5732 				r = UU_WALK_ERROR;
5733 				goto deltemp;
5734 
5735 			case SCF_ERROR_PERMISSION_DENIED:
5736 				warn(gettext("Could not take \"%s\" snapshot "
5737 				    "of %s (permission denied).\n"),
5738 				    snap_lastimport, inst->sc_fmri);
5739 				r = stash_scferror(lcbdata);
5740 				goto deltemp;
5741 
5742 			default:
5743 				scfwarn();
5744 				lcbdata->sc_err = -1;
5745 				r = UU_WALK_ERROR;
5746 				goto deltemp;
5747 
5748 			case SCF_ERROR_NOT_SET:
5749 			case SCF_ERROR_INTERNAL:
5750 			case SCF_ERROR_INVALID_ARGUMENT:
5751 			case SCF_ERROR_HANDLE_MISMATCH:
5752 				bad_error("_scf_snapshot_take_new",
5753 				    scf_error());
5754 			}
5755 		}
5756 
5757 		if (li_only)
5758 			goto lionly;
5759 
5760 		inst->sc_import_state = IMPORT_PROP_BEGUN;
5761 
5762 		r = lscf_import_instance_pgs(imp_inst, inst->sc_fmri, inst,
5763 		    flags);
5764 		switch (r) {
5765 		case 0:
5766 			break;
5767 
5768 		case ECONNABORTED:
5769 			goto connaborted;
5770 
5771 		case ECANCELED:
5772 			warn(gettext("%s changed unexpectedly "
5773 			    "(instance \"%s\" deleted).\n"),
5774 			    inst->sc_parent->sc_fmri, inst->sc_name);
5775 			lcbdata->sc_err = EBUSY;
5776 			r = UU_WALK_ERROR;
5777 			goto deltemp;
5778 
5779 		case EEXIST:
5780 			warn(gettext("%s changed unexpectedly "
5781 			    "(property group added).\n"), inst->sc_fmri);
5782 			lcbdata->sc_err = EBUSY;
5783 			r = UU_WALK_ERROR;
5784 			goto deltemp;
5785 
5786 		default:
5787 			lcbdata->sc_err = r;
5788 			r = UU_WALK_ERROR;
5789 			goto deltemp;
5790 
5791 		case EINVAL:	/* caught above */
5792 			bad_error("lscf_import_instance_pgs", r);
5793 		}
5794 
5795 		ctx.sc_parent = imp_inst;
5796 		ctx.sc_service = 0;
5797 		ctx.sc_trans = NULL;
5798 		if (uu_list_walk(inst->sc_dependents, lscf_dependent_import,
5799 		    &ctx, UU_DEFAULT) != 0) {
5800 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
5801 				bad_error("uu_list_walk", uu_error());
5802 
5803 			if (ctx.sc_err == ECONNABORTED)
5804 				goto connaborted;
5805 			lcbdata->sc_err = ctx.sc_err;
5806 			r = UU_WALK_ERROR;
5807 			goto deltemp;
5808 		}
5809 
5810 		inst->sc_import_state = IMPORT_PROP_DONE;
5811 
5812 		if (g_verbose)
5813 			warn(gettext("Taking \"%s\" snapshot for %s.\n"),
5814 			    snap_initial, inst->sc_fmri);
5815 		r = take_snap(imp_inst, snap_initial, imp_snap);
5816 		switch (r) {
5817 		case 0:
5818 			break;
5819 
5820 		case ECONNABORTED:
5821 			goto connaborted;
5822 
5823 		case ENOSPC:
5824 		case -1:
5825 			lcbdata->sc_err = r;
5826 			r = UU_WALK_ERROR;
5827 			goto deltemp;
5828 
5829 		case ECANCELED:
5830 			warn(gettext("%s changed unexpectedly "
5831 			    "(instance %s deleted).\n"),
5832 			    inst->sc_parent->sc_fmri, inst->sc_name);
5833 			lcbdata->sc_err = r;
5834 			r = UU_WALK_ERROR;
5835 			goto deltemp;
5836 
5837 		case EPERM:
5838 			warn(emsg_snap_perm, snap_initial, inst->sc_fmri);
5839 			lcbdata->sc_err = r;
5840 			r = UU_WALK_ERROR;
5841 			goto deltemp;
5842 
5843 		default:
5844 			bad_error("take_snap", r);
5845 		}
5846 	}
5847 
5848 lionly:
5849 	if (lcbdata->sc_flags & SCI_NOSNAP)
5850 		goto deltemp;
5851 
5852 	/* transfer snapshot from temporary instance */
5853 	if (g_verbose)
5854 		warn(gettext("Taking \"%s\" snapshot for %s.\n"),
5855 		    snap_lastimport, inst->sc_fmri);
5856 	if (_scf_snapshot_attach(imp_tlisnap, imp_lisnap) != 0) {
5857 		switch (scf_error()) {
5858 		case SCF_ERROR_CONNECTION_BROKEN:
5859 			goto connaborted;
5860 
5861 		case SCF_ERROR_NO_RESOURCES:
5862 			r = stash_scferror(lcbdata);
5863 			goto deltemp;
5864 
5865 		case SCF_ERROR_PERMISSION_DENIED:
5866 			warn(gettext("Could not take \"%s\" snapshot for %s "
5867 			    "(permission denied).\n"), snap_lastimport,
5868 			    inst->sc_fmri);
5869 			r = stash_scferror(lcbdata);
5870 			goto deltemp;
5871 
5872 		case SCF_ERROR_NOT_SET:
5873 		case SCF_ERROR_HANDLE_MISMATCH:
5874 		default:
5875 			bad_error("_scf_snapshot_attach", scf_error());
5876 		}
5877 	}
5878 
5879 	inst->sc_import_state = IMPORT_COMPLETE;
5880 
5881 	r = UU_WALK_NEXT;
5882 
5883 deltemp:
5884 	/* delete temporary instance */
5885 	if (scf_instance_delete(imp_tinst) != 0) {
5886 		switch (scf_error()) {
5887 		case SCF_ERROR_DELETED:
5888 			break;
5889 
5890 		case SCF_ERROR_CONNECTION_BROKEN:
5891 			goto connaborted;
5892 
5893 		case SCF_ERROR_NOT_SET:
5894 		case SCF_ERROR_NOT_BOUND:
5895 		default:
5896 			bad_error("scf_instance_delete", scf_error());
5897 		}
5898 	}
5899 
5900 	return (r);
5901 
5902 connaborted:
5903 	warn(gettext("Could not delete svc:/%s:%s "
5904 	    "(repository connection broken).\n"), imp_tsname, inst->sc_name);
5905 	lcbdata->sc_err = ECONNABORTED;
5906 	return (UU_WALK_ERROR);
5907 }
5908 
5909 /*
5910  * If the service is missing, create it, import its properties, and import the
5911  * instances.  Since the service is brand new, it should be empty, and if we
5912  * run into any existing entities (SCF_ERROR_EXISTS), abort.
5913  *
5914  * If the service exists, we want to upgrade its properties and import the
5915  * instances.  Upgrade requires a last-import snapshot, though, which are
5916  * children of instances, so first we'll have to go through the instances
5917  * looking for a last-import snapshot.  If we don't find one then we'll just
5918  * override-import the service properties (but don't delete existing
5919  * properties: another service might have declared us as a dependent).  Before
5920  * we change anything, though, we want to take the previous snapshots.  We
5921  * also give lscf_instance_import() a leg up on taking last-import snapshots
5922  * by importing the manifest's service properties into a temporary service.
5923  *
5924  * On success, returns UU_WALK_NEXT.  On failure, returns UU_WALK_ERROR and
5925  * sets lcbdata->sc_err to
5926  *   ECONNABORTED - repository connection broken
5927  *   ENOMEM - out of memory
5928  *   ENOSPC - svc.configd is out of resources
5929  *   EPERM - couldn't create temporary service (error printed)
5930  *	   - couldn't import into temp service (error printed)
5931  *	   - couldn't create service (error printed)
5932  *	   - couldn't import dependent (error printed)
5933  *	   - couldn't take snapshot (error printed)
5934  *	   - couldn't create instance (error printed)
5935  *	   - couldn't create, modify, or delete pg (error printed)
5936  *	   - couldn't create, modify, or delete dependent (error printed)
5937  *	   - couldn't import instance (error printed)
5938  *   EROFS - couldn't create temporary service (repository read-only)
5939  *	   - couldn't import into temporary service (repository read-only)
5940  *	   - couldn't create service (repository read-only)
5941  *	   - couldn't import dependent (repository read-only)
5942  *	   - couldn't create instance (repository read-only)
5943  *	   - couldn't create, modify, or delete pg or dependent
5944  *	   - couldn't import instance (repository read-only)
5945  *   EACCES - couldn't create temporary service (backend access denied)
5946  *	    - couldn't import into temporary service (backend access denied)
5947  *	    - couldn't create service (backend access denied)
5948  *	    - couldn't import dependent (backend access denied)
5949  *	    - couldn't create instance (backend access denied)
5950  *	    - couldn't create, modify, or delete pg or dependent
5951  *	    - couldn't import instance (backend access denied)
5952  *   EINVAL - service name is invalid (error printed)
5953  *	    - service name is too long (error printed)
5954  *	    - s has invalid pgroup (error printed)
5955  *	    - s has invalid dependent (error printed)
5956  *	    - instance name is invalid (error printed)
5957  *	    - instance entity_t is invalid (error printed)
5958  *   EEXIST - couldn't create temporary service (already exists) (error printed)
5959  *	    - couldn't import dependent (dependency pg already exists) (printed)
5960  *	    - dependency collision in dependent service (error printed)
5961  *   EBUSY - temporary service deleted (error printed)
5962  *	   - property group added to temporary service (error printed)
5963  *	   - new property group changed or was deleted (error printed)
5964  *	   - service was added unexpectedly (error printed)
5965  *	   - service was deleted unexpectedly (error printed)
5966  *	   - property group added to new service (error printed)
5967  *	   - instance added unexpectedly (error printed)
5968  *	   - instance deleted unexpectedly (error printed)
5969  *	   - dependent service deleted unexpectedly (error printed)
5970  *	   - pg was added, changed, or deleted (error printed)
5971  *	   - dependent pg changed (error printed)
5972  *	   - temporary instance added, changed, or deleted (error printed)
5973  *   EBADF - a last-import snapshot is corrupt (error printed)
5974  *	   - the service is corrupt (error printed)
5975  *	   - a dependent is corrupt (error printed)
5976  *	   - an instance is corrupt (error printed)
5977  *	   - an instance has a corrupt last-import snapshot (error printed)
5978  *	   - dependent target has a corrupt snapshot (error printed)
5979  *   -1 - unknown libscf error (error printed)
5980  */
5981 static int
5982 lscf_service_import(void *v, void *pvt)
5983 {
5984 	entity_t *s = v;
5985 	scf_callback_t cbdata;
5986 	scf_callback_t *lcbdata = pvt;
5987 	scf_scope_t *scope = lcbdata->sc_parent;
5988 	entity_t *inst, linst;
5989 	int r;
5990 	int fresh = 0;
5991 	scf_snaplevel_t *running;
5992 	int have_ge;
5993 
5994 	const char * const ts_deleted = gettext("Temporary service svc:/%s "
5995 	    "was deleted unexpectedly.\n");
5996 	const char * const ts_pg_added = gettext("Temporary service svc:/%s "
5997 	    "changed unexpectedly (property group added).\n");
5998 	const char * const s_deleted =
5999 	    gettext("%s was deleted unexpectedly.\n");
6000 	const char * const i_deleted =
6001 	    gettext("%s changed unexpectedly (instance \"%s\" deleted).\n");
6002 	const char * const badsnap = gettext("\"%s\" snapshot of svc:/%s:%s "
6003 	    "is corrupt (missing service snaplevel).\n");
6004 
6005 	/* Validate the service name */
6006 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6007 		switch (scf_error()) {
6008 		case SCF_ERROR_CONNECTION_BROKEN:
6009 			return (stash_scferror(lcbdata));
6010 
6011 		case SCF_ERROR_INVALID_ARGUMENT:
6012 			warn(gettext("\"%s\" is an invalid service name.  "
6013 			    "Cannot import.\n"), s->sc_name);
6014 			return (stash_scferror(lcbdata));
6015 
6016 		case SCF_ERROR_NOT_FOUND:
6017 			break;
6018 
6019 		case SCF_ERROR_HANDLE_MISMATCH:
6020 		case SCF_ERROR_NOT_BOUND:
6021 		case SCF_ERROR_NOT_SET:
6022 		default:
6023 			bad_error("scf_scope_get_service", scf_error());
6024 		}
6025 	}
6026 
6027 	/* create temporary service */
6028 	/*
6029 	 * the size of the buffer was reduced to max_scf_name_len to prevent
6030 	 * hitting bug 6681151.  After the bug fix, the size of the buffer
6031 	 * should be restored to its original value (max_scf_name_len +1)
6032 	 */
6033 	r = snprintf(imp_tsname, max_scf_name_len, "TEMP/%s", s->sc_name);
6034 	if (r < 0)
6035 		bad_error("snprintf", errno);
6036 	if (r > max_scf_name_len) {
6037 		warn(gettext(
6038 		    "Service name \"%s\" is too long.  Cannot import.\n"),
6039 		    s->sc_name);
6040 		lcbdata->sc_err = EINVAL;
6041 		return (UU_WALK_ERROR);
6042 	}
6043 
6044 	if (scf_scope_add_service(imp_scope, imp_tsname, imp_tsvc) != 0) {
6045 		switch (scf_error()) {
6046 		case SCF_ERROR_CONNECTION_BROKEN:
6047 		case SCF_ERROR_NO_RESOURCES:
6048 		case SCF_ERROR_BACKEND_READONLY:
6049 		case SCF_ERROR_BACKEND_ACCESS:
6050 			return (stash_scferror(lcbdata));
6051 
6052 		case SCF_ERROR_EXISTS:
6053 			warn(gettext(
6054 			    "Temporary service \"%s\" must be deleted before "
6055 			    "this manifest can be imported.\n"), imp_tsname);
6056 			return (stash_scferror(lcbdata));
6057 
6058 		case SCF_ERROR_PERMISSION_DENIED:
6059 			warn(gettext("Could not create temporary service "
6060 			    "\"%s\" (permission denied).\n"), imp_tsname);
6061 			return (stash_scferror(lcbdata));
6062 
6063 		case SCF_ERROR_INVALID_ARGUMENT:
6064 		case SCF_ERROR_HANDLE_MISMATCH:
6065 		case SCF_ERROR_NOT_BOUND:
6066 		case SCF_ERROR_NOT_SET:
6067 		default:
6068 			bad_error("scf_scope_add_service", scf_error());
6069 		}
6070 	}
6071 
6072 	r = snprintf(imp_str, imp_str_sz, "svc:/%s", imp_tsname);
6073 	if (r < 0)
6074 		bad_error("snprintf", errno);
6075 
6076 	cbdata.sc_handle = lcbdata->sc_handle;
6077 	cbdata.sc_parent = imp_tsvc;
6078 	cbdata.sc_service = 1;
6079 	cbdata.sc_source_fmri = s->sc_fmri;
6080 	cbdata.sc_target_fmri = imp_str;
6081 	cbdata.sc_flags = 0;
6082 
6083 	if (uu_list_walk(s->sc_pgroups, entity_pgroup_import, &cbdata,
6084 	    UU_DEFAULT) != 0) {
6085 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6086 			bad_error("uu_list_walk", uu_error());
6087 
6088 		lcbdata->sc_err = cbdata.sc_err;
6089 		switch (cbdata.sc_err) {
6090 		case ECONNABORTED:
6091 			goto connaborted;
6092 
6093 		case ECANCELED:
6094 			warn(ts_deleted, imp_tsname);
6095 			lcbdata->sc_err = EBUSY;
6096 			return (UU_WALK_ERROR);
6097 
6098 		case EEXIST:
6099 			warn(ts_pg_added, imp_tsname);
6100 			lcbdata->sc_err = EBUSY;
6101 			return (UU_WALK_ERROR);
6102 		}
6103 
6104 		r = UU_WALK_ERROR;
6105 		goto deltemp;
6106 	}
6107 
6108 	if (uu_list_walk(s->sc_dependents, entity_pgroup_import, &cbdata,
6109 	    UU_DEFAULT) != 0) {
6110 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6111 			bad_error("uu_list_walk", uu_error());
6112 
6113 		lcbdata->sc_err = cbdata.sc_err;
6114 		switch (cbdata.sc_err) {
6115 		case ECONNABORTED:
6116 			goto connaborted;
6117 
6118 		case ECANCELED:
6119 			warn(ts_deleted, imp_tsname);
6120 			lcbdata->sc_err = EBUSY;
6121 			return (UU_WALK_ERROR);
6122 
6123 		case EEXIST:
6124 			warn(ts_pg_added, imp_tsname);
6125 			lcbdata->sc_err = EBUSY;
6126 			return (UU_WALK_ERROR);
6127 		}
6128 
6129 		r = UU_WALK_ERROR;
6130 		goto deltemp;
6131 	}
6132 
6133 	if (scf_scope_get_service(scope, s->sc_name, imp_svc) != 0) {
6134 		switch (scf_error()) {
6135 		case SCF_ERROR_NOT_FOUND:
6136 			break;
6137 
6138 		case SCF_ERROR_CONNECTION_BROKEN:
6139 			goto connaborted;
6140 
6141 		case SCF_ERROR_INVALID_ARGUMENT:
6142 		case SCF_ERROR_HANDLE_MISMATCH:
6143 		case SCF_ERROR_NOT_BOUND:
6144 		case SCF_ERROR_NOT_SET:
6145 		default:
6146 			bad_error("scf_scope_get_service", scf_error());
6147 		}
6148 
6149 		if (scf_scope_add_service(scope, s->sc_name, imp_svc) != 0) {
6150 			switch (scf_error()) {
6151 			case SCF_ERROR_CONNECTION_BROKEN:
6152 				goto connaborted;
6153 
6154 			case SCF_ERROR_NO_RESOURCES:
6155 			case SCF_ERROR_BACKEND_READONLY:
6156 			case SCF_ERROR_BACKEND_ACCESS:
6157 				r = stash_scferror(lcbdata);
6158 				goto deltemp;
6159 
6160 			case SCF_ERROR_EXISTS:
6161 				warn(gettext("Scope \"%s\" changed unexpectedly"
6162 				    " (service \"%s\" added).\n"),
6163 				    SCF_SCOPE_LOCAL, s->sc_name);
6164 				lcbdata->sc_err = EBUSY;
6165 				goto deltemp;
6166 
6167 			case SCF_ERROR_PERMISSION_DENIED:
6168 				warn(gettext("Could not create service \"%s\" "
6169 				    "(permission denied).\n"), s->sc_name);
6170 				goto deltemp;
6171 
6172 			case SCF_ERROR_INVALID_ARGUMENT:
6173 			case SCF_ERROR_HANDLE_MISMATCH:
6174 			case SCF_ERROR_NOT_BOUND:
6175 			case SCF_ERROR_NOT_SET:
6176 			default:
6177 				bad_error("scf_scope_add_service", scf_error());
6178 			}
6179 		}
6180 
6181 		s->sc_import_state = IMPORT_PROP_BEGUN;
6182 
6183 		/* import service properties */
6184 		cbdata.sc_handle = lcbdata->sc_handle;
6185 		cbdata.sc_parent = imp_svc;
6186 		cbdata.sc_service = 1;
6187 		cbdata.sc_flags = lcbdata->sc_flags;
6188 		cbdata.sc_source_fmri = s->sc_fmri;
6189 		cbdata.sc_target_fmri = s->sc_fmri;
6190 
6191 		if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6192 		    &cbdata, UU_DEFAULT) != 0) {
6193 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6194 				bad_error("uu_list_walk", uu_error());
6195 
6196 			lcbdata->sc_err = cbdata.sc_err;
6197 			switch (cbdata.sc_err) {
6198 			case ECONNABORTED:
6199 				goto connaborted;
6200 
6201 			case ECANCELED:
6202 				warn(s_deleted, s->sc_fmri);
6203 				lcbdata->sc_err = EBUSY;
6204 				return (UU_WALK_ERROR);
6205 
6206 			case EEXIST:
6207 				warn(gettext("%s changed unexpectedly "
6208 				    "(property group added).\n"), s->sc_fmri);
6209 				lcbdata->sc_err = EBUSY;
6210 				return (UU_WALK_ERROR);
6211 
6212 			case EINVAL:
6213 				/* caught above */
6214 				bad_error("entity_pgroup_import",
6215 				    cbdata.sc_err);
6216 			}
6217 
6218 			r = UU_WALK_ERROR;
6219 			goto deltemp;
6220 		}
6221 
6222 		cbdata.sc_trans = NULL;
6223 		if (uu_list_walk(s->sc_dependents, lscf_dependent_import,
6224 		    &cbdata, UU_DEFAULT) != 0) {
6225 			if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6226 				bad_error("uu_list_walk", uu_error());
6227 
6228 			lcbdata->sc_err = cbdata.sc_err;
6229 			if (cbdata.sc_err == ECONNABORTED)
6230 				goto connaborted;
6231 			r = UU_WALK_ERROR;
6232 			goto deltemp;
6233 		}
6234 
6235 		s->sc_import_state = IMPORT_PROP_DONE;
6236 
6237 		/*
6238 		 * This is a new service, so we can't take previous snapshots
6239 		 * or upgrade service properties.
6240 		 */
6241 		fresh = 1;
6242 		goto instances;
6243 	}
6244 
6245 	/* Clear sc_seen for the instances. */
6246 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances, clear_int,
6247 	    (void *)offsetof(entity_t, sc_seen), UU_DEFAULT) != 0)
6248 		bad_error("uu_list_walk", uu_error());
6249 
6250 	/*
6251 	 * Take previous snapshots for all instances.  Even for ones not
6252 	 * mentioned in the bundle, since we might change their service
6253 	 * properties.
6254 	 */
6255 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6256 		switch (scf_error()) {
6257 		case SCF_ERROR_CONNECTION_BROKEN:
6258 			goto connaborted;
6259 
6260 		case SCF_ERROR_DELETED:
6261 			warn(s_deleted, s->sc_fmri);
6262 			lcbdata->sc_err = EBUSY;
6263 			r = UU_WALK_ERROR;
6264 			goto deltemp;
6265 
6266 		case SCF_ERROR_HANDLE_MISMATCH:
6267 		case SCF_ERROR_NOT_BOUND:
6268 		case SCF_ERROR_NOT_SET:
6269 		default:
6270 			bad_error("scf_iter_service_instances", scf_error());
6271 		}
6272 	}
6273 
6274 	for (;;) {
6275 		r = scf_iter_next_instance(imp_iter, imp_inst);
6276 		if (r == 0)
6277 			break;
6278 		if (r != 1) {
6279 			switch (scf_error()) {
6280 			case SCF_ERROR_DELETED:
6281 				warn(s_deleted, s->sc_fmri);
6282 				lcbdata->sc_err = EBUSY;
6283 				r = UU_WALK_ERROR;
6284 				goto deltemp;
6285 
6286 			case SCF_ERROR_CONNECTION_BROKEN:
6287 				goto connaborted;
6288 
6289 			case SCF_ERROR_NOT_BOUND:
6290 			case SCF_ERROR_HANDLE_MISMATCH:
6291 			case SCF_ERROR_INVALID_ARGUMENT:
6292 			case SCF_ERROR_NOT_SET:
6293 			default:
6294 				bad_error("scf_iter_next_instance",
6295 				    scf_error());
6296 			}
6297 		}
6298 
6299 		if (scf_instance_get_name(imp_inst, imp_str, imp_str_sz) < 0) {
6300 			switch (scf_error()) {
6301 			case SCF_ERROR_DELETED:
6302 				continue;
6303 
6304 			case SCF_ERROR_CONNECTION_BROKEN:
6305 				goto connaborted;
6306 
6307 			case SCF_ERROR_NOT_SET:
6308 			case SCF_ERROR_NOT_BOUND:
6309 			default:
6310 				bad_error("scf_instance_get_name", scf_error());
6311 			}
6312 		}
6313 
6314 		if (g_verbose)
6315 			warn(gettext(
6316 			    "Taking \"%s\" snapshot for svc:/%s:%s.\n"),
6317 			    snap_previous, s->sc_name, imp_str);
6318 
6319 		r = take_snap(imp_inst, snap_previous, imp_snap);
6320 		switch (r) {
6321 		case 0:
6322 			break;
6323 
6324 		case ECANCELED:
6325 			continue;
6326 
6327 		case ECONNABORTED:
6328 			goto connaborted;
6329 
6330 		case EPERM:
6331 			warn(gettext("Could not take \"%s\" snapshot of "
6332 			    "svc:/%s:%s (permission denied).\n"),
6333 			    snap_previous, s->sc_name, imp_str);
6334 			lcbdata->sc_err = r;
6335 			return (UU_WALK_ERROR);
6336 
6337 		case ENOSPC:
6338 		case -1:
6339 			lcbdata->sc_err = r;
6340 			r = UU_WALK_ERROR;
6341 			goto deltemp;
6342 
6343 		default:
6344 			bad_error("take_snap", r);
6345 		}
6346 
6347 		linst.sc_name = imp_str;
6348 		inst = uu_list_find(s->sc_u.sc_service.sc_service_instances,
6349 		    &linst, NULL, NULL);
6350 		if (inst != NULL) {
6351 			inst->sc_import_state = IMPORT_PREVIOUS;
6352 			inst->sc_seen = 1;
6353 		}
6354 	}
6355 
6356 	/*
6357 	 * Create the new instances and take previous snapshots of
6358 	 * them.  This is not necessary, but it maximizes data preservation.
6359 	 */
6360 	for (inst = uu_list_first(s->sc_u.sc_service.sc_service_instances);
6361 	    inst != NULL;
6362 	    inst = uu_list_next(s->sc_u.sc_service.sc_service_instances,
6363 	    inst)) {
6364 		if (inst->sc_seen)
6365 			continue;
6366 
6367 		if (scf_service_add_instance(imp_svc, inst->sc_name,
6368 		    imp_inst) != 0) {
6369 			switch (scf_error()) {
6370 			case SCF_ERROR_CONNECTION_BROKEN:
6371 				goto connaborted;
6372 
6373 			case SCF_ERROR_BACKEND_READONLY:
6374 			case SCF_ERROR_BACKEND_ACCESS:
6375 			case SCF_ERROR_NO_RESOURCES:
6376 				r = stash_scferror(lcbdata);
6377 				goto deltemp;
6378 
6379 			case SCF_ERROR_EXISTS:
6380 				warn(gettext("%s changed unexpectedly "
6381 				    "(instance \"%s\" added).\n"), s->sc_fmri,
6382 				    inst->sc_name);
6383 				lcbdata->sc_err = EBUSY;
6384 				r = UU_WALK_ERROR;
6385 				goto deltemp;
6386 
6387 			case SCF_ERROR_INVALID_ARGUMENT:
6388 				warn(gettext("Service \"%s\" has instance with "
6389 				    "invalid name \"%s\".\n"), s->sc_name,
6390 				    inst->sc_name);
6391 				r = stash_scferror(lcbdata);
6392 				goto deltemp;
6393 
6394 			case SCF_ERROR_PERMISSION_DENIED:
6395 				warn(gettext("Could not create instance \"%s\" "
6396 				    "in %s (permission denied).\n"),
6397 				    inst->sc_name, s->sc_fmri);
6398 				r = stash_scferror(lcbdata);
6399 				goto deltemp;
6400 
6401 			case SCF_ERROR_HANDLE_MISMATCH:
6402 			case SCF_ERROR_NOT_BOUND:
6403 			case SCF_ERROR_NOT_SET:
6404 			default:
6405 				bad_error("scf_service_add_instance",
6406 				    scf_error());
6407 			}
6408 		}
6409 
6410 		if (g_verbose)
6411 			warn(gettext("Taking \"%s\" snapshot for "
6412 			    "new service %s.\n"), snap_previous, inst->sc_fmri);
6413 		r = take_snap(imp_inst, snap_previous, imp_snap);
6414 		switch (r) {
6415 		case 0:
6416 			break;
6417 
6418 		case ECANCELED:
6419 			warn(i_deleted, s->sc_fmri, inst->sc_name);
6420 			lcbdata->sc_err = EBUSY;
6421 			r = UU_WALK_ERROR;
6422 			goto deltemp;
6423 
6424 		case ECONNABORTED:
6425 			goto connaborted;
6426 
6427 		case EPERM:
6428 			warn(emsg_snap_perm, snap_previous, inst->sc_fmri);
6429 			lcbdata->sc_err = r;
6430 			r = UU_WALK_ERROR;
6431 			goto deltemp;
6432 
6433 		case ENOSPC:
6434 		case -1:
6435 			r = UU_WALK_ERROR;
6436 			goto deltemp;
6437 
6438 		default:
6439 			bad_error("take_snap", r);
6440 		}
6441 	}
6442 
6443 	s->sc_import_state = IMPORT_PREVIOUS;
6444 
6445 	/*
6446 	 * Upgrade service properties, if we can find a last-import snapshot.
6447 	 * Any will do because we don't support different service properties
6448 	 * in different manifests, so all snaplevels of the service in all of
6449 	 * the last-import snapshots of the instances should be the same.
6450 	 */
6451 	if (scf_iter_service_instances(imp_iter, imp_svc) != 0) {
6452 		switch (scf_error()) {
6453 		case SCF_ERROR_CONNECTION_BROKEN:
6454 			goto connaborted;
6455 
6456 		case SCF_ERROR_DELETED:
6457 			warn(s_deleted, s->sc_fmri);
6458 			lcbdata->sc_err = EBUSY;
6459 			r = UU_WALK_ERROR;
6460 			goto deltemp;
6461 
6462 		case SCF_ERROR_HANDLE_MISMATCH:
6463 		case SCF_ERROR_NOT_BOUND:
6464 		case SCF_ERROR_NOT_SET:
6465 		default:
6466 			bad_error("scf_iter_service_instances", scf_error());
6467 		}
6468 	}
6469 
6470 	have_ge = 0;
6471 	li_only = 0;
6472 
6473 	for (;;) {
6474 		r = scf_iter_next_instance(imp_iter, imp_inst);
6475 		if (r == -1) {
6476 			switch (scf_error()) {
6477 			case SCF_ERROR_DELETED:
6478 				warn(s_deleted, s->sc_fmri);
6479 				lcbdata->sc_err = EBUSY;
6480 				r = UU_WALK_ERROR;
6481 				goto deltemp;
6482 
6483 			case SCF_ERROR_CONNECTION_BROKEN:
6484 				goto connaborted;
6485 
6486 			case SCF_ERROR_NOT_BOUND:
6487 			case SCF_ERROR_HANDLE_MISMATCH:
6488 			case SCF_ERROR_INVALID_ARGUMENT:
6489 			case SCF_ERROR_NOT_SET:
6490 			default:
6491 				bad_error("scf_iter_next_instance",
6492 				    scf_error());
6493 			}
6494 		}
6495 
6496 		if (r == 0) {
6497 			/*
6498 			 * Didn't find any last-import snapshots.  Override-
6499 			 * import the properties.  Unless one of the instances
6500 			 * has a general/enabled property, in which case we're
6501 			 * probably running a last-import-capable svccfg for
6502 			 * the first time, and we should only take the
6503 			 * last-import snapshot.
6504 			 */
6505 			if (have_ge) {
6506 				li_only = 1;
6507 				no_refresh = 1;
6508 				break;
6509 			}
6510 
6511 			s->sc_import_state = IMPORT_PROP_BEGUN;
6512 
6513 			cbdata.sc_handle = g_hndl;
6514 			cbdata.sc_parent = imp_svc;
6515 			cbdata.sc_service = 1;
6516 			cbdata.sc_flags = SCI_FORCE;
6517 			cbdata.sc_source_fmri = s->sc_fmri;
6518 			cbdata.sc_target_fmri = s->sc_fmri;
6519 			if (uu_list_walk(s->sc_pgroups, entity_pgroup_import,
6520 			    &cbdata, UU_DEFAULT) != 0) {
6521 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6522 					bad_error("uu_list_walk", uu_error());
6523 				lcbdata->sc_err = cbdata.sc_err;
6524 				switch (cbdata.sc_err) {
6525 				case ECONNABORTED:
6526 					goto connaborted;
6527 
6528 				case ECANCELED:
6529 					warn(s_deleted, s->sc_fmri);
6530 					lcbdata->sc_err = EBUSY;
6531 					break;
6532 
6533 				case EINVAL:	/* caught above */
6534 				case EEXIST:
6535 					bad_error("entity_pgroup_import",
6536 					    cbdata.sc_err);
6537 				}
6538 
6539 				r = UU_WALK_ERROR;
6540 				goto deltemp;
6541 			}
6542 
6543 			cbdata.sc_trans = NULL;
6544 			if (uu_list_walk(s->sc_dependents,
6545 			    lscf_dependent_import, &cbdata, UU_DEFAULT) != 0) {
6546 				if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6547 					bad_error("uu_list_walk", uu_error());
6548 				lcbdata->sc_err = cbdata.sc_err;
6549 				if (cbdata.sc_err == ECONNABORTED)
6550 					goto connaborted;
6551 				r = UU_WALK_ERROR;
6552 				goto deltemp;
6553 			}
6554 			break;
6555 		}
6556 
6557 		if (scf_instance_get_snapshot(imp_inst, snap_lastimport,
6558 		    imp_snap) != 0) {
6559 			switch (scf_error()) {
6560 			case SCF_ERROR_DELETED:
6561 				continue;
6562 
6563 			case SCF_ERROR_NOT_FOUND:
6564 				break;
6565 
6566 			case SCF_ERROR_CONNECTION_BROKEN:
6567 				goto connaborted;
6568 
6569 			case SCF_ERROR_HANDLE_MISMATCH:
6570 			case SCF_ERROR_NOT_BOUND:
6571 			case SCF_ERROR_INVALID_ARGUMENT:
6572 			case SCF_ERROR_NOT_SET:
6573 			default:
6574 				bad_error("scf_instance_get_snapshot",
6575 				    scf_error());
6576 			}
6577 
6578 			if (have_ge)
6579 				continue;
6580 
6581 			/*
6582 			 * Check for a general/enabled property.  This is how
6583 			 * we tell whether to import if there turn out to be
6584 			 * no last-import snapshots.
6585 			 */
6586 			if (scf_instance_get_pg(imp_inst, SCF_PG_GENERAL,
6587 			    imp_pg) == 0) {
6588 				if (scf_pg_get_property(imp_pg,
6589 				    SCF_PROPERTY_ENABLED, imp_prop) == 0) {
6590 					have_ge = 1;
6591 				} else {
6592 					switch (scf_error()) {
6593 					case SCF_ERROR_DELETED:
6594 					case SCF_ERROR_NOT_FOUND:
6595 						continue;
6596 
6597 					case SCF_ERROR_INVALID_ARGUMENT:
6598 					case SCF_ERROR_HANDLE_MISMATCH:
6599 					case SCF_ERROR_CONNECTION_BROKEN:
6600 					case SCF_ERROR_NOT_BOUND:
6601 					case SCF_ERROR_NOT_SET:
6602 					default:
6603 						bad_error("scf_pg_get_property",
6604 						    scf_error());
6605 					}
6606 				}
6607 			} else {
6608 				switch (scf_error()) {
6609 				case SCF_ERROR_DELETED:
6610 				case SCF_ERROR_NOT_FOUND:
6611 					continue;
6612 
6613 				case SCF_ERROR_CONNECTION_BROKEN:
6614 					goto connaborted;
6615 
6616 				case SCF_ERROR_NOT_BOUND:
6617 				case SCF_ERROR_NOT_SET:
6618 				case SCF_ERROR_INVALID_ARGUMENT:
6619 				case SCF_ERROR_HANDLE_MISMATCH:
6620 				default:
6621 					bad_error("scf_instance_get_pg",
6622 					    scf_error());
6623 				}
6624 			}
6625 			continue;
6626 		}
6627 
6628 		/* find service snaplevel */
6629 		r = get_snaplevel(imp_snap, 1, imp_snpl);
6630 		switch (r) {
6631 		case 0:
6632 			break;
6633 
6634 		case ECONNABORTED:
6635 			goto connaborted;
6636 
6637 		case ECANCELED:
6638 			continue;
6639 
6640 		case ENOENT:
6641 			if (scf_instance_get_name(imp_inst, imp_str,
6642 			    imp_str_sz) < 0)
6643 				(void) strcpy(imp_str, "?");
6644 			warn(badsnap, snap_lastimport, s->sc_name, imp_str);
6645 			lcbdata->sc_err = EBADF;
6646 			r = UU_WALK_ERROR;
6647 			goto deltemp;
6648 
6649 		default:
6650 			bad_error("get_snaplevel", r);
6651 		}
6652 
6653 		if (scf_instance_get_snapshot(imp_inst, snap_running,
6654 		    imp_rsnap) != 0) {
6655 			switch (scf_error()) {
6656 			case SCF_ERROR_DELETED:
6657 				continue;
6658 
6659 			case SCF_ERROR_NOT_FOUND:
6660 				break;
6661 
6662 			case SCF_ERROR_CONNECTION_BROKEN:
6663 				goto connaborted;
6664 
6665 			case SCF_ERROR_INVALID_ARGUMENT:
6666 			case SCF_ERROR_HANDLE_MISMATCH:
6667 			case SCF_ERROR_NOT_BOUND:
6668 			case SCF_ERROR_NOT_SET:
6669 			default:
6670 				bad_error("scf_instance_get_snapshot",
6671 				    scf_error());
6672 			}
6673 			running = NULL;
6674 		} else {
6675 			r = get_snaplevel(imp_rsnap, 1, imp_rsnpl);
6676 			switch (r) {
6677 			case 0:
6678 				running = imp_rsnpl;
6679 				break;
6680 
6681 			case ECONNABORTED:
6682 				goto connaborted;
6683 
6684 			case ECANCELED:
6685 				continue;
6686 
6687 			case ENOENT:
6688 				if (scf_instance_get_name(imp_inst, imp_str,
6689 				    imp_str_sz) < 0)
6690 					(void) strcpy(imp_str, "?");
6691 				warn(badsnap, snap_running, s->sc_name,
6692 				    imp_str);
6693 				lcbdata->sc_err = EBADF;
6694 				r = UU_WALK_ERROR;
6695 				goto deltemp;
6696 
6697 			default:
6698 				bad_error("get_snaplevel", r);
6699 			}
6700 		}
6701 
6702 		if (g_verbose) {
6703 			if (scf_instance_get_name(imp_inst, imp_str,
6704 			    imp_str_sz) < 0)
6705 				(void) strcpy(imp_str, "?");
6706 			warn(gettext("Upgrading properties of %s according to "
6707 			    "instance \"%s\".\n"), s->sc_fmri, imp_str);
6708 		}
6709 
6710 		/* upgrade service properties */
6711 		r = upgrade_props(imp_svc, running, imp_snpl, s);
6712 		if (r == 0)
6713 			break;
6714 
6715 		switch (r) {
6716 		case ECONNABORTED:
6717 			goto connaborted;
6718 
6719 		case ECANCELED:
6720 			warn(s_deleted, s->sc_fmri);
6721 			lcbdata->sc_err = EBUSY;
6722 			break;
6723 
6724 		case ENODEV:
6725 			if (scf_instance_get_name(imp_inst, imp_str,
6726 			    imp_str_sz) < 0)
6727 				(void) strcpy(imp_str, "?");
6728 			warn(i_deleted, s->sc_fmri, imp_str);
6729 			lcbdata->sc_err = EBUSY;
6730 			break;
6731 
6732 		default:
6733 			lcbdata->sc_err = r;
6734 		}
6735 
6736 		r = UU_WALK_ERROR;
6737 		goto deltemp;
6738 	}
6739 
6740 	s->sc_import_state = IMPORT_PROP_DONE;
6741 
6742 instances:
6743 	/* import instances */
6744 	cbdata.sc_handle = lcbdata->sc_handle;
6745 	cbdata.sc_parent = imp_svc;
6746 	cbdata.sc_service = 1;
6747 	cbdata.sc_flags = lcbdata->sc_flags | (fresh ? SCI_FRESH : 0);
6748 	cbdata.sc_general = NULL;
6749 
6750 	if (uu_list_walk(s->sc_u.sc_service.sc_service_instances,
6751 	    lscf_instance_import, &cbdata, UU_DEFAULT) != 0) {
6752 		if (uu_error() != UU_ERROR_CALLBACK_FAILED)
6753 			bad_error("uu_list_walk", uu_error());
6754 
6755 		lcbdata->sc_err = cbdata.sc_err;
6756 		if (cbdata.sc_err == ECONNABORTED)
6757 			goto connaborted;
6758 		r = UU_WALK_ERROR;
6759 		goto deltemp;
6760 	}
6761 
6762 	s->sc_import_state = IMPORT_COMPLETE;
6763 	r = UU_WALK_NEXT;
6764 
6765 deltemp:
6766 	/* delete temporary service */
6767 	if (scf_service_delete(imp_tsvc) != 0) {
6768 		switch (scf_error()) {
6769 		case SCF_ERROR_DELETED:
6770 			break;
6771 
6772 		case SCF_ERROR_CONNECTION_BROKEN:
6773 			goto connaborted;
6774 
6775 		case SCF_ERROR_EXISTS:
6776 			warn(gettext(
6777 			    "Could not delete svc:/%s (instances exist).\n"),
6778 			    imp_tsname);
6779 			break;
6780 
6781 		case SCF_ERROR_NOT_SET:
6782 		case SCF_ERROR_NOT_BOUND:
6783 		default:
6784 			bad_error("scf_service_delete", scf_error());
6785 		}
6786 	}
6787 
6788 	return (r);
6789 
6790 connaborted:
6791 	warn(gettext("Could not delete svc:/%s "
6792 	    "(repository connection broken).\n"), imp_tsname);
6793 	lcbdata->sc_err = ECONNABORTED;
6794 	return (UU_WALK_ERROR);
6795 }
6796 
6797 static const char *
6798 import_progress(int st)
6799 {
6800 	switch (st) {
6801 	case 0:
6802 		return (gettext("not reached."));
6803 
6804 	case IMPORT_PREVIOUS:
6805 		return (gettext("previous snapshot taken."));
6806 
6807 	case IMPORT_PROP_BEGUN:
6808 		return (gettext("some properties imported."));
6809 
6810 	case IMPORT_PROP_DONE:
6811 		return (gettext("properties imported."));
6812 
6813 	case IMPORT_COMPLETE:
6814 		return (gettext("imported."));
6815 
6816 	case IMPORT_REFRESHED:
6817 		return (gettext("refresh requested."));
6818 
6819 	default:
6820 #ifndef NDEBUG
6821 		(void) fprintf(stderr, "%s:%d: Unknown entity state %d.\n",
6822 		    __FILE__, __LINE__, st);
6823 #endif
6824 		abort();
6825 		/* NOTREACHED */
6826 	}
6827 }
6828 
6829 /*
6830  * Returns
6831  *   0 - success
6832  *     - fmri wasn't found (error printed)
6833  *     - entity was deleted (error printed)
6834  *     - backend denied access (error printed)
6835  *   ENOMEM - out of memory (error printed)
6836  *   ECONNABORTED - repository connection broken (error printed)
6837  *   EPERM - permission denied (error printed)
6838  *   -1 - unknown libscf error (error printed)
6839  */
6840 static int
6841 imp_refresh_fmri(const char *fmri, const char *name, const char *d_fmri)
6842 {
6843 	scf_error_t serr;
6844 	void *ent;
6845 	int issvc;
6846 	int r;
6847 
6848 	const char *deleted = gettext("Could not refresh %s (deleted).\n");
6849 	const char *dpt_deleted = gettext("Could not refresh %s "
6850 	    "(dependent \"%s\" of %s) (deleted).\n");
6851 
6852 	serr = fmri_to_entity(g_hndl, fmri, &ent, &issvc);
6853 	switch (serr) {
6854 	case SCF_ERROR_NONE:
6855 		break;
6856 
6857 	case SCF_ERROR_NO_MEMORY:
6858 		if (name == NULL)
6859 			warn(gettext("Could not refresh %s (out of memory).\n"),
6860 			    fmri);
6861 		else
6862 			warn(gettext("Could not refresh %s "
6863 			    "(dependent \"%s\" of %s) (out of memory).\n"),
6864 			    fmri, name, d_fmri);
6865 		return (ENOMEM);
6866 
6867 	case SCF_ERROR_NOT_FOUND:
6868 		if (name == NULL)
6869 			warn(deleted, fmri);
6870 		else
6871 			warn(dpt_deleted, fmri, name, d_fmri);
6872 		return (0);
6873 
6874 	case SCF_ERROR_INVALID_ARGUMENT:
6875 	case SCF_ERROR_CONSTRAINT_VIOLATED:
6876 	default:
6877 		bad_error("fmri_to_entity", serr);
6878 	}
6879 
6880 	r = refresh_entity(issvc, ent, fmri, imp_inst, imp_iter, imp_str);
6881 	switch (r) {
6882 	case 0:
6883 		break;
6884 
6885 	case ECONNABORTED:
6886 		if (name != NULL)
6887 			warn(gettext("Could not refresh %s "
6888 			    "(dependent \"%s\" of %s) "
6889 			    "(repository connection broken).\n"), fmri, name,
6890 			    d_fmri);
6891 		return (r);
6892 
6893 	case ECANCELED:
6894 		if (name == NULL)
6895 			warn(deleted, fmri);
6896 		else
6897 			warn(dpt_deleted, fmri, name, d_fmri);
6898 		return (0);
6899 
6900 	case EACCES:
6901 		if (!g_verbose)
6902 			return (0);
6903 		if (name == NULL)
6904 			warn(gettext("Could not refresh %s "
6905 			    "(backend access denied).\n"), fmri);
6906 		else
6907 			warn(gettext("Could not refresh %s "
6908 			    "(dependent \"%s\" of %s) "
6909 			    "(backend access denied).\n"), fmri, name, d_fmri);
6910 		return (0);
6911 
6912 	case EPERM:
6913 		if (name == NULL)
6914 			warn(gettext("Could not refresh %s "
6915 			    "(permission denied).\n"), fmri);
6916 		else
6917 			warn(gettext("Could not refresh %s "
6918 			    "(dependent \"%s\" of %s) "
6919 			    "(permission denied).\n"), fmri, name, d_fmri);
6920 		return (r);
6921 
6922 	case ENOSPC:
6923 		if (name == NULL)
6924 			warn(gettext("Could not refresh %s "
6925 			    "(repository server out of resources).\n"),
6926 			    fmri);
6927 		else
6928 			warn(gettext("Could not refresh %s "
6929 			    "(dependent \"%s\" of %s) "
6930 			    "(repository server out of resources).\n"),
6931 			    fmri, name, d_fmri);
6932 		return (r);
6933 
6934 	case -1:
6935 		scfwarn();
6936 		return (r);
6937 
6938 	default:
6939 		bad_error("refresh_entity", r);
6940 	}
6941 
6942 	if (issvc)
6943 		scf_service_destroy(ent);
6944 	else
6945 		scf_instance_destroy(ent);
6946 
6947 	return (0);
6948 }
6949 
6950 int
6951 lscf_bundle_import(bundle_t *bndl, const char *filename, uint_t flags)
6952 {
6953 	scf_callback_t cbdata;
6954 	int result = 0;
6955 	entity_t *svc, *inst;
6956 	uu_list_t *insts;
6957 	int r;
6958 	pgroup_t *old_dpt;
6959 	void *cookie;
6960 	int annotation_set = 0;
6961 
6962 	const char * const emsg_nomem = gettext("Out of memory.\n");
6963 	const char * const emsg_nores =
6964 	    gettext("svc.configd is out of resources.\n");
6965 
6966 	lscf_prep_hndl();
6967 
6968 	imp_str_sz = ((max_scf_name_len > max_scf_fmri_len) ?
6969 	    max_scf_name_len : max_scf_fmri_len) + 1;
6970 
6971 	if ((imp_scope = scf_scope_create(g_hndl)) == NULL ||
6972 	    (imp_svc = scf_service_create(g_hndl)) == NULL ||
6973 	    (imp_tsvc = scf_service_create(g_hndl)) == NULL ||
6974 	    (imp_inst = scf_instance_create(g_hndl)) == NULL ||
6975 	    (imp_tinst = scf_instance_create(g_hndl)) == NULL ||
6976 	    (imp_snap = scf_snapshot_create(g_hndl)) == NULL ||
6977 	    (imp_lisnap = scf_snapshot_create(g_hndl)) == NULL ||
6978 	    (imp_tlisnap = scf_snapshot_create(g_hndl)) == NULL ||
6979 	    (imp_rsnap = scf_snapshot_create(g_hndl)) == NULL ||
6980 	    (imp_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
6981 	    (imp_rsnpl = scf_snaplevel_create(g_hndl)) == NULL ||
6982 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
6983 	    (imp_pg2 = scf_pg_create(g_hndl)) == NULL ||
6984 	    (imp_prop = scf_property_create(g_hndl)) == NULL ||
6985 	    (imp_iter = scf_iter_create(g_hndl)) == NULL ||
6986 	    (imp_rpg_iter = scf_iter_create(g_hndl)) == NULL ||
6987 	    (imp_up_iter = scf_iter_create(g_hndl)) == NULL ||
6988 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL ||
6989 	    (imp_str = malloc(imp_str_sz)) == NULL ||
6990 	    (imp_tsname = malloc(max_scf_name_len + 1)) == NULL ||
6991 	    (imp_fe1 = malloc(max_scf_fmri_len + 1)) == NULL ||
6992 	    (imp_fe2 = malloc(max_scf_fmri_len + 1)) == NULL ||
6993 	    (imp_deleted_dpts = uu_list_create(string_pool, NULL, 0)) == NULL ||
6994 	    (ud_inst = scf_instance_create(g_hndl)) == NULL ||
6995 	    (ud_snpl = scf_snaplevel_create(g_hndl)) == NULL ||
6996 	    (ud_pg = scf_pg_create(g_hndl)) == NULL ||
6997 	    (ud_cur_depts_pg = scf_pg_create(g_hndl)) == NULL ||
6998 	    (ud_run_dpts_pg = scf_pg_create(g_hndl)) == NULL ||
6999 	    (ud_prop = scf_property_create(g_hndl)) == NULL ||
7000 	    (ud_dpt_prop = scf_property_create(g_hndl)) == NULL ||
7001 	    (ud_val = scf_value_create(g_hndl)) == NULL ||
7002 	    (ud_iter = scf_iter_create(g_hndl)) == NULL ||
7003 	    (ud_iter2 = scf_iter_create(g_hndl)) == NULL ||
7004 	    (ud_tx = scf_transaction_create(g_hndl)) == NULL ||
7005 	    (ud_ctarg = malloc(max_scf_value_len + 1)) == NULL ||
7006 	    (ud_oldtarg = malloc(max_scf_value_len + 1)) == NULL ||
7007 	    (ud_name = malloc(max_scf_name_len + 1)) == NULL) {
7008 		if (scf_error() == SCF_ERROR_NO_RESOURCES)
7009 			warn(emsg_nores);
7010 		else
7011 			warn(emsg_nomem);
7012 		result = -1;
7013 		goto out;
7014 	}
7015 
7016 	r = load_init();
7017 	switch (r) {
7018 	case 0:
7019 		break;
7020 
7021 	case ENOMEM:
7022 		warn(emsg_nomem);
7023 		result = -1;
7024 		goto out;
7025 
7026 	default:
7027 		bad_error("load_init", r);
7028 	}
7029 
7030 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, imp_scope) != 0) {
7031 		switch (scf_error()) {
7032 		case SCF_ERROR_CONNECTION_BROKEN:
7033 			warn(gettext("Repository connection broken.\n"));
7034 			repository_teardown();
7035 			result = -1;
7036 			goto out;
7037 
7038 		case SCF_ERROR_NOT_FOUND:
7039 		case SCF_ERROR_INVALID_ARGUMENT:
7040 		case SCF_ERROR_NOT_BOUND:
7041 		case SCF_ERROR_HANDLE_MISMATCH:
7042 		default:
7043 			bad_error("scf_handle_get_scope", scf_error());
7044 		}
7045 	}
7046 
7047 	/* Set up the auditing annotation. */
7048 	if (_scf_set_annotation(g_hndl, "svccfg import", filename) == 0) {
7049 		annotation_set = 1;
7050 	} else {
7051 		switch (scf_error()) {
7052 		case SCF_ERROR_CONNECTION_BROKEN:
7053 			warn(gettext("Repository connection broken.\n"));
7054 			repository_teardown();
7055 			result = -1;
7056 			goto out;
7057 
7058 		case SCF_ERROR_INVALID_ARGUMENT:
7059 		case SCF_ERROR_NOT_BOUND:
7060 		case SCF_ERROR_NO_RESOURCES:
7061 		case SCF_ERROR_INTERNAL:
7062 			bad_error("_scf_set_annotation", scf_error());
7063 			/* NOTREACHED */
7064 
7065 		default:
7066 			/*
7067 			 * Do not terminate import because of inability to
7068 			 * generate annotation audit event.
7069 			 */
7070 			warn(gettext("_scf_set_annotation() unexpectedly "
7071 			    "failed with return code of %d\n"), scf_error());
7072 			break;
7073 		}
7074 	}
7075 
7076 	/*
7077 	 * Clear the sc_import_state's of all services & instances so we can
7078 	 * report how far we got if we fail.
7079 	 */
7080 	for (svc = uu_list_first(bndl->sc_bundle_services);
7081 	    svc != NULL;
7082 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7083 		svc->sc_import_state = 0;
7084 
7085 		if (uu_list_walk(svc->sc_u.sc_service.sc_service_instances,
7086 		    clear_int, (void *)offsetof(entity_t, sc_import_state),
7087 		    UU_DEFAULT) != 0)
7088 			bad_error("uu_list_walk", uu_error());
7089 	}
7090 
7091 	cbdata.sc_handle = g_hndl;
7092 	cbdata.sc_parent = imp_scope;
7093 	cbdata.sc_flags = flags;
7094 	cbdata.sc_general = NULL;
7095 
7096 	if (uu_list_walk(bndl->sc_bundle_services, lscf_service_import,
7097 	    &cbdata, UU_DEFAULT) == 0) {
7098 		/* Success.  Refresh everything. */
7099 
7100 		if (flags & SCI_NOREFRESH || no_refresh) {
7101 			result = 0;
7102 			goto out;
7103 		}
7104 
7105 		for (svc = uu_list_first(bndl->sc_bundle_services);
7106 		    svc != NULL;
7107 		    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7108 			pgroup_t *dpt;
7109 
7110 			insts = svc->sc_u.sc_service.sc_service_instances;
7111 
7112 			for (inst = uu_list_first(insts);
7113 			    inst != NULL;
7114 			    inst = uu_list_next(insts, inst)) {
7115 				r = imp_refresh_fmri(inst->sc_fmri, NULL, NULL);
7116 				switch (r) {
7117 				case 0:
7118 					break;
7119 
7120 				case ENOMEM:
7121 				case ECONNABORTED:
7122 				case EPERM:
7123 				case -1:
7124 					goto progress;
7125 
7126 				default:
7127 					bad_error("imp_refresh_fmri", r);
7128 				}
7129 
7130 				inst->sc_import_state = IMPORT_REFRESHED;
7131 
7132 				for (dpt = uu_list_first(inst->sc_dependents);
7133 				    dpt != NULL;
7134 				    dpt = uu_list_next(inst->sc_dependents,
7135 				    dpt))
7136 					if (imp_refresh_fmri(
7137 					    dpt->sc_pgroup_fmri,
7138 					    dpt->sc_pgroup_name,
7139 					    inst->sc_fmri) != 0)
7140 						goto progress;
7141 			}
7142 
7143 			for (dpt = uu_list_first(svc->sc_dependents);
7144 			    dpt != NULL;
7145 			    dpt = uu_list_next(svc->sc_dependents, dpt))
7146 				if (imp_refresh_fmri(dpt->sc_pgroup_fmri,
7147 				    dpt->sc_pgroup_name, svc->sc_fmri) != 0)
7148 					goto progress;
7149 		}
7150 
7151 		for (old_dpt = uu_list_first(imp_deleted_dpts);
7152 		    old_dpt != NULL;
7153 		    old_dpt = uu_list_next(imp_deleted_dpts, old_dpt))
7154 			if (imp_refresh_fmri(old_dpt->sc_pgroup_fmri,
7155 			    old_dpt->sc_pgroup_name,
7156 			    old_dpt->sc_parent->sc_fmri) != 0)
7157 				goto progress;
7158 
7159 		result = 0;
7160 		goto out;
7161 	}
7162 
7163 	if (uu_error() != UU_ERROR_CALLBACK_FAILED)
7164 		bad_error("uu_list_walk", uu_error());
7165 
7166 printerr:
7167 	/* If the error hasn't been printed yet, do so here. */
7168 	switch (cbdata.sc_err) {
7169 	case ECONNABORTED:
7170 		warn(gettext("Repository connection broken.\n"));
7171 		break;
7172 
7173 	case ENOMEM:
7174 		warn(emsg_nomem);
7175 		break;
7176 
7177 	case ENOSPC:
7178 		warn(emsg_nores);
7179 		break;
7180 
7181 	case EROFS:
7182 		warn(gettext("Repository is read-only.\n"));
7183 		break;
7184 
7185 	case EACCES:
7186 		warn(gettext("Repository backend denied access.\n"));
7187 		break;
7188 
7189 	case EPERM:
7190 	case EINVAL:
7191 	case EEXIST:
7192 	case EBUSY:
7193 	case EBADF:
7194 	case -1:
7195 		break;
7196 
7197 	default:
7198 		bad_error("lscf_service_import", cbdata.sc_err);
7199 	}
7200 
7201 progress:
7202 	warn(gettext("Import of %s failed.  Progress:\n"), filename);
7203 
7204 	for (svc = uu_list_first(bndl->sc_bundle_services);
7205 	    svc != NULL;
7206 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7207 		insts = svc->sc_u.sc_service.sc_service_instances;
7208 
7209 		warn(gettext("  Service \"%s\": %s\n"), svc->sc_name,
7210 		    import_progress(svc->sc_import_state));
7211 
7212 		for (inst = uu_list_first(insts);
7213 		    inst != NULL;
7214 		    inst = uu_list_next(insts, inst))
7215 			warn(gettext("    Instance \"%s\": %s\n"),
7216 			    inst->sc_name,
7217 			    import_progress(inst->sc_import_state));
7218 	}
7219 
7220 	if (cbdata.sc_err == ECONNABORTED)
7221 		repository_teardown();
7222 
7223 
7224 	result = -1;
7225 
7226 out:
7227 	if (annotation_set != 0) {
7228 		/* Turn off annotation.  It is no longer needed. */
7229 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7230 	}
7231 	load_fini();
7232 
7233 	free(ud_ctarg);
7234 	free(ud_oldtarg);
7235 	free(ud_name);
7236 	ud_ctarg = ud_oldtarg = ud_name = NULL;
7237 
7238 	scf_transaction_destroy(ud_tx);
7239 	ud_tx = NULL;
7240 	scf_iter_destroy(ud_iter);
7241 	scf_iter_destroy(ud_iter2);
7242 	ud_iter = ud_iter2 = NULL;
7243 	scf_value_destroy(ud_val);
7244 	ud_val = NULL;
7245 	scf_property_destroy(ud_prop);
7246 	scf_property_destroy(ud_dpt_prop);
7247 	ud_prop = ud_dpt_prop = NULL;
7248 	scf_pg_destroy(ud_pg);
7249 	scf_pg_destroy(ud_cur_depts_pg);
7250 	scf_pg_destroy(ud_run_dpts_pg);
7251 	ud_pg = ud_cur_depts_pg = ud_run_dpts_pg = NULL;
7252 	scf_snaplevel_destroy(ud_snpl);
7253 	ud_snpl = NULL;
7254 	scf_instance_destroy(ud_inst);
7255 	ud_inst = NULL;
7256 
7257 	free(imp_str);
7258 	free(imp_tsname);
7259 	free(imp_fe1);
7260 	free(imp_fe2);
7261 	imp_str = imp_tsname = imp_fe1 = imp_fe2 = NULL;
7262 
7263 	cookie = NULL;
7264 	while ((old_dpt = uu_list_teardown(imp_deleted_dpts, &cookie)) !=
7265 	    NULL) {
7266 		free((char *)old_dpt->sc_pgroup_name);
7267 		free((char *)old_dpt->sc_pgroup_fmri);
7268 		internal_pgroup_free(old_dpt);
7269 	}
7270 	uu_list_destroy(imp_deleted_dpts);
7271 
7272 	scf_transaction_destroy(imp_tx);
7273 	imp_tx = NULL;
7274 	scf_iter_destroy(imp_iter);
7275 	scf_iter_destroy(imp_rpg_iter);
7276 	scf_iter_destroy(imp_up_iter);
7277 	imp_iter = imp_rpg_iter = imp_up_iter = NULL;
7278 	scf_property_destroy(imp_prop);
7279 	imp_prop = NULL;
7280 	scf_pg_destroy(imp_pg);
7281 	scf_pg_destroy(imp_pg2);
7282 	imp_pg = imp_pg2 = NULL;
7283 	scf_snaplevel_destroy(imp_snpl);
7284 	scf_snaplevel_destroy(imp_rsnpl);
7285 	imp_snpl = imp_rsnpl = NULL;
7286 	scf_snapshot_destroy(imp_snap);
7287 	scf_snapshot_destroy(imp_lisnap);
7288 	scf_snapshot_destroy(imp_tlisnap);
7289 	scf_snapshot_destroy(imp_rsnap);
7290 	imp_snap = imp_lisnap = imp_tlisnap = imp_rsnap = NULL;
7291 	scf_instance_destroy(imp_inst);
7292 	scf_instance_destroy(imp_tinst);
7293 	imp_inst = imp_tinst = NULL;
7294 	scf_service_destroy(imp_svc);
7295 	scf_service_destroy(imp_tsvc);
7296 	imp_svc = imp_tsvc = NULL;
7297 	scf_scope_destroy(imp_scope);
7298 	imp_scope = NULL;
7299 
7300 	return (result);
7301 }
7302 
7303 
7304 /*
7305  * Returns
7306  *   0 - success
7307  *   -1 - lscf_import_instance_pgs() failed.
7308  */
7309 int
7310 lscf_bundle_apply(bundle_t *bndl, const char *file)
7311 {
7312 	entity_t *svc, *inst;
7313 	scf_scope_t *rscope;
7314 	scf_service_t *rsvc;
7315 	scf_instance_t *rinst;
7316 	int annotation_set = 0;
7317 	int r;
7318 
7319 	lscf_prep_hndl();
7320 
7321 	if ((rscope = scf_scope_create(g_hndl)) == NULL ||
7322 	    (rsvc = scf_service_create(g_hndl)) == NULL ||
7323 	    (rinst = scf_instance_create(g_hndl)) == NULL ||
7324 	    (imp_pg = scf_pg_create(g_hndl)) == NULL ||
7325 	    (imp_tx = scf_transaction_create(g_hndl)) == NULL)
7326 		scfdie();
7327 
7328 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, rscope) != 0)
7329 		scfdie();
7330 
7331 	/*
7332 	 * Set the strings to be used for the security audit annotation
7333 	 * event.
7334 	 */
7335 	if (_scf_set_annotation(g_hndl, "svccfg apply", file) == 0) {
7336 		annotation_set = 1;
7337 	} else {
7338 		switch (scf_error()) {
7339 		case SCF_ERROR_CONNECTION_BROKEN:
7340 			warn(gettext("Repository connection broken.\n"));
7341 			goto out;
7342 
7343 		case SCF_ERROR_INVALID_ARGUMENT:
7344 		case SCF_ERROR_NOT_BOUND:
7345 		case SCF_ERROR_NO_RESOURCES:
7346 		case SCF_ERROR_INTERNAL:
7347 			bad_error("_scf_set_annotation", scf_error());
7348 			/* NOTREACHED */
7349 
7350 		default:
7351 			/*
7352 			 * Do not abort apply operation because of
7353 			 * inability to create annotation audit event.
7354 			 */
7355 			warn(gettext("_scf_set_annotation() unexpectedly "
7356 			    "failed with return code of %d\n"), scf_error());
7357 			break;
7358 		}
7359 	}
7360 
7361 	for (svc = uu_list_first(bndl->sc_bundle_services);
7362 	    svc != NULL;
7363 	    svc = uu_list_next(bndl->sc_bundle_services, svc)) {
7364 		if (scf_scope_get_service(rscope, svc->sc_name, rsvc) != 0) {
7365 			switch (scf_error()) {
7366 			case SCF_ERROR_NOT_FOUND:
7367 				if (g_verbose)
7368 					warn(gettext("Ignoring nonexistent "
7369 					    "service %s.\n"), svc->sc_name);
7370 				continue;
7371 
7372 			default:
7373 				scfdie();
7374 			}
7375 		}
7376 
7377 		for (inst = uu_list_first(
7378 		    svc->sc_u.sc_service.sc_service_instances);
7379 		    inst != NULL;
7380 		    inst = uu_list_next(
7381 		    svc->sc_u.sc_service.sc_service_instances, inst)) {
7382 			if (scf_service_get_instance(rsvc, inst->sc_name,
7383 			    rinst) != 0) {
7384 				switch (scf_error()) {
7385 				case SCF_ERROR_NOT_FOUND:
7386 					if (g_verbose)
7387 						warn(gettext("Ignoring "
7388 						    "nonexistant instance "
7389 						    "%s:%s.\n"),
7390 						    inst->sc_parent->sc_name,
7391 						    inst->sc_name);
7392 					continue;
7393 
7394 				default:
7395 					scfdie();
7396 				}
7397 			}
7398 
7399 			r = lscf_import_instance_pgs(rinst, inst->sc_fmri, inst,
7400 			    SCI_FORCE | SCI_KEEP);
7401 			switch (r) {
7402 			case 0:
7403 				if (g_verbose)
7404 					warn(gettext("%s updated.\n"),
7405 					    inst->sc_fmri);
7406 				break;
7407 
7408 			case ECONNABORTED:
7409 				warn(gettext("Could not update %s "
7410 				    "(repository connection broken).\n"),
7411 				    inst->sc_fmri);
7412 				goto out;
7413 
7414 			case ENOMEM:
7415 				warn(gettext("Could not update %s "
7416 				    "(out of memory).\n"), inst->sc_fmri);
7417 				goto out;
7418 
7419 			case ENOSPC:
7420 				warn(gettext("Could not update %s "
7421 				    "(repository server out of resources).\n"),
7422 				    inst->sc_fmri);
7423 				goto out;
7424 
7425 			case ECANCELED:
7426 				warn(gettext(
7427 				    "Could not update %s (deleted).\n"),
7428 				    inst->sc_fmri);
7429 				break;
7430 
7431 			case EPERM:
7432 			case EINVAL:
7433 			case EBUSY:
7434 				break;
7435 
7436 			case EROFS:
7437 				warn(gettext("Could not update %s "
7438 				    "(repository read-only).\n"),
7439 				    inst->sc_fmri);
7440 				goto out;
7441 
7442 			case EACCES:
7443 				warn(gettext("Could not update %s "
7444 				    "(backend access denied).\n"),
7445 				    inst->sc_fmri);
7446 				break;
7447 
7448 			case EEXIST:
7449 			default:
7450 				bad_error("lscf_import_instance_pgs", r);
7451 			}
7452 		}
7453 	}
7454 
7455 out:
7456 	if (annotation_set) {
7457 		/* Remove security audit annotation strings. */
7458 		(void) _scf_set_annotation(g_hndl, NULL, NULL);
7459 	}
7460 
7461 	scf_transaction_destroy(imp_tx);
7462 	imp_tx = NULL;
7463 	scf_pg_destroy(imp_pg);
7464 	imp_pg = NULL;
7465 
7466 	scf_instance_destroy(rinst);
7467 	scf_service_destroy(rsvc);
7468 	scf_scope_destroy(rscope);
7469 	return (0);
7470 }
7471 
7472 
7473 /*
7474  * Export.  These functions create and output an XML tree of a service
7475  * description from the repository.  This is largely the inverse of
7476  * lxml_get_bundle() in svccfg_xml.c, but with some kickers:
7477  *
7478  * - We must include any properties which are not represented specifically by
7479  *   a service manifest, e.g., properties created by an admin post-import.  To
7480  *   do so we'll iterate through all properties and deal with each
7481  *   apropriately.
7482  *
7483  * - Children of services and instances must must be in the order set by the
7484  *   DTD, but we iterate over the properties in undefined order.  The elements
7485  *   are not easily (or efficiently) sortable by name.  Since there's a fixed
7486  *   number of classes of them, however, we'll keep the classes separate and
7487  *   assemble them in order.
7488  */
7489 
7490 /*
7491  * Convenience function to handle xmlSetProp errors (and type casting).
7492  */
7493 static void
7494 safe_setprop(xmlNodePtr n, const char *name, const char *val)
7495 {
7496 	if (xmlSetProp(n, (const xmlChar *)name, (const xmlChar *)val) == NULL)
7497 		uu_die(gettext("Could not set XML property.\n"));
7498 }
7499 
7500 /*
7501  * Convenience function to set an XML attribute to the single value of an
7502  * astring property.  If the value happens to be the default, don't set the
7503  * attribute.  "dval" should be the default value supplied by the DTD, or
7504  * NULL for no default.
7505  */
7506 static int
7507 set_attr_from_prop_default(scf_property_t *prop, xmlNodePtr n,
7508     const char *name, const char *dval)
7509 {
7510 	scf_value_t *val;
7511 	ssize_t len;
7512 	char *str;
7513 
7514 	val = scf_value_create(g_hndl);
7515 	if (val == NULL)
7516 		scfdie();
7517 
7518 	if (prop_get_val(prop, val) != 0) {
7519 		scf_value_destroy(val);
7520 		return (-1);
7521 	}
7522 
7523 	len = scf_value_get_as_string(val, NULL, 0);
7524 	if (len < 0)
7525 		scfdie();
7526 
7527 	str = safe_malloc(len + 1);
7528 
7529 	if (scf_value_get_as_string(val, str, len + 1) < 0)
7530 		scfdie();
7531 
7532 	scf_value_destroy(val);
7533 
7534 	if (dval == NULL || strcmp(str, dval) != 0)
7535 		safe_setprop(n, name, str);
7536 
7537 	free(str);
7538 
7539 	return (0);
7540 }
7541 
7542 /*
7543  * As above, but the attribute is always set.
7544  */
7545 static int
7546 set_attr_from_prop(scf_property_t *prop, xmlNodePtr n, const char *name)
7547 {
7548 	return (set_attr_from_prop_default(prop, n, name, NULL));
7549 }
7550 
7551 /*
7552  * Dump the given document onto f, with "'s replaced by ''s.
7553  */
7554 static int
7555 write_service_bundle(xmlDocPtr doc, FILE *f)
7556 {
7557 	xmlChar *mem;
7558 	int sz, i;
7559 
7560 	mem = NULL;
7561 	xmlDocDumpFormatMemory(doc, &mem, &sz, 1);
7562 
7563 	if (mem == NULL) {
7564 		semerr(gettext("Could not dump XML tree.\n"));
7565 		return (-1);
7566 	}
7567 
7568 	/*
7569 	 * Fortunately libxml produces &quot; instead of ", so we can blindly
7570 	 * replace all " with '.  Cursed libxml2!  Why must you #ifdef out the
7571 	 * &apos; code?!
7572 	 */
7573 	for (i = 0; i < sz; ++i) {
7574 		char c = (char)mem[i];
7575 
7576 		if (c == '"')
7577 			(void) fputc('\'', f);
7578 		else if (c == '\'')
7579 			(void) fwrite("&apos;", sizeof ("&apos;") - 1, 1, f);
7580 		else
7581 			(void) fputc(c, f);
7582 	}
7583 
7584 	return (0);
7585 }
7586 
7587 /*
7588  * Create the DOM elements in elts necessary to (generically) represent prop
7589  * (i.e., a property or propval element).  If the name of the property is
7590  * known, it should be passed as name_arg.  Otherwise, pass NULL.
7591  */
7592 static void
7593 export_property(scf_property_t *prop, const char *name_arg,
7594     struct pg_elts *elts, int flags)
7595 {
7596 	const char *type;
7597 	scf_error_t err = 0;
7598 	xmlNodePtr pnode, lnode;
7599 	char *lnname;
7600 	int ret;
7601 
7602 	/* name */
7603 	if (name_arg != NULL) {
7604 		(void) strcpy(exp_str, name_arg);
7605 	} else {
7606 		if (scf_property_get_name(prop, exp_str, exp_str_sz) < 0)
7607 			scfdie();
7608 	}
7609 
7610 	/* type */
7611 	type = prop_to_typestr(prop);
7612 	if (type == NULL)
7613 		uu_die(gettext("Can't export property %s: unknown type.\n"),
7614 		    exp_str);
7615 
7616 	/* If we're exporting values, and there's just one, export it here. */
7617 	if (!(flags & SCE_ALL_VALUES))
7618 		goto empty;
7619 
7620 	if (scf_property_get_value(prop, exp_val) == SCF_SUCCESS) {
7621 		xmlNodePtr n;
7622 
7623 		/* Single value, so use propval */
7624 		n = xmlNewNode(NULL, (xmlChar *)"propval");
7625 		if (n == NULL)
7626 			uu_die(emsg_create_xml);
7627 
7628 		safe_setprop(n, name_attr, exp_str);
7629 		safe_setprop(n, type_attr, type);
7630 
7631 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
7632 			scfdie();
7633 		safe_setprop(n, value_attr, exp_str);
7634 
7635 		if (elts->propvals == NULL)
7636 			elts->propvals = n;
7637 		else
7638 			(void) xmlAddSibling(elts->propvals, n);
7639 
7640 		return;
7641 	}
7642 
7643 	err = scf_error();
7644 
7645 	if (err == SCF_ERROR_PERMISSION_DENIED) {
7646 		semerr(emsg_permission_denied);
7647 		return;
7648 	}
7649 
7650 	if (err != SCF_ERROR_CONSTRAINT_VIOLATED &&
7651 	    err != SCF_ERROR_NOT_FOUND &&
7652 	    err != SCF_ERROR_PERMISSION_DENIED)
7653 		scfdie();
7654 
7655 empty:
7656 	/* Multiple (or no) values, so use property */
7657 	pnode = xmlNewNode(NULL, (xmlChar *)"property");
7658 	if (pnode == NULL)
7659 		uu_die(emsg_create_xml);
7660 
7661 	safe_setprop(pnode, name_attr, exp_str);
7662 	safe_setprop(pnode, type_attr, type);
7663 
7664 	if (err == SCF_ERROR_CONSTRAINT_VIOLATED) {
7665 		lnname = uu_msprintf("%s_list", type);
7666 		if (lnname == NULL)
7667 			uu_die(gettext("Could not create string"));
7668 
7669 		lnode = xmlNewChild(pnode, NULL, (xmlChar *)lnname, NULL);
7670 		if (lnode == NULL)
7671 			uu_die(emsg_create_xml);
7672 
7673 		uu_free(lnname);
7674 
7675 		if (scf_iter_property_values(exp_val_iter, prop) != SCF_SUCCESS)
7676 			scfdie();
7677 
7678 		while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) ==
7679 		    1) {
7680 			xmlNodePtr vn;
7681 
7682 			vn = xmlNewChild(lnode, NULL, (xmlChar *)"value_node",
7683 			    NULL);
7684 			if (vn == NULL)
7685 				uu_die(emsg_create_xml);
7686 
7687 			if (scf_value_get_as_string(exp_val, exp_str,
7688 			    exp_str_sz) < 0)
7689 				scfdie();
7690 			safe_setprop(vn, value_attr, exp_str);
7691 		}
7692 		if (ret != 0)
7693 			scfdie();
7694 	}
7695 
7696 	if (elts->properties == NULL)
7697 		elts->properties = pnode;
7698 	else
7699 		(void) xmlAddSibling(elts->properties, pnode);
7700 }
7701 
7702 /*
7703  * Add a property_group element for this property group to elts.
7704  */
7705 static void
7706 export_pg(scf_propertygroup_t *pg, struct entity_elts *eelts, int flags)
7707 {
7708 	xmlNodePtr n;
7709 	struct pg_elts elts;
7710 	int ret;
7711 	boolean_t read_protected;
7712 
7713 	n = xmlNewNode(NULL, (xmlChar *)"property_group");
7714 
7715 	/* name */
7716 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
7717 		scfdie();
7718 	safe_setprop(n, name_attr, exp_str);
7719 
7720 	/* type */
7721 	if (scf_pg_get_type(pg, exp_str, exp_str_sz) < 0)
7722 		scfdie();
7723 	safe_setprop(n, type_attr, exp_str);
7724 
7725 	/* properties */
7726 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
7727 		scfdie();
7728 
7729 	(void) memset(&elts, 0, sizeof (elts));
7730 
7731 	/*
7732 	 * If this property group is not read protected, we always want to
7733 	 * output all the values.  Otherwise, we only output the values if the
7734 	 * caller set SCE_ALL_VALUES (i.e., the user gave us export/archive -a).
7735 	 */
7736 	if (_scf_pg_is_read_protected(pg, &read_protected) != SCF_SUCCESS)
7737 		scfdie();
7738 
7739 	if (!read_protected)
7740 		flags |= SCE_ALL_VALUES;
7741 
7742 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
7743 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
7744 			scfdie();
7745 
7746 		if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
7747 			xmlNodePtr m;
7748 
7749 			m = xmlNewNode(NULL, (xmlChar *)"stability");
7750 			if (m == NULL)
7751 				uu_die(emsg_create_xml);
7752 
7753 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
7754 				elts.stability = m;
7755 				continue;
7756 			}
7757 
7758 			xmlFreeNode(m);
7759 		}
7760 
7761 		export_property(exp_prop, NULL, &elts, flags);
7762 	}
7763 	if (ret == -1)
7764 		scfdie();
7765 
7766 	(void) xmlAddChild(n, elts.stability);
7767 	(void) xmlAddChildList(n, elts.propvals);
7768 	(void) xmlAddChildList(n, elts.properties);
7769 
7770 	if (eelts->property_groups == NULL)
7771 		eelts->property_groups = n;
7772 	else
7773 		(void) xmlAddSibling(eelts->property_groups, n);
7774 }
7775 
7776 /*
7777  * Create an XML node representing the dependency described by the given
7778  * property group and put it in eelts.  Unless the dependency is not valid, in
7779  * which case create a generic property_group element which represents it and
7780  * put it in eelts.
7781  */
7782 static void
7783 export_dependency(scf_propertygroup_t *pg, struct entity_elts *eelts)
7784 {
7785 	xmlNodePtr n;
7786 	int err = 0, ret;
7787 	struct pg_elts elts;
7788 
7789 	n = xmlNewNode(NULL, (xmlChar *)"dependency");
7790 	if (n == NULL)
7791 		uu_die(emsg_create_xml);
7792 
7793 	/*
7794 	 * If the external flag is present, skip this dependency because it
7795 	 * should have been created by another manifest.
7796 	 */
7797 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) == 0) {
7798 		if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
7799 		    prop_get_val(exp_prop, exp_val) == 0) {
7800 			uint8_t b;
7801 
7802 			if (scf_value_get_boolean(exp_val, &b) != SCF_SUCCESS)
7803 				scfdie();
7804 
7805 			if (b)
7806 				return;
7807 		}
7808 	} else if (scf_error() != SCF_ERROR_NOT_FOUND)
7809 		scfdie();
7810 
7811 	/* Get the required attributes. */
7812 
7813 	/* name */
7814 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
7815 		scfdie();
7816 	safe_setprop(n, name_attr, exp_str);
7817 
7818 	/* grouping */
7819 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
7820 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
7821 		err = 1;
7822 
7823 	/* restart_on */
7824 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
7825 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
7826 		err = 1;
7827 
7828 	/* type */
7829 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
7830 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
7831 		err = 1;
7832 
7833 	/*
7834 	 * entities: Not required, but if we create no children, it will be
7835 	 * created as empty on import, so fail if it's missing.
7836 	 */
7837 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
7838 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0) {
7839 		scf_iter_t *eiter;
7840 		int ret2;
7841 
7842 		eiter = scf_iter_create(g_hndl);
7843 		if (eiter == NULL)
7844 			scfdie();
7845 
7846 		if (scf_iter_property_values(eiter, exp_prop) != SCF_SUCCESS)
7847 			scfdie();
7848 
7849 		while ((ret2 = scf_iter_next_value(eiter, exp_val)) == 1) {
7850 			xmlNodePtr ch;
7851 
7852 			if (scf_value_get_astring(exp_val, exp_str,
7853 			    exp_str_sz) < 0)
7854 				scfdie();
7855 
7856 			/*
7857 			 * service_fmri's must be first, so we can add them
7858 			 * here.
7859 			 */
7860 			ch = xmlNewChild(n, NULL, (xmlChar *)"service_fmri",
7861 			    NULL);
7862 			if (ch == NULL)
7863 				uu_die(emsg_create_xml);
7864 
7865 			safe_setprop(ch, value_attr, exp_str);
7866 		}
7867 		if (ret2 == -1)
7868 			scfdie();
7869 
7870 		scf_iter_destroy(eiter);
7871 	} else
7872 		err = 1;
7873 
7874 	if (err) {
7875 		xmlFreeNode(n);
7876 
7877 		export_pg(pg, eelts, 0);
7878 
7879 		return;
7880 	}
7881 
7882 	/* Iterate through the properties & handle each. */
7883 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
7884 		scfdie();
7885 
7886 	(void) memset(&elts, 0, sizeof (elts));
7887 
7888 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
7889 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
7890 			scfdie();
7891 
7892 		if (strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
7893 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
7894 		    strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
7895 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
7896 			continue;
7897 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
7898 			xmlNodePtr m;
7899 
7900 			m = xmlNewNode(NULL, (xmlChar *)"stability");
7901 			if (m == NULL)
7902 				uu_die(emsg_create_xml);
7903 
7904 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
7905 				elts.stability = m;
7906 				continue;
7907 			}
7908 
7909 			xmlFreeNode(m);
7910 		}
7911 
7912 		export_property(exp_prop, exp_str, &elts, 0);
7913 	}
7914 	if (ret == -1)
7915 		scfdie();
7916 
7917 	(void) xmlAddChild(n, elts.stability);
7918 	(void) xmlAddChildList(n, elts.propvals);
7919 	(void) xmlAddChildList(n, elts.properties);
7920 
7921 	if (eelts->dependencies == NULL)
7922 		eelts->dependencies = n;
7923 	else
7924 		(void) xmlAddSibling(eelts->dependencies, n);
7925 }
7926 
7927 static xmlNodePtr
7928 export_method_environment(scf_propertygroup_t *pg)
7929 {
7930 	xmlNodePtr env;
7931 	int ret;
7932 	int children = 0;
7933 
7934 	if (scf_pg_get_property(pg, SCF_PROPERTY_ENVIRONMENT, NULL) != 0)
7935 		return (NULL);
7936 
7937 	env = xmlNewNode(NULL, (xmlChar *)"method_environment");
7938 	if (env == NULL)
7939 		uu_die(emsg_create_xml);
7940 
7941 	if (pg_get_prop(pg, SCF_PROPERTY_ENVIRONMENT, exp_prop) != 0)
7942 		scfdie();
7943 
7944 	if (scf_iter_property_values(exp_val_iter, exp_prop) != SCF_SUCCESS)
7945 		scfdie();
7946 
7947 	while ((ret = scf_iter_next_value(exp_val_iter, exp_val)) == 1) {
7948 		xmlNodePtr ev;
7949 		char *cp;
7950 
7951 		if (scf_value_get_as_string(exp_val, exp_str, exp_str_sz) < 0)
7952 			scfdie();
7953 
7954 		if ((cp = strchr(exp_str, '=')) == NULL || cp == exp_str) {
7955 			warn(gettext("Invalid environment variable \"%s\".\n"),
7956 			    exp_str);
7957 			continue;
7958 		} else if (strncmp(exp_str, "SMF_", 4) == 0) {
7959 			warn(gettext("Invalid environment variable \"%s\"; "
7960 			    "\"SMF_\" prefix is reserved.\n"), exp_str);
7961 			continue;
7962 		}
7963 
7964 		*cp = '\0';
7965 		cp++;
7966 
7967 		ev = xmlNewChild(env, NULL, (xmlChar *)"envvar", NULL);
7968 		if (ev == NULL)
7969 			uu_die(emsg_create_xml);
7970 
7971 		safe_setprop(ev, name_attr, exp_str);
7972 		safe_setprop(ev, value_attr, cp);
7973 		children++;
7974 	}
7975 
7976 	if (ret != 0)
7977 		scfdie();
7978 
7979 	if (children == 0) {
7980 		xmlFreeNode(env);
7981 		return (NULL);
7982 	}
7983 
7984 	return (env);
7985 }
7986 
7987 /*
7988  * As above, but for a method property group.
7989  */
7990 static void
7991 export_method(scf_propertygroup_t *pg, struct entity_elts *eelts)
7992 {
7993 	xmlNodePtr n, env;
7994 	char *str;
7995 	int err = 0, nonenv, ret;
7996 	uint8_t use_profile;
7997 	struct pg_elts elts;
7998 	xmlNodePtr ctxt = NULL;
7999 
8000 	n = xmlNewNode(NULL, (xmlChar *)"exec_method");
8001 
8002 	/* Get the required attributes. */
8003 
8004 	/* name */
8005 	if (scf_pg_get_name(pg, exp_str, max_scf_name_len + 1) < 0)
8006 		scfdie();
8007 	safe_setprop(n, name_attr, exp_str);
8008 
8009 	/* type */
8010 	if (pg_get_prop(pg, SCF_PROPERTY_TYPE, exp_prop) != 0 ||
8011 	    set_attr_from_prop(exp_prop, n, type_attr) != 0)
8012 		err = 1;
8013 
8014 	/* exec */
8015 	if (pg_get_prop(pg, SCF_PROPERTY_EXEC, exp_prop) != 0 ||
8016 	    set_attr_from_prop(exp_prop, n, "exec") != 0)
8017 		err = 1;
8018 
8019 	/* timeout */
8020 	if (pg_get_prop(pg, SCF_PROPERTY_TIMEOUT, exp_prop) == 0 &&
8021 	    prop_check_type(exp_prop, SCF_TYPE_COUNT) == 0 &&
8022 	    prop_get_val(exp_prop, exp_val) == 0) {
8023 		uint64_t c;
8024 
8025 		if (scf_value_get_count(exp_val, &c) != SCF_SUCCESS)
8026 			scfdie();
8027 
8028 		str = uu_msprintf("%llu", c);
8029 		if (str == NULL)
8030 			uu_die(gettext("Could not create string"));
8031 
8032 		safe_setprop(n, "timeout_seconds", str);
8033 		free(str);
8034 	} else
8035 		err = 1;
8036 
8037 	if (err) {
8038 		xmlFreeNode(n);
8039 
8040 		export_pg(pg, eelts, 0);
8041 
8042 		return;
8043 	}
8044 
8045 
8046 	/*
8047 	 * If we're going to have a method_context child, we need to know
8048 	 * before we iterate through the properties.  Since method_context's
8049 	 * are optional, we don't want to complain about any properties
8050 	 * missing if none of them are there.  Thus we can't use the
8051 	 * convenience functions.
8052 	 */
8053 	nonenv =
8054 	    scf_pg_get_property(pg, SCF_PROPERTY_WORKING_DIRECTORY, NULL) ==
8055 	    SCF_SUCCESS ||
8056 	    scf_pg_get_property(pg, SCF_PROPERTY_PROJECT, NULL) ==
8057 	    SCF_SUCCESS ||
8058 	    scf_pg_get_property(pg, SCF_PROPERTY_RESOURCE_POOL, NULL) ==
8059 	    SCF_SUCCESS ||
8060 	    scf_pg_get_property(pg, SCF_PROPERTY_USE_PROFILE, NULL) ==
8061 	    SCF_SUCCESS;
8062 
8063 	if (nonenv) {
8064 		ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8065 		if (ctxt == NULL)
8066 			uu_die(emsg_create_xml);
8067 
8068 		if (pg_get_prop(pg, SCF_PROPERTY_WORKING_DIRECTORY, exp_prop) ==
8069 		    0 &&
8070 		    set_attr_from_prop_default(exp_prop, ctxt,
8071 		    "working_directory", ":default") != 0)
8072 			err = 1;
8073 
8074 		if (pg_get_prop(pg, SCF_PROPERTY_PROJECT, exp_prop) == 0 &&
8075 		    set_attr_from_prop_default(exp_prop, ctxt, "project",
8076 		    ":default") != 0)
8077 			err = 1;
8078 
8079 		if (pg_get_prop(pg, SCF_PROPERTY_RESOURCE_POOL, exp_prop) ==
8080 		    0 &&
8081 		    set_attr_from_prop_default(exp_prop, ctxt,
8082 		    "resource_pool", ":default") != 0)
8083 			err = 1;
8084 		/*
8085 		 * We only want to complain about profile or credential
8086 		 * properties if we will use them.  To determine that we must
8087 		 * examine USE_PROFILE.
8088 		 */
8089 		if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8090 		    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8091 		    prop_get_val(exp_prop, exp_val) == 0) {
8092 			if (scf_value_get_boolean(exp_val, &use_profile) !=
8093 			    SCF_SUCCESS) {
8094 				scfdie();
8095 			}
8096 
8097 			if (use_profile) {
8098 				xmlNodePtr prof;
8099 
8100 				prof = xmlNewChild(ctxt, NULL,
8101 				    (xmlChar *)"method_profile", NULL);
8102 				if (prof == NULL)
8103 					uu_die(emsg_create_xml);
8104 
8105 				if (pg_get_prop(pg, SCF_PROPERTY_PROFILE,
8106 				    exp_prop) != 0 ||
8107 				    set_attr_from_prop(exp_prop, prof,
8108 				    name_attr) != 0)
8109 					err = 1;
8110 			} else {
8111 				xmlNodePtr cred;
8112 
8113 				cred = xmlNewChild(ctxt, NULL,
8114 				    (xmlChar *)"method_credential", NULL);
8115 				if (cred == NULL)
8116 					uu_die(emsg_create_xml);
8117 
8118 				if (pg_get_prop(pg, SCF_PROPERTY_USER,
8119 				    exp_prop) != 0 ||
8120 				    set_attr_from_prop(exp_prop, cred,
8121 				    "user") != 0) {
8122 					err = 1;
8123 				}
8124 
8125 				if (pg_get_prop(pg, SCF_PROPERTY_GROUP,
8126 				    exp_prop) == 0 &&
8127 				    set_attr_from_prop_default(exp_prop, cred,
8128 				    "group", ":default") != 0)
8129 					err = 1;
8130 
8131 				if (pg_get_prop(pg, SCF_PROPERTY_SUPP_GROUPS,
8132 				    exp_prop) == 0 &&
8133 				    set_attr_from_prop_default(exp_prop, cred,
8134 				    "supp_groups", ":default") != 0)
8135 					err = 1;
8136 
8137 				if (pg_get_prop(pg, SCF_PROPERTY_PRIVILEGES,
8138 				    exp_prop) == 0 &&
8139 				    set_attr_from_prop_default(exp_prop, cred,
8140 				    "privileges", ":default") != 0)
8141 					err = 1;
8142 
8143 				if (pg_get_prop(pg,
8144 				    SCF_PROPERTY_LIMIT_PRIVILEGES,
8145 				    exp_prop) == 0 &&
8146 				    set_attr_from_prop_default(exp_prop, cred,
8147 				    "limit_privileges", ":default") != 0)
8148 					err = 1;
8149 			}
8150 		}
8151 	}
8152 
8153 	if ((env = export_method_environment(pg)) != NULL) {
8154 		if (ctxt == NULL) {
8155 			ctxt = xmlNewNode(NULL, (xmlChar *)"method_context");
8156 			if (ctxt == NULL)
8157 				uu_die(emsg_create_xml);
8158 		}
8159 		(void) xmlAddChild(ctxt, env);
8160 	}
8161 
8162 	if (env != NULL || (nonenv && err == 0))
8163 		(void) xmlAddChild(n, ctxt);
8164 	else
8165 		xmlFreeNode(ctxt);
8166 
8167 	nonenv = (err == 0);
8168 
8169 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8170 		scfdie();
8171 
8172 	(void) memset(&elts, 0, sizeof (elts));
8173 
8174 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8175 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8176 			scfdie();
8177 
8178 		if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0 ||
8179 		    strcmp(exp_str, SCF_PROPERTY_EXEC) == 0 ||
8180 		    strcmp(exp_str, SCF_PROPERTY_TIMEOUT) == 0) {
8181 			continue;
8182 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8183 			xmlNodePtr m;
8184 
8185 			m = xmlNewNode(NULL, (xmlChar *)"stability");
8186 			if (m == NULL)
8187 				uu_die(emsg_create_xml);
8188 
8189 			if (set_attr_from_prop(exp_prop, m, value_attr) == 0) {
8190 				elts.stability = m;
8191 				continue;
8192 			}
8193 
8194 			xmlFreeNode(m);
8195 		} else if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) ==
8196 		    0 ||
8197 		    strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0 ||
8198 		    strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0 ||
8199 		    strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8200 			if (nonenv)
8201 				continue;
8202 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0 ||
8203 		    strcmp(exp_str, SCF_PROPERTY_GROUP) == 0 ||
8204 		    strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0 ||
8205 		    strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0 ||
8206 		    strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) == 0) {
8207 			if (nonenv && !use_profile)
8208 				continue;
8209 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8210 			if (nonenv && use_profile)
8211 				continue;
8212 		} else if (strcmp(exp_str, SCF_PROPERTY_ENVIRONMENT) == 0) {
8213 			if (env != NULL)
8214 				continue;
8215 		}
8216 
8217 		export_property(exp_prop, exp_str, &elts, 0);
8218 	}
8219 	if (ret == -1)
8220 		scfdie();
8221 
8222 	(void) xmlAddChild(n, elts.stability);
8223 	(void) xmlAddChildList(n, elts.propvals);
8224 	(void) xmlAddChildList(n, elts.properties);
8225 
8226 	if (eelts->exec_methods == NULL)
8227 		eelts->exec_methods = n;
8228 	else
8229 		(void) xmlAddSibling(eelts->exec_methods, n);
8230 }
8231 
8232 static void
8233 export_pg_elts(struct pg_elts *elts, const char *name, const char *type,
8234     struct entity_elts *eelts)
8235 {
8236 	xmlNodePtr pgnode;
8237 
8238 	pgnode = xmlNewNode(NULL, (xmlChar *)"property_group");
8239 	if (pgnode == NULL)
8240 		uu_die(emsg_create_xml);
8241 
8242 	safe_setprop(pgnode, name_attr, name);
8243 	safe_setprop(pgnode, type_attr, type);
8244 
8245 	(void) xmlAddChildList(pgnode, elts->propvals);
8246 	(void) xmlAddChildList(pgnode, elts->properties);
8247 
8248 	if (eelts->property_groups == NULL)
8249 		eelts->property_groups = pgnode;
8250 	else
8251 		(void) xmlAddSibling(eelts->property_groups, pgnode);
8252 }
8253 
8254 /*
8255  * Process the general property group for a service.  This is the one with the
8256  * goodies.
8257  */
8258 static void
8259 export_svc_general(scf_propertygroup_t *pg, struct entity_elts *selts)
8260 {
8261 	struct pg_elts elts;
8262 	int ret;
8263 
8264 	/*
8265 	 * In case there are properties which don't correspond to child
8266 	 * entities of the service entity, we'll set up a pg_elts structure to
8267 	 * put them in.
8268 	 */
8269 	(void) memset(&elts, 0, sizeof (elts));
8270 
8271 	/* Walk the properties, looking for special ones. */
8272 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8273 		scfdie();
8274 
8275 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8276 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8277 			scfdie();
8278 
8279 		if (strcmp(exp_str, SCF_PROPERTY_SINGLE_INSTANCE) == 0) {
8280 			if (prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8281 			    prop_get_val(exp_prop, exp_val) == 0) {
8282 				uint8_t b;
8283 
8284 				if (scf_value_get_boolean(exp_val, &b) !=
8285 				    SCF_SUCCESS)
8286 					scfdie();
8287 
8288 				if (b) {
8289 					selts->single_instance =
8290 					    xmlNewNode(NULL,
8291 					    (xmlChar *)"single_instance");
8292 					if (selts->single_instance == NULL)
8293 						uu_die(emsg_create_xml);
8294 				}
8295 
8296 				continue;
8297 			}
8298 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8299 			xmlNodePtr rnode, sfnode;
8300 
8301 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8302 			if (rnode == NULL)
8303 				uu_die(emsg_create_xml);
8304 
8305 			sfnode = xmlNewChild(rnode, NULL,
8306 			    (xmlChar *)"service_fmri", NULL);
8307 			if (sfnode == NULL)
8308 				uu_die(emsg_create_xml);
8309 
8310 			if (set_attr_from_prop(exp_prop, sfnode,
8311 			    value_attr) == 0) {
8312 				selts->restarter = rnode;
8313 				continue;
8314 			}
8315 
8316 			xmlFreeNode(rnode);
8317 		} else if (strcmp(exp_str, SCF_PROPERTY_ENTITY_STABILITY) ==
8318 		    0) {
8319 			xmlNodePtr s;
8320 
8321 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8322 			if (s == NULL)
8323 				uu_die(emsg_create_xml);
8324 
8325 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8326 				selts->stability = s;
8327 				continue;
8328 			}
8329 
8330 			xmlFreeNode(s);
8331 		}
8332 
8333 		export_property(exp_prop, exp_str, &elts, 0);
8334 	}
8335 	if (ret == -1)
8336 		scfdie();
8337 
8338 	if (elts.propvals != NULL || elts.properties != NULL)
8339 		export_pg_elts(&elts, scf_pg_general, scf_group_framework,
8340 		    selts);
8341 }
8342 
8343 static void
8344 export_method_context(scf_propertygroup_t *pg, struct entity_elts *elts)
8345 {
8346 	xmlNodePtr n, prof, cred, env;
8347 	uint8_t use_profile;
8348 	int ret, err = 0;
8349 
8350 	n = xmlNewNode(NULL, (xmlChar *)"method_context");
8351 
8352 	env = export_method_environment(pg);
8353 
8354 	/* Need to know whether we'll use a profile or not. */
8355 	if (pg_get_prop(pg, SCF_PROPERTY_USE_PROFILE, exp_prop) == 0 &&
8356 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8357 	    prop_get_val(exp_prop, exp_val) == 0) {
8358 		if (scf_value_get_boolean(exp_val, &use_profile) != SCF_SUCCESS)
8359 			scfdie();
8360 
8361 		if (use_profile)
8362 			prof =
8363 			    xmlNewChild(n, NULL, (xmlChar *)"method_profile",
8364 			    NULL);
8365 		else
8366 			cred =
8367 			    xmlNewChild(n, NULL, (xmlChar *)"method_credential",
8368 			    NULL);
8369 	}
8370 
8371 	if (env != NULL)
8372 		(void) xmlAddChild(n, env);
8373 
8374 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8375 		scfdie();
8376 
8377 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8378 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8379 			scfdie();
8380 
8381 		if (strcmp(exp_str, SCF_PROPERTY_WORKING_DIRECTORY) == 0) {
8382 			if (set_attr_from_prop(exp_prop, n,
8383 			    "working_directory") != 0)
8384 				err = 1;
8385 		} else if (strcmp(exp_str, SCF_PROPERTY_PROJECT) == 0) {
8386 			if (set_attr_from_prop(exp_prop, n, "project") != 0)
8387 				err = 1;
8388 		} else if (strcmp(exp_str, SCF_PROPERTY_RESOURCE_POOL) == 0) {
8389 			if (set_attr_from_prop(exp_prop, n,
8390 			    "resource_pool") != 0)
8391 				err = 1;
8392 		} else if (strcmp(exp_str, SCF_PROPERTY_USE_PROFILE) == 0) {
8393 			/* EMPTY */
8394 		} else if (strcmp(exp_str, SCF_PROPERTY_USER) == 0) {
8395 			if (use_profile ||
8396 			    set_attr_from_prop(exp_prop, cred, "user") != 0)
8397 				err = 1;
8398 		} else if (strcmp(exp_str, SCF_PROPERTY_GROUP) == 0) {
8399 			if (use_profile ||
8400 			    set_attr_from_prop(exp_prop, cred, "group") != 0)
8401 				err = 1;
8402 		} else if (strcmp(exp_str, SCF_PROPERTY_SUPP_GROUPS) == 0) {
8403 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8404 			    "supp_groups") != 0)
8405 				err = 1;
8406 		} else if (strcmp(exp_str, SCF_PROPERTY_PRIVILEGES) == 0) {
8407 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8408 			    "privileges") != 0)
8409 				err = 1;
8410 		} else if (strcmp(exp_str, SCF_PROPERTY_LIMIT_PRIVILEGES) ==
8411 		    0) {
8412 			if (use_profile || set_attr_from_prop(exp_prop, cred,
8413 			    "limit_privileges") != 0)
8414 				err = 1;
8415 		} else if (strcmp(exp_str, SCF_PROPERTY_PROFILE) == 0) {
8416 			if (!use_profile || set_attr_from_prop(exp_prop,
8417 			    prof, name_attr) != 0)
8418 				err = 1;
8419 		} else {
8420 			/* Can't have generic properties in method_context's */
8421 			err = 1;
8422 		}
8423 	}
8424 	if (ret == -1)
8425 		scfdie();
8426 
8427 	if (err && env == NULL) {
8428 		xmlFreeNode(n);
8429 		export_pg(pg, elts, 0);
8430 		return;
8431 	}
8432 
8433 	elts->method_context = n;
8434 }
8435 
8436 /*
8437  * Given a dependency property group in the tfmri entity (target fmri), return
8438  * a dependent element which represents it.
8439  */
8440 static xmlNodePtr
8441 export_dependent(scf_propertygroup_t *pg, const char *name, const char *tfmri)
8442 {
8443 	uint8_t b;
8444 	xmlNodePtr n, sf;
8445 	int err = 0, ret;
8446 	struct pg_elts pgelts;
8447 
8448 	/*
8449 	 * If external isn't set to true then exporting the service will
8450 	 * export this as a normal dependency, so we should stop to avoid
8451 	 * duplication.
8452 	 */
8453 	if (scf_pg_get_property(pg, scf_property_external, exp_prop) != 0 ||
8454 	    scf_property_get_value(exp_prop, exp_val) != 0 ||
8455 	    scf_value_get_boolean(exp_val, &b) != 0 || !b) {
8456 		if (g_verbose) {
8457 			warn(gettext("Dependent \"%s\" cannot be exported "
8458 			    "properly because the \"%s\" property of the "
8459 			    "\"%s\" dependency of %s is not set to true.\n"),
8460 			    name, scf_property_external, name, tfmri);
8461 		}
8462 
8463 		return (NULL);
8464 	}
8465 
8466 	n = xmlNewNode(NULL, (xmlChar *)"dependent");
8467 	if (n == NULL)
8468 		uu_die(emsg_create_xml);
8469 
8470 	safe_setprop(n, name_attr, name);
8471 
8472 	/* Get the required attributes */
8473 	if (pg_get_prop(pg, SCF_PROPERTY_RESTART_ON, exp_prop) != 0 ||
8474 	    set_attr_from_prop(exp_prop, n, "restart_on") != 0)
8475 		err = 1;
8476 
8477 	if (pg_get_prop(pg, SCF_PROPERTY_GROUPING, exp_prop) != 0 ||
8478 	    set_attr_from_prop(exp_prop, n, "grouping") != 0)
8479 		err = 1;
8480 
8481 	if (pg_get_prop(pg, SCF_PROPERTY_ENTITIES, exp_prop) == 0 &&
8482 	    prop_check_type(exp_prop, SCF_TYPE_FMRI) == 0 &&
8483 	    prop_get_val(exp_prop, exp_val) == 0) {
8484 		/* EMPTY */
8485 	} else
8486 		err = 1;
8487 
8488 	if (err) {
8489 		xmlFreeNode(n);
8490 		return (NULL);
8491 	}
8492 
8493 	sf = xmlNewChild(n, NULL, (xmlChar *)"service_fmri", NULL);
8494 	if (sf == NULL)
8495 		uu_die(emsg_create_xml);
8496 
8497 	safe_setprop(sf, value_attr, tfmri);
8498 
8499 	/*
8500 	 * Now add elements for the other properties.
8501 	 */
8502 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8503 		scfdie();
8504 
8505 	(void) memset(&pgelts, 0, sizeof (pgelts));
8506 
8507 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8508 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8509 			scfdie();
8510 
8511 		if (strcmp(exp_str, scf_property_external) == 0 ||
8512 		    strcmp(exp_str, SCF_PROPERTY_RESTART_ON) == 0 ||
8513 		    strcmp(exp_str, SCF_PROPERTY_GROUPING) == 0 ||
8514 		    strcmp(exp_str, SCF_PROPERTY_ENTITIES) == 0) {
8515 			continue;
8516 		} else if (strcmp(exp_str, SCF_PROPERTY_TYPE) == 0) {
8517 			if (prop_check_type(exp_prop, SCF_TYPE_ASTRING) == 0 &&
8518 			    prop_get_val(exp_prop, exp_val) == 0) {
8519 				char type[sizeof ("service") + 1];
8520 
8521 				if (scf_value_get_astring(exp_val, type,
8522 				    sizeof (type)) < 0)
8523 					scfdie();
8524 
8525 				if (strcmp(type, "service") == 0)
8526 					continue;
8527 			}
8528 		} else if (strcmp(exp_str, SCF_PROPERTY_STABILITY) == 0) {
8529 			xmlNodePtr s;
8530 
8531 			s = xmlNewNode(NULL, (xmlChar *)"stability");
8532 			if (s == NULL)
8533 				uu_die(emsg_create_xml);
8534 
8535 			if (set_attr_from_prop(exp_prop, s, value_attr) == 0) {
8536 				pgelts.stability = s;
8537 				continue;
8538 			}
8539 
8540 			xmlFreeNode(s);
8541 		}
8542 
8543 		export_property(exp_prop, exp_str, &pgelts, 0);
8544 	}
8545 	if (ret == -1)
8546 		scfdie();
8547 
8548 	(void) xmlAddChild(n, pgelts.stability);
8549 	(void) xmlAddChildList(n, pgelts.propvals);
8550 	(void) xmlAddChildList(n, pgelts.properties);
8551 
8552 	return (n);
8553 }
8554 
8555 static void
8556 export_dependents(scf_propertygroup_t *pg, struct entity_elts *eelts)
8557 {
8558 	scf_propertygroup_t *opg;
8559 	scf_iter_t *iter;
8560 	char *type, *fmri;
8561 	int ret;
8562 	struct pg_elts pgelts;
8563 	xmlNodePtr n;
8564 	scf_error_t serr;
8565 
8566 	if ((opg = scf_pg_create(g_hndl)) == NULL ||
8567 	    (iter = scf_iter_create(g_hndl)) == NULL)
8568 		scfdie();
8569 
8570 	/* Can't use exp_prop_iter due to export_dependent(). */
8571 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
8572 		scfdie();
8573 
8574 	type = safe_malloc(max_scf_pg_type_len + 1);
8575 
8576 	/* Get an extra byte so we can tell if values are too long. */
8577 	fmri = safe_malloc(max_scf_fmri_len + 2);
8578 
8579 	(void) memset(&pgelts, 0, sizeof (pgelts));
8580 
8581 	while ((ret = scf_iter_next_property(iter, exp_prop)) == 1) {
8582 		void *entity;
8583 		int isservice;
8584 		scf_type_t ty;
8585 
8586 		if (scf_property_type(exp_prop, &ty) != SCF_SUCCESS)
8587 			scfdie();
8588 
8589 		if ((ty != SCF_TYPE_ASTRING &&
8590 		    prop_check_type(exp_prop, SCF_TYPE_FMRI) != 0) ||
8591 		    prop_get_val(exp_prop, exp_val) != 0) {
8592 			export_property(exp_prop, NULL, &pgelts, 0);
8593 			continue;
8594 		}
8595 
8596 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8597 			scfdie();
8598 
8599 		if (scf_value_get_astring(exp_val, fmri,
8600 		    max_scf_fmri_len + 2) < 0)
8601 			scfdie();
8602 
8603 		/* Look for a dependency group in the target fmri. */
8604 		serr = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
8605 		switch (serr) {
8606 		case SCF_ERROR_NONE:
8607 			break;
8608 
8609 		case SCF_ERROR_NO_MEMORY:
8610 			uu_die(gettext("Out of memory.\n"));
8611 			/* NOTREACHED */
8612 
8613 		case SCF_ERROR_INVALID_ARGUMENT:
8614 			if (g_verbose) {
8615 				if (scf_property_to_fmri(exp_prop, fmri,
8616 				    max_scf_fmri_len + 2) < 0)
8617 					scfdie();
8618 
8619 				warn(gettext("The value of %s is not a valid "
8620 				    "FMRI.\n"), fmri);
8621 			}
8622 
8623 			export_property(exp_prop, exp_str, &pgelts, 0);
8624 			continue;
8625 
8626 		case SCF_ERROR_CONSTRAINT_VIOLATED:
8627 			if (g_verbose) {
8628 				if (scf_property_to_fmri(exp_prop, fmri,
8629 				    max_scf_fmri_len + 2) < 0)
8630 					scfdie();
8631 
8632 				warn(gettext("The value of %s does not specify "
8633 				    "a service or an instance.\n"), fmri);
8634 			}
8635 
8636 			export_property(exp_prop, exp_str, &pgelts, 0);
8637 			continue;
8638 
8639 		case SCF_ERROR_NOT_FOUND:
8640 			if (g_verbose) {
8641 				if (scf_property_to_fmri(exp_prop, fmri,
8642 				    max_scf_fmri_len + 2) < 0)
8643 					scfdie();
8644 
8645 				warn(gettext("The entity specified by %s does "
8646 				    "not exist.\n"), fmri);
8647 			}
8648 
8649 			export_property(exp_prop, exp_str, &pgelts, 0);
8650 			continue;
8651 
8652 		default:
8653 #ifndef NDEBUG
8654 			(void) fprintf(stderr, "%s:%d: %s() failed with "
8655 			    "unexpected error %d.\n", __FILE__, __LINE__,
8656 			    "fmri_to_entity", serr);
8657 #endif
8658 			abort();
8659 		}
8660 
8661 		if (entity_get_pg(entity, isservice, exp_str, opg) != 0) {
8662 			if (scf_error() != SCF_ERROR_NOT_FOUND)
8663 				scfdie();
8664 
8665 			warn(gettext("Entity %s is missing dependency property "
8666 			    "group %s.\n"), fmri, exp_str);
8667 
8668 			export_property(exp_prop, NULL, &pgelts, 0);
8669 			continue;
8670 		}
8671 
8672 		if (scf_pg_get_type(opg, type, max_scf_pg_type_len + 1) < 0)
8673 			scfdie();
8674 
8675 		if (strcmp(type, SCF_GROUP_DEPENDENCY) != 0) {
8676 			if (scf_pg_to_fmri(opg, fmri, max_scf_fmri_len + 2) < 0)
8677 				scfdie();
8678 
8679 			warn(gettext("Property group %s is not of "
8680 			    "expected type %s.\n"), fmri, SCF_GROUP_DEPENDENCY);
8681 
8682 			export_property(exp_prop, NULL, &pgelts, 0);
8683 			continue;
8684 		}
8685 
8686 		n = export_dependent(opg, exp_str, fmri);
8687 		if (n == NULL)
8688 			export_property(exp_prop, exp_str, &pgelts, 0);
8689 		else {
8690 			if (eelts->dependents == NULL)
8691 				eelts->dependents = n;
8692 			else
8693 				(void) xmlAddSibling(eelts->dependents,
8694 				    n);
8695 		}
8696 	}
8697 	if (ret == -1)
8698 		scfdie();
8699 
8700 	free(fmri);
8701 	free(type);
8702 
8703 	scf_iter_destroy(iter);
8704 	scf_pg_destroy(opg);
8705 
8706 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
8707 		export_pg_elts(&pgelts, SCF_PG_DEPENDENTS, scf_group_framework,
8708 		    eelts);
8709 }
8710 
8711 static void
8712 make_node(xmlNodePtr *nodep, const char *name)
8713 {
8714 	if (*nodep == NULL) {
8715 		*nodep = xmlNewNode(NULL, (xmlChar *)name);
8716 		if (*nodep == NULL)
8717 			uu_die(emsg_create_xml);
8718 	}
8719 }
8720 
8721 static xmlNodePtr
8722 export_tm_loctext(scf_propertygroup_t *pg, const char *parname)
8723 {
8724 	int ret;
8725 	xmlNodePtr parent = NULL;
8726 	xmlNodePtr loctext = NULL;
8727 
8728 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8729 		scfdie();
8730 
8731 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8732 		if (prop_check_type(exp_prop, SCF_TYPE_USTRING) != 0 ||
8733 		    prop_get_val(exp_prop, exp_val) != 0)
8734 			continue;
8735 
8736 		if (scf_value_get_ustring(exp_val, exp_str, exp_str_sz) < 0)
8737 			scfdie();
8738 
8739 		make_node(&parent, parname);
8740 		loctext = xmlNewTextChild(parent, NULL, (xmlChar *)"loctext",
8741 		    (xmlChar *)exp_str);
8742 		if (loctext == NULL)
8743 			uu_die(emsg_create_xml);
8744 
8745 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8746 			scfdie();
8747 
8748 		safe_setprop(loctext, "xml:lang", exp_str);
8749 	}
8750 
8751 	if (ret == -1)
8752 		scfdie();
8753 
8754 	return (parent);
8755 }
8756 
8757 static xmlNodePtr
8758 export_tm_manpage(scf_propertygroup_t *pg)
8759 {
8760 	xmlNodePtr manpage = xmlNewNode(NULL, (xmlChar *)"manpage");
8761 	if (manpage == NULL)
8762 		uu_die(emsg_create_xml);
8763 
8764 	if (pg_get_prop(pg, SCF_PROPERTY_TM_TITLE, exp_prop) != 0 ||
8765 	    set_attr_from_prop(exp_prop, manpage, "title") != 0 ||
8766 	    pg_get_prop(pg, SCF_PROPERTY_TM_SECTION, exp_prop) != 0 ||
8767 	    set_attr_from_prop(exp_prop, manpage, "section") != 0) {
8768 		xmlFreeNode(manpage);
8769 		return (NULL);
8770 	}
8771 
8772 	if (pg_get_prop(pg, SCF_PROPERTY_TM_MANPATH, exp_prop) == 0)
8773 		(void) set_attr_from_prop_default(exp_prop,
8774 		    manpage, "manpath", ":default");
8775 
8776 	return (manpage);
8777 }
8778 
8779 static xmlNodePtr
8780 export_tm_doc_link(scf_propertygroup_t *pg)
8781 {
8782 	xmlNodePtr doc_link = xmlNewNode(NULL, (xmlChar *)"doc_link");
8783 	if (doc_link == NULL)
8784 		uu_die(emsg_create_xml);
8785 
8786 	if (pg_get_prop(pg, SCF_PROPERTY_TM_NAME, exp_prop) != 0 ||
8787 	    set_attr_from_prop(exp_prop, doc_link, "name") != 0 ||
8788 	    pg_get_prop(pg, SCF_PROPERTY_TM_URI, exp_prop) != 0 ||
8789 	    set_attr_from_prop(exp_prop, doc_link, "uri") != 0) {
8790 		xmlFreeNode(doc_link);
8791 		return (NULL);
8792 	}
8793 	return (doc_link);
8794 }
8795 
8796 /*
8797  * Process template information for a service or instances.
8798  */
8799 static void
8800 export_template(scf_propertygroup_t *pg, struct entity_elts *elts,
8801     struct template_elts *telts)
8802 {
8803 	size_t mansz = strlen(SCF_PG_TM_MAN_PREFIX);
8804 	size_t docsz = strlen(SCF_PG_TM_DOC_PREFIX);
8805 	xmlNodePtr child = NULL;
8806 
8807 	if (scf_pg_get_name(pg, exp_str, exp_str_sz) < 0)
8808 		scfdie();
8809 
8810 	if (strcmp(exp_str, SCF_PG_TM_COMMON_NAME) == 0) {
8811 		telts->common_name = export_tm_loctext(pg, "common_name");
8812 		if (telts->common_name == NULL)
8813 			export_pg(pg, elts, 0);
8814 		return;
8815 	} else if (strcmp(exp_str, SCF_PG_TM_DESCRIPTION) == 0) {
8816 		telts->description = export_tm_loctext(pg, "description");
8817 		if (telts->description == NULL)
8818 			export_pg(pg, elts, 0);
8819 		return;
8820 	}
8821 
8822 	if (strncmp(exp_str, SCF_PG_TM_MAN_PREFIX, mansz) == 0) {
8823 		child = export_tm_manpage(pg);
8824 	} else if (strncmp(exp_str, SCF_PG_TM_DOC_PREFIX, docsz) == 0) {
8825 		child = export_tm_doc_link(pg);
8826 	}
8827 
8828 	if (child != NULL) {
8829 		make_node(&telts->documentation, "documentation");
8830 		(void) xmlAddChild(telts->documentation, child);
8831 	} else {
8832 		export_pg(pg, elts, 0);
8833 	}
8834 }
8835 
8836 /*
8837  * Process the general property group for an instance.
8838  */
8839 static void
8840 export_inst_general(scf_propertygroup_t *pg, xmlNodePtr inode,
8841     struct entity_elts *elts)
8842 {
8843 	uint8_t enabled;
8844 	struct pg_elts pgelts;
8845 	int ret;
8846 
8847 	/* enabled */
8848 	if (pg_get_prop(pg, scf_property_enabled, exp_prop) == 0 &&
8849 	    prop_check_type(exp_prop, SCF_TYPE_BOOLEAN) == 0 &&
8850 	    prop_get_val(exp_prop, exp_val) == 0) {
8851 		if (scf_value_get_boolean(exp_val, &enabled) != SCF_SUCCESS)
8852 			scfdie();
8853 	} else {
8854 		enabled = 0;
8855 	}
8856 
8857 	safe_setprop(inode, enabled_attr, enabled ? true : false);
8858 
8859 	if (scf_iter_pg_properties(exp_prop_iter, pg) != SCF_SUCCESS)
8860 		scfdie();
8861 
8862 	(void) memset(&pgelts, 0, sizeof (pgelts));
8863 
8864 	while ((ret = scf_iter_next_property(exp_prop_iter, exp_prop)) == 1) {
8865 		if (scf_property_get_name(exp_prop, exp_str, exp_str_sz) < 0)
8866 			scfdie();
8867 
8868 		if (strcmp(exp_str, scf_property_enabled) == 0) {
8869 			continue;
8870 		} else if (strcmp(exp_str, SCF_PROPERTY_RESTARTER) == 0) {
8871 			xmlNodePtr rnode, sfnode;
8872 
8873 			rnode = xmlNewNode(NULL, (xmlChar *)"restarter");
8874 			if (rnode == NULL)
8875 				uu_die(emsg_create_xml);
8876 
8877 			sfnode = xmlNewChild(rnode, NULL,
8878 			    (xmlChar *)"service_fmri", NULL);
8879 			if (sfnode == NULL)
8880 				uu_die(emsg_create_xml);
8881 
8882 			if (set_attr_from_prop(exp_prop, sfnode,
8883 			    value_attr) == 0) {
8884 				elts->restarter = rnode;
8885 				continue;
8886 			}
8887 
8888 			xmlFreeNode(rnode);
8889 		}
8890 
8891 		export_property(exp_prop, exp_str, &pgelts, 0);
8892 	}
8893 	if (ret == -1)
8894 		scfdie();
8895 
8896 	if (pgelts.propvals != NULL || pgelts.properties != NULL)
8897 		export_pg_elts(&pgelts, scf_pg_general, scf_group_framework,
8898 		    elts);
8899 }
8900 
8901 /*
8902  * Put an instance element for the given instance into selts.
8903  */
8904 static void
8905 export_instance(scf_instance_t *inst, struct entity_elts *selts, int flags)
8906 {
8907 	xmlNodePtr n;
8908 	boolean_t isdefault;
8909 	struct entity_elts elts;
8910 	struct template_elts template_elts;
8911 	int ret;
8912 
8913 	n = xmlNewNode(NULL, (xmlChar *)"instance");
8914 	if (n == NULL)
8915 		uu_die(emsg_create_xml);
8916 
8917 	/* name */
8918 	if (scf_instance_get_name(inst, exp_str, exp_str_sz) < 0)
8919 		scfdie();
8920 	safe_setprop(n, name_attr, exp_str);
8921 	isdefault = strcmp(exp_str, "default") == 0;
8922 
8923 	/* check existance of general pg (since general/enabled is required) */
8924 	if (scf_instance_get_pg(inst, scf_pg_general, exp_pg) != SCF_SUCCESS) {
8925 		if (scf_error() != SCF_ERROR_NOT_FOUND)
8926 			scfdie();
8927 
8928 		if (g_verbose) {
8929 			if (scf_instance_to_fmri(inst, exp_str, exp_str_sz) < 0)
8930 				scfdie();
8931 
8932 			warn(gettext("Instance %s has no general property "
8933 			    "group; it will be marked disabled.\n"), exp_str);
8934 		}
8935 
8936 		safe_setprop(n, enabled_attr, false);
8937 	} else if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0 ||
8938 	    strcmp(exp_str, scf_group_framework) != 0) {
8939 		if (g_verbose) {
8940 			if (scf_pg_to_fmri(exp_pg, exp_str, exp_str_sz) < 0)
8941 				scfdie();
8942 
8943 			warn(gettext("Property group %s is not of type "
8944 			    "framework; the instance will be marked "
8945 			    "disabled.\n"), exp_str);
8946 		}
8947 
8948 		safe_setprop(n, enabled_attr, false);
8949 	}
8950 
8951 	/* property groups */
8952 	if (scf_iter_instance_pgs(exp_pg_iter, inst) < 0)
8953 		scfdie();
8954 
8955 	(void) memset(&elts, 0, sizeof (elts));
8956 	(void) memset(&template_elts, 0, sizeof (template_elts));
8957 
8958 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
8959 		uint32_t pgflags;
8960 
8961 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
8962 			scfdie();
8963 
8964 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
8965 			continue;
8966 
8967 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
8968 			scfdie();
8969 
8970 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
8971 			export_dependency(exp_pg, &elts);
8972 			continue;
8973 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
8974 			export_method(exp_pg, &elts);
8975 			continue;
8976 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
8977 			if (scf_pg_get_name(exp_pg, exp_str,
8978 			    max_scf_name_len + 1) < 0)
8979 				scfdie();
8980 
8981 			if (strcmp(exp_str, scf_pg_general) == 0) {
8982 				export_inst_general(exp_pg, n, &elts);
8983 				continue;
8984 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
8985 			    0) {
8986 				export_method_context(exp_pg, &elts);
8987 				continue;
8988 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
8989 				export_dependents(exp_pg, &elts);
8990 				continue;
8991 			}
8992 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
8993 			export_template(exp_pg, &elts, &template_elts);
8994 			continue;
8995 		}
8996 
8997 		/* Ordinary pg. */
8998 		export_pg(exp_pg, &elts, flags);
8999 	}
9000 	if (ret == -1)
9001 		scfdie();
9002 
9003 	if (template_elts.common_name != NULL) {
9004 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9005 		(void) xmlAddChild(elts.template, template_elts.common_name);
9006 		(void) xmlAddChild(elts.template, template_elts.description);
9007 		(void) xmlAddChild(elts.template, template_elts.documentation);
9008 	} else {
9009 		xmlFreeNode(template_elts.description);
9010 		xmlFreeNode(template_elts.documentation);
9011 	}
9012 
9013 	if (isdefault && elts.restarter == NULL &&
9014 	    elts.dependencies == NULL && elts.method_context == NULL &&
9015 	    elts.exec_methods == NULL && elts.property_groups == NULL &&
9016 	    elts.template == NULL) {
9017 		xmlChar *eval;
9018 
9019 		/* This is a default instance */
9020 		eval = xmlGetProp(n, (xmlChar *)enabled_attr);
9021 
9022 		xmlFreeNode(n);
9023 
9024 		n = xmlNewNode(NULL, (xmlChar *)"create_default_instance");
9025 		if (n == NULL)
9026 			uu_die(emsg_create_xml);
9027 
9028 		safe_setprop(n, enabled_attr, (char *)eval);
9029 		xmlFree(eval);
9030 
9031 		selts->create_default_instance = n;
9032 	} else {
9033 		/* Assemble the children in order. */
9034 		(void) xmlAddChild(n, elts.restarter);
9035 		(void) xmlAddChildList(n, elts.dependencies);
9036 		(void) xmlAddChildList(n, elts.dependents);
9037 		(void) xmlAddChild(n, elts.method_context);
9038 		(void) xmlAddChildList(n, elts.exec_methods);
9039 		(void) xmlAddChildList(n, elts.property_groups);
9040 		(void) xmlAddChild(n, elts.template);
9041 
9042 		if (selts->instances == NULL)
9043 			selts->instances = n;
9044 		else
9045 			(void) xmlAddSibling(selts->instances, n);
9046 	}
9047 }
9048 
9049 /*
9050  * Return a service element for the given service.
9051  */
9052 static xmlNodePtr
9053 export_service(scf_service_t *svc, int flags)
9054 {
9055 	xmlNodePtr snode;
9056 	struct entity_elts elts;
9057 	struct template_elts template_elts;
9058 	int ret;
9059 
9060 	snode = xmlNewNode(NULL, (xmlChar *)"service");
9061 	if (snode == NULL)
9062 		uu_die(emsg_create_xml);
9063 
9064 	/* Get & set name attribute */
9065 	if (scf_service_get_name(svc, exp_str, max_scf_name_len + 1) < 0)
9066 		scfdie();
9067 	safe_setprop(snode, name_attr, exp_str);
9068 
9069 	safe_setprop(snode, type_attr, "service");
9070 	safe_setprop(snode, "version", "0");
9071 
9072 	/* Acquire child elements. */
9073 	if (scf_iter_service_pgs(exp_pg_iter, svc) != SCF_SUCCESS)
9074 		scfdie();
9075 
9076 	(void) memset(&elts, 0, sizeof (elts));
9077 	(void) memset(&template_elts, 0, sizeof (template_elts));
9078 
9079 	while ((ret = scf_iter_next_pg(exp_pg_iter, exp_pg)) == 1) {
9080 		uint32_t pgflags;
9081 
9082 		if (scf_pg_get_flags(exp_pg, &pgflags) != 0)
9083 			scfdie();
9084 
9085 		if (pgflags & SCF_PG_FLAG_NONPERSISTENT)
9086 			continue;
9087 
9088 		if (scf_pg_get_type(exp_pg, exp_str, exp_str_sz) < 0)
9089 			scfdie();
9090 
9091 		if (strcmp(exp_str, SCF_GROUP_DEPENDENCY) == 0) {
9092 			export_dependency(exp_pg, &elts);
9093 			continue;
9094 		} else if (strcmp(exp_str, SCF_GROUP_METHOD) == 0) {
9095 			export_method(exp_pg, &elts);
9096 			continue;
9097 		} else if (strcmp(exp_str, scf_group_framework) == 0) {
9098 			if (scf_pg_get_name(exp_pg, exp_str,
9099 			    max_scf_name_len + 1) < 0)
9100 				scfdie();
9101 
9102 			if (strcmp(exp_str, scf_pg_general) == 0) {
9103 				export_svc_general(exp_pg, &elts);
9104 				continue;
9105 			} else if (strcmp(exp_str, SCF_PG_METHOD_CONTEXT) ==
9106 			    0) {
9107 				export_method_context(exp_pg, &elts);
9108 				continue;
9109 			} else if (strcmp(exp_str, SCF_PG_DEPENDENTS) == 0) {
9110 				export_dependents(exp_pg, &elts);
9111 				continue;
9112 			}
9113 		} else if (strcmp(exp_str, SCF_GROUP_TEMPLATE) == 0) {
9114 			export_template(exp_pg, &elts, &template_elts);
9115 			continue;
9116 		}
9117 
9118 		export_pg(exp_pg, &elts, flags);
9119 	}
9120 	if (ret == -1)
9121 		scfdie();
9122 
9123 	if (template_elts.common_name != NULL) {
9124 		elts.template = xmlNewNode(NULL, (xmlChar *)"template");
9125 		(void) xmlAddChild(elts.template, template_elts.common_name);
9126 		(void) xmlAddChild(elts.template, template_elts.description);
9127 		(void) xmlAddChild(elts.template, template_elts.documentation);
9128 	} else {
9129 		xmlFreeNode(template_elts.description);
9130 		xmlFreeNode(template_elts.documentation);
9131 	}
9132 
9133 	/* Iterate instances */
9134 	if (scf_iter_service_instances(exp_inst_iter, svc) != SCF_SUCCESS)
9135 		scfdie();
9136 
9137 	while ((ret = scf_iter_next_instance(exp_inst_iter, exp_inst)) == 1)
9138 		export_instance(exp_inst, &elts, flags);
9139 	if (ret == -1)
9140 		scfdie();
9141 
9142 	/* Now add all of the accumulated elements in order. */
9143 	(void) xmlAddChild(snode, elts.create_default_instance);
9144 	(void) xmlAddChild(snode, elts.single_instance);
9145 	(void) xmlAddChild(snode, elts.restarter);
9146 	(void) xmlAddChildList(snode, elts.dependencies);
9147 	(void) xmlAddChildList(snode, elts.dependents);
9148 	(void) xmlAddChild(snode, elts.method_context);
9149 	(void) xmlAddChildList(snode, elts.exec_methods);
9150 	(void) xmlAddChildList(snode, elts.property_groups);
9151 	(void) xmlAddChildList(snode, elts.instances);
9152 	(void) xmlAddChild(snode, elts.stability);
9153 	(void) xmlAddChild(snode, elts.template);
9154 
9155 	return (snode);
9156 }
9157 
9158 static int
9159 export_callback(void *data, scf_walkinfo_t *wip)
9160 {
9161 	FILE *f;
9162 	xmlDocPtr doc;
9163 	xmlNodePtr sb;
9164 	int result;
9165 	struct export_args *argsp = (struct export_args *)data;
9166 
9167 	if ((exp_inst = scf_instance_create(g_hndl)) == NULL ||
9168 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9169 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9170 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9171 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9172 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9173 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9174 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9175 		scfdie();
9176 
9177 	exp_str_sz = max_scf_len + 1;
9178 	exp_str = safe_malloc(exp_str_sz);
9179 
9180 	if (argsp->filename != NULL) {
9181 		errno = 0;
9182 		f = fopen(argsp->filename, "wb");
9183 		if (f == NULL) {
9184 			if (errno == 0)
9185 				uu_die(gettext("Could not open \"%s\": no free "
9186 				    "stdio streams.\n"), argsp->filename);
9187 			else
9188 				uu_die(gettext("Could not open \"%s\""),
9189 				    argsp->filename);
9190 		}
9191 	} else
9192 		f = stdout;
9193 
9194 	doc = xmlNewDoc((xmlChar *)"1.0");
9195 	if (doc == NULL)
9196 		uu_die(gettext("Could not create XML document.\n"));
9197 
9198 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9199 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9200 		uu_die(emsg_create_xml);
9201 
9202 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9203 	if (sb == NULL)
9204 		uu_die(emsg_create_xml);
9205 	safe_setprop(sb, type_attr, "manifest");
9206 	safe_setprop(sb, name_attr, "export");
9207 	(void) xmlAddSibling(doc->children, sb);
9208 
9209 	(void) xmlAddChild(sb, export_service(wip->svc, argsp->flags));
9210 
9211 	result = write_service_bundle(doc, f);
9212 
9213 	free(exp_str);
9214 	scf_iter_destroy(exp_val_iter);
9215 	scf_iter_destroy(exp_prop_iter);
9216 	scf_iter_destroy(exp_pg_iter);
9217 	scf_iter_destroy(exp_inst_iter);
9218 	scf_value_destroy(exp_val);
9219 	scf_property_destroy(exp_prop);
9220 	scf_pg_destroy(exp_pg);
9221 	scf_instance_destroy(exp_inst);
9222 
9223 	xmlFreeDoc(doc);
9224 
9225 	if (f != stdout)
9226 		(void) fclose(f);
9227 
9228 	return (result);
9229 }
9230 
9231 /*
9232  * Get the service named by fmri, build an XML tree which represents it, and
9233  * dump it into filename (or stdout if filename is NULL).
9234  */
9235 int
9236 lscf_service_export(char *fmri, const char *filename, int flags)
9237 {
9238 	struct export_args args;
9239 	int ret, err;
9240 
9241 	lscf_prep_hndl();
9242 
9243 	bzero(&args, sizeof (args));
9244 	args.filename = filename;
9245 	args.flags = flags;
9246 
9247 	err = 0;
9248 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri,
9249 	    SCF_WALK_SERVICE | SCF_WALK_NOINSTANCE, export_callback,
9250 	    &args, &err, semerr)) != 0) {
9251 		if (ret != -1)
9252 			semerr(gettext("Failed to walk instances: %s\n"),
9253 			    scf_strerror(ret));
9254 		return (-1);
9255 	}
9256 
9257 	/*
9258 	 * Error message has already been printed.
9259 	 */
9260 	if (err != 0)
9261 		return (-1);
9262 
9263 	return (0);
9264 }
9265 
9266 
9267 /*
9268  * Archive
9269  */
9270 
9271 static xmlNodePtr
9272 make_archive(int flags)
9273 {
9274 	xmlNodePtr sb;
9275 	scf_scope_t *scope;
9276 	scf_service_t *svc;
9277 	scf_iter_t *iter;
9278 	int r;
9279 
9280 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9281 	    (svc = scf_service_create(g_hndl)) == NULL ||
9282 	    (iter = scf_iter_create(g_hndl)) == NULL ||
9283 	    (exp_inst = scf_instance_create(g_hndl)) == NULL ||
9284 	    (exp_pg = scf_pg_create(g_hndl)) == NULL ||
9285 	    (exp_prop = scf_property_create(g_hndl)) == NULL ||
9286 	    (exp_val = scf_value_create(g_hndl)) == NULL ||
9287 	    (exp_inst_iter = scf_iter_create(g_hndl)) == NULL ||
9288 	    (exp_pg_iter = scf_iter_create(g_hndl)) == NULL ||
9289 	    (exp_prop_iter = scf_iter_create(g_hndl)) == NULL ||
9290 	    (exp_val_iter = scf_iter_create(g_hndl)) == NULL)
9291 		scfdie();
9292 
9293 	exp_str_sz = max_scf_len + 1;
9294 	exp_str = safe_malloc(exp_str_sz);
9295 
9296 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9297 	if (sb == NULL)
9298 		uu_die(emsg_create_xml);
9299 	safe_setprop(sb, type_attr, "archive");
9300 	safe_setprop(sb, name_attr, "none");
9301 
9302 	if (scf_handle_get_scope(g_hndl, SCF_SCOPE_LOCAL, scope) != 0)
9303 		scfdie();
9304 	if (scf_iter_scope_services(iter, scope) != 0)
9305 		scfdie();
9306 
9307 	for (;;) {
9308 		r = scf_iter_next_service(iter, svc);
9309 		if (r == 0)
9310 			break;
9311 		if (r != 1)
9312 			scfdie();
9313 
9314 		if (scf_service_get_name(svc, exp_str,
9315 		    max_scf_name_len + 1) < 0)
9316 			scfdie();
9317 
9318 		if (strcmp(exp_str, SCF_LEGACY_SERVICE) == 0)
9319 			continue;
9320 
9321 		xmlAddChild(sb, export_service(svc, flags));
9322 	}
9323 
9324 	free(exp_str);
9325 
9326 	scf_iter_destroy(exp_val_iter);
9327 	scf_iter_destroy(exp_prop_iter);
9328 	scf_iter_destroy(exp_pg_iter);
9329 	scf_iter_destroy(exp_inst_iter);
9330 	scf_value_destroy(exp_val);
9331 	scf_property_destroy(exp_prop);
9332 	scf_pg_destroy(exp_pg);
9333 	scf_instance_destroy(exp_inst);
9334 	scf_iter_destroy(iter);
9335 	scf_service_destroy(svc);
9336 	scf_scope_destroy(scope);
9337 
9338 	return (sb);
9339 }
9340 
9341 int
9342 lscf_archive(const char *filename, int flags)
9343 {
9344 	FILE *f;
9345 	xmlDocPtr doc;
9346 	int result;
9347 
9348 	lscf_prep_hndl();
9349 
9350 	if (filename != NULL) {
9351 		errno = 0;
9352 		f = fopen(filename, "wb");
9353 		if (f == NULL) {
9354 			if (errno == 0)
9355 				uu_die(gettext("Could not open \"%s\": no free "
9356 				    "stdio streams.\n"), filename);
9357 			else
9358 				uu_die(gettext("Could not open \"%s\""),
9359 				    filename);
9360 		}
9361 	} else
9362 		f = stdout;
9363 
9364 	doc = xmlNewDoc((xmlChar *)"1.0");
9365 	if (doc == NULL)
9366 		uu_die(gettext("Could not create XML document.\n"));
9367 
9368 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9369 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9370 		uu_die(emsg_create_xml);
9371 
9372 	(void) xmlAddSibling(doc->children, make_archive(flags));
9373 
9374 	result = write_service_bundle(doc, f);
9375 
9376 	xmlFreeDoc(doc);
9377 
9378 	if (f != stdout)
9379 		(void) fclose(f);
9380 
9381 	return (result);
9382 }
9383 
9384 
9385 /*
9386  * "Extract" a profile.
9387  */
9388 int
9389 lscf_profile_extract(const char *filename)
9390 {
9391 	FILE *f;
9392 	xmlDocPtr doc;
9393 	xmlNodePtr sb, snode, inode;
9394 	scf_scope_t *scope;
9395 	scf_service_t *svc;
9396 	scf_instance_t *inst;
9397 	scf_propertygroup_t *pg;
9398 	scf_property_t *prop;
9399 	scf_value_t *val;
9400 	scf_iter_t *siter, *iiter;
9401 	int r, s;
9402 	char *namebuf;
9403 	uint8_t b;
9404 	int result;
9405 
9406 	lscf_prep_hndl();
9407 
9408 	if (filename != NULL) {
9409 		errno = 0;
9410 		f = fopen(filename, "wb");
9411 		if (f == NULL) {
9412 			if (errno == 0)
9413 				uu_die(gettext("Could not open \"%s\": no "
9414 				    "free stdio streams.\n"), filename);
9415 			else
9416 				uu_die(gettext("Could not open \"%s\""),
9417 				    filename);
9418 		}
9419 	} else
9420 		f = stdout;
9421 
9422 	doc = xmlNewDoc((xmlChar *)"1.0");
9423 	if (doc == NULL)
9424 		uu_die(gettext("Could not create XML document.\n"));
9425 
9426 	if (xmlCreateIntSubset(doc, (xmlChar *)"service_bundle", NULL,
9427 	    (xmlChar *)MANIFEST_DTD_PATH) == NULL)
9428 		uu_die(emsg_create_xml);
9429 
9430 	sb = xmlNewNode(NULL, (xmlChar *)"service_bundle");
9431 	if (sb == NULL)
9432 		uu_die(emsg_create_xml);
9433 	safe_setprop(sb, type_attr, "profile");
9434 	safe_setprop(sb, name_attr, "extract");
9435 	(void) xmlAddSibling(doc->children, sb);
9436 
9437 	if ((scope = scf_scope_create(g_hndl)) == NULL ||
9438 	    (svc = scf_service_create(g_hndl)) == NULL ||
9439 	    (inst = scf_instance_create(g_hndl)) == NULL ||
9440 	    (pg = scf_pg_create(g_hndl)) == NULL ||
9441 	    (prop = scf_property_create(g_hndl)) == NULL ||
9442 	    (val = scf_value_create(g_hndl)) == NULL ||
9443 	    (siter = scf_iter_create(g_hndl)) == NULL ||
9444 	    (iiter = scf_iter_create(g_hndl)) == NULL)
9445 		scfdie();
9446 
9447 	if (scf_handle_get_local_scope(g_hndl, scope) != SCF_SUCCESS)
9448 		scfdie();
9449 
9450 	if (scf_iter_scope_services(siter, scope) != SCF_SUCCESS)
9451 		scfdie();
9452 
9453 	namebuf = safe_malloc(max_scf_name_len + 1);
9454 
9455 	while ((r = scf_iter_next_service(siter, svc)) == 1) {
9456 		if (scf_iter_service_instances(iiter, svc) != SCF_SUCCESS)
9457 			scfdie();
9458 
9459 		snode = xmlNewNode(NULL, (xmlChar *)"service");
9460 		if (snode == NULL)
9461 			uu_die(emsg_create_xml);
9462 
9463 		if (scf_service_get_name(svc, namebuf, max_scf_name_len + 1) <
9464 		    0)
9465 			scfdie();
9466 
9467 		safe_setprop(snode, name_attr, namebuf);
9468 
9469 		safe_setprop(snode, type_attr, "service");
9470 		safe_setprop(snode, "version", "0");
9471 
9472 		while ((s = scf_iter_next_instance(iiter, inst)) == 1) {
9473 			if (scf_instance_get_pg(inst, scf_pg_general, pg) !=
9474 			    SCF_SUCCESS) {
9475 				if (scf_error() != SCF_ERROR_NOT_FOUND)
9476 					scfdie();
9477 
9478 				if (g_verbose) {
9479 					ssize_t len;
9480 					char *fmri;
9481 
9482 					len =
9483 					    scf_instance_to_fmri(inst, NULL, 0);
9484 					if (len < 0)
9485 						scfdie();
9486 
9487 					fmri = safe_malloc(len + 1);
9488 
9489 					if (scf_instance_to_fmri(inst, fmri,
9490 					    len + 1) < 0)
9491 						scfdie();
9492 
9493 					warn("Instance %s has no \"%s\" "
9494 					    "property group.\n", fmri,
9495 					    scf_pg_general);
9496 
9497 					free(fmri);
9498 				}
9499 
9500 				continue;
9501 			}
9502 
9503 			if (pg_get_prop(pg, scf_property_enabled, prop) != 0 ||
9504 			    prop_check_type(prop, SCF_TYPE_BOOLEAN) != 0 ||
9505 			    prop_get_val(prop, val) != 0)
9506 				continue;
9507 
9508 			inode = xmlNewChild(snode, NULL, (xmlChar *)"instance",
9509 			    NULL);
9510 			if (inode == NULL)
9511 				uu_die(emsg_create_xml);
9512 
9513 			if (scf_instance_get_name(inst, namebuf,
9514 			    max_scf_name_len + 1) < 0)
9515 				scfdie();
9516 
9517 			safe_setprop(inode, name_attr, namebuf);
9518 
9519 			if (scf_value_get_boolean(val, &b) != SCF_SUCCESS)
9520 				scfdie();
9521 
9522 			safe_setprop(inode, enabled_attr, b ? true : false);
9523 		}
9524 		if (s < 0)
9525 			scfdie();
9526 
9527 		if (snode->children != NULL)
9528 			xmlAddChild(sb, snode);
9529 		else
9530 			xmlFreeNode(snode);
9531 	}
9532 	if (r < 0)
9533 		scfdie();
9534 
9535 	free(namebuf);
9536 
9537 	result = write_service_bundle(doc, f);
9538 
9539 	xmlFreeDoc(doc);
9540 
9541 	if (f != stdout)
9542 		(void) fclose(f);
9543 
9544 	return (result);
9545 }
9546 
9547 
9548 /*
9549  * Entity manipulation commands
9550  */
9551 
9552 /*
9553  * Entity selection.  If no entity is selected, then the current scope is in
9554  * cur_scope, and cur_svc and cur_inst are NULL.  When a service is selected,
9555  * only cur_inst is NULL, and when an instance is selected, none are NULL.
9556  * When the snaplevel of a snapshot is selected, cur_level, cur_snap, and
9557  * cur_inst will be non-NULL.
9558  */
9559 
9560 /* Returns 1 if maybe absolute fmri, 0 on success (dies on failure) */
9561 static int
9562 select_inst(const char *name)
9563 {
9564 	scf_instance_t *inst;
9565 	scf_error_t err;
9566 
9567 	assert(cur_svc != NULL);
9568 
9569 	inst = scf_instance_create(g_hndl);
9570 	if (inst == NULL)
9571 		scfdie();
9572 
9573 	if (scf_service_get_instance(cur_svc, name, inst) == SCF_SUCCESS) {
9574 		cur_inst = inst;
9575 		return (0);
9576 	}
9577 
9578 	err = scf_error();
9579 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9580 		scfdie();
9581 
9582 	scf_instance_destroy(inst);
9583 	return (1);
9584 }
9585 
9586 /* Returns as above. */
9587 static int
9588 select_svc(const char *name)
9589 {
9590 	scf_service_t *svc;
9591 	scf_error_t err;
9592 
9593 	assert(cur_scope != NULL);
9594 
9595 	svc = scf_service_create(g_hndl);
9596 	if (svc == NULL)
9597 		scfdie();
9598 
9599 	if (scf_scope_get_service(cur_scope, name, svc) == SCF_SUCCESS) {
9600 		cur_svc = svc;
9601 		return (0);
9602 	}
9603 
9604 	err = scf_error();
9605 	if (err != SCF_ERROR_NOT_FOUND && err != SCF_ERROR_INVALID_ARGUMENT)
9606 		scfdie();
9607 
9608 	scf_service_destroy(svc);
9609 	return (1);
9610 }
9611 
9612 /* ARGSUSED */
9613 static int
9614 select_callback(void *unused, scf_walkinfo_t *wip)
9615 {
9616 	scf_instance_t *inst;
9617 	scf_service_t *svc;
9618 	scf_scope_t *scope;
9619 
9620 	if (wip->inst != NULL) {
9621 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9622 		    (svc = scf_service_create(g_hndl)) == NULL ||
9623 		    (inst = scf_instance_create(g_hndl)) == NULL)
9624 			scfdie();
9625 
9626 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9627 		    inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9628 			scfdie();
9629 	} else {
9630 		assert(wip->svc != NULL);
9631 
9632 		if ((scope = scf_scope_create(g_hndl)) == NULL ||
9633 		    (svc = scf_service_create(g_hndl)) == NULL)
9634 			scfdie();
9635 
9636 		if (scf_handle_decode_fmri(g_hndl, wip->fmri, scope, svc,
9637 		    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != SCF_SUCCESS)
9638 			scfdie();
9639 
9640 		inst = NULL;
9641 	}
9642 
9643 	/* Clear out the current selection */
9644 	assert(cur_scope != NULL);
9645 	scf_scope_destroy(cur_scope);
9646 	scf_service_destroy(cur_svc);
9647 	scf_instance_destroy(cur_inst);
9648 
9649 	cur_scope = scope;
9650 	cur_svc = svc;
9651 	cur_inst = inst;
9652 
9653 	return (0);
9654 }
9655 
9656 static int
9657 validate_callback(void *fmri_p, scf_walkinfo_t *wip)
9658 {
9659 	char **fmri = fmri_p;
9660 
9661 	*fmri = strdup(wip->fmri);
9662 	if (*fmri == NULL)
9663 		uu_die(gettext("Out of memory.\n"));
9664 
9665 	return (0);
9666 }
9667 
9668 /*
9669  * validate [fmri]
9670  * Perform the validation of an FMRI instance.
9671  */
9672 void
9673 lscf_validate_fmri(const char *fmri)
9674 {
9675 	int ret = 0;
9676 	size_t inst_sz;
9677 	char *inst_fmri = NULL;
9678 	scf_tmpl_errors_t *errs = NULL;
9679 	char *snapbuf = NULL;
9680 
9681 	lscf_prep_hndl();
9682 
9683 	if (fmri == NULL) {
9684 		inst_sz = max_scf_fmri_len + 1;
9685 		inst_fmri = safe_malloc(inst_sz);
9686 
9687 		if (cur_snap != NULL) {
9688 			snapbuf = safe_malloc(max_scf_name_len + 1);
9689 			if (scf_snapshot_get_name(cur_snap, snapbuf,
9690 			    max_scf_name_len + 1) < 0)
9691 				scfdie();
9692 		}
9693 		if (cur_inst == NULL) {
9694 			semerr(gettext("No instance selected\n"));
9695 			goto cleanup;
9696 		} else if (scf_instance_to_fmri(cur_inst, inst_fmri,
9697 		    inst_sz) >= inst_sz) {
9698 			/* sanity check. Should never get here */
9699 			uu_die(gettext("Unexpected error! file %s, line %d\n"),
9700 			    __FILE__, __LINE__);
9701 		}
9702 	} else {
9703 		scf_error_t scf_err;
9704 		int err = 0;
9705 
9706 		if ((scf_err = scf_walk_fmri(g_hndl, 1, (char **)&fmri, 0,
9707 		    validate_callback, &inst_fmri, &err, semerr)) != 0) {
9708 			uu_warn("Failed to walk instances: %s\n",
9709 			    scf_strerror(scf_err));
9710 			goto cleanup;
9711 		}
9712 		if (err != 0)
9713 			/* error message displayed by scf_walk_fmri */
9714 			goto cleanup;
9715 	}
9716 
9717 	ret = scf_tmpl_validate_fmri(g_hndl, inst_fmri, snapbuf, &errs,
9718 	    SCF_TMPL_VALIDATE_FLAG_CURRENT);
9719 	if (ret == -1) {
9720 		if (scf_error() == SCF_ERROR_TEMPLATE_INVALID) {
9721 			warn(gettext("Template data for %s is invalid. "
9722 			    "Consider reverting to a previous snapshot or "
9723 			    "restoring original configuration.\n"), inst_fmri);
9724 		} else {
9725 			uu_warn("%s: %s\n",
9726 			    gettext("Error validating the instance"),
9727 			    scf_strerror(scf_error()));
9728 		}
9729 	} else if (ret == 1 && errs != NULL) {
9730 		scf_tmpl_error_t *err = NULL;
9731 		char *msg;
9732 		size_t len = 256;	/* initial error buffer size */
9733 		int flag = (est->sc_cmd_flags & SC_CMD_IACTIVE) ?
9734 		    SCF_TMPL_STRERROR_HUMAN : 0;
9735 
9736 		msg = safe_malloc(len);
9737 
9738 		while ((err = scf_tmpl_next_error(errs)) != NULL) {
9739 			int ret;
9740 
9741 			if ((ret = scf_tmpl_strerror(err, msg, len,
9742 			    flag)) >= len) {
9743 				len = ret + 1;
9744 				msg = realloc(msg, len);
9745 				if (msg == NULL)
9746 					uu_die(gettext(
9747 					    "Out of memory.\n"));
9748 				(void) scf_tmpl_strerror(err, msg, len,
9749 				    flag);
9750 			}
9751 			(void) fprintf(stderr, "%s\n", msg);
9752 		}
9753 		if (msg != NULL)
9754 			free(msg);
9755 	}
9756 	if (errs != NULL)
9757 		scf_tmpl_errors_destroy(errs);
9758 cleanup:
9759 	free(inst_fmri);
9760 	free(snapbuf);
9761 }
9762 
9763 static void
9764 lscf_validate_file(const char *filename)
9765 {
9766 	tmpl_errors_t *errs;
9767 
9768 	bundle_t *b = internal_bundle_new();
9769 	if (lxml_get_bundle_file(b, filename, SVCCFG_OP_IMPORT) == 0) {
9770 		if (tmpl_validate_bundle(b, &errs) != TVS_SUCCESS) {
9771 			tmpl_errors_print(stderr, errs, "");
9772 			semerr(gettext("Validation failed.\n"));
9773 		}
9774 		tmpl_errors_destroy(errs);
9775 	}
9776 	(void) internal_bundle_free(b);
9777 }
9778 
9779 /*
9780  * validate [fmri|file]
9781  */
9782 void
9783 lscf_validate(const char *arg)
9784 {
9785 	const char *str;
9786 
9787 	if (strncmp(arg, SCF_FMRI_FILE_PREFIX,
9788 	    sizeof (SCF_FMRI_FILE_PREFIX) - 1) == 0) {
9789 		str = arg + sizeof (SCF_FMRI_FILE_PREFIX) - 1;
9790 		lscf_validate_file(str);
9791 	} else if (strncmp(arg, SCF_FMRI_SVC_PREFIX,
9792 	    sizeof (SCF_FMRI_SVC_PREFIX) - 1) == 0) {
9793 		str = arg + sizeof (SCF_FMRI_SVC_PREFIX) - 1;
9794 		lscf_validate_fmri(str);
9795 	} else if (access(arg, R_OK | F_OK) == 0) {
9796 		lscf_validate_file(arg);
9797 	} else {
9798 		lscf_validate_fmri(arg);
9799 	}
9800 }
9801 
9802 void
9803 lscf_select(const char *fmri)
9804 {
9805 	int ret, err;
9806 
9807 	lscf_prep_hndl();
9808 
9809 	if (cur_snap != NULL) {
9810 		struct snaplevel *elt;
9811 		char *buf;
9812 
9813 		/* Error unless name is that of the next level. */
9814 		elt = uu_list_next(cur_levels, cur_elt);
9815 		if (elt == NULL) {
9816 			semerr(gettext("No children.\n"));
9817 			return;
9818 		}
9819 
9820 		buf = safe_malloc(max_scf_name_len + 1);
9821 
9822 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
9823 		    max_scf_name_len + 1) < 0)
9824 			scfdie();
9825 
9826 		if (strcmp(buf, fmri) != 0) {
9827 			semerr(gettext("No such child.\n"));
9828 			free(buf);
9829 			return;
9830 		}
9831 
9832 		free(buf);
9833 
9834 		cur_elt = elt;
9835 		cur_level = elt->sl;
9836 		return;
9837 	}
9838 
9839 	/*
9840 	 * Special case for 'svc:', which takes the user to the scope level.
9841 	 */
9842 	if (strcmp(fmri, "svc:") == 0) {
9843 		scf_instance_destroy(cur_inst);
9844 		scf_service_destroy(cur_svc);
9845 		cur_inst = NULL;
9846 		cur_svc = NULL;
9847 		return;
9848 	}
9849 
9850 	/*
9851 	 * Special case for ':properties'.  This appears as part of 'list' but
9852 	 * can't be selected.  Give a more helpful error message in this case.
9853 	 */
9854 	if (strcmp(fmri, ":properties") == 0) {
9855 		semerr(gettext(":properties is not an entity.  Try 'listprop' "
9856 		    "to list properties.\n"));
9857 		return;
9858 	}
9859 
9860 	/*
9861 	 * First try the argument as relative to the current selection.
9862 	 */
9863 	if (cur_inst != NULL) {
9864 		/* EMPTY */;
9865 	} else if (cur_svc != NULL) {
9866 		if (select_inst(fmri) != 1)
9867 			return;
9868 	} else {
9869 		if (select_svc(fmri) != 1)
9870 			return;
9871 	}
9872 
9873 	err = 0;
9874 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
9875 	    select_callback, NULL, &err, semerr)) != 0) {
9876 		semerr(gettext("Failed to walk instances: %s\n"),
9877 		    scf_strerror(ret));
9878 	}
9879 }
9880 
9881 void
9882 lscf_unselect(void)
9883 {
9884 	lscf_prep_hndl();
9885 
9886 	if (cur_snap != NULL) {
9887 		struct snaplevel *elt;
9888 
9889 		elt = uu_list_prev(cur_levels, cur_elt);
9890 		if (elt == NULL) {
9891 			semerr(gettext("No parent levels.\n"));
9892 		} else {
9893 			cur_elt = elt;
9894 			cur_level = elt->sl;
9895 		}
9896 	} else if (cur_inst != NULL) {
9897 		scf_instance_destroy(cur_inst);
9898 		cur_inst = NULL;
9899 	} else if (cur_svc != NULL) {
9900 		scf_service_destroy(cur_svc);
9901 		cur_svc = NULL;
9902 	} else {
9903 		semerr(gettext("Cannot unselect at scope level.\n"));
9904 	}
9905 }
9906 
9907 /*
9908  * Return the FMRI of the current selection, for the prompt.
9909  */
9910 void
9911 lscf_get_selection_str(char *buf, size_t bufsz)
9912 {
9913 	char *cp;
9914 	ssize_t fmrilen, szret;
9915 	boolean_t deleted = B_FALSE;
9916 
9917 	if (g_hndl == NULL) {
9918 		(void) strlcpy(buf, "svc:", bufsz);
9919 		return;
9920 	}
9921 
9922 	if (cur_level != NULL) {
9923 		assert(cur_snap != NULL);
9924 
9925 		/* [ snapshot ] FMRI [: instance ] */
9926 		assert(bufsz >= 1 + max_scf_name_len + 1 + max_scf_fmri_len
9927 		    + 2 + max_scf_name_len + 1 + 1);
9928 
9929 		buf[0] = '[';
9930 
9931 		szret = scf_snapshot_get_name(cur_snap, buf + 1,
9932 		    max_scf_name_len + 1);
9933 		if (szret < 0) {
9934 			if (scf_error() != SCF_ERROR_DELETED)
9935 				scfdie();
9936 
9937 			goto snap_deleted;
9938 		}
9939 
9940 		(void) strcat(buf, "]svc:/");
9941 
9942 		cp = strchr(buf, '\0');
9943 
9944 		szret = scf_snaplevel_get_service_name(cur_level, cp,
9945 		    max_scf_name_len + 1);
9946 		if (szret < 0) {
9947 			if (scf_error() != SCF_ERROR_DELETED)
9948 				scfdie();
9949 
9950 			goto snap_deleted;
9951 		}
9952 
9953 		cp = strchr(cp, '\0');
9954 
9955 		if (snaplevel_is_instance(cur_level)) {
9956 			*cp++ = ':';
9957 
9958 			if (scf_snaplevel_get_instance_name(cur_level, cp,
9959 			    max_scf_name_len + 1) < 0) {
9960 				if (scf_error() != SCF_ERROR_DELETED)
9961 					scfdie();
9962 
9963 				goto snap_deleted;
9964 			}
9965 		} else {
9966 			*cp++ = '[';
9967 			*cp++ = ':';
9968 
9969 			if (scf_instance_get_name(cur_inst, cp,
9970 			    max_scf_name_len + 1) < 0) {
9971 				if (scf_error() != SCF_ERROR_DELETED)
9972 					scfdie();
9973 
9974 				goto snap_deleted;
9975 			}
9976 
9977 			(void) strcat(buf, "]");
9978 		}
9979 
9980 		return;
9981 
9982 snap_deleted:
9983 		deleted = B_TRUE;
9984 		free(buf);
9985 		unselect_cursnap();
9986 	}
9987 
9988 	assert(cur_snap == NULL);
9989 
9990 	if (cur_inst != NULL) {
9991 		assert(cur_svc != NULL);
9992 		assert(cur_scope != NULL);
9993 
9994 		fmrilen = scf_instance_to_fmri(cur_inst, buf, bufsz);
9995 		if (fmrilen >= 0) {
9996 			assert(fmrilen < bufsz);
9997 			if (deleted)
9998 				warn(emsg_deleted);
9999 			return;
10000 		}
10001 
10002 		if (scf_error() != SCF_ERROR_DELETED)
10003 			scfdie();
10004 
10005 		deleted = B_TRUE;
10006 
10007 		scf_instance_destroy(cur_inst);
10008 		cur_inst = NULL;
10009 	}
10010 
10011 	if (cur_svc != NULL) {
10012 		assert(cur_scope != NULL);
10013 
10014 		szret = scf_service_to_fmri(cur_svc, buf, bufsz);
10015 		if (szret >= 0) {
10016 			assert(szret < bufsz);
10017 			if (deleted)
10018 				warn(emsg_deleted);
10019 			return;
10020 		}
10021 
10022 		if (scf_error() != SCF_ERROR_DELETED)
10023 			scfdie();
10024 
10025 		deleted = B_TRUE;
10026 		scf_service_destroy(cur_svc);
10027 		cur_svc = NULL;
10028 	}
10029 
10030 	assert(cur_scope != NULL);
10031 	fmrilen = scf_scope_to_fmri(cur_scope, buf, bufsz);
10032 
10033 	if (fmrilen < 0)
10034 		scfdie();
10035 
10036 	assert(fmrilen < bufsz);
10037 	if (deleted)
10038 		warn(emsg_deleted);
10039 }
10040 
10041 /*
10042  * Entity listing.  Entities and colon namespaces (e.g., :properties and
10043  * :statistics) are listed for the current selection.
10044  */
10045 void
10046 lscf_list(const char *pattern)
10047 {
10048 	scf_iter_t *iter;
10049 	char *buf;
10050 	int ret;
10051 
10052 	lscf_prep_hndl();
10053 
10054 	if (cur_level != NULL) {
10055 		struct snaplevel *elt;
10056 
10057 		(void) fputs(COLON_NAMESPACES, stdout);
10058 
10059 		elt = uu_list_next(cur_levels, cur_elt);
10060 		if (elt == NULL)
10061 			return;
10062 
10063 		/*
10064 		 * For now, we know that the next level is an instance.  But
10065 		 * if we ever have multiple scopes, this could be complicated.
10066 		 */
10067 		buf = safe_malloc(max_scf_name_len + 1);
10068 		if (scf_snaplevel_get_instance_name(elt->sl, buf,
10069 		    max_scf_name_len + 1) >= 0) {
10070 			(void) puts(buf);
10071 		} else {
10072 			if (scf_error() != SCF_ERROR_DELETED)
10073 				scfdie();
10074 		}
10075 
10076 		free(buf);
10077 
10078 		return;
10079 	}
10080 
10081 	if (cur_inst != NULL) {
10082 		(void) fputs(COLON_NAMESPACES, stdout);
10083 		return;
10084 	}
10085 
10086 	iter = scf_iter_create(g_hndl);
10087 	if (iter == NULL)
10088 		scfdie();
10089 
10090 	buf = safe_malloc(max_scf_name_len + 1);
10091 
10092 	if (cur_svc != NULL) {
10093 		/* List the instances in this service. */
10094 		scf_instance_t *inst;
10095 
10096 		inst = scf_instance_create(g_hndl);
10097 		if (inst == NULL)
10098 			scfdie();
10099 
10100 		if (scf_iter_service_instances(iter, cur_svc) == 0) {
10101 			safe_printf(COLON_NAMESPACES);
10102 
10103 			for (;;) {
10104 				ret = scf_iter_next_instance(iter, inst);
10105 				if (ret == 0)
10106 					break;
10107 				if (ret != 1) {
10108 					if (scf_error() != SCF_ERROR_DELETED)
10109 						scfdie();
10110 
10111 					break;
10112 				}
10113 
10114 				if (scf_instance_get_name(inst, buf,
10115 				    max_scf_name_len + 1) >= 0) {
10116 					if (pattern == NULL ||
10117 					    fnmatch(pattern, buf, 0) == 0)
10118 						(void) puts(buf);
10119 				} else {
10120 					if (scf_error() != SCF_ERROR_DELETED)
10121 						scfdie();
10122 				}
10123 			}
10124 		} else {
10125 			if (scf_error() != SCF_ERROR_DELETED)
10126 				scfdie();
10127 		}
10128 
10129 		scf_instance_destroy(inst);
10130 	} else {
10131 		/* List the services in this scope. */
10132 		scf_service_t *svc;
10133 
10134 		assert(cur_scope != NULL);
10135 
10136 		svc = scf_service_create(g_hndl);
10137 		if (svc == NULL)
10138 			scfdie();
10139 
10140 		if (scf_iter_scope_services(iter, cur_scope) != SCF_SUCCESS)
10141 			scfdie();
10142 
10143 		for (;;) {
10144 			ret = scf_iter_next_service(iter, svc);
10145 			if (ret == 0)
10146 				break;
10147 			if (ret != 1)
10148 				scfdie();
10149 
10150 			if (scf_service_get_name(svc, buf,
10151 			    max_scf_name_len + 1) >= 0) {
10152 				if (pattern == NULL ||
10153 				    fnmatch(pattern, buf, 0) == 0)
10154 					safe_printf("%s\n", buf);
10155 			} else {
10156 				if (scf_error() != SCF_ERROR_DELETED)
10157 					scfdie();
10158 			}
10159 		}
10160 
10161 		scf_service_destroy(svc);
10162 	}
10163 
10164 	free(buf);
10165 	scf_iter_destroy(iter);
10166 }
10167 
10168 /*
10169  * Entity addition.  Creates an empty entity in the current selection.
10170  */
10171 void
10172 lscf_add(const char *name)
10173 {
10174 	lscf_prep_hndl();
10175 
10176 	if (cur_snap != NULL) {
10177 		semerr(emsg_cant_modify_snapshots);
10178 	} else if (cur_inst != NULL) {
10179 		semerr(gettext("Cannot add entities to an instance.\n"));
10180 	} else if (cur_svc != NULL) {
10181 
10182 		if (scf_service_add_instance(cur_svc, name, NULL) !=
10183 		    SCF_SUCCESS) {
10184 			switch (scf_error()) {
10185 			case SCF_ERROR_INVALID_ARGUMENT:
10186 				semerr(gettext("Invalid name.\n"));
10187 				break;
10188 
10189 			case SCF_ERROR_EXISTS:
10190 				semerr(gettext("Instance already exists.\n"));
10191 				break;
10192 
10193 			case SCF_ERROR_PERMISSION_DENIED:
10194 				semerr(emsg_permission_denied);
10195 				break;
10196 
10197 			default:
10198 				scfdie();
10199 			}
10200 		}
10201 	} else {
10202 		assert(cur_scope != NULL);
10203 
10204 		if (scf_scope_add_service(cur_scope, name, NULL) !=
10205 		    SCF_SUCCESS) {
10206 			switch (scf_error()) {
10207 			case SCF_ERROR_INVALID_ARGUMENT:
10208 				semerr(gettext("Invalid name.\n"));
10209 				break;
10210 
10211 			case SCF_ERROR_EXISTS:
10212 				semerr(gettext("Service already exists.\n"));
10213 				break;
10214 
10215 			case SCF_ERROR_PERMISSION_DENIED:
10216 				semerr(emsg_permission_denied);
10217 				break;
10218 
10219 			case SCF_ERROR_BACKEND_READONLY:
10220 				semerr(emsg_read_only);
10221 				break;
10222 
10223 			default:
10224 				scfdie();
10225 			}
10226 		}
10227 	}
10228 }
10229 
10230 /* return 1 if the entity has no persistent pgs, else return 0 */
10231 static int
10232 entity_has_no_pgs(void *ent, int isservice)
10233 {
10234 	scf_iter_t *iter = NULL;
10235 	scf_propertygroup_t *pg = NULL;
10236 	uint32_t flags;
10237 	int err;
10238 	int ret = 1;
10239 
10240 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10241 	    (pg = scf_pg_create(g_hndl)) == NULL)
10242 		scfdie();
10243 
10244 	if (isservice) {
10245 		if (scf_iter_service_pgs(iter, (scf_service_t *)ent) < 0)
10246 			scfdie();
10247 	} else {
10248 		if (scf_iter_instance_pgs(iter, (scf_instance_t *)ent) < 0)
10249 			scfdie();
10250 	}
10251 
10252 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10253 		if (scf_pg_get_flags(pg, &flags) != 0)
10254 			scfdie();
10255 
10256 		/* skip nonpersistent pgs */
10257 		if (flags & SCF_PG_FLAG_NONPERSISTENT)
10258 			continue;
10259 
10260 		ret = 0;
10261 		break;
10262 	}
10263 
10264 	if (err == -1)
10265 		scfdie();
10266 
10267 	scf_pg_destroy(pg);
10268 	scf_iter_destroy(iter);
10269 
10270 	return (ret);
10271 }
10272 
10273 /* return 1 if the service has no instances, else return 0 */
10274 static int
10275 svc_has_no_insts(scf_service_t *svc)
10276 {
10277 	scf_instance_t *inst;
10278 	scf_iter_t *iter;
10279 	int r;
10280 	int ret = 1;
10281 
10282 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10283 	    (iter = scf_iter_create(g_hndl)) == NULL)
10284 		scfdie();
10285 
10286 	if (scf_iter_service_instances(iter, svc) != 0)
10287 		scfdie();
10288 
10289 	r = scf_iter_next_instance(iter, inst);
10290 	if (r == 1) {
10291 		ret = 0;
10292 	} else if (r == 0) {
10293 		ret = 1;
10294 	} else if (r == -1) {
10295 		scfdie();
10296 	} else {
10297 		bad_error("scf_iter_next_instance", r);
10298 	}
10299 
10300 	scf_iter_destroy(iter);
10301 	scf_instance_destroy(inst);
10302 
10303 	return (ret);
10304 }
10305 
10306 /*
10307  * Entity deletion.
10308  */
10309 
10310 /*
10311  * Delete the property group <fmri>/:properties/<name>.  Returns
10312  * SCF_ERROR_NONE on success (or if the entity is not found),
10313  * SCF_ERROR_INVALID_ARGUMENT if the fmri is bad, SCF_ERROR_TYPE_MISMATCH if
10314  * the pg is the wrong type, or SCF_ERROR_PERMISSION_DENIED if permission was
10315  * denied.
10316  */
10317 static scf_error_t
10318 delete_dependency_pg(const char *fmri, const char *name)
10319 {
10320 	void *entity = NULL;
10321 	int isservice;
10322 	scf_propertygroup_t *pg = NULL;
10323 	scf_error_t result;
10324 	char *pgty;
10325 	scf_service_t *svc = NULL;
10326 	scf_instance_t *inst = NULL;
10327 	scf_iter_t *iter = NULL;
10328 	char *name_buf = NULL;
10329 
10330 	result = fmri_to_entity(g_hndl, fmri, &entity, &isservice);
10331 	switch (result) {
10332 	case SCF_ERROR_NONE:
10333 		break;
10334 
10335 	case SCF_ERROR_NO_MEMORY:
10336 		uu_die(gettext("Out of memory.\n"));
10337 		/* NOTREACHED */
10338 
10339 	case SCF_ERROR_INVALID_ARGUMENT:
10340 	case SCF_ERROR_CONSTRAINT_VIOLATED:
10341 		return (SCF_ERROR_INVALID_ARGUMENT);
10342 
10343 	case SCF_ERROR_NOT_FOUND:
10344 		result = SCF_ERROR_NONE;
10345 		goto out;
10346 
10347 	default:
10348 		bad_error("fmri_to_entity", result);
10349 	}
10350 
10351 	pg = scf_pg_create(g_hndl);
10352 	if (pg == NULL)
10353 		scfdie();
10354 
10355 	if (entity_get_pg(entity, isservice, name, pg) != 0) {
10356 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10357 			scfdie();
10358 
10359 		result = SCF_ERROR_NONE;
10360 		goto out;
10361 	}
10362 
10363 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10364 
10365 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10366 		scfdie();
10367 
10368 	if (strcmp(pgty, SCF_GROUP_DEPENDENCY) != 0) {
10369 		result = SCF_ERROR_TYPE_MISMATCH;
10370 		free(pgty);
10371 		goto out;
10372 	}
10373 
10374 	free(pgty);
10375 
10376 	if (scf_pg_delete(pg) != 0) {
10377 		result = scf_error();
10378 		if (result != SCF_ERROR_PERMISSION_DENIED)
10379 			scfdie();
10380 		goto out;
10381 	}
10382 
10383 	/*
10384 	 * We have to handle the case where we've just deleted the last
10385 	 * property group of a "dummy" entity (instance or service).
10386 	 * A "dummy" entity is an entity only present to hold an
10387 	 * external dependency.
10388 	 * So, in the case we deleted the last property group then we
10389 	 * can also delete the entity. If the entity is an instance then
10390 	 * we must verify if this was the last instance for the service
10391 	 * and if it is, we can also delete the service if it doesn't
10392 	 * have any property group either.
10393 	 */
10394 
10395 	result = SCF_ERROR_NONE;
10396 
10397 	if (isservice) {
10398 		svc = (scf_service_t *)entity;
10399 
10400 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
10401 		    (iter = scf_iter_create(g_hndl)) == NULL)
10402 			scfdie();
10403 
10404 		name_buf = safe_malloc(max_scf_name_len + 1);
10405 	} else {
10406 		inst = (scf_instance_t *)entity;
10407 	}
10408 
10409 	/*
10410 	 * If the entity is an instance and we've just deleted its last
10411 	 * property group then we should delete it.
10412 	 */
10413 	if (!isservice && entity_has_no_pgs(entity, isservice)) {
10414 		/* find the service before deleting the inst. - needed later */
10415 		if ((svc = scf_service_create(g_hndl)) == NULL)
10416 			scfdie();
10417 
10418 		if (scf_instance_get_parent(inst, svc) != 0)
10419 			scfdie();
10420 
10421 		/* delete the instance */
10422 		if (scf_instance_delete(inst) != 0) {
10423 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10424 				scfdie();
10425 
10426 			result = SCF_ERROR_PERMISSION_DENIED;
10427 			goto out;
10428 		}
10429 		/* no need to refresh the instance */
10430 		inst = NULL;
10431 	}
10432 
10433 	/*
10434 	 * If the service has no more instances and pgs or we just deleted the
10435 	 * last instance and the service doesn't have anymore propery groups
10436 	 * then the service should be deleted.
10437 	 */
10438 	if (svc != NULL &&
10439 	    svc_has_no_insts(svc) &&
10440 	    entity_has_no_pgs((void *)svc, 1)) {
10441 		if (scf_service_delete(svc) == 0) {
10442 			if (isservice) {
10443 				/* no need to refresh the service */
10444 				svc = NULL;
10445 			}
10446 
10447 			goto out;
10448 		}
10449 
10450 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10451 			scfdie();
10452 
10453 		result = SCF_ERROR_PERMISSION_DENIED;
10454 	}
10455 
10456 	/* if the entity has not been deleted, refresh it */
10457 	if ((isservice && svc != NULL) || (!isservice && inst != NULL)) {
10458 		(void) refresh_entity(isservice, entity, fmri, inst, iter,
10459 		    name_buf);
10460 	}
10461 
10462 out:
10463 	if (isservice && (inst != NULL && iter != NULL)) {
10464 		free(name_buf);
10465 		scf_iter_destroy(iter);
10466 		scf_instance_destroy(inst);
10467 	}
10468 
10469 	if (!isservice && svc != NULL) {
10470 		scf_service_destroy(svc);
10471 	}
10472 
10473 	scf_pg_destroy(pg);
10474 	if (entity != NULL)
10475 		entity_destroy(entity, isservice);
10476 
10477 	return (result);
10478 }
10479 
10480 static int
10481 delete_dependents(scf_propertygroup_t *pg)
10482 {
10483 	char *pgty, *name, *fmri;
10484 	scf_property_t *prop;
10485 	scf_value_t *val;
10486 	scf_iter_t *iter;
10487 	int r;
10488 	scf_error_t err;
10489 
10490 	/* Verify that the pg has the correct type. */
10491 	pgty = safe_malloc(max_scf_pg_type_len + 1);
10492 	if (scf_pg_get_type(pg, pgty, max_scf_pg_type_len + 1) < 0)
10493 		scfdie();
10494 
10495 	if (strcmp(pgty, scf_group_framework) != 0) {
10496 		if (g_verbose) {
10497 			fmri = safe_malloc(max_scf_fmri_len + 1);
10498 			if (scf_pg_to_fmri(pg, fmri, max_scf_fmri_len + 1) < 0)
10499 				scfdie();
10500 
10501 			warn(gettext("Property group %s is not of expected "
10502 			    "type %s.\n"), fmri, scf_group_framework);
10503 
10504 			free(fmri);
10505 		}
10506 
10507 		free(pgty);
10508 		return (-1);
10509 	}
10510 
10511 	free(pgty);
10512 
10513 	/* map delete_dependency_pg onto the properties. */
10514 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10515 	    (val = scf_value_create(g_hndl)) == NULL ||
10516 	    (iter = scf_iter_create(g_hndl)) == NULL)
10517 		scfdie();
10518 
10519 	if (scf_iter_pg_properties(iter, pg) != SCF_SUCCESS)
10520 		scfdie();
10521 
10522 	name = safe_malloc(max_scf_name_len + 1);
10523 	fmri = safe_malloc(max_scf_fmri_len + 2);
10524 
10525 	while ((r = scf_iter_next_property(iter, prop)) == 1) {
10526 		scf_type_t ty;
10527 
10528 		if (scf_property_get_name(prop, name, max_scf_name_len + 1) < 0)
10529 			scfdie();
10530 
10531 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
10532 			scfdie();
10533 
10534 		if ((ty != SCF_TYPE_ASTRING &&
10535 		    prop_check_type(prop, SCF_TYPE_FMRI) != 0) ||
10536 		    prop_get_val(prop, val) != 0)
10537 			continue;
10538 
10539 		if (scf_value_get_astring(val, fmri, max_scf_fmri_len + 2) < 0)
10540 			scfdie();
10541 
10542 		err = delete_dependency_pg(fmri, name);
10543 		if (err == SCF_ERROR_INVALID_ARGUMENT && g_verbose) {
10544 			if (scf_property_to_fmri(prop, fmri,
10545 			    max_scf_fmri_len + 2) < 0)
10546 				scfdie();
10547 
10548 			warn(gettext("Value of %s is not a valid FMRI.\n"),
10549 			    fmri);
10550 		} else if (err == SCF_ERROR_TYPE_MISMATCH && g_verbose) {
10551 			warn(gettext("Property group \"%s\" of entity \"%s\" "
10552 			    "does not have dependency type.\n"), name, fmri);
10553 		} else if (err == SCF_ERROR_PERMISSION_DENIED && g_verbose) {
10554 			warn(gettext("Could not delete property group \"%s\" "
10555 			    "of entity \"%s\" (permission denied).\n"), name,
10556 			    fmri);
10557 		}
10558 	}
10559 	if (r == -1)
10560 		scfdie();
10561 
10562 	scf_value_destroy(val);
10563 	scf_property_destroy(prop);
10564 
10565 	return (0);
10566 }
10567 
10568 /*
10569  * Returns 1 if the instance may be running, and 0 otherwise.
10570  */
10571 static int
10572 inst_is_running(scf_instance_t *inst)
10573 {
10574 	scf_propertygroup_t *pg;
10575 	scf_property_t *prop;
10576 	scf_value_t *val;
10577 	char buf[MAX_SCF_STATE_STRING_SZ];
10578 	int ret = 0;
10579 	ssize_t szret;
10580 
10581 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10582 	    (prop = scf_property_create(g_hndl)) == NULL ||
10583 	    (val = scf_value_create(g_hndl)) == NULL)
10584 		scfdie();
10585 
10586 	if (scf_instance_get_pg(inst, SCF_PG_RESTARTER, pg) != SCF_SUCCESS) {
10587 		if (scf_error() != SCF_ERROR_NOT_FOUND)
10588 			scfdie();
10589 		goto out;
10590 	}
10591 
10592 	if (pg_get_prop(pg, SCF_PROPERTY_STATE, prop) != 0 ||
10593 	    prop_check_type(prop, SCF_TYPE_ASTRING) != 0 ||
10594 	    prop_get_val(prop, val) != 0)
10595 		goto out;
10596 
10597 	szret = scf_value_get_astring(val, buf, sizeof (buf));
10598 	assert(szret >= 0);
10599 
10600 	ret = (strcmp(buf, SCF_STATE_STRING_ONLINE) == 0 ||
10601 	    strcmp(buf, SCF_STATE_STRING_DEGRADED) == 0) ? 1 : 0;
10602 
10603 out:
10604 	scf_value_destroy(val);
10605 	scf_property_destroy(prop);
10606 	scf_pg_destroy(pg);
10607 	return (ret);
10608 }
10609 
10610 static uint8_t
10611 pg_is_external_dependency(scf_propertygroup_t *pg)
10612 {
10613 	char *type;
10614 	scf_value_t *val;
10615 	scf_property_t *prop;
10616 	uint8_t b = B_FALSE;
10617 
10618 	type = safe_malloc(max_scf_pg_type_len + 1);
10619 
10620 	if (scf_pg_get_type(pg, type, max_scf_pg_type_len + 1) < 0)
10621 		scfdie();
10622 
10623 	if ((prop = scf_property_create(g_hndl)) == NULL ||
10624 	    (val = scf_value_create(g_hndl)) == NULL)
10625 		scfdie();
10626 
10627 	if (strcmp(type, SCF_GROUP_DEPENDENCY) == 0) {
10628 		if (pg_get_prop(pg, scf_property_external, prop) == 0) {
10629 			if (scf_property_get_value(prop, val) != 0)
10630 				scfdie();
10631 			if (scf_value_get_boolean(val, &b) != 0)
10632 				scfdie();
10633 		}
10634 	}
10635 
10636 	free(type);
10637 	(void) scf_value_destroy(val);
10638 	(void) scf_property_destroy(prop);
10639 
10640 	return (b);
10641 }
10642 
10643 #define	DELETE_FAILURE			-1
10644 #define	DELETE_SUCCESS_NOEXTDEPS	0
10645 #define	DELETE_SUCCESS_EXTDEPS		1
10646 
10647 /*
10648  * lscf_instance_delete() deletes an instance.  Before calling
10649  * scf_instance_delete(), though, we make sure the instance isn't
10650  * running and delete dependencies in other entities which the instance
10651  * declared as "dependents".  If there are dependencies which were
10652  * created for other entities, then instead of deleting the instance we
10653  * make it "empty" by deleting all other property groups and all
10654  * snapshots.
10655  *
10656  * lscf_instance_delete() verifies that there is no external dependency pgs
10657  * before suppressing the instance. If there is, then we must not remove them
10658  * now in case the instance is re-created otherwise the dependencies would be
10659  * lost. The external dependency pgs will be removed if the dependencies are
10660  * removed.
10661  *
10662  * Returns:
10663  *  DELETE_FAILURE		on failure
10664  *  DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
10665  *  DELETE_SUCCESS_EXTDEPS	on success - external dependencies
10666  */
10667 static int
10668 lscf_instance_delete(scf_instance_t *inst, int force)
10669 {
10670 	scf_propertygroup_t *pg;
10671 	scf_snapshot_t *snap;
10672 	scf_iter_t *iter;
10673 	int err;
10674 	int external = 0;
10675 
10676 	/* If we're not forcing and the instance is running, refuse. */
10677 	if (!force && inst_is_running(inst)) {
10678 		char *fmri;
10679 
10680 		fmri = safe_malloc(max_scf_fmri_len + 1);
10681 
10682 		if (scf_instance_to_fmri(inst, fmri, max_scf_fmri_len + 1) < 0)
10683 			scfdie();
10684 
10685 		semerr(gettext("Instance %s may be running.  "
10686 		    "Use delete -f if it is not.\n"), fmri);
10687 
10688 		free(fmri);
10689 		return (DELETE_FAILURE);
10690 	}
10691 
10692 	pg = scf_pg_create(g_hndl);
10693 	if (pg == NULL)
10694 		scfdie();
10695 
10696 	if (scf_instance_get_pg(inst, SCF_PG_DEPENDENTS, pg) == 0)
10697 		(void) delete_dependents(pg);
10698 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
10699 		scfdie();
10700 
10701 	scf_pg_destroy(pg);
10702 
10703 	/*
10704 	 * If the instance has some external dependencies then we must
10705 	 * keep them in case the instance is reimported otherwise the
10706 	 * dependencies would be lost on reimport.
10707 	 */
10708 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
10709 	    (pg = scf_pg_create(g_hndl)) == NULL)
10710 		scfdie();
10711 
10712 	if (scf_iter_instance_pgs(iter, inst) < 0)
10713 		scfdie();
10714 
10715 	while ((err = scf_iter_next_pg(iter, pg)) == 1) {
10716 		if (pg_is_external_dependency(pg)) {
10717 			external = 1;
10718 			continue;
10719 		}
10720 
10721 		if (scf_pg_delete(pg) != 0) {
10722 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10723 				scfdie();
10724 			else {
10725 				semerr(emsg_permission_denied);
10726 
10727 				(void) scf_iter_destroy(iter);
10728 				(void) scf_pg_destroy(pg);
10729 				return (DELETE_FAILURE);
10730 			}
10731 		}
10732 	}
10733 
10734 	if (err == -1)
10735 		scfdie();
10736 
10737 	(void) scf_iter_destroy(iter);
10738 	(void) scf_pg_destroy(pg);
10739 
10740 	if (external) {
10741 		/*
10742 		 * All the pgs have been deleted for the instance except
10743 		 * the ones holding the external dependencies.
10744 		 * For the job to be complete, we must also delete the
10745 		 * snapshots associated with the instance.
10746 		 */
10747 		if ((snap = scf_snapshot_create((scf_handle_t *)g_hndl)) ==
10748 		    NULL)
10749 			scfdie();
10750 		if ((iter = scf_iter_create((scf_handle_t *)g_hndl)) == NULL)
10751 			scfdie();
10752 
10753 		if (scf_iter_instance_snapshots(iter, inst) == -1)
10754 			scfdie();
10755 
10756 		while ((err = scf_iter_next_snapshot(iter, snap)) == 1) {
10757 			if (_scf_snapshot_delete(snap) != 0) {
10758 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10759 					scfdie();
10760 
10761 				semerr(emsg_permission_denied);
10762 
10763 				(void) scf_iter_destroy(iter);
10764 				(void) scf_snapshot_destroy(snap);
10765 				return (DELETE_FAILURE);
10766 			}
10767 		}
10768 
10769 		if (err == -1)
10770 			scfdie();
10771 
10772 		(void) scf_iter_destroy(iter);
10773 		(void) scf_snapshot_destroy(snap);
10774 		return (DELETE_SUCCESS_EXTDEPS);
10775 	}
10776 
10777 	if (scf_instance_delete(inst) != 0) {
10778 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10779 			scfdie();
10780 
10781 		semerr(emsg_permission_denied);
10782 
10783 		return (DELETE_FAILURE);
10784 	}
10785 
10786 	return (DELETE_SUCCESS_NOEXTDEPS);
10787 }
10788 
10789 /*
10790  * lscf_service_delete() deletes a service.  Before calling
10791  * scf_service_delete(), though, we call lscf_instance_delete() for
10792  * each of the instances and delete dependencies in other entities
10793  * which were created as "dependents" of this service.  If there are
10794  * dependencies which were created for other entities, then we delete
10795  * all other property groups in the service and leave it as "empty".
10796  *
10797  * lscf_service_delete() verifies that there is no external dependency
10798  * pgs at the instance & service level before suppressing the service.
10799  * If there is, then we must not remove them now in case the service
10800  * is re-imported otherwise the dependencies would be lost. The external
10801  * dependency pgs will be removed if the dependencies are removed.
10802  *
10803  * Returns:
10804  *   DELETE_FAILURE		on failure
10805  *   DELETE_SUCCESS_NOEXTDEPS	on success - no external dependencies
10806  *   DELETE_SUCCESS_EXTDEPS	on success - external dependencies
10807  */
10808 static int
10809 lscf_service_delete(scf_service_t *svc, int force)
10810 {
10811 	int r;
10812 	scf_instance_t *inst;
10813 	scf_propertygroup_t *pg;
10814 	scf_iter_t *iter;
10815 	int ret;
10816 	int external = 0;
10817 
10818 	if ((inst = scf_instance_create(g_hndl)) == NULL ||
10819 	    (pg = scf_pg_create(g_hndl)) == NULL ||
10820 	    (iter = scf_iter_create(g_hndl)) == NULL)
10821 		scfdie();
10822 
10823 	if (scf_iter_service_instances(iter, svc) != 0)
10824 		scfdie();
10825 
10826 	for (r = scf_iter_next_instance(iter, inst);
10827 	    r == 1;
10828 	    r = scf_iter_next_instance(iter, inst)) {
10829 
10830 		ret = lscf_instance_delete(inst, force);
10831 		if (ret == DELETE_FAILURE) {
10832 			scf_iter_destroy(iter);
10833 			scf_pg_destroy(pg);
10834 			scf_instance_destroy(inst);
10835 			return (DELETE_FAILURE);
10836 		}
10837 
10838 		/*
10839 		 * Record the fact that there is some external dependencies
10840 		 * at the instance level.
10841 		 */
10842 		if (ret == DELETE_SUCCESS_EXTDEPS)
10843 			external |= 1;
10844 	}
10845 
10846 	if (r != 0)
10847 		scfdie();
10848 
10849 	/* Delete dependency property groups in dependent services. */
10850 	if (scf_service_get_pg(svc, SCF_PG_DEPENDENTS, pg) == 0)
10851 		(void) delete_dependents(pg);
10852 	else if (scf_error() != SCF_ERROR_NOT_FOUND)
10853 		scfdie();
10854 
10855 	scf_iter_destroy(iter);
10856 	scf_pg_destroy(pg);
10857 	scf_instance_destroy(inst);
10858 
10859 	/*
10860 	 * If the service has some external dependencies then we don't
10861 	 * want to remove them in case the service is re-imported.
10862 	 */
10863 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
10864 	    (iter = scf_iter_create(g_hndl)) == NULL)
10865 		scfdie();
10866 
10867 	if (scf_iter_service_pgs(iter, svc) < 0)
10868 		scfdie();
10869 
10870 	while ((r = scf_iter_next_pg(iter, pg)) == 1) {
10871 		if (pg_is_external_dependency(pg)) {
10872 			external |= 2;
10873 			continue;
10874 		}
10875 
10876 		if (scf_pg_delete(pg) != 0) {
10877 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10878 				scfdie();
10879 			else {
10880 				semerr(emsg_permission_denied);
10881 
10882 				(void) scf_iter_destroy(iter);
10883 				(void) scf_pg_destroy(pg);
10884 				return (DELETE_FAILURE);
10885 			}
10886 		}
10887 	}
10888 
10889 	if (r == -1)
10890 		scfdie();
10891 
10892 	(void) scf_iter_destroy(iter);
10893 	(void) scf_pg_destroy(pg);
10894 
10895 	if (external != 0)
10896 		return (DELETE_SUCCESS_EXTDEPS);
10897 
10898 	if (scf_service_delete(svc) == 0)
10899 		return (DELETE_SUCCESS_NOEXTDEPS);
10900 
10901 	if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
10902 		scfdie();
10903 
10904 	semerr(emsg_permission_denied);
10905 	return (DELETE_FAILURE);
10906 }
10907 
10908 static int
10909 delete_callback(void *data, scf_walkinfo_t *wip)
10910 {
10911 	int force = (int)data;
10912 
10913 	if (wip->inst != NULL)
10914 		(void) lscf_instance_delete(wip->inst, force);
10915 	else
10916 		(void) lscf_service_delete(wip->svc, force);
10917 
10918 	return (0);
10919 }
10920 
10921 void
10922 lscf_delete(const char *fmri, int force)
10923 {
10924 	scf_service_t *svc;
10925 	scf_instance_t *inst;
10926 	int ret;
10927 
10928 	lscf_prep_hndl();
10929 
10930 	if (cur_snap != NULL) {
10931 		if (!snaplevel_is_instance(cur_level)) {
10932 			char *buf;
10933 
10934 			buf = safe_malloc(max_scf_name_len + 1);
10935 			if (scf_instance_get_name(cur_inst, buf,
10936 			    max_scf_name_len + 1) >= 0) {
10937 				if (strcmp(buf, fmri) == 0) {
10938 					semerr(emsg_cant_modify_snapshots);
10939 					free(buf);
10940 					return;
10941 				}
10942 			} else if (scf_error() != SCF_ERROR_DELETED) {
10943 				scfdie();
10944 			}
10945 			free(buf);
10946 		}
10947 	} else if (cur_inst != NULL) {
10948 		/* EMPTY */;
10949 	} else if (cur_svc != NULL) {
10950 		inst = scf_instance_create(g_hndl);
10951 		if (inst == NULL)
10952 			scfdie();
10953 
10954 		if (scf_service_get_instance(cur_svc, fmri, inst) ==
10955 		    SCF_SUCCESS) {
10956 			(void) lscf_instance_delete(inst, force);
10957 			scf_instance_destroy(inst);
10958 			return;
10959 		}
10960 
10961 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
10962 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
10963 			scfdie();
10964 
10965 		scf_instance_destroy(inst);
10966 	} else {
10967 		assert(cur_scope != NULL);
10968 
10969 		svc = scf_service_create(g_hndl);
10970 		if (svc == NULL)
10971 			scfdie();
10972 
10973 		if (scf_scope_get_service(cur_scope, fmri, svc) ==
10974 		    SCF_SUCCESS) {
10975 			(void) lscf_service_delete(svc, force);
10976 			scf_service_destroy(svc);
10977 			return;
10978 		}
10979 
10980 		if (scf_error() != SCF_ERROR_NOT_FOUND &&
10981 		    scf_error() != SCF_ERROR_INVALID_ARGUMENT)
10982 			scfdie();
10983 
10984 		scf_service_destroy(svc);
10985 	}
10986 
10987 	/*
10988 	 * Match FMRI to entity.
10989 	 */
10990 	if ((ret = scf_walk_fmri(g_hndl, 1, (char **)&fmri, SCF_WALK_SERVICE,
10991 	    delete_callback, (void *)force, NULL, semerr)) != 0) {
10992 		semerr(gettext("Failed to walk instances: %s\n"),
10993 		    scf_strerror(ret));
10994 	}
10995 }
10996 
10997 
10998 
10999 /*
11000  * :properties commands.  These all end with "pg" or "prop" and generally
11001  * operate on the currently selected entity.
11002  */
11003 
11004 /*
11005  * Property listing.  List the property groups, properties, their types and
11006  * their values for the currently selected entity.
11007  */
11008 static void
11009 list_pg_info(const scf_propertygroup_t *pg, const char *name, size_t namewidth)
11010 {
11011 	char *buf;
11012 	uint32_t flags;
11013 
11014 	buf = safe_malloc(max_scf_pg_type_len + 1);
11015 
11016 	if (scf_pg_get_type(pg, buf, max_scf_pg_type_len + 1) < 0)
11017 		scfdie();
11018 
11019 	if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
11020 		scfdie();
11021 
11022 	safe_printf("%-*s  %s", namewidth, name, buf);
11023 
11024 	if (flags & SCF_PG_FLAG_NONPERSISTENT)
11025 		safe_printf("\tNONPERSISTENT");
11026 
11027 	safe_printf("\n");
11028 
11029 	free(buf);
11030 }
11031 
11032 static boolean_t
11033 prop_has_multiple_values(const scf_property_t *prop, scf_value_t *val)
11034 {
11035 	if (scf_property_get_value(prop, val) == 0) {
11036 		return (B_FALSE);
11037 	} else {
11038 		switch (scf_error()) {
11039 		case SCF_ERROR_NOT_FOUND:
11040 			return (B_FALSE);
11041 		case SCF_ERROR_PERMISSION_DENIED:
11042 		case SCF_ERROR_CONSTRAINT_VIOLATED:
11043 			return (B_TRUE);
11044 		default:
11045 			scfdie();
11046 			/*NOTREACHED*/
11047 		}
11048 	}
11049 }
11050 
11051 static void
11052 list_prop_info(const scf_property_t *prop, const char *name, size_t len)
11053 {
11054 	scf_iter_t *iter;
11055 	scf_value_t *val;
11056 	const char *type;
11057 	int multiple_strings = 0;
11058 	int ret;
11059 
11060 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11061 	    (val = scf_value_create(g_hndl)) == NULL)
11062 		scfdie();
11063 
11064 	type = prop_to_typestr(prop);
11065 	assert(type != NULL);
11066 
11067 	safe_printf("%-*s  %-7s ", len, name, type);
11068 
11069 	if (prop_has_multiple_values(prop, val) &&
11070 	    (scf_value_type(val) == SCF_TYPE_ASTRING ||
11071 	    scf_value_type(val) == SCF_TYPE_USTRING))
11072 		multiple_strings = 1;
11073 
11074 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11075 		scfdie();
11076 
11077 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11078 		char *buf;
11079 		ssize_t vlen, szret;
11080 
11081 		vlen = scf_value_get_as_string(val, NULL, 0);
11082 		if (vlen < 0)
11083 			scfdie();
11084 
11085 		buf = safe_malloc(vlen + 1);
11086 
11087 		szret = scf_value_get_as_string(val, buf, vlen + 1);
11088 		if (szret < 0)
11089 			scfdie();
11090 		assert(szret <= vlen);
11091 
11092 		/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11093 		if (multiple_strings || strpbrk(buf, " \t\n\"()") != NULL) {
11094 			safe_printf(" \"");
11095 			(void) quote_and_print(buf, stdout, 0);
11096 			(void) putchar('"');
11097 			if (ferror(stdout)) {
11098 				(void) putchar('\n');
11099 				uu_die(gettext("Error writing to stdout.\n"));
11100 			}
11101 		} else {
11102 			safe_printf(" %s", buf);
11103 		}
11104 
11105 		free(buf);
11106 	}
11107 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11108 		scfdie();
11109 
11110 	if (putchar('\n') != '\n')
11111 		uu_die(gettext("Could not output newline"));
11112 }
11113 
11114 /*
11115  * Outputs template property group info for the describe subcommand.
11116  * If 'templates' == 2, verbose output is printed in the format expected
11117  * for describe -v, which includes all templates fields.  If pg is
11118  * not NULL, we're describing the template data, not an existing property
11119  * group, and formatting should be appropriate for describe -t.
11120  */
11121 static void
11122 list_pg_tmpl(scf_pg_tmpl_t *pgt, scf_propertygroup_t *pg, int templates)
11123 {
11124 	char *buf;
11125 	uint8_t required;
11126 	scf_property_t *stability_prop;
11127 	scf_value_t *stability_val;
11128 
11129 	if (templates == 0)
11130 		return;
11131 
11132 	if ((stability_prop = scf_property_create(g_hndl)) == NULL ||
11133 	    (stability_val = scf_value_create(g_hndl)) == NULL)
11134 		scfdie();
11135 
11136 	if (templates == 2 && pg != NULL) {
11137 		if (scf_pg_get_property(pg, SCF_PROPERTY_STABILITY,
11138 		    stability_prop) == 0) {
11139 			if (prop_check_type(stability_prop,
11140 			    SCF_TYPE_ASTRING) == 0 &&
11141 			    prop_get_val(stability_prop, stability_val) == 0) {
11142 				char *stability;
11143 
11144 				stability = safe_malloc(max_scf_value_len + 1);
11145 
11146 				if (scf_value_get_astring(stability_val,
11147 				    stability, max_scf_value_len + 1) == -1 &&
11148 				    scf_error() != SCF_ERROR_NOT_FOUND)
11149 					scfdie();
11150 
11151 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11152 				    gettext("stability"), stability);
11153 
11154 				free(stability);
11155 			}
11156 		} else if (scf_error() != SCF_ERROR_NOT_FOUND)
11157 			scfdie();
11158 	}
11159 
11160 	scf_property_destroy(stability_prop);
11161 	scf_value_destroy(stability_val);
11162 
11163 	if (pgt == NULL)
11164 		return;
11165 
11166 	if (pg == NULL || templates == 2) {
11167 		/* print type info only if scf_tmpl_pg_name succeeds */
11168 		if (scf_tmpl_pg_name(pgt, &buf) != -1) {
11169 			if (pg != NULL)
11170 				safe_printf("%s", TMPL_INDENT);
11171 			safe_printf("%s: ", gettext("name"));
11172 			safe_printf("%s\n", buf);
11173 			free(buf);
11174 		}
11175 
11176 		/* print type info only if scf_tmpl_pg_type succeeds */
11177 		if (scf_tmpl_pg_type(pgt, &buf) != -1) {
11178 			if (pg != NULL)
11179 				safe_printf("%s", TMPL_INDENT);
11180 			safe_printf("%s: ", gettext("type"));
11181 			safe_printf("%s\n", buf);
11182 			free(buf);
11183 		}
11184 	}
11185 
11186 	if (templates == 2 && scf_tmpl_pg_required(pgt, &required) == 0)
11187 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11188 		    required ? "true" : "false");
11189 
11190 	if (templates == 2 && scf_tmpl_pg_target(pgt, &buf) > 0) {
11191 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("target"),
11192 		    buf);
11193 		free(buf);
11194 	}
11195 
11196 	if (templates == 2 && scf_tmpl_pg_common_name(pgt, NULL, &buf) > 0) {
11197 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11198 		    buf);
11199 		free(buf);
11200 	}
11201 
11202 	if (scf_tmpl_pg_description(pgt, NULL, &buf) > 0) {
11203 		if (templates == 2)
11204 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11205 			    gettext("description"), buf);
11206 		else
11207 			safe_printf("%s%s\n", TMPL_INDENT, buf);
11208 		free(buf);
11209 	}
11210 
11211 }
11212 
11213 /*
11214  * With as_value set to true, indent as appropriate for the value level.
11215  * If false, indent to appropriate level for inclusion in constraint
11216  * or choice printout.
11217  */
11218 static void
11219 print_template_value_details(scf_prop_tmpl_t *prt, const char *val_buf,
11220     int as_value)
11221 {
11222 	char *buf;
11223 
11224 	if (scf_tmpl_value_common_name(prt, NULL, val_buf, &buf) > 0) {
11225 		if (as_value == 0)
11226 			safe_printf("%s", TMPL_CHOICE_INDENT);
11227 		else
11228 			safe_printf("%s", TMPL_INDENT);
11229 		safe_printf("%s: %s\n", gettext("value common name"), buf);
11230 		free(buf);
11231 	}
11232 
11233 	if (scf_tmpl_value_description(prt, NULL, val_buf, &buf) > 0) {
11234 		if (as_value == 0)
11235 			safe_printf("%s", TMPL_CHOICE_INDENT);
11236 		else
11237 			safe_printf("%s", TMPL_INDENT);
11238 		safe_printf("%s: %s\n", gettext("value description"), buf);
11239 		free(buf);
11240 	}
11241 }
11242 
11243 static void
11244 print_template_value(scf_prop_tmpl_t *prt, const char *val_buf)
11245 {
11246 	safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("value"));
11247 	/* This is to be human-readable, so don't use CHARS_TO_QUOTE */
11248 	safe_printf("%s\n", val_buf);
11249 
11250 	print_template_value_details(prt, val_buf, 1);
11251 }
11252 
11253 static void
11254 print_template_constraints(scf_prop_tmpl_t *prt, int verbose)
11255 {
11256 	int i, printed = 0;
11257 	scf_values_t values;
11258 	scf_count_ranges_t c_ranges;
11259 	scf_int_ranges_t i_ranges;
11260 
11261 	printed = 0;
11262 	i = 0;
11263 	if (scf_tmpl_value_name_constraints(prt, &values) == 0) {
11264 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11265 		    gettext("value constraints"));
11266 		printed++;
11267 		for (i = 0; i < values.value_count; ++i) {
11268 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11269 			    gettext("value name"), values.values_as_strings[i]);
11270 			if (verbose == 1)
11271 				print_template_value_details(prt,
11272 				    values.values_as_strings[i], 0);
11273 		}
11274 
11275 		scf_values_destroy(&values);
11276 	}
11277 
11278 	if (scf_tmpl_value_count_range_constraints(prt, &c_ranges) == 0) {
11279 		if (printed++ == 0)
11280 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11281 			    gettext("value constraints"));
11282 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11283 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11284 			    gettext("range"), c_ranges.scr_min[i],
11285 			    c_ranges.scr_max[i]);
11286 		}
11287 		scf_count_ranges_destroy(&c_ranges);
11288 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11289 	    scf_tmpl_value_int_range_constraints(prt, &i_ranges) == 0) {
11290 		if (printed++ == 0)
11291 			safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11292 			    gettext("value constraints"));
11293 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11294 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11295 			    gettext("range"), i_ranges.sir_min[i],
11296 			    i_ranges.sir_max[i]);
11297 		}
11298 		scf_int_ranges_destroy(&i_ranges);
11299 	}
11300 }
11301 
11302 static void
11303 print_template_choices(scf_prop_tmpl_t *prt, int verbose)
11304 {
11305 	int i = 0, printed = 0;
11306 	scf_values_t values;
11307 	scf_count_ranges_t c_ranges;
11308 	scf_int_ranges_t i_ranges;
11309 
11310 	printed = 0;
11311 	if (scf_tmpl_value_name_choices(prt, &values) == 0) {
11312 		safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11313 		    gettext("value constraints"));
11314 		printed++;
11315 		for (i = 0; i < values.value_count; i++) {
11316 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11317 			    gettext("value name"), values.values_as_strings[i]);
11318 			if (verbose == 1)
11319 				print_template_value_details(prt,
11320 				    values.values_as_strings[i], 0);
11321 		}
11322 
11323 		scf_values_destroy(&values);
11324 	}
11325 
11326 	if (scf_tmpl_value_count_range_choices(prt, &c_ranges) == 0) {
11327 		for (i = 0; i < c_ranges.scr_num_ranges; ++i) {
11328 			if (printed++ == 0)
11329 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11330 				    gettext("value choices"));
11331 			safe_printf("%s%s: %llu to %llu\n", TMPL_INDENT,
11332 			    gettext("range"), c_ranges.scr_min[i],
11333 			    c_ranges.scr_max[i]);
11334 		}
11335 		scf_count_ranges_destroy(&c_ranges);
11336 	} else if (scf_error() == SCF_ERROR_CONSTRAINT_VIOLATED &&
11337 	    scf_tmpl_value_int_range_choices(prt, &i_ranges) == 0) {
11338 		for (i = 0; i < i_ranges.sir_num_ranges; ++i) {
11339 			if (printed++ == 0)
11340 				safe_printf("%s%s:\n", TMPL_VALUE_INDENT,
11341 				    gettext("value choices"));
11342 			safe_printf("%s%s: %lld to %lld\n", TMPL_INDENT,
11343 			    gettext("range"), i_ranges.sir_min[i],
11344 			    i_ranges.sir_max[i]);
11345 		}
11346 		scf_int_ranges_destroy(&i_ranges);
11347 	}
11348 }
11349 
11350 static void
11351 list_values_by_template(scf_prop_tmpl_t *prt)
11352 {
11353 	print_template_constraints(prt, 1);
11354 	print_template_choices(prt, 1);
11355 }
11356 
11357 static void
11358 list_values_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop)
11359 {
11360 	char *val_buf;
11361 	scf_iter_t *iter;
11362 	scf_value_t *val;
11363 	int ret;
11364 
11365 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
11366 	    (val = scf_value_create(g_hndl)) == NULL)
11367 		scfdie();
11368 
11369 	if (scf_iter_property_values(iter, prop) != SCF_SUCCESS)
11370 		scfdie();
11371 
11372 	val_buf = safe_malloc(max_scf_value_len + 1);
11373 
11374 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
11375 		if (scf_value_get_as_string(val, val_buf,
11376 		    max_scf_value_len + 1) < 0)
11377 			scfdie();
11378 
11379 		print_template_value(prt, val_buf);
11380 	}
11381 	if (ret != 0 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
11382 		scfdie();
11383 	free(val_buf);
11384 
11385 	print_template_constraints(prt, 0);
11386 	print_template_choices(prt, 0);
11387 
11388 }
11389 
11390 /*
11391  * Outputs property info for the describe subcommand
11392  * Verbose output if templates == 2, -v option of svccfg describe
11393  * Displays template data if prop is not NULL, -t option of svccfg describe
11394  */
11395 static void
11396 list_prop_tmpl(scf_prop_tmpl_t *prt, scf_property_t *prop, int templates)
11397 {
11398 	char *buf;
11399 	uint8_t u_buf;
11400 	int i;
11401 	uint64_t min, max;
11402 	scf_values_t values;
11403 
11404 	if (prt == NULL || templates == 0)
11405 		return;
11406 
11407 	if (prop == NULL) {
11408 		safe_printf("%s%s: ", TMPL_VALUE_INDENT, gettext("name"));
11409 		if (scf_tmpl_prop_name(prt, &buf) > 0) {
11410 			safe_printf("%s\n", buf);
11411 			free(buf);
11412 		} else
11413 			safe_printf("(%s)\n", gettext("any"));
11414 	}
11415 
11416 	if (prop == NULL || templates == 2) {
11417 		if (prop != NULL)
11418 			safe_printf("%s", TMPL_INDENT);
11419 		else
11420 			safe_printf("%s", TMPL_VALUE_INDENT);
11421 		safe_printf("%s: ", gettext("type"));
11422 		if ((buf = _scf_read_tmpl_prop_type_as_string(prt)) != NULL) {
11423 			safe_printf("%s\n", buf);
11424 			free(buf);
11425 		} else
11426 			safe_printf("(%s)\n", gettext("any"));
11427 	}
11428 
11429 	if (templates == 2 && scf_tmpl_prop_required(prt, &u_buf) == 0)
11430 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("required"),
11431 		    u_buf ? "true" : "false");
11432 
11433 	if (templates == 2 && scf_tmpl_prop_common_name(prt, NULL, &buf) > 0) {
11434 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("common name"),
11435 		    buf);
11436 		free(buf);
11437 	}
11438 
11439 	if (templates == 2 && scf_tmpl_prop_units(prt, NULL, &buf) > 0) {
11440 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("units"),
11441 		    buf);
11442 		free(buf);
11443 	}
11444 
11445 	if (scf_tmpl_prop_description(prt, NULL, &buf) > 0) {
11446 		safe_printf("%s%s\n", TMPL_INDENT, buf);
11447 		free(buf);
11448 	}
11449 
11450 	if (templates == 2 && scf_tmpl_prop_visibility(prt, &u_buf) == 0)
11451 		safe_printf("%s%s: %s\n", TMPL_INDENT, gettext("visibility"),
11452 		    scf_tmpl_visibility_to_string(u_buf));
11453 
11454 	if (templates == 2 && scf_tmpl_prop_cardinality(prt, &min, &max) == 0) {
11455 		safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11456 		    gettext("minimum number of values"), min);
11457 		if (max == ULLONG_MAX) {
11458 			safe_printf("%s%s: %s\n", TMPL_INDENT,
11459 			    gettext("maximum number of values"),
11460 			    gettext("unlimited"));
11461 		} else {
11462 			safe_printf("%s%s: %" PRIu64 "\n", TMPL_INDENT,
11463 			    gettext("maximum number of values"), max);
11464 		}
11465 	}
11466 
11467 	if (templates == 2 && scf_tmpl_prop_internal_seps(prt, &values) == 0) {
11468 		for (i = 0; i < values.value_count; i++) {
11469 			if (i == 0) {
11470 				safe_printf("%s%s:", TMPL_INDENT,
11471 				    gettext("internal separators"));
11472 			}
11473 			safe_printf(" \"%s\"", values.values_as_strings[i]);
11474 		}
11475 		safe_printf("\n");
11476 	}
11477 
11478 	if (templates != 2)
11479 		return;
11480 
11481 	if (prop != NULL)
11482 		list_values_tmpl(prt, prop);
11483 	else
11484 		list_values_by_template(prt);
11485 }
11486 
11487 static char *
11488 read_astring(scf_propertygroup_t *pg, const char *prop_name)
11489 {
11490 	char *rv;
11491 
11492 	rv = _scf_read_single_astring_from_pg(pg, prop_name);
11493 	if (rv == NULL) {
11494 		switch (scf_error()) {
11495 		case SCF_ERROR_NOT_FOUND:
11496 			break;
11497 		default:
11498 			scfdie();
11499 		}
11500 	}
11501 	return (rv);
11502 }
11503 
11504 static void
11505 display_documentation(scf_iter_t *iter, scf_propertygroup_t *pg)
11506 {
11507 	size_t doc_len;
11508 	size_t man_len;
11509 	char *pg_name;
11510 	char *text = NULL;
11511 	int rv;
11512 
11513 	doc_len = strlen(SCF_PG_TM_DOC_PREFIX);
11514 	man_len = strlen(SCF_PG_TM_MAN_PREFIX);
11515 	pg_name = safe_malloc(max_scf_name_len + 1);
11516 	while ((rv = scf_iter_next_pg(iter, pg)) == 1) {
11517 		if (scf_pg_get_name(pg, pg_name, max_scf_name_len + 1) == -1) {
11518 			scfdie();
11519 		}
11520 		if (strncmp(pg_name, SCF_PG_TM_DOC_PREFIX, doc_len) == 0) {
11521 			/* Display doc_link and and uri */
11522 			safe_printf("%s%s:\n", TMPL_INDENT,
11523 			    gettext("doc_link"));
11524 			text = read_astring(pg, SCF_PROPERTY_TM_NAME);
11525 			if (text != NULL) {
11526 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11527 				    TMPL_INDENT, gettext("name"), text);
11528 				uu_free(text);
11529 			}
11530 			text = read_astring(pg, SCF_PROPERTY_TM_URI);
11531 			if (text != NULL) {
11532 				safe_printf("%s%s: %s\n", TMPL_INDENT_2X,
11533 				    gettext("uri"), text);
11534 				uu_free(text);
11535 			}
11536 		} else if (strncmp(pg_name, SCF_PG_TM_MAN_PREFIX,
11537 		    man_len) == 0) {
11538 			/* Display manpage title, section and path */
11539 			safe_printf("%s%s:\n", TMPL_INDENT,
11540 			    gettext("manpage"));
11541 			text = read_astring(pg, SCF_PROPERTY_TM_TITLE);
11542 			if (text != NULL) {
11543 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11544 				    TMPL_INDENT, gettext("title"), text);
11545 				uu_free(text);
11546 			}
11547 			text = read_astring(pg, SCF_PROPERTY_TM_SECTION);
11548 			if (text != NULL) {
11549 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11550 				    TMPL_INDENT, gettext("section"), text);
11551 				uu_free(text);
11552 			}
11553 			text = read_astring(pg, SCF_PROPERTY_TM_MANPATH);
11554 			if (text != NULL) {
11555 				safe_printf("%s%s%s: %s\n", TMPL_INDENT,
11556 				    TMPL_INDENT, gettext("manpath"), text);
11557 				uu_free(text);
11558 			}
11559 		}
11560 	}
11561 	if (rv == -1)
11562 		scfdie();
11563 
11564 done:
11565 	free(pg_name);
11566 }
11567 
11568 static void
11569 list_entity_tmpl(int templates)
11570 {
11571 	char *common_name = NULL;
11572 	char *description = NULL;
11573 	char *locale = NULL;
11574 	scf_iter_t *iter;
11575 	scf_propertygroup_t *pg;
11576 	scf_property_t *prop;
11577 	int r;
11578 	scf_value_t *val;
11579 
11580 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11581 	    (prop = scf_property_create(g_hndl)) == NULL ||
11582 	    (val = scf_value_create(g_hndl)) == NULL ||
11583 	    (iter = scf_iter_create(g_hndl)) == NULL)
11584 		scfdie();
11585 
11586 	locale = setlocale(LC_MESSAGES, NULL);
11587 
11588 	if (get_pg(SCF_PG_TM_COMMON_NAME, pg) == 0) {
11589 		common_name = safe_malloc(max_scf_value_len + 1);
11590 
11591 		/* Try both the current locale and the "C" locale. */
11592 		if (scf_pg_get_property(pg, locale, prop) == 0 ||
11593 		    (scf_error() == SCF_ERROR_NOT_FOUND &&
11594 		    scf_pg_get_property(pg, "C", prop) == 0)) {
11595 			if (prop_get_val(prop, val) == 0 &&
11596 			    scf_value_get_ustring(val, common_name,
11597 			    max_scf_value_len + 1) != -1) {
11598 				safe_printf("%s%s: %s\n", TMPL_INDENT,
11599 				    gettext("common name"), common_name);
11600 			}
11601 		}
11602 	}
11603 
11604 	/*
11605 	 * Do description, manpages, and doc links if templates == 2.
11606 	 */
11607 	if (templates == 2) {
11608 		/* Get the description. */
11609 		if (get_pg(SCF_PG_TM_DESCRIPTION, pg) == 0) {
11610 			description = safe_malloc(max_scf_value_len + 1);
11611 
11612 			/* Try both the current locale and the "C" locale. */
11613 			if (scf_pg_get_property(pg, locale, prop) == 0 ||
11614 			    (scf_error() == SCF_ERROR_NOT_FOUND &&
11615 			    scf_pg_get_property(pg, "C", prop) == 0)) {
11616 				if (prop_get_val(prop, val) == 0 &&
11617 				    scf_value_get_ustring(val, description,
11618 				    max_scf_value_len + 1) != -1) {
11619 					safe_printf("%s%s: %s\n", TMPL_INDENT,
11620 					    gettext("description"),
11621 					    description);
11622 				}
11623 			}
11624 		}
11625 
11626 		/* Process doc_link & manpage elements. */
11627 		if (cur_level != NULL) {
11628 			r = scf_iter_snaplevel_pgs_typed(iter, cur_level,
11629 			    SCF_GROUP_TEMPLATE);
11630 		} else if (cur_inst != NULL) {
11631 			r = scf_iter_instance_pgs_typed(iter, cur_inst,
11632 			    SCF_GROUP_TEMPLATE);
11633 		} else {
11634 			r = scf_iter_service_pgs_typed(iter, cur_svc,
11635 			    SCF_GROUP_TEMPLATE);
11636 		}
11637 		if (r == 0) {
11638 			display_documentation(iter, pg);
11639 		}
11640 	}
11641 
11642 	free(common_name);
11643 	free(description);
11644 	scf_pg_destroy(pg);
11645 	scf_property_destroy(prop);
11646 	scf_value_destroy(val);
11647 	scf_iter_destroy(iter);
11648 }
11649 
11650 static void
11651 listtmpl(const char *pattern, int templates)
11652 {
11653 	scf_pg_tmpl_t *pgt;
11654 	scf_prop_tmpl_t *prt;
11655 	char *snapbuf = NULL;
11656 	char *fmribuf;
11657 	char *pg_name = NULL, *prop_name = NULL;
11658 	ssize_t prop_name_size;
11659 	char *qual_prop_name;
11660 	char *search_name;
11661 	int listed = 0;
11662 
11663 	if ((pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
11664 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL)
11665 		scfdie();
11666 
11667 	fmribuf = safe_malloc(max_scf_name_len + 1);
11668 	qual_prop_name = safe_malloc(max_scf_name_len + 1);
11669 
11670 	if (cur_snap != NULL) {
11671 		snapbuf = safe_malloc(max_scf_name_len + 1);
11672 		if (scf_snapshot_get_name(cur_snap, snapbuf,
11673 		    max_scf_name_len + 1) < 0)
11674 			scfdie();
11675 	}
11676 
11677 	if (cur_inst != NULL) {
11678 		if (scf_instance_to_fmri(cur_inst, fmribuf,
11679 		    max_scf_name_len + 1) < 0)
11680 			scfdie();
11681 	} else if (cur_svc != NULL) {
11682 		if (scf_service_to_fmri(cur_svc, fmribuf,
11683 		    max_scf_name_len + 1) < 0)
11684 			scfdie();
11685 	} else
11686 		abort();
11687 
11688 	/* If pattern is specified, we want to list only those items. */
11689 	while (scf_tmpl_iter_pgs(pgt, fmribuf, snapbuf, NULL, NULL) == 1) {
11690 		listed = 0;
11691 		if (pattern == NULL || (scf_tmpl_pg_name(pgt, &pg_name) > 0 &&
11692 		    fnmatch(pattern, pg_name, 0) == 0)) {
11693 			list_pg_tmpl(pgt, NULL, templates);
11694 			listed++;
11695 		}
11696 
11697 		scf_tmpl_prop_reset(prt);
11698 
11699 		while (scf_tmpl_iter_props(pgt, prt, NULL) == 0) {
11700 			search_name = NULL;
11701 			prop_name_size = scf_tmpl_prop_name(prt, &prop_name);
11702 			if ((prop_name_size > 0) && (pg_name != NULL)) {
11703 				if (snprintf(qual_prop_name,
11704 				    max_scf_name_len + 1, "%s/%s",
11705 				    pg_name, prop_name) >=
11706 				    max_scf_name_len + 1) {
11707 					prop_name_size = -1;
11708 				} else {
11709 					search_name = qual_prop_name;
11710 				}
11711 			}
11712 			if (listed > 0 || pattern == NULL ||
11713 			    (prop_name_size > 0 &&
11714 			    fnmatch(pattern, search_name,
11715 			    FNM_PATHNAME) == 0))
11716 				list_prop_tmpl(prt, NULL, templates);
11717 			if (prop_name != NULL) {
11718 				free(prop_name);
11719 				prop_name = NULL;
11720 			}
11721 		}
11722 		if (pg_name != NULL) {
11723 			free(pg_name);
11724 			pg_name = NULL;
11725 		}
11726 	}
11727 
11728 	scf_tmpl_prop_destroy(prt);
11729 	scf_tmpl_pg_destroy(pgt);
11730 	free(snapbuf);
11731 	free(fmribuf);
11732 	free(qual_prop_name);
11733 }
11734 
11735 static void
11736 listprop(const char *pattern, int only_pgs, int templates)
11737 {
11738 	scf_propertygroup_t *pg;
11739 	scf_property_t *prop;
11740 	scf_iter_t *iter, *piter;
11741 	char *pgnbuf, *prnbuf, *ppnbuf;
11742 	scf_pg_tmpl_t *pgt, *pgtp;
11743 	scf_prop_tmpl_t *prt;
11744 
11745 	void **objects;
11746 	char **names;
11747 	void **tmpls;
11748 	int allocd, i;
11749 
11750 	int ret;
11751 	ssize_t pgnlen, prnlen, szret;
11752 	size_t max_len = 0;
11753 
11754 	if (cur_svc == NULL && cur_inst == NULL) {
11755 		semerr(emsg_entity_not_selected);
11756 		return;
11757 	}
11758 
11759 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
11760 	    (prop = scf_property_create(g_hndl)) == NULL ||
11761 	    (iter = scf_iter_create(g_hndl)) == NULL ||
11762 	    (piter = scf_iter_create(g_hndl)) == NULL ||
11763 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
11764 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL)
11765 		scfdie();
11766 
11767 	prnbuf = safe_malloc(max_scf_name_len + 1);
11768 
11769 	if (cur_level != NULL)
11770 		ret = scf_iter_snaplevel_pgs(iter, cur_level);
11771 	else if (cur_inst != NULL)
11772 		ret = scf_iter_instance_pgs(iter, cur_inst);
11773 	else
11774 		ret = scf_iter_service_pgs(iter, cur_svc);
11775 	if (ret != 0) {
11776 		return;
11777 	}
11778 
11779 	/*
11780 	 * We want to only list items which match pattern, and we want the
11781 	 * second column to line up, so during the first pass we'll save
11782 	 * matching items, their names, and their templates in objects,
11783 	 * names, and tmpls, computing the maximum name length as we go,
11784 	 * and then we'll print them out.
11785 	 *
11786 	 * Note: We always keep an extra slot available so the array can be
11787 	 * NULL-terminated.
11788 	 */
11789 	i = 0;
11790 	allocd = 1;
11791 	objects = safe_malloc(sizeof (*objects));
11792 	names = safe_malloc(sizeof (*names));
11793 	tmpls = safe_malloc(sizeof (*tmpls));
11794 
11795 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
11796 		int new_pg = 0;
11797 		int print_props = 0;
11798 		pgtp = NULL;
11799 
11800 		pgnlen = scf_pg_get_name(pg, NULL, 0);
11801 		if (pgnlen < 0)
11802 			scfdie();
11803 
11804 		pgnbuf = safe_malloc(pgnlen + 1);
11805 
11806 		szret = scf_pg_get_name(pg, pgnbuf, pgnlen + 1);
11807 		if (szret < 0)
11808 			scfdie();
11809 		assert(szret <= pgnlen);
11810 
11811 		if (scf_tmpl_get_by_pg(pg, pgt, NULL) == -1) {
11812 			if (scf_error() != SCF_ERROR_NOT_FOUND)
11813 				scfdie();
11814 			pgtp = NULL;
11815 		} else {
11816 			pgtp = pgt;
11817 		}
11818 
11819 		if (pattern == NULL ||
11820 		    fnmatch(pattern, pgnbuf, 0) == 0) {
11821 			if (i+1 >= allocd) {
11822 				allocd *= 2;
11823 				objects = realloc(objects,
11824 				    sizeof (*objects) * allocd);
11825 				names =
11826 				    realloc(names, sizeof (*names) * allocd);
11827 				tmpls = realloc(tmpls,
11828 				    sizeof (*tmpls) * allocd);
11829 				if (objects == NULL || names == NULL ||
11830 				    tmpls == NULL)
11831 					uu_die(gettext("Out of memory"));
11832 			}
11833 			objects[i] = pg;
11834 			names[i] = pgnbuf;
11835 
11836 			if (pgtp == NULL)
11837 				tmpls[i] = NULL;
11838 			else
11839 				tmpls[i] = pgt;
11840 
11841 			++i;
11842 
11843 			if (pgnlen > max_len)
11844 				max_len = pgnlen;
11845 
11846 			new_pg = 1;
11847 			print_props = 1;
11848 		}
11849 
11850 		if (only_pgs) {
11851 			if (new_pg) {
11852 				pg = scf_pg_create(g_hndl);
11853 				if (pg == NULL)
11854 					scfdie();
11855 				pgt = scf_tmpl_pg_create(g_hndl);
11856 				if (pgt == NULL)
11857 					scfdie();
11858 			} else
11859 				free(pgnbuf);
11860 
11861 			continue;
11862 		}
11863 
11864 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
11865 			scfdie();
11866 
11867 		while ((ret = scf_iter_next_property(piter, prop)) == 1) {
11868 			prnlen = scf_property_get_name(prop, prnbuf,
11869 			    max_scf_name_len + 1);
11870 			if (prnlen < 0)
11871 				scfdie();
11872 
11873 			/* Will prepend the property group name and a slash. */
11874 			prnlen += pgnlen + 1;
11875 
11876 			ppnbuf = safe_malloc(prnlen + 1);
11877 
11878 			if (snprintf(ppnbuf, prnlen + 1, "%s/%s", pgnbuf,
11879 			    prnbuf) < 0)
11880 				uu_die("snprintf");
11881 
11882 			if (pattern == NULL || print_props == 1 ||
11883 			    fnmatch(pattern, ppnbuf, 0) == 0) {
11884 				if (i+1 >= allocd) {
11885 					allocd *= 2;
11886 					objects = realloc(objects,
11887 					    sizeof (*objects) * allocd);
11888 					names = realloc(names,
11889 					    sizeof (*names) * allocd);
11890 					tmpls = realloc(tmpls,
11891 					    sizeof (*tmpls) * allocd);
11892 					if (objects == NULL || names == NULL ||
11893 					    tmpls == NULL)
11894 						uu_die(gettext(
11895 						    "Out of memory"));
11896 				}
11897 
11898 				objects[i] = prop;
11899 				names[i] = ppnbuf;
11900 
11901 				if (pgtp != NULL) {
11902 					if (scf_tmpl_get_by_prop(pgt, prnbuf,
11903 					    prt, NULL) < 0) {
11904 						if (scf_error() !=
11905 						    SCF_ERROR_NOT_FOUND)
11906 							scfdie();
11907 						tmpls[i] = NULL;
11908 					} else {
11909 						tmpls[i] = prt;
11910 					}
11911 				} else {
11912 					tmpls[i] = NULL;
11913 				}
11914 
11915 				++i;
11916 
11917 				if (prnlen > max_len)
11918 					max_len = prnlen;
11919 
11920 				prop = scf_property_create(g_hndl);
11921 				prt = scf_tmpl_prop_create(g_hndl);
11922 			} else {
11923 				free(ppnbuf);
11924 			}
11925 		}
11926 
11927 		if (new_pg) {
11928 			pg = scf_pg_create(g_hndl);
11929 			if (pg == NULL)
11930 				scfdie();
11931 			pgt = scf_tmpl_pg_create(g_hndl);
11932 			if (pgt == NULL)
11933 				scfdie();
11934 		} else
11935 			free(pgnbuf);
11936 	}
11937 	if (ret != 0)
11938 		scfdie();
11939 
11940 	objects[i] = NULL;
11941 
11942 	scf_pg_destroy(pg);
11943 	scf_tmpl_pg_destroy(pgt);
11944 	scf_property_destroy(prop);
11945 	scf_tmpl_prop_destroy(prt);
11946 
11947 	for (i = 0; objects[i] != NULL; ++i) {
11948 		if (strchr(names[i], '/') == NULL) {
11949 			/* property group */
11950 			pg = (scf_propertygroup_t *)objects[i];
11951 			pgt = (scf_pg_tmpl_t *)tmpls[i];
11952 			list_pg_info(pg, names[i], max_len);
11953 			list_pg_tmpl(pgt, pg, templates);
11954 			free(names[i]);
11955 			scf_pg_destroy(pg);
11956 			if (pgt != NULL)
11957 				scf_tmpl_pg_destroy(pgt);
11958 		} else {
11959 			/* property */
11960 			prop = (scf_property_t *)objects[i];
11961 			prt = (scf_prop_tmpl_t *)tmpls[i];
11962 			list_prop_info(prop, names[i], max_len);
11963 			list_prop_tmpl(prt, prop, templates);
11964 			free(names[i]);
11965 			scf_property_destroy(prop);
11966 			if (prt != NULL)
11967 				scf_tmpl_prop_destroy(prt);
11968 		}
11969 	}
11970 
11971 	free(names);
11972 	free(objects);
11973 	free(tmpls);
11974 }
11975 
11976 void
11977 lscf_listpg(const char *pattern)
11978 {
11979 	lscf_prep_hndl();
11980 
11981 	listprop(pattern, 1, 0);
11982 }
11983 
11984 /*
11985  * Property group and property creation, setting, and deletion.  setprop (and
11986  * its alias, addprop) can either create a property group of a given type, or
11987  * it can create or set a property to a given type and list of values.
11988  */
11989 void
11990 lscf_addpg(const char *name, const char *type, const char *flags)
11991 {
11992 	scf_propertygroup_t *pg;
11993 	int ret;
11994 	uint32_t flgs = 0;
11995 	const char *cp;
11996 
11997 
11998 	lscf_prep_hndl();
11999 
12000 	if (cur_snap != NULL) {
12001 		semerr(emsg_cant_modify_snapshots);
12002 		return;
12003 	}
12004 
12005 	if (cur_inst == NULL && cur_svc == NULL) {
12006 		semerr(emsg_entity_not_selected);
12007 		return;
12008 	}
12009 
12010 	if (flags != NULL) {
12011 		for (cp = flags; *cp != '\0'; ++cp) {
12012 			switch (*cp) {
12013 			case 'P':
12014 				flgs |= SCF_PG_FLAG_NONPERSISTENT;
12015 				break;
12016 
12017 			case 'p':
12018 				flgs &= ~SCF_PG_FLAG_NONPERSISTENT;
12019 				break;
12020 
12021 			default:
12022 				semerr(gettext("Invalid property group flag "
12023 				    "%c."), *cp);
12024 				return;
12025 			}
12026 		}
12027 	}
12028 
12029 	pg = scf_pg_create(g_hndl);
12030 	if (pg == NULL)
12031 		scfdie();
12032 
12033 	if (cur_inst != NULL)
12034 		ret = scf_instance_add_pg(cur_inst, name, type, flgs, pg);
12035 	else
12036 		ret = scf_service_add_pg(cur_svc, name, type, flgs, pg);
12037 
12038 	if (ret != SCF_SUCCESS) {
12039 		switch (scf_error()) {
12040 		case SCF_ERROR_INVALID_ARGUMENT:
12041 			semerr(gettext("Name, type, or flags are invalid.\n"));
12042 			break;
12043 
12044 		case SCF_ERROR_EXISTS:
12045 			semerr(gettext("Property group already exists.\n"));
12046 			break;
12047 
12048 		case SCF_ERROR_PERMISSION_DENIED:
12049 			semerr(emsg_permission_denied);
12050 			break;
12051 
12052 		case SCF_ERROR_BACKEND_ACCESS:
12053 			semerr(gettext("Backend refused access.\n"));
12054 			break;
12055 
12056 		default:
12057 			scfdie();
12058 		}
12059 	}
12060 
12061 	scf_pg_destroy(pg);
12062 
12063 	private_refresh();
12064 }
12065 
12066 void
12067 lscf_delpg(char *name)
12068 {
12069 	lscf_prep_hndl();
12070 
12071 	if (cur_snap != NULL) {
12072 		semerr(emsg_cant_modify_snapshots);
12073 		return;
12074 	}
12075 
12076 	if (cur_inst == NULL && cur_svc == NULL) {
12077 		semerr(emsg_entity_not_selected);
12078 		return;
12079 	}
12080 
12081 	if (strchr(name, '/') != NULL) {
12082 		semerr(emsg_invalid_pg_name, name);
12083 		return;
12084 	}
12085 
12086 	lscf_delprop(name);
12087 }
12088 
12089 /*
12090  * scf_delhash() is used to remove the property group related to the
12091  * hash entry for a specific manifest in the repository. pgname will be
12092  * constructed from the location of the manifest file. If deathrow isn't 0,
12093  * manifest file doesn't need to exist (manifest string will be used as
12094  * an absolute path).
12095  */
12096 void
12097 lscf_delhash(char *manifest, int deathrow)
12098 {
12099 	char *pgname;
12100 
12101 	if (cur_snap != NULL ||
12102 	    cur_inst != NULL || cur_svc != NULL) {
12103 		warn(gettext("error, an entity is selected\n"));
12104 		return;
12105 	}
12106 
12107 	/* select smf/manifest */
12108 	lscf_select("smf/manifest");
12109 	/*
12110 	 * Translate the manifest file name to property name. In the deathrow
12111 	 * case, the manifest file does not need to exist.
12112 	 */
12113 	pgname = mhash_filename_to_propname(manifest,
12114 	    deathrow ? B_TRUE : B_FALSE);
12115 	if (pgname == NULL) {
12116 		warn(gettext("cannot resolve pathname for %s\n"), manifest);
12117 		return;
12118 	}
12119 	/* delete the hash property name */
12120 	lscf_delpg(pgname);
12121 }
12122 
12123 void
12124 lscf_listprop(const char *pattern)
12125 {
12126 	lscf_prep_hndl();
12127 
12128 	listprop(pattern, 0, 0);
12129 }
12130 
12131 int
12132 lscf_setprop(const char *pgname, const char *type, const char *value,
12133     const uu_list_t *values)
12134 {
12135 	scf_type_t ty, current_ty;
12136 	scf_service_t *svc;
12137 	scf_propertygroup_t *pg, *parent_pg;
12138 	scf_property_t *prop, *parent_prop;
12139 	scf_pg_tmpl_t *pgt;
12140 	scf_prop_tmpl_t *prt;
12141 	int ret, result = 0;
12142 	scf_transaction_t *tx;
12143 	scf_transaction_entry_t *e;
12144 	scf_value_t *v;
12145 	uu_list_walk_t *walk;
12146 	string_list_t *sp;
12147 	char *propname;
12148 	int req_quotes = 0;
12149 
12150 	lscf_prep_hndl();
12151 
12152 	if ((e = scf_entry_create(g_hndl)) == NULL ||
12153 	    (svc = scf_service_create(g_hndl)) == NULL ||
12154 	    (parent_pg = scf_pg_create(g_hndl)) == NULL ||
12155 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12156 	    (parent_prop = scf_property_create(g_hndl)) == NULL ||
12157 	    (prop = scf_property_create(g_hndl)) == NULL ||
12158 	    (pgt = scf_tmpl_pg_create(g_hndl)) == NULL ||
12159 	    (prt = scf_tmpl_prop_create(g_hndl)) == NULL ||
12160 	    (tx = scf_transaction_create(g_hndl)) == NULL)
12161 		scfdie();
12162 
12163 	if (cur_snap != NULL) {
12164 		semerr(emsg_cant_modify_snapshots);
12165 		goto fail;
12166 	}
12167 
12168 	if (cur_inst == NULL && cur_svc == NULL) {
12169 		semerr(emsg_entity_not_selected);
12170 		goto fail;
12171 	}
12172 
12173 	propname = strchr(pgname, '/');
12174 	if (propname == NULL) {
12175 		semerr(gettext("Property names must contain a `/'.\n"));
12176 		goto fail;
12177 	}
12178 
12179 	*propname = '\0';
12180 	++propname;
12181 
12182 	if (type != NULL) {
12183 		ty = string_to_type(type);
12184 		if (ty == SCF_TYPE_INVALID) {
12185 			semerr(gettext("Unknown type \"%s\".\n"), type);
12186 			goto fail;
12187 		}
12188 	}
12189 
12190 	if (cur_inst != NULL)
12191 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12192 	else
12193 		ret = scf_service_get_pg(cur_svc, pgname, pg);
12194 	if (ret != SCF_SUCCESS) {
12195 		switch (scf_error()) {
12196 		case SCF_ERROR_NOT_FOUND:
12197 			semerr(emsg_no_such_pg, pgname);
12198 			goto fail;
12199 
12200 		case SCF_ERROR_INVALID_ARGUMENT:
12201 			semerr(emsg_invalid_pg_name, pgname);
12202 			goto fail;
12203 
12204 		default:
12205 			scfdie();
12206 			break;
12207 		}
12208 	}
12209 
12210 	do {
12211 		if (scf_pg_update(pg) == -1)
12212 			scfdie();
12213 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12214 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12215 				scfdie();
12216 
12217 			semerr(emsg_permission_denied);
12218 			goto fail;
12219 		}
12220 
12221 		ret = scf_pg_get_property(pg, propname, prop);
12222 		if (ret == SCF_SUCCESS) {
12223 			if (scf_property_type(prop, &current_ty) != SCF_SUCCESS)
12224 				scfdie();
12225 
12226 			if (type == NULL)
12227 				ty = current_ty;
12228 			if (scf_transaction_property_change_type(tx, e,
12229 			    propname, ty) == -1)
12230 				scfdie();
12231 
12232 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12233 			/* Infer the type, if possible. */
12234 			if (type == NULL) {
12235 				/*
12236 				 * First check if we're an instance and the
12237 				 * property is set on the service.
12238 				 */
12239 				if (cur_inst != NULL &&
12240 				    scf_instance_get_parent(cur_inst,
12241 				    svc) == 0 &&
12242 				    scf_service_get_pg(cur_svc, pgname,
12243 				    parent_pg) == 0 &&
12244 				    scf_pg_get_property(parent_pg, propname,
12245 				    parent_prop) == 0 &&
12246 				    scf_property_type(parent_prop,
12247 				    &current_ty) == 0) {
12248 					ty = current_ty;
12249 
12250 				/* Then check for a type set in a template. */
12251 				} else if (scf_tmpl_get_by_pg(pg, pgt,
12252 				    NULL) == 0 &&
12253 				    scf_tmpl_get_by_prop(pgt, propname, prt,
12254 				    NULL) == 0 &&
12255 				    scf_tmpl_prop_type(prt, &current_ty) == 0) {
12256 					ty = current_ty;
12257 
12258 				/* If type can't be inferred, fail. */
12259 				} else {
12260 					semerr(gettext("Type required for new "
12261 					    "properties.\n"));
12262 					goto fail;
12263 				}
12264 			}
12265 			if (scf_transaction_property_new(tx, e, propname,
12266 			    ty) == -1)
12267 				scfdie();
12268 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12269 			semerr(emsg_invalid_prop_name, propname);
12270 			goto fail;
12271 		} else {
12272 			scfdie();
12273 		}
12274 
12275 		if (ty == SCF_TYPE_ASTRING || ty == SCF_TYPE_USTRING)
12276 			req_quotes = 1;
12277 
12278 		if (value != NULL) {
12279 			v = string_to_value(value, ty, 0);
12280 
12281 			if (v == NULL)
12282 				goto fail;
12283 
12284 			ret = scf_entry_add_value(e, v);
12285 			assert(ret == SCF_SUCCESS);
12286 		} else {
12287 			assert(values != NULL);
12288 
12289 			walk = uu_list_walk_start((uu_list_t *)values,
12290 			    UU_DEFAULT);
12291 			if (walk == NULL)
12292 				uu_die(gettext("Could not walk list"));
12293 
12294 			for (sp = uu_list_walk_next(walk); sp != NULL;
12295 			    sp = uu_list_walk_next(walk)) {
12296 				v = string_to_value(sp->str, ty, req_quotes);
12297 
12298 				if (v == NULL) {
12299 					scf_entry_destroy_children(e);
12300 					goto fail;
12301 				}
12302 
12303 				ret = scf_entry_add_value(e, v);
12304 				assert(ret == SCF_SUCCESS);
12305 			}
12306 			uu_list_walk_end(walk);
12307 		}
12308 		result = scf_transaction_commit(tx);
12309 
12310 		scf_transaction_reset(tx);
12311 		scf_entry_destroy_children(e);
12312 	} while (result == 0);
12313 
12314 	if (result < 0) {
12315 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12316 			scfdie();
12317 
12318 		semerr(emsg_permission_denied);
12319 		goto fail;
12320 	}
12321 
12322 	ret = 0;
12323 
12324 	private_refresh();
12325 
12326 	goto cleanup;
12327 
12328 fail:
12329 	ret = -1;
12330 
12331 cleanup:
12332 	scf_transaction_destroy(tx);
12333 	scf_entry_destroy(e);
12334 	scf_service_destroy(svc);
12335 	scf_pg_destroy(parent_pg);
12336 	scf_pg_destroy(pg);
12337 	scf_property_destroy(parent_prop);
12338 	scf_property_destroy(prop);
12339 	scf_tmpl_pg_destroy(pgt);
12340 	scf_tmpl_prop_destroy(prt);
12341 
12342 	return (ret);
12343 }
12344 
12345 void
12346 lscf_delprop(char *pgn)
12347 {
12348 	char *slash, *pn;
12349 	scf_propertygroup_t *pg;
12350 	scf_transaction_t *tx;
12351 	scf_transaction_entry_t *e;
12352 	int ret;
12353 
12354 
12355 	lscf_prep_hndl();
12356 
12357 	if (cur_snap != NULL) {
12358 		semerr(emsg_cant_modify_snapshots);
12359 		return;
12360 	}
12361 
12362 	if (cur_inst == NULL && cur_svc == NULL) {
12363 		semerr(emsg_entity_not_selected);
12364 		return;
12365 	}
12366 
12367 	pg = scf_pg_create(g_hndl);
12368 	if (pg == NULL)
12369 		scfdie();
12370 
12371 	slash = strchr(pgn, '/');
12372 	if (slash == NULL) {
12373 		pn = NULL;
12374 	} else {
12375 		*slash = '\0';
12376 		pn = slash + 1;
12377 	}
12378 
12379 	if (cur_inst != NULL)
12380 		ret = scf_instance_get_pg(cur_inst, pgn, pg);
12381 	else
12382 		ret = scf_service_get_pg(cur_svc, pgn, pg);
12383 	if (ret != SCF_SUCCESS) {
12384 		switch (scf_error()) {
12385 		case SCF_ERROR_NOT_FOUND:
12386 			semerr(emsg_no_such_pg, pgn);
12387 			break;
12388 
12389 		case SCF_ERROR_INVALID_ARGUMENT:
12390 			semerr(emsg_invalid_pg_name, pgn);
12391 			break;
12392 
12393 		default:
12394 			scfdie();
12395 		}
12396 
12397 		scf_pg_destroy(pg);
12398 
12399 		return;
12400 	}
12401 
12402 	if (pn == NULL) {
12403 		/* Try to delete the property group. */
12404 		if (scf_pg_delete(pg) != SCF_SUCCESS) {
12405 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12406 				scfdie();
12407 
12408 			semerr(emsg_permission_denied);
12409 		} else {
12410 			private_refresh();
12411 		}
12412 
12413 		scf_pg_destroy(pg);
12414 		return;
12415 	}
12416 
12417 	e = scf_entry_create(g_hndl);
12418 	tx = scf_transaction_create(g_hndl);
12419 
12420 	do {
12421 		if (scf_pg_update(pg) == -1)
12422 			scfdie();
12423 		if (scf_transaction_start(tx, pg) != SCF_SUCCESS) {
12424 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12425 				scfdie();
12426 
12427 			semerr(emsg_permission_denied);
12428 			break;
12429 		}
12430 
12431 		if (scf_transaction_property_delete(tx, e, pn) != SCF_SUCCESS) {
12432 			if (scf_error() == SCF_ERROR_NOT_FOUND) {
12433 				semerr(gettext("No such property %s/%s.\n"),
12434 				    pgn, pn);
12435 				break;
12436 			} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12437 				semerr(emsg_invalid_prop_name, pn);
12438 				break;
12439 			} else {
12440 				scfdie();
12441 			}
12442 		}
12443 
12444 		ret = scf_transaction_commit(tx);
12445 
12446 		if (ret == 0)
12447 			scf_transaction_reset(tx);
12448 	} while (ret == 0);
12449 
12450 	if (ret < 0) {
12451 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12452 			scfdie();
12453 
12454 		semerr(emsg_permission_denied);
12455 	} else {
12456 		private_refresh();
12457 	}
12458 
12459 	scf_transaction_destroy(tx);
12460 	scf_entry_destroy(e);
12461 	scf_pg_destroy(pg);
12462 }
12463 
12464 /*
12465  * Property editing.
12466  */
12467 
12468 static int
12469 write_edit_script(FILE *strm)
12470 {
12471 	char *fmribuf;
12472 	ssize_t fmrilen;
12473 
12474 	scf_propertygroup_t *pg;
12475 	scf_property_t *prop;
12476 	scf_value_t *val;
12477 	scf_type_t ty;
12478 	int ret, result = 0;
12479 	scf_iter_t *iter, *piter, *viter;
12480 	char *buf, *tybuf, *pname;
12481 	const char *emsg_write_error;
12482 
12483 
12484 	emsg_write_error = gettext("Error writing temoprary file: %s.\n");
12485 
12486 
12487 	/* select fmri */
12488 	if (cur_inst != NULL) {
12489 		fmrilen = scf_instance_to_fmri(cur_inst, NULL, 0);
12490 		if (fmrilen < 0)
12491 			scfdie();
12492 		fmribuf = safe_malloc(fmrilen + 1);
12493 		if (scf_instance_to_fmri(cur_inst, fmribuf, fmrilen + 1) < 0)
12494 			scfdie();
12495 	} else {
12496 		assert(cur_svc != NULL);
12497 		fmrilen = scf_service_to_fmri(cur_svc, NULL, 0);
12498 		if (fmrilen < 0)
12499 			scfdie();
12500 		fmribuf = safe_malloc(fmrilen + 1);
12501 		if (scf_service_to_fmri(cur_svc, fmribuf, fmrilen + 1) < 0)
12502 			scfdie();
12503 	}
12504 
12505 	if (fprintf(strm, "select %s\n\n", fmribuf) < 0) {
12506 		warn(emsg_write_error, strerror(errno));
12507 		free(fmribuf);
12508 		return (-1);
12509 	}
12510 
12511 	free(fmribuf);
12512 
12513 
12514 	if ((pg = scf_pg_create(g_hndl)) == NULL ||
12515 	    (prop = scf_property_create(g_hndl)) == NULL ||
12516 	    (val = scf_value_create(g_hndl)) == NULL ||
12517 	    (iter = scf_iter_create(g_hndl)) == NULL ||
12518 	    (piter = scf_iter_create(g_hndl)) == NULL ||
12519 	    (viter = scf_iter_create(g_hndl)) == NULL)
12520 		scfdie();
12521 
12522 	buf = safe_malloc(max_scf_name_len + 1);
12523 	tybuf = safe_malloc(max_scf_pg_type_len + 1);
12524 	pname = safe_malloc(max_scf_name_len + 1);
12525 
12526 	if (cur_inst != NULL)
12527 		ret = scf_iter_instance_pgs(iter, cur_inst);
12528 	else
12529 		ret = scf_iter_service_pgs(iter, cur_svc);
12530 	if (ret != SCF_SUCCESS)
12531 		scfdie();
12532 
12533 	while ((ret = scf_iter_next_pg(iter, pg)) == 1) {
12534 		int ret2;
12535 
12536 		/*
12537 		 * # delprop pg
12538 		 * # addpg pg type
12539 		 */
12540 		if (scf_pg_get_name(pg, buf, max_scf_name_len + 1) < 0)
12541 			scfdie();
12542 
12543 		if (scf_pg_get_type(pg, tybuf, max_scf_pg_type_len + 1) < 0)
12544 			scfdie();
12545 
12546 		if (fprintf(strm, "# Property group \"%s\"\n"
12547 		    "# delprop %s\n"
12548 		    "# addpg %s %s\n", buf, buf, buf, tybuf) < 0) {
12549 			warn(emsg_write_error, strerror(errno));
12550 			result = -1;
12551 			goto out;
12552 		}
12553 
12554 		/* # setprop pg/prop = (values) */
12555 
12556 		if (scf_iter_pg_properties(piter, pg) != SCF_SUCCESS)
12557 			scfdie();
12558 
12559 		while ((ret2 = scf_iter_next_property(piter, prop)) == 1) {
12560 			int first = 1;
12561 			int ret3;
12562 			int multiple;
12563 			int is_str;
12564 			scf_type_t bty;
12565 
12566 			if (scf_property_get_name(prop, pname,
12567 			    max_scf_name_len + 1) < 0)
12568 				scfdie();
12569 
12570 			if (scf_property_type(prop, &ty) != 0)
12571 				scfdie();
12572 
12573 			multiple = prop_has_multiple_values(prop, val);
12574 
12575 			if (fprintf(strm, "# setprop %s/%s = %s: %s", buf,
12576 			    pname, scf_type_to_string(ty), multiple ? "(" : "")
12577 			    < 0) {
12578 				warn(emsg_write_error, strerror(errno));
12579 				result = -1;
12580 				goto out;
12581 			}
12582 
12583 			(void) scf_type_base_type(ty, &bty);
12584 			is_str = (bty == SCF_TYPE_ASTRING);
12585 
12586 			if (scf_iter_property_values(viter, prop) !=
12587 			    SCF_SUCCESS)
12588 				scfdie();
12589 
12590 			while ((ret3 = scf_iter_next_value(viter, val)) == 1) {
12591 				char *buf;
12592 				ssize_t buflen;
12593 
12594 				buflen = scf_value_get_as_string(val, NULL, 0);
12595 				if (buflen < 0)
12596 					scfdie();
12597 
12598 				buf = safe_malloc(buflen + 1);
12599 
12600 				if (scf_value_get_as_string(val, buf,
12601 				    buflen + 1) < 0)
12602 					scfdie();
12603 
12604 				if (first)
12605 					first = 0;
12606 				else {
12607 					if (putc(' ', strm) != ' ') {
12608 						warn(emsg_write_error,
12609 						    strerror(errno));
12610 						result = -1;
12611 						goto out;
12612 					}
12613 				}
12614 
12615 				if ((is_str && multiple) ||
12616 				    strpbrk(buf, CHARS_TO_QUOTE) != NULL) {
12617 					(void) putc('"', strm);
12618 					(void) quote_and_print(buf, strm, 1);
12619 					(void) putc('"', strm);
12620 
12621 					if (ferror(strm)) {
12622 						warn(emsg_write_error,
12623 						    strerror(errno));
12624 						result = -1;
12625 						goto out;
12626 					}
12627 				} else {
12628 					if (fprintf(strm, "%s", buf) < 0) {
12629 						warn(emsg_write_error,
12630 						    strerror(errno));
12631 						result = -1;
12632 						goto out;
12633 					}
12634 				}
12635 
12636 				free(buf);
12637 			}
12638 			if (ret3 < 0 &&
12639 			    scf_error() != SCF_ERROR_PERMISSION_DENIED)
12640 				scfdie();
12641 
12642 			/* Write closing paren if mult-value property */
12643 			if ((multiple && putc(')', strm) == EOF) ||
12644 
12645 			    /* Write final newline */
12646 			    fputc('\n', strm) == EOF) {
12647 				warn(emsg_write_error, strerror(errno));
12648 				result = -1;
12649 				goto out;
12650 			}
12651 		}
12652 		if (ret2 < 0)
12653 			scfdie();
12654 
12655 		if (fputc('\n', strm) == EOF) {
12656 			warn(emsg_write_error, strerror(errno));
12657 			result = -1;
12658 			goto out;
12659 		}
12660 	}
12661 	if (ret < 0)
12662 		scfdie();
12663 
12664 out:
12665 	free(pname);
12666 	free(tybuf);
12667 	free(buf);
12668 	scf_iter_destroy(viter);
12669 	scf_iter_destroy(piter);
12670 	scf_iter_destroy(iter);
12671 	scf_value_destroy(val);
12672 	scf_property_destroy(prop);
12673 	scf_pg_destroy(pg);
12674 
12675 	if (result == 0) {
12676 		if (fflush(strm) != 0) {
12677 			warn(emsg_write_error, strerror(errno));
12678 			return (-1);
12679 		}
12680 	}
12681 
12682 	return (result);
12683 }
12684 
12685 int
12686 lscf_editprop()
12687 {
12688 	char *buf, *editor;
12689 	size_t bufsz;
12690 	int tmpfd;
12691 	char tempname[] = TEMP_FILE_PATTERN;
12692 
12693 	lscf_prep_hndl();
12694 
12695 	if (cur_snap != NULL) {
12696 		semerr(emsg_cant_modify_snapshots);
12697 		return (-1);
12698 	}
12699 
12700 	if (cur_svc == NULL && cur_inst == NULL) {
12701 		semerr(emsg_entity_not_selected);
12702 		return (-1);
12703 	}
12704 
12705 	tmpfd = mkstemp(tempname);
12706 	if (tmpfd == -1) {
12707 		semerr(gettext("Could not create temporary file.\n"));
12708 		return (-1);
12709 	}
12710 
12711 	(void) strcpy(tempfilename, tempname);
12712 
12713 	tempfile = fdopen(tmpfd, "r+");
12714 	if (tempfile == NULL) {
12715 		warn(gettext("Could not create temporary file.\n"));
12716 		if (close(tmpfd) == -1)
12717 			warn(gettext("Could not close temporary file: %s.\n"),
12718 			    strerror(errno));
12719 
12720 		remove_tempfile();
12721 
12722 		return (-1);
12723 	}
12724 
12725 	if (write_edit_script(tempfile) == -1) {
12726 		remove_tempfile();
12727 		return (-1);
12728 	}
12729 
12730 	editor = getenv("EDITOR");
12731 	if (editor == NULL)
12732 		editor = "vi";
12733 
12734 	bufsz = strlen(editor) + 1 + strlen(tempname) + 1;
12735 	buf = safe_malloc(bufsz);
12736 
12737 	if (snprintf(buf, bufsz, "%s %s", editor, tempname) < 0)
12738 		uu_die(gettext("Error creating editor command"));
12739 
12740 	if (system(buf) == -1) {
12741 		semerr(gettext("Could not launch editor %s: %s\n"), editor,
12742 		    strerror(errno));
12743 		free(buf);
12744 		remove_tempfile();
12745 		return (-1);
12746 	}
12747 
12748 	free(buf);
12749 
12750 	(void) engine_source(tempname, est->sc_cmd_flags & SC_CMD_IACTIVE);
12751 
12752 	remove_tempfile();
12753 
12754 	return (0);
12755 }
12756 
12757 static void
12758 add_string(uu_list_t *strlist, const char *str)
12759 {
12760 	string_list_t *elem;
12761 	elem = safe_malloc(sizeof (*elem));
12762 	uu_list_node_init(elem, &elem->node, string_pool);
12763 	elem->str = safe_strdup(str);
12764 	if (uu_list_append(strlist, elem) != 0)
12765 		uu_die(gettext("libuutil error: %s\n"),
12766 		    uu_strerror(uu_error()));
12767 }
12768 
12769 /*
12770  * Get all property values that don't match the given glob pattern,
12771  * if a pattern is specified.
12772  */
12773 static void
12774 get_prop_values(scf_property_t *prop, uu_list_t *values,
12775     const char *pattern)
12776 {
12777 	scf_iter_t *iter;
12778 	scf_value_t *val;
12779 	int ret;
12780 
12781 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
12782 	    (val = scf_value_create(g_hndl)) == NULL)
12783 		scfdie();
12784 
12785 	if (scf_iter_property_values(iter, prop) != 0)
12786 		scfdie();
12787 
12788 	while ((ret = scf_iter_next_value(iter, val)) == 1) {
12789 		char *buf;
12790 		ssize_t vlen, szret;
12791 
12792 		vlen = scf_value_get_as_string(val, NULL, 0);
12793 		if (vlen < 0)
12794 			scfdie();
12795 
12796 		buf = safe_malloc(vlen + 1);
12797 
12798 		szret = scf_value_get_as_string(val, buf, vlen + 1);
12799 		if (szret < 0)
12800 			scfdie();
12801 		assert(szret <= vlen);
12802 
12803 		if (pattern == NULL || fnmatch(pattern, buf, 0) != 0)
12804 			add_string(values, buf);
12805 
12806 		free(buf);
12807 	}
12808 
12809 	if (ret == -1)
12810 		scfdie();
12811 
12812 	scf_value_destroy(val);
12813 	scf_iter_destroy(iter);
12814 }
12815 
12816 static int
12817 lscf_setpropvalue(const char *pgname, const char *type,
12818     const char *arg, int isadd, int isnotfoundok)
12819 {
12820 	scf_type_t ty;
12821 	scf_propertygroup_t *pg;
12822 	scf_property_t *prop;
12823 	int ret, result = 0;
12824 	scf_transaction_t *tx;
12825 	scf_transaction_entry_t *e;
12826 	scf_value_t *v;
12827 	string_list_t *sp;
12828 	char *propname;
12829 	uu_list_t *values;
12830 	uu_list_walk_t *walk;
12831 	void *cookie = NULL;
12832 	char *pattern = NULL;
12833 
12834 	lscf_prep_hndl();
12835 
12836 	if ((values = uu_list_create(string_pool, NULL, 0)) == NULL)
12837 		uu_die(gettext("Could not create property list: %s\n"),
12838 		    uu_strerror(uu_error()));
12839 
12840 	if (!isadd)
12841 		pattern = safe_strdup(arg);
12842 
12843 	if ((e = scf_entry_create(g_hndl)) == NULL ||
12844 	    (pg = scf_pg_create(g_hndl)) == NULL ||
12845 	    (prop = scf_property_create(g_hndl)) == NULL ||
12846 	    (tx = scf_transaction_create(g_hndl)) == NULL)
12847 		scfdie();
12848 
12849 	if (cur_snap != NULL) {
12850 		semerr(emsg_cant_modify_snapshots);
12851 		goto fail;
12852 	}
12853 
12854 	if (cur_inst == NULL && cur_svc == NULL) {
12855 		semerr(emsg_entity_not_selected);
12856 		goto fail;
12857 	}
12858 
12859 	propname = strchr(pgname, '/');
12860 	if (propname == NULL) {
12861 		semerr(gettext("Property names must contain a `/'.\n"));
12862 		goto fail;
12863 	}
12864 
12865 	*propname = '\0';
12866 	++propname;
12867 
12868 	if (type != NULL) {
12869 		ty = string_to_type(type);
12870 		if (ty == SCF_TYPE_INVALID) {
12871 			semerr(gettext("Unknown type \"%s\".\n"), type);
12872 			goto fail;
12873 		}
12874 	}
12875 
12876 	if (cur_inst != NULL)
12877 		ret = scf_instance_get_pg(cur_inst, pgname, pg);
12878 	else
12879 		ret = scf_service_get_pg(cur_svc, pgname, pg);
12880 	if (ret != 0) {
12881 		switch (scf_error()) {
12882 		case SCF_ERROR_NOT_FOUND:
12883 			if (isnotfoundok) {
12884 				result = 0;
12885 			} else {
12886 				semerr(emsg_no_such_pg, pgname);
12887 				result = -1;
12888 			}
12889 			goto out;
12890 
12891 		case SCF_ERROR_INVALID_ARGUMENT:
12892 			semerr(emsg_invalid_pg_name, pgname);
12893 			goto fail;
12894 
12895 		default:
12896 			scfdie();
12897 		}
12898 	}
12899 
12900 	do {
12901 		if (scf_pg_update(pg) == -1)
12902 			scfdie();
12903 		if (scf_transaction_start(tx, pg) != 0) {
12904 			if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
12905 				scfdie();
12906 
12907 			semerr(emsg_permission_denied);
12908 			goto fail;
12909 		}
12910 
12911 		ret = scf_pg_get_property(pg, propname, prop);
12912 		if (ret == 0) {
12913 			scf_type_t ptype;
12914 			char *pat = pattern;
12915 
12916 			if (scf_property_type(prop, &ptype) != 0)
12917 				scfdie();
12918 
12919 			if (isadd) {
12920 				if (type != NULL && ptype != ty) {
12921 					semerr(gettext("Property \"%s\" is not "
12922 					    "of type \"%s\".\n"), propname,
12923 					    type);
12924 					goto fail;
12925 				}
12926 
12927 				pat = NULL;
12928 			} else {
12929 				size_t len = strlen(pat);
12930 				if (len > 0 && pat[len - 1] == '\"')
12931 					pat[len - 1] = '\0';
12932 				if (len > 0 && pat[0] == '\"')
12933 					pat++;
12934 			}
12935 
12936 			ty = ptype;
12937 
12938 			get_prop_values(prop, values, pat);
12939 
12940 			if (isadd)
12941 				add_string(values, arg);
12942 
12943 			if (scf_transaction_property_change(tx, e,
12944 			    propname, ty) == -1)
12945 				scfdie();
12946 		} else if (scf_error() == SCF_ERROR_NOT_FOUND) {
12947 			if (isadd) {
12948 				if (type == NULL) {
12949 					semerr(gettext("Type required "
12950 					    "for new properties.\n"));
12951 					goto fail;
12952 				}
12953 
12954 				add_string(values, arg);
12955 
12956 				if (scf_transaction_property_new(tx, e,
12957 				    propname, ty) == -1)
12958 					scfdie();
12959 			} else if (isnotfoundok) {
12960 				result = 0;
12961 				goto out;
12962 			} else {
12963 				semerr(gettext("No such property %s/%s.\n"),
12964 				    pgname, propname);
12965 				result = -1;
12966 				goto out;
12967 			}
12968 		} else if (scf_error() == SCF_ERROR_INVALID_ARGUMENT) {
12969 			semerr(emsg_invalid_prop_name, propname);
12970 			goto fail;
12971 		} else {
12972 			scfdie();
12973 		}
12974 
12975 		walk = uu_list_walk_start(values, UU_DEFAULT);
12976 		if (walk == NULL)
12977 			uu_die(gettext("Could not walk property list.\n"));
12978 
12979 		for (sp = uu_list_walk_next(walk); sp != NULL;
12980 		    sp = uu_list_walk_next(walk)) {
12981 			v = string_to_value(sp->str, ty, 0);
12982 
12983 			if (v == NULL) {
12984 				scf_entry_destroy_children(e);
12985 				goto fail;
12986 			}
12987 			ret = scf_entry_add_value(e, v);
12988 			assert(ret == 0);
12989 		}
12990 		uu_list_walk_end(walk);
12991 
12992 		result = scf_transaction_commit(tx);
12993 
12994 		scf_transaction_reset(tx);
12995 		scf_entry_destroy_children(e);
12996 	} while (result == 0);
12997 
12998 	if (result < 0) {
12999 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13000 			scfdie();
13001 
13002 		semerr(emsg_permission_denied);
13003 		goto fail;
13004 	}
13005 
13006 	result = 0;
13007 
13008 	private_refresh();
13009 
13010 out:
13011 	scf_transaction_destroy(tx);
13012 	scf_entry_destroy(e);
13013 	scf_pg_destroy(pg);
13014 	scf_property_destroy(prop);
13015 	free(pattern);
13016 
13017 	while ((sp = uu_list_teardown(values, &cookie)) != NULL) {
13018 		free(sp->str);
13019 		free(sp);
13020 	}
13021 
13022 	uu_list_destroy(values);
13023 
13024 	return (result);
13025 
13026 fail:
13027 	result = -1;
13028 	goto out;
13029 }
13030 
13031 int
13032 lscf_addpropvalue(const char *pgname, const char *type, const char *value)
13033 {
13034 	return (lscf_setpropvalue(pgname, type, value, 1, 0));
13035 }
13036 
13037 int
13038 lscf_delpropvalue(const char *pgname, const char *pattern, int isnotfoundok)
13039 {
13040 	return (lscf_setpropvalue(pgname, NULL, pattern, 0, isnotfoundok));
13041 }
13042 
13043 /*
13044  * Look for a standard start method, first in the instance (if any),
13045  * then the service.
13046  */
13047 static const char *
13048 start_method_name(int *in_instance)
13049 {
13050 	scf_propertygroup_t *pg;
13051 	char **p;
13052 	int ret;
13053 	scf_instance_t *inst = cur_inst;
13054 
13055 	if ((pg = scf_pg_create(g_hndl)) == NULL)
13056 		scfdie();
13057 
13058 again:
13059 	for (p = start_method_names; *p != NULL; p++) {
13060 		if (inst != NULL)
13061 			ret = scf_instance_get_pg(inst, *p, pg);
13062 		else
13063 			ret = scf_service_get_pg(cur_svc, *p, pg);
13064 
13065 		if (ret == 0) {
13066 			size_t bufsz = strlen(SCF_GROUP_METHOD) + 1;
13067 			char *buf = safe_malloc(bufsz);
13068 
13069 			if ((ret = scf_pg_get_type(pg, buf, bufsz)) < 0) {
13070 				free(buf);
13071 				continue;
13072 			}
13073 			if (strcmp(buf, SCF_GROUP_METHOD) != 0) {
13074 				free(buf);
13075 				continue;
13076 			}
13077 
13078 			free(buf);
13079 			*in_instance = (inst != NULL);
13080 			scf_pg_destroy(pg);
13081 			return (*p);
13082 		}
13083 
13084 		if (scf_error() == SCF_ERROR_NOT_FOUND)
13085 			continue;
13086 
13087 		scfdie();
13088 	}
13089 
13090 	if (inst != NULL) {
13091 		inst = NULL;
13092 		goto again;
13093 	}
13094 
13095 	scf_pg_destroy(pg);
13096 	return (NULL);
13097 }
13098 
13099 static int
13100 addpg(const char *name, const char *type)
13101 {
13102 	scf_propertygroup_t *pg;
13103 	int ret;
13104 
13105 	pg = scf_pg_create(g_hndl);
13106 	if (pg == NULL)
13107 		scfdie();
13108 
13109 	if (cur_inst != NULL)
13110 		ret = scf_instance_add_pg(cur_inst, name, type, 0, pg);
13111 	else
13112 		ret = scf_service_add_pg(cur_svc, name, type, 0, pg);
13113 
13114 	if (ret != 0) {
13115 		switch (scf_error()) {
13116 		case SCF_ERROR_EXISTS:
13117 			ret = 0;
13118 			break;
13119 
13120 		case SCF_ERROR_PERMISSION_DENIED:
13121 			semerr(emsg_permission_denied);
13122 			break;
13123 
13124 		default:
13125 			scfdie();
13126 		}
13127 	}
13128 
13129 	scf_pg_destroy(pg);
13130 	return (ret);
13131 }
13132 
13133 int
13134 lscf_setenv(uu_list_t *args, int isunset)
13135 {
13136 	int ret = 0;
13137 	size_t i;
13138 	int argc;
13139 	char **argv = NULL;
13140 	string_list_t *slp;
13141 	char *pattern;
13142 	char *prop;
13143 	int do_service = 0;
13144 	int do_instance = 0;
13145 	const char *method = NULL;
13146 	const char *name = NULL;
13147 	const char *value = NULL;
13148 	scf_instance_t *saved_cur_inst = cur_inst;
13149 
13150 	lscf_prep_hndl();
13151 
13152 	argc = uu_list_numnodes(args);
13153 	if (argc < 1)
13154 		goto usage;
13155 
13156 	argv = calloc(argc + 1, sizeof (char *));
13157 	if (argv == NULL)
13158 		uu_die(gettext("Out of memory.\n"));
13159 
13160 	for (slp = uu_list_first(args), i = 0;
13161 	    slp != NULL;
13162 	    slp = uu_list_next(args, slp), ++i)
13163 		argv[i] = slp->str;
13164 
13165 	argv[i] = NULL;
13166 
13167 	opterr = 0;
13168 	optind = 0;
13169 	for (;;) {
13170 		ret = getopt(argc, argv, "sim:");
13171 		if (ret == -1)
13172 			break;
13173 
13174 		switch (ret) {
13175 		case 's':
13176 			do_service = 1;
13177 			cur_inst = NULL;
13178 			break;
13179 
13180 		case 'i':
13181 			do_instance = 1;
13182 			break;
13183 
13184 		case 'm':
13185 			method = optarg;
13186 			break;
13187 
13188 		case '?':
13189 			goto usage;
13190 
13191 		default:
13192 			bad_error("getopt", ret);
13193 		}
13194 	}
13195 
13196 	argc -= optind;
13197 	if ((do_service && do_instance) ||
13198 	    (isunset && argc != 1) ||
13199 	    (!isunset && argc != 2))
13200 		goto usage;
13201 
13202 	name = argv[optind];
13203 	if (!isunset)
13204 		value = argv[optind + 1];
13205 
13206 	if (cur_snap != NULL) {
13207 		semerr(emsg_cant_modify_snapshots);
13208 		ret = -1;
13209 		goto out;
13210 	}
13211 
13212 	if (cur_inst == NULL && cur_svc == NULL) {
13213 		semerr(emsg_entity_not_selected);
13214 		ret = -1;
13215 		goto out;
13216 	}
13217 
13218 	if (do_instance && cur_inst == NULL) {
13219 		semerr(gettext("No instance is selected.\n"));
13220 		ret = -1;
13221 		goto out;
13222 	}
13223 
13224 	if (do_service && cur_svc == NULL) {
13225 		semerr(gettext("No service is selected.\n"));
13226 		ret = -1;
13227 		goto out;
13228 	}
13229 
13230 	if (method == NULL) {
13231 		if (do_instance || do_service) {
13232 			method = "method_context";
13233 			if (!isunset) {
13234 				ret = addpg("method_context",
13235 				    SCF_GROUP_FRAMEWORK);
13236 				if (ret != 0)
13237 					goto out;
13238 			}
13239 		} else {
13240 			int in_instance;
13241 			method = start_method_name(&in_instance);
13242 			if (method == NULL) {
13243 				semerr(gettext(
13244 				    "Couldn't find start method; please "
13245 				    "specify a method with '-m'.\n"));
13246 				ret = -1;
13247 				goto out;
13248 			}
13249 			if (!in_instance)
13250 				cur_inst = NULL;
13251 		}
13252 	} else {
13253 		scf_propertygroup_t *pg;
13254 		size_t bufsz;
13255 		char *buf;
13256 		int ret;
13257 
13258 		if ((pg = scf_pg_create(g_hndl)) == NULL)
13259 			scfdie();
13260 
13261 		if (cur_inst != NULL)
13262 			ret = scf_instance_get_pg(cur_inst, method, pg);
13263 		else
13264 			ret = scf_service_get_pg(cur_svc, method, pg);
13265 
13266 		if (ret != 0) {
13267 			scf_pg_destroy(pg);
13268 			switch (scf_error()) {
13269 			case SCF_ERROR_NOT_FOUND:
13270 				semerr(gettext("Couldn't find the method "
13271 				    "\"%s\".\n"), method);
13272 				goto out;
13273 
13274 			case SCF_ERROR_INVALID_ARGUMENT:
13275 				semerr(gettext("Invalid method name \"%s\".\n"),
13276 				    method);
13277 				goto out;
13278 
13279 			default:
13280 				scfdie();
13281 			}
13282 		}
13283 
13284 		bufsz = strlen(SCF_GROUP_METHOD) + 1;
13285 		buf = safe_malloc(bufsz);
13286 
13287 		if (scf_pg_get_type(pg, buf, bufsz) < 0 ||
13288 		    strcmp(buf, SCF_GROUP_METHOD) != 0) {
13289 			semerr(gettext("Property group \"%s\" is not of type "
13290 			    "\"method\".\n"), method);
13291 			ret = -1;
13292 			free(buf);
13293 			scf_pg_destroy(pg);
13294 			goto out;
13295 		}
13296 
13297 		free(buf);
13298 		scf_pg_destroy(pg);
13299 	}
13300 
13301 	prop = uu_msprintf("%s/environment", method);
13302 	pattern = uu_msprintf("%s=*", name);
13303 
13304 	if (prop == NULL || pattern == NULL)
13305 		uu_die(gettext("Out of memory.\n"));
13306 
13307 	ret = lscf_delpropvalue(prop, pattern, !isunset);
13308 
13309 	if (ret == 0 && !isunset) {
13310 		uu_free(pattern);
13311 		uu_free(prop);
13312 		prop = uu_msprintf("%s/environment", method);
13313 		pattern = uu_msprintf("%s=%s", name, value);
13314 		if (prop == NULL || pattern == NULL)
13315 			uu_die(gettext("Out of memory.\n"));
13316 		ret = lscf_addpropvalue(prop, "astring:", pattern);
13317 	}
13318 	uu_free(pattern);
13319 	uu_free(prop);
13320 
13321 out:
13322 	cur_inst = saved_cur_inst;
13323 
13324 	free(argv);
13325 	return (ret);
13326 usage:
13327 	ret = -2;
13328 	goto out;
13329 }
13330 
13331 /*
13332  * Snapshot commands
13333  */
13334 
13335 void
13336 lscf_listsnap()
13337 {
13338 	scf_snapshot_t *snap;
13339 	scf_iter_t *iter;
13340 	char *nb;
13341 	int r;
13342 
13343 	lscf_prep_hndl();
13344 
13345 	if (cur_inst == NULL) {
13346 		semerr(gettext("Instance not selected.\n"));
13347 		return;
13348 	}
13349 
13350 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13351 	    (iter = scf_iter_create(g_hndl)) == NULL)
13352 		scfdie();
13353 
13354 	if (scf_iter_instance_snapshots(iter, cur_inst) != SCF_SUCCESS)
13355 		scfdie();
13356 
13357 	nb = safe_malloc(max_scf_name_len + 1);
13358 
13359 	while ((r = scf_iter_next_snapshot(iter, snap)) == 1) {
13360 		if (scf_snapshot_get_name(snap, nb, max_scf_name_len + 1) < 0)
13361 			scfdie();
13362 
13363 		(void) puts(nb);
13364 	}
13365 	if (r < 0)
13366 		scfdie();
13367 
13368 	free(nb);
13369 	scf_iter_destroy(iter);
13370 	scf_snapshot_destroy(snap);
13371 }
13372 
13373 void
13374 lscf_selectsnap(const char *name)
13375 {
13376 	scf_snapshot_t *snap;
13377 	scf_snaplevel_t *level;
13378 
13379 	lscf_prep_hndl();
13380 
13381 	if (cur_inst == NULL) {
13382 		semerr(gettext("Instance not selected.\n"));
13383 		return;
13384 	}
13385 
13386 	if (cur_snap != NULL) {
13387 		if (name != NULL) {
13388 			char *cur_snap_name;
13389 			boolean_t nochange;
13390 
13391 			cur_snap_name = safe_malloc(max_scf_name_len + 1);
13392 
13393 			if (scf_snapshot_get_name(cur_snap, cur_snap_name,
13394 			    max_scf_name_len + 1) < 0)
13395 				scfdie();
13396 
13397 			nochange = strcmp(name, cur_snap_name) == 0;
13398 
13399 			free(cur_snap_name);
13400 
13401 			if (nochange)
13402 				return;
13403 		}
13404 
13405 		unselect_cursnap();
13406 	}
13407 
13408 	if (name == NULL)
13409 		return;
13410 
13411 	if ((snap = scf_snapshot_create(g_hndl)) == NULL ||
13412 	    (level = scf_snaplevel_create(g_hndl)) == NULL)
13413 		scfdie();
13414 
13415 	if (scf_instance_get_snapshot(cur_inst, name, snap) !=
13416 	    SCF_SUCCESS) {
13417 		switch (scf_error()) {
13418 		case SCF_ERROR_INVALID_ARGUMENT:
13419 			semerr(gettext("Invalid name \"%s\".\n"), name);
13420 			break;
13421 
13422 		case SCF_ERROR_NOT_FOUND:
13423 			semerr(gettext("No such snapshot \"%s\".\n"), name);
13424 			break;
13425 
13426 		default:
13427 			scfdie();
13428 		}
13429 
13430 		scf_snaplevel_destroy(level);
13431 		scf_snapshot_destroy(snap);
13432 		return;
13433 	}
13434 
13435 	/* Load the snaplevels into our list. */
13436 	cur_levels = uu_list_create(snaplevel_pool, NULL, 0);
13437 	if (cur_levels == NULL)
13438 		uu_die(gettext("Could not create list: %s\n"),
13439 		    uu_strerror(uu_error()));
13440 
13441 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13442 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13443 			scfdie();
13444 
13445 		semerr(gettext("Snapshot has no snaplevels.\n"));
13446 
13447 		scf_snaplevel_destroy(level);
13448 		scf_snapshot_destroy(snap);
13449 		return;
13450 	}
13451 
13452 	cur_snap = snap;
13453 
13454 	for (;;) {
13455 		cur_elt = safe_malloc(sizeof (*cur_elt));
13456 		uu_list_node_init(cur_elt, &cur_elt->list_node,
13457 		    snaplevel_pool);
13458 		cur_elt->sl = level;
13459 		if (uu_list_insert_after(cur_levels, NULL, cur_elt) != 0)
13460 			uu_die(gettext("libuutil error: %s\n"),
13461 			    uu_strerror(uu_error()));
13462 
13463 		level = scf_snaplevel_create(g_hndl);
13464 		if (level == NULL)
13465 			scfdie();
13466 
13467 		if (scf_snaplevel_get_next_snaplevel(cur_elt->sl,
13468 		    level) != SCF_SUCCESS) {
13469 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13470 				scfdie();
13471 
13472 			scf_snaplevel_destroy(level);
13473 			break;
13474 		}
13475 	}
13476 
13477 	cur_elt = uu_list_last(cur_levels);
13478 	cur_level = cur_elt->sl;
13479 }
13480 
13481 /*
13482  * Copies the properties & values in src to dst.  Assumes src won't change.
13483  * Returns -1 if permission is denied, -2 if another transaction interrupts,
13484  * and 0 on success.
13485  *
13486  * If enabled is 0 or 1, its value is used for the SCF_PROPERTY_ENABLED
13487  * property, if it is copied and has type boolean.  (See comment in
13488  * lscf_revert()).
13489  */
13490 static int
13491 pg_copy(const scf_propertygroup_t *src, scf_propertygroup_t *dst,
13492     uint8_t enabled)
13493 {
13494 	scf_transaction_t *tx;
13495 	scf_iter_t *iter, *viter;
13496 	scf_property_t *prop;
13497 	scf_value_t *v;
13498 	char *nbuf;
13499 	int r;
13500 
13501 	tx = scf_transaction_create(g_hndl);
13502 	if (tx == NULL)
13503 		scfdie();
13504 
13505 	if (scf_transaction_start(tx, dst) != SCF_SUCCESS) {
13506 		if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13507 			scfdie();
13508 
13509 		scf_transaction_destroy(tx);
13510 
13511 		return (-1);
13512 	}
13513 
13514 	if ((iter = scf_iter_create(g_hndl)) == NULL ||
13515 	    (prop = scf_property_create(g_hndl)) == NULL ||
13516 	    (viter = scf_iter_create(g_hndl)) == NULL)
13517 		scfdie();
13518 
13519 	nbuf = safe_malloc(max_scf_name_len + 1);
13520 
13521 	if (scf_iter_pg_properties(iter, src) != SCF_SUCCESS)
13522 		scfdie();
13523 
13524 	for (;;) {
13525 		scf_transaction_entry_t *e;
13526 		scf_type_t ty;
13527 
13528 		r = scf_iter_next_property(iter, prop);
13529 		if (r == -1)
13530 			scfdie();
13531 		if (r == 0)
13532 			break;
13533 
13534 		e = scf_entry_create(g_hndl);
13535 		if (e == NULL)
13536 			scfdie();
13537 
13538 		if (scf_property_type(prop, &ty) != SCF_SUCCESS)
13539 			scfdie();
13540 
13541 		if (scf_property_get_name(prop, nbuf, max_scf_name_len + 1) < 0)
13542 			scfdie();
13543 
13544 		if (scf_transaction_property_new(tx, e, nbuf,
13545 		    ty) != SCF_SUCCESS)
13546 			scfdie();
13547 
13548 		if ((enabled == 0 || enabled == 1) &&
13549 		    strcmp(nbuf, scf_property_enabled) == 0 &&
13550 		    ty == SCF_TYPE_BOOLEAN) {
13551 			v = scf_value_create(g_hndl);
13552 			if (v == NULL)
13553 				scfdie();
13554 
13555 			scf_value_set_boolean(v, enabled);
13556 
13557 			if (scf_entry_add_value(e, v) != 0)
13558 				scfdie();
13559 		} else {
13560 			if (scf_iter_property_values(viter, prop) != 0)
13561 				scfdie();
13562 
13563 			for (;;) {
13564 				v = scf_value_create(g_hndl);
13565 				if (v == NULL)
13566 					scfdie();
13567 
13568 				r = scf_iter_next_value(viter, v);
13569 				if (r == -1)
13570 					scfdie();
13571 				if (r == 0) {
13572 					scf_value_destroy(v);
13573 					break;
13574 				}
13575 
13576 				if (scf_entry_add_value(e, v) != SCF_SUCCESS)
13577 					scfdie();
13578 			}
13579 		}
13580 	}
13581 
13582 	free(nbuf);
13583 	scf_iter_destroy(viter);
13584 	scf_property_destroy(prop);
13585 	scf_iter_destroy(iter);
13586 
13587 	r = scf_transaction_commit(tx);
13588 	if (r == -1 && scf_error() != SCF_ERROR_PERMISSION_DENIED)
13589 		scfdie();
13590 
13591 	scf_transaction_destroy_children(tx);
13592 	scf_transaction_destroy(tx);
13593 
13594 	switch (r) {
13595 	case 1:		return (0);
13596 	case 0:		return (-2);
13597 	case -1:	return (-1);
13598 
13599 	default:
13600 		abort();
13601 	}
13602 
13603 	/* NOTREACHED */
13604 }
13605 
13606 void
13607 lscf_revert(const char *snapname)
13608 {
13609 	scf_snapshot_t *snap, *prev;
13610 	scf_snaplevel_t *level, *nlevel;
13611 	scf_iter_t *iter;
13612 	scf_propertygroup_t *pg, *npg;
13613 	scf_property_t *prop;
13614 	scf_value_t *val;
13615 	char *nbuf, *tbuf;
13616 	uint8_t enabled;
13617 
13618 	lscf_prep_hndl();
13619 
13620 	if (cur_inst == NULL) {
13621 		semerr(gettext("Instance not selected.\n"));
13622 		return;
13623 	}
13624 
13625 	if (snapname != NULL) {
13626 		snap = scf_snapshot_create(g_hndl);
13627 		if (snap == NULL)
13628 			scfdie();
13629 
13630 		if (scf_instance_get_snapshot(cur_inst, snapname, snap) !=
13631 		    SCF_SUCCESS) {
13632 			switch (scf_error()) {
13633 			case SCF_ERROR_INVALID_ARGUMENT:
13634 				semerr(gettext("Invalid snapshot name "
13635 				    "\"%s\".\n"), snapname);
13636 				break;
13637 
13638 			case SCF_ERROR_NOT_FOUND:
13639 				semerr(gettext("No such snapshot.\n"));
13640 				break;
13641 
13642 			default:
13643 				scfdie();
13644 			}
13645 
13646 			scf_snapshot_destroy(snap);
13647 			return;
13648 		}
13649 	} else {
13650 		if (cur_snap != NULL) {
13651 			snap = cur_snap;
13652 		} else {
13653 			semerr(gettext("No snapshot selected.\n"));
13654 			return;
13655 		}
13656 	}
13657 
13658 	if ((prev = scf_snapshot_create(g_hndl)) == NULL ||
13659 	    (level = scf_snaplevel_create(g_hndl)) == NULL ||
13660 	    (iter = scf_iter_create(g_hndl)) == NULL ||
13661 	    (pg = scf_pg_create(g_hndl)) == NULL ||
13662 	    (npg = scf_pg_create(g_hndl)) == NULL ||
13663 	    (prop = scf_property_create(g_hndl)) == NULL ||
13664 	    (val = scf_value_create(g_hndl)) == NULL)
13665 		scfdie();
13666 
13667 	nbuf = safe_malloc(max_scf_name_len + 1);
13668 	tbuf = safe_malloc(max_scf_pg_type_len + 1);
13669 
13670 	/* Take the "previous" snapshot before we blow away the properties. */
13671 	if (scf_instance_get_snapshot(cur_inst, snap_previous, prev) == 0) {
13672 		if (_scf_snapshot_take_attach(cur_inst, prev) != 0)
13673 			scfdie();
13674 	} else {
13675 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13676 			scfdie();
13677 
13678 		if (_scf_snapshot_take_new(cur_inst, snap_previous, prev) != 0)
13679 			scfdie();
13680 	}
13681 
13682 	/* Save general/enabled, since we're probably going to replace it. */
13683 	enabled = 2;
13684 	if (scf_instance_get_pg(cur_inst, scf_pg_general, pg) == 0 &&
13685 	    scf_pg_get_property(pg, scf_property_enabled, prop) == 0 &&
13686 	    scf_property_get_value(prop, val) == 0)
13687 		(void) scf_value_get_boolean(val, &enabled);
13688 
13689 	if (scf_snapshot_get_base_snaplevel(snap, level) != SCF_SUCCESS) {
13690 		if (scf_error() != SCF_ERROR_NOT_FOUND)
13691 			scfdie();
13692 
13693 		goto out;
13694 	}
13695 
13696 	for (;;) {
13697 		boolean_t isinst;
13698 		uint32_t flags;
13699 		int r;
13700 
13701 		/* Clear the properties from the corresponding entity. */
13702 		isinst = snaplevel_is_instance(level);
13703 
13704 		if (!isinst)
13705 			r = scf_iter_service_pgs(iter, cur_svc);
13706 		else
13707 			r = scf_iter_instance_pgs(iter, cur_inst);
13708 		if (r != SCF_SUCCESS)
13709 			scfdie();
13710 
13711 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13712 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13713 				scfdie();
13714 
13715 			/* Skip nonpersistent pgs. */
13716 			if (flags & SCF_PG_FLAG_NONPERSISTENT)
13717 				continue;
13718 
13719 			if (scf_pg_delete(pg) != SCF_SUCCESS) {
13720 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13721 					scfdie();
13722 
13723 				semerr(emsg_permission_denied);
13724 				goto out;
13725 			}
13726 		}
13727 		if (r == -1)
13728 			scfdie();
13729 
13730 		/* Copy the properties to the corresponding entity. */
13731 		if (scf_iter_snaplevel_pgs(iter, level) != SCF_SUCCESS)
13732 			scfdie();
13733 
13734 		while ((r = scf_iter_next_pg(iter, pg)) == 1) {
13735 			if (scf_pg_get_name(pg, nbuf, max_scf_name_len + 1) < 0)
13736 				scfdie();
13737 
13738 			if (scf_pg_get_type(pg, tbuf, max_scf_pg_type_len + 1) <
13739 			    0)
13740 				scfdie();
13741 
13742 			if (scf_pg_get_flags(pg, &flags) != SCF_SUCCESS)
13743 				scfdie();
13744 
13745 			if (!isinst)
13746 				r = scf_service_add_pg(cur_svc, nbuf, tbuf,
13747 				    flags, npg);
13748 			else
13749 				r = scf_instance_add_pg(cur_inst, nbuf, tbuf,
13750 				    flags, npg);
13751 			if (r != SCF_SUCCESS) {
13752 				if (scf_error() != SCF_ERROR_PERMISSION_DENIED)
13753 					scfdie();
13754 
13755 				semerr(emsg_permission_denied);
13756 				goto out;
13757 			}
13758 
13759 			if ((enabled == 0 || enabled == 1) &&
13760 			    strcmp(nbuf, scf_pg_general) == 0)
13761 				r = pg_copy(pg, npg, enabled);
13762 			else
13763 				r = pg_copy(pg, npg, 2);
13764 
13765 			switch (r) {
13766 			case 0:
13767 				break;
13768 
13769 			case -1:
13770 				semerr(emsg_permission_denied);
13771 				goto out;
13772 
13773 			case -2:
13774 				semerr(gettext(
13775 				    "Interrupted by another change.\n"));
13776 				goto out;
13777 
13778 			default:
13779 				abort();
13780 			}
13781 		}
13782 		if (r == -1)
13783 			scfdie();
13784 
13785 		/* Get next level. */
13786 		nlevel = scf_snaplevel_create(g_hndl);
13787 		if (nlevel == NULL)
13788 			scfdie();
13789 
13790 		if (scf_snaplevel_get_next_snaplevel(level, nlevel) !=
13791 		    SCF_SUCCESS) {
13792 			if (scf_error() != SCF_ERROR_NOT_FOUND)
13793 				scfdie();
13794 
13795 			scf_snaplevel_destroy(nlevel);
13796 			break;
13797 		}
13798 
13799 		scf_snaplevel_destroy(level);
13800 		level = nlevel;
13801 	}
13802 
13803 	if (snapname == NULL) {
13804 		lscf_selectsnap(NULL);
13805 		snap = NULL;		/* cur_snap has been destroyed */
13806 	}
13807 
13808 out:
13809 	free(tbuf);
13810 	free(nbuf);
13811 	scf_value_destroy(val);
13812 	scf_property_destroy(prop);
13813 	scf_pg_destroy(npg);
13814 	scf_pg_destroy(pg);
13815 	scf_iter_destroy(iter);
13816 	scf_snaplevel_destroy(level);
13817 	scf_snapshot_destroy(prev);
13818 	if (snap != cur_snap)
13819 		scf_snapshot_destroy(snap);
13820 }
13821 
13822 void
13823 lscf_refresh(void)
13824 {
13825 	ssize_t fmrilen;
13826 	size_t bufsz;
13827 	char *fmribuf;
13828 	int r;
13829 
13830 	lscf_prep_hndl();
13831 
13832 	if (cur_inst == NULL) {
13833 		semerr(gettext("Instance not selected.\n"));
13834 		return;
13835 	}
13836 
13837 	bufsz = max_scf_fmri_len + 1;
13838 	fmribuf = safe_malloc(bufsz);
13839 	fmrilen = scf_instance_to_fmri(cur_inst, fmribuf, bufsz);
13840 	if (fmrilen < 0) {
13841 		free(fmribuf);
13842 		if (scf_error() != SCF_ERROR_DELETED)
13843 			scfdie();
13844 		scf_instance_destroy(cur_inst);
13845 		cur_inst = NULL;
13846 		warn(emsg_deleted);
13847 		return;
13848 	}
13849 	assert(fmrilen < bufsz);
13850 
13851 	r = refresh_entity(0, cur_inst, fmribuf, NULL, NULL, NULL);
13852 	switch (r) {
13853 	case 0:
13854 		break;
13855 
13856 	case ECONNABORTED:
13857 		warn(gettext("Could not refresh %s "
13858 		    "(repository connection broken).\n"), fmribuf);
13859 		break;
13860 
13861 	case ECANCELED:
13862 		warn(emsg_deleted);
13863 		break;
13864 
13865 	case EPERM:
13866 		warn(gettext("Could not refresh %s "
13867 		    "(permission denied).\n"), fmribuf);
13868 		break;
13869 
13870 	case ENOSPC:
13871 		warn(gettext("Could not refresh %s "
13872 		    "(repository server out of resources).\n"),
13873 		    fmribuf);
13874 		break;
13875 
13876 	case EACCES:
13877 	default:
13878 		bad_error("refresh_entity", scf_error());
13879 	}
13880 
13881 	free(fmribuf);
13882 }
13883 
13884 /*
13885  * describe [-v] [-t] [pg/prop]
13886  */
13887 int
13888 lscf_describe(uu_list_t *args, int hasargs)
13889 {
13890 	int ret = 0;
13891 	size_t i;
13892 	int argc;
13893 	char **argv = NULL;
13894 	string_list_t *slp;
13895 	int do_verbose = 0;
13896 	int do_templates = 0;
13897 	char *pattern = NULL;
13898 
13899 	lscf_prep_hndl();
13900 
13901 	if (hasargs != 0)  {
13902 		argc = uu_list_numnodes(args);
13903 		if (argc < 1)
13904 			goto usage;
13905 
13906 		argv = calloc(argc + 1, sizeof (char *));
13907 		if (argv == NULL)
13908 			uu_die(gettext("Out of memory.\n"));
13909 
13910 		for (slp = uu_list_first(args), i = 0;
13911 		    slp != NULL;
13912 		    slp = uu_list_next(args, slp), ++i)
13913 			argv[i] = slp->str;
13914 
13915 		argv[i] = NULL;
13916 
13917 		/*
13918 		 * We start optind = 0 because our list of arguments
13919 		 * starts at argv[0]
13920 		 */
13921 		optind = 0;
13922 		opterr = 0;
13923 		for (;;) {
13924 			ret = getopt(argc, argv, "vt");
13925 			if (ret == -1)
13926 				break;
13927 
13928 			switch (ret) {
13929 			case 'v':
13930 				do_verbose = 1;
13931 				break;
13932 
13933 			case 't':
13934 				do_templates = 1;
13935 				break;
13936 
13937 			case '?':
13938 				goto usage;
13939 
13940 			default:
13941 				bad_error("getopt", ret);
13942 			}
13943 		}
13944 
13945 		pattern = argv[optind];
13946 	}
13947 
13948 	if (cur_inst == NULL && cur_svc == NULL) {
13949 		semerr(emsg_entity_not_selected);
13950 		ret = -1;
13951 		goto out;
13952 	}
13953 
13954 	/*
13955 	 * list_entity_tmpl(), listprop() and listtmpl() produce verbose
13956 	 * output if their last parameter is set to 2.  Less information is
13957 	 * produced if the parameter is set to 1.
13958 	 */
13959 	if (pattern == NULL) {
13960 		if (do_verbose == 1)
13961 			list_entity_tmpl(2);
13962 		else
13963 			list_entity_tmpl(1);
13964 	}
13965 
13966 	if (do_templates == 0) {
13967 		if (do_verbose == 1)
13968 			listprop(pattern, 0, 2);
13969 		else
13970 			listprop(pattern, 0, 1);
13971 	} else {
13972 		if (do_verbose == 1)
13973 			listtmpl(pattern, 2);
13974 		else
13975 			listtmpl(pattern, 1);
13976 	}
13977 
13978 	ret = 0;
13979 out:
13980 	if (argv != NULL)
13981 		free(argv);
13982 	return (ret);
13983 usage:
13984 	ret = -2;
13985 	goto out;
13986 }
13987 
13988 #ifndef NATIVE_BUILD
13989 /* ARGSUSED */
13990 CPL_MATCH_FN(complete_select)
13991 {
13992 	const char *arg0, *arg1, *arg1end;
13993 	int word_start, err = 0, r;
13994 	size_t len;
13995 	char *buf;
13996 
13997 	lscf_prep_hndl();
13998 
13999 	arg0 = line + strspn(line, " \t");
14000 	assert(strncmp(arg0, "select", sizeof ("select") - 1) == 0);
14001 
14002 	arg1 = arg0 + sizeof ("select") - 1;
14003 	arg1 += strspn(arg1, " \t");
14004 	word_start = arg1 - line;
14005 
14006 	arg1end = arg1 + strcspn(arg1, " \t");
14007 	if (arg1end < line + word_end)
14008 		return (0);
14009 
14010 	len = line + word_end - arg1;
14011 
14012 	buf = safe_malloc(max_scf_name_len + 1);
14013 
14014 	if (cur_snap != NULL) {
14015 		return (0);
14016 	} else if (cur_inst != NULL) {
14017 		return (0);
14018 	} else if (cur_svc != NULL) {
14019 		scf_instance_t *inst;
14020 		scf_iter_t *iter;
14021 
14022 		if ((inst = scf_instance_create(g_hndl)) == NULL ||
14023 		    (iter = scf_iter_create(g_hndl)) == NULL)
14024 			scfdie();
14025 
14026 		if (scf_iter_service_instances(iter, cur_svc) != 0)
14027 			scfdie();
14028 
14029 		for (;;) {
14030 			r = scf_iter_next_instance(iter, inst);
14031 			if (r == 0)
14032 				break;
14033 			if (r != 1)
14034 				scfdie();
14035 
14036 			if (scf_instance_get_name(inst, buf,
14037 			    max_scf_name_len + 1) < 0)
14038 				scfdie();
14039 
14040 			if (strncmp(buf, arg1, len) == 0) {
14041 				err = cpl_add_completion(cpl, line, word_start,
14042 				    word_end, buf + len, "", " ");
14043 				if (err != 0)
14044 					break;
14045 			}
14046 		}
14047 
14048 		scf_iter_destroy(iter);
14049 		scf_instance_destroy(inst);
14050 
14051 		return (err);
14052 	} else {
14053 		scf_service_t *svc;
14054 		scf_iter_t *iter;
14055 
14056 		assert(cur_scope != NULL);
14057 
14058 		if ((svc = scf_service_create(g_hndl)) == NULL ||
14059 		    (iter = scf_iter_create(g_hndl)) == NULL)
14060 			scfdie();
14061 
14062 		if (scf_iter_scope_services(iter, cur_scope) != 0)
14063 			scfdie();
14064 
14065 		for (;;) {
14066 			r = scf_iter_next_service(iter, svc);
14067 			if (r == 0)
14068 				break;
14069 			if (r != 1)
14070 				scfdie();
14071 
14072 			if (scf_service_get_name(svc, buf,
14073 			    max_scf_name_len + 1) < 0)
14074 				scfdie();
14075 
14076 			if (strncmp(buf, arg1, len) == 0) {
14077 				err = cpl_add_completion(cpl, line, word_start,
14078 				    word_end, buf + len, "", " ");
14079 				if (err != 0)
14080 					break;
14081 			}
14082 		}
14083 
14084 		scf_iter_destroy(iter);
14085 		scf_service_destroy(svc);
14086 
14087 		return (err);
14088 	}
14089 }
14090 
14091 /* ARGSUSED */
14092 CPL_MATCH_FN(complete_command)
14093 {
14094 	uint32_t scope = 0;
14095 
14096 	if (cur_snap != NULL)
14097 		scope = CS_SNAP;
14098 	else if (cur_inst != NULL)
14099 		scope = CS_INST;
14100 	else if (cur_svc != NULL)
14101 		scope = CS_SVC;
14102 	else
14103 		scope = CS_SCOPE;
14104 
14105 	return (scope ? add_cmd_matches(cpl, line, word_end, scope) : 0);
14106 }
14107 #endif	/* NATIVE_BUILD */
14108