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