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