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