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