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