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